blob: 8700e2773f5109c208cdca78dffd49828e7f0546 [file] [log] [blame]
Brian Paul355da232001-03-23 22:46:26 +00001/*
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 *
Brian Paulad802332003-04-09 21:47:19 +000026 * Command line options:
Brian Paul50253ea2003-09-08 15:06:23 +000027 * -info print GL implementation information
Brian Paul20831312004-10-26 14:36:32 +000028 * -stereo use stereo enabled GLX visual
Brian Paul50253ea2003-09-08 15:06:23 +000029 *
Brian Paul355da232001-03-23 22:46:26 +000030 */
31
32
33#include <math.h>
34#include <stdlib.h>
35#include <stdio.h>
36#include <string.h>
37#include <X11/Xlib.h>
38#include <X11/keysym.h>
39#include <GL/gl.h>
40#include <GL/glx.h>
41
Brian Paul785774d2003-05-30 15:30:16 +000042
Brian Paul355da232001-03-23 22:46:26 +000043#define BENCHMARK
44
45#ifdef BENCHMARK
46
47/* XXX this probably isn't very portable */
48
49#include <sys/time.h>
50#include <unistd.h>
51
52/* return current time (in seconds) */
53static int
54current_time(void)
55{
56 struct timeval tv;
Jouk Jansenf72a3da2002-10-08 08:38:26 +000057#ifdef __VMS
58 (void) gettimeofday(&tv, NULL );
59#else
Brian Paul355da232001-03-23 22:46:26 +000060 struct timezone tz;
61 (void) gettimeofday(&tv, &tz);
Jouk Jansenf72a3da2002-10-08 08:38:26 +000062#endif
Brian Paul355da232001-03-23 22:46:26 +000063 return (int) tv.tv_sec;
64}
65
66#else /*BENCHMARK*/
67
68/* dummy */
69static int
70current_time(void)
71{
72 return 0;
73}
74
75#endif /*BENCHMARK*/
76
77
78
79#ifndef M_PI
80#define M_PI 3.14159265
81#endif
82
83
84static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
85static GLint gear1, gear2, gear3;
86static GLfloat angle = 0.0;
87
Keith Whitwell16db1572004-12-20 14:48:19 +000088static GLboolean fullscreen = GL_FALSE; /* Create a single fullscreen window */
Brian Paul20831312004-10-26 14:36:32 +000089static GLboolean stereo = GL_FALSE; /* Enable stereo. */
90static GLfloat eyesep = 5.0; /* Eye separation. */
91static GLfloat fix_point = 40.0; /* Fixation point distance. */
92static GLfloat left, right, asp; /* Stereo frustum params. */
93
Brian Paul785774d2003-05-30 15:30:16 +000094
Brian Paul355da232001-03-23 22:46:26 +000095/*
96 *
97 * Draw a gear wheel. You'll probably want to call this function when
98 * building a display list since we do a lot of trig here.
99 *
100 * Input: inner_radius - radius of hole at center
101 * outer_radius - radius at center of teeth
102 * width - width of gear
103 * teeth - number of teeth
104 * tooth_depth - depth of tooth
105 */
106static void
107gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
108 GLint teeth, GLfloat tooth_depth)
109{
110 GLint i;
111 GLfloat r0, r1, r2;
112 GLfloat angle, da;
113 GLfloat u, v, len;
114
115 r0 = inner_radius;
116 r1 = outer_radius - tooth_depth / 2.0;
117 r2 = outer_radius + tooth_depth / 2.0;
118
119 da = 2.0 * M_PI / teeth / 4.0;
120
121 glShadeModel(GL_FLAT);
122
123 glNormal3f(0.0, 0.0, 1.0);
124
125 /* draw front face */
126 glBegin(GL_QUAD_STRIP);
127 for (i = 0; i <= teeth; i++) {
128 angle = i * 2.0 * M_PI / teeth;
129 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
130 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
131 if (i < teeth) {
132 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
133 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
134 width * 0.5);
135 }
136 }
137 glEnd();
138
139 /* draw front sides of teeth */
140 glBegin(GL_QUADS);
141 da = 2.0 * M_PI / teeth / 4.0;
142 for (i = 0; i < teeth; i++) {
143 angle = i * 2.0 * M_PI / teeth;
144
145 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
146 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
147 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
148 width * 0.5);
149 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
150 width * 0.5);
151 }
152 glEnd();
153
154 glNormal3f(0.0, 0.0, -1.0);
155
156 /* draw back face */
157 glBegin(GL_QUAD_STRIP);
158 for (i = 0; i <= teeth; i++) {
159 angle = i * 2.0 * M_PI / teeth;
160 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
161 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
162 if (i < teeth) {
163 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
164 -width * 0.5);
165 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
166 }
167 }
168 glEnd();
169
170 /* draw back sides of teeth */
171 glBegin(GL_QUADS);
172 da = 2.0 * M_PI / teeth / 4.0;
173 for (i = 0; i < teeth; i++) {
174 angle = i * 2.0 * M_PI / teeth;
175
176 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
177 -width * 0.5);
178 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
179 -width * 0.5);
180 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
181 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
182 }
183 glEnd();
184
185 /* draw outward faces of teeth */
186 glBegin(GL_QUAD_STRIP);
187 for (i = 0; i < teeth; i++) {
188 angle = i * 2.0 * M_PI / teeth;
189
190 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
191 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
192 u = r2 * cos(angle + da) - r1 * cos(angle);
193 v = r2 * sin(angle + da) - r1 * sin(angle);
194 len = sqrt(u * u + v * v);
195 u /= len;
196 v /= len;
197 glNormal3f(v, -u, 0.0);
198 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
199 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
200 glNormal3f(cos(angle), sin(angle), 0.0);
201 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
202 width * 0.5);
203 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
204 -width * 0.5);
205 u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
206 v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
207 glNormal3f(v, -u, 0.0);
208 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
209 width * 0.5);
210 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
211 -width * 0.5);
212 glNormal3f(cos(angle), sin(angle), 0.0);
213 }
214
215 glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
216 glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
217
218 glEnd();
219
220 glShadeModel(GL_SMOOTH);
221
222 /* draw inside radius cylinder */
223 glBegin(GL_QUAD_STRIP);
224 for (i = 0; i <= teeth; i++) {
225 angle = i * 2.0 * M_PI / teeth;
226 glNormal3f(-cos(angle), -sin(angle), 0.0);
227 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
228 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
229 }
230 glEnd();
231}
232
233
234static void
Brian Paul20831312004-10-26 14:36:32 +0000235do_draw(void)
Brian Paul355da232001-03-23 22:46:26 +0000236{
Brian Paul50253ea2003-09-08 15:06:23 +0000237 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Brian Paul355da232001-03-23 22:46:26 +0000238
239 glPushMatrix();
240 glRotatef(view_rotx, 1.0, 0.0, 0.0);
241 glRotatef(view_roty, 0.0, 1.0, 0.0);
242 glRotatef(view_rotz, 0.0, 0.0, 1.0);
243
244 glPushMatrix();
245 glTranslatef(-3.0, -2.0, 0.0);
246 glRotatef(angle, 0.0, 0.0, 1.0);
247 glCallList(gear1);
248 glPopMatrix();
249
250 glPushMatrix();
251 glTranslatef(3.1, -2.0, 0.0);
252 glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
253 glCallList(gear2);
254 glPopMatrix();
255
256 glPushMatrix();
257 glTranslatef(-3.1, 4.2, 0.0);
258 glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
259 glCallList(gear3);
260 glPopMatrix();
261
262 glPopMatrix();
263}
264
Brian Paul20831312004-10-26 14:36:32 +0000265static void
266draw(void)
267{
268 if (stereo) {
269 /* First left eye. */
270 glDrawBuffer(GL_BACK_LEFT);
271
272 glMatrixMode(GL_PROJECTION);
273 glLoadIdentity();
274 glFrustum(left, right, -asp, asp, 5.0, 60.0);
275
276 glMatrixMode(GL_MODELVIEW);
277
278 glPushMatrix();
279 glTranslated(+0.5 * eyesep, 0.0, 0.0);
280 do_draw();
281 glPopMatrix();
282
283 /* Then right eye. */
284 glDrawBuffer(GL_BACK_RIGHT);
285
286 glMatrixMode(GL_PROJECTION);
287 glLoadIdentity();
288 glFrustum(-right, -left, -asp, asp, 5.0, 60.0);
289
290 glMatrixMode(GL_MODELVIEW);
291
292 glPushMatrix();
293 glTranslated(-0.5 * eyesep, 0.0, 0.0);
294 do_draw();
295 glPopMatrix();
296 } else
297 do_draw();
298}
299
Brian Paul355da232001-03-23 22:46:26 +0000300
301/* new window size or exposure */
302static void
303reshape(int width, int height)
304{
Brian Paul355da232001-03-23 22:46:26 +0000305 glViewport(0, 0, (GLint) width, (GLint) height);
Brian Paul20831312004-10-26 14:36:32 +0000306
307 if (stereo) {
308 GLfloat w;
309
310 asp = (GLfloat) height / (GLfloat) width;
311 w = fix_point * (1.0 / 5.0);
312
313 left = -5.0 * ((w - 0.5 * eyesep) / fix_point);
314 right = 5.0 * ((w + 0.5 * eyesep) / fix_point);
315 } else {
316 GLfloat h = (GLfloat) height / (GLfloat) width;
317
318 glMatrixMode(GL_PROJECTION);
319 glLoadIdentity();
320 glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
321 }
322
Brian Paul355da232001-03-23 22:46:26 +0000323 glMatrixMode(GL_MODELVIEW);
324 glLoadIdentity();
325 glTranslatef(0.0, 0.0, -40.0);
326}
Brian Paul20831312004-10-26 14:36:32 +0000327
Brian Paul355da232001-03-23 22:46:26 +0000328
329
330static void
331init(void)
332{
333 static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
334 static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
335 static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
336 static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
337
338 glLightfv(GL_LIGHT0, GL_POSITION, pos);
339 glEnable(GL_CULL_FACE);
340 glEnable(GL_LIGHTING);
341 glEnable(GL_LIGHT0);
342 glEnable(GL_DEPTH_TEST);
343
344 /* make the gears */
345 gear1 = glGenLists(1);
346 glNewList(gear1, GL_COMPILE);
347 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
348 gear(1.0, 4.0, 1.0, 20, 0.7);
349 glEndList();
350
351 gear2 = glGenLists(1);
352 glNewList(gear2, GL_COMPILE);
353 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
354 gear(0.5, 2.0, 2.0, 10, 0.7);
355 glEndList();
356
357 gear3 = glGenLists(1);
358 glNewList(gear3, GL_COMPILE);
359 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
360 gear(1.3, 2.0, 0.5, 10, 0.7);
361 glEndList();
362
363 glEnable(GL_NORMALIZE);
364}
365
366
367/*
368 * Create an RGB, double-buffered window.
369 * Return the window and context handles.
370 */
371static void
372make_window( Display *dpy, const char *name,
373 int x, int y, int width, int height,
374 Window *winRet, GLXContext *ctxRet)
375{
Brian Paul20831312004-10-26 14:36:32 +0000376 int attribs[] = { GLX_RGBA,
377 GLX_RED_SIZE, 1,
378 GLX_GREEN_SIZE, 1,
379 GLX_BLUE_SIZE, 1,
380 GLX_DOUBLEBUFFER,
381 GLX_DEPTH_SIZE, 1,
382 None };
383 int stereoAttribs[] = { GLX_RGBA,
384 GLX_RED_SIZE, 1,
385 GLX_GREEN_SIZE, 1,
386 GLX_BLUE_SIZE, 1,
387 GLX_DOUBLEBUFFER,
388 GLX_DEPTH_SIZE, 1,
389 GLX_STEREO,
390 None };
Brian Paul355da232001-03-23 22:46:26 +0000391 int scrnum;
392 XSetWindowAttributes attr;
393 unsigned long mask;
394 Window root;
395 Window win;
396 GLXContext ctx;
397 XVisualInfo *visinfo;
398
399 scrnum = DefaultScreen( dpy );
400 root = RootWindow( dpy, scrnum );
401
Keith Whitwell16db1572004-12-20 14:48:19 +0000402 if (fullscreen) {
403 x = 0; y = 0;
404 width = DisplayWidth( dpy, scrnum );
405 height = DisplayHeight( dpy, scrnum );
406 }
407
Brian Paul20831312004-10-26 14:36:32 +0000408 if (stereo)
409 visinfo = glXChooseVisual( dpy, scrnum, stereoAttribs );
410 else
411 visinfo = glXChooseVisual( dpy, scrnum, attribs );
Brian Paul355da232001-03-23 22:46:26 +0000412 if (!visinfo) {
Brian Paul20831312004-10-26 14:36:32 +0000413 if (stereo) {
414 printf("Error: couldn't get an RGB, "
415 "Double-buffered, Stereo visual\n");
416 } else
417 printf("Error: couldn't get an RGB, Double-buffered visual\n");
Brian Paul355da232001-03-23 22:46:26 +0000418 exit(1);
419 }
420
421 /* window attributes */
422 attr.background_pixel = 0;
423 attr.border_pixel = 0;
424 attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
425 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
Keith Whitwell16db1572004-12-20 14:48:19 +0000426 attr.override_redirect = fullscreen;
427 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
Brian Paul355da232001-03-23 22:46:26 +0000428
429 win = XCreateWindow( dpy, root, 0, 0, width, height,
430 0, visinfo->depth, InputOutput,
431 visinfo->visual, mask, &attr );
432
433 /* set hints and properties */
434 {
435 XSizeHints sizehints;
436 sizehints.x = x;
437 sizehints.y = y;
438 sizehints.width = width;
439 sizehints.height = height;
440 sizehints.flags = USSize | USPosition;
441 XSetNormalHints(dpy, win, &sizehints);
442 XSetStandardProperties(dpy, win, name, name,
443 None, (char **)NULL, 0, &sizehints);
444 }
445
446 ctx = glXCreateContext( dpy, visinfo, NULL, True );
447 if (!ctx) {
448 printf("Error: glXCreateContext failed\n");
449 exit(1);
450 }
451
452 XFree(visinfo);
453
454 *winRet = win;
455 *ctxRet = ctx;
456}
457
458
459static void
460event_loop(Display *dpy, Window win)
461{
462 while (1) {
463 while (XPending(dpy) > 0) {
464 XEvent event;
465 XNextEvent(dpy, &event);
466 switch (event.type) {
467 case Expose:
468 /* we'll redraw below */
469 break;
470 case ConfigureNotify:
471 reshape(event.xconfigure.width, event.xconfigure.height);
472 break;
473 case KeyPress:
474 {
475 char buffer[10];
476 int r, code;
477 code = XLookupKeysym(&event.xkey, 0);
478 if (code == XK_Left) {
479 view_roty += 5.0;
480 }
481 else if (code == XK_Right) {
482 view_roty -= 5.0;
483 }
484 else if (code == XK_Up) {
485 view_rotx += 5.0;
486 }
487 else if (code == XK_Down) {
488 view_rotx -= 5.0;
489 }
490 else {
491 r = XLookupString(&event.xkey, buffer, sizeof(buffer),
492 NULL, NULL);
493 if (buffer[0] == 27) {
494 /* escape */
495 return;
496 }
497 }
498 }
499 }
500 }
501
502 /* next frame */
503 angle += 2.0;
Brian Paul07553c52004-10-23 18:55:48 +0000504 if (angle > 3600.0)
505 angle -= 3600.0;
Brian Paul355da232001-03-23 22:46:26 +0000506
507 draw();
508 glXSwapBuffers(dpy, win);
509
510 /* calc framerate */
511 {
512 static int t0 = -1;
513 static int frames = 0;
514 int t = current_time();
515
516 if (t0 < 0)
517 t0 = t;
518
519 frames++;
520
521 if (t - t0 >= 5.0) {
522 GLfloat seconds = t - t0;
523 GLfloat fps = frames / seconds;
Brian Paul50253ea2003-09-08 15:06:23 +0000524 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
525 fps);
Brian Paul355da232001-03-23 22:46:26 +0000526 t0 = t;
527 frames = 0;
528 }
529 }
530 }
531}
532
533
534int
535main(int argc, char *argv[])
536{
537 Display *dpy;
538 Window win;
539 GLXContext ctx;
Brian Paul20831312004-10-26 14:36:32 +0000540 char *dpyName = NULL;
Brian Paul355da232001-03-23 22:46:26 +0000541 GLboolean printInfo = GL_FALSE;
542 int i;
543
544 for (i = 1; i < argc; i++) {
Brian Paul50253ea2003-09-08 15:06:23 +0000545 if (strcmp(argv[i], "-display") == 0) {
Brian Paul355da232001-03-23 22:46:26 +0000546 dpyName = argv[i+1];
547 i++;
548 }
549 else if (strcmp(argv[i], "-info") == 0) {
550 printInfo = GL_TRUE;
551 }
Brian Paul20831312004-10-26 14:36:32 +0000552 else if (strcmp(argv[i], "-stereo") == 0) {
553 stereo = GL_TRUE;
554 }
Keith Whitwell16db1572004-12-20 14:48:19 +0000555 else if (strcmp(argv[i], "-fullscreen") == 0) {
556 fullscreen = GL_TRUE;
557 }
Brian Paul20831312004-10-26 14:36:32 +0000558 else
559 printf("Warrning: unknown parameter: %s\n", argv[i]);
Brian Paul355da232001-03-23 22:46:26 +0000560 }
561
562 dpy = XOpenDisplay(dpyName);
563 if (!dpy) {
Brian Paul20831312004-10-26 14:36:32 +0000564 printf("Error: couldn't open display %s\n",
565 dpyName ? dpyName : getenv("DISPLAY"));
Brian Paul355da232001-03-23 22:46:26 +0000566 return -1;
567 }
568
569 make_window(dpy, "glxgears", 0, 0, 300, 300, &win, &ctx);
570 XMapWindow(dpy, win);
571 glXMakeCurrent(dpy, win, ctx);
572
573 if (printInfo) {
574 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
575 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
576 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
577 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
Brian Paul355da232001-03-23 22:46:26 +0000578 }
579
580 init();
581
582 event_loop(dpy, win);
583
584 glXDestroyContext(dpy, ctx);
585 XDestroyWindow(dpy, win);
586 XCloseDisplay(dpy);
587
588 return 0;
589}