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;
100 * Draw a gear wheel. You'll probably want to call this function when
101 * building a display list since we do a lot of trig here.
103 * Input: inner_radius - radius of hole at center
104 * outer_radius - radius at center of teeth
105 * width - width of gear
106 * teeth - number of teeth
107 * tooth_depth - depth of tooth
110 gear(GLfloat inner_radius
, GLfloat outer_radius
, GLfloat width
,
111 GLint teeth
, GLfloat tooth_depth
)
119 r1
= outer_radius
- tooth_depth
/ 2.0;
120 r2
= outer_radius
+ tooth_depth
/ 2.0;
122 da
= 2.0 * M_PI
/ teeth
/ 4.0;
124 glShadeModel(GL_FLAT
);
126 glNormal3f(0.0, 0.0, 1.0);
128 /* draw front face */
129 glBegin(GL_QUAD_STRIP
);
130 for (i
= 0; i
<= teeth
; i
++) {
131 angle
= i
* 2.0 * M_PI
/ teeth
;
132 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
133 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
135 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
136 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
142 /* draw front sides of teeth */
144 da
= 2.0 * M_PI
/ teeth
/ 4.0;
145 for (i
= 0; i
< teeth
; i
++) {
146 angle
= i
* 2.0 * M_PI
/ teeth
;
148 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
149 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
150 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
152 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
157 glNormal3f(0.0, 0.0, -1.0);
160 glBegin(GL_QUAD_STRIP
);
161 for (i
= 0; i
<= teeth
; i
++) {
162 angle
= i
* 2.0 * M_PI
/ teeth
;
163 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
164 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
166 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
168 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
173 /* draw back sides of teeth */
175 da
= 2.0 * M_PI
/ teeth
/ 4.0;
176 for (i
= 0; i
< teeth
; i
++) {
177 angle
= i
* 2.0 * M_PI
/ teeth
;
179 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
181 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
183 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
184 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
188 /* draw outward faces of teeth */
189 glBegin(GL_QUAD_STRIP
);
190 for (i
= 0; i
< teeth
; i
++) {
191 angle
= i
* 2.0 * M_PI
/ teeth
;
193 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
194 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
195 u
= r2
* cos(angle
+ da
) - r1
* cos(angle
);
196 v
= r2
* sin(angle
+ da
) - r1
* sin(angle
);
197 len
= sqrt(u
* u
+ v
* v
);
200 glNormal3f(v
, -u
, 0.0);
201 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
202 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
203 glNormal3f(cos(angle
), sin(angle
), 0.0);
204 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
206 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
208 u
= r1
* cos(angle
+ 3 * da
) - r2
* cos(angle
+ 2 * da
);
209 v
= r1
* sin(angle
+ 3 * da
) - r2
* sin(angle
+ 2 * da
);
210 glNormal3f(v
, -u
, 0.0);
211 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
213 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
215 glNormal3f(cos(angle
), sin(angle
), 0.0);
218 glVertex3f(r1
* cos(0), r1
* sin(0), width
* 0.5);
219 glVertex3f(r1
* cos(0), r1
* sin(0), -width
* 0.5);
223 glShadeModel(GL_SMOOTH
);
225 /* draw inside radius cylinder */
226 glBegin(GL_QUAD_STRIP
);
227 for (i
= 0; i
<= teeth
; i
++) {
228 angle
= i
* 2.0 * M_PI
/ teeth
;
229 glNormal3f(-cos(angle
), -sin(angle
), 0.0);
230 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
231 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
240 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
243 glRotatef(view_rotx
, 1.0, 0.0, 0.0);
244 glRotatef(view_roty
, 0.0, 1.0, 0.0);
245 glRotatef(view_rotz
, 0.0, 0.0, 1.0);
248 glTranslatef(-3.0, -2.0, 0.0);
249 glRotatef(angle
, 0.0, 0.0, 1.0);
254 glTranslatef(3.1, -2.0, 0.0);
255 glRotatef(-2.0 * angle
- 9.0, 0.0, 0.0, 1.0);
260 glTranslatef(-3.1, 4.2, 0.0);
261 glRotatef(-2.0 * angle
- 25.0, 0.0, 0.0, 1.0);
269 /* new window size or exposure */
271 reshape(int width
, int height
)
273 GLfloat ar
= (GLfloat
) width
/ (GLfloat
) height
;
275 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
277 glMatrixMode(GL_PROJECTION
);
279 glFrustum(-ar
, ar
, -1, 1, 5.0, 60.0);
281 glMatrixMode(GL_MODELVIEW
);
283 glTranslatef(0.0, 0.0, -40.0);
291 static GLfloat pos
[4] = { 5.0, 5.0, 10.0, 0.0 };
292 static GLfloat red
[4] = { 0.8, 0.1, 0.0, 1.0 };
293 static GLfloat green
[4] = { 0.0, 0.8, 0.2, 1.0 };
294 static GLfloat blue
[4] = { 0.2, 0.2, 1.0, 1.0 };
296 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
297 glEnable(GL_CULL_FACE
);
298 glEnable(GL_LIGHTING
);
300 glEnable(GL_DEPTH_TEST
);
303 gear1
= glGenLists(1);
304 glNewList(gear1
, GL_COMPILE
);
305 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, red
);
306 gear(1.0, 4.0, 1.0, 20, 0.7);
309 gear2
= glGenLists(1);
310 glNewList(gear2
, GL_COMPILE
);
311 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, green
);
312 gear(0.5, 2.0, 2.0, 10, 0.7);
315 gear3
= glGenLists(1);
316 glNewList(gear3
, GL_COMPILE
);
317 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, blue
);
318 gear(1.3, 2.0, 0.5, 10, 0.7);
321 glEnable(GL_NORMALIZE
);
323 glClearColor(0.2, 0.2, 0.2, 0.0);
328 EGLNativeDisplayType xdpy
;
329 EGLNativeWindowType xwin
;
330 EGLNativePixmapType xpix
;
344 static struct egl_manager
*
345 egl_manager_new(EGLNativeDisplayType xdpy
, const EGLint
*attrib_list
,
348 struct egl_manager
*eman
;
352 eman
= calloc(1, sizeof(*eman
));
356 eman
->verbose
= verbose
;
359 eman
->dpy
= eglGetDisplay(eman
->xdpy
);
360 if (eman
->dpy
== EGL_NO_DISPLAY
) {
361 printf("eglGetDisplay() failed\n");
366 if (!eglInitialize(eman
->dpy
, &eman
->major
, &eman
->minor
)) {
367 printf("eglInitialize() failed\n");
372 ver
= eglQueryString(eman
->dpy
, EGL_VERSION
);
373 printf("EGL_VERSION = %s\n", ver
);
375 if (!eglChooseConfig(eman
->dpy
, attrib_list
, &eman
->conf
, 1, &num_conf
) ||
377 printf("eglChooseConfig() failed\n");
378 eglTerminate(eman
->dpy
);
383 eman
->ctx
= eglCreateContext(eman
->dpy
, eman
->conf
, EGL_NO_CONTEXT
, NULL
);
384 if (eman
->ctx
== EGL_NO_CONTEXT
) {
385 printf("eglCreateContext() failed\n");
386 eglTerminate(eman
->dpy
);
395 egl_manager_create_window(struct egl_manager
*eman
, const char *name
,
396 EGLint w
, EGLint h
, EGLBoolean need_surface
,
397 EGLBoolean fullscreen
, const EGLint
*attrib_list
)
399 XVisualInfo vinfo_template
, *vinfo
= NULL
;
400 EGLint val
, num_vinfo
;
402 XSetWindowAttributes attrs
;
406 if (!eglGetConfigAttrib(eman
->dpy
, eman
->conf
,
407 EGL_NATIVE_VISUAL_ID
, &val
)) {
408 printf("eglGetConfigAttrib() failed\n");
412 vinfo_template
.visualid
= (VisualID
) val
;
413 vinfo
= XGetVisualInfo(eman
->xdpy
, VisualIDMask
, &vinfo_template
, &num_vinfo
);
415 /* try harder if window surface is not needed */
416 if (!vinfo
&& !need_surface
&&
417 eglGetConfigAttrib(eman
->dpy
, eman
->conf
, EGL_BUFFER_SIZE
, &val
)) {
420 vinfo_template
.depth
= val
;
421 vinfo
= XGetVisualInfo(eman
->xdpy
, VisualDepthMask
, &vinfo_template
, &num_vinfo
);
425 printf("XGetVisualInfo() failed\n");
429 root
= DefaultRootWindow(eman
->xdpy
);
432 w
= DisplayWidth(eman
->xdpy
, DefaultScreen(eman
->xdpy
));
433 h
= DisplayHeight(eman
->xdpy
, DefaultScreen(eman
->xdpy
));
436 /* window attributes */
437 attrs
.background_pixel
= 0;
438 attrs
.border_pixel
= 0;
439 attrs
.colormap
= XCreateColormap(eman
->xdpy
, root
, vinfo
->visual
, AllocNone
);
440 attrs
.event_mask
= StructureNotifyMask
| ExposureMask
| KeyPressMask
;
441 attrs
.override_redirect
= fullscreen
;
442 mask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWEventMask
| CWOverrideRedirect
;
444 eman
->xwin
= XCreateWindow(eman
->xdpy
, root
, x
, y
, w
, h
,
445 0, vinfo
->depth
, InputOutput
,
446 vinfo
->visual
, mask
, &attrs
);
449 /* set hints and properties */
451 XSizeHints sizehints
;
455 sizehints
.height
= h
;
456 sizehints
.flags
= USSize
| USPosition
;
457 XSetNormalHints(eman
->xdpy
, eman
->xwin
, &sizehints
);
458 XSetStandardProperties(eman
->xdpy
, eman
->xwin
, name
, name
,
459 None
, (char **)NULL
, 0, &sizehints
);
463 eman
->win
= eglCreateWindowSurface(eman
->dpy
, eman
->conf
,
464 eman
->xwin
, attrib_list
);
465 if (eman
->win
== EGL_NO_SURFACE
) {
466 printf("eglCreateWindowSurface() failed\n");
467 XDestroyWindow(eman
->xdpy
, eman
->xwin
);
473 XMapWindow(eman
->xdpy
, eman
->xwin
);
479 egl_manager_create_pixmap(struct egl_manager
*eman
, EGLNativeWindowType xwin
,
480 EGLBoolean need_surface
, const EGLint
*attrib_list
)
482 XWindowAttributes attrs
;
484 if (!XGetWindowAttributes(eman
->xdpy
, xwin
, &attrs
)) {
485 printf("XGetWindowAttributes() failed\n");
489 eman
->xpix
= XCreatePixmap(eman
->xdpy
, xwin
,
490 attrs
.width
, attrs
.height
, attrs
.depth
);
493 eman
->pix
= eglCreatePixmapSurface(eman
->dpy
, eman
->conf
,
494 eman
->xpix
, attrib_list
);
495 if (eman
->pix
== EGL_NO_SURFACE
) {
496 printf("eglCreatePixmapSurface() failed\n");
497 XFreePixmap(eman
->xdpy
, eman
->xpix
);
507 egl_manager_create_pbuffer(struct egl_manager
*eman
, const EGLint
*attrib_list
)
509 eman
->pbuf
= eglCreatePbufferSurface(eman
->dpy
, eman
->conf
, attrib_list
);
510 if (eman
->pbuf
== EGL_NO_SURFACE
) {
511 printf("eglCreatePbufferSurface() failed\n");
519 egl_manager_destroy(struct egl_manager
*eman
)
521 eglMakeCurrent(eman
->dpy
, EGL_NO_SURFACE
, EGL_NO_SURFACE
, EGL_NO_CONTEXT
);
522 eglTerminate(eman
->dpy
);
524 if (eman
->xwin
!= None
)
525 XDestroyWindow(eman
->xdpy
, eman
->xwin
);
526 if (eman
->xpix
!= None
)
527 XFreePixmap(eman
->xdpy
, eman
->xpix
);
533 event_loop(struct egl_manager
*eman
, EGLint surface_type
, EGLint w
, EGLint h
)
535 GC gc
= XCreateGC(eman
->xdpy
, eman
->xwin
, 0, NULL
);
536 EGLint orig_w
= w
, orig_h
= h
;
538 if (surface_type
== EGL_PBUFFER_BIT
)
539 printf("there will be no screen update if "
540 "eglCopyBuffers() is not implemented\n");
543 while (XPending(eman
->xdpy
) > 0) {
545 XNextEvent(eman
->xdpy
, &event
);
546 switch (event
.type
) {
548 /* we'll redraw below */
550 case ConfigureNotify
:
551 w
= event
.xconfigure
.width
;
552 h
= event
.xconfigure
.height
;
553 if (surface_type
== EGL_WINDOW_BIT
)
560 code
= XLookupKeysym(&event
.xkey
, 0);
561 if (code
== XK_Left
) {
564 else if (code
== XK_Right
) {
567 else if (code
== XK_Up
) {
570 else if (code
== XK_Down
) {
574 r
= XLookupString(&event
.xkey
, buffer
, sizeof(buffer
),
576 if (buffer
[0] == 27) {
586 static int frames
= 0;
587 static double tRot0
= -1.0, tRate0
= -1.0;
588 double dt
, t
= current_time();
595 /* advance rotation for next frame */
596 angle
+= 70.0 * dt
; /* 70 degrees per second */
601 switch (surface_type
) {
603 eglSwapBuffers(eman
->dpy
, eman
->win
);
605 case EGL_PBUFFER_BIT
:
607 if (!eglCopyBuffers(eman
->dpy
, eman
->pbuf
, eman
->xpix
))
612 for (x
= 0; x
< w
; x
+= orig_w
) {
613 for (y
= 0; y
< h
; y
+= orig_h
) {
614 XCopyArea(eman
->xdpy
, eman
->xpix
, eman
->xwin
, gc
,
615 0, 0, orig_w
, orig_h
, x
, y
);
625 if (t
- tRate0
>= 5.0) {
626 GLfloat seconds
= t
- tRate0
;
627 GLfloat fps
= frames
/ seconds
;
628 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames
, seconds
,
636 XFreeGC(eman
->xdpy
, gc
);
644 printf(" -display <displayname> set the display to run on\n");
645 printf(" -fullscreen run in fullscreen mode\n");
646 printf(" -info display OpenGL renderer info\n");
647 printf(" -pixmap use pixmap surface\n");
648 printf(" -pbuffer use pbuffer surface\n");
653 main(int argc
, char *argv
[])
655 const int winWidth
= 300, winHeight
= 300;
657 char *dpyName
= NULL
;
658 struct egl_manager
*eman
;
660 EGL_SURFACE_TYPE
, 0, /* filled later */
665 EGL_RENDERABLE_TYPE
, EGL_OPENGL_BIT
,
668 char win_title
[] = "xeglgears (window/pixmap/pbuffer)";
669 EGLint surface_type
= EGL_WINDOW_BIT
;
670 GLboolean printInfo
= GL_FALSE
;
671 GLboolean fullscreen
= GL_FALSE
;
675 for (i
= 1; i
< argc
; i
++) {
676 if (strcmp(argv
[i
], "-display") == 0) {
680 else if (strcmp(argv
[i
], "-info") == 0) {
683 else if (strcmp(argv
[i
], "-fullscreen") == 0) {
684 fullscreen
= GL_TRUE
;
686 else if (strcmp(argv
[i
], "-pixmap") == 0) {
687 surface_type
= EGL_PIXMAP_BIT
;
689 else if (strcmp(argv
[i
], "-pbuffer") == 0) {
690 surface_type
= EGL_PBUFFER_BIT
;
698 /* set surface type */
699 attribs
[1] = surface_type
;
701 x_dpy
= XOpenDisplay(dpyName
);
703 printf("Error: couldn't open display %s\n",
704 dpyName
? dpyName
: getenv("DISPLAY"));
708 eglBindAPI(EGL_OPENGL_API
);
710 eman
= egl_manager_new(x_dpy
, attribs
, printInfo
);
712 XCloseDisplay(x_dpy
);
716 snprintf(win_title
, sizeof(win_title
), "xeglgears (%s)",
717 (surface_type
== EGL_WINDOW_BIT
) ? "window" :
718 (surface_type
== EGL_PIXMAP_BIT
) ? "pixmap" : "pbuffer");
720 /* create surface(s) */
721 switch (surface_type
) {
723 ret
= egl_manager_create_window(eman
, win_title
, winWidth
, winHeight
,
724 EGL_TRUE
, fullscreen
, NULL
);
726 ret
= eglMakeCurrent(eman
->dpy
, eman
->win
, eman
->win
, eman
->ctx
);
729 ret
= (egl_manager_create_window(eman
, win_title
, winWidth
, winHeight
,
730 EGL_FALSE
, fullscreen
, NULL
) &&
731 egl_manager_create_pixmap(eman
, eman
->xwin
,
734 ret
= eglMakeCurrent(eman
->dpy
, eman
->pix
, eman
->pix
, eman
->ctx
);
736 case EGL_PBUFFER_BIT
:
738 EGLint pbuf_attribs
[] = {
740 EGL_HEIGHT
, winHeight
,
743 ret
= (egl_manager_create_window(eman
, win_title
, winWidth
, winHeight
,
744 EGL_FALSE
, fullscreen
, NULL
) &&
745 egl_manager_create_pixmap(eman
, eman
->xwin
,
747 egl_manager_create_pbuffer(eman
, pbuf_attribs
));
749 ret
= eglMakeCurrent(eman
->dpy
, eman
->pbuf
, eman
->pbuf
, eman
->ctx
);
758 egl_manager_destroy(eman
);
759 XCloseDisplay(x_dpy
);
764 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
765 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
766 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
771 /* Set initial projection/viewing transformation.
772 * We can't be sure we'll get a ConfigureNotify event when the window
775 reshape(winWidth
, winHeight
);
777 event_loop(eman
, surface_type
, winWidth
, winHeight
);
779 glDeleteLists(gear1
, 1);
780 glDeleteLists(gear2
, 1);
781 glDeleteLists(gear3
, 1);
783 egl_manager_destroy(eman
);
784 XCloseDisplay(x_dpy
);