2 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 * Ported to X/EGL/GLES. XXX Actually, uses full OpenGL ATM.
29 * Command line options:
30 * -info print GL implementation information
40 #include <X11/Xutil.h>
41 #include <X11/keysym.h>
50 /* XXX this probably isn't very portable */
55 /* return current time (in seconds) */
61 (void) gettimeofday(&tv
, NULL
);
64 (void) gettimeofday(&tv
, &tz
);
66 return (double) tv
.tv_sec
+ tv
.tv_usec
/ 1000000.0;
75 /* update this function for other platforms! */
76 static double t
= 0.0;
79 fprintf(stderr
, "Warning: current_time() not implemented!!\n");
90 #define M_PI 3.14159265
94 static GLfloat view_rotx
= 20.0, view_roty
= 30.0, view_rotz
= 0.0;
95 static GLint gear1
, gear2
, gear3
;
96 static GLfloat angle
= 0.0;
98 static GLboolean fullscreen
= GL_FALSE
; /* Create a single fullscreen window */
103 * Draw a gear wheel. You'll probably want to call this function when
104 * building a display list since we do a lot of trig here.
106 * Input: inner_radius - radius of hole at center
107 * outer_radius - radius at center of teeth
108 * width - width of gear
109 * teeth - number of teeth
110 * tooth_depth - depth of tooth
113 gear(GLfloat inner_radius
, GLfloat outer_radius
, GLfloat width
,
114 GLint teeth
, GLfloat tooth_depth
)
122 r1
= outer_radius
- tooth_depth
/ 2.0;
123 r2
= outer_radius
+ tooth_depth
/ 2.0;
125 da
= 2.0 * M_PI
/ teeth
/ 4.0;
127 glShadeModel(GL_FLAT
);
129 glNormal3f(0.0, 0.0, 1.0);
131 /* draw front face */
132 glBegin(GL_QUAD_STRIP
);
133 for (i
= 0; i
<= teeth
; i
++) {
134 angle
= i
* 2.0 * M_PI
/ teeth
;
135 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
136 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
138 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
139 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
145 /* draw front sides of teeth */
147 da
= 2.0 * M_PI
/ teeth
/ 4.0;
148 for (i
= 0; i
< teeth
; i
++) {
149 angle
= i
* 2.0 * M_PI
/ teeth
;
151 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
152 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
153 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
155 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
160 glNormal3f(0.0, 0.0, -1.0);
163 glBegin(GL_QUAD_STRIP
);
164 for (i
= 0; i
<= teeth
; i
++) {
165 angle
= i
* 2.0 * M_PI
/ teeth
;
166 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
167 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
169 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
171 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
176 /* draw back sides of teeth */
178 da
= 2.0 * M_PI
/ teeth
/ 4.0;
179 for (i
= 0; i
< teeth
; i
++) {
180 angle
= i
* 2.0 * M_PI
/ teeth
;
182 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
184 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
186 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
187 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
191 /* draw outward faces of teeth */
192 glBegin(GL_QUAD_STRIP
);
193 for (i
= 0; i
< teeth
; i
++) {
194 angle
= i
* 2.0 * M_PI
/ teeth
;
196 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
197 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
198 u
= r2
* cos(angle
+ da
) - r1
* cos(angle
);
199 v
= r2
* sin(angle
+ da
) - r1
* sin(angle
);
200 len
= sqrt(u
* u
+ v
* v
);
203 glNormal3f(v
, -u
, 0.0);
204 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
205 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
206 glNormal3f(cos(angle
), sin(angle
), 0.0);
207 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
209 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
211 u
= r1
* cos(angle
+ 3 * da
) - r2
* cos(angle
+ 2 * da
);
212 v
= r1
* sin(angle
+ 3 * da
) - r2
* sin(angle
+ 2 * da
);
213 glNormal3f(v
, -u
, 0.0);
214 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
216 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
218 glNormal3f(cos(angle
), sin(angle
), 0.0);
221 glVertex3f(r1
* cos(0), r1
* sin(0), width
* 0.5);
222 glVertex3f(r1
* cos(0), r1
* sin(0), -width
* 0.5);
226 glShadeModel(GL_SMOOTH
);
228 /* draw inside radius cylinder */
229 glBegin(GL_QUAD_STRIP
);
230 for (i
= 0; i
<= teeth
; i
++) {
231 angle
= i
* 2.0 * M_PI
/ teeth
;
232 glNormal3f(-cos(angle
), -sin(angle
), 0.0);
233 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
234 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
243 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
246 glRotatef(view_rotx
, 1.0, 0.0, 0.0);
247 glRotatef(view_roty
, 0.0, 1.0, 0.0);
248 glRotatef(view_rotz
, 0.0, 0.0, 1.0);
251 glTranslatef(-3.0, -2.0, 0.0);
252 glRotatef(angle
, 0.0, 0.0, 1.0);
257 glTranslatef(3.1, -2.0, 0.0);
258 glRotatef(-2.0 * angle
- 9.0, 0.0, 0.0, 1.0);
263 glTranslatef(-3.1, 4.2, 0.0);
264 glRotatef(-2.0 * angle
- 25.0, 0.0, 0.0, 1.0);
272 /* new window size or exposure */
274 reshape(int width
, int height
)
276 GLfloat ar
= (GLfloat
) width
/ (GLfloat
) height
;
278 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
280 glMatrixMode(GL_PROJECTION
);
282 glFrustum(-ar
, ar
, -1, 1, 5.0, 60.0);
284 glMatrixMode(GL_MODELVIEW
);
286 glTranslatef(0.0, 0.0, -40.0);
294 static GLfloat pos
[4] = { 5.0, 5.0, 10.0, 0.0 };
295 static GLfloat red
[4] = { 0.8, 0.1, 0.0, 1.0 };
296 static GLfloat green
[4] = { 0.0, 0.8, 0.2, 1.0 };
297 static GLfloat blue
[4] = { 0.2, 0.2, 1.0, 1.0 };
299 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
300 glEnable(GL_CULL_FACE
);
301 glEnable(GL_LIGHTING
);
303 glEnable(GL_DEPTH_TEST
);
306 gear1
= glGenLists(1);
307 glNewList(gear1
, GL_COMPILE
);
308 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, red
);
309 gear(1.0, 4.0, 1.0, 20, 0.7);
312 gear2
= glGenLists(1);
313 glNewList(gear2
, GL_COMPILE
);
314 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, green
);
315 gear(0.5, 2.0, 2.0, 10, 0.7);
318 gear3
= glGenLists(1);
319 glNewList(gear3
, GL_COMPILE
);
320 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, blue
);
321 gear(1.3, 2.0, 0.5, 10, 0.7);
324 glEnable(GL_NORMALIZE
);
326 glClearColor(0.2, 0.2, 0.2, 0.0);
331 * Create an RGB, double-buffered X window.
332 * Return the window and context handles.
335 make_x_window(Display
*x_dpy
, EGLDisplay egl_dpy
,
337 int x
, int y
, int width
, int height
,
342 static const EGLint attribs
[] = {
346 /*EGL_DOUBLEBUFFER,*/
352 XSetWindowAttributes attr
;
356 XVisualInfo
*visInfo
, visTemplate
;
360 EGLint num_configs
, vid
;
362 scrnum
= DefaultScreen( x_dpy
);
363 root
= RootWindow( x_dpy
, scrnum
);
367 width
= DisplayWidth( x_dpy
, scrnum
);
368 height
= DisplayHeight( x_dpy
, scrnum
);
371 if (!eglChooseConfig( egl_dpy
, attribs
, &config
, 1, &num_configs
)) {
372 printf("Error: couldn't get an EGL visual config\n");
376 if (!eglGetConfigAttrib(egl_dpy
, config
, EGL_NATIVE_VISUAL_ID
, &vid
)) {
377 printf("Error: eglGetConfigAttrib() failed\n");
381 /* The X window visual must match the EGL config */
382 visTemplate
.visualid
= vid
;
383 visInfo
= XGetVisualInfo(x_dpy
, VisualIDMask
, &visTemplate
, &num_visuals
);
385 printf("Error: couldn't get X visual\n");
389 /* window attributes */
390 attr
.background_pixel
= 0;
391 attr
.border_pixel
= 0;
392 attr
.colormap
= XCreateColormap( x_dpy
, root
, visInfo
->visual
, AllocNone
);
393 attr
.event_mask
= StructureNotifyMask
| ExposureMask
| KeyPressMask
;
394 attr
.override_redirect
= fullscreen
;
395 mask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWEventMask
| CWOverrideRedirect
;
397 win
= XCreateWindow( x_dpy
, root
, 0, 0, width
, height
,
398 0, visInfo
->depth
, InputOutput
,
399 visInfo
->visual
, mask
, &attr
);
401 /* set hints and properties */
403 XSizeHints sizehints
;
406 sizehints
.width
= width
;
407 sizehints
.height
= height
;
408 sizehints
.flags
= USSize
| USPosition
;
409 XSetNormalHints(x_dpy
, win
, &sizehints
);
410 XSetStandardProperties(x_dpy
, win
, name
, name
,
411 None
, (char **)NULL
, 0, &sizehints
);
414 eglBindAPI(EGL_OPENGL_API
);
416 ctx
= eglCreateContext(egl_dpy
, config
, EGL_NO_CONTEXT
, NULL
);
418 printf("Error: glXCreateContext failed\n");
422 *surfRet
= eglCreateWindowSurface(egl_dpy
, config
, win
, NULL
);
432 event_loop(Display
*dpy
, Window win
,
433 EGLDisplay egl_dpy
, EGLSurface egl_surf
)
436 while (XPending(dpy
) > 0) {
438 XNextEvent(dpy
, &event
);
439 switch (event
.type
) {
441 /* we'll redraw below */
443 case ConfigureNotify
:
444 reshape(event
.xconfigure
.width
, event
.xconfigure
.height
);
450 code
= XLookupKeysym(&event
.xkey
, 0);
451 if (code
== XK_Left
) {
454 else if (code
== XK_Right
) {
457 else if (code
== XK_Up
) {
460 else if (code
== XK_Down
) {
464 r
= XLookupString(&event
.xkey
, buffer
, sizeof(buffer
),
466 if (buffer
[0] == 27) {
476 static int frames
= 0;
477 static double tRot0
= -1.0, tRate0
= -1.0;
478 double dt
, t
= current_time();
484 /* advance rotation for next frame */
485 angle
+= 70.0 * dt
; /* 70 degrees per second */
490 eglSwapBuffers(egl_dpy
, egl_surf
);
496 if (t
- tRate0
>= 5.0) {
497 GLfloat seconds
= t
- tRate0
;
498 GLfloat fps
= frames
/ seconds
;
499 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames
, seconds
,
513 printf(" -display <displayname> set the display to run on\n");
514 printf(" -fullscreen run in fullscreen mode\n");
515 printf(" -info display OpenGL renderer info\n");
520 main(int argc
, char *argv
[])
522 const int winWidth
= 300, winHeight
= 300;
528 char *dpyName
= NULL
;
529 GLboolean printInfo
= GL_FALSE
;
530 EGLint egl_major
, egl_minor
;
534 for (i
= 1; i
< argc
; i
++) {
535 if (strcmp(argv
[i
], "-display") == 0) {
539 else if (strcmp(argv
[i
], "-info") == 0) {
542 else if (strcmp(argv
[i
], "-fullscreen") == 0) {
543 fullscreen
= GL_TRUE
;
551 x_dpy
= XOpenDisplay(dpyName
);
553 printf("Error: couldn't open display %s\n",
554 dpyName
? dpyName
: getenv("DISPLAY"));
558 egl_dpy
= eglGetDisplay(x_dpy
);
560 printf("Error: eglGetDisplay() failed\n");
564 if (!eglInitialize(egl_dpy
, &egl_major
, &egl_minor
)) {
565 printf("Error: eglInitialize() failed\n");
569 s
= eglQueryString(egl_dpy
, EGL_VERSION
);
570 printf("EGL_VERSION = %s\n", s
);
572 make_x_window(x_dpy
, egl_dpy
,
573 "glxgears", 0, 0, winWidth
, winHeight
,
574 &win
, &egl_ctx
, &egl_surf
);
576 XMapWindow(x_dpy
, win
);
577 eglMakeCurrent(egl_dpy
, egl_surf
, egl_surf
, egl_ctx
);
580 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
581 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
582 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
587 /* Set initial projection/viewing transformation.
588 * We can't be sure we'll get a ConfigureNotify event when the window
591 reshape(winWidth
, winHeight
);
593 event_loop(x_dpy
, win
, egl_dpy
, egl_surf
);
595 glDeleteLists(gear1
, 1);
596 glDeleteLists(gear2
, 1);
597 glDeleteLists(gear3
, 1);
599 eglDestroyContext(egl_dpy
, egl_ctx
);
600 eglDestroySurface(egl_dpy
, egl_surf
);
601 eglTerminate(egl_dpy
);
604 XDestroyWindow(x_dpy
, win
);
605 XCloseDisplay(x_dpy
);