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