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