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 static PFNGLXCHOOSEFBCONFIGPROC choose_fbconfig
= NULL
;
50 static PFNGLXGETVISUALFROMFBCONFIGPROC get_visual_from_fbconfig
= NULL
;
51 static PFNGLXCREATENEWCONTEXTPROC create_new_context
= NULL
;
52 static PFNGLXCREATEWINDOWPROC create_window
= NULL
;
53 static PFNGLXDESTROYWINDOWPROC destroy_window
= NULL
;
59 /* XXX this probably isn't very portable */
64 /* return current time (in seconds) */
70 (void) gettimeofday(&tv
, NULL
);
73 (void) gettimeofday(&tv
, &tz
);
75 return (int) tv
.tv_sec
;
92 #define M_PI 3.14159265
96 static GLfloat view_rotx
= 20.0, view_roty
= 30.0, view_rotz
= 0.0;
97 static GLint gear1
, gear2
, gear3
;
98 static GLfloat angle
= 0.0;
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 h
= (GLfloat
) height
/ (GLfloat
) width
;
278 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
279 glMatrixMode(GL_PROJECTION
);
281 glFrustum(-1.0, 1.0, -h
, h
, 5.0, 60.0);
282 glMatrixMode(GL_MODELVIEW
);
284 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
);
326 dummy_create_window(Display
*dpy
, GLXFBConfig config
, Window win
,
327 const int *attrib_list
)
333 return (GLXWindow
) win
;
338 dummy_destroy_window(Display
*dpy
, GLXWindow win
)
346 * Initialize fbconfig related function pointers.
349 init_fbconfig_functions(Display
*dpy
, int scrnum
)
351 const char * glx_extensions
;
353 static const char ext_name
[] = "GLX_SGIX_fbconfig";
354 const size_t len
= strlen( ext_name
);
357 GLboolean ext_version_supported
;
358 GLboolean glx_1_3_supported
;
361 /* Determine if GLX 1.3 or greater is supported.
363 glXQueryVersion(dpy
, & major
, & minor
);
364 glx_1_3_supported
= (major
== 1) && (minor
>= 3);
366 /* Determine if GLX_SGIX_fbconfig is supported.
368 glx_extensions
= glXQueryExtensionsString(dpy
, scrnum
);
369 match
= strstr( glx_extensions
, ext_name
);
371 ext_version_supported
= (match
!= NULL
)
372 && ((match
[len
] == '\0') || (match
[len
] == ' '));
374 printf( "GLX 1.3 is %ssupported.\n",
375 (glx_1_3_supported
) ? "" : "not " );
376 printf( "%s is %ssupported.\n",
377 ext_name
, (ext_version_supported
) ? "" : "not " );
379 if ( glx_1_3_supported
) {
380 choose_fbconfig
= (PFNGLXCHOOSEFBCONFIGPROC
)
381 glXGetProcAddressARB((GLubyte
*) "glXChooseFBConfig");
382 get_visual_from_fbconfig
= (PFNGLXGETVISUALFROMFBCONFIGPROC
)
383 glXGetProcAddressARB((GLubyte
*) "glXGetVisualFromFBConfig");
384 create_new_context
= (PFNGLXCREATENEWCONTEXTPROC
)
385 glXGetProcAddressARB((GLubyte
*) "glXCreateNewContext");
386 create_window
= (PFNGLXCREATEWINDOWPROC
)
387 glXGetProcAddressARB((GLubyte
*) "glXCreateWindow");
388 destroy_window
= (PFNGLXDESTROYWINDOWPROC
)
389 glXGetProcAddressARB((GLubyte
*) "glXDestroyWindow");
391 else if ( ext_version_supported
) {
392 choose_fbconfig
= (PFNGLXCHOOSEFBCONFIGPROC
)
393 glXGetProcAddressARB((GLubyte
*) "glXChooseFBConfigSGIX");
394 get_visual_from_fbconfig
= (PFNGLXGETVISUALFROMFBCONFIGPROC
)
395 glXGetProcAddressARB((GLubyte
*) "glXGetVisualFromFBConfigSGIX");
396 create_new_context
= (PFNGLXCREATENEWCONTEXTPROC
)
397 glXGetProcAddressARB((GLubyte
*) "glXCreateContextWithConfigSGIX");
398 create_window
= dummy_create_window
;
399 destroy_window
= dummy_destroy_window
;
402 printf( "This demo requires either GLX 1.3 or %s be supported.\n",
407 if ( choose_fbconfig
== NULL
) {
408 printf( "glXChooseFBConfig not found!\n" );
412 if ( get_visual_from_fbconfig
== NULL
) {
413 printf( "glXGetVisualFromFBConfig not found!\n" );
417 if ( create_new_context
== NULL
) {
418 printf( "glXCreateNewContext not found!\n" );
425 * Create an RGB, double-buffered window.
426 * Return the window and context handles.
429 make_window( Display
*dpy
, const char *name
,
430 int x
, int y
, int width
, int height
,
431 Window
*winRet
, GLXWindow
*glxWinRet
, GLXContext
*ctxRet
)
433 int attrib
[] = { GLX_DRAWABLE_TYPE
, GLX_WINDOW_BIT
,
434 GLX_RENDER_TYPE
, GLX_RGBA_BIT
,
438 GLX_DOUBLEBUFFER
, GL_TRUE
,
441 GLXFBConfig
* fbconfig
;
445 XSetWindowAttributes attr
;
451 XVisualInfo
*visinfo
;
453 scrnum
= DefaultScreen( dpy
);
454 root
= RootWindow( dpy
, scrnum
);
456 init_fbconfig_functions(dpy
, scrnum
);
457 fbconfig
= (*choose_fbconfig
)(dpy
, scrnum
, attrib
, & num_configs
);
458 if (fbconfig
== NULL
) {
459 printf("Error: couldn't get an RGB, Double-buffered visual\n");
463 printf("\nThe following fbconfigs meet the requirements. The first one "
464 "will be used.\n\n");
465 for ( i
= 0 ; i
< num_configs
; i
++ ) {
466 PrintFBConfigInfo(dpy
, scrnum
, fbconfig
[i
], GL_TRUE
);
469 /* window attributes */
470 visinfo
= (*get_visual_from_fbconfig
)(dpy
, fbconfig
[0]);
471 assert(visinfo
!= NULL
);
472 attr
.background_pixel
= 0;
473 attr
.border_pixel
= 0;
474 attr
.colormap
= XCreateColormap( dpy
, root
, visinfo
->visual
, AllocNone
);
475 attr
.event_mask
= StructureNotifyMask
| ExposureMask
| KeyPressMask
;
476 mask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWEventMask
;
478 win
= XCreateWindow( dpy
, root
, 0, 0, width
, height
,
479 0, visinfo
->depth
, InputOutput
,
480 visinfo
->visual
, mask
, &attr
);
482 /* set hints and properties */
484 XSizeHints sizehints
;
487 sizehints
.width
= width
;
488 sizehints
.height
= height
;
489 sizehints
.flags
= USSize
| USPosition
;
490 XSetNormalHints(dpy
, win
, &sizehints
);
491 XSetStandardProperties(dpy
, win
, name
, name
,
492 None
, (char **)NULL
, 0, &sizehints
);
495 glxWin
= (*create_window
)(dpy
, fbconfig
[0], win
, NULL
);
497 ctx
= (*create_new_context
)(dpy
, fbconfig
[0], GLX_RGBA_TYPE
, NULL
, GL_TRUE
);
499 printf("Error: glXCreateNewContext failed\n");
512 event_loop(Display
*dpy
, GLXWindow win
)
515 while (XPending(dpy
) > 0) {
517 XNextEvent(dpy
, &event
);
518 switch (event
.type
) {
520 /* we'll redraw below */
522 case ConfigureNotify
:
523 reshape(event
.xconfigure
.width
, event
.xconfigure
.height
);
529 code
= XLookupKeysym(&event
.xkey
, 0);
530 if (code
== XK_Left
) {
533 else if (code
== XK_Right
) {
536 else if (code
== XK_Up
) {
539 else if (code
== XK_Down
) {
543 XLookupString(&event
.xkey
, buffer
, sizeof(buffer
),
545 if (buffer
[0] == 27) {
558 glXSwapBuffers(dpy
, win
);
563 static int frames
= 0;
564 int t
= current_time();
572 GLfloat seconds
= t
- t0
;
573 GLfloat fps
= frames
/ seconds
;
574 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames
, seconds
,
586 main(int argc
, char *argv
[])
592 const char *dpyName
= NULL
;
593 GLboolean printInfo
= GL_FALSE
;
596 for (i
= 1; i
< argc
; i
++) {
597 if (strcmp(argv
[i
], "-display") == 0) {
601 else if (strcmp(argv
[i
], "-info") == 0) {
606 dpy
= XOpenDisplay(dpyName
);
608 printf("Error: couldn't open display %s\n", XDisplayName(dpyName
));
612 make_window(dpy
, "glxgears", 0, 0, 300, 300, &win
, &glxWin
, &ctx
);
613 XMapWindow(dpy
, win
);
614 glXMakeCurrent(dpy
, glxWin
, ctx
);
617 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
618 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
619 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
620 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS
));
625 event_loop(dpy
, glxWin
);
627 glXDestroyContext(dpy
, ctx
);
628 destroy_window(dpy
, glxWin
);
629 XDestroyWindow(dpy
, win
);