From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / glx / pipes.c
index be4ae600b27a0b7e55d360783195feee0ceb1e8d..77be33e1fce2ed41c40b4ea451b4e3f0aea39df0 100644 (file)
@@ -1,9 +1,8 @@
 /* -*- Mode: C; tab-width: 4 -*- */
 /* pipes --- 3D selfbuiding pipe system */
 
-#if !defined( lint ) && !defined( SABER )
+#if 0
 static const char sccsid[] = "@(#)pipes.c      4.07 97/11/24 xlockmore";
-
 #endif
 
 /*-
@@ -33,39 +32,44 @@ static const char sccsid[] = "@(#)pipes.c   4.07 97/11/24 xlockmore";
  * Since I'm not a native English speaker, my apologies for any grammatical
  * mistake.
  *
- * My e-mail addresses are
- *
- * vianna@cat.cbpf.br 
- *         and
+ * My e-mail address is
  * m-vianna@usa.net
  * Marcelo F. Vianna (Apr-09-1997)
  *
  * Revision History:
+ * 24-Jun-12: Eliminate single-buffer dependency.
  * 29-Apr-97: Factory equipment by Ed Mackey.  Productive day today, eh?
  * 29-Apr-97: Less tight turns Jeff Epler <jepler@inetnebr.com>
  * 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
+/* This program was originally written to be single-buffered: it kept
+   building up new objects in the front buffer by never clearing the
+   depth or color buffers at the end of each frame.  In that way, it
+   was drawing a very small number of polygons per frame.  However,
+   modern systems make it difficult to live in a single-buffered world
+   like that.  So I changed it to re-generate the scene at every
+   frame, which makes it vastly less efficient, but also, makes it
+   work right on modern hardware.  It generates the entire system up
+   front, putting each "frame" of the animation into its own display
+   list; then it draws successively more of those display lists each
+   time the redisplay method is called.  When it reaches the end,
+   it regenerates a new system and re-populates the existing display
+   lists. -- jwz.
  */
 
-#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      "*delay:                100     \n"                     \
+# define DEFAULTS      "*delay:                10000   \n"                     \
                                        "*count:                2       \n"                     \
                                        "*cycles:               5       \n"                     \
                                        "*size:                 500     \n"                     \
-                                       "*fisheye:              True    \n"                     \
-                                       "*tightturns:   False   \n"                     \
-                                       "*rotatepipes:  True    \n"                     \
-                                       "*noBuffer:             True    \n"
+                       "*showFPS:      False   \n"                 \
+                       "*fpsSolid:     True    \n"                 \
+                       "*wireframe:    False   \n"                 \
+                                       "*suppressRotationAnimation: True\n" \
+
+# define refresh_pipes 0
+# define release_pipes 0
 # include "xlockmore.h"                                /* from the xscreensaver distribution */
 #else  /* !STANDALONE */
 # include "xlock.h"                                    /* from the xlockmore distribution */
@@ -73,8 +77,22 @@ static const char sccsid[] = "@(#)pipes.c    4.07 97/11/24 xlockmore";
 
 #ifdef USE_GL
 
-#include <GL/glu.h>
+#ifdef HAVE_JWXYZ
+# include "jwxyz.h"
+#else
+# include <X11/Xlib.h>
+# include <GL/gl.h>
+# include <GL/glu.h>
+#endif
+
+#ifdef HAVE_JWZGLES
+# include "jwzgles.h"
+#endif /* HAVE_JWZGLES */
+
+#include "sphere.h"
 #include "buildlwo.h"
+#include "teapot.h"
+#include "gltrackball.h"
 
 #define DEF_FACTORY     "2"
 #define DEF_FISHEYE     "True"
@@ -87,40 +105,36 @@ static Bool fisheye, tightturns, rotatepipes;
 
 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"},
 };
 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},
 };
 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"},
 };
 
