From http://www.jwz.org/xscreensaver/xscreensaver-5.30.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
70 # define refresh_pipes 0
71 # include "xlockmore.h"                         /* from the xscreensaver distribution */
72 #else  /* !STANDALONE */
73 # include "xlock.h"                                     /* from the xlockmore distribution */
74 #endif /* !STANDALONE */
75
76 #ifdef USE_GL
77
78 #ifdef HAVE_COCOA
79 # include "jwxyz.h"
80 #else
81 # include <X11/Xlib.h>
82 # include <GL/gl.h>
83 # include <GL/glu.h>
84 #endif
85
86 #ifdef HAVE_JWZGLES
87 # include "jwzgles.h"
88 #endif /* HAVE_JWZGLES */
89
90 #include "sphere.h"
91 #include "buildlwo.h"
92 #include "teapot.h"
93 #include "gltrackball.h"
94
95 #define DEF_FACTORY     "2"
96 #define DEF_FISHEYE     "True"
97 #define DEF_TIGHTTURNS  "False"
98 #define DEF_ROTATEPIPES "True"
99 #define NofSysTypes     3
100
101 static int  factory;
102 static Bool fisheye, tightturns, rotatepipes;
103
104 static XrmOptionDescRec opts[] =
105 {
106         {"-factory", ".pipes.factory", XrmoptionSepArg, 0},
107         {"-fisheye", ".pipes.fisheye", XrmoptionNoArg, "on"},
108         {"+fisheye", ".pipes.fisheye", XrmoptionNoArg, "off"},
109         {"-tightturns", ".pipes.tightturns", XrmoptionNoArg, "on"},
110         {"+tightturns", ".pipes.tightturns", XrmoptionNoArg, "off"},
111       {"-rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, "on"},
112       {"+rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, "off"},
113 };
114 static argtype vars[] =
115 {
116         {&factory, "factory", "Factory", DEF_FACTORY, t_Int},
117         {&fisheye, "fisheye", "Fisheye", DEF_FISHEYE, t_Bool},
118         {&tightturns, "tightturns", "Tightturns", DEF_TIGHTTURNS, t_Bool},
119         {&rotatepipes, "rotatepipes", "Rotatepipes", DEF_ROTATEPIPES, t_Bool},
120 };
121 static OptionStruct desc[] =
122 {
123         {"-factory num", "how much extra equipment in pipes (0 for none)"},
124         {"-/+fisheye", "turn on/off zoomed-in view of pipes"},
125         {"-/+tightturns", "turn on/off tight turns"},
126         {"-/+rotatepipes", "turn on/off pipe system rotation per screenful"},
127 };
128
129 ENTRYPOINT ModeSpecOpt pipes_opts =
130 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
131
132 #ifdef USE_MODULES
133 ModStruct   pipes_description =
134 {"pipes", "init_pipes", "draw_pipes", "release_pipes",
135  "draw_pipes",
136  "change_pipes", NULL, &pipes_opts,
137  1000, 2, 5, 500, 4, 1.0, "",
138  "Shows a selfbuilding pipe system", 0, NULL};
139
140 #endif
141
142 #define Scale4Window               0.1
143
144 #define one_third                  0.3333333333333333333
145
146 #define dirNone -1
147 #define dirUP 0
148 #define dirDOWN 1
149 #define dirLEFT 2
150 #define dirRIGHT 3
151 #define dirNEAR 4
152 #define dirFAR 5
153
154 #define HCELLS 33
155 #define VCELLS 25
156 #define DEFINEDCOLORS 7
157 #define elbowradius 0.5
158
159 /*************************************************************************/
160
161 typedef struct {
162         int         flip;
163
164         int         Cells[HCELLS][VCELLS][HCELLS];
165         int         usedcolors[DEFINEDCOLORS];
166         int         directions[6];
167         int         ndirections;
168         int         nowdir, olddir;
169         int         system_number;
170         int         counter;
171         int         PX, PY, PZ;
172         int         number_of_systems;
173         int         system_type;
174         int         system_length;
175         int         turncounter;
176         Window      window;
177         const float *system_color;
178         GLfloat     initial_rotation;
179         GLuint      valve, bolts, betweenbolts, elbowbolts, elbowcoins;
180         GLuint      guagehead, guageface, guagedial, guageconnector, teapot;
181     int         teapot_polys;
182         GLXContext *glx_context;
183
184     Bool button_down_p;
185     trackball_state *trackball;
186     GLuint *dlists, *poly_counts;
187     int dlist_count, dlist_size;
188     int system_index, system_size;
189
190     int fadeout;
191
192 } pipesstruct;
193
194 extern struct lwo LWO_BigValve, LWO_PipeBetweenBolts, LWO_Bolts3D;
195 extern struct lwo LWO_GuageHead, LWO_GuageFace, LWO_GuageDial, LWO_GuageConnector;
196 extern struct lwo LWO_ElbowBolts, LWO_ElbowCoins;
197
198 static const float front_shininess[] = {60.0};
199 static const float front_specular[] = {0.7, 0.7, 0.7, 1.0};
200 static const float ambient0[] = {0.4, 0.4, 0.4, 1.0};
201 static const float diffuse0[] = {1.0, 1.0, 1.0, 1.0};
202 static const float ambient1[] = {0.2, 0.2, 0.2, 1.0};
203 static const float diffuse1[] = {0.5, 0.5, 0.5, 1.0};
204 static const float position0[] = {1.0, 1.0, 1.0, 0.0};
205 static const float position1[] = {-1.0, -1.0, 1.0, 0.0};
206 static const float lmodel_ambient[] = {0.5, 0.5, 0.5, 1.0};
207 static const float lmodel_twoside[] = {GL_TRUE};
208
209 static const float MaterialRed[] = {0.7, 0.0, 0.0, 1.0};
210 static const float MaterialGreen[] = {0.1, 0.5, 0.2, 1.0};
211 static const float MaterialBlue[] = {0.0, 0.0, 0.7, 1.0};
212 static const float MaterialCyan[] = {0.2, 0.5, 0.7, 1.0};
213 static const float MaterialYellow[] = {0.7, 0.7, 0.0, 1.0};
214 static const float MaterialMagenta[] = {0.6, 0.2, 0.5, 1.0};
215 static const float MaterialWhite[] = {0.7, 0.7, 0.7, 1.0};
216 static const float MaterialGray[] = {0.2, 0.2, 0.2, 1.0};
217
218 static pipesstruct *pipes = NULL;
219
220
221 static void
222 MakeTube(ModeInfo *mi, int direction)
223 {
224     Bool        wire = MI_IS_WIREFRAME(mi);
225         float       an;
226         float       SINan_3, COSan_3;
227     int facets = (wire ? 5 : 24);
228
229         /*dirUP    = 00000000 */
230         /*dirDOWN  = 00000001 */
231         /*dirLEFT  = 00000010 */
232         /*dirRIGHT = 00000011 */
233         /*dirNEAR  = 00000100 */
234         /*dirFAR   = 00000101 */
235
236         if (!(direction & 4)) {
237                 glRotatef(90.0, (direction & 2) ? 0.0 : 1.0,
238                           (direction & 2) ? 1.0 : 0.0, 0.0);
239         }
240         glBegin(wire ? GL_LINE_STRIP : GL_QUAD_STRIP);
241         for (an = 0.0; an <= 2.0 * M_PI; an += M_PI * 2 / facets) {
242                 glNormal3f((COSan_3 = cos(an) / 3.0), (SINan_3 = sin(an) / 3.0), 0.0);
243                 glVertex3f(COSan_3, SINan_3, one_third);
244                 glVertex3f(COSan_3, SINan_3, -one_third);
245         mi->polygon_count++;
246         }
247         glEnd();
248 }
249
250 static void
251 mySphere(float radius, Bool wire)
252 {
253 #if 0
254         GLUquadricObj *quadObj;
255
256         quadObj = gluNewQuadric();
257         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
258         gluSphere(quadObj, radius, 16, 16);
259         gluDeleteQuadric(quadObj);
260 #else
261     glPushMatrix();
262     glScalef (radius, radius, radius);
263     glRotatef (90, 1, 0, 0);
264     unit_sphere (16, 16, wire);
265     glPopMatrix();
266 #endif
267 }
268
269 static void
270 myElbow(ModeInfo * mi, int bolted)
271 {
272         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
273     Bool        wire = MI_IS_WIREFRAME(mi);
274
275     int nsides = (wire ? 6 : 25);
276     int rings  = nsides;
277 #define r one_third
278 #define R one_third
279
280         int         i, j;
281         GLfloat     p0[3], p1[3], p2[3], p3[3];
282         GLfloat     n0[3], n1[3], n2[3], n3[3];
283         GLfloat     COSphi, COSphi1, COStheta, COStheta1;
284         GLfloat     _SINtheta, _SINtheta1;
285
286         for (i = 0; i <= rings / 4; i++) {
287                 GLfloat     theta, theta1;
288
289                 theta = (GLfloat) i *2.0 * M_PI / rings;
290
291                 theta1 = (GLfloat) (i + 1) * 2.0 * M_PI / rings;
292                 for (j = 0; j < nsides; j++) {
293                         GLfloat     phi, phi1;
294
295                         phi = (GLfloat) j *2.0 * M_PI / nsides;
296
297                         phi1 = (GLfloat) (j + 1) * 2.0 * M_PI / nsides;
298
299                         p0[0] = (COStheta = cos(theta)) * (R + r * (COSphi = cos(phi)));
300                         p0[1] = (_SINtheta = -sin(theta)) * (R + r * COSphi);
301
302                         p1[0] = (COStheta1 = cos(theta1)) * (R + r * COSphi);
303                         p1[1] = (_SINtheta1 = -sin(theta1)) * (R + r * COSphi);
304
305                         p2[0] = COStheta1 * (R + r * (COSphi1 = cos(phi1)));
306                         p2[1] = _SINtheta1 * (R + r * COSphi1);
307
308                         p3[0] = COStheta * (R + r * COSphi1);
309                         p3[1] = _SINtheta * (R + r * COSphi1);
310
311                         n0[0] = COStheta * COSphi;
312                         n0[1] = _SINtheta * COSphi;
313
314                         n1[0] = COStheta1 * COSphi;
315                         n1[1] = _SINtheta1 * COSphi;
316
317                         n2[0] = COStheta1 * COSphi1;
318                         n2[1] = _SINtheta1 * COSphi1;
319
320                         n3[0] = COStheta * COSphi1;
321                         n3[1] = _SINtheta * COSphi1;
322
323                         p0[2] = p1[2] = r * (n0[2] = n1[2] = sin(phi));
324                         p2[2] = p3[2] = r * (n2[2] = n3[2] = sin(phi1));
325
326                         glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
327                         glNormal3fv(n3);
328                         glVertex3fv(p3);
329                         glNormal3fv(n2);
330                         glVertex3fv(p2);
331                         glNormal3fv(n1);
332                         glVertex3fv(p1);
333                         glNormal3fv(n0);
334                         glVertex3fv(p0);
335             mi->polygon_count++;
336                         glEnd();
337                 }
338         }
339
340         if (factory > 0 && bolted) {
341                 /* Bolt the elbow onto the pipe system */
342                 glFrontFace(GL_CW);
343                 glPushMatrix();
344                 glRotatef(90.0, 0.0, 0.0, -1.0);
345                 glRotatef(90.0, 0.0, 1.0, 0.0);
346                 glTranslatef(0.0, one_third, one_third);
347                 glCallList(pp->elbowcoins);
348         mi->polygon_count += LWO_ElbowCoins.num_pnts/3;
349                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
350                 glCallList(pp->elbowbolts);
351         mi->polygon_count += LWO_ElbowBolts.num_pnts/3;
352                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
353                 glPopMatrix();
354                 glFrontFace(GL_CCW);
355         }
356 #undef r
357 #undef R
358 #undef nsides
359 #undef rings
360 }
361
362 static void
363 FindNeighbors(ModeInfo * mi)
364 {
365         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
366
367         pp->ndirections = 0;
368         pp->directions[dirUP] = (!pp->Cells[pp->PX][pp->PY + 1][pp->PZ]) ? 1 : 0;
369         pp->ndirections += pp->directions[dirUP];
370         pp->directions[dirDOWN] = (!pp->Cells[pp->PX][pp->PY - 1][pp->PZ]) ? 1 : 0;
371         pp->ndirections += pp->directions[dirDOWN];
372         pp->directions[dirLEFT] = (!pp->Cells[pp->PX - 1][pp->PY][pp->PZ]) ? 1 : 0;
373         pp->ndirections += pp->directions[dirLEFT];
374         pp->directions[dirRIGHT] = (!pp->Cells[pp->PX + 1][pp->PY][pp->PZ]) ? 1 : 0;
375         pp->ndirections += pp->directions[dirRIGHT];
376         pp->directions[dirFAR] = (!pp->Cells[pp->PX][pp->PY][pp->PZ - 1]) ? 1 : 0;
377         pp->ndirections += pp->directions[dirFAR];
378         pp->directions[dirNEAR] = (!pp->Cells[pp->PX][pp->PY][pp->PZ + 1]) ? 1 : 0;
379         pp->ndirections += pp->directions[dirNEAR];
380 }
381
382 static int
383 SelectNeighbor(ModeInfo * mi)
384 {
385         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
386         int         dirlist[6];
387         int         i, j;
388
389         for (i = 0, j = 0; i < 6; i++) {
390                 if (pp->directions[i]) {
391                         dirlist[j] = i;
392                         j++;
393                 }
394         }
395
396         return dirlist[NRAND(pp->ndirections)];
397 }
398
399 static void
400 MakeValve(ModeInfo * mi, int newdir)
401 {
402         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
403
404         /* There is a glPopMatrix() right after this subroutine returns. */
405         switch (newdir) {
406                 case dirUP:
407                 case dirDOWN:
408                         glRotatef(90.0, 1.0, 0.0, 0.0);
409                         glRotatef(NRAND(3) * 90.0, 0.0, 0.0, 1.0);
410                         break;
411                 case dirLEFT:
412                 case dirRIGHT:
413                         glRotatef(90.0, 0.0, -1.0, 0.0);
414                         glRotatef((NRAND(3) * 90.0) - 90.0, 0.0, 0.0, 1.0);
415                         break;
416                 case dirNEAR:
417                 case dirFAR:
418                         glRotatef(NRAND(4) * 90.0, 0.0, 0.0, 1.0);
419                         break;
420         }
421         glFrontFace(GL_CW);
422         glCallList(pp->betweenbolts);
423     mi->polygon_count += LWO_PipeBetweenBolts.num_pnts/3;
424         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
425         glCallList(pp->bolts);
426     mi->polygon_count += LWO_Bolts3D.num_pnts/3;
427         if (!MI_IS_MONO(mi)) {
428                 if (pp->system_color == MaterialRed) {
429                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialYellow : MaterialBlue);
430                 } else if (pp->system_color == MaterialBlue) {
431                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialRed : MaterialYellow);
432                 } else if (pp->system_color == MaterialYellow) {
433                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialBlue : MaterialRed);
434                 } else {
435                         switch ((NRAND(3))) {
436                                 case 0:
437                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
438                                         break;
439                                 case 1:
440                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlue);
441                                         break;
442                                 case 2:
443                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
444                         }
445                 }
446         }
447         glRotatef((GLfloat) (NRAND(90)), 1.0, 0.0, 0.0);
448         glCallList(pp->valve);
449     mi->polygon_count += LWO_BigValve.num_pnts/3;
450         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
451         glFrontFace(GL_CCW);
452 }
453
454 static int
455 MakeGuage(ModeInfo * mi, int newdir)
456 {
457         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
458
459         /* Can't have a guage on a vertical pipe. */
460         if ((newdir == dirUP) || (newdir == dirDOWN))
461                 return (0);
462
463         /* Is there space above this pipe for a guage? */
464         if (!pp->directions[dirUP])
465                 return (0);
466
467         /* Yes!  Mark the space as used. */
468         pp->Cells[pp->PX][pp->PY + 1][pp->PZ] = 1;
469
470         glFrontFace(GL_CW);
471         glPushMatrix();
472         if ((newdir == dirLEFT) || (newdir == dirRIGHT))
473                 glRotatef(90.0, 0.0, 1.0, 0.0);
474         glCallList(pp->betweenbolts);
475     mi->polygon_count += LWO_PipeBetweenBolts.num_pnts/3;
476         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
477         glCallList(pp->bolts);
478     mi->polygon_count += LWO_Bolts3D.num_pnts/3;
479         glPopMatrix();
480
481         glCallList(pp->guageconnector);
482     mi->polygon_count += LWO_GuageConnector.num_pnts/3;
483         glPushMatrix();
484         glTranslatef(0.0, 1.33333, 0.0);
485         /* Do not change the above to 1 + ONE_THIRD, because */
486         /* the object really is centered on 1.3333300000. */
487         glRotatef(NRAND(270) + 45.0, 0.0, 0.0, -1.0);
488         /* Random rotation for the dial.  I love it. */
489         glCallList(pp->guagedial);
490     mi->polygon_count += LWO_GuageDial.num_pnts/3;
491         glPopMatrix();
492
493         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
494         glCallList(pp->guagehead);
495     mi->polygon_count += LWO_GuageHead.num_pnts/3;
496
497         /* GuageFace is drawn last, in case of low-res depth buffers. */
498         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
499         glCallList(pp->guageface);
500     mi->polygon_count += LWO_GuageFace.num_pnts/3;
501
502         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
503         glFrontFace(GL_CCW);
504
505         return (1);
506 }
507
508
509 static GLuint
510 build_teapot(ModeInfo *mi)
511 {
512   pipesstruct *pp = &pipes[MI_SCREEN(mi)];
513   GLuint list = glGenLists(1);
514   if (!list) return 0;
515   glNewList(list, GL_COMPILE);
516   pp->teapot_polys = unit_teapot (12, MI_IS_WIREFRAME(mi));
517   glEndList();
518   return list;
519 }
520
521
522 static void
523 MakeTeapot(ModeInfo * mi, int newdir)
524 {
525   pipesstruct *pp = &pipes[MI_SCREEN(mi)];
526
527   switch (newdir) {
528   case dirUP:
529   case dirDOWN:
530     glRotatef(90.0, 1.0, 0.0, 0.0);
531     glRotatef(NRAND(3) * 90.0, 0.0, 0.0, 1.0);
532     break;
533   case dirLEFT:
534   case dirRIGHT:
535     glRotatef(90.0, 0.0, -1.0, 0.0);
536     glRotatef((NRAND(3) * 90.0) - 90.0, 0.0, 0.0, 1.0);
537     break;
538   case dirNEAR:
539   case dirFAR:
540     glRotatef(NRAND(4) * 90.0, 0.0, 0.0, 1.0);
541     break;
542   }
543
544   glCallList(pp->teapot);
545   mi->polygon_count += pp->teapot_polys;
546   glFrontFace(GL_CCW);
547 }
548
549
550 static void
551 MakeShape(ModeInfo * mi, int newdir)
552 {
553   int n = NRAND(100);
554   if (n < 50) {
555     if (!MakeGuage(mi, newdir))
556       MakeTube(mi, newdir);
557   } else if (n < 98) {
558     MakeValve(mi, newdir);
559   } else {
560     MakeTeapot(mi,newdir);
561   }
562 }
563
564 static void
565 pinit(ModeInfo * mi, int zera)
566 {
567         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
568         int         X, Y, Z;
569
570         if (zera) {
571                 pp->system_number = 1;
572                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
573                 (void) memset(pp->Cells, 0, sizeof (pp->Cells));
574                 for (X = 0; X < HCELLS; X++) {
575                         for (Y = 0; Y < VCELLS; Y++) {
576                                 pp->Cells[X][Y][0] = 1;
577                                 pp->Cells[X][Y][HCELLS - 1] = 1;
578                                 pp->Cells[0][Y][X] = 1;
579                                 pp->Cells[HCELLS - 1][Y][X] = 1;
580                         }
581                 }
582                 for (X = 0; X < HCELLS; X++) {
583                         for (Z = 0; Z < HCELLS; Z++) {
584                                 pp->Cells[X][0][Z] = 1;
585                                 pp->Cells[X][VCELLS - 1][Z] = 1;
586                         }
587                 }
588                 (void) memset(pp->usedcolors, 0, sizeof (pp->usedcolors));
589         }
590         pp->counter = 0;
591         pp->turncounter = 0;
592
593         if (!MI_IS_MONO(mi)) {
594                 int         collist[DEFINEDCOLORS];
595                 int         i, j, lower = 1000;
596
597                 /* Avoid repeating colors on the same screen unless necessary */
598                 for (i = 0; i < DEFINEDCOLORS; i++) {
599                         if (lower > pp->usedcolors[i])
600                                 lower = pp->usedcolors[i];
601                 }
602                 for (i = 0, j = 0; i < DEFINEDCOLORS; i++) {
603                         if (pp->usedcolors[i] == lower) {
604                                 collist[j] = i;
605                                 j++;
606                         }
607                 }
608                 i = collist[NRAND(j)];
609                 pp->usedcolors[i]++;
610                 switch (i) {
611                         case 0:
612                                 pp->system_color = MaterialRed;
613                                 break;
614                         case 1:
615                                 pp->system_color = MaterialGreen;
616                                 break;
617                         case 2:
618                                 pp->system_color = MaterialBlue;
619                                 break;
620                         case 3:
621                                 pp->system_color = MaterialCyan;
622                                 break;
623                         case 4:
624                                 pp->system_color = MaterialYellow;
625                                 break;
626                         case 5:
627                                 pp->system_color = MaterialMagenta;
628                                 break;
629                         case 6:
630                                 pp->system_color = MaterialWhite;
631                                 break;
632                 }
633         } else {
634                 pp->system_color = MaterialGray;
635         }
636
637         do {
638                 pp->PX = NRAND((HCELLS - 1)) + 1;
639                 pp->PY = NRAND((VCELLS - 1)) + 1;
640                 pp->PZ = NRAND((HCELLS - 1)) + 1;
641         } while (pp->Cells[pp->PX][pp->PY][pp->PZ] ||
642                  (pp->Cells[pp->PX + 1][pp->PY][pp->PZ] && pp->Cells[pp->PX - 1][pp->PY][pp->PZ] &&
643                   pp->Cells[pp->PX][pp->PY + 1][pp->PZ] && pp->Cells[pp->PX][pp->PY - 1][pp->PZ] &&
644                   pp->Cells[pp->PX][pp->PY][pp->PZ + 1] && pp->Cells[pp->PX][pp->PY][pp->PZ - 1]));
645         pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
646         pp->olddir = dirNone;
647
648         FindNeighbors(mi);
649
650         pp->nowdir = SelectNeighbor(mi);
651 }
652
653
654 ENTRYPOINT void
655 reshape_pipes(ModeInfo * mi, int width, int height)
656 {
657         glViewport(0, 0, width, (GLint) height);
658         glMatrixMode(GL_PROJECTION);
659         glLoadIdentity();
660         /*glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0); */
661         gluPerspective(65.0, (GLfloat) width / (GLfloat) height, 0.1, 20.0);
662         glMatrixMode(GL_MODELVIEW);
663
664   glClear(GL_COLOR_BUFFER_BIT);
665 }
666
667 ENTRYPOINT Bool
668 pipes_handle_event (ModeInfo *mi, XEvent *event)
669 {
670   pipesstruct *pp = &pipes[MI_SCREEN(mi)];
671
672   if (gltrackball_event_handler (event, pp->trackball,
673                                  MI_WIDTH (mi), MI_HEIGHT (mi),
674                                  &pp->button_down_p))
675     return True;
676   else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
677     {
678       pp->fadeout = 100;
679       return True;
680     }
681
682   return False;
683 }
684
685
686
687 static void generate_system (ModeInfo *);
688
689
690 ENTRYPOINT void
691 init_pipes (ModeInfo * mi)
692 {
693         int         screen = MI_SCREEN(mi);
694         pipesstruct *pp;
695
696         if (pipes == NULL) {
697                 if ((pipes = (pipesstruct *) calloc(MI_NUM_SCREENS(mi),
698                                               sizeof (pipesstruct))) == NULL)
699                         return;
700         }
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 ENTRYPOINT void
1171 release_pipes (ModeInfo * mi)
1172 {
1173         if (pipes != NULL) {
1174                 int         screen;
1175
1176                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1177                         pipesstruct *pp = &pipes[screen];
1178
1179                         if (pp->glx_context) {
1180
1181                                 /* Display lists MUST be freed while their glXContext is current. */
1182                                 glXMakeCurrent(MI_DISPLAY(mi), pp->window, *(pp->glx_context));
1183
1184                                 if (pp->valve)
1185                                         glDeleteLists(pp->valve, 1);
1186                                 if (pp->bolts)
1187                                         glDeleteLists(pp->bolts, 1);
1188                                 if (pp->betweenbolts)
1189                                         glDeleteLists(pp->betweenbolts, 1);
1190
1191                                 if (pp->elbowbolts)
1192                                         glDeleteLists(pp->elbowbolts, 1);
1193                                 if (pp->elbowcoins)
1194                                         glDeleteLists(pp->elbowcoins, 1);
1195
1196                                 if (pp->guagehead)
1197                                         glDeleteLists(pp->guagehead, 1);
1198                                 if (pp->guageface)
1199                                         glDeleteLists(pp->guageface, 1);
1200                                 if (pp->guagedial)
1201                                         glDeleteLists(pp->guagedial, 1);
1202                                 if (pp->guageconnector)
1203                                         glDeleteLists(pp->guageconnector, 1);
1204                                 if (pp->teapot)
1205                                         glDeleteLists(pp->teapot, 1);
1206                 if (pp->dlists)
1207                   {
1208                     int i;
1209                     for (i = 0; i < pp->dlist_count; i++)
1210                       glDeleteLists (pp->dlists[i], 1);
1211                     free (pp->dlists);
1212                     free (pp->poly_counts);
1213                   }
1214                         }
1215                 }
1216
1217                 (void) free((void *) pipes);
1218                 pipes = NULL;
1219         }
1220         FreeAllGL(mi);
1221 }
1222
1223 XSCREENSAVER_MODULE ("Pipes", pipes)
1224
1225 #endif