ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-5.01.tar.gz
[xscreensaver] / hacks / glx / pipes.c
index c6f35d90becad0d782a069f1bc880db9f253fdc4..e47361eaaaf8a1e0fffdacbd1fe3ee4ec8049e4a 100644 (file)
@@ -1,10 +1,12 @@
-/* -*- Mode: C; tab-width: 4 -*-
- * pipes.c - Shows 3D selfbuiding pipe system (xlock Version)
- */
-#if !defined( lint ) && !defined( SABER )
-static const char sccsid[] = "@(#)pipes.c      4.04 97/07/28 xlockmore";
+/* -*- Mode: C; tab-width: 4 -*- */
+/* pipes --- 3D selfbuiding pipe system */
+
+#if 0
+static const char sccsid[] = "@(#)pipes.c      4.07 97/11/24 xlockmore";
 #endif
-/* Permission to use, copy, modify, and distribute this software and its
+
+/*-
+ * Permission to use, copy, modify, and distribute this software and its
  * documentation for any purpose and without fee is hereby granted,
  * provided that the above copyright notice appear in all copies and that
  * both that copyright notice and this permission notice appear in
@@ -27,15 +29,11 @@ static const char sccsid[] = "@(#)pipes.c   4.04 97/07/28 xlockmore";
  * Thanks goes to Brian Paul for making it possible and inexpensive to use
  * OpenGL at home.
  *
- * Since I'm not a native english speaker, my apologies for any gramatical
+ * Since I'm not a native English speaker, my apologies for any grammatical
  * mistake.
  *
- * My e-mail addresses are
- *
- * vianna@cat.cbpf.br 
- *         and
- * marcelo@venus.rdc.puc-rio.br
- *
+ * My e-mail address is
+ * m-vianna@usa.net
  * Marcelo F. Vianna (Apr-09-1997)
  *
  * Revision History:
@@ -44,26 +42,15 @@ static const char sccsid[] = "@(#)pipes.c   4.04 97/07/28 xlockmore";
  * 29-Apr-97: Efficiency speed-ups by Marcelo F. Vianna
  */
 
-/*-
- * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
- * otherwise caddr_t is not defined correctly
- */
-
-#include <X11/Intrinsic.h>
-
 #ifdef STANDALONE
-# define PROGCLASS                                     "Pipes"
-# define HACK_INIT                                     init_pipes
-# define HACK_DRAW                                     draw_pipes
-# define pipes_opts                                    xlockmore_opts
-# define DEFAULTS      "*count:                2       \n"                     \
+# define DEFAULTS      "*delay:                10000   \n"                     \
+                                       "*count:                2       \n"                     \
                                        "*cycles:               5       \n"                     \
                                        "*size:                 500     \n"                     \
-                                       "*delay:                100     \n"                     \
-                                       "*fisheye:              True    \n"                     \
-                                       "*tightturns:   False   \n"                     \
-                                       "*rotatepipes:  True    \n"                     \
-                                       "*noBuffer:             True    \n"
+                       "*showFPS:      False   \n"                 \
+                       "*fpsSolid:     True    \n"
+# define refresh_pipes 0
+# define pipes_handle_event 0
 # include "xlockmore.h"                                /* from the xscreensaver distribution */
 #else  /* !STANDALONE */
 # include "xlock.h"                                    /* from the xlockmore distribution */
@@ -71,45 +58,60 @@ static const char sccsid[] = "@(#)pipes.c   4.04 97/07/28 xlockmore";
 
 #ifdef USE_GL
 
-#include <GL/glu.h>
 #include "buildlwo.h"
 
 #define DEF_FACTORY     "2"
 #define DEF_FISHEYE     "True"
 #define DEF_TIGHTTURNS  "False"
 #define DEF_ROTATEPIPES "True"
+#define DEF_DBUF        "False"
 #define NofSysTypes     3
 
 static int  factory;
 static Bool fisheye, tightturns, rotatepipes;