-ModeSpecOpt pipes_opts =
+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",
-#if defined( MESA ) && defined( SLOW )
+{"pipes", "init_pipes", "draw_pipes", NULL,
  "draw_pipes",
-#else
- "change_pipes",
-#endif
  "change_pipes", NULL, &pipes_opts,
  1000, 2, 5, 500, 4, 1.0, "",
  "Shows a selfbuilding pipe system", 0, NULL};
@@ -128,7 +142,6 @@ ModStruct   pipes_description =
 #endif
 
 #define Scale4Window               0.1
-#define Scale4Iconic               0.07
 
 #define one_third                  0.3333333333333333333
 
@@ -148,10 +161,8 @@ ModStruct   pipes_description =
 /*************************************************************************/
 
 typedef struct {
-#if defined( MESA ) && defined( SLOW )
        int         flip;
-#endif
-       GLint       WindH, WindW;
+
        int         Cells[HCELLS][VCELLS][HCELLS];
        int         usedcolors[DEFINEDCOLORS];
        int         directions[6];
@@ -165,63 +176,57 @@ typedef struct {
        int         system_length;
        int         turncounter;
        Window      window;
-       float      *system_color;
+       const float *system_color;
        GLfloat     initial_rotation;
        GLuint      valve, bolts, betweenbolts, elbowbolts, elbowcoins;
-       GLuint      guagehead, guageface, guagedial, guageconnector;
+       GLuint      guagehead, guageface, guagedial, guageconnector, teapot;
+    int         teapot_polys;
        GLXContext *glx_context;
+
+    Bool button_down_p;
+    trackball_state *trackball;
+    GLuint *dlists, *poly_counts;
+    int dlist_count, dlist_size;
+    int system_index, system_size;
+
+    int fadeout;
+
 } 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)
 {
+    Bool        wire = MI_IS_WIREFRAME(mi);
        float       an;
        float       SINan_3, COSan_3;
+    int facets = (wire ? 5 : 24);
 
        /*dirUP    = 00000000 */
        /*dirDOWN  = 00000001 */
@@ -234,36 +239,46 @@ MakeTube(int direction)
                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) {
+       glBegin(wire ? GL_LINE_STRIP : GL_QUAD_STRIP);
+       for (an = 0.0; an <= 2.0 * M_PI; an += M_PI * 2 / facets) {
                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();
 }
 
 static void
-mySphere(float radius)
+mySphere(float radius, Bool wire)
 {
+#if 0
        GLUquadricObj *quadObj;
 
        quadObj = gluNewQuadric();
        gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
        gluSphere(quadObj, radius, 16, 16);
        gluDeleteQuadric(quadObj);
+#else
+    glPushMatrix();
+    glScalef (radius, radius, radius);
+    glRotatef (90, 1, 0, 0);
+    unit_sphere (16, 16, wire);
+    glPopMatrix();
+#endif
 }
 
 static void
 myElbow(ModeInfo * mi, int bolted)
 {
-#define nsides 25
-#define rings 25
+       pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+    Bool        wire = MI_IS_WIREFRAME(mi);
+
+    int nsides = (wire ? 6 : 25);
+    int rings  = nsides;
 #define r one_third
 #define R one_third
 
-       pipesstruct *pp = &pipes[MI_SCREEN(mi)];
-
        int         i, j;
        GLfloat     p0[3], p1[3], p2[3], p3[3];
        GLfloat     n0[3], n1[3], n2[3], n3[3];
@@ -310,7 +325,7 @@ myElbow(ModeInfo * mi, int bolted)
                        p0[2] = p1[2] = r * (n0[2] = n1[2] = sin(phi));
                        p2[2] = p3[2] = r * (n2[2] = n3[2] = sin(phi1));
 
-                       glBegin(GL_QUADS);
+                       glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
                        glNormal3fv(n3);
                        glVertex3fv(p3);
                        glNormal3fv(n2);
@@ -319,6 +334,7 @@ myElbow(ModeInfo * mi, int bolted)
                        glVertex3fv(p1);
                        glNormal3fv(n0);
                        glVertex3fv(p0);
+            mi->polygon_count++;
                        glEnd();
                }
        }
