http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.23.tar.gz
[xscreensaver] / hacks / glx / gears.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* gears --- 3D gear wheels */
3
4 #if 0
5 static const char sccsid[] = "@(#)gears.c       4.07 97/11/24 xlockmore";
6 #endif
7
8 /*-
9  * Permission to use, copy, modify, and distribute this software and its
10  * documentation for any purpose and without fee is hereby granted,
11  * provided that the above copyright notice appear in all copies and that
12  * both that copyright notice and this permission notice appear in
13  * supporting documentation.
14  *
15  * This file is provided AS IS with no warranties of any kind.  The author
16  * shall have no liability with respect to the infringement of copyrights,
17  * trade secrets or any patents by this file or any part thereof.  In no
18  * event will the author be liable for any lost revenue or profits or
19  * other special, indirect and consequential damages.
20  *
21  * Revision History:
22  * 09-Feb-01: "Planetary" gear system added by jwz@jwz.org.
23  * 10-May-97: Compatible with xscreensaver
24  * 22-Mar-97: Added support for -mono mode, and monochrome X servers.
25  *              Ed Mackey, emackey@netaxs.com
26  * 13-Mar-97: Memory leak fix by Tom Schmidt <tschmidt@micron.com>
27  * 1996: "written" by Danny Sung <dannys@ucla.edu>
28  *       Based on 3-D gear wheels by Brian Paul which is in the public domain.
29  */
30
31 /*-
32  * PURIFY 3.0a on SunOS4 reports an unitialized memory read on each of
33  * the glCallList() functions below when using MesaGL 2.1.  This has
34  * been fixed in MesaGL 2.2 and later releases.
35  */
36
37 #ifdef STANDALONE
38 # define PROGCLASS                                      "Gears"
39 # define HACK_INIT                                      init_gears
40 # define HACK_DRAW                                      draw_gears
41 # define HACK_RESHAPE                           reshape_gears
42 # define HACK_HANDLE_EVENT                      gears_handle_event
43 # define EVENT_MASK                                     PointerMotionMask
44 # define gears_opts                                     xlockmore_opts
45 # define DEFAULTS       "*count:                1       \n"                     \
46                                         "*cycles:               2       \n"                     \
47                                         "*delay:                20000   \n"                     \
48                                         "*showFPS:      False   \n"                     \
49                                         "*wireframe:    False   \n"
50 # include "xlockmore.h"                         /* from the xscreensaver distribution */
51 #else  /* !STANDALONE */
52 # include "xlock.h"                                     /* from the xlockmore distribution */
53 #endif /* !STANDALONE */
54
55 #ifdef USE_GL
56
57 #include "rotator.h"
58 #include "gltrackball.h"
59
60 #undef countof
61 #define countof(x) (sizeof((x))/sizeof((*x)))
62
63 #define DEF_PLANETARY "False"
64 #define DEF_SPIN "True"
65
66 static int planetary;
67 static int spin;
68
69 static XrmOptionDescRec opts[] = {
70   {"-planetary", ".gears.planetary", XrmoptionNoArg, "true" },
71   {"+planetary", ".gears.planetary", XrmoptionNoArg, "false" },
72   {"-spin", ".gears.spin", XrmoptionNoArg, "true" },
73   {"+spin", ".gears.spin", XrmoptionNoArg, "false" },
74 };
75
76 static argtype vars[] = {
77   {&planetary, "planetary", "Planetary", DEF_PLANETARY, t_Bool},
78   {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
79 };
80
81 ModeSpecOpt gears_opts = {countof(opts), opts, countof(vars), vars, NULL};
82
83 #ifdef USE_MODULES
84 ModStruct   gears_description =
85 {"gears", "init_gears", "draw_gears", "release_gears",
86  "draw_gears", "init_gears", NULL, &gears_opts,
87  1000, 1, 2, 1, 4, 1.0, "",
88  "Shows GL's gears", 0, NULL};
89
90 #endif
91
92 #define SMOOTH_TUBE       /* whether to have smooth or faceted tubes */
93
94 #ifdef SMOOTH_TUBE
95 # define TUBE_FACES  20   /* how densely to render tubes */
96 #else
97 # define TUBE_FACES  6
98 #endif
99
100
101 typedef struct {
102   GLuint      gear1, gear2, gear3;
103   GLuint      gear_inner, gear_outer;
104   GLuint      armature;
105   GLfloat     angle;
106   GLXContext *glx_context;
107   Window      window;
108   rotator    *rot;
109   trackball_state *trackball;
110   Bool            button_down_p;
111 } gearsstruct;
112
113 static gearsstruct *gears = NULL;
114
115 /*-
116  * Draw a gear wheel.  You'll probably want to call this function when
117  * building a display list since we do a lot of trig here.
118  *
119  * Input:  inner_radius - radius of hole at center
120  *         outer_radius - radius at center of teeth
121  *         width - width of gear
122  *         teeth - number of teeth
123  *         tooth_depth - depth of tooth
124  *         wire - true for wireframe mode
125  */
126 static void
127 gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
128      GLint teeth, GLfloat tooth_depth, Bool wire, Bool invert)
129 {
130         GLint       i;
131         GLfloat     r0, r1, r2;
132         GLfloat     angle, da;
133         GLfloat     u, v, len;
134
135     if (!invert)
136       {
137         r0 = inner_radius;
138         r1 = outer_radius - tooth_depth / 2.0;
139         r2 = outer_radius + tooth_depth / 2.0;
140         glFrontFace(GL_CCW);
141       }
142     else
143       {
144         r0 = outer_radius;
145         r2 = inner_radius + tooth_depth / 2.0;
146         r1 = outer_radius - tooth_depth / 2.0;
147         glFrontFace(GL_CW);
148       }
149
150         da = 2.0 * M_PI / teeth / 4.0;
151
152         glShadeModel(GL_FLAT);
153
154         /* This subroutine got kind of messy when I added all the checks
155          * for wireframe mode.  A much cleaner solution that I sometimes
156          * use is to have a variable hold the value GL_LINE_LOOP when
157          * in wireframe mode, or hold the value GL_POLYGON otherwise.
158          * Then I just call glBegin(that_variable), give my polygon
159          * coordinates, and glEnd().  Pretty neat eh?  Too bad I couldn't
160          * integrate that trick here.
161          *                                  --Ed.
162          */
163
164         if (!wire)
165                 glNormal3f(0.0, 0.0, 1.0);
166
167         /* draw front face */
168         if (!wire)
169                 glBegin(GL_QUAD_STRIP);
170         for (i = 0; i <= teeth; i++) {
171                 if (wire)
172                         glBegin(GL_LINES);
173                 angle = i * 2.0 * M_PI / teeth;
174                 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
175                 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
176                 if (!wire) {
177                         glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
178                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
179                 } else {
180                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
181                         glVertex3f(r1 * cos(angle + 4 * da), r1 * sin(angle + 4 * da), width * 0.5);
182                         glEnd();
183                 }
184         }
185         if (!wire)
186                 glEnd();
187
188         /* draw front sides of teeth */
189         if (!wire)
190                 glBegin(GL_QUADS);
191         da = 2.0 * M_PI / teeth / 4.0;
192         for (i = 0; i < teeth; i++) {
193                 angle = i * 2.0 * M_PI / teeth;
194
195                 if (wire)
196                         glBegin(GL_LINE_LOOP);
197                 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
198                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
199                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5);
200                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
201                 if (wire)
202                         glEnd();
203         }
204         if (!wire)
205                 glEnd();
206
207
208         if (!wire)
209                 glNormal3f(0.0, 0.0, -1.0);
210
211         /* draw back face */
212         if (!wire)
213                 glBegin(GL_QUAD_STRIP);
214         for (i = 0; i <= teeth; i++) {
215                 angle = i * 2.0 * M_PI / teeth;
216                 if (wire)
217                         glBegin(GL_LINES);
218                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
219                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
220                 if (!wire) {
221                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
222                         glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
223                 } else {
224                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
225                         glVertex3f(r1 * cos(angle + 4 * da), r1 * sin(angle + 4 * da), -width * 0.5);
226                         glEnd();
227                 }
228         }
229         if (!wire)
230                 glEnd();
231
232         /* draw back sides of teeth */
233         if (!wire)
234                 glBegin(GL_QUADS);
235         da = 2.0 * M_PI / teeth / 4.0;
236         for (i = 0; i < teeth; i++) {
237                 angle = i * 2.0 * M_PI / teeth;
238
239                 if (wire)
240                         glBegin(GL_LINE_LOOP);
241                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
242                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5);
243                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
244                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
245                 if (wire)
246                         glEnd();
247         }
248         if (!wire)
249                 glEnd();
250
251
252         /* draw outward faces of teeth */
253         if (!wire)
254                 glBegin(GL_QUAD_STRIP);
255         for (i = 0; i <= teeth; i++) {
256                 angle = i * 2.0 * M_PI / teeth;
257
258         if(!invert) {
259           u = r2 * cos(angle + da) - r1 * cos(angle);
260           v = r2 * sin(angle + da) - r1 * sin(angle);
261         } else {
262           u = r2 * cos(angle + da + M_PI/2) - r1 * cos(angle + M_PI/2);
263           v = r2 * sin(angle + da + M_PI/2) - r1 * sin(angle + M_PI/2);
264         }
265
266                 len = sqrt(u * u + v * v);
267                 u /= len;
268                 v /= len;
269                 glNormal3f(v, -u, 0.0);
270
271                 if (wire)
272                         glBegin(GL_LINES);
273                 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
274                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
275
276                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
277                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
278
279         if(!invert)
280           glNormal3f(cos(angle), sin(angle), 0.0);
281         else
282           glNormal3f(cos(angle + M_PI/2), sin(angle + M_PI/2), 0.0);
283
284                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5);
285                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5);
286
287         if(!invert) {
288           u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
289           v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
290         } else {
291           u = r1 * cos(angle + 3 * da + M_PI/2) - r2 * cos(angle + 2 * da + M_PI/2);
292           v = r1 * sin(angle + 3 * da + M_PI/2) - r2 * sin(angle + 2 * da + M_PI/2);
293         }
294
295                 glNormal3f(v, -u, 0.0);
296
297                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
298                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
299
300         if (!invert)
301           glNormal3f(cos(angle), sin(angle), 0.0);
302         else
303           glNormal3f(cos(angle + M_PI/2), sin(angle + M_PI/2), 0.0);
304
305                 if (wire)
306                         glEnd();
307         }
308
309         if (!wire) {
310                 glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
311                 glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
312                 glEnd();
313         }
314         if (!wire)
315                 glShadeModel(GL_SMOOTH);
316
317         /* draw inside radius cylinder */
318         if (!wire)
319                 glBegin(GL_QUAD_STRIP);
320         for (i = 0; i <= teeth; i++) {
321                 angle = i * 2.0 * M_PI / teeth;
322                 if (wire)
323                         glBegin(GL_LINES);
324
325         if (!invert)
326           glNormal3f(-cos(angle), -sin(angle), 0.0);
327         else
328           glNormal3f(cos(angle), sin(angle), 0.0);
329
330                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
331                 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
332                 if (wire) {
333                         glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
334                         glVertex3f(r0 * cos(angle + 4 * da), r0 * sin(angle + 4 * da), -width * 0.5);
335                         glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
336                         glVertex3f(r0 * cos(angle + 4 * da), r0 * sin(angle + 4 * da), width * 0.5);
337                         glEnd();
338                 }
339         }
340         if (!wire)
341                 glEnd();
342
343 }
344
345
346 static void
347 unit_tube (Bool wire)
348 {
349   int i;
350   int faces = TUBE_FACES;
351   GLfloat step = M_PI * 2 / faces;
352   GLfloat th;
353   int z = 0;
354
355   /* side walls
356    */
357   glFrontFace(GL_CCW);
358
359 # ifdef SMOOTH_TUBE
360   glBegin(wire ? GL_LINES : GL_QUAD_STRIP);
361 # else
362   glBegin(wire ? GL_LINES : GL_QUADS);
363 # endif
364
365   for (i = 0, th = 0; i <= faces; i++)
366     {
367       GLfloat x = cos (th);
368       GLfloat y = sin (th);
369       glNormal3f(x, 0, y);
370       glVertex3f(x, 0.0, y);
371       glVertex3f(x, 1.0, y);
372       th += step;
373
374 # ifndef SMOOTH_TUBE
375       x = cos (th);
376       y = sin (th);
377       glVertex3f(x, 1.0, y);
378       glVertex3f(x, 0.0, y);
379 # endif
380     }
381   glEnd();
382
383   /* End caps
384    */
385   for (z = 0; z <= 1; z++)
386     {
387       glFrontFace(z == 0 ? GL_CCW : GL_CW);
388       glNormal3f(0, (z == 0 ? -1 : 1), 0);
389       glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
390       if (! wire) glVertex3f(0, z, 0);
391       for (i = 0, th = 0; i <= faces; i++)
392         {
393           GLfloat x = cos (th);
394           GLfloat y = sin (th);
395           glVertex3f(x, z, y);
396           th += step;
397         }
398       glEnd();
399     }
400 }
401
402
403 static void
404 tube (GLfloat x1, GLfloat y1, GLfloat z1,
405       GLfloat x2, GLfloat y2, GLfloat z2,
406       GLfloat diameter, GLfloat cap_size,
407       Bool wire)
408 {
409   GLfloat length, angle, a, b, c;
410
411   if (diameter <= 0) abort();
412
413   a = (x2 - x1);
414   b = (y2 - y1);
415   c = (z2 - z1);
416
417   length = sqrt (a*a + b*b + c*c);
418   angle = acos (a / length);
419
420   glPushMatrix();
421   glTranslatef(x1, y1, z1);
422   glScalef (length, length, length);
423
424   if (c == 0 && b == 0)
425     glRotatef (angle / (M_PI / 180), 0, 1, 0);
426   else
427     glRotatef (angle / (M_PI / 180), 0, -c, b);
428
429   glRotatef (-90, 0, 0, 1);
430   glScalef (diameter/length, 1, diameter/length);
431
432   /* extend the endpoints of the tube by the cap size in both directions */
433   if (cap_size != 0)
434     {
435       GLfloat c = cap_size/length;
436       glTranslatef (0, -c, 0);
437       glScalef (1, 1+c+c, 1);
438     }
439
440   unit_tube (wire);
441   glPopMatrix();
442 }
443
444
445 static void
446 ctube (GLfloat diameter, GLfloat width, Bool wire)
447 {
448   tube (0, 0,  width/2,
449         0, 0, -width/2,
450         diameter, 0, wire);
451 }
452
453 static void
454 arm(GLfloat length,
455     GLfloat width1, GLfloat height1,
456     GLfloat width2, GLfloat height2,
457     Bool wire)
458 {
459   glShadeModel(GL_FLAT);
460
461 #if 0  /* don't need these - they're embedded in other objects */
462   /* draw end 1 */
463   glFrontFace(GL_CW);
464   glNormal3f(-1, 0, 0);
465   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
466   glVertex3f(-length/2, -width1/2, -height1/2);
467   glVertex3f(-length/2,  width1/2, -height1/2);
468   glVertex3f(-length/2,  width1/2,  height1/2);
469   glVertex3f(-length/2, -width1/2,  height1/2);
470   glEnd();
471
472   /* draw end 2 */
473   glFrontFace(GL_CCW);
474   glNormal3f(1, 0, 0);
475   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
476   glVertex3f(length/2, -width2/2, -height2/2);
477   glVertex3f(length/2,  width2/2, -height2/2);
478   glVertex3f(length/2,  width2/2,  height2/2);
479   glVertex3f(length/2, -width2/2,  height2/2);
480   glEnd();
481 #endif
482
483   /* draw top */
484   glFrontFace(GL_CCW);
485   glNormal3f(0, 0, -1);
486   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
487   glVertex3f(-length/2, -width1/2, -height1/2);
488   glVertex3f(-length/2,  width1/2, -height1/2);
489   glVertex3f( length/2,  width2/2, -height2/2);
490   glVertex3f( length/2, -width2/2, -height2/2);
491   glEnd();
492
493   /* draw bottom */
494   glFrontFace(GL_CW);
495   glNormal3f(0, 0, 1);
496   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
497   glVertex3f(-length/2, -width1/2, height1/2);
498   glVertex3f(-length/2,  width1/2, height1/2);
499   glVertex3f( length/2,  width2/2, height2/2);
500   glVertex3f( length/2, -width2/2, height2/2);
501   glEnd();
502
503   /* draw left */
504   glFrontFace(GL_CW);
505   glNormal3f(0, -1, 0);
506   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
507   glVertex3f(-length/2, -width1/2, -height1/2);
508   glVertex3f(-length/2, -width1/2,  height1/2);
509   glVertex3f( length/2, -width2/2,  height2/2);
510   glVertex3f( length/2, -width2/2, -height2/2);
511   glEnd();
512
513   /* draw right */
514   glFrontFace(GL_CCW);
515   glNormal3f(0, 1, 0);
516   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
517   glVertex3f(-length/2,  width1/2, -height1/2);
518   glVertex3f(-length/2,  width1/2,  height1/2);
519   glVertex3f( length/2,  width2/2,  height2/2);
520   glVertex3f( length/2,  width2/2, -height2/2);
521   glEnd();
522
523   glFrontFace(GL_CCW);
524 }
525
526
527 static void
528 draw(ModeInfo * mi)
529 {
530         gearsstruct *gp = &gears[MI_SCREEN(mi)];
531         int         wire = MI_IS_WIREFRAME(mi);
532
533         if (!wire) {
534                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
535         } else {
536                 glClear(GL_COLOR_BUFFER_BIT);
537         }
538
539         glPushMatrix();
540
541     gltrackball_rotate (gp->trackball);
542
543     if (spin)
544           {
545                 double x, y, z;
546                 get_rotation (gp->rot, &x, &y, &z, !gp->button_down_p);
547                 glRotatef (x * 360, 1.0, 0.0, 0.0);
548                 glRotatef (y * 360, 0.0, 1.0, 0.0);
549                 glRotatef (z * 360, 0.0, 0.0, 1.0);
550           }
551
552     if (!planetary) {
553       glPushMatrix();
554       glTranslatef(-3.0, -2.0, 0.0);
555       glRotatef(gp->angle, 0.0, 0.0, 1.0);
556 /* PURIFY 4.0.1 reports an unitialized memory read on the next line when using
557    * MesaGL 2.2 and -mono.  This has been fixed in MesaGL 2.3 and later. */
558       glCallList(gp->gear1);
559       glPopMatrix();
560
561       glPushMatrix();
562       glTranslatef(3.1, -2.0, 0.0);
563       glRotatef(-2.0 * gp->angle - 9.0, 0.0, 0.0, 1.0);
564       glCallList(gp->gear2);
565       glPopMatrix();
566
567       glPushMatrix();
568       glTranslatef(-3.1, 4.2, 0.0);
569       glRotatef(-2.0 * gp->angle - 25.0, 0.0, 0.0, 1.0);
570       glCallList(gp->gear3);
571       glPopMatrix();
572
573     } else { /* planetary */
574
575       glScalef(0.8, 0.8, 0.8);
576
577       glPushMatrix();
578       glTranslatef(0.0, 4.2, 0.0);
579       glRotatef(gp->angle - 7.0, 0.0, 0.0, 1.0);
580       glCallList(gp->gear1);
581       glPopMatrix();
582
583       glPushMatrix();
584       glRotatef(120, 0.0, 0.0, 1.0);
585       glTranslatef(0.0, 4.2, 0.0);
586       glRotatef(gp->angle - 7.0, 0.0, 0.0, 1.0);
587       glCallList(gp->gear2);
588       glPopMatrix();
589
590       glPushMatrix();
591       glRotatef(240, 0.0, 0.0, 1.0);
592       glTranslatef(0.0, 4.2, 0.0);
593       glRotatef(gp->angle - 7.0, 0.0, 0.0, 1.0);
594       glCallList(gp->gear3);
595       glPopMatrix();
596
597       glPushMatrix();
598       glTranslatef(0.0, 0.0, 0.0);
599       glRotatef(-gp->angle, 0.0, 0.0, 1.0);
600       glCallList(gp->gear_inner);
601       glPopMatrix();
602
603       glPushMatrix();
604       glTranslatef(0.0, 0.0, 0.0);
605       glRotatef((gp->angle / 3.0) - 7.5, 0.0, 0.0, 1.0);
606       glCallList(gp->gear_outer);
607       glPopMatrix();
608
609       glPushMatrix();
610       glTranslatef(0.0, 0.0, 0.0);
611       glCallList(gp->armature);
612       glPopMatrix();
613     }
614
615         glPopMatrix();
616 }
617
618
619
620 /* new window size or exposure */
621 void
622 reshape_gears(ModeInfo *mi, int width, int height)
623 {
624         GLfloat     h = (GLfloat) height / (GLfloat) width;
625
626         glViewport(0, 0, (GLint) width, (GLint) height);
627         glMatrixMode(GL_PROJECTION);
628         glLoadIdentity();
629         glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
630         glMatrixMode(GL_MODELVIEW);
631         glLoadIdentity();
632         glTranslatef(0.0, 0.0, -40.0);
633
634         /* The depth buffer will be cleared, if needed, before the
635          * next frame.  Right now we just want to black the screen.
636          */
637         glClear(GL_COLOR_BUFFER_BIT);
638
639 }
640
641
642 static void
643 pinit(ModeInfo * mi)
644 {
645         gearsstruct *gp = &gears[MI_SCREEN(mi)];
646         static GLfloat pos[4] =
647         {5.0, 5.0, 10.0, 1.0};
648         static GLfloat red[4] =
649         {0.8, 0.1, 0.0, 1.0};
650         static GLfloat green[4] =
651         {0.0, 0.8, 0.2, 1.0};
652         static GLfloat blue[4] =
653         {0.2, 0.2, 1.0, 1.0};
654         static GLfloat gray[4] =
655         {0.5, 0.5, 0.5, 1.0};
656         static GLfloat white[4] =
657         {1.0, 1.0, 1.0, 1.0};
658         int         wire = MI_IS_WIREFRAME(mi);
659         int         mono = MI_IS_MONO(mi);
660
661         if (!wire) {
662                 glLightfv(GL_LIGHT0, GL_POSITION, pos);
663                 glEnable(GL_CULL_FACE);
664                 glEnable(GL_LIGHTING);
665                 glEnable(GL_LIGHT0);
666                 glEnable(GL_DEPTH_TEST);
667         }
668 #if 0
669 /*-
670  * Messes up on multiscreen Pseudocolor:0 StaticGray(monochrome):1
671  * 2nd time mode is run it is Grayscale on PseudoColor.
672  * The code below forces monochrome on TrueColor.
673  */
674         if (MI_IS_MONO(mi)) {
675                 red[0] = red[1] = red[2] = 1.0;
676                 green[0] = green[1] = green[2] = 1.0;
677                 blue[0] = blue[1] = blue[2] = 1.0;
678         }
679 #endif
680
681         /* make the gears */
682
683     if (! planetary) {
684
685       gp->gear1 = glGenLists(1);
686       glNewList(gp->gear1, GL_COMPILE);
687       if (wire) {
688                 if (mono)
689           glColor4fv(white);
690                 else
691           glColor4fv(red);
692       } else {
693                 if (mono)
694           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
695                 else
696           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
697       }
698
699       gear(1.0, 4.0, 1.0, 20, 0.7, wire, False);
700       glEndList();
701
702       gp->gear2 = glGenLists(1);
703       glNewList(gp->gear2, GL_COMPILE);
704       if (wire) {
705                 if (mono)
706           glColor4fv(white);
707                 else
708           glColor4fv(green);
709       } else {
710                 if (mono)
711           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
712                 else
713           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
714       }
715       gear(0.5, 2.0, 2.0, 10, 0.7, wire, False);
716       glEndList();
717
718       gp->gear3 = glGenLists(1);
719       glNewList(gp->gear3, GL_COMPILE);
720       if (wire) {
721                 if (mono)
722           glColor4fv(white);
723                 else
724           glColor4fv(blue);
725       } else {
726                 if (mono)
727           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
728                 else
729           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
730       }
731       gear(1.3, 2.0, 0.5, 10, 0.7, wire, False);
732       glEndList();
733       if (!wire)
734                 glEnable(GL_NORMALIZE);
735
736     } else { /* planetary */
737
738       gp->gear1 = glGenLists(1);
739       glNewList(gp->gear1, GL_COMPILE);
740       if (wire) {
741                 if (mono)
742           glColor4fv(white);
743                 else
744           glColor4fv(red);
745       } else {
746                 if (mono)
747           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
748                 else
749           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
750       }
751       gear(1.3, 2.0, 2.0, 12, 0.7, wire, False);
752       glEndList();
753
754       gp->gear2 = glGenLists(1);
755       glNewList(gp->gear2, GL_COMPILE);
756       if (wire) {
757                 if (mono)
758           glColor4fv(white);
759                 else
760           glColor4fv(green);
761       } else {
762                 if (mono)
763           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
764                 else
765           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
766       }
767       gear(1.3, 2.0, 2.0, 12, 0.7, wire, False);
768       glEndList();
769
770       gp->gear3 = glGenLists(1);
771       glNewList(gp->gear3, GL_COMPILE);
772       if (wire) {
773                 if (mono)
774           glColor4fv(white);
775                 else
776           glColor4fv(blue);
777       } else {
778                 if (mono)
779           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
780                 else
781           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
782       }
783       gear(1.3, 2.0, 2.0, 12, 0.7, wire, False);
784       glEndList();
785       if (!wire)
786                 glEnable(GL_NORMALIZE);
787
788
789       gp->gear_inner = glGenLists(1);
790       glNewList(gp->gear_inner, GL_COMPILE);
791       if (wire) {
792                 if (mono)
793           glColor4fv(white);
794                 else
795           glColor4fv(blue);
796       } else {
797                 if (mono)
798           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
799                 else
800           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
801       }
802       gear(1.0, 2.0, 2.0, 12, 0.7, wire, False);
803       glEndList();
804       if (!wire)
805                 glEnable(GL_NORMALIZE);
806
807
808       gp->gear_outer = glGenLists(1);
809       glNewList(gp->gear_outer, GL_COMPILE);
810       if (wire) {
811                 if (mono)
812           glColor4fv(white);
813                 else
814           glColor4fv(blue);
815       } else {
816                 if (mono)
817           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
818                 else
819           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
820       }
821       gear(5.7, 7.0, 2.0, 36, 0.7, wire, True);
822
823       /* put some nubs on the outer ring, so we can tell how it's moving */
824       glPushMatrix();
825       glTranslatef(7.0, 0, 0);
826       glRotatef(90, 0, 1, 0);
827
828       ctube(0.5, 0.5, wire);   /* nub 1 */
829       glPopMatrix();
830
831       glPushMatrix();
832       glRotatef(120, 0, 0, 1);
833       glTranslatef(7.0, 0, 0);
834       glRotatef(90, 0, 1, 0);
835       ctube(0.5, 0.5, wire);   /* nub 2 */
836       glPopMatrix();
837
838       glPushMatrix();
839       glRotatef(240, 0, 0, 1);
840       glTranslatef(7.0, 0, 0);
841       glRotatef(90, 0, 1, 0);
842       ctube(0.5, 0.5, wire);   /* nub 3 */
843       glPopMatrix();
844
845
846       glEndList();
847       if (!wire)
848                 glEnable(GL_NORMALIZE);
849
850       gp->armature = glGenLists(1);
851       glNewList(gp->armature, GL_COMPILE);
852       if (wire) {
853         if (mono)
854           glColor4fv(white);
855         else
856           glColor4fv(blue);
857       } else {
858         if (mono)
859           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
860         else
861           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
862       }
863
864       glTranslatef(0, 0, 1.5);
865       ctube(0.5, 10, wire);       /* center axle */
866
867       glPushMatrix();
868       glTranslatef(0.0, 4.2, -1);
869       ctube(0.5, 3, wire);       /* axle 1 */
870       glTranslatef(0, 0, 1.8);
871       ctube(0.7, 0.7, wire);
872       glPopMatrix();
873
874       glPushMatrix();
875       glRotatef(120, 0.0, 0.0, 1.0);
876       glTranslatef(0.0, 4.2, -1);
877       ctube(0.5, 3, wire);       /* axle 2 */
878       glTranslatef(0, 0, 1.8);
879       ctube(0.7, 0.7, wire);
880       glPopMatrix();
881
882       glPushMatrix();
883       glRotatef(240, 0.0, 0.0, 1.0);
884       glTranslatef(0.0, 4.2, -1);
885       ctube(0.5, 3, wire);       /* axle 3 */
886       glTranslatef(0, 0, 1.8);
887       ctube(0.7, 0.7, wire);
888       glPopMatrix();
889
890       glTranslatef(0, 0, 1.5);      /* center disk */
891       ctube(1.5, 2, wire);
892
893       glPushMatrix();
894       glRotatef(270, 0, 0, 1);
895       glRotatef(-10, 0, 1, 0);
896       glTranslatef(-2.2, 0, 0);
897       arm(4.0, 1.0, 0.5, 2.0, 1.0, wire);               /* arm 1 */
898       glPopMatrix();
899
900       glPushMatrix();
901       glRotatef(30, 0, 0, 1);
902       glRotatef(-10, 0, 1, 0);
903       glTranslatef(-2.2, 0, 0);
904       arm(4.0, 1.0, 0.5, 2.0, 1.0, wire);               /* arm 2 */
905       glPopMatrix();
906
907       glPushMatrix();
908       glRotatef(150, 0, 0, 1);
909       glRotatef(-10, 0, 1, 0);
910       glTranslatef(-2.2, 0, 0);
911       arm(4.0, 1.0, 0.5, 2.0, 1.0, wire);               /* arm 3 */
912       glPopMatrix();
913
914       glEndList();
915       if (!wire)
916         glEnable(GL_NORMALIZE);
917     }
918 }
919
920
921 Bool
922 gears_handle_event (ModeInfo *mi, XEvent *event)
923 {
924   gearsstruct *gp = &gears[MI_SCREEN(mi)];
925
926   if (event->xany.type == ButtonPress &&
927       event->xbutton.button == Button1)
928     {
929       gp->button_down_p = True;
930       gltrackball_start (gp->trackball,
931                          event->xbutton.x, event->xbutton.y,
932                          MI_WIDTH (mi), MI_HEIGHT (mi));
933       return True;
934     }
935   else if (event->xany.type == ButtonRelease &&
936            event->xbutton.button == Button1)
937     {
938       gp->button_down_p = False;
939       return True;
940     }
941   else if (event->xany.type == ButtonPress &&
942            (event->xbutton.button == Button4 ||
943             event->xbutton.button == Button5))
944     {
945       gltrackball_mousewheel (gp->trackball, event->xbutton.button, 10,
946                               !!event->xbutton.state);
947       return True;
948     }
949   else if (event->xany.type == MotionNotify &&
950            gp->button_down_p)
951     {
952       gltrackball_track (gp->trackball,
953                          event->xmotion.x, event->xmotion.y,
954                          MI_WIDTH (mi), MI_HEIGHT (mi));
955       return True;
956     }
957
958   return False;
959 }
960
961
962 void
963 init_gears(ModeInfo * mi)
964 {
965         int         screen = MI_SCREEN(mi);
966
967         /*Colormap    cmap; */
968         /* Boolean     rgba, doublebuffer, cmap_installed; */
969         gearsstruct *gp;
970
971         if (gears == NULL) {
972                 if ((gears = (gearsstruct *) calloc(MI_NUM_SCREENS(mi),
973                                               sizeof (gearsstruct))) == NULL)
974                         return;
975         }
976         gp = &gears[screen];
977
978         gp->window = MI_WINDOW(mi);
979
980     gp->rot = make_rotator (1, 1, 1, 1, 0, True);
981     gp->trackball = gltrackball_init ();
982
983         if ((gp->glx_context = init_GL(mi)) != NULL) {
984                 reshape_gears(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
985                 pinit(mi);
986         } else {
987                 MI_CLEARWINDOW(mi);
988         }
989 }
990
991 void
992 draw_gears(ModeInfo * mi)
993 {
994         gearsstruct *gp = &gears[MI_SCREEN(mi)];
995         Display    *display = MI_DISPLAY(mi);
996         Window      window = MI_WINDOW(mi);
997         int         angle_incr = MI_CYCLES(mi) ? MI_CYCLES(mi) : 2;
998
999     if (planetary)
1000       angle_incr *= 3;
1001
1002         if (!gp->glx_context)
1003                 return;
1004
1005         glDrawBuffer(GL_BACK);
1006
1007         glXMakeCurrent(display, window, *(gp->glx_context));
1008         draw(mi);
1009
1010         /* let's do something so we don't get bored */
1011         gp->angle = (int) (gp->angle + angle_incr) % 360;
1012
1013     if (mi->fps_p) do_fps (mi);
1014         glFinish();
1015         glXSwapBuffers(display, window);
1016 }
1017
1018 void
1019 release_gears(ModeInfo * mi)
1020 {
1021         if (gears != NULL) {
1022                 int         screen;
1023
1024                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1025                         gearsstruct *gp = &gears[screen];
1026
1027                         if (gp->glx_context) {
1028                                 /* Display lists MUST be freed while their glXContext is current. */
1029                                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1030
1031                                 if (glIsList(gp->gear1))
1032                                         glDeleteLists(gp->gear1, 1);
1033                                 if (glIsList(gp->gear2))
1034                                         glDeleteLists(gp->gear2, 1);
1035                                 if (glIsList(gp->gear3))
1036                                         glDeleteLists(gp->gear3, 1);
1037                                 if (glIsList(gp->gear_inner))
1038                                         glDeleteLists(gp->gear_inner, 1);
1039                                 if (glIsList(gp->gear_outer))
1040                                         glDeleteLists(gp->gear_outer, 1);
1041
1042                         }
1043                 }
1044                 (void) free((void *) gears);
1045                 gears = NULL;
1046         }
1047         FreeAllGL(mi);
1048 }
1049
1050
1051 /*********************************************************/
1052
1053 #endif