+static Bool dbuf_p;
 
 static XrmOptionDescRec opts[] =
 {
-       {"-factory", ".pipes.factory", XrmoptionSepArg, (caddr_t) NULL},
-       {"-fisheye", ".pipes.fisheye", XrmoptionNoArg, (caddr_t) "on"},
-       {"+fisheye", ".pipes.fisheye", XrmoptionNoArg, (caddr_t) "off"},
-       {"-tightturns", ".pipes.tightturns", XrmoptionNoArg, (caddr_t) "on"},
-       {"+tightturns", ".pipes.tightturns", XrmoptionNoArg, (caddr_t) "off"},
-      {"-rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, (caddr_t) "on"},
-      {"+rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, (caddr_t) "off"}
+       {"-factory", ".pipes.factory", XrmoptionSepArg, 0},
+       {"-fisheye", ".pipes.fisheye", XrmoptionNoArg, "on"},
+       {"+fisheye", ".pipes.fisheye", XrmoptionNoArg, "off"},
+       {"-tightturns", ".pipes.tightturns", XrmoptionNoArg, "on"},
+       {"+tightturns", ".pipes.tightturns", XrmoptionNoArg, "off"},
+      {"-rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, "on"},
+      {"+rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, "off"},
+      {"-db", ".pipes.doubleBuffer", XrmoptionNoArg, "on"},
+      {"+db", ".pipes.doubleBuffer", XrmoptionNoArg, "off"},
 };
 static argtype vars[] =
 {
-       {(caddr_t *) & factory, "factory", "Factory", DEF_FACTORY, t_Int},
-       {(caddr_t *) & fisheye, "fisheye", "Fisheye", DEF_FISHEYE, t_Bool},
-       {(caddr_t *) & tightturns, "tightturns", "Tightturns", DEF_TIGHTTURNS, t_Bool},
-       {(caddr_t *) & rotatepipes, "rotatepipes", "Rotatepipes", DEF_ROTATEPIPES, t_Bool}
+       {&factory, "factory", "Factory", DEF_FACTORY, t_Int},
+       {&fisheye, "fisheye", "Fisheye", DEF_FISHEYE, t_Bool},
+       {&tightturns, "tightturns", "Tightturns", DEF_TIGHTTURNS, t_Bool},
+       {&rotatepipes, "rotatepipes", "Rotatepipes", DEF_ROTATEPIPES, t_Bool},
+       {&dbuf_p, "doubleBuffer", "DoubleBuffer", DEF_DBUF, t_Bool}
 };
 static OptionStruct desc[] =
 {
        {"-factory num", "how much extra equipment in pipes (0 for none)"},
        {"-/+fisheye", "turn on/off zoomed-in view of pipes"},
        {"-/+tightturns", "turn on/off tight turns"},
-       {"-/+rotatepipes", "turn on/off pipe system rotation per screenful"}
+       {"-/+rotatepipes", "turn on/off pipe system rotation per screenful"},
+       {"-/+db", "turn on/off double buffering"}
 };
 
-ModeSpecOpt pipes_opts =
-{7, opts, 4, vars, desc};
+ENTRYPOINT ModeSpecOpt pipes_opts =
+{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
+
+#ifdef USE_MODULES
+ModStruct   pipes_description =
+{"pipes", "init_pipes", "draw_pipes", "release_pipes",
+ "draw_pipes",
+ "change_pipes", NULL, &pipes_opts,
+ 1000, 2, 5, 500, 4, 1.0, "",
+ "Shows a selfbuilding pipe system", 0, NULL};
+
+#endif
 
 #define Scale4Window               0.1
 #define Scale4Iconic               0.07
@@ -132,9 +134,8 @@ ModeSpecOpt pipes_opts =
 /*************************************************************************/
 
 typedef struct {
-#if defined( MESA ) && defined( SLOW )
        int         flip;
-#endif
+
        GLint       WindH, WindW;
        int         Cells[HCELLS][VCELLS][HCELLS];
        int         usedcolors[DEFINEDCOLORS];
@@ -148,60 +149,44 @@ typedef struct {
        int         system_type;
        int         system_length;
        int         turncounter;
-       float      *system_color;
+       Window      window;
+       const float *system_color;
        GLfloat     initial_rotation;
        GLuint      valve, bolts, betweenbolts, elbowbolts, elbowcoins;
        GLuint      guagehead, guageface, guagedial, guageconnector;
-       GLXContext  glx_context;
+    int         reset;
+       GLXContext *glx_context;
 } pipesstruct;
 
 extern struct lwo LWO_BigValve, LWO_PipeBetweenBolts, LWO_Bolts3D;
 extern struct lwo LWO_GuageHead, LWO_GuageFace, LWO_GuageDial, LWO_GuageConnector;
 extern struct lwo LWO_ElbowBolts, LWO_ElbowCoins;
 
-static float front_shininess[] =
-{60.0};
-static float front_specular[] =
-{0.7, 0.7, 0.7, 1.0};
-static float ambient0[] =
-{0.4, 0.4, 0.4, 1.0};
-static float diffuse0[] =
-{1.0, 1.0, 1.0, 1.0};
-static float ambient1[] =
-{0.2, 0.2, 0.2, 1.0};
-static float diffuse1[] =
-{0.5, 0.5, 0.5, 1.0};
-static float position0[] =
-{1.0, 1.0, 1.0, 0.0};
-static float position1[] =
-{-1.0, -1.0, 1.0, 0.0};
-static float lmodel_ambient[] =
-{0.5, 0.5, 0.5, 1.0};
-static float lmodel_twoside[] =
-{GL_TRUE};
-
-static float MaterialRed[] =
-{0.7, 0.0, 0.0, 1.0};
-static float MaterialGreen[] =
-{0.1, 0.5, 0.2, 1.0};
-static float MaterialBlue[] =
-{0.0, 0.0, 0.7, 1.0};
-static float MaterialCyan[] =
-{0.2, 0.5, 0.7, 1.0};
-static float MaterialYellow[] =
-{0.7, 0.7, 0.0, 1.0};
-static float MaterialMagenta[] =
-{0.6, 0.2, 0.5, 1.0};
-static float MaterialWhite[] =
-{0.7, 0.7, 0.7, 1.0};
-static float MaterialGray[] =
-{0.2, 0.2, 0.2, 1.0};
+static const float front_shininess[] = {60.0};
+static const float front_specular[] = {0.7, 0.7, 0.7, 1.0};
+static const float ambient0[] = {0.4, 0.4, 0.4, 1.0};
+static const float diffuse0[] = {1.0, 1.0, 1.0, 1.0};
+static const float ambient1[] = {0.2, 0.2, 0.2, 1.0};
+static const float diffuse1[] = {0.5, 0.5, 0.5, 1.0};
+static const float position0[] = {1.0, 1.0, 1.0, 0.0};
+static const float position1[] = {-1.0, -1.0, 1.0, 0.0};
+static const float lmodel_ambient[] = {0.5, 0.5, 0.5, 1.0};
+static const float lmodel_twoside[] = {GL_TRUE};
+
+static const float MaterialRed[] = {0.7, 0.0, 0.0, 1.0};
+static const float MaterialGreen[] = {0.1, 0.5, 0.2, 1.0};
+static const float MaterialBlue[] = {0.0, 0.0, 0.7, 1.0};
+static const float MaterialCyan[] = {0.2, 0.5, 0.7, 1.0};
+static const float MaterialYellow[] = {0.7, 0.7, 0.0, 1.0};
+static const float MaterialMagenta[] = {0.6, 0.2, 0.5, 1.0};
+static const float MaterialWhite[] = {0.7, 0.7, 0.7, 1.0};
+static const float MaterialGray[] = {0.2, 0.2, 0.2, 1.0};
 
 static pipesstruct *pipes = NULL;
 
 
 static void
-MakeTube(int direction)
+MakeTube(ModeInfo *mi, int direction)
 {
        float       an;
        float       SINan_3, COSan_3;
@@ -213,13 +198,16 @@ MakeTube(int direction)
        /*dirNEAR  = 00000100 */
        /*dirFAR   = 00000101 */
 
-       glRotatef(90.0, (direction & 6) ? 0.0 : 1.0, (direction & 2) ? 1.0 : 0.0, 0.0);
-
+       if (!(direction & 4)) {
+               glRotatef(90.0, (direction & 2) ? 0.0 : 1.0,
+                         (direction & 2) ? 1.0 : 0.0, 0.0);
+       }
        glBegin(GL_QUAD_STRIP);
        for (an = 0.0; an <= 2.0 * M_PI; an += M_PI / 12.0) {
                glNormal3f((COSan_3 = cos(an) / 3.0), (SINan_3 = sin(an) / 3.0), 0.0);
                glVertex3f(COSan_3, SINan_3, one_third);
                glVertex3f(COSan_3, SINan_3, -one_third);
+        mi->polygon_count++;
        }
        glEnd();
 }
@@ -300,6 +288,7 @@ myElbow(ModeInfo * mi, int bolted)
                        glVertex3fv(p1);
                        glNormal3fv(n0);
                        glVertex3fv(p0);
+            mi->polygon_count++;
                        glEnd();
                }
        }
@@ -312,8 +301,10 @@ myElbow(ModeInfo * mi, int bolted)
                glRotatef(90.0, 0.0, 1.0, 0.0);
                glTranslatef(0.0, one_third, one_third);
                glCallList(pp->elbowcoins);
+        mi->polygon_count += LWO_ElbowCoins.num_pnts/3;
                glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
                glCallList(pp->elbowbolts);
+        mi->polygon_count += LWO_ElbowBolts.num_pnts/3;
                glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
                glPopMatrix();
                glFrontFace(GL_CCW);
@@ -385,9 +376,11 @@ MakeValve(ModeInfo * mi, int newdir)
        }
        glFrontFace(GL_CW);
        glCallList(pp->betweenbolts);
+    mi->polygon_count += LWO_PipeBetweenBolts.num_pnts/3;
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
        glCallList(pp->bolts);
-       if (!MI_WIN_IS_MONO(mi)) {
+    mi->polygon_count += LWO_Bolts3D.num_pnts/3;
+       if (!MI_IS_MONO(mi)) {
                if (pp->system_color == MaterialRed) {
                        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialYellow : MaterialBlue);
                } else if (pp->system_color == MaterialBlue) {
@@ -409,6 +402,7 @@ MakeValve(ModeInfo * mi, int newdir)
        }
        glRotatef((GLfloat) (NRAND(90)), 1.0, 0.0, 0.0);
        glCallList(pp->valve);
+    mi->polygon_count += LWO_BigValve.num_pnts/3;
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
        glFrontFace(GL_CCW);
 }
@@ -434,11 +428,14 @@ MakeGuage(ModeInfo * mi, int newdir)
        if ((newdir == dirLEFT) || (newdir == dirRIGHT))
                glRotatef(90.0, 0.0, 1.0, 0.0);
        glCallList(pp->betweenbolts);
+    mi->polygon_count += LWO_PipeBetweenBolts.num_pnts/3;
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
        glCallList(pp->bolts);
+    mi->polygon_count += LWO_Bolts3D.num_pnts/3;
        glPopMatrix();
 
        glCallList(pp->guageconnector);
+    mi->polygon_count += LWO_GuageConnector.num_pnts/3;
        glPushMatrix();
        glTranslatef(0.0, 1.33333, 0.0);
        /* Do not change the above to 1 + ONE_THIRD, because */
@@ -446,14 +443,17 @@ MakeGuage(ModeInfo * mi, int newdir)
        glRotatef(NRAND(270) + 45.0, 0.0, 0.0, -1.0);
        /* Random rotation for the dial.  I love it. */
        glCallList(pp->guagedial);
+    mi->polygon_count += LWO_GuageDial.num_pnts/3;
        glPopMatrix();
 
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
        glCallList(pp->guagehead);
+    mi->polygon_count += LWO_GuageHead.num_pnts/3;
 
        /* GuageFace is drawn last, in case of low-res depth buffers. */
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
        glCallList(pp->guageface);
+    mi->polygon_count += LWO_GuageFace.num_pnts/3;
 
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
        glFrontFace(GL_CCW);
@@ -467,7 +467,7 @@ MakeShape(ModeInfo * mi, int newdir)
        switch (NRAND(2)) {
                case 1:
                        if (!MakeGuage(mi, newdir))
-                               MakeTube(newdir);
+                               MakeTube(mi, newdir);
                        break;
                default:
                        MakeValve(mi, newdir);
@@ -475,10 +475,205 @@ MakeShape(ModeInfo * mi, int newdir)
        }
 }
 
-static void pinit(ModeInfo * mi, int zera);
+static void
+pinit(ModeInfo * mi, int zera)
+{
+       pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+       int         X, Y, Z;
+
+    if (zera)
+      mi->polygon_count = 0;
+
+       glClearDepth(1.0);
+       glClearColor(0.0, 0.0, 0.0, 1.0);
+       glColor3f(1.0, 1.0, 1.0);
+
+       glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);
+       glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
+       glLightfv(GL_LIGHT0, GL_POSITION, position0);
+       glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1);
+       glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
+       glLightfv(GL_LIGHT1, GL_POSITION, position1);
+       glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
+       glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
+       glEnable(GL_LIGHTING);
+       glEnable(GL_LIGHT0);
+       glEnable(GL_LIGHT1);
+       glEnable(GL_DEPTH_TEST);
+       glEnable(GL_NORMALIZE);
+       glEnable(GL_CULL_FACE);
+
+       glShadeModel(GL_SMOOTH);
+       glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
+       glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
+
+       if (zera) {
+               pp->system_number = 1;
+               glDrawBuffer(dbuf_p ? GL_BACK : GL_FRONT);
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+               (void) memset(pp->Cells, 0, sizeof (pp->Cells));
+               for (X = 0; X < HCELLS; X++) {
+                       for (Y = 0; Y < VCELLS; Y++) {
+                               pp->Cells[X][Y][0] = 1;
+                               pp->Cells[X][Y][HCELLS - 1] = 1;
+                               pp->Cells[0][Y][X] = 1;
+                               pp->Cells[HCELLS - 1][Y][X] = 1;
+                       }
+               }
+               for (X = 0; X < HCELLS; X++) {
+                       for (Z = 0; Z < HCELLS; Z++) {
+                               pp->Cells[X][0][Z] = 1;
+                               pp->Cells[X][VCELLS - 1][Z] = 1;
+                       }
+               }
+               (void) memset(pp->usedcolors, 0, sizeof (pp->usedcolors));
+               if ((pp->initial_rotation += 10.0) > 45.0) {
+                       pp->initial_rotation -= 90.0;
+               }
+       }
+       pp->counter = 0;
+       pp->turncounter = 0;
+
+       if (!MI_IS_MONO(mi)) {
+               int         collist[DEFINEDCOLORS];
+               int         i, j, lower = 1000;
+
+               /* Avoid repeating colors on the same screen unless necessary */
+               for (i = 0; i < DEFINEDCOLORS; i++) {
+                       if (lower > pp->usedcolors[i])
+                               lower = pp->usedcolors[i];
+               }
+               for (i = 0, j = 0; i < DEFINEDCOLORS; i++) {
+                       if (pp->usedcolors[i] == lower) {
+                               collist[j] = i;
+                               j++;
+                       }
+               }
+               i = collist[NRAND(j)];
+               pp->usedcolors[i]++;
+               switch (i) {
+                       case 0:
+                               pp->system_color = MaterialRed;
+                               break;
+                       case 1:
+                               pp->system_color = MaterialGreen;
+                               break;
+                       case 2:
+                               pp->system_color = MaterialBlue;
+                               break;
+                       case 3:
+                               pp->system_color = MaterialCyan;
+                               break;
+                       case 4:
+                               pp->system_color = MaterialYellow;
+                               break;
+                       case 5:
+                               pp->system_color = MaterialMagenta;
+                               break;
+                       case 6:
+                               pp->system_color = MaterialWhite;
+                               break;
+               }
+       } else {
+               pp->system_color = MaterialGray;
+       }
+
+       do {
+               pp->PX = NRAND((HCELLS - 1)) + 1;
+               pp->PY = NRAND((VCELLS - 1)) + 1;
+               pp->PZ = NRAND((HCELLS - 1)) + 1;
+       } while (pp->Cells[pp->PX][pp->PY][pp->PZ] ||
+                (pp->Cells[pp->PX + 1][pp->PY][pp->PZ] && pp->Cells[pp->PX - 1][pp->PY][pp->PZ] &&
+                 pp->Cells[pp->PX][pp->PY + 1][pp->PZ] && pp->Cells[pp->PX][pp->PY - 1][pp->PZ] &&
+                 pp->Cells[pp->PX][pp->PY][pp->PZ + 1] && pp->Cells[pp->PX][pp->PY][pp->PZ - 1]));
+       pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
+       pp->olddir = dirNone;
+
+       FindNeighbors(mi);
+
+       pp->nowdir = SelectNeighbor(mi);
+}
+
+ENTRYPOINT void
+reshape_pipes(ModeInfo * mi, int width, int height)
+{
+       pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+    pinit(mi, 1);
+
+       glViewport(0, 0, pp->WindW = (GLint) width, pp->WindH = (GLint) height);
+       glMatrixMode(GL_PROJECTION);
+       glLoadIdentity();
+       /*glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0); */
+       gluPerspective(65.0, (GLfloat) width / (GLfloat) height, 0.1, 20.0);
+       glMatrixMode(GL_MODELVIEW);
+
+  glClear(GL_COLOR_BUFFER_BIT);
+}
+
+ENTRYPOINT void
+init_pipes (ModeInfo * mi)
+{
+       int         screen = MI_SCREEN(mi);
+       pipesstruct *pp;
+
+       if (pipes == NULL) {
+               if ((pipes = (pipesstruct *) calloc(MI_NUM_SCREENS(mi),
+                                             sizeof (pipesstruct))) == NULL)
+                       return;
+       }
+       pp = &pipes[screen];
+
+       pp->window = MI_WINDOW(mi);
+       if ((pp->glx_context = init_GL(mi)) != NULL) {
+
+               reshape_pipes(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
+               if (rotatepipes)
+                 pp->initial_rotation = NRAND(180); /* jwz */
+               else
+                 pp->initial_rotation = -10.0;
+               pinit(mi, 1);
+
+               if (factory > 0) {
+                       pp->valve = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_BigValve);
+                       pp->bolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_Bolts3D);
+                       pp->betweenbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_PipeBetweenBolts);
+
+                       pp->elbowbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowBolts);
+                       pp->elbowcoins = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowCoins);
+
+                       pp->guagehead = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageHead);
+                       pp->guageface = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageFace);
+                       pp->guagedial = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageDial);
+                       pp->guageconnector = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageConnector);
+               }
+               /* else they are all 0, thanks to calloc(). */
+
+               if (MI_COUNT(mi) < 1 || MI_COUNT(mi) > NofSysTypes + 1) {
+                       pp->system_type = NRAND(NofSysTypes) + 1;
+               } else {
+                       pp->system_type = MI_COUNT(mi);
+               }
+
+               if (MI_CYCLES(mi) > 0 && MI_CYCLES(mi) < 11) {
+                       pp->number_of_systems = MI_CYCLES(mi);
+               } else {
+                       pp->number_of_systems = 5;
+               }
+
+               if (MI_SIZE(mi) < 10) {
+                       pp->system_length = 10;
+               } else if (MI_SIZE(mi) > 1000) {
+                       pp->system_length = 1000;
+               } else {
+                       pp->system_length = MI_SIZE(mi);
+               }
+       } else {
+               MI_CLEARWINDOW(mi);
+       }
+}
 