@@ -331,8 +347,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);
@@ -404,8 +422,10 @@ 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);
+    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);
@@ -428,6 +448,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);
 }
@@ -453,11 +474,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 */
@@ -465,14 +489,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);
@@ -480,31 +507,60 @@ MakeGuage(ModeInfo * mi, int newdir)
        return (1);
 }
 
-static void
-MakeShape(ModeInfo * mi, int newdir)
+
+static GLuint
+build_teapot(ModeInfo *mi)
 {
-       switch (NRAND(2)) {
-               case 1:
-                       if (!MakeGuage(mi, newdir))
-                               MakeTube(newdir);
-                       break;
-               default:
-                       MakeValve(mi, newdir);
-                       break;
-       }
+  pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+  GLuint list = glGenLists(1);
+  if (!list) return 0;
+  glNewList(list, GL_COMPILE);
+  pp->teapot_polys = unit_teapot (12, MI_IS_WIREFRAME(mi));
+  glEndList();
+  return list;
 }
 
+
 static void
-reshape(ModeInfo * mi, int width, int height)
+MakeTeapot(ModeInfo * mi, int newdir)
 {
-       pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+  pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+
+  switch (newdir) {
+  case dirUP:
+  case dirDOWN:
+    glRotatef(90.0, 1.0, 0.0, 0.0);
+    glRotatef(NRAND(3) * 90.0, 0.0, 0.0, 1.0);
+    break;
+  case dirLEFT:
+  case dirRIGHT:
+    glRotatef(90.0, 0.0, -1.0, 0.0);
+    glRotatef((NRAND(3) * 90.0) - 90.0, 0.0, 0.0, 1.0);
+    break;
+  case dirNEAR:
+  case dirFAR:
+    glRotatef(NRAND(4) * 90.0, 0.0, 0.0, 1.0);
+    break;
+  }
+
+  glCallList(pp->teapot);
+  mi->polygon_count += pp->teapot_polys;
+  glFrontFace(GL_CCW);
+}
 
-       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);
+
+static void
+MakeShape(ModeInfo * mi, int newdir)
+{
+  int n = NRAND(100);
+  if (n < 50) {
+    if (!MakeGuage(mi, newdir))
+      MakeTube(mi, newdir);
+  } else if (n < 98) {
+    MakeValve(mi, newdir);
+  } else {
+    MakeTeapot(mi,newdir);
+  }
 }
 
 static void
@@ -513,32 +569,8 @@ pinit(ModeInfo * mi, int zera)
        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++) {
@@ -556,9 +588,6 @@ pinit(ModeInfo * mi, int zera)
                        }
                }
                (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;
@@ -623,24 +652,62 @@ pinit(ModeInfo * mi, int zera)
        pp->nowdir = SelectNeighbor(mi);
 }
 
-void
-init_pipes(ModeInfo * mi)
+
+ENTRYPOINT void
+reshape_pipes(ModeInfo * mi, int width, int height)
+{
+       glViewport(0, 0, width, (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 Bool
+pipes_handle_event (ModeInfo *mi, XEvent *event)
+{
+  pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+
+  if (gltrackball_event_handler (event, pp->trackball,
+                                 MI_WIDTH (mi), MI_HEIGHT (mi),
+                                 &pp->button_down_p))
+    return True;
+  else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
+    {
+      pp->fadeout = 100;
+      return True;
+    }
+
+  return False;
+}
+
+
+
+static void generate_system (ModeInfo *);
+
+
+static void free_pipes (ModeInfo *);
+
+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;
-       }
+       MI_INIT (mi, pipes, free_pipes);
        pp = &pipes[screen];
 
        pp->window = MI_WINDOW(mi);
        if ((pp->glx_context = init_GL(mi)) != NULL) {
 
-               reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
-               pp->initial_rotation = -10.0;
+               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) {
@@ -655,6 +722,7 @@ init_pipes(ModeInfo * mi)
                        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);
+                       pp->teapot = build_teapot(mi);
                }
                /* else they are all 0, thanks to calloc(). */
 
@@ -680,51 +748,71 @@ init_pipes(ModeInfo * mi)
        } else {
                MI_CLEARWINDOW(mi);
        }
