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