-void
-draw_pipes(ModeInfo * mi)
+ENTRYPOINT void
+draw_pipes (ModeInfo * mi)
 {
        pipesstruct *pp = &pipes[MI_SCREEN(mi)];
 
@@ -488,20 +683,27 @@ draw_pipes(ModeInfo * mi)
        int         newdir;
        int         OPX, OPY, OPZ;
 
-       glXMakeCurrent(display, window, pp->glx_context);
+       if (!pp->glx_context)
+               return;
+
+       glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
+
+    if (pp->reset) {
+      if (--pp->reset) {
+        /* Would be nice to fade to black here, by drawing successive quads
+           over the whole scene with gamma. */
+        return;
+      }
+      pinit(mi, 1);
+    }
 
-#if defined( MESA ) && defined( SLOW )
-       glDrawBuffer(GL_BACK);
-#else
-       glDrawBuffer(GL_FRONT);
-#endif
        glPushMatrix();
 
        glTranslatef(0.0, 0.0, fisheye ? -3.8 : -4.8);
        if (rotatepipes)
                glRotatef(pp->initial_rotation, 0.0, 1.0, 0.0);
 
-       if (!MI_WIN_IS_ICONIC(mi)) {
+       if (!MI_IS_ICONIC(mi)) {
                /* Width/height ratio handled by gluPerspective() now. */
                glScalef(Scale4Window, Scale4Window, Scale4Window);
        } else {
@@ -525,16 +727,15 @@ draw_pipes(ModeInfo * mi)
                glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
                /* Finish the system with another sphere */
                mySphere(0.6);
-#if defined( MESA ) && defined( SLOW )
-               glXSwapBuffers(display, window);
-#endif
+
                glPopMatrix();
 
                /* If the maximum number of system was drawn, restart (clearing the screen), */
                /* else start a new system. */
                if (++pp->system_number > pp->number_of_systems) {
-                       (void) sleep(1);
-                       pinit(mi, 1);
+          /* pause doing nothing for N seconds before clearing the screen. */
+          int secs = 3;
+          pp->reset = secs * 1000000 / MI_PAUSE(mi);
                } else {
                        pinit(mi, 0);
                }
@@ -573,7 +774,7 @@ draw_pipes(ModeInfo * mi)
                if ((pp->counter > 1) && (NRAND(100) < factory)) {
                        MakeShape(mi, newdir);
                } else {
-                       MakeTube(newdir);
+                       MakeTube(mi, newdir);
                }
                glPopMatrix();
        } else {
@@ -757,215 +958,35 @@ draw_pipes(ModeInfo * mi)
 
        /* Cells'face pipe */
        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);
-       MakeTube(newdir);
+       MakeTube(mi, newdir);
 
        glPopMatrix();
 
        glFlush();
 
-#if defined( MESA ) && defined( SLOW )
-       pp->flip = !pp->flip;
-       if (pp->flip)
-               glXSwapBuffers(display, window);
-#endif
-}
-
-static void
-reshape(ModeInfo * mi, int width, int height)
-{
-       pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+    if (dbuf_p)
+      glXSwapBuffers(display, window);
 
-       glViewport(0, 0, pp->WindW = (GLint) width, pp->WindH = (GLint) height);
-       glMatrixMode(GL_PROJECTION);
-       glLoadIdentity();
-       /*glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0); */
-       gluPerspective(65.0, (GLfloat) width / (GLfloat) height, 0.1, 20.0);
-       glMatrixMode(GL_MODELVIEW);
+    if (mi->fps_p) do_fps (mi);
 }
 
-static void
-pinit(ModeInfo * mi, int zera)
+#ifndef STANDALONE
+ENTRYPOINT void
+change_pipes (ModeInfo * mi)
 {
        pipesstruct *pp = &pipes[MI_SCREEN(mi)];
-       int         X, Y, Z;
-
-       glClearDepth(1.0);
-       glClearColor(0.0, 0.0, 0.0, 1.0);
-       glColor3f(1.0, 1.0, 1.0);
-
-       glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);
-       glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
-       glLightfv(GL_LIGHT0, GL_POSITION, position0);
-       glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1);
-       glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
-       glLightfv(GL_LIGHT1, GL_POSITION, position1);
-       glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
-       glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
-       glEnable(GL_LIGHTING);
-       glEnable(GL_LIGHT0);
-       glEnable(GL_LIGHT1);
-       glEnable(GL_DEPTH_TEST);
-       glEnable(GL_NORMALIZE);
-       glEnable(GL_CULL_FACE);
-
-       glShadeModel(GL_SMOOTH);
-       glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
-       glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
-
-       if (zera) {
-               pp->system_number = 1;
-               glDrawBuffer(GL_FRONT_AND_BACK);
-               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-               (void) memset(pp->Cells, 0, sizeof (pp->Cells));
-               for (X = 0; X < HCELLS; X++) {
-                       for (Y = 0; Y < VCELLS; Y++) {
-                               pp->Cells[X][Y][0] = 1;
-                               pp->Cells[X][Y][HCELLS - 1] = 1;
-                               pp->Cells[0][Y][X] = 1;
-                               pp->Cells[HCELLS - 1][Y][X] = 1;
-                       }
-               }
-               for (X = 0; X < HCELLS; X++) {
-                       for (Z = 0; Z < HCELLS; Z++) {
-                               pp->Cells[X][0][Z] = 1;
-                               pp->Cells[X][VCELLS - 1][Z] = 1;
-                       }
-               }
-               (void) memset(pp->usedcolors, 0, sizeof (pp->usedcolors));
-               if ((pp->initial_rotation += 10.0) > 45.0) {
-                       pp->initial_rotation -= 90.0;
-               }
-       }
-       pp->counter = 0;
-       pp->turncounter = 0;
-
-       if (!MI_WIN_IS_MONO(mi)) {
-               int         collist[DEFINEDCOLORS];
-               int         i, j, lower = 1000;
-
-               /* Avoid repeating colors on the same screen unless necessary */
-               for (i = 0; i < DEFINEDCOLORS; i++) {
-                       if (lower > pp->usedcolors[i])
-                               lower = pp->usedcolors[i];
-               }
-               for (i = 0, j = 0; i < DEFINEDCOLORS; i++) {
-                       if (pp->usedcolors[i] == lower) {
-                               collist[j] = i;
-                               j++;
-                       }
-               }
-               i = collist[NRAND(j)];
-               pp->usedcolors[i]++;
-               switch (i) {
-                       case 0:
-                               pp->system_color = MaterialRed;
-                               break;
-                       case 1:
-                               pp->system_color = MaterialGreen;
-                               break;
-                       case 2:
-                               pp->system_color = MaterialBlue;
-                               break;
-                       case 3:
-                               pp->system_color = MaterialCyan;
-                               break;
-                       case 4:
-                               pp->system_color = MaterialYellow;
-                               break;
-                       case 5:
-                               pp->system_color = MaterialMagenta;
-                               break;
-                       case 6:
-                               pp->system_color = MaterialWhite;
-                               break;
-               }
-       } else {
-               pp->system_color = MaterialGray;
-       }
-
-       do {
-               pp->PX = NRAND((HCELLS - 1)) + 1;
-               pp->PY = NRAND((VCELLS - 1)) + 1;
-               pp->PZ = NRAND((HCELLS - 1)) + 1;
-       } while (pp->Cells[pp->PX][pp->PY][pp->PZ] ||
-                (pp->Cells[pp->PX + 1][pp->PY][pp->PZ] && pp->Cells[pp->PX - 1][pp->PY][pp->PZ] &&
-                 pp->Cells[pp->PX][pp->PY + 1][pp->PZ] && pp->Cells[pp->PX][pp->PY - 1][pp->PZ] &&
-                 pp->Cells[pp->PX][pp->PY][pp->PZ + 1] && pp->Cells[pp->PX][pp->PY][pp->PZ - 1]));
-       pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
-       pp->olddir = dirNone;
-
-       FindNeighbors(mi);
-
-       pp->nowdir = SelectNeighbor(mi);
-}
-
-void
-init_pipes(ModeInfo * mi)
-{
-       int         screen = MI_SCREEN(mi);
-       pipesstruct *pp;
 
-       if (pipes == NULL) {
-               if ((pipes = (pipesstruct *) calloc(MI_NUM_SCREENS(mi),
-                                             sizeof (pipesstruct))) == NULL)
-                       return;
-       }
-       pp = &pipes[screen];
-
-       pp->glx_context = init_GL(mi);
+       if (!pp->glx_context)
+               return;
 
-       reshape(mi, MI_WIN_WIDTH(mi), MI_WIN_HEIGHT(mi));
-       pp->initial_rotation = -10.0;
+       glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
        pinit(mi, 1);
-
-       if (factory > 0) {
-               pp->valve = BuildLWO(MI_WIN_IS_WIREFRAME(mi), &LWO_BigValve);
-               pp->bolts = BuildLWO(MI_WIN_IS_WIREFRAME(mi), &LWO_Bolts3D);
-               pp->betweenbolts = BuildLWO(MI_WIN_IS_WIREFRAME(mi), &LWO_PipeBetweenBolts);
-
-               pp->elbowbolts = BuildLWO(MI_WIN_IS_WIREFRAME(mi), &LWO_ElbowBolts);
-               pp->elbowcoins = BuildLWO(MI_WIN_IS_WIREFRAME(mi), &LWO_ElbowCoins);
-
-               pp->guagehead = BuildLWO(MI_WIN_IS_WIREFRAME(mi), &LWO_GuageHead);
-               pp->guageface = BuildLWO(MI_WIN_IS_WIREFRAME(mi), &LWO_GuageFace);
-               pp->guagedial = BuildLWO(MI_WIN_IS_WIREFRAME(mi), &LWO_GuageDial);
-               pp->guageconnector = BuildLWO(MI_WIN_IS_WIREFRAME(mi), &LWO_GuageConnector);
-       }
-       /* else they are all 0, thanks to calloc(). */
-
-       if (MI_BATCHCOUNT(mi) < 1 || MI_BATCHCOUNT(mi) > NofSysTypes + 1) {
-               pp->system_type = NRAND(NofSysTypes) + 1;
-       } else {
-               pp->system_type = MI_BATCHCOUNT(mi);
-       }
-
-       if (MI_CYCLES(mi) > 0 && MI_CYCLES(mi) < 11) {
-               pp->number_of_systems = MI_CYCLES(mi);
-       } else {
-               pp->number_of_systems = 5;
-       }
-
-       if (MI_SIZE(mi) < 10) {
-               pp->system_length = 10;
-       } else if (MI_SIZE(mi) > 1000) {
-               pp->system_length = 1000;
-       } else {
-               pp->system_length = MI_SIZE(mi);
-       }
-
 }
