http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.00.tar.gz
[xscreensaver] / hacks / glx / engine.c
1 /*
2  * engine.c - GL representation of a 4 stroke engine
3  *
4  * version 1.0
5  *
6  * Copyright (C) 2001 Ben Buxton (bb@cactii.net)
7  *
8  * Permission to use, copy, modify, distribute, and sell this software and its
9  * documentation for any purpose is hereby granted without fee, provided that
10  * the above copyright notice appear in all copies and that both that
11  * copyright notice and this permission notice appear in supporting
12  * documentation.  No representations are made about the suitability of this
13  * software for any purpose.  It is provided "as is" without express or
14  * implied warranty.
15  */
16
17
18 #include <X11/Intrinsic.h>
19
20 #ifdef STANDALONE
21 # define PROGCLASS                                      "Engine"
22 # define HACK_INIT                                      init_engine
23 # define HACK_DRAW                                      draw_engine
24 # define HACK_RESHAPE                           reshape_engine
25 # define engine_opts                                     xlockmore_opts
26 /* insert defaults here */
27
28 #define DEFAULTS        "*delay:       10000       \n" \
29                         "*showFPS:       False       \n" \
30                         "*move:       True       \n" \
31                         "*spin:       True       \n" \
32                         "*rotatespeed:      1\n" \
33
34 # include "xlockmore.h"                         /* from the xscreensaver distribution */
35 #else  /* !STANDALONE */
36 # include "xlock.h"                                     /* from the xlockmore distribution */
37 #endif /* !STANDALONE */
38
39 /* lifted from lament.c */
40 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
41 #define RANDSIGN() ((random() & 1) ? 1 : -1)
42
43
44 #ifdef USE_GL
45
46 #include <GL/glu.h>
47
48
49 static int rotatespeed;
50 static int move;
51 static int spin;
52
53 #undef countof
54 #define countof(x) (sizeof((x))/sizeof((*x)))
55
56 static XrmOptionDescRec opts[] = {
57   {"-rotate-speed", ".engine.rotatespeed", XrmoptionSepArg, "1" },
58   {"-move", ".engine.move", XrmoptionNoArg, (caddr_t) "true" },
59   {"+move", ".engine.move", XrmoptionNoArg, (caddr_t) "false" },
60   {"-spin", ".engine.spin", XrmoptionNoArg, (caddr_t) "true" },
61   {"+spin", ".engine.spin", XrmoptionNoArg, (caddr_t) "false" },
62 };
63
64 static argtype vars[] = {
65   {(caddr_t *) &rotatespeed, "rotatespeed", "Rotatespeed", "1", t_Int},
66   {(caddr_t *) &move, "move", "Move", "True", t_Bool},
67   {(caddr_t *) &spin, "spin", "Spin", "True", t_Bool},
68 };
69
70 ModeSpecOpt engine_opts = {countof(opts), opts, countof(vars), vars, NULL};
71
72 #ifdef USE_MODULES
73 ModStruct   engine_description =
74 {"engine", "init_engine", "draw_engine", "release_engine",
75  "draw_engine", "init_engine", NULL, &engine_opts,
76  1000, 1, 2, 1, 4, 1.0, "",
77  "A four stroke engine", 0, NULL};
78
79 #endif
80
81
82 typedef struct {
83   GLXContext *glx_context;
84   Window window;
85   GLfloat x, y, z; /* position */
86   GLfloat dx, dy, dz; /* position */
87   GLfloat an1, an2, an3; /* internal angle */
88   GLfloat nx, ny, nz; /* spin vector */
89   GLfloat a; /* spin angle */
90   GLfloat da; /* spin speed */
91 } Engine;
92
93 static Engine *engine = NULL;
94
95 #include <math.h>
96 #include <sys/time.h>
97 #include <stdio.h>
98 #include <stdlib.h>
99
100 #ifndef M_PI
101 #define M_PI 3.14159265
102 #endif
103
104 #define MOVE_MULT 0.05
105
106 #define RAND_RANGE(min, max) ((min) + (max - min) * f_rand())
107
108 int win_w, win_h;
109
110 static GLfloat viewer[] = {0.0, 0.0, 30.0};
111 static GLfloat lookat[] = {0.0, 0.0, 0.0};
112 static GLfloat lightpos[] = {7.0, 7.0, 12, 1.0};
113 GLfloat light_sp[] = {0.8, 0.8, 0.8, 0.5};
114 static GLfloat red[] = {1.0, 0, 0, 1.0};
115 static GLfloat green[] = {0.0, 1, 0, 1.0};
116 static GLfloat blue[] = {0, 0, 1, 1.0};
117 static GLfloat white[] = {1.0, 1, 1, 1.0};
118 static GLfloat yellow_t[] = {1, 1, 0, 0.4};
119
120 void circle(float, int,int);
121 GLvoid normal(GLfloat [], GLfloat [], GLfloat [], 
122                   GLfloat *, GLfloat *, GLfloat *);
123
124 float sin_table[720];
125 float cos_table[720];
126 float tan_table[720];
127
128 /* we use trig tables to speed things up - 200 calls to sin()
129  in one frame can be a bit harsh..
130 */
131
132 void make_tables(void) {
133 int i;
134 float f;
135
136   f = 360 / (M_PI * 2);
137   for (i = 0 ; i <= 720 ; i++) {
138     sin_table[i] = sin(i/f);
139   }
140   for (i = 0 ; i <= 720 ; i++) {
141     cos_table[i] = cos(i/f);
142   }
143   for (i = 0 ; i <= 720 ; i++) {
144     tan_table[i] = tan(i/f);
145   }
146 }
147
148 /* if inner and outer are the same, we draw a cylinder, not a tube */
149 /* for a tube, endcaps is 0 (none), 1 (left), 2 (right) or 3(both) */
150 /* angle is how far around the axis to go (up to 360) */
151
152 void cylinder (GLfloat x, GLfloat y, GLfloat z, float length, float outer, float inner, int endcaps, int sang,
153                  int eang) {
154 int a; /* current angle around cylinder */
155 int b = 0; /* previous */
156 int angle, norm, step, sangle;
157 float z1, y1, z2, y2, ex;
158 float y3, z3;
159 float Z1, Y1, Z2, Y2, xl, Y3, Z3;
160 GLfloat y2c[720], z2c[720];
161 GLfloat ony, onz; /* previous normals */
162 int nsegs, tube = 0;
163
164   glPushMatrix();
165   nsegs = outer*(MAX(win_w, win_h)/200);
166   nsegs = MAX(nsegs, 6);
167   nsegs = MAX(nsegs, 40);
168   if (nsegs % 2)
169      nsegs += 1;
170   sangle = sang;
171   angle = eang;
172   ony = onz = 0;
173   z1 = cos_table[sangle]*outer+z; y1 = sin_table[sangle] * outer+y;
174   Z1 = cos_table[sangle] * inner+z; Y1 = sin_table[sangle]*inner+y ; 
175   Z2 = z;
176   Y2 = y;
177   xl = x + length;
178   if (inner < outer && endcaps < 3) tube = 1;
179   step = 360/nsegs;
180
181   glBegin(GL_QUADS);
182   for (a = sangle ; a <= angle || b <= angle ; a+= step) {
183     y2=outer*(float)sin_table[a]+y;
184     z2=outer*(float)cos_table[a]+z;
185     y3=outer*(float)sin_table[a+step]+y;
186     z3=outer*(float)cos_table[a+step]+z;
187     if (endcaps)
188        y2c[a] = y2; z2c[a] = z2; /* cache for later */
189     if (tube) {
190       Y2=inner*(float)sin_table[a]+y;
191       Z2=inner*(float)cos_table[a]+z;
192       Y3=inner*(float)sin_table[a+step]+y;
193       Z3=inner*(float)cos_table[a+step]+z;
194     }
195     glNormal3f(0, y1, z1);
196     glVertex3f(x,y1,z1);
197     glVertex3f(xl,y1,z1);
198     glNormal3f(0, y2, z2);
199     glVertex3f(xl,y2,z2);
200     glVertex3f(x,y2,z2);
201     if (a == sangle && angle - sangle < 360) {
202       if (tube)
203         glVertex3f(x, Y1, Z1);
204       else
205         glVertex3f(x, y, z);
206       glVertex3f(x, y1, z1);
207       glVertex3f(xl, y1, z1);
208       if (tube)
209         glVertex3f(xl, Z1, Z1);
210       else
211         glVertex3f(xl, y, z);
212     }
213     if (tube) {
214       if (endcaps != 1) {
215         glNormal3f(-1, 0, 0); /* left end */
216         glVertex3f(x, y1, z1);
217         glVertex3f(x, y2, z2);
218         glVertex3f(x, Y2, Z2);
219         glVertex3f(x, Y1, Z1);
220       }
221
222       glNormal3f(0, -Y1, -Z1); /* inner surface */
223       glVertex3f(x, Y1, Z1);
224       glVertex3f(xl, Y1, Z1);
225       glNormal3f(0, -Y2, -Z2);
226       glVertex3f(xl, Y2, Z2);
227       glVertex3f(x, Y2, Z2);
228
229       if (endcaps != 2) {
230         glNormal3f(1, 0, 0); /* right end */
231         glVertex3f(xl, y1, z1);
232         glVertex3f(xl, y2, z2);
233         glVertex3f(xl, Y2, Z2);
234         glVertex3f(xl, Y1, Z1);
235       }
236     }
237
238     z1=z2; y1=y2;
239     Z1=Z2; Y1=Y2;
240     b = a;
241   }
242   glEnd();
243
244   if (angle - sangle < 360) {
245     GLfloat nx, ny, nz;
246     GLfloat v1[3], v2[3], v3[3];
247     v1[0] = x; v1[1] = y; v1[2] = z;
248     v2[0] = x; v2[1] = y1; v2[2] = z1;
249     v3[0] = xl; v3[1] = y1; v3[2] = z1;
250     normal(&v2[0], &v1[0], &v3[0], &nx, &ny, &nz);
251     glBegin(GL_QUADS);
252     glNormal3f(nx, ny, nz);
253     glVertex3f(x, y, z);
254     glVertex3f(x, y1, z1);
255     glVertex3f(xl, y1, z1);
256     glVertex3f(xl, y, z);
257     glEnd();
258   }
259   if (endcaps) {
260     GLfloat end, start;
261     if (tube) {
262       if (endcaps == 1) {
263         end = 0;
264         start = 0;
265       } else if (endcaps == 2) {
266         start = end = length+0.01;
267       } else {
268         end = length+0.02; start = -0.01;
269       }
270       norm = (ex == length+0.01) ? -1 : 1;
271     } else  {
272       end = length;
273       start = 0;
274       norm = -1;
275     }
276
277     for(ex = start ; ex <= end ; ex += length) {
278       z1 = outer*cos_table[sangle]+z;
279       y1 = y+sin_table[sangle]*outer;
280       step = 360/nsegs;
281       glBegin(GL_TRIANGLES);
282       b = 0;
283       for (a = sangle ; a <= angle || b <= angle; a+= step) {
284           glNormal3f(norm, 0, 0);
285           glVertex3f(x+ex,y, z);
286           glVertex3f(x+ex,y1,z1);
287           glVertex3f(x+ex,y2c[a],z2c[a]);
288         y1 = y2c[a]; z1 = z2c[a];
289         b = a;
290       }
291       if (!tube) norm = 1;
292       glEnd();
293     }
294   }
295   glPopMatrix();
296 }
297
298 GLvoid normal(GLfloat v1[], GLfloat v2[], GLfloat v3[], 
299                   GLfloat *nx, GLfloat *ny, GLfloat *nz)
300 {
301    GLfloat x, y, z, X, Y, Z;
302
303    x = v2[0]-v1[0];
304    y = v2[1]-v1[1];
305    z = v2[2]-v1[2];
306    X = v3[0]-v1[0];
307    Y = v3[1]-v1[1];
308    Z = v3[2]-v1[2];
309
310    *nx = Y*z - Z*y;
311    *ny = Z*x - X*z;
312    *nz = X*y - Y*x;
313
314
315
316
317
318 void circle(float radius, int segments, int half) {
319 float x1 = 0, x2 = 0;
320 float y1 = 0, y2 = 0;
321 int i, t, s;
322
323   if (half) {
324     t = 270; s = 90;
325     x1 = radius, y1 = 0;
326   } else {
327     t = 360, s = 0;
328   }
329   glBegin(GL_TRIANGLES);
330   glNormal3f(1, 0, 0);
331   for(i=s;i<=t;i+=10)
332   {
333     float angle=i;
334     x2=radius*(float)cos_table[(int)angle];
335     y2=radius*(float)sin_table[(int)angle];
336     glVertex3f(0,0,0);
337     glVertex3f(x1,y1,0);
338     glVertex3f(x2,y2,0);
339     x1=x2;
340     y1=y2;
341   }
342   glEnd();
343 }
344
345 void ring(GLfloat inner, GLfloat outer, int nsegs) {
346 GLfloat z1, z2, y1, y2;
347 GLfloat Z1, Z2, Y1, Y2;
348 int i;
349
350   z1 = inner; y1 = 0;
351   Z1 = outer; Y1 = 0;
352   glBegin(GL_QUADS);
353   glNormal3f(1, 0, 0);
354   for(i=0; i <=360 ; i+= 360/nsegs)
355   {
356     float angle=i;
357     z2=inner*(float)sin_table[(int)angle];
358     y2=inner*(float)cos_table[(int)angle];
359     Z2=outer*(float)sin_table[(int)angle];
360     Y2=outer*(float)cos_table[(int)angle];
361     glVertex3f(0, Y1, Z1);
362     glVertex3f(0, y1, z1);
363     glVertex3f(0, y2, z2);
364     glVertex3f(0, Y2, Z2);
365     z1=z2;
366     y1=y2;
367     Z1=Z2;
368     Y1=Y2;
369   }
370   glEnd();
371 }
372
373 void Rect(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
374             GLfloat t) {
375 GLfloat yh;
376 GLfloat xw;
377 GLfloat zt;
378
379   yh = y+h; xw = x+w; zt = z - t;
380
381   glBegin(GL_QUADS); /* front */
382     glNormal3f(0, 0, 1);
383     glVertex3f(x, y, z);
384     glVertex3f(x, yh, z);
385     glVertex3f(xw, yh, z);
386     glVertex3f(xw, y, z);
387   /* back */
388     glNormal3f(0, 0, -1);
389     glVertex3f(x, y, zt);
390     glVertex3f(x, yh, zt);
391     glVertex3f(xw, yh, zt);
392     glVertex3f(xw, y, zt);
393   /* top */
394     glNormal3f(0, 1, 0);
395     glVertex3f(x, yh, z);
396     glVertex3f(x, yh, zt);
397     glVertex3f(xw, yh, zt);
398     glVertex3f(xw, yh, z);
399   /* bottom */
400     glNormal3f(0, -1, 0);
401     glVertex3f(x, y, z);
402     glVertex3f(x, y, zt);
403     glVertex3f(xw, y, zt);
404     glVertex3f(xw, y, z);
405   /* left */
406     glNormal3f(-1, 0, 0);
407     glVertex3f(x, y, z);
408     glVertex3f(x, y, zt);
409     glVertex3f(x, yh, zt);
410     glVertex3f(x, yh, z);
411   /* right */
412     glNormal3f(1, 0, 0);
413     glVertex3f(xw, y, z);
414     glVertex3f(xw, y, zt);
415     glVertex3f(xw, yh, zt);
416     glVertex3f(xw, yh, z);
417   glEnd();
418 }
419
420 void makepiston(void) {
421 GLfloat colour[] = {0.6, 0.6, 0.6, 1.0};
422 int i;
423   
424   i = glGenLists(1);
425   glNewList(i, GL_COMPILE);
426   glRotatef(90, 0, 0, 1);
427   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colour);
428   glMaterialfv(GL_FRONT, GL_SPECULAR, colour);
429   glMateriali(GL_FRONT, GL_SHININESS, 20);
430   cylinder(0, 0, 0, 2, 1, 0.7, 2, 0, 360); /* body */
431   colour[0] = colour[1] = colour[2] = 0.2;
432   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colour);
433   cylinder(1.6, 0, 0, 0.1, 1.05, 1.05, 0, 0, 360); /* ring */
434   cylinder(1.8, 0, 0, 0.1, 1.05, 1.05, 0, 0, 360); /* ring */
435   glEndList();
436 }
437
438 void CrankBit(GLfloat x, GLfloat y, GLfloat z) {
439   Rect(x, y, z, 0.2, 1.8, 1);
440 }
441
442 void boom(GLfloat x, GLfloat y, int s) {
443 static GLfloat red[] = {0, 0, 0, 0.9};
444 static GLfloat lpos[] = {0, 0, 0, 1};
445 static GLfloat d = 0, wd;
446 static int time = 0;
447
448   if (time == 0 && s) {
449     red[0] = red[1] = 0;
450     d = 0.05;
451     time++;
452     glEnable(GL_LIGHT1); 
453   } else if (time == 0 && !s) {
454     return;
455   } else if (time >= 8 && time < 16 && !s) {
456     time++;
457     red[0] -= 0.2; red[1] -= 0.1;
458     d-= 0.04;
459   } else if (time >= 16) {
460     time = 0;
461     glDisable(GL_LIGHT1);
462     return;
463   } else {
464     red[0] += 0.2; red[1] += 0.1;
465     d+= 0.04;
466     time++;
467   }
468   lpos[0] = x; lpos[1] = y-d;
469   glLightfv(GL_LIGHT1, GL_POSITION, lpos);
470   glLightfv(GL_LIGHT1, GL_DIFFUSE, red);
471   glLightfv(GL_LIGHT1, GL_SPECULAR, red);
472   glLighti(GL_LIGHT1, GL_LINEAR_ATTENUATION, 1.3);
473   glLighti(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0);
474
475   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
476   glPushMatrix();
477   glRotatef(90, 0, 0, 1);
478   wd = d*3;
479   if (wd > 0.7) wd = 0.7;
480   glEnable(GL_BLEND);
481   glDepthMask(GL_FALSE);
482   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
483   cylinder(y-d, -x, 0, d, wd, wd, 1, 0, 360);
484   glDepthMask(GL_TRUE);
485   glDisable(GL_BLEND);
486   glPopMatrix();
487 }
488
489 void display(Engine *e) {
490
491 static int a = 0;
492 GLfloat zb, yb;
493 static GLfloat ln[730], yp[730], ang[730];
494 static int ln_init = 0;
495 static int spark;
496
497   glEnable(GL_LIGHTING);
498   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
499   glLoadIdentity();
500   gluLookAt(viewer[0], viewer[1], viewer[2], lookat[0], lookat[1], lookat[2], 0.0, 1.0, 0.0);
501   glPushMatrix();
502   glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
503   glLightfv(GL_LIGHT0, GL_SPECULAR, light_sp);
504   glLightfv(GL_LIGHT0, GL_DIFFUSE, light_sp);
505
506   if (move) {
507 /* calculate position for the whole object */
508     e->x = sin(e->an1)*15;
509     e->an1 += e->dx; 
510     if (e->an1 >= 2*M_PI) e->an1 -= 2*M_PI;
511
512     e->y = sin(e->an2)*15;
513     e->an2 += e->dy; 
514     if (e->an2 >= 2*M_PI) e->an2 -= 2*M_PI;
515
516     e->z = sin(e->an3)*10-10;
517     e->an3 += e->dz; 
518     if (e->an3 >= 2*M_PI) e->an3 -= 2*M_PI;
519     glTranslatef(e->x, e->y, e->z);
520   }
521
522   if (spin) glRotatef(e->a, e->nx, e->ny, e->nz); 
523   glTranslatef(-5, 0, 0); 
524   if (spin) e->a += e->da;
525   if (spin && (e->a > 360 || e->a < -360)) {
526      e->a -= (e->a > 0) ? 360 : -360;
527      if ((random() % 5) == 4) {
528         e->da = (float)(random() % 1000);
529         e->da = e->da/125 - 4;
530      }
531      if ((random() % 5) == 4) {
532         e->nx = (float)(random() % 100) / 100;
533         e->ny = (float)(random() % 100) / 100;
534         e->nz = (float)(random() % 100) / 100;
535      }
536   }
537 /* crankshaft */
538   glPushMatrix();
539   glRotatef(a, 1, 0, 0);
540   glCallList(1);
541   glPopMatrix();
542
543   /* init the ln[] matrix for speed */
544   if (ln_init == 0) {
545     for (ln_init = 0 ; ln_init < 730 ; ln_init++) {
546       zb = sin_table[ln_init];
547       yb = cos_table[ln_init];
548       yp[ln_init] = yb + sqrt(25 - (zb*zb)); /* y ordinate of piston */
549       ln[ln_init] = sqrt(zb*zb + (yb-yp[ln_init])*(yb-yp[ln_init])); /* length of rod */
550       ang[ln_init] = asin(zb/5)*57; /* angle of connecting rod */
551       ang[ln_init] *= -1;
552     }
553   }
554
555   zb = sin_table[a];
556   yb = cos_table[a];
557
558 /* pistons */
559   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, white);
560   glPushMatrix();
561   glTranslatef(0, yp[a]-0.3, 0);
562   glCallList(2);
563   glPopMatrix();
564   glPushMatrix();
565   glTranslatef(3.2, yp[(a > 180 ? a-180 : a+180)]-0.3, 0);
566   glCallList(2);
567   glPopMatrix();
568   glPushMatrix();
569   glTranslatef(6.5, yp[a]-0.3, 0);
570   glCallList(2);
571   glPopMatrix();
572   glPushMatrix();
573   glTranslatef(9.8, yp[(a > 180 ? a-180 : a+180)]-0.3, 0);
574   glCallList(2);
575   glPopMatrix();
576
577 /* spark plugs */
578   glPushMatrix();
579   glRotatef(90, 0, 0, 1);
580   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
581   cylinder(8.5, 0, 0, 0.5, 0.4, 0.3, 1, 0, 360);
582   cylinder(8.5, -3.2, 0, 0.5, 0.4, 0.3, 1, 0, 360);
583   cylinder(8.5, -6.5, 0, 0.5, 0.4, 0.3, 1, 0, 360);
584   cylinder(8.5, -9.8, 0, 0.5, 0.4, 0.3, 1, 0, 360);
585
586   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, white);
587   cylinder(8, 0, 0, 0.5, 0.2, 0.2, 1, 0, 360);
588   cylinder(8, -3.2, 0, 0.5, 0.2, 0.2, 1, 0, 360);
589   cylinder(8, -6.5, 0, 0.5, 0.2, 0.2, 1, 0, 360);
590   cylinder(8, -9.8, 0, 0.5, 0.2, 0.2, 1, 0, 360);
591
592   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, white);
593   cylinder(9, 0, 0, 1, 0.15, 0.15, 1, 0, 360);
594   cylinder(9, -3.2, 0, 1, 0.15, 0.15, 1, 0, 360);
595   cylinder(9, -6.5, 0, 1, 0.15, 0.15, 1, 0, 360);
596   cylinder(9, -9.8, 0, 1, 0.15, 0.15, 1, 0, 360);
597
598   glPopMatrix();
599
600   if (a == 0) spark = 1 - spark;
601
602   if (spark == 0) {
603     if (a == 0)
604       boom(0, 8, 1);
605     else if (a == 180) 
606       boom(3.2, 8, 1);
607     if (a < 180)
608       boom(0, 8, 0);
609     else if (a < 360)
610       boom(3.2, 8, 0);
611   } else {
612     if (a == 0)
613       boom(6.5, 8, 1);
614     else if (a == 180) 
615       boom(9.8, 8, 1);
616     if (a < 180)
617       boom(6.5, 8, 0);
618     else if (a < 360)
619       boom(9.8, 8, 0);
620   }
621
622
623
624   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
625   glPushMatrix();
626   cylinder(-0.8, yb, zb, 1.6, 0.3, 0.3, 1, 0, 365);
627   cylinder(5.7, yb, zb, 1.7, 0.3, 0.3, 1, 0, 365);
628
629   cylinder(2.4, -yb, -zb, 1.7, 0.3, 0.3, 1, 0, 365);
630   cylinder(9.0, -yb, -zb, 1.7, 0.3, 0.3, 1, 0, 365);
631   glPopMatrix();
632
633  /* rod */
634   glPushMatrix();
635   glRotatef(90, 0, 0, 1);
636   glRotatef(ang[a], 0, -1, 0);
637   cylinder(yb, 0, zb, ln[a], 0.2, 0.2, 0, 0, 365);
638   cylinder(yb, -6.4, zb, ln[a], 0.2, 0.2, 0, 0, 365);
639   glPopMatrix();
640
641   glPushMatrix();
642   glRotatef(90, 0, 0, 1);
643   glRotatef(ang[a+180], 0, -1, 0);
644   cylinder(-yb, -3.2, -zb, ln[a], 0.2, 0.2, 0, 0, 365);
645   cylinder(-yb, -9.7, -zb, ln[a], 0.2, 0.2, 0, 0, 365);
646   glPopMatrix();
647
648
649   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, yellow_t);
650   glEnable(GL_BLEND);
651   glDepthMask(GL_FALSE);
652   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
653
654   Rect(-1, 8.3, 1, 12, 0.2, 2);
655   Rect(-1.2, -0.5, 1, 0.2, 9, 2);
656
657   Rect(1.4, 3, 1, 0.6, 5.3, 2);
658   Rect(4.4, 3, 1, 1, 5.3, 2);
659   Rect(7.7, 3, 1, 0.8, 5.3, 2);
660   Rect(10.8, -0.5, 1, 0.2, 8.8, 2);
661
662   Rect(-1, 2.8, 1, 12, 0.2, 0.2); 
663   Rect(-1, 2.8, -1, 12, 0.2, 0.2); 
664
665   glDepthMask(GL_TRUE);
666   glDisable(GL_BLEND);
667
668
669   a+=10; if (a >= 360) a = 0;
670   glPopMatrix();
671   glFlush();
672 }
673
674 void makeshaft (void) {
675 int i;
676   i = glGenLists(1);
677   glNewList(i, GL_COMPILE);
678   cylinder(10.4, 0, 0, 2, 0.3, 0.3, 1, 0, 365);
679   cylinder(7.1, 0, 0, 2, 0.3, 0.3, 0, 0, 365);
680   cylinder(3.8, 0, 0, 2, 0.3, 0.3, 0, 0, 365);
681   cylinder(0.5, 0, 0, 2, 0.3, 0.3, 0, 0, 365);
682   cylinder(-1.5, 0, 0, 1, 0.3, 0.3, 1, 0, 365);
683
684   cylinder(12.4, 0, 0, 1, 3, 2.5, 0, 0, 365);
685   Rect(12.4, -0.3, 2.8, 0.5, 0.6, 5.6);
686   Rect(12.4, -2.8, 0.3, 0.5, 5.6, 0.6);
687
688   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
689   CrankBit(0.5, -0.4, 0.5);
690   cylinder(0.5, 0.5, 0, 0.2, 2, 2, 1, 240, 300);
691   CrankBit(-0.7, -0.4, 0.5);
692   cylinder(-0.7, 0.5, 0, 0.2, 2, 2, 1, 240, 300);
693
694   CrankBit(2.5, -1.4, 0.5);
695   cylinder(2.5, -0.5, 0, 0.2, 2, 2, 1, 60, 120);
696   CrankBit(3.8, -1.4, 0.5);
697   cylinder(3.8, -0.5, 0, 0.2, 2, 2, 1, 60, 120);
698
699   CrankBit(5.8, -0.4, 0.5);
700   cylinder(5.8, 0.5, 0, 0.2, 2, 2, 1, 240, 300);
701   CrankBit(7.1, -0.4, 0.5);
702   cylinder(7.1, 0.5, 0, 0.2, 2, 2, 1, 240, 300);
703
704   CrankBit(9.1, -1.4, 0.5);
705   cylinder(9.1, -0.5, 0, 0.2, 2, 2, 1, 60, 120);
706   CrankBit(10.4, -1.4, 0.5);
707   cylinder(10.4, -0.5, 0, 0.2, 2, 2, 1, 60, 120);
708
709   glEndList();
710
711 }
712
713 void reshape_engine(ModeInfo *mi, int width, int height)
714 {
715
716  glViewport(0,0,(GLint)width, (GLint) height);
717  glMatrixMode(GL_PROJECTION);
718  glLoadIdentity();
719  glFrustum(-1.0,1.0,-1.0,1.0,1.5,70.0);
720  glMatrixMode(GL_MODELVIEW);
721  win_h = height; win_w = width;
722 }
723
724
725 void init_engine(ModeInfo *mi)
726 {
727 int screen = MI_SCREEN(mi);
728 Engine *e;
729
730  if (engine == NULL) {
731    if ((engine = (Engine *) calloc(MI_NUM_SCREENS(mi),
732                                         sizeof(Engine))) == NULL)
733           return;
734  }
735  e = &engine[screen];
736  e->window = MI_WINDOW(mi);
737
738  e->x = e->y = e->z = e->a = e->an1 = e->nx = e->ny = e->nz = 
739  e->dx = e->dy = e->dz = e->da = 0;
740
741  if (move) {
742    e->dx = (float)(random() % 1000)/30000;
743    e->dy = (float)(random() % 1000)/30000;
744    e->dz = (float)(random() % 1000)/30000;
745  } else {
746   viewer[0] = 0; viewer[1] = 6; viewer[2] = 15;
747   lookat[0] = 0; lookat[1] = 4; lookat[2] = 0; 
748  }
749  if (spin) {
750    e->da = (float)(random() % 1000)/125 - 4;
751    e->nx = (float)(random() % 100) / 100;
752    e->ny = (float)(random() % 100) / 100;
753    e->nz = (float)(random() % 100) / 100;
754  }
755
756  if ((e->glx_context = init_GL(mi)) != NULL) {
757       reshape_engine(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
758  } else {
759      MI_CLEARWINDOW(mi);
760  }
761  glClearColor(0.0,0.0,0.0,0.0);
762  glShadeModel(GL_SMOOTH);
763  glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
764  glEnable(GL_DEPTH_TEST);
765  glEnable(GL_LIGHTING);
766  glEnable(GL_LIGHT0);
767  glEnable(GL_NORMALIZE);
768  make_tables();
769  makeshaft();
770  makepiston();
771 }
772
773 void draw_engine(ModeInfo *mi) {
774 Engine *e = &engine[MI_SCREEN(mi)];
775 Window w = MI_WINDOW(mi);
776 Display *disp = MI_DISPLAY(mi);
777
778   if (!e->glx_context)
779       return;
780
781   glXMakeCurrent(disp, w, *(e->glx_context));
782
783   display(e);
784
785   if(mi->fps_p) do_fps(mi);
786   glFinish(); 
787   glXSwapBuffers(disp, w);
788 }
789
790 void release_engine(ModeInfo *mi) {
791
792   if (engine != NULL) {
793    (void) free((void *) engine);
794    engine = NULL;
795   }
796   FreeAllGL(MI);
797 }
798
799 #endif