mesa: Add "shader/" path to #include statements in shader parser/lexer sources
[mesa.git] / progs / xdemos / glxgears.c
1 /*
2 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
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.
20 */
21
22 /*
23 * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
24 * Port by Brian Paul 23 March 2001
25 *
26 * See usage() below for command line options.
27 */
28
29
30 #include <math.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <X11/Xlib.h>
35 #include <X11/keysym.h>
36 #include <GL/gl.h>
37 #include <GL/glx.h>
38
39 #ifndef GLX_MESA_swap_control
40 #define GLX_MESA_swap_control 1
41 typedef int (*PFNGLXGETSWAPINTERVALMESAPROC)(void);
42 #endif
43
44
45 #define BENCHMARK
46
47 #ifdef BENCHMARK
48
49 /* XXX this probably isn't very portable */
50
51 #include <sys/time.h>
52 #include <unistd.h>
53
54 /* return current time (in seconds) */
55 static double
56 current_time(void)
57 {
58 struct timeval tv;
59 #ifdef __VMS
60 (void) gettimeofday(&tv, NULL );
61 #else
62 struct timezone tz;
63 (void) gettimeofday(&tv, &tz);
64 #endif
65 return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
66 }
67
68 #else /*BENCHMARK*/
69
70 /* dummy */
71 static double
72 current_time(void)
73 {
74 /* update this function for other platforms! */
75 static double t = 0.0;
76 static int warn = 1;
77 if (warn) {
78 fprintf(stderr, "Warning: current_time() not implemented!!\n");
79 warn = 0;
80 }
81 return t += 1.0;
82 }
83
84 #endif /*BENCHMARK*/
85
86
87
88 #ifndef M_PI
89 #define M_PI 3.14159265
90 #endif
91
92
93 /** Event handler results: */
94 #define NOP 0
95 #define EXIT 1
96 #define DRAW 2
97
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;
101
102 static GLboolean fullscreen = GL_FALSE; /* Create a single fullscreen window */
103 static GLboolean stereo = GL_FALSE; /* Enable stereo. */
104 static GLboolean animate = GL_TRUE; /* Animation */
105 static GLfloat eyesep = 5.0; /* Eye separation. */
106 static GLfloat fix_point = 40.0; /* Fixation point distance. */
107 static GLfloat left, right, asp; /* Stereo frustum params. */
108
109
110 /*
111 *
112 * Draw a gear wheel. You'll probably want to call this function when
113 * building a display list since we do a lot of trig here.
114 *
115 * Input: inner_radius - radius of hole at center
116 * outer_radius - radius at center of teeth
117 * width - width of gear
118 * teeth - number of teeth
119 * tooth_depth - depth of tooth
120 */
121 static void
122 gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
123 GLint teeth, GLfloat tooth_depth)
124 {
125 GLint i;
126 GLfloat r0, r1, r2;
127 GLfloat angle, da;
128 GLfloat u, v, len;
129
130 r0 = inner_radius;
131 r1 = outer_radius - tooth_depth / 2.0;
132 r2 = outer_radius + tooth_depth / 2.0;
133
134 da = 2.0 * M_PI / teeth / 4.0;
135
136 glShadeModel(GL_FLAT);
137
138 glNormal3f(0.0, 0.0, 1.0);
139
140 /* draw front face */
141 glBegin(GL_QUAD_STRIP);
142 for (i = 0; i <= teeth; i++) {
143 angle = i * 2.0 * M_PI / teeth;
144 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
145 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
146 if (i < teeth) {
147 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
148 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
149 width * 0.5);
150 }
151 }
152 glEnd();
153
154 /* draw front sides of teeth */
155 glBegin(GL_QUADS);
156 da = 2.0 * M_PI / teeth / 4.0;
157 for (i = 0; i < teeth; i++) {
158 angle = i * 2.0 * M_PI / teeth;
159
160 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
161 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
162 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
163 width * 0.5);
164 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
165 width * 0.5);
166 }
167 glEnd();
168
169 glNormal3f(0.0, 0.0, -1.0);
170
171 /* draw back face */
172 glBegin(GL_QUAD_STRIP);
173 for (i = 0; i <= teeth; i++) {
174 angle = i * 2.0 * M_PI / teeth;
175 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
176 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
177 if (i < teeth) {
178 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
179 -width * 0.5);
180 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
181 }
182 }
183 glEnd();
184
185 /* draw back sides of teeth */
186 glBegin(GL_QUADS);
187 da = 2.0 * M_PI / teeth / 4.0;
188 for (i = 0; i < teeth; i++) {
189 angle = i * 2.0 * M_PI / teeth;
190
191 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
192 -width * 0.5);
193 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
194 -width * 0.5);
195 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
196 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
197 }
198 glEnd();
199
200 /* draw outward faces of teeth */
201 glBegin(GL_QUAD_STRIP);
202 for (i = 0; i < teeth; i++) {
203 angle = i * 2.0 * M_PI / teeth;
204
205 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
206 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
207 u = r2 * cos(angle + da) - r1 * cos(angle);
208 v = r2 * sin(angle + da) - r1 * sin(angle);
209 len = sqrt(u * u + v * v);
210 u /= len;
211 v /= len;
212 glNormal3f(v, -u, 0.0);
213 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
214 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
215 glNormal3f(cos(angle), sin(angle), 0.0);
216 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
217 width * 0.5);
218 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
219 -width * 0.5);
220 u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
221 v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
222 glNormal3f(v, -u, 0.0);
223 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
224 width * 0.5);
225 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
226 -width * 0.5);
227 glNormal3f(cos(angle), sin(angle), 0.0);
228 }
229
230 glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
231 glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
232
233 glEnd();
234
235 glShadeModel(GL_SMOOTH);
236
237 /* draw inside radius cylinder */
238 glBegin(GL_QUAD_STRIP);
239 for (i = 0; i <= teeth; i++) {
240 angle = i * 2.0 * M_PI / teeth;
241 glNormal3f(-cos(angle), -sin(angle), 0.0);
242 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
243 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
244 }
245 glEnd();
246 }
247
248
249 static void
250 draw(void)
251 {
252 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
253
254 glPushMatrix();
255 glRotatef(view_rotx, 1.0, 0.0, 0.0);
256 glRotatef(view_roty, 0.0, 1.0, 0.0);
257 glRotatef(view_rotz, 0.0, 0.0, 1.0);
258
259 glPushMatrix();
260 glTranslatef(-3.0, -2.0, 0.0);
261 glRotatef(angle, 0.0, 0.0, 1.0);
262 glCallList(gear1);
263 glPopMatrix();
264
265 glPushMatrix();
266 glTranslatef(3.1, -2.0, 0.0);
267 glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
268 glCallList(gear2);
269 glPopMatrix();
270
271 glPushMatrix();
272 glTranslatef(-3.1, 4.2, 0.0);
273 glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
274 glCallList(gear3);
275 glPopMatrix();
276
277 glPopMatrix();
278 }
279
280
281 static void
282 draw_gears(void)
283 {
284 if (stereo) {
285 /* First left eye. */
286 glDrawBuffer(GL_BACK_LEFT);
287
288 glMatrixMode(GL_PROJECTION);
289 glLoadIdentity();
290 glFrustum(left, right, -asp, asp, 5.0, 60.0);
291
292 glMatrixMode(GL_MODELVIEW);
293
294 glPushMatrix();
295 glTranslated(+0.5 * eyesep, 0.0, 0.0);
296 draw();
297 glPopMatrix();
298
299 /* Then right eye. */
300 glDrawBuffer(GL_BACK_RIGHT);
301
302 glMatrixMode(GL_PROJECTION);
303 glLoadIdentity();
304 glFrustum(-right, -left, -asp, asp, 5.0, 60.0);
305
306 glMatrixMode(GL_MODELVIEW);
307
308 glPushMatrix();
309 glTranslated(-0.5 * eyesep, 0.0, 0.0);
310 draw();
311 glPopMatrix();
312 }
313 else {
314 draw();
315 }
316 }
317
318
319 /** Draw single frame, do SwapBuffers, compute FPS */
320 static void
321 draw_frame(Display *dpy, Window win)
322 {
323 static int frames = 0;
324 static double tRot0 = -1.0, tRate0 = -1.0;
325 double dt, t = current_time();
326
327 if (tRot0 < 0.0)
328 tRot0 = t;
329 dt = t - tRot0;
330 tRot0 = t;
331
332 if (animate) {
333 /* advance rotation for next frame */
334 angle += 70.0 * dt; /* 70 degrees per second */
335 if (angle > 3600.0)
336 angle -= 3600.0;
337 }
338
339 draw_gears();
340 glXSwapBuffers(dpy, win);
341
342 frames++;
343
344 if (tRate0 < 0.0)
345 tRate0 = t;
346 if (t - tRate0 >= 5.0) {
347 GLfloat seconds = t - tRate0;
348 GLfloat fps = frames / seconds;
349 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
350 fps);
351 tRate0 = t;
352 frames = 0;
353 }
354 }
355
356
357 /* new window size or exposure */
358 static void
359 reshape(int width, int height)
360 {
361 glViewport(0, 0, (GLint) width, (GLint) height);
362
363 if (stereo) {
364 GLfloat w;
365
366 asp = (GLfloat) height / (GLfloat) width;
367 w = fix_point * (1.0 / 5.0);
368
369 left = -5.0 * ((w - 0.5 * eyesep) / fix_point);
370 right = 5.0 * ((w + 0.5 * eyesep) / fix_point);
371 }
372 else {
373 GLfloat h = (GLfloat) height / (GLfloat) width;
374
375 glMatrixMode(GL_PROJECTION);
376 glLoadIdentity();
377 glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
378 }
379
380 glMatrixMode(GL_MODELVIEW);
381 glLoadIdentity();
382 glTranslatef(0.0, 0.0, -40.0);
383 }
384
385
386
387 static void
388 init(void)
389 {
390 static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
391 static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
392 static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
393 static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
394
395 glLightfv(GL_LIGHT0, GL_POSITION, pos);
396 glEnable(GL_CULL_FACE);
397 glEnable(GL_LIGHTING);
398 glEnable(GL_LIGHT0);
399 glEnable(GL_DEPTH_TEST);
400
401 /* make the gears */
402 gear1 = glGenLists(1);
403 glNewList(gear1, GL_COMPILE);
404 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
405 gear(1.0, 4.0, 1.0, 20, 0.7);
406 glEndList();
407
408 gear2 = glGenLists(1);
409 glNewList(gear2, GL_COMPILE);
410 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
411 gear(0.5, 2.0, 2.0, 10, 0.7);
412 glEndList();
413
414 gear3 = glGenLists(1);
415 glNewList(gear3, GL_COMPILE);
416 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
417 gear(1.3, 2.0, 0.5, 10, 0.7);
418 glEndList();
419
420 glEnable(GL_NORMALIZE);
421 }
422
423
424 /**
425 * Remove window border/decorations.
426 */
427 static void
428 no_border( Display *dpy, Window w)
429 {
430 static const unsigned MWM_HINTS_DECORATIONS = (1 << 1);
431 static const int PROP_MOTIF_WM_HINTS_ELEMENTS = 5;
432
433 typedef struct
434 {
435 unsigned long flags;
436 unsigned long functions;
437 unsigned long decorations;
438 long inputMode;
439 unsigned long status;
440 } PropMotifWmHints;
441
442 PropMotifWmHints motif_hints;
443 Atom prop, proptype;
444 unsigned long flags = 0;
445
446 /* setup the property */
447 motif_hints.flags = MWM_HINTS_DECORATIONS;
448 motif_hints.decorations = flags;
449
450 /* get the atom for the property */
451 prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
452 if (!prop) {
453 /* something went wrong! */
454 return;
455 }
456
457 /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
458 proptype = prop;
459
460 XChangeProperty( dpy, w, /* display, window */
461 prop, proptype, /* property, type */
462 32, /* format: 32-bit datums */
463 PropModeReplace, /* mode */
464 (unsigned char *) &motif_hints, /* data */
465 PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
466 );
467 }
468
469
470 /*
471 * Create an RGB, double-buffered window.
472 * Return the window and context handles.
473 */
474 static void
475 make_window( Display *dpy, const char *name,
476 int x, int y, int width, int height,
477 Window *winRet, GLXContext *ctxRet)
478 {
479 int attribs[] = { GLX_RGBA,
480 GLX_RED_SIZE, 1,
481 GLX_GREEN_SIZE, 1,
482 GLX_BLUE_SIZE, 1,
483 GLX_DOUBLEBUFFER,
484 GLX_DEPTH_SIZE, 1,
485 None };
486 int stereoAttribs[] = { GLX_RGBA,
487 GLX_RED_SIZE, 1,
488 GLX_GREEN_SIZE, 1,
489 GLX_BLUE_SIZE, 1,
490 GLX_DOUBLEBUFFER,
491 GLX_DEPTH_SIZE, 1,
492 GLX_STEREO,
493 None };
494 int scrnum;
495 XSetWindowAttributes attr;
496 unsigned long mask;
497 Window root;
498 Window win;
499 GLXContext ctx;
500 XVisualInfo *visinfo;
501
502 scrnum = DefaultScreen( dpy );
503 root = RootWindow( dpy, scrnum );
504
505 if (fullscreen) {
506 x = 0; y = 0;
507 width = DisplayWidth( dpy, scrnum );
508 height = DisplayHeight( dpy, scrnum );
509 }
510
511 if (stereo)
512 visinfo = glXChooseVisual( dpy, scrnum, stereoAttribs );
513 else
514 visinfo = glXChooseVisual( dpy, scrnum, attribs );
515 if (!visinfo) {
516 if (stereo) {
517 printf("Error: couldn't get an RGB, "
518 "Double-buffered, Stereo visual\n");
519 } else
520 printf("Error: couldn't get an RGB, Double-buffered visual\n");
521 exit(1);
522 }
523
524 /* window attributes */
525 attr.background_pixel = 0;
526 attr.border_pixel = 0;
527 attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
528 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
529 /* XXX this is a bad way to get a borderless window! */
530 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
531
532 win = XCreateWindow( dpy, root, x, y, width, height,
533 0, visinfo->depth, InputOutput,
534 visinfo->visual, mask, &attr );
535
536 if (fullscreen)
537 no_border(dpy, win);
538
539 /* set hints and properties */
540 {
541 XSizeHints sizehints;
542 sizehints.x = x;
543 sizehints.y = y;
544 sizehints.width = width;
545 sizehints.height = height;
546 sizehints.flags = USSize | USPosition;
547 XSetNormalHints(dpy, win, &sizehints);
548 XSetStandardProperties(dpy, win, name, name,
549 None, (char **)NULL, 0, &sizehints);
550 }
551
552 ctx = glXCreateContext( dpy, visinfo, NULL, True );
553 if (!ctx) {
554 printf("Error: glXCreateContext failed\n");
555 exit(1);
556 }
557
558 XFree(visinfo);
559
560 *winRet = win;
561 *ctxRet = ctx;
562 }
563
564
565 /**
566 * Determine whether or not a GLX extension is supported.
567 */
568 static int
569 is_glx_extension_supported(Display *dpy, const char *query)
570 {
571 const int scrnum = DefaultScreen(dpy);
572 const char *glx_extensions = NULL;
573 const size_t len = strlen(query);
574 const char *ptr;
575
576 if (glx_extensions == NULL) {
577 glx_extensions = glXQueryExtensionsString(dpy, scrnum);
578 }
579
580 ptr = strstr(glx_extensions, query);
581 return ((ptr != NULL) && ((ptr[len] == ' ') || (ptr[len] == '\0')));
582 }
583
584
585 /**
586 * Attempt to determine whether or not the display is synched to vblank.
587 */
588 static void
589 query_vsync(Display *dpy)
590 {
591 int interval = 0;
592
593
594 if (is_glx_extension_supported(dpy, "GLX_MESA_swap_control")) {
595 PFNGLXGETSWAPINTERVALMESAPROC pglXGetSwapIntervalMESA =
596 (PFNGLXGETSWAPINTERVALMESAPROC)
597 glXGetProcAddressARB((const GLubyte *) "glXGetSwapIntervalMESA");
598
599 interval = (*pglXGetSwapIntervalMESA)();
600 } else if (is_glx_extension_supported(dpy, "GLX_SGI_swap_control")) {
601 /* The default swap interval with this extension is 1. Assume that it
602 * is set to the default.
603 *
604 * Many Mesa-based drivers default to 0, but all of these drivers also
605 * export GLX_MESA_swap_control. In that case, this branch will never
606 * be taken, and the correct result should be reported.
607 */
608 interval = 1;
609 }
610
611
612 if (interval > 0) {
613 printf("Running synchronized to the vertical refresh. The framerate should be\n");
614 if (interval == 1) {
615 printf("approximately the same as the monitor refresh rate.\n");
616 } else if (interval > 1) {
617 printf("approximately 1/%d the monitor refresh rate.\n",
618 interval);
619 }
620 }
621 }
622
623 /**
624 * Handle one X event.
625 * \return NOP, EXIT or DRAW
626 */
627 static int
628 handle_event(Display *dpy, Window win, XEvent *event)
629 {
630 (void) dpy;
631 (void) win;
632
633 switch (event->type) {
634 case Expose:
635 return DRAW;
636 case ConfigureNotify:
637 reshape(event->xconfigure.width, event->xconfigure.height);
638 break;
639 case KeyPress:
640 {
641 char buffer[10];
642 int r, code;
643 code = XLookupKeysym(&event->xkey, 0);
644 if (code == XK_Left) {
645 view_roty += 5.0;
646 }
647 else if (code == XK_Right) {
648 view_roty -= 5.0;
649 }
650 else if (code == XK_Up) {
651 view_rotx += 5.0;
652 }
653 else if (code == XK_Down) {
654 view_rotx -= 5.0;
655 }
656 else {
657 r = XLookupString(&event->xkey, buffer, sizeof(buffer),
658 NULL, NULL);
659 if (buffer[0] == 27) {
660 /* escape */
661 return EXIT;
662 }
663 else if (buffer[0] == 'a' || buffer[0] == 'A') {
664 animate = !animate;
665 }
666 }
667 return DRAW;
668 }
669 }
670 return NOP;
671 }
672
673
674 static void
675 event_loop(Display *dpy, Window win)
676 {
677 while (1) {
678 int op;
679 while (!animate || XPending(dpy) > 0) {
680 XEvent event;
681 XNextEvent(dpy, &event);
682 op = handle_event(dpy, win, &event);
683 if (op == EXIT)
684 return;
685 else if (op == DRAW)
686 break;
687 }
688
689 draw_frame(dpy, win);
690 }
691 }
692
693
694 static void
695 usage(void)
696 {
697 printf("Usage:\n");
698 printf(" -display <displayname> set the display to run on\n");
699 printf(" -stereo run in stereo mode\n");
700 printf(" -fullscreen run in fullscreen mode\n");
701 printf(" -info display OpenGL renderer info\n");
702 printf(" -geometry WxH+X+Y window geometry\n");
703 }
704
705
706 int
707 main(int argc, char *argv[])
708 {
709 unsigned int winWidth = 300, winHeight = 300;
710 int x = 0, y = 0;
711 Display *dpy;
712 Window win;
713 GLXContext ctx;
714 char *dpyName = NULL;
715 GLboolean printInfo = GL_FALSE;
716 int i;
717
718 for (i = 1; i < argc; i++) {
719 if (strcmp(argv[i], "-display") == 0) {
720 dpyName = argv[i+1];
721 i++;
722 }
723 else if (strcmp(argv[i], "-info") == 0) {
724 printInfo = GL_TRUE;
725 }
726 else if (strcmp(argv[i], "-stereo") == 0) {
727 stereo = GL_TRUE;
728 }
729 else if (strcmp(argv[i], "-fullscreen") == 0) {
730 fullscreen = GL_TRUE;
731 }
732 else if (i < argc-1 && strcmp(argv[i], "-geometry") == 0) {
733 XParseGeometry(argv[i+1], &x, &y, &winWidth, &winHeight);
734 i++;
735 }
736 else {
737 usage();
738 return -1;
739 }
740 }
741
742 dpy = XOpenDisplay(dpyName);
743 if (!dpy) {
744 printf("Error: couldn't open display %s\n",
745 dpyName ? dpyName : getenv("DISPLAY"));
746 return -1;
747 }
748
749 make_window(dpy, "glxgears", x, y, winWidth, winHeight, &win, &ctx);
750 XMapWindow(dpy, win);
751 glXMakeCurrent(dpy, win, ctx);
752 query_vsync(dpy);
753
754 if (printInfo) {
755 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
756 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
757 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
758 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
759 }
760
761 init();
762
763 /* Set initial projection/viewing transformation.
764 * We can't be sure we'll get a ConfigureNotify event when the window
765 * first appears.
766 */
767 reshape(winWidth, winHeight);
768
769 event_loop(dpy, win);
770
771 glDeleteLists(gear1, 1);
772 glDeleteLists(gear2, 1);
773 glDeleteLists(gear3, 1);
774 glXDestroyContext(dpy, ctx);
775 XDestroyWindow(dpy, win);
776 XCloseDisplay(dpy);
777
778 return 0;
779 }