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 * \file glxgears_fbconfig.c
24 * Yet-another-version of gears. Originally ported to GLX by Brian Paul on
25 * 23 March 2001. Modified to use fbconfigs by Ian Romanick on 10 Feb 2004.
27 * Command line options:
28 * -info print GL implementation information
31 * \author Ian Romanick <idr@us.ibm.com>
35 #define GLX_GLXEXT_PROTOTYPES
42 #include <X11/keysym.h>
45 #include <GL/glxext.h>
49 /* I had to use the SGIX versions of these because for some reason glxext.h
50 * doesn't define the core versions if GLX_VERSION_1_3 is defined, and glx.h
51 * doesn't define them at all. One or both header files is clearly broken.
53 static PFNGLXCHOOSEFBCONFIGSGIXPROC choose_fbconfig
= NULL
;
54 static PFNGLXGETVISUALFROMFBCONFIGSGIXPROC get_visual_from_fbconfig
= NULL
;
55 static PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC create_new_context
= NULL
;
61 /* XXX this probably isn't very portable */
66 /* return current time (in seconds) */
72 (void) gettimeofday(&tv
, NULL
);
75 (void) gettimeofday(&tv
, &tz
);
77 return (int) tv
.tv_sec
;
94 #define M_PI 3.14159265
98 static GLfloat view_rotx
= 20.0, view_roty
= 30.0, view_rotz
= 0.0;
99 static GLint gear1
, gear2
, gear3
;
100 static GLfloat angle
= 0.0;
105 * Draw a gear wheel. You'll probably want to call this function when
106 * building a display list since we do a lot of trig here.
108 * Input: inner_radius - radius of hole at center
109 * outer_radius - radius at center of teeth
110 * width - width of gear
111 * teeth - number of teeth
112 * tooth_depth - depth of tooth
115 gear(GLfloat inner_radius
, GLfloat outer_radius
, GLfloat width
,
116 GLint teeth
, GLfloat tooth_depth
)
124 r1
= outer_radius
- tooth_depth
/ 2.0;
125 r2
= outer_radius
+ tooth_depth
/ 2.0;
127 da
= 2.0 * M_PI
/ teeth
/ 4.0;
129 glShadeModel(GL_FLAT
);
131 glNormal3f(0.0, 0.0, 1.0);
133 /* draw front face */
134 glBegin(GL_QUAD_STRIP
);
135 for (i
= 0; i
<= teeth
; i
++) {
136 angle
= i
* 2.0 * M_PI
/ teeth
;
137 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
138 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
140 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
141 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
147 /* draw front sides of teeth */
149 da
= 2.0 * M_PI
/ teeth
/ 4.0;
150 for (i
= 0; i
< teeth
; i
++) {
151 angle
= i
* 2.0 * M_PI
/ teeth
;
153 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
154 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
155 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
157 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
162 glNormal3f(0.0, 0.0, -1.0);
165 glBegin(GL_QUAD_STRIP
);
166 for (i
= 0; i
<= teeth
; i
++) {
167 angle
= i
* 2.0 * M_PI
/ teeth
;
168 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
169 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
171 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
173 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
178 /* draw back sides of teeth */
180 da
= 2.0 * M_PI
/ teeth
/ 4.0;
181 for (i
= 0; i
< teeth
; i
++) {
182 angle
= i
* 2.0 * M_PI
/ teeth
;
184 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
186 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
188 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
189 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
193 /* draw outward faces of teeth */
194 glBegin(GL_QUAD_STRIP
);
195 for (i
= 0; i
< teeth
; i
++) {
196 angle
= i
* 2.0 * M_PI
/ teeth
;
198 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
199 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
200 u
= r2
* cos(angle
+ da
) - r1
* cos(angle
);
201 v
= r2
* sin(angle
+ da
) - r1
* sin(angle
);
202 len
= sqrt(u
* u
+ v
* v
);
205 glNormal3f(v
, -u
, 0.0);
206 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
207 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
208 glNormal3f(cos(angle
), sin(angle
), 0.0);
209 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
211 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
213 u
= r1
* cos(angle
+ 3 * da
) - r2
* cos(angle
+ 2 * da
);
214 v
= r1
* sin(angle
+ 3 * da
) - r2
* sin(angle
+ 2 * da
);
215 glNormal3f(v
, -u
, 0.0);
216 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
218 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
220 glNormal3f(cos(angle
), sin(angle
), 0.0);
223 glVertex3f(r1
* cos(0), r1
* sin(0), width
* 0.5);
224 glVertex3f(r1
* cos(0), r1
* sin(0), -width
* 0.5);
228 glShadeModel(GL_SMOOTH
);
230 /* draw inside radius cylinder */
231 glBegin(GL_QUAD_STRIP
);
232 for (i
= 0; i
<= teeth
; i
++) {
233 angle
= i
* 2.0 * M_PI
/ teeth
;
234 glNormal3f(-cos(angle
), -sin(angle
), 0.0);
235 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
236 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
245 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
248 glRotatef(view_rotx
, 1.0, 0.0, 0.0);
249 glRotatef(view_roty
, 0.0, 1.0, 0.0);
250 glRotatef(view_rotz
, 0.0, 0.0, 1.0);
253 glTranslatef(-3.0, -2.0, 0.0);
254 glRotatef(angle
, 0.0, 0.0, 1.0);
259 glTranslatef(3.1, -2.0, 0.0);
260 glRotatef(-2.0 * angle
- 9.0, 0.0, 0.0, 1.0);
265 glTranslatef(-3.1, 4.2, 0.0);
266 glRotatef(-2.0 * angle
- 25.0, 0.0, 0.0, 1.0);
274 /* new window size or exposure */
276 reshape(int width
, int height
)
278 GLfloat h
= (GLfloat
) height
/ (GLfloat
) width
;
280 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
281 glMatrixMode(GL_PROJECTION
);
283 glFrustum(-1.0, 1.0, -h
, h
, 5.0, 60.0);
284 glMatrixMode(GL_MODELVIEW
);
286 glTranslatef(0.0, 0.0, -40.0);
293 static GLfloat pos
[4] = { 5.0, 5.0, 10.0, 0.0 };
294 static GLfloat red
[4] = { 0.8, 0.1, 0.0, 1.0 };
295 static GLfloat green
[4] = { 0.0, 0.8, 0.2, 1.0 };
296 static GLfloat blue
[4] = { 0.2, 0.2, 1.0, 1.0 };
298 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
299 glEnable(GL_CULL_FACE
);
300 glEnable(GL_LIGHTING
);
302 glEnable(GL_DEPTH_TEST
);
305 gear1
= glGenLists(1);
306 glNewList(gear1
, GL_COMPILE
);
307 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, red
);
308 gear(1.0, 4.0, 1.0, 20, 0.7);
311 gear2
= glGenLists(1);
312 glNewList(gear2
, GL_COMPILE
);
313 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, green
);
314 gear(0.5, 2.0, 2.0, 10, 0.7);
317 gear3
= glGenLists(1);
318 glNewList(gear3
, GL_COMPILE
);
319 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, blue
);
320 gear(1.3, 2.0, 0.5, 10, 0.7);
323 glEnable(GL_NORMALIZE
);
328 * Initialize fbconfig related function pointers.
331 init_fbconfig_functions(Display
*dpy
, int scrnum
)
333 const char * glx_extensions
;
335 static const char ext_name
[] = "GLX_SGIX_fbconfig";
336 const size_t len
= strlen( ext_name
);
339 GLboolean ext_version_supported
;
340 GLboolean glx_1_3_supported
;
343 /* Determine if GLX 1.3 or greater is supported.
345 glXQueryVersion(dpy
, & major
, & minor
);
346 glx_1_3_supported
= (major
== 1) && (minor
>= 3);
348 /* Determine if GLX_SGIX_fbconfig is supported.
350 glx_extensions
= glXQueryExtensionsString(dpy
, scrnum
);
351 match
= strstr( glx_extensions
, ext_name
);
353 ext_version_supported
= (match
!= NULL
)
354 && ((match
[len
] == '\0') || (match
[len
] == ' '));
356 printf( "GLX 1.3 is %ssupported.\n",
357 (glx_1_3_supported
) ? "" : "not " );
358 printf( "%s is %ssupported.\n",
359 ext_name
, (ext_version_supported
) ? "" : "not " );
361 if ( glx_1_3_supported
) {
362 choose_fbconfig
= (PFNGLXCHOOSEFBCONFIGSGIXPROC
) glXGetProcAddressARB(
363 (GLubyte
*) "glXChooseFBConfig");
364 get_visual_from_fbconfig
= (PFNGLXGETVISUALFROMFBCONFIGSGIXPROC
) glXGetProcAddressARB(
365 (GLubyte
*) "glXGetVisualFromFBConfig");
366 create_new_context
= (PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC
) glXGetProcAddressARB(
367 (GLubyte
*) "glXCreateNewContext");
369 else if ( ext_version_supported
) {
370 choose_fbconfig
= (PFNGLXCHOOSEFBCONFIGSGIXPROC
) glXGetProcAddressARB(
371 (GLubyte
*) "glXChooseFBConfigSGIX");
372 get_visual_from_fbconfig
= (PFNGLXGETVISUALFROMFBCONFIGSGIXPROC
) glXGetProcAddressARB(
373 (GLubyte
*) "glXGetVisualFromFBConfigSGIX");
374 create_new_context
= (PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC
) glXGetProcAddressARB(
375 (GLubyte
*) "glXCreateContextWithConfigSGIX");
378 printf( "This demo requires either GLX 1.3 or %s be supported.\n",
383 if ( choose_fbconfig
== NULL
) {
384 printf( "glXChooseFBConfig not found!\n" );
388 if ( get_visual_from_fbconfig
== NULL
) {
389 printf( "glXGetVisualFromFBConfig not found!\n" );
393 if ( create_new_context
== NULL
) {
394 printf( "glXCreateNewContext not found!\n" );
401 * Create an RGB, double-buffered window.
402 * Return the window and context handles.
405 make_window( Display
*dpy
, const char *name
,
406 int x
, int y
, int width
, int height
,
407 Window
*winRet
, GLXContext
*ctxRet
)
409 int attrib
[] = { GLX_DRAWABLE_TYPE
, GLX_WINDOW_BIT
,
410 GLX_RENDER_TYPE
, GLX_RGBA_BIT
,
414 GLX_DOUBLEBUFFER
, GL_TRUE
,
417 GLXFBConfig
* fbconfig
;
421 XSetWindowAttributes attr
;
426 XVisualInfo
*visinfo
;
428 scrnum
= DefaultScreen( dpy
);
429 root
= RootWindow( dpy
, scrnum
);
431 init_fbconfig_functions(dpy
, scrnum
);
432 fbconfig
= (*choose_fbconfig
)(dpy
, scrnum
, attrib
, & num_configs
);
433 if (fbconfig
== NULL
) {
434 printf("Error: couldn't get an RGB, Double-buffered visual\n");
438 printf("\nThe following fbconfigs meet the requirements. The first one "
439 "will be used.\n\n");
440 for ( i
= 0 ; i
< num_configs
; i
++ ) {
441 PrintFBConfigInfo(dpy
, scrnum
, fbconfig
[i
], GL_TRUE
);
444 /* window attributes */
445 visinfo
= (*get_visual_from_fbconfig
)(dpy
, fbconfig
[0]);
446 assert(visinfo
!= NULL
);
447 attr
.background_pixel
= 0;
448 attr
.border_pixel
= 0;
449 attr
.colormap
= XCreateColormap( dpy
, root
, visinfo
->visual
, AllocNone
);
450 attr
.event_mask
= StructureNotifyMask
| ExposureMask
| KeyPressMask
;
451 mask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWEventMask
;
453 win
= XCreateWindow( dpy
, root
, 0, 0, width
, height
,
454 0, visinfo
->depth
, InputOutput
,
455 visinfo
->visual
, mask
, &attr
);
457 /* set hints and properties */
459 XSizeHints sizehints
;
462 sizehints
.width
= width
;
463 sizehints
.height
= height
;
464 sizehints
.flags
= USSize
| USPosition
;
465 XSetNormalHints(dpy
, win
, &sizehints
);
466 XSetStandardProperties(dpy
, win
, name
, name
,
467 None
, (char **)NULL
, 0, &sizehints
);
470 ctx
= (*create_new_context
)(dpy
, fbconfig
[0], GLX_RGBA_BIT
, NULL
, GL_TRUE
);
472 printf("Error: glXCreateNewContext failed\n");
484 event_loop(Display
*dpy
, Window win
)
487 while (XPending(dpy
) > 0) {
489 XNextEvent(dpy
, &event
);
490 switch (event
.type
) {
492 /* we'll redraw below */
494 case ConfigureNotify
:
495 reshape(event
.xconfigure
.width
, event
.xconfigure
.height
);
501 code
= XLookupKeysym(&event
.xkey
, 0);
502 if (code
== XK_Left
) {
505 else if (code
== XK_Right
) {
508 else if (code
== XK_Up
) {
511 else if (code
== XK_Down
) {
515 r
= XLookupString(&event
.xkey
, buffer
, sizeof(buffer
),
517 if (buffer
[0] == 27) {
530 glXSwapBuffers(dpy
, win
);
535 static int frames
= 0;
536 int t
= current_time();
544 GLfloat seconds
= t
- t0
;
545 GLfloat fps
= frames
/ seconds
;
546 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames
, seconds
,
557 main(int argc
, char *argv
[])
562 const char *dpyName
= NULL
;
563 GLboolean printInfo
= GL_FALSE
;
566 for (i
= 1; i
< argc
; i
++) {
567 if (strcmp(argv
[i
], "-display") == 0) {
571 else if (strcmp(argv
[i
], "-info") == 0) {
576 dpy
= XOpenDisplay(dpyName
);
578 printf("Error: couldn't open display %s\n", dpyName
);
582 make_window(dpy
, "glxgears", 0, 0, 300, 300, &win
, &ctx
);
583 XMapWindow(dpy
, win
);
584 glXMakeCurrent(dpy
, win
, ctx
);
587 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
588 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
589 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
590 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS
));
595 event_loop(dpy
, win
);
597 glXDestroyContext(dpy
, ctx
);
598 XDestroyWindow(dpy
, win
);