http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.30.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 #define SMOOTH_TUBE       /* whether to have smooth or faceted tubes */
92
93 #ifdef SMOOTH_TUBE
94 # define TUBE_FACES  20   /* how densely to render tubes */
95 #else
96 # define TUBE_FACES  6
97 #endif
98
99
100 typedef struct {
101
102   GLfloat rotx, roty, rotz;        /* current object rotation */
103   GLfloat dx, dy, dz;              /* current rotational velocity */
104   GLfloat ddx, ddy, ddz;           /* current rotational acceleration */
105   GLfloat d_max;                           /* max velocity */
106
107   GLuint      gear1, gear2, gear3;
108   GLuint      gear_inner, gear_outer;
109   GLuint      armature;
110   GLfloat     angle;
111   GLXContext *glx_context;
112   Window      window;
113 } gearsstruct;
114
115 static gearsstruct *gears = NULL;
116
117 /*-
118  * Draw a gear wheel.  You'll probably want to call this function when
119  * building a display list since we do a lot of trig here.
120  *
121  * Input:  inner_radius - radius of hole at center
122  *         outer_radius - radius at center of teeth
123  *         width - width of gear
124  *         teeth - number of teeth
125  *         tooth_depth - depth of tooth
126  *         wire - true for wireframe mode
127  */
128 static void
129 gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
130      GLint teeth, GLfloat tooth_depth, Bool wire, Bool invert)
131 {
132         GLint       i;
133         GLfloat     r0, r1, r2;
134         GLfloat     angle, da;
135         GLfloat     u, v, len;
136
137     if (!invert)
138       {
139         r0 = inner_radius;
140         r1 = outer_radius - tooth_depth / 2.0;
141         r2 = outer_radius + tooth_depth / 2.0;
142         glFrontFace(GL_CCW);
143       }
144     else
145       {
146         r0 = outer_radius;
147         r2 = inner_radius + tooth_depth / 2.0;
148         r1 = outer_radius - tooth_depth / 2.0;
149         glFrontFace(GL_CW);
150       }
151
152         da = 2.0 * M_PI / teeth / 4.0;
153
154         glShadeModel(GL_FLAT);
155
156         /* This subroutine got kind of messy when I added all the checks
157          * for wireframe mode.  A much cleaner solution that I sometimes
158          * use is to have a variable hold the value GL_LINE_LOOP when
159          * in wireframe mode, or hold the value GL_POLYGON otherwise.
160          * Then I just call glBegin(that_variable), give my polygon
161          * coordinates, and glEnd().  Pretty neat eh?  Too bad I couldn't
162          * integrate that trick here.
163          *                                  --Ed.
164          */
165
166         if (!wire)
167                 glNormal3f(0.0, 0.0, 1.0);
168
169         /* draw front face */
170         if (!wire)
171                 glBegin(GL_QUAD_STRIP);
172         for (i = 0; i <= teeth; i++) {
173                 if (wire)
174                         glBegin(GL_LINES);
175                 angle = i * 2.0 * M_PI / teeth;
176                 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
177                 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
178                 if (!wire) {
179                         glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
180                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
181                 } else {
182                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
183                         glVertex3f(r1 * cos(angle + 4 * da), r1 * sin(angle + 4 * da), width * 0.5);
184                         glEnd();
185                 }
186         }
187         if (!wire)
188                 glEnd();
189
190         /* draw front sides of teeth */
191         if (!wire)
192                 glBegin(GL_QUADS);
193         da = 2.0 * M_PI / teeth / 4.0;
194         for (i = 0; i < teeth; i++) {
195                 angle = i * 2.0 * M_PI / teeth;
196
197                 if (wire)
198                         glBegin(GL_LINE_LOOP);
199                 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
200                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
201                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5);
202                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
203                 if (wire)
204                         glEnd();
205         }
206         if (!wire)
207                 glEnd();
208
209
210         if (!wire)
211                 glNormal3f(0.0, 0.0, -1.0);
212
213         /* draw back face */
214         if (!wire)
215                 glBegin(GL_QUAD_STRIP);
216         for (i = 0; i <= teeth; i++) {
217                 angle = i * 2.0 * M_PI / teeth;
218                 if (wire)
219                         glBegin(GL_LINES);
220                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
221                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
222                 if (!wire) {
223                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
224                         glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
225                 } else {
226                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
227                         glVertex3f(r1 * cos(angle + 4 * da), r1 * sin(angle + 4 * da), -width * 0.5);
228                         glEnd();
229                 }
230         }
231         if (!wire)
232                 glEnd();
233
234         /* draw back sides of teeth */
235         if (!wire)
236                 glBegin(GL_QUADS);
237         da = 2.0 * M_PI / teeth / 4.0;
238         for (i = 0; i < teeth; i++) {
239                 angle = i * 2.0 * M_PI / teeth;
240
241                 if (wire)
242                         glBegin(GL_LINE_LOOP);
243                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
244                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5);
245                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
246                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
247                 if (wire)
248                         glEnd();
249         }
250         if (!wire)
251                 glEnd();
252
253
254         /* draw outward faces of teeth */
255         if (!wire)
256                 glBegin(GL_QUAD_STRIP);
257         for (i = 0; i <= teeth; i++) {
258                 angle = i * 2.0 * M_PI / teeth;
259
260         if(!invert) {
261           u = r2 * cos(angle + da) - r1 * cos(angle);
262           v = r2 * sin(angle + da) - r1 * sin(angle);
263         } else {
264           u = r2 * cos(angle + da + M_PI/2) - r1 * cos(angle + M_PI/2);
265           v = r2 * sin(angle + da + M_PI/2) - r1 * sin(angle + M_PI/2);
266         }
267
268                 len = sqrt(u * u + v * v);
269                 u /= len;
270                 v /= len;
271                 glNormal3f(v, -u, 0.0);
272
273                 if (wire)
274                         glBegin(GL_LINES);
275                 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
276                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
277
278                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
279                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
280
281         if(!invert)
282           glNormal3f(cos(angle), sin(angle), 0.0);
283         else
284           glNormal3f(cos(angle + M_PI/2), sin(angle + M_PI/2), 0.0);
285
286                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5);
287                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5);
288
289         if(!invert) {
290           u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
291           v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
292         } else {
293           u = r1 * cos(angle + 3 * da + M_PI/2) - r2 * cos(angle + 2 * da + M_PI/2);
294           v = r1 * sin(angle + 3 * da + M_PI/2) - r2 * sin(angle + 2 * da + M_PI/2);
295         }
296
297                 glNormal3f(v, -u, 0.0);
298
299                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
300                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
301
302         if (!invert)
303           glNormal3f(cos(angle), sin(angle), 0.0);
304         else
305           glNormal3f(cos(angle + M_PI/2), sin(angle + M_PI/2), 0.0);
306
307                 if (wire)
308                         glEnd();
309         }
310
311         if (!wire) {
312                 glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
313                 glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
314                 glEnd();
315         }
316         if (!wire)
317                 glShadeModel(GL_SMOOTH);
318
319         /* draw inside radius cylinder */
320         if (!wire)
321                 glBegin(GL_QUAD_STRIP);
322         for (i = 0; i <= teeth; i++) {
323                 angle = i * 2.0 * M_PI / teeth;
324                 if (wire)
325                         glBegin(GL_LINES);
326
327         if (!invert)
328           glNormal3f(-cos(angle), -sin(angle), 0.0);
329         else
330           glNormal3f(cos(angle), sin(angle), 0.0);
331
332                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
333                 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
334                 if (wire) {
335                         glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
336                         glVertex3f(r0 * cos(angle + 4 * da), r0 * sin(angle + 4 * da), -width * 0.5);
337                         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                         glEnd();
340                 }
341         }
342         if (!wire)
343                 glEnd();
344
345 }
346
347
348 static void
349 unit_tube (Bool wire)
350 {
351   int i;
352   int faces = TUBE_FACES;
353   GLfloat step = M_PI * 2 / faces;
354   GLfloat th;
355   int z = 0;
356
357   /* side walls
358    */
359   glFrontFace(GL_CCW);
360
361 # ifdef SMOOTH_TUBE
362   glBegin(wire ? GL_LINES : GL_QUAD_STRIP);
363 # else
364   glBegin(wire ? GL_LINES : GL_QUADS);
365 # endif
366
367   for (i = 0, th = 0; i <= faces; i++)
368     {
369       GLfloat x = cos (th);
370       GLfloat y = sin (th);
371       glNormal3f(x, 0, y);
372       glVertex3f(x, 0.0, y);
373       glVertex3f(x, 1.0, y);
374       th += step;
375
376 # ifndef SMOOTH_TUBE
377       x = cos (th);
378       y = sin (th);
379       glVertex3f(x, 1.0, y);
380       glVertex3f(x, 0.0, y);
381 # endif
382     }
383   glEnd();
384
385   /* End caps
386    */
387   for (z = 0; z <= 1; z++)
388     {
389       glFrontFace(z == 0 ? GL_CCW : GL_CW);
390       glNormal3f(0, (z == 0 ? -1 : 1), 0);
391       glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
392       if (! wire) glVertex3f(0, z, 0);
393       for (i = 0, th = 0; i <= faces; i++)
394         {
395           GLfloat x = cos (th);
396           GLfloat y = sin (th);
397           glVertex3f(x, z, y);
398           th += step;
399         }
400       glEnd();
401     }
402 }
403
404
405 static void
406 tube (GLfloat x1, GLfloat y1, GLfloat z1,
407       GLfloat x2, GLfloat y2, GLfloat z2,
408       GLfloat diameter, GLfloat cap_size,
409       Bool wire)
410 {
411   GLfloat length, angle, a, b, c;
412
413   if (diameter <= 0) abort();
414
415   a = (x2 - x1);
416   b = (y2 - y1);
417   c = (z2 - z1);
418
419   length = sqrt (a*a + b*b + c*c);
420   angle = acos (a / length);
421
422   glPushMatrix();
423   glTranslatef(x1, y1, z1);
424   glScalef (length, length, length);
425
426   if (c == 0 && b == 0)
427     glRotatef (angle / (M_PI / 180), 0, 1, 0);
428   else
429     glRotatef (angle / (M_PI / 180), 0, -c, b);
430
431   glRotatef (-90, 0, 0, 1);
432   glScalef (diameter/length, 1, diameter/length);
433
434   /* extend the endpoints of the tube by the cap size in both directions */
435   if (cap_size != 0)
436     {
437       GLfloat c = cap_size/length;
438       glTranslatef (0, -c, 0);
439       glScalef (1, 1+c+c, 1);
440     }
441
442   unit_tube (wire);
443   glPopMatrix();
444 }
445
446
447 static void
448 ctube (GLfloat diameter, GLfloat width, Bool wire)
449 {
450   tube (0, 0,  width/2,
451         0, 0, -width/2,
452         diameter, 0, wire);
453 }
454
455 static void
456 arm(GLfloat length,
457     GLfloat width1, GLfloat height1,
458     GLfloat width2, GLfloat height2,
459     Bool wire)
460 {
461   glShadeModel(GL_FLAT);
462
463 #if 0  /* don't need these - they're embedded in other objects */
464   /* draw end 1 */
465   glFrontFace(GL_CW);
466   glNormal3f(-1, 0, 0);
467   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
468   glVertex3f(-length/2, -width1/2, -height1/2);
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   glEnd();
473
474   /* draw end 2 */
475   glFrontFace(GL_CCW);
476   glNormal3f(1, 0, 0);
477   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
478   glVertex3f(length/2, -width2/2, -height2/2);
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   glEnd();
483 #endif
484
485   /* draw top */
486   glFrontFace(GL_CCW);
487   glNormal3f(0, 0, -1);
488   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
489   glVertex3f(-length/2, -width1/2, -height1/2);
490   glVertex3f(-length/2,  width1/2, -height1/2);
491   glVertex3f( length/2,  width2/2, -height2/2);
492   glVertex3f( length/2, -width2/2, -height2/2);
493   glEnd();
494
495   /* draw bottom */
496   glFrontFace(GL_CW);
497   glNormal3f(0, 0, 1);
498   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
499   glVertex3f(-length/2, -width1/2, height1/2);
500   glVertex3f(-length/2,  width1/2, height1/2);
501   glVertex3f( length/2,  width2/2, height2/2);
502   glVertex3f( length/2, -width2/2, height2/2);
503   glEnd();
504
505   /* draw left */
506   glFrontFace(GL_CW);
507   glNormal3f(0, -1, 0);
508   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
509   glVertex3f(-length/2, -width1/2, -height1/2);
510   glVertex3f(-length/2, -width1/2,  height1/2);
511   glVertex3f( length/2, -width2/2,  height2/2);
512   glVertex3f( length/2, -width2/2, -height2/2);
513   glEnd();
514
515   /* draw right */
516   glFrontFace(GL_CCW);
517   glNormal3f(0, 1, 0);
518   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
519   glVertex3f(-length/2,  width1/2, -height1/2);
520   glVertex3f(-length/2,  width1/2,  height1/2);
521   glVertex3f( length/2,  width2/2,  height2/2);
522   glVertex3f( length/2,  width2/2, -height2/2);
523   glEnd();
524
525   glFrontFace(GL_CCW);
526 }
527
528
529 static void
530 draw(ModeInfo * mi)
531 {
532         gearsstruct *gp = &gears[MI_SCREEN(mi)];
533         int         wire = MI_IS_WIREFRAME(mi);
534
535         if (!wire) {
536                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
537         } else {
538                 glClear(GL_COLOR_BUFFER_BIT);
539         }
540
541         glPushMatrix();
542
543     {
544       GLfloat x = gp->rotx;
545       GLfloat y = gp->roty;
546       GLfloat z = gp->rotz;
547       if (x < 0) x = 1 - (x + 1);
548       if (y < 0) y = 1 - (y + 1);
549       if (z < 0) z = 1 - (z + 1);
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 /* lifted from lament.c */
925 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
926 #define RANDSIGN() ((random() & 1) ? 1 : -1)
927
928 static void
929 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
930 {
931   double ppos = *pos;
932
933   /* tick position */
934   if (ppos < 0)
935     ppos = -(ppos + *v);
936   else
937     ppos += *v;
938
939   if (ppos > 1.0)
940     ppos -= 1.0;
941   else if (ppos < 0)
942     ppos += 1.0;
943
944   if (ppos < 0) abort();
945   if (ppos > 1.0) abort();
946   *pos = (*pos > 0 ? ppos : -ppos);
947
948   /* accelerate */
949   *v += *dv;
950
951   /* clamp velocity */
952   if (*v > max_v || *v < -max_v)
953     {
954       *dv = -*dv;
955     }
956   /* If it stops, start it going in the other direction. */
957   else if (*v < 0)
958     {
959       if (random() % 4)
960         {
961           *v = 0;
962
963           /* keep going in the same direction */
964           if (random() % 2)
965             *dv = 0;
966           else if (*dv < 0)
967             *dv = -*dv;
968         }
969       else
970         {
971           /* reverse gears */
972           *v = -*v;
973           *dv = -*dv;
974           *pos = -*pos;
975         }
976     }
977
978   /* Alter direction of rotational acceleration randomly. */
979   if (! (random() % 120))
980     *dv = -*dv;
981
982   /* Change acceleration very occasionally. */
983   if (! (random() % 200))
984     {
985       if (*dv == 0)
986         *dv = 0.00001;
987       else if (random() & 1)
988         *dv *= 1.2;
989       else
990         *dv *= 0.8;
991     }
992 }
993
994
995 void
996 init_gears(ModeInfo * mi)
997 {
998         int         screen = MI_SCREEN(mi);
999
1000         /*Colormap    cmap; */
1001         /* Boolean     rgba, doublebuffer, cmap_installed; */
1002         gearsstruct *gp;
1003
1004         if (gears == NULL) {
1005                 if ((gears = (gearsstruct *) calloc(MI_NUM_SCREENS(mi),
1006                                               sizeof (gearsstruct))) == NULL)
1007                         return;
1008         }
1009         gp = &gears[screen];
1010
1011         gp->window = MI_WINDOW(mi);
1012
1013     gp->rotx = frand(1.0) * RANDSIGN();
1014     gp->roty = frand(1.0) * RANDSIGN();
1015     gp->rotz = frand(1.0) * RANDSIGN();
1016
1017     /* bell curve from 0-1.5 degrees, avg 0.75 */
1018     gp->dx = (frand(1) + frand(1) + frand(1)) / (360*2);
1019     gp->dy = (frand(1) + frand(1) + frand(1)) / (360*2);
1020     gp->dz = (frand(1) + frand(1) + frand(1)) / (360*2);
1021
1022     gp->d_max = gp->dx * 2;
1023
1024     gp->ddx = 0.00006 + frand(0.00003);
1025     gp->ddy = 0.00006 + frand(0.00003);
1026     gp->ddz = 0.00006 + frand(0.00003);
1027
1028         if ((gp->glx_context = init_GL(mi)) != NULL) {
1029                 reshape_gears(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1030                 pinit(mi);
1031         } else {
1032                 MI_CLEARWINDOW(mi);
1033         }
1034 }
1035
1036 void
1037 draw_gears(ModeInfo * mi)
1038 {
1039         gearsstruct *gp = &gears[MI_SCREEN(mi)];
1040         Display    *display = MI_DISPLAY(mi);
1041         Window      window = MI_WINDOW(mi);
1042         int         angle_incr = MI_CYCLES(mi) ? MI_CYCLES(mi) : 2;
1043
1044     if (planetary)
1045       angle_incr *= 3;
1046
1047         if (!gp->glx_context)
1048                 return;
1049
1050         glDrawBuffer(GL_BACK);
1051
1052         glXMakeCurrent(display, window, *(gp->glx_context));
1053         draw(mi);
1054
1055         /* let's do something so we don't get bored */
1056         gp->angle = (int) (gp->angle + angle_incr) % 360;
1057
1058     rotate(&gp->rotx, &gp->dx, &gp->ddx, gp->d_max);
1059     rotate(&gp->roty, &gp->dy, &gp->ddy, gp->d_max);
1060     rotate(&gp->rotz, &gp->dz, &gp->ddz, gp->d_max);
1061
1062     if (mi->fps_p) do_fps (mi);
1063         glFinish();
1064         glXSwapBuffers(display, window);
1065 }
1066
1067 void
1068 release_gears(ModeInfo * mi)
1069 {
1070         if (gears != NULL) {
1071                 int         screen;
1072
1073                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1074                         gearsstruct *gp = &gears[screen];
1075
1076                         if (gp->glx_context) {
1077                                 /* Display lists MUST be freed while their glXContext is current. */
1078                                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1079
1080                                 if (glIsList(gp->gear1))
1081                                         glDeleteLists(gp->gear1, 1);
1082                                 if (glIsList(gp->gear2))
1083                                         glDeleteLists(gp->gear2, 1);
1084                                 if (glIsList(gp->gear3))
1085                                         glDeleteLists(gp->gear3, 1);
1086                                 if (glIsList(gp->gear_inner))
1087                                         glDeleteLists(gp->gear_inner, 1);
1088                                 if (glIsList(gp->gear_outer))
1089                                         glDeleteLists(gp->gear_outer, 1);
1090
1091                         }
1092                 }
1093                 (void) free((void *) gears);
1094                 gears = NULL;
1095         }
1096         FreeAllGL(mi);
1097 }
1098
1099
1100 /*********************************************************/
1101
1102 #endif