+#endif /* !STANDALONE */
 
-void
-change_pipes(ModeInfo * mi)
-{
-       pipesstruct *pp = &pipes[MI_SCREEN(mi)];
-
-       glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), pp->glx_context);
-       pinit(mi, 1);
-}
 
-void
-release_pipes(ModeInfo * mi)
+ENTRYPOINT void
+release_pipes (ModeInfo * mi)
 {
        if (pipes != NULL) {
                int         screen;
@@ -973,36 +994,40 @@ release_pipes(ModeInfo * mi)
                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
                        pipesstruct *pp = &pipes[screen];
 
-                       /* Display lists MUST be freed while their glXContext is current. */
-                       glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), pp->glx_context);
-
-                       if (pp->valve)
-                               glDeleteLists(pp->valve, 1);
-                       if (pp->bolts)
-                               glDeleteLists(pp->bolts, 1);
-                       if (pp->betweenbolts)
-                               glDeleteLists(pp->betweenbolts, 1);
-
-                       if (pp->elbowbolts)
-                               glDeleteLists(pp->elbowbolts, 1);
-                       if (pp->elbowcoins)
-                               glDeleteLists(pp->elbowcoins, 1);
-
-                       if (pp->guagehead)
-                               glDeleteLists(pp->guagehead, 1);
-                       if (pp->guageface)
-                               glDeleteLists(pp->guageface, 1);
-                       if (pp->guagedial)
-                               glDeleteLists(pp->guagedial, 1);
-                       if (pp->guageconnector)
-                               glDeleteLists(pp->guageconnector, 1);
+                       if (pp->glx_context) {
+
+                               /* Display lists MUST be freed while their glXContext is current. */
+                               glXMakeCurrent(MI_DISPLAY(mi), pp->window, *(pp->glx_context));
+
+                               if (pp->valve)
+                                       glDeleteLists(pp->valve, 1);
+                               if (pp->bolts)
+                                       glDeleteLists(pp->bolts, 1);
+                               if (pp->betweenbolts)
+                                       glDeleteLists(pp->betweenbolts, 1);
+
+                               if (pp->elbowbolts)
+                                       glDeleteLists(pp->elbowbolts, 1);
+                               if (pp->elbowcoins)
+                                       glDeleteLists(pp->elbowcoins, 1);
+
+                               if (pp->guagehead)
+                                       glDeleteLists(pp->guagehead, 1);
+                               if (pp->guageface)
+                                       glDeleteLists(pp->guageface, 1);
+                               if (pp->guagedial)
+                                       glDeleteLists(pp->guagedial, 1);
+                               if (pp->guageconnector)
+                                       glDeleteLists(pp->guageconnector, 1);
+                       }
                }
 
-               /* Don't destroy the glXContext.  init_GL does that. */
-
                (void) free((void *) pipes);
                pipes = NULL;
        }
+       FreeAllGL(mi);
 }
 
+XSCREENSAVER_MODULE ("Pipes", pipes)
+
 #endif