+
+    pp->trackball = gltrackball_init (True);
+    generate_system (mi);
 }
 
-void
-draw_pipes(ModeInfo * mi)
+
+static GLuint
+get_dlist (ModeInfo *mi, int i)
 {
-       pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+  pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+  if (i >= pp->dlist_count)
+    {
+      pp->dlist_count++;
+      if (pp->dlist_count >= pp->dlist_size)
+        {
+          int s2 = (pp->dlist_size + 100) * 1.2;
+          pp->dlists = (GLuint *)
+            realloc (pp->dlists, s2 * sizeof(*pp->dlists));
+          if (! pp->dlists) abort();
+          pp->poly_counts = (GLuint *)
+            realloc (pp->poly_counts, s2 * sizeof(*pp->poly_counts));
+          if (! pp->poly_counts) abort();
+          pp->dlist_size = s2;
+        }
+      pp->dlists [i] = glGenLists (1);
+      pp->poly_counts [i] = 0;
+    }
+  return pp->dlists[i];
+}
+
 
-       Display    *display = MI_DISPLAY(mi);
-       Window      window = MI_WINDOW(mi);
+
+static void
+generate_system (ModeInfo * mi)
+{
+       pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+    Bool        wire = MI_IS_WIREFRAME(mi);
 
        int         newdir;
        int         OPX, OPY, OPZ;
 
-       if (!pp->glx_context)
-               return;
+    Bool reset_p = False;
 
-       glXMakeCurrent(display, window, *(pp->glx_context));
+    pp->system_index = 0;
+    pp->system_size = 0;
+    pinit (mi, 1);
 
-#if defined( MESA ) && defined( SLOW )
-       glDrawBuffer(GL_BACK);
-#else
-       glDrawBuffer(GL_FRONT);
-#endif
-       glPushMatrix();
+    while (1) {
+      glNewList (get_dlist (mi, pp->system_size++), GL_COMPILE);
+      mi->polygon_count = 0;
 
-       glTranslatef(0.0, 0.0, fisheye ? -3.8 : -4.8);
-       if (rotatepipes)
-               glRotatef(pp->initial_rotation, 0.0, 1.0, 0.0);
-
-       if (!MI_IS_ICONIC(mi)) {
-               /* Width/height ratio handled by gluPerspective() now. */
-               glScalef(Scale4Window, Scale4Window, Scale4Window);
-       } else {
-               glScalef(Scale4Iconic, Scale4Iconic, Scale4Iconic);
-       }
+       glPushMatrix();
 
        FindNeighbors(mi);
 
-       glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
+    if (wire)
+      glColor4fv (pp->system_color);
+    else
+      glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
 
        /* If it's the begining of a system, draw a sphere */
        if (pp->olddir == dirNone) {
                glPushMatrix();
                glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
-               mySphere(0.6);
+               mySphere(0.6, wire);
                glPopMatrix();
        }
        /* Check for stop conditions */
@@ -732,23 +820,19 @@ draw_pipes(ModeInfo * mi)
                glPushMatrix();
                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
+               mySphere(0.6, wire);
+
                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);
+          reset_p = True;
                } else {
                        pinit(mi, 0);
                }
 
-               glPopMatrix();
-               return;
+        goto NEXT;
        }
        pp->counter++;
        pp->turncounter++;
@@ -781,7 +865,7 @@ draw_pipes(ModeInfo * mi)
                if ((pp->counter > 1) && (NRAND(100) < factory)) {
                        MakeShape(mi, newdir);
                } else {
-                       MakeTube(newdir);
+                       MakeTube(mi, newdir);
                }
                glPopMatrix();
        } else {
@@ -796,7 +880,7 @@ draw_pipes(ModeInfo * mi)
                switch (sysT) {
                        case 1:
                                glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
-                               mySphere(elbowradius);
+                               mySphere(elbowradius, wire);
                                break;
                        case 2:
                        case 3:
@@ -965,21 +1049,112 @@ 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);
 
+    NEXT:
        glPopMatrix();
+    glEndList();
+    pp->poly_counts [pp->system_size-1] = mi->polygon_count;
 
-       glFlush();
+    if (reset_p)
+      break;
+    }
+}
 
