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