From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / glx / pipes.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* pipes --- 3D selfbuiding pipe system */
3
4 #if 0
5 static const char sccsid[] = "@(#)pipes.c       4.07 97/11/24 xlockmore";
6 #endif
7
8 /*-
9  * Permission to use, copy, modify, and distribute this software and its
10  * documentation for any purpose and without fee is hereby granted,
11  * provided that the above copyright notice appear in all copies and that
12  * both that copyright notice and this permission notice appear in
13  * supporting documentation.
14  *
15  * This file is provided AS IS with no warranties of any kind.  The author
16  * shall have no liability with respect to the infringement of copyrights,
17  * trade secrets or any patents by this file or any part thereof.  In no
18  * event will the author be liable for any lost revenue or profits or
19  * other special, indirect and consequential damages.
20  *
21  * This program was inspired on a WindowsNT(R)'s screen saver. It was written 
22  * from scratch and it was not based on any other source code.
23  *
24  * ==========================================================================
25  * The routine myElbow is derivated from the doughnut routine from the MesaGL
26  * library (more especifically the Mesaaux library) written by Brian Paul.
27  * ==========================================================================
28  *
29  * Thanks goes to Brian Paul for making it possible and inexpensive to use
30  * OpenGL at home.
31  *
32  * Since I'm not a native English speaker, my apologies for any grammatical
33  * mistake.
34  *
35  * My e-mail address is
36  * m-vianna@usa.net
37  * Marcelo F. Vianna (Apr-09-1997)
38  *
39  * Revision History:
40  * 24-Jun-12: Eliminate single-buffer dependency.
41  * 29-Apr-97: Factory equipment by Ed Mackey.  Productive day today, eh?
42  * 29-Apr-97: Less tight turns Jeff Epler <jepler@inetnebr.com>
43  * 29-Apr-97: Efficiency speed-ups by Marcelo F. Vianna
44  */
45
46 /* This program was originally written to be single-buffered: it kept
47    building up new objects in the front buffer by never clearing the
48    depth or color buffers at the end of each frame.  In that way, it
49    was drawing a very small number of polygons per frame.  However,
50    modern systems make it difficult to live in a single-buffered world
51    like that.  So I changed it to re-generate the scene at every
52    frame, which makes it vastly less efficient, but also, makes it
53    work right on modern hardware.  It generates the entire system up
54    front, putting each "frame" of the animation into its own display
55    list; then it draws successively more of those display lists each
56    time the redisplay method is called.  When it reaches the end,
57    it regenerates a new system and re-populates the existing display
58    lists. -- jwz.
59  */
60
61 #ifdef STANDALONE
62 # define DEFAULTS       "*delay:                10000   \n"                     \
63                                         "*count:                2       \n"                     \
64                                         "*cycles:               5       \n"                     \
65                                         "*size:                 500     \n"                     \
66                         "*showFPS:      False   \n"                 \
67                         "*fpsSolid:     True    \n"                 \
68                         "*wireframe:    False   \n"                 \
69                                         "*suppressRotationAnimation: True\n" \
70
71 # define refresh_pipes 0
72 # define release_pipes 0
73 # include "xlockmore.h"                         /* from the xscreensaver distribution */
74 #else  /* !STANDALONE */
75 # include "xlock.h"                                     /* from the xlockmore distribution */
76 #endif /* !STANDALONE */
77
78 #ifdef USE_GL
79
80 #ifdef HAVE_JWXYZ
81 # include "jwxyz.h"
82 #else
83 # include <X11/Xlib.h>
84 # include <GL/gl.h>
85 # include <GL/glu.h>
86 #endif
87
88 #ifdef HAVE_JWZGLES
89 # include "jwzgles.h"
90 #endif /* HAVE_JWZGLES */
91
92 #include "sphere.h"
93 #include "buildlwo.h"
94 #include "teapot.h"
95 #include "gltrackball.h"
96
97 #define DEF_FACTORY     "2"
98 #define DEF_FISHEYE     "True"
99 #define DEF_TIGHTTURNS  "False"
100 #define DEF_ROTATEPIPES "True"
101 #define NofSysTypes     3
102
103 static int  factory;
104 static Bool fisheye, tightturns, rotatepipes;
105
106 static XrmOptionDescRec opts[] =
107 {
108         {"-factory", ".pipes.factory", XrmoptionSepArg, 0},
109         {"-fisheye", ".pipes.fisheye", XrmoptionNoArg, "on"},
110         {"+fisheye", ".pipes.fisheye", XrmoptionNoArg, "off"},
111         {"-tightturns", ".pipes.tightturns", XrmoptionNoArg, "on"},
112         {"+tightturns", ".pipes.tightturns", XrmoptionNoArg, "off"},
113       {"-rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, "on"},
114       {"+rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, "off"},
115 };
116 static argtype vars[] =
117 {
118         {&factory, "factory", "Factory", DEF_FACTORY, t_Int},
119         {&fisheye, "fisheye", "Fisheye", DEF_FISHEYE, t_Bool},
120         {&tightturns, "tightturns", "Tightturns", DEF_TIGHTTURNS, t_Bool},
121         {&rotatepipes, "rotatepipes", "Rotatepipes", DEF_ROTATEPIPES, t_Bool},
122 };
123 static OptionStruct desc[] =
124 {
125         {"-factory num", "how much extra equipment in pipes (0 for none)"},
126         {"-/+fisheye", "turn on/off zoomed-in view of pipes"},
127         {"-/+tightturns", "turn on/off tight turns"},
128         {"-/+rotatepipes", "turn on/off pipe system rotation per screenful"},
129 };
130
131 ENTRYPOINT ModeSpecOpt pipes_opts =
132 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
133
134 #ifdef USE_MODULES
135 ModStruct   pipes_description =
136 {"pipes", "init_pipes", "draw_pipes", NULL,
137  "draw_pipes",
138  "change_pipes", NULL, &pipes_opts,
139  1000, 2, 5, 500, 4, 1.0, "",
140  "Shows a selfbuilding pipe system", 0, NULL};
141
142 #endif
143
144 #define Scale4Window               0.1
145
146 #define one_third                  0.3333333333333333333
147
148 #define dirNone -1
149 #define dirUP 0
150 #define dirDOWN 1
151 #define dirLEFT 2
152 #define dirRIGHT 3
153 #define dirNEAR 4
154 #define dirFAR 5
155
156 #define HCELLS 33
157 #define VCELLS 25
158 #define DEFINEDCOLORS 7
159 #define elbowradius 0.5
160
161 /*************************************************************************/
162
163 typedef struct {
164         int         flip;
165
166         int         Cells[HCELLS][VCELLS][HCELLS];
167         int         usedcolors[DEFINEDCOLORS];
168         int         directions[6];
169         int         ndirections;
170         int         nowdir, olddir;
171         int         system_number;
172         int         counter;
173         int         PX, PY, PZ;
174         int         number_of_systems;
175         int         system_type;
176         int         system_length;
177         int         turncounter;
178         Window      window;
179         const float *system_color;
180         GLfloat     initial_rotation;
181         GLuint      valve, bolts, betweenbolts, elbowbolts, elbowcoins;
182         GLuint      guagehead, guageface, guagedial, guageconnector, teapot;
183     int         teapot_polys;
184         GLXContext *glx_context;
185
186     Bool button_down_p;
187     trackball_state *trackball;
188     GLuint *dlists, *poly_counts;
189     int dlist_count, dlist_size;
190     int system_index, system_size;
191
192     int fadeout;
193
194 } pipesstruct;
195
196 extern struct lwo LWO_BigValve, LWO_PipeBetweenBolts, LWO_Bolts3D;
197 extern struct lwo LWO_GuageHead, LWO_GuageFace, LWO_GuageDial, LWO_GuageConnector;
198 extern struct lwo LWO_ElbowBolts, LWO_ElbowCoins;
199
200 static const float front_shininess[] = {60.0};
201 static const float front_specular[] = {0.7, 0.7, 0.7, 1.0};
202 static const float ambient0[] = {0.4, 0.4, 0.4, 1.0};
203 static const float diffuse0[] = {1.0, 1.0, 1.0, 1.0};
204 static const float ambient1[] = {0.2, 0.2, 0.2, 1.0};
205 static const float diffuse1[] = {0.5, 0.5, 0.5, 1.0};
206 static const float position0[] = {1.0, 1.0, 1.0, 0.0};
207 static const float position1[] = {-1.0, -1.0, 1.0, 0.0};
208 static const float lmodel_ambient[] = {0.5, 0.5, 0.5, 1.0};
209 static const float lmodel_twoside[] = {GL_TRUE};
210
211 static const float MaterialRed[] = {0.7, 0.0, 0.0, 1.0};
212 static const float MaterialGreen[] = {0.1, 0.5, 0.2, 1.0};
213 static const float MaterialBlue[] = {0.0, 0.0, 0.7, 1.0};
214 static const float MaterialCyan[] = {0.2, 0.5, 0.7, 1.0};
215 static const float MaterialYellow[] = {0.7, 0.7, 0.0, 1.0};
216 static const float MaterialMagenta[] = {0.6, 0.2, 0.5, 1.0};
217 static const float MaterialWhite[] = {0.7, 0.7, 0.7, 1.0};
218 static const float MaterialGray[] = {0.2, 0.2, 0.2, 1.0};
219
220 static pipesstruct *pipes = NULL;
221
222
223 static void
224 MakeTube(ModeInfo *mi, int direction)
225 {
226     Bool        wire = MI_IS_WIREFRAME(mi);
227         float       an;
228         float       SINan_3, COSan_3;
229     int facets = (wire ? 5 : 24);
230
231         /*dirUP    = 00000000 */
232         /*dirDOWN  = 00000001 */
233         /*dirLEFT  = 00000010 */
234         /*dirRIGHT = 00000011 */
235         /*dirNEAR  = 00000100 */
236         /*dirFAR   = 00000101 */
237
238         if (!(direction & 4)) {
239                 glRotatef(90.0, (direction & 2) ? 0.0 : 1.0,
240                           (direction & 2) ? 1.0 : 0.0, 0.0);
241         }
242         glBegin(wire ? GL_LINE_STRIP : GL_QUAD_STRIP);
243         for (an = 0.0; an <= 2.0 * M_PI; an += M_PI * 2 / facets) {
244                 glNormal3f((COSan_3 = cos(an) / 3.0), (SINan_3 = sin(an) / 3.0), 0.0);
245                 glVertex3f(COSan_3, SINan_3, one_third);
246                 glVertex3f(COSan_3, SINan_3, -one_third);
247         mi->polygon_count++;
248         }
249         glEnd();
250 }
251
252 static void
253 mySphere(float radius, Bool wire)
254 {
255 #if 0
256         GLUquadricObj *quadObj;
257
258         quadObj = gluNewQuadric();
259         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
260         gluSphere(quadObj, radius, 16, 16);
261         gluDeleteQuadric(quadObj);
262 #else
263     glPushMatrix();
264     glScalef (radius, radius, radius);
265     glRotatef (90, 1, 0, 0);
266     unit_sphere (16, 16, wire);
267     glPopMatrix();
268 #endif
269 }
270
271 static void
272 myElbow(ModeInfo * mi, int bolted)
273 {
274         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
275     Bool        wire = MI_IS_WIREFRAME(mi);
276
277     int nsides = (wire ? 6 : 25);
278     int rings  = nsides;
279 #define r one_third
280 #define R one_third
281
282         int         i, j;
283         GLfloat     p0[3], p1[3], p2[3], p3[3];
284         GLfloat     n0[3], n1[3], n2[3], n3[3];
285         GLfloat     COSphi, COSphi1, COStheta, COStheta1;
286         GLfloat     _SINtheta, _SINtheta1;
287
288         for (i = 0; i <= rings / 4; i++) {
289                 GLfloat     theta, theta1;
290
291                 theta = (GLfloat) i *2.0 * M_PI / rings;
292
293                 theta1 = (GLfloat) (i + 1) * 2.0 * M_PI / rings;
294                 for (j = 0; j < nsides; j++) {
295                         GLfloat     phi, phi1;
296
297                         phi = (GLfloat) j *2.0 * M_PI / nsides;
298
299                         phi1 = (GLfloat) (j + 1) * 2.0 * M_PI / nsides;
300
301                         p0[0] = (COStheta = cos(theta)) * (R + r * (COSphi = cos(phi)));
302                         p0[1] = (_SINtheta = -sin(theta)) * (R + r * COSphi);
303
304                         p1[0] = (COStheta1 = cos(theta1)) * (R + r * COSphi);
305                         p1[1] = (_SINtheta1 = -sin(theta1)) * (R + r * COSphi);
306
307                         p2[0] = COStheta1 * (R + r * (COSphi1 = cos(phi1)));
308                         p2[1] = _SINtheta1 * (R + r * COSphi1);
309
310                         p3[0] = COStheta * (R + r * COSphi1);
311                         p3[1] = _SINtheta * (R + r * COSphi1);
312
313                         n0[0] = COStheta * COSphi;
314                         n0[1] = _SINtheta * COSphi;
315
316                         n1[0] = COStheta1 * COSphi;
317                         n1[1] = _SINtheta1 * COSphi;
318
319                         n2[0] = COStheta1 * COSphi1;
320                         n2[1] = _SINtheta1 * COSphi1;
321
322                         n3[0] = COStheta * COSphi1;
323                         n3[1] = _SINtheta * COSphi1;
324
325                         p0[2] = p1[2] = r * (n0[2] = n1[2] = sin(phi));
326                         p2[2] = p3[2] = r * (n2[2] = n3[2] = sin(phi1));
327
328                         glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
329                         glNormal3fv(n3);
330                         glVertex3fv(p3);
331                         glNormal3fv(n2);
332                         glVertex3fv(p2);
333                         glNormal3fv(n1);
334                         glVertex3fv(p1);
335                         glNormal3fv(n0);
336                         glVertex3fv(p0);
337             mi->polygon_count++;
338                         glEnd();
339                 }
340         }
341
342         if (factory > 0 && bolted) {
343                 /* Bolt the elbow onto the pipe system */
344                 glFrontFace(GL_CW);
345                 glPushMatrix();
346                 glRotatef(90.0, 0.0, 0.0, -1.0);
347                 glRotatef(90.0, 0.0, 1.0, 0.0);
348                 glTranslatef(0.0, one_third, one_third);
349                 glCallList(pp->elbowcoins);
350         mi->polygon_count += LWO_ElbowCoins.num_pnts/3;
351                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
352                 glCallList(pp->elbowbolts);
353         mi->polygon_count += LWO_ElbowBolts.num_pnts/3;
354                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
355                 glPopMatrix();
356                 glFrontFace(GL_CCW);
357         }
358 #undef r
359 #undef R
360 #undef nsides
361 #undef rings
362 }
363
364 static void
365 FindNeighbors(ModeInfo * mi)
366 {
367         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
368
369         pp->ndirections = 0;
370         pp->directions[dirUP] = (!pp->Cells[pp->PX][pp->PY + 1][pp->PZ]) ? 1 : 0;
371         pp->ndirections += pp->directions[dirUP];
372         pp->directions[dirDOWN] = (!pp->Cells[pp->PX][pp->PY - 1][pp->PZ]) ? 1 : 0;
373         pp->ndirections += pp->directions[dirDOWN];
374         pp->directions[dirLEFT] = (!pp->Cells[pp->PX - 1][pp->PY][pp->PZ]) ? 1 : 0;
375         pp->ndirections += pp->directions[dirLEFT];
376         pp->directions[dirRIGHT] = (!pp->Cells[pp->PX + 1][pp->PY][pp->PZ]) ? 1 : 0;
377         pp->ndirections += pp->directions[dirRIGHT];
378         pp->directions[dirFAR] = (!pp->Cells[pp->PX][pp->PY][pp->PZ - 1]) ? 1 : 0;
379         pp->ndirections += pp->directions[dirFAR];
380         pp->directions[dirNEAR] = (!pp->Cells[pp->PX][pp->PY][pp->PZ + 1]) ? 1 : 0;
381         pp->ndirections += pp->directions[dirNEAR];
382 }
383
384 static int
385 SelectNeighbor(ModeInfo * mi)
386 {
387         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
388         int         dirlist[6];
389         int         i, j;
390
391         for (i = 0, j = 0; i < 6; i++) {
392                 if (pp->directions[i]) {
393                         dirlist[j] = i;
394                         j++;
395                 }
396         }
397
398         return dirlist[NRAND(pp->ndirections)];
399 }
400
401 static void
402 MakeValve(ModeInfo * mi, int newdir)
403 {
404         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
405
406         /* There is a glPopMatrix() right after this subroutine returns. */
407         switch (newdir) {
408                 case dirUP:
409                 case dirDOWN:
410                         glRotatef(90.0, 1.0, 0.0, 0.0);
411                         glRotatef(NRAND(3) * 90.0, 0.0, 0.0, 1.0);
412                         break;
413                 case dirLEFT:
414                 case dirRIGHT:
415                         glRotatef(90.0, 0.0, -1.0, 0.0);
416                         glRotatef((NRAND(3) * 90.0) - 90.0, 0.0, 0.0, 1.0);
417                         break;
418                 case dirNEAR:
419                 case dirFAR:
420                         glRotatef(NRAND(4) * 90.0, 0.0, 0.0, 1.0);
421                         break;
422         }
423         glFrontFace(GL_CW);
424         glCallList(pp->betweenbolts);
425     mi->polygon_count += LWO_PipeBetweenBolts.num_pnts/3;
426         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
427         glCallList(pp->bolts);
428     mi->polygon_count += LWO_Bolts3D.num_pnts/3;
429         if (!MI_IS_MONO(mi)) {
430                 if (pp->system_color == MaterialRed) {
431                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialYellow : MaterialBlue);
432                 } else if (pp->system_color == MaterialBlue) {
433                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialRed : MaterialYellow);
434                 } else if (pp->system_color == MaterialYellow) {
435                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialBlue : MaterialRed);
436                 } else {
437                         switch ((NRAND(3))) {
438                                 case 0:
439                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
440                                         break;
441                                 case 1:
442                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlue);
443                                         break;
444                                 case 2:
445                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
446                         }
447                 }
448         }
449         glRotatef((GLfloat) (NRAND(90)), 1.0, 0.0, 0.0);
450         glCallList(pp->valve);
451     mi->polygon_count += LWO_BigValve.num_pnts/3;
452         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
453         glFrontFace(GL_CCW);
454 }
455
456 static int
457 MakeGuage(ModeInfo * mi, int newdir)
458 {
459         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
460
461         /* Can't have a guage on a vertical pipe. */
462         if ((newdir == dirUP) || (newdir == dirDOWN))
463                 return (0);
464
465         /* Is there space above this pipe for a guage? */
466         if (!pp->directions[dirUP])
467                 return (0);
468
469         /* Yes!  Mark the space as used. */
470         pp->Cells[pp->PX][pp->PY + 1][pp->PZ] = 1;
471
472         glFrontFace(GL_CW);
473         glPushMatrix();
474         if ((newdir == dirLEFT) || (newdir == dirRIGHT))
475                 glRotatef(90.0, 0.0, 1.0, 0.0);
476         glCallList(pp->betweenbolts);
477     mi->polygon_count += LWO_PipeBetweenBolts.num_pnts/3;
478         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
479         glCallList(pp->bolts);
480     mi->polygon_count += LWO_Bolts3D.num_pnts/3;
481         glPopMatrix();
482
483         glCallList(pp->guageconnector);
484     mi->polygon_count += LWO_GuageConnector.num_pnts/3;
485         glPushMatrix();
486         glTranslatef(0.0, 1.33333, 0.0);
487         /* Do not change the above to 1 + ONE_THIRD, because */
488         /* the object really is centered on 1.3333300000. */
489         glRotatef(NRAND(270) + 45.0, 0.0, 0.0, -1.0);
490         /* Random rotation for the dial.  I love it. */
491         glCallList(pp->guagedial);
492     mi->polygon_count += LWO_GuageDial.num_pnts/3;
493         glPopMatrix();
494
495         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
496         glCallList(pp->guagehead);
497     mi->polygon_count += LWO_GuageHead.num_pnts/3;
498
499         /* GuageFace is drawn last, in case of low-res depth buffers. */
500         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
501         glCallList(pp->guageface);
502     mi->polygon_count += LWO_GuageFace.num_pnts/3;
503
504         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
505         glFrontFace(GL_CCW);
506
507         return (1);
508 }
509
510
511 static GLuint
512 build_teapot(ModeInfo *mi)
513 {
514   pipesstruct *pp = &pipes[MI_SCREEN(mi)];
515   GLuint list = glGenLists(1);
516   if (!list) return 0;
517   glNewList(list, GL_COMPILE);
518   pp->teapot_polys = unit_teapot (12, MI_IS_WIREFRAME(mi));
519   glEndList();
520   return list;
521 }
522
523
524 static void
525 MakeTeapot(ModeInfo * mi, int newdir)
526 {
527   pipesstruct *pp = &pipes[MI_SCREEN(mi)];
528
529   switch (newdir) {
530   case dirUP:
531   case dirDOWN:
532     glRotatef(90.0, 1.0, 0.0, 0.0);
533     glRotatef(NRAND(3) * 90.0, 0.0, 0.0, 1.0);
534     break;
535   case dirLEFT:
536   case dirRIGHT:
537     glRotatef(90.0, 0.0, -1.0, 0.0);
538     glRotatef((NRAND(3) * 90.0) - 90.0, 0.0, 0.0, 1.0);
539     break;
540   case dirNEAR:
541   case dirFAR:
542     glRotatef(NRAND(4) * 90.0, 0.0, 0.0, 1.0);
543     break;
544   }
545
546   glCallList(pp->teapot);
547   mi->polygon_count += pp->teapot_polys;
548   glFrontFace(GL_CCW);
549 }
550
551
552 static void
553 MakeShape(ModeInfo * mi, int newdir)
554 {
555   int n = NRAND(100);
556   if (n < 50) {
557     if (!MakeGuage(mi, newdir))
558       MakeTube(mi, newdir);
559   } else if (n < 98) {
560     MakeValve(mi, newdir);
561   } else {
562     MakeTeapot(mi,newdir);
563   }
564 }
565
566 static void
567 pinit(ModeInfo * mi, int zera)
568 {
569         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
570         int         X, Y, Z;
571
572         if (zera) {
573                 pp->system_number = 1;
574                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
575                 (void) memset(pp->Cells, 0, sizeof (pp->Cells));
576                 for (X = 0; X < HCELLS; X++) {
577                         for (Y = 0; Y < VCELLS; Y++) {
578                                 pp->Cells[X][Y][0] = 1;
579                                 pp->Cells[X][Y][HCELLS - 1] = 1;
580                                 pp->Cells[0][Y][X] = 1;
581                                 pp->Cells[HCELLS - 1][Y][X] = 1;
582                         }
583                 }
584                 for (X = 0; X < HCELLS; X++) {
585                         for (Z = 0; Z < HCELLS; Z++) {
586                                 pp->Cells[X][0][Z] = 1;
587                                 pp->Cells[X][VCELLS - 1][Z] = 1;
588                         }
589                 }
590                 (void) memset(pp->usedcolors, 0, sizeof (pp->usedcolors));
591         }
592         pp->counter = 0;
593         pp->turncounter = 0;
594
595         if (!MI_IS_MONO(mi)) {
596                 int         collist[DEFINEDCOLORS];
597                 int         i, j, lower = 1000;
598
599                 /* Avoid repeating colors on the same screen unless necessary */
600                 for (i = 0; i < DEFINEDCOLORS; i++) {
601                         if (lower > pp->usedcolors[i])
602                                 lower = pp->usedcolors[i];
603                 }
604                 for (i = 0, j = 0; i < DEFINEDCOLORS; i++) {
605                         if (pp->usedcolors[i] == lower) {
606                                 collist[j] = i;
607                                 j++;
608                         }
609                 }
610                 i = collist[NRAND(j)];
611                 pp->usedcolors[i]++;
612                 switch (i) {
613                         case 0:
614                                 pp->system_color = MaterialRed;
615                                 break;
616                         case 1:
617                                 pp->system_color = MaterialGreen;
618                                 break;
619                         case 2:
620                                 pp->system_color = MaterialBlue;
621                                 break;
622                         case 3:
623                                 pp->system_color = MaterialCyan;
624                                 break;
625                         case 4:
626                                 pp->system_color = MaterialYellow;
627                                 break;
628                         case 5:
629                                 pp->system_color = MaterialMagenta;
630                                 break;
631                         case 6:
632                                 pp->system_color = MaterialWhite;
633                                 break;
634                 }
635         } else {
636                 pp->system_color = MaterialGray;
637         }
638
639         do {
640                 pp->PX = NRAND((HCELLS - 1)) + 1;
641                 pp->PY = NRAND((VCELLS - 1)) + 1;
642                 pp->PZ = NRAND((HCELLS - 1)) + 1;
643         } while (pp->Cells[pp->PX][pp->PY][pp->PZ] ||
644                  (pp->Cells[pp->PX + 1][pp->PY][pp->PZ] && pp->Cells[pp->PX - 1][pp->PY][pp->PZ] &&
645                   pp->Cells[pp->PX][pp->PY + 1][pp->PZ] && pp->Cells[pp->PX][pp->PY - 1][pp->PZ] &&
646                   pp->Cells[pp->PX][pp->PY][pp->PZ + 1] && pp->Cells[pp->PX][pp->PY][pp->PZ - 1]));
647         pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
648         pp->olddir = dirNone;
649
650         FindNeighbors(mi);
651
652         pp->nowdir = SelectNeighbor(mi);
653 }
654
655
656 ENTRYPOINT void
657 reshape_pipes(ModeInfo * mi, int width, int height)
658 {
659         glViewport(0, 0, width, (GLint) height);
660         glMatrixMode(GL_PROJECTION);
661         glLoadIdentity();
662         /*glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0); */
663         gluPerspective(65.0, (GLfloat) width / (GLfloat) height, 0.1, 20.0);
664         glMatrixMode(GL_MODELVIEW);
665
666   glClear(GL_COLOR_BUFFER_BIT);
667 }
668
669 ENTRYPOINT Bool
670 pipes_handle_event (ModeInfo *mi, XEvent *event)
671 {
672   pipesstruct *pp = &pipes[MI_SCREEN(mi)];
673
674   if (gltrackball_event_handler (event, pp->trackball,
675                                  MI_WIDTH (mi), MI_HEIGHT (mi),
676                                  &pp->button_down_p))
677     return True;
678   else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
679     {
680       pp->fadeout = 100;
681       return True;
682     }
683
684   return False;
685 }
686
687
688
689 static void generate_system (ModeInfo *);
690
691
692 static void free_pipes (ModeInfo *);
693
694 ENTRYPOINT void
695 init_pipes (ModeInfo * mi)
696 {
697         int         screen = MI_SCREEN(mi);
698         pipesstruct *pp;
699
700         MI_INIT (mi, pipes, free_pipes);
701         pp = &pipes[screen];
702
703         pp->window = MI_WINDOW(mi);
704         if ((pp->glx_context = init_GL(mi)) != NULL) {
705
706                 reshape_pipes(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
707                 if (rotatepipes)
708                   pp->initial_rotation = NRAND(180); /* jwz */
709                 else
710                   pp->initial_rotation = -10.0;
711                 pinit(mi, 1);
712
713                 if (factory > 0) {
714                         pp->valve = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_BigValve);
715                         pp->bolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_Bolts3D);
716                         pp->betweenbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_PipeBetweenBolts);
717
718                         pp->elbowbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowBolts);
719                         pp->elbowcoins = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowCoins);
720
721                         pp->guagehead = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageHead);
722                         pp->guageface = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageFace);
723                         pp->guagedial = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageDial);
724                         pp->guageconnector = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageConnector);
725                         pp->teapot = build_teapot(mi);
726                 }
727                 /* else they are all 0, thanks to calloc(). */
728
729                 if (MI_COUNT(mi) < 1 || MI_COUNT(mi) > NofSysTypes + 1) {
730                         pp->system_type = NRAND(NofSysTypes) + 1;
731                 } else {
732                         pp->system_type = MI_COUNT(mi);
733                 }
734
735                 if (MI_CYCLES(mi) > 0 && MI_CYCLES(mi) < 11) {
736                         pp->number_of_systems = MI_CYCLES(mi);
737                 } else {
738                         pp->number_of_systems = 5;
739                 }
740
741                 if (MI_SIZE(mi) < 10) {
742                         pp->system_length = 10;
743                 } else if (MI_SIZE(mi) > 1000) {
744                         pp->system_length = 1000;
745                 } else {
746                         pp->system_length = MI_SIZE(mi);
747                 }
748         } else {
749                 MI_CLEARWINDOW(mi);
750         }
751
752     pp->trackball = gltrackball_init (True);
753     generate_system (mi);
754 }
755
756
757 static GLuint
758 get_dlist (ModeInfo *mi, int i)
759 {
760   pipesstruct *pp = &pipes[MI_SCREEN(mi)];
761   if (i >= pp->dlist_count)
762     {
763       pp->dlist_count++;
764       if (pp->dlist_count >= pp->dlist_size)
765         {
766           int s2 = (pp->dlist_size + 100) * 1.2;
767           pp->dlists = (GLuint *)
768             realloc (pp->dlists, s2 * sizeof(*pp->dlists));
769           if (! pp->dlists) abort();
770           pp->poly_counts = (GLuint *)
771             realloc (pp->poly_counts, s2 * sizeof(*pp->poly_counts));
772           if (! pp->poly_counts) abort();
773           pp->dlist_size = s2;
774         }
775       pp->dlists [i] = glGenLists (1);
776       pp->poly_counts [i] = 0;
777     }
778   return pp->dlists[i];
779 }
780
781
782
783 static void
784 generate_system (ModeInfo * mi)
785 {
786         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
787     Bool        wire = MI_IS_WIREFRAME(mi);
788
789         int         newdir;
790         int         OPX, OPY, OPZ;
791
792     Bool reset_p = False;
793
794     pp->system_index = 0;
795     pp->system_size = 0;
796     pinit (mi, 1);
797
798     while (1) {
799       glNewList (get_dlist (mi, pp->system_size++), GL_COMPILE);
800       mi->polygon_count = 0;
801
802         glPushMatrix();
803
804         FindNeighbors(mi);
805
806     if (wire)
807       glColor4fv (pp->system_color);
808     else
809       glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
810
811         /* If it's the begining of a system, draw a sphere */
812         if (pp->olddir == dirNone) {
813                 glPushMatrix();
814                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
815                 mySphere(0.6, wire);
816                 glPopMatrix();
817         }
818         /* Check for stop conditions */
819         if (pp->ndirections == 0 || pp->counter > pp->system_length) {
820                 glPushMatrix();
821                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
822                 /* Finish the system with another sphere */
823                 mySphere(0.6, wire);
824
825                 glPopMatrix();
826
827                 /* If the maximum number of system was drawn, restart (clearing the screen), */
828                 /* else start a new system. */
829                 if (++pp->system_number > pp->number_of_systems) {
830           reset_p = True;
831                 } else {
832                         pinit(mi, 0);
833                 }
834
835         goto NEXT;
836         }
837         pp->counter++;
838         pp->turncounter++;
839
840         /* Do will the direction change? if so, determine the new one */
841         newdir = pp->nowdir;
842         if (!pp->directions[newdir]) {  /* cannot proceed in the current direction */
843                 newdir = SelectNeighbor(mi);
844         } else {
845                 if (tightturns) {
846                         /* random change (20% chance) */
847                         if ((pp->counter > 1) && (NRAND(100) < 20)) {
848                                 newdir = SelectNeighbor(mi);
849                         }
850                 } else {
851                         /* Chance to turn increases after each length of pipe drawn */
852                         if ((pp->counter > 1) && NRAND(50) < NRAND(pp->turncounter + 1)) {
853                                 newdir = SelectNeighbor(mi);
854                                 pp->turncounter = 0;
855                         }
856                 }
857         }
858
859         /* Has the direction changed? */
860         if (newdir == pp->nowdir) {
861                 /* If not, draw the cell's center pipe */
862                 glPushMatrix();
863                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
864                 /* Chance of factory shape here, if enabled. */
865                 if ((pp->counter > 1) && (NRAND(100) < factory)) {
866                         MakeShape(mi, newdir);
867                 } else {
868                         MakeTube(mi, newdir);
869                 }
870                 glPopMatrix();
871         } else {
872                 /* If so, draw the cell's center elbow/sphere */
873                 int         sysT = pp->system_type;
874
875                 if (sysT == NofSysTypes + 1) {
876                         sysT = ((pp->system_number - 1) % NofSysTypes) + 1;
877                 }
878                 glPushMatrix();
879
880                 switch (sysT) {
881                         case 1:
882                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
883                                 mySphere(elbowradius, wire);
884                                 break;
885                         case 2:
886                         case 3:
887                                 switch (pp->nowdir) {
888                                         case dirUP:
889                                                 switch (newdir) {
890                                                         case dirLEFT:
891                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0);
892                                                                 glRotatef(180.0, 1.0, 0.0, 0.0);
893                                                                 break;
894                                                         case dirRIGHT:
895                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0);
896                                                                 glRotatef(180.0, 1.0, 0.0, 0.0);
897                                                                 glRotatef(180.0, 0.0, 1.0, 0.0);
898                                                                 break;
899                                                         case dirFAR:
900                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
901                                                                 glRotatef(90.0, 0.0, 1.0, 0.0);
902                                                                 glRotatef(180.0, 0.0, 0.0, 1.0);
903                                                                 break;
904                                                         case dirNEAR:
905                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
906                                                                 glRotatef(90.0, 0.0, 1.0, 0.0);
907                                                                 glRotatef(180.0, 1.0, 0.0, 0.0);
908                                                                 break;
909                                                 }
910                                                 break;
911                                         case dirDOWN:
912                                                 switch (newdir) {
913                                                         case dirLEFT:
914                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0);
915                                                                 break;
916                                                         case dirRIGHT:
917                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0);
918                                                                 glRotatef(180.0, 0.0, 1.0, 0.0);
919                                                                 break;
920                                                         case dirFAR:
921                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
922                                                                 glRotatef(270.0, 0.0, 1.0, 0.0);
923                                                                 break;
924                                                         case dirNEAR:
925                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
926                                                                 glRotatef(90.0, 0.0, 1.0, 0.0);
927                                                                 break;
928                                                 }
929                                                 break;
930                                         case dirLEFT:
931                                                 switch (newdir) {
932                                                         case dirUP:
933                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0);
934                                                                 glRotatef(180.0, 0.0, 1.0, 0.0);
935                                                                 break;
936                                                         case dirDOWN:
937                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0);
938                                                                 glRotatef(180.0, 1.0, 0.0, 0.0);
939                                                                 glRotatef(180.0, 0.0, 1.0, 0.0);
940                                                                 break;
941                                                         case dirFAR:
942                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
943                                                                 glRotatef(270.0, 1.0, 0.0, 0.0);
944                                                                 glRotatef(180.0, 0.0, 1.0, 0.0);
945                                                                 break;
946                                                         case dirNEAR:
947                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
948                                                                 glRotatef(270.0, 1.0, 0.0, 0.0);
949                                                                 glRotatef(180.0, 0.0, 0.0, 1.0);
950                                                                 break;
951                                                 }
952                                                 break;
953                                         case dirRIGHT:
954                                                 switch (newdir) {
955                                                         case dirUP:
956                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0);
957                                                                 break;
958                                                         case dirDOWN:
959                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0);
960                                                                 glRotatef(180.0, 1.0, 0.0, 0.0);
961                                                                 break;
962                                                         case dirFAR:
963                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
964                                                                 glRotatef(270.0, 1.0, 0.0, 0.0);
965                                                                 break;
966                                                         case dirNEAR:
967                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
968                                                                 glRotatef(90.0, 1.0, 0.0, 0.0);
969                                                                 break;
970                                                 }
971                                                 break;
972                                         case dirNEAR:
973                                                 switch (newdir) {
974                                                         case dirLEFT:
975                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
976                                                                 glRotatef(270.0, 1.0, 0.0, 0.0);
977                                                                 break;
978                                                         case dirRIGHT:
979                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
980                                                                 glRotatef(270.0, 1.0, 0.0, 0.0);
981                                                                 glRotatef(180.0, 0.0, 1.0, 0.0);
982                                                                 break;
983                                                         case dirUP:
984                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
985                                                                 glRotatef(270.0, 0.0, 1.0, 0.0);
986                                                                 break;
987                                                         case dirDOWN:
988                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
989                                                                 glRotatef(90.0, 0.0, 1.0, 0.0);
990                                                                 glRotatef(180.0, 0.0, 0.0, 1.0);
991                                                                 break;
992                                                 }
993                                                 break;
994                                         case dirFAR:
995                                                 switch (newdir) {
996                                                         case dirUP:
997                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
998                                                                 glRotatef(90.0, 0.0, 1.0, 0.0);
999                                                                 break;
1000                                                         case dirDOWN:
1001                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
1002                                                                 glRotatef(90.0, 0.0, 1.0, 0.0);
1003                                                                 glRotatef(180.0, 1.0, 0.0, 0.0);
1004                                                                 break;
1005                                                         case dirLEFT:
1006                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
1007                                                                 glRotatef(90.0, 1.0, 0.0, 0.0);
1008                                                                 break;
1009                                                         case dirRIGHT:
1010                                                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
1011                                                                 glRotatef(270.0, 1.0, 0.0, 0.0);
1012                                                                 glRotatef(180.0, 0.0, 0.0, 1.0);
1013                                                                 break;
1014                                                 }
1015                                                 break;
1016                                 }
1017                                 myElbow(mi, (sysT == 2));
1018                                 break;
1019                 }
1020                 glPopMatrix();
1021         }
1022
1023         OPX = pp->PX;
1024         OPY = pp->PY;
1025         OPZ = pp->PZ;
1026         pp->olddir = pp->nowdir;
1027         pp->nowdir = newdir;
1028         switch (pp->nowdir) {
1029                 case dirUP:
1030                         pp->PY++;
1031                         break;
1032                 case dirDOWN:
1033                         pp->PY--;
1034                         break;
1035                 case dirLEFT:
1036                         pp->PX--;
1037                         break;
1038                 case dirRIGHT:
1039                         pp->PX++;
1040                         break;
1041                 case dirNEAR:
1042                         pp->PZ++;
1043                         break;
1044                 case dirFAR:
1045                         pp->PZ--;
1046                         break;
1047         }
1048         pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
1049
1050         /* Cells'face pipe */
1051         glTranslatef(((pp->PX + OPX) / 2.0 - 16) / 3.0 * 4.0, ((pp->PY + OPY) / 2.0 - 12) / 3.0 * 4.0, ((pp->PZ + OPZ) / 2.0 - 16) / 3.0 * 4.0);
1052         MakeTube(mi, newdir);
1053
1054     NEXT:
1055         glPopMatrix();
1056     glEndList();
1057     pp->poly_counts [pp->system_size-1] = mi->polygon_count;
1058
1059     if (reset_p)
1060       break;
1061     }
1062 }
1063
1064
1065 ENTRYPOINT void
1066 draw_pipes (ModeInfo * mi)
1067 {
1068         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
1069         Display *display = MI_DISPLAY(mi);
1070         Window    window = MI_WINDOW(mi);
1071     Bool        wire = MI_IS_WIREFRAME(mi);
1072     int i = 0;
1073
1074         if (!pp->glx_context)
1075                 return;
1076
1077         glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
1078     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1079
1080         glColor3f(1.0, 1.0, 1.0);
1081
1082         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);
1083         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
1084         glLightfv(GL_LIGHT0, GL_POSITION, position0);
1085         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1);
1086         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
1087         glLightfv(GL_LIGHT1, GL_POSITION, position1);
1088         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
1089         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
1090
1091     if (wire)
1092       glDisable(GL_LIGHTING);
1093     else
1094       {
1095         glEnable(GL_LIGHTING);
1096         glEnable(GL_LIGHT0);
1097         /* This looks crappy. */
1098         /* glEnable(GL_LIGHT1); */
1099         glEnable(GL_DEPTH_TEST);
1100         glEnable(GL_NORMALIZE);
1101         glEnable(GL_CULL_FACE);
1102       }
1103
1104         glShadeModel(GL_SMOOTH);
1105         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
1106         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
1107
1108     glPushMatrix();
1109
1110     pp->initial_rotation += 0.02;
1111
1112         glTranslatef(0.0, 0.0, fisheye ? -3.8 : -4.8);
1113
1114     gltrackball_rotate (pp->trackball);
1115
1116         if (rotatepipes)
1117       glRotatef(pp->initial_rotation, 0.0, 1.0, 0.0);
1118
1119     glScalef(Scale4Window, Scale4Window, Scale4Window);
1120
1121     mi->polygon_count = 0;
1122
1123     if (pp->fadeout)
1124       {
1125         GLfloat s = (pp->fadeout * pp->fadeout) / 10000.0;
1126         glScalef (s, s, s);
1127         glRotatef (90 * (1 - (pp->fadeout/100.0)), 1, 0, 0.1);
1128         pp->fadeout -= 4;
1129         if (pp->fadeout <= 0)
1130           {
1131             pp->fadeout = 0;
1132             generate_system (mi);
1133           }
1134       }
1135     else if (pp->system_index < pp->system_size)
1136       pp->system_index++;
1137     else
1138       pp->fadeout = 100;
1139
1140     for (i = 0; i < pp->system_index; i++)
1141       {
1142         glCallList (pp->dlists[i]);
1143         mi->polygon_count += pp->poly_counts[i];
1144       }
1145
1146     glPopMatrix();
1147
1148     if (mi->fps_p) do_fps (mi);
1149     glFinish();
1150
1151     glXSwapBuffers(display, window);
1152 }
1153
1154
1155 #ifndef STANDALONE
1156 ENTRYPOINT void
1157 change_pipes (ModeInfo * mi)
1158 {
1159         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
1160
1161         if (!pp->glx_context)
1162                 return;
1163
1164         glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
1165         pinit(mi, 1);
1166 }
1167 #endif /* !STANDALONE */
1168
1169
1170 static void
1171 free_pipes (ModeInfo * mi)
1172 {
1173         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
1174
1175         if (pp->glx_context) {
1176
1177                 /* Display lists MUST be freed while their glXContext is current. */
1178                 glXMakeCurrent(MI_DISPLAY(mi), pp->window, *(pp->glx_context));
1179
1180                 if (pp->valve)
1181                         glDeleteLists(pp->valve, 1);
1182                 if (pp->bolts)
1183                         glDeleteLists(pp->bolts, 1);
1184                 if (pp->betweenbolts)
1185                         glDeleteLists(pp->betweenbolts, 1);
1186
1187                 if (pp->elbowbolts)
1188                         glDeleteLists(pp->elbowbolts, 1);
1189                 if (pp->elbowcoins)
1190                         glDeleteLists(pp->elbowcoins, 1);
1191
1192                 if (pp->guagehead)
1193                         glDeleteLists(pp->guagehead, 1);
1194                 if (pp->guageface)
1195                         glDeleteLists(pp->guageface, 1);
1196                 if (pp->guagedial)
1197                         glDeleteLists(pp->guagedial, 1);
1198                 if (pp->guageconnector)
1199                         glDeleteLists(pp->guageconnector, 1);
1200                 if (pp->teapot)
1201                         glDeleteLists(pp->teapot, 1);
1202         if (pp->dlists)
1203           {
1204             int i;
1205             for (i = 0; i < pp->dlist_count; i++)
1206               glDeleteLists (pp->dlists[i], 1);
1207             free (pp->dlists);
1208             free (pp->poly_counts);
1209           }
1210         }
1211 }
1212
1213 XSCREENSAVER_MODULE ("Pipes", pipes)
1214
1215 #endif