-#if defined( MESA ) && defined( SLOW )
-       pp->flip = !pp->flip;
-       if (pp->flip)
-               glXSwapBuffers(display, window);
-#endif
+
+ENTRYPOINT void
+draw_pipes (ModeInfo * mi)
+{
+       pipesstruct *pp = &pipes[MI_SCREEN(mi)];
+       Display *display = MI_DISPLAY(mi);
+       Window    window = MI_WINDOW(mi);
+    Bool        wire = MI_IS_WIREFRAME(mi);
+    int i = 0;
+
+       if (!pp->glx_context)
+               return;
+
+       glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+       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);
+
+    if (wire)
+      glDisable(GL_LIGHTING);
+    else
+      {
+        glEnable(GL_LIGHTING);
+        glEnable(GL_LIGHT0);
+        /* This looks crappy. */
+        /* 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);
+
+    glPushMatrix();
+
+    pp->initial_rotation += 0.02;
+
+       glTranslatef(0.0, 0.0, fisheye ? -3.8 : -4.8);
+
+    gltrackball_rotate (pp->trackball);
+
+       if (rotatepipes)
+      glRotatef(pp->initial_rotation, 0.0, 1.0, 0.0);
+
+    glScalef(Scale4Window, Scale4Window, Scale4Window);
+
+    mi->polygon_count = 0;
+
+    if (pp->fadeout)
+      {
+        GLfloat s = (pp->fadeout * pp->fadeout) / 10000.0;
+        glScalef (s, s, s);
+        glRotatef (90 * (1 - (pp->fadeout/100.0)), 1, 0, 0.1);
+        pp->fadeout -= 4;
+        if (pp->fadeout <= 0)
+          {
+            pp->fadeout = 0;
+            generate_system (mi);
+          }
+      }
+    else if (pp->system_index < pp->system_size)
+      pp->system_index++;
+    else
+      pp->fadeout = 100;
+
+    for (i = 0; i < pp->system_index; i++)
+      {
+        glCallList (pp->dlists[i]);
+        mi->polygon_count += pp->poly_counts[i];
+      }
+
+    glPopMatrix();
+
+    if (mi->fps_p) do_fps (mi);
+    glFinish();
+
+    glXSwapBuffers(display, window);
 }
 
-void
-change_pipes(ModeInfo * mi)
+
+#ifndef STANDALONE
+ENTRYPOINT void
+change_pipes (ModeInfo * mi)
 {
        pipesstruct *pp = &pipes[MI_SCREEN(mi)];
 
@@ -989,48 +1164,52 @@ change_pipes(ModeInfo * mi)
        glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
        pinit(mi, 1);
 }
+#endif /* !STANDALONE */
 
-void
-release_pipes(ModeInfo * mi)
+
+static void
+free_pipes (ModeInfo * mi)
 {
-       if (pipes != NULL) {
-               int         screen;
-
-               for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
-                       pipesstruct *pp = &pipes[screen];
-
-                       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);
-                       }
-               }
+       pipesstruct *pp = &pipes[MI_SCREEN(mi)];
 
-               (void) free((void *) pipes);
-               pipes = NULL;
+       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);
+               if (pp->teapot)
+                       glDeleteLists(pp->teapot, 1);
+        if (pp->dlists)
+          {
+            int i;
+            for (i = 0; i < pp->dlist_count; i++)
+              glDeleteLists (pp->dlists[i], 1);
+            free (pp->dlists);
+            free (pp->poly_counts);
+          }
        }
-       FreeAllGL(mi);
 }
 
+XSCREENSAVER_MODULE ("Pipes", pipes)
+
 #endif