From http://www.jwz.org/xscreensaver/xscreensaver-5.38.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 release_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", NULL,
136  "draw_pipes",
137  "change_pipes", "free_pipes", &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   double h = (GLfloat) height / (GLfloat) width;  
659   int y = 0;
660
661   if (width > height * 5) {   /* tiny window: show middle */
662     height = width * 9/16;
663     y = -height/2;
664     h = height / (GLfloat) width;
665   }
666   glViewport(0, y, width, (GLint) height);
667   glMatrixMode(GL_PROJECTION);
668   glLoadIdentity();
669   /*glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0); */
670   gluPerspective(65.0, 1/h, 0.1, 20.0);
671   glMatrixMode(GL_MODELVIEW);
672
673   glClear(GL_COLOR_BUFFER_BIT);
674 }
675
676 ENTRYPOINT Bool
677 pipes_handle_event (ModeInfo *mi, XEvent *event)
678 {
679   pipesstruct *pp = &pipes[MI_SCREEN(mi)];
680
681   if (gltrackball_event_handler (event, pp->trackball,
682                                  MI_WIDTH (mi), MI_HEIGHT (mi),
683                                  &pp->button_down_p))
684     return True;
685   else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
686     {
687       pp->fadeout = 100;
688       return True;
689     }
690
691   return False;
692 }
693
694
695
696 static void generate_system (ModeInfo *);
697
698
699 ENTRYPOINT void
700 init_pipes (ModeInfo * mi)
701 {
702         int         screen = MI_SCREEN(mi);
703         pipesstruct *pp;
704
705         MI_INIT (mi, pipes);
706         pp = &pipes[screen];
707
708         pp->window = MI_WINDOW(mi);
709         if ((pp->glx_context = init_GL(mi)) != NULL) {
710
711                 reshape_pipes(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
712                 if (rotatepipes)
713                   pp->initial_rotation = NRAND(180); /* jwz */
714                 else
715                   pp->initial_rotation = -10.0;
716                 pinit(mi, 1);
717
718                 if (factory > 0) {
719                         pp->valve = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_BigValve);
720                         pp->bolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_Bolts3D);
721                         pp->betweenbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_PipeBetweenBolts);
722
723                         pp->elbowbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowBolts);
724                         pp->elbowcoins = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowCoins);
725
726                         pp->guagehead = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageHead);
727                         pp->guageface = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageFace);
728                         pp->guagedial = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageDial);
729                         pp->guageconnector = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageConnector);
730                         pp->teapot = build_teapot(mi);
731                 }
732                 /* else they are all 0, thanks to calloc(). */
733
734                 if (MI_COUNT(mi) < 1 || MI_COUNT(mi) > NofSysTypes + 1) {
735                         pp->system_type = NRAND(NofSysTypes) + 1;
736                 } else {
737                         pp->system_type = MI_COUNT(mi);
738                 }
739
740                 if (MI_CYCLES(mi) > 0 && MI_CYCLES(mi) < 11) {
741                         pp->number_of_systems = MI_CYCLES(mi);
742                 } else {
743                         pp->number_of_systems = 5;
744                 }
745
746                 if (MI_SIZE(mi) < 10) {
747                         pp->system_length = 10;
748                 } else if (MI_SIZE(mi) > 1000) {
749                         pp->system_length = 1000;
750                 } else {
751                         pp->system_length = MI_SIZE(mi);
752                 }
753         } else {
754                 MI_CLEARWINDOW(mi);
755         }
756
757     pp->trackball = gltrackball_init (True);
758     generate_system (mi);
759 }
760
761
762 static GLuint
763 get_dlist (ModeInfo *mi, int i)
764 {
765   pipesstruct *pp = &pipes[MI_SCREEN(mi)];
766   if (i >= pp->dlist_count)
767     {
768       pp->dlist_count++;
769       if (pp->dlist_count >= pp->dlist_size)
770         {
771           int s2 = (pp->dlist_size + 100) * 1.2;
772           pp->dlists = (GLuint *)
773             realloc (pp->dlists, s2 * sizeof(*pp->dlists));
774           if (! pp->dlists) abort();
775           pp->poly_counts = (GLuint *)
776             realloc (pp->poly_counts, s2 * sizeof(*pp->poly_counts));
777           if (! pp->poly_counts) abort();
778           pp->dlist_size = s2;
779         }
780       pp->dlists [i] = glGenLists (1);
781       pp->poly_counts [i] = 0;
782     }
783   return pp->dlists[i];
784 }
785
786
787
788 static void
789 generate_system (ModeInfo * mi)
790 {
791         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
792     Bool        wire = MI_IS_WIREFRAME(mi);
793
794         int         newdir;
795         int         OPX, OPY, OPZ;
796
797     Bool reset_p = False;
798
799     pp->system_index = 0;
800     pp->system_size = 0;
801     pinit (mi, 1);
802
803     while (1) {
804       glNewList (get_dlist (mi, pp->system_size++), GL_COMPILE);
805       mi->polygon_count = 0;
806
807         glPushMatrix();
808
809         FindNeighbors(mi);
810
811     if (wire)
812       glColor4fv (pp->system_color);
813     else
814       glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
815
816         /* If it's the begining of a system, draw a sphere */
817         if (pp->olddir == dirNone) {
818                 glPushMatrix();
819                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
820                 mySphere(0.6, wire);
821                 glPopMatrix();
822         }
823         /* Check for stop conditions */
824         if (pp->ndirections == 0 || pp->counter > pp->system_length) {
825                 glPushMatrix();
826                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
827                 /* Finish the system with another sphere */
828                 mySphere(0.6, wire);
829
830                 glPopMatrix();
831
832                 /* If the maximum number of system was drawn, restart (clearing the screen), */
833                 /* else start a new system. */
834                 if (++pp->system_number > pp->number_of_systems) {
835           reset_p = True;
836                 } else {
837                         pinit(mi, 0);
838                 }
839
840         goto NEXT;
841         }
842         pp->counter++;
843         pp->turncounter++;
844
845         /* Do will the direction change? if so, determine the new one */
846         newdir = pp->nowdir;
847         if (!pp->directions[newdir]) {  /* cannot proceed in the current direction */
848                 newdir = SelectNeighbor(mi);
849         } else {
850                 if (tightturns) {
851                         /* random change (20% chance) */
852                         if ((pp->counter > 1) && (NRAND(100) < 20)) {
853                                 newdir = SelectNeighbor(mi);
854                         }
855                 } else {
856                         /* Chance to turn increases after each length of pipe drawn */
857                         if ((pp->counter > 1) && NRAND(50) < NRAND(pp->turncounter + 1)) {
858                                 newdir = SelectNeighbor(mi);
859                                 pp->turncounter = 0;
860                         }
861                 }
862         }
863
864         /* Has the direction changed? */
865         if (newdir == pp->nowdir) {
866                 /* If not, draw the cell's center pipe */
867                 glPushMatrix();
868                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
869                 /* Chance of factory shape here, if enabled. */
870                 if ((pp->counter > 1) && (NRAND(100) < factory)) {
871                         MakeShape(mi, newdir);
872                 } else {
873                         MakeTube(mi, newdir);
874                 }
875                 glPopMatrix();
876         } else {
877                 /* If so, draw the cell's center elbow/sphere */
878                 int         sysT = pp->system_type;
879
880                 if (sysT == NofSysTypes + 1) {
881                         sysT = ((pp->system_number - 1) % NofSysTypes) + 1;
882                 }
883                 glPushMatrix();
884
885                 switch (sysT) {
886                         case 1:
887                                 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
888                                 mySphere(elbowradius, wire);
889                                 break;
890                         case 2:
891                         case 3:
892                                 switch (pp->nowdir) {
893                                         case dirUP:
894                                                 switch (newdir) {
895                                                         case dirLEFT:
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                                                                 break;
899                                                         case dirRIGHT:
900                                                                 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);
901                                                                 glRotatef(180.0, 1.0, 0.0, 0.0);
902                                                                 glRotatef(180.0, 0.0, 1.0, 0.0);
903                                                                 break;
904                                                         case dirFAR:
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, 0.0, 0.0, 1.0);
908                                                                 break;
909                                                         case dirNEAR:
910                                                                 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));
911                                                                 glRotatef(90.0, 0.0, 1.0, 0.0);
912                                                                 glRotatef(180.0, 1.0, 0.0, 0.0);
913                                                                 break;
914                                                 }
915                                                 break;
916                                         case dirDOWN:
917                                                 switch (newdir) {
918                                                         case dirLEFT:
919                                                                 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);
920                                                                 break;
921                                                         case dirRIGHT:
922                                                                 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);
923                                                                 glRotatef(180.0, 0.0, 1.0, 0.0);
924                                                                 break;
925                                                         case dirFAR:
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(270.0, 0.0, 1.0, 0.0);
928                                                                 break;
929                                                         case dirNEAR:
930                                                                 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));
931                                                                 glRotatef(90.0, 0.0, 1.0, 0.0);
932                                                                 break;
933                                                 }
934                                                 break;
935                                         case dirLEFT:
936                                                 switch (newdir) {
937                                                         case dirUP:
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, 0.0, 1.0, 0.0);
940                                                                 break;
941                                                         case dirDOWN:
942                                                                 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);
943                                                                 glRotatef(180.0, 1.0, 0.0, 0.0);
944                                                                 glRotatef(180.0, 0.0, 1.0, 0.0);
945                                                                 break;
946                                                         case dirFAR:
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, 1.0, 0.0);
950                                                                 break;
951                                                         case dirNEAR:
952                                                                 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));
953                                                                 glRotatef(270.0, 1.0, 0.0, 0.0);
954                                                                 glRotatef(180.0, 0.0, 0.0, 1.0);
955                                                                 break;
956                                                 }
957                                                 break;
958                                         case dirRIGHT:
959                                                 switch (newdir) {
960                                                         case dirUP:
961                                                                 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);
962                                                                 break;
963                                                         case dirDOWN:
964                                                                 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);
965                                                                 glRotatef(180.0, 1.0, 0.0, 0.0);
966                                                                 break;
967                                                         case dirFAR:
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(270.0, 1.0, 0.0, 0.0);
970                                                                 break;
971                                                         case dirNEAR:
972                                                                 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));
973                                                                 glRotatef(90.0, 1.0, 0.0, 0.0);
974                                                                 break;
975                                                 }
976                                                 break;
977                                         case dirNEAR:
978                                                 switch (newdir) {
979                                                         case dirLEFT:
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                                                                 break;
983                                                         case dirRIGHT:
984                                                                 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));
985                                                                 glRotatef(270.0, 1.0, 0.0, 0.0);
986                                                                 glRotatef(180.0, 0.0, 1.0, 0.0);
987                                                                 break;
988                                                         case dirUP:
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(270.0, 0.0, 1.0, 0.0);
991                                                                 break;
992                                                         case dirDOWN:
993                                                                 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));
994                                                                 glRotatef(90.0, 0.0, 1.0, 0.0);
995                                                                 glRotatef(180.0, 0.0, 0.0, 1.0);
996                                                                 break;
997                                                 }
998                                                 break;
999                                         case dirFAR:
1000                                                 switch (newdir) {
1001                                                         case dirUP:
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                                                                 break;
1005                                                         case dirDOWN:
1006                                                                 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));
1007                                                                 glRotatef(90.0, 0.0, 1.0, 0.0);
1008                                                                 glRotatef(180.0, 1.0, 0.0, 0.0);
1009                                                                 break;
1010                                                         case dirLEFT:
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(90.0, 1.0, 0.0, 0.0);
1013                                                                 break;
1014                                                         case dirRIGHT:
1015                                                                 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));
1016                                                                 glRotatef(270.0, 1.0, 0.0, 0.0);
1017                                                                 glRotatef(180.0, 0.0, 0.0, 1.0);
1018                                                                 break;
1019                                                 }
1020                                                 break;
1021                                 }
1022                                 myElbow(mi, (sysT == 2));
1023                                 break;
1024                 }
1025                 glPopMatrix();
1026         }
1027
1028         OPX = pp->PX;
1029         OPY = pp->PY;
1030         OPZ = pp->PZ;
1031         pp->olddir = pp->nowdir;
1032         pp->nowdir = newdir;
1033         switch (pp->nowdir) {
1034                 case dirUP:
1035                         pp->PY++;
1036                         break;
1037                 case dirDOWN:
1038                         pp->PY--;
1039                         break;
1040                 case dirLEFT:
1041                         pp->PX--;
1042                         break;
1043                 case dirRIGHT:
1044                         pp->PX++;
1045                         break;
1046                 case dirNEAR:
1047                         pp->PZ++;
1048                         break;
1049                 case dirFAR:
1050                         pp->PZ--;
1051                         break;
1052         }
1053         pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
1054
1055         /* Cells'face pipe */
1056         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);
1057         MakeTube(mi, newdir);
1058
1059     NEXT:
1060         glPopMatrix();
1061     glEndList();
1062     pp->poly_counts [pp->system_size-1] = mi->polygon_count;
1063
1064     if (reset_p)
1065       break;
1066     }
1067 }
1068
1069
1070 ENTRYPOINT void
1071 draw_pipes (ModeInfo * mi)
1072 {
1073         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
1074         Display *display = MI_DISPLAY(mi);
1075         Window    window = MI_WINDOW(mi);
1076     Bool        wire = MI_IS_WIREFRAME(mi);
1077     int i = 0;
1078
1079         if (!pp->glx_context)
1080                 return;
1081
1082         glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
1083     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1084
1085         glColor3f(1.0, 1.0, 1.0);
1086
1087         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);
1088         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
1089         glLightfv(GL_LIGHT0, GL_POSITION, position0);
1090         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1);
1091         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
1092         glLightfv(GL_LIGHT1, GL_POSITION, position1);
1093         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
1094         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
1095
1096     if (wire)
1097       glDisable(GL_LIGHTING);
1098     else
1099       {
1100         glEnable(GL_LIGHTING);
1101         glEnable(GL_LIGHT0);
1102         /* This looks crappy. */
1103         /* glEnable(GL_LIGHT1); */
1104         glEnable(GL_DEPTH_TEST);
1105         glEnable(GL_NORMALIZE);
1106         glEnable(GL_CULL_FACE);
1107       }
1108
1109         glShadeModel(GL_SMOOTH);
1110         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
1111         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
1112
1113     glPushMatrix();
1114
1115     pp->initial_rotation += 0.02;
1116
1117         glTranslatef(0.0, 0.0, fisheye ? -3.8 : -4.8);
1118
1119     gltrackball_rotate (pp->trackball);
1120
1121         if (rotatepipes)
1122       glRotatef(pp->initial_rotation, 0.0, 1.0, 0.0);
1123
1124     glScalef(Scale4Window, Scale4Window, Scale4Window);
1125
1126     mi->polygon_count = 0;
1127
1128     if (pp->fadeout)
1129       {
1130         GLfloat s = (pp->fadeout * pp->fadeout) / 10000.0;
1131         glScalef (s, s, s);
1132         glRotatef (90 * (1 - (pp->fadeout/100.0)), 1, 0, 0.1);
1133         pp->fadeout -= 4;
1134         if (pp->fadeout <= 0)
1135           {
1136             pp->fadeout = 0;
1137             generate_system (mi);
1138           }
1139       }
1140     else if (pp->system_index < pp->system_size)
1141       pp->system_index++;
1142     else
1143       pp->fadeout = 100;
1144
1145     for (i = 0; i < pp->system_index; i++)
1146       {
1147         glCallList (pp->dlists[i]);
1148         mi->polygon_count += pp->poly_counts[i];
1149       }
1150
1151     glPopMatrix();
1152
1153     if (mi->fps_p) do_fps (mi);
1154     glFinish();
1155
1156     glXSwapBuffers(display, window);
1157 }
1158
1159
1160 #ifndef STANDALONE
1161 ENTRYPOINT void
1162 change_pipes (ModeInfo * mi)
1163 {
1164         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
1165
1166         if (!pp->glx_context)
1167                 return;
1168
1169         glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
1170         pinit(mi, 1);
1171 }
1172 #endif /* !STANDALONE */
1173
1174
1175 ENTRYPOINT void
1176 free_pipes (ModeInfo * mi)
1177 {
1178         pipesstruct *pp = &pipes[MI_SCREEN(mi)];
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 XSCREENSAVER_MODULE ("Pipes", pipes)
1219
1220 #endif