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