From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / glx / boxed.c
index 1200e62c7a339949af85a1de29062b95200b261e..1791052602042a21944acddc82b25f538883aaa4 100644 (file)
@@ -1,4 +1,4 @@
-/* thebox --- 3D bouncing balls that explode */
+/* boxed --- 3D bouncing balls that explode */
 
 #if 0
 static const char sccsid[] = "@(#)boxed.c      0.9 01/09/26 xlockmore";
@@ -23,9 +23,15 @@ static const char sccsid[] = "@(#)boxed.c    0.9 01/09/26 xlockmore";
  *       as an OpenGL screensaver for the xscreensaver package.
  *       Lots of hardcoded values still in place. Also, there are some
  *       copy/paste leftovers from the gears hack. opts don't work.
+ *
+ * 2005: opts work. added options -balls, -ballsize, -explosion
+ *
+ * 2006: opts work. added option -decay
+ *
+ * 2008: opts work. added option -momentum
+ *
  */
 
-#include <X11/Intrinsic.h>
 #include "boxed.h"
 
 /*
@@ -35,49 +41,64 @@ static const char sccsid[] = "@(#)boxed.c   0.9 01/09/26 xlockmore";
 */
 
 #ifdef STANDALONE
-# define PROGCLASS                                     "boxed"
-# define HACK_INIT                                     init_boxed
-# define HACK_DRAW                                     draw_boxed
-# define HACK_RESHAPE                                  reshape_boxed
-# define boxed_opts                                    xlockmore_opts
-# define DEFAULTS      "*delay:                20000   \n"                     \
-     "*showFPS:         False   \n"                    \
-
-# include "xlockmore.h"                                /* from the xscreensaver distribution */
+# define DEFAULTS      "*delay:     15000   \n" \
+                       "*showFPS:   False   \n" \
+                       "*wireframe: False   \n"
+
+# define refresh_boxed 0
+# define release_boxed 0
+# define boxed_handle_event 0
+# include "xlockmore.h"                /* from the xscreensaver distribution */
 #else  /* !STANDALONE */
-# include "xlock.h"                                    /* from the xlockmore distribution */
+# include "xlock.h"            /* from the xlockmore distribution */
 #endif /* !STANDALONE */
 
 #ifdef USE_GL
-#include <GL/glu.h>
+
+# define DEF_SPEED      "0.5"
+# define DEF_BALLS     "20"
+# define DEF_BALLSIZE   "3.0"
+# define DEF_EXPLOSION "15.0"
+# define DEF_DECAY     "0.07"
+# define DEF_MOMENTUM  "0.6"
 
 #undef countof 
 #define countof(x) (int)(sizeof((x))/sizeof((*x)))
 #undef rnd
 #define rnd() (frand(1.0))
 
-/* #define DEF_PLANETARY "False"
+static GLfloat speed;  /* jwz -- overall speed factor applied to all motion */
+static int cfg_balls;
+static GLfloat cfg_ballsize;
+static GLfloat cfg_explosion;
+static GLfloat cfg_decay;
+static GLfloat cfg_momentum;
 
-static int planetary;
 
 static XrmOptionDescRec opts[] = {
-  {"-planetary", ".gears.planetary", XrmoptionNoArg, (caddr_t) "true" },
-  {"+planetary", ".gears.planetary", XrmoptionNoArg, (caddr_t) "false" },
+    {"-speed", ".boxed.speed", XrmoptionSepArg, 0},
+    {"-balls", ".boxed.balls", XrmoptionSepArg, 0},
+    {"-ballsize", ".boxed.ballsize", XrmoptionSepArg, 0},
+    {"-explosion", ".boxed.explosion", XrmoptionSepArg, 0},
+    {"-decay", ".boxed.decay", XrmoptionSepArg, 0},
+    {"-momentum", ".boxed.momentum", XrmoptionSepArg, 0},
 };
 
 static argtype vars[] = {
-  {&planetary, "planetary", "Planetary", DEF_PLANETARY, t_Bool},
+    {&speed, "speed", "Speed", DEF_SPEED, t_Float},
+    {&cfg_balls, "balls", "Balls", DEF_BALLS, t_Int},
+    {&cfg_ballsize, "ballsize", "Ball Size", DEF_BALLSIZE, t_Float},
+    {&cfg_explosion, "explosion", "Explosion", DEF_EXPLOSION, t_Float},
+    {&cfg_decay, "decay", "Explosion Decay", DEF_DECAY, t_Float},
+    {&cfg_momentum, "momentum", "Explosion Momentum", DEF_MOMENTUM, t_Float},
 };
-*/
 
-/* ModeSpecOpts boxed_opts = {countof(opts), opts, countof(vars), vars, NULL}; */
-
-ModeSpecOpt boxed_opts = {0, NULL, 0, NULL, NULL};
+ENTRYPOINT ModeSpecOpt boxed_opts = {countof(opts), opts, countof(vars), vars, NULL};
 
 #ifdef USE_MODULES
 
 ModStruct   boxed_description = { 
-     "boxed", "init_boxed", "draw_boxed", "release_boxed",
+     "boxed", "init_boxed", "draw_boxed", NULL,
      "draw_boxed", "init_boxed", NULL, &boxed_opts,
      1000, 1, 2, 1, 4, 1.0, "",
      "Shows GL's boxed balls", 0, NULL};
@@ -88,27 +109,18 @@ ModStruct   boxed_description = {
 #define TRUE 1
 #define FALSE 0
 
-/* rendering defines */
-
-/* box size */
-#define BOX_SIZE       20.0f
-
 /* camera */
-#define CAM_HEIGHT     100.0f
-#define CAMDISTANCE_MIN 20.0
+#define CAM_HEIGHT     80.0f
+#define CAMDISTANCE_MIN 35.0
 #define CAMDISTANCE_MAX 150.0
 #define CAMDISTANCE_SPEED 1.5
+#define LOOKAT_R 30.0
 
 /* rendering the sphere */
-#define MESH_SIZE      5
+#define MESH_SIZE      10
 #define SPHERE_VERTICES        (2+MESH_SIZE*MESH_SIZE*2)
 #define SPHERE_INDICES ((MESH_SIZE*4 + MESH_SIZE*4*(MESH_SIZE-1))*3)
 
-#define EXPLOSION 10.0f
-#define MAXBALLS  50;
-#define NUMBALLS 12;
-#define BALLSIZE 3.0f;
-
 /*
 **-----------------------------------------------------------------------------
 **     Typedefs
@@ -142,6 +154,7 @@ typedef struct {
    vectorf     loc;
    vectorf     dir;
    BOOL         far;
+   int          gone;
 } tri;
 
 typedef struct {
@@ -149,6 +162,8 @@ typedef struct {
    int                 lifetime;
    float       scalefac;
    float       explosion;
+   float       decay;
+   float       momentum;
    vectorf     color;
    tri         *tris;
    GLint       *indices;
@@ -160,6 +175,8 @@ typedef struct {
    int numballs;
    float ballsize;
    float explosion;
+   float decay;
+   float momentum;
    BOOL textures;
    BOOL transparent;
    float camspeed;
@@ -170,6 +187,7 @@ typedef struct {
    float          cam_x_speed, cam_z_speed, cam_y_speed;
    boxed_config  config;
    float         tic;
+   float          camtic;
    vectorf        spherev[SPHERE_VERTICES];
    GLint          spherei[SPHERE_INDICES];
    ballman        bman;
@@ -177,6 +195,7 @@ typedef struct {
    GLXContext     *glx_context;
    GLuint         listobjects;
    GLuint         gllists[3];
+   int            list_polys[3];
    Window         window;
    BOOL           stop;
    char           *tex1;
@@ -254,6 +273,12 @@ squaremagnitude(vectorf * v)
    return v->x * v->x + v->y * v->y + v->z * v->z;
 }
 
+static inline GLfloat
+squaremagnitudehorz(vectorf * v)
+{
+   return v->x * v->x + v->z * v->z;
+}
+
 
 
 /*
@@ -262,7 +287,7 @@ squaremagnitude(vectorf * v)
  * Input: 
  */ 
 
-static void generatesphere(void)
+static void generatesphere(boxedstruct *gp)
 {
    float   dj = M_PI/(MESH_SIZE+1.0f);
    float   di = M_PI/MESH_SIZE;
@@ -278,8 +303,8 @@ static void generatesphere(void)
     * vertices 0 and 1 are the north and south poles
     */
    
-   spherei = boxed->spherei;
-   spherev = boxed->spherev;
+   spherei = gp->spherei;
+   spherev = gp->spherev;
    
    spherev[0].x = 0.0f; spherev[0].y =1.0f; spherev[0].z = 0.0f;
    spherev[1].x = 0.0f; spherev[1].y =-1.0f; spherev[1].z = 0.0f;
@@ -342,18 +367,19 @@ static void generatesphere(void)
  * create fresh ball 
  */
 
-void createball(ball *newball) {
+static void createball(ball *newball) 
+{
    float r=0.0f,g=0.0f,b=0.0f;
    newball->loc.x = 5-10*rnd();
    newball->loc.y = 35+20*rnd();
    newball->loc.z = 5-10*rnd();
-   newball->dir.x = 0.5f-rnd();
+   newball->dir.x = (0.5f-rnd()) * speed;
    newball->dir.y = 0.0;
-   newball->dir.z = 0.5-rnd();
+   newball->dir.z = (0.5-rnd())  * speed;
    newball->offside = 0;
    newball->bounced = FALSE;
-   newball->radius = BALLSIZE;
-   while (r+g+b < 1.7f ) {
+   newball->radius = cfg_ballsize;
+   while (r+g+b < 1.8f ) {
       newball->color.x = r=rnd();
       newball->color.y = g=rnd();
       newball->color.z = b=rnd();
@@ -363,24 +389,27 @@ void createball(ball *newball) {
 
 /* Update position of each ball */
 
-void updateballs(ballman *bman) {
+static void updateballs(ballman *bman) 
+{
    register int b,j;
    vectorf dvect,richting,relspeed,influence;
    GLfloat squaredist;
 
    for (b=0;b<bman->num_balls;b++) {
 
+     GLfloat gravity = 0.30f * speed;
+
       /* apply gravity */
-      bman->balls[b].dir.y -= 0.15f;
+      bman->balls[b].dir.y -= gravity;
       /* apply movement */
       addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
       /* boundary check */
       if (bman->balls[b].loc.y < bman->balls[b].radius) { /* ball onder bodem? (bodem @ y=0) */
-        if ((bman->balls[b].loc.x < -100.0) || 
-            (bman->balls[b].loc.x > 100.0) ||
-            (bman->balls[b].loc.z < -100.0) ||
-            (bman->balls[b].loc.z > 100.0)) {
-           if (bman->balls[b].loc.y < -1000.0)
+        if ((bman->balls[b].loc.x < -95.0) || 
+            (bman->balls[b].loc.x > 95.0) ||
+            (bman->balls[b].loc.z < -95.0) ||
+            (bman->balls[b].loc.z > 95.0)) {
+           if (bman->balls[b].loc.y < -2000.0)
              createball(&bman->balls[b]);
         } else {
            bman->balls[b].loc.y = bman->balls[b].radius  + (bman->balls[b].radius - bman->balls[b].loc.y);
@@ -390,7 +419,10 @@ void updateballs(ballman *bman) {
               scalevector(&bman->balls[b].dir,&bman->balls[b].dir,0.80f);
               if (squaremagnitude(&bman->balls[b].dir) < 0.08f) {
                  createball(&bman->balls[b]);
-              }
+               }
+              if (squaremagnitudehorz(&bman->balls[b].dir) < 0.005f) {
+                 createball(&bman->balls[b]);
+               }
            }
         }
         
@@ -457,16 +489,19 @@ void updateballs(ballman *bman) {
 * explode ball into triangles
 */
 
-void createtrisfromball(triman* tman, vectorf *spherev, GLint *spherei, int ind_num, ball *b) {
+static void createtrisfromball(triman* tman, vectorf *spherev, GLint *spherei, int ind_num, ball *b)
+{
    int pos;
    float explosion;
+   float momentum;
    float scale;
    register int i;
-   vectorf avgdir,dvect;
+   vectorf avgdir,dvect,mvect;
 
    tman->scalefac = b->radius;
    copyvector(&tman->color,&b->color);
    explosion = 1.0f + tman->explosion * 2.0 * rnd();
+   momentum = tman->momentum;
 
    tman->num_tri = ind_num/3;
    
@@ -478,6 +513,7 @@ void createtrisfromball(triman* tman, vectorf *spherev, GLint *spherei, int ind_
    
    for (i=0; i<(tman->num_tri); i++) {
       tman->tris[i].far = FALSE;
+      tman->tris[i].gone = 0;
       pos = i * 3;
       /* kopieer elke poly apart naar een tri structure */
       copyvector(&tman->vertices[pos+0],&spherev[spherei[pos+0]]);
@@ -509,12 +545,28 @@ void createtrisfromball(triman* tman, vectorf *spherev, GLint *spherei, int ind_
       scalevector(&tman->vertices[pos+1],&tman->vertices[pos+1],scale);
       scalevector(&tman->vertices[pos+2],&tman->vertices[pos+2],scale);
             
+      tman->vertices[pos+0].x += avgdir.x;
+      tman->vertices[pos+0].y += avgdir.y;
+      tman->vertices[pos+0].z += avgdir.z;
+      tman->vertices[pos+1].x += avgdir.x;
+      tman->vertices[pos+1].y += avgdir.y;
+      tman->vertices[pos+1].z += avgdir.z;
+      tman->vertices[pos+2].x += avgdir.x;
+      tman->vertices[pos+2].y += avgdir.y;
+      tman->vertices[pos+2].z += avgdir.z;
+
       /* bereken nieuwe richting */
       scalevector(&tman->tris[i].dir,&avgdir,explosion);
-      dvect.x = 0.1f - 0.2f*rnd();
-      dvect.y = 0.15f - 0.3f*rnd();
-      dvect.z = 0.1f - 0.2f*rnd(); 
+      dvect.x = (0.1f - 0.2f*rnd());
+      dvect.y = (0.15f - 0.3f*rnd());
+      dvect.z = (0.1f - 0.2f*rnd());
       addvectors(&tman->tris[i].dir,&tman->tris[i].dir,&dvect);
+
+      /* add ball's momentum to each piece of the exploded ball */
+      mvect.x = b->dir.x * momentum;
+      mvect.y = 0;
+      mvect.z = b->dir.z * momentum;
+      addvectors(&tman->tris[i].dir,&tman->tris[i].dir,&mvect);
    }
 }
 
@@ -523,22 +575,28 @@ void createtrisfromball(triman* tman, vectorf *spherev, GLint *spherei, int ind_
 * update position of each tri
 */
 
-void updatetris(triman *t) {
+static void updatetris(triman *t) 
+{
    int b;
    GLfloat xd,zd;
    
    for (b=0;b<t->num_tri;b++) {
+      /* the exploded triangles disappear over time */
+      if (rnd() < t->decay) {
+         if (t->tris[b].gone == 0)
+             t->tris[b].gone = 1;
+      }
       /* apply gravity */
-      t->tris[b].dir.y -= 0.1f;
+      t->tris[b].dir.y -= (0.1f * speed);
       /* apply movement */
       addvectors(&t->tris[b].loc,&t->tris[b].loc,&t->tris[b].dir);
       /* boundary check */
       if (t->tris[b].far) continue;
       if (t->tris[b].loc.y < 0) { /* onder bodem ? */
-        if ((t->tris[b].loc.x > -100.0f) &
-            (t->tris[b].loc.x < 100.0f) &
-            (t->tris[b].loc.z > -100.0f) &
-            (t->tris[b].loc.z < 100.0f)) {  /* in veld  */
+        if ((t->tris[b].loc.x > -95.0f) &
+            (t->tris[b].loc.x < 95.0f) &
+            (t->tris[b].loc.z > -95.0f) &
+            (t->tris[b].loc.z < 95.0f)) {  /* in veld  */
            t->tris[b].dir.y = -(t->tris[b].dir.y);
            t->tris[b].loc.y = -t->tris[b].loc.y;
            scalevector(&t->tris[b].dir,&t->tris[b].dir,0.80f); /* dampening */
@@ -595,7 +653,8 @@ void updatetris(triman *t) {
 /*
  * free memory allocated by a tri manager
  */
-void freetris(triman *t) {
+static void freetris(triman *t) 
+{
    if (!t) return;
    if (t->tris) free(t->tris);
    if (t->vertices) free(t->vertices);
@@ -611,12 +670,21 @@ void freetris(triman *t) {
 /*
  *load defaults in config structure
  */
-void setdefaultconfig(boxed_config *config) {
-  config->numballs = NUMBALLS;
+static void setdefaultconfig(boxed_config *config) 
+{
+  cfg_balls = MAX(3,MIN(40,cfg_balls));
+  cfg_ballsize = MAX(1.0f,MIN(5.0f,cfg_ballsize));
+  cfg_explosion = MAX(0.0f,MIN(50.0f,cfg_explosion));
+  cfg_decay = MAX(0.02f,MIN(0.90f,cfg_decay));
+  cfg_momentum = MAX(0.0f,MIN(1.0f,cfg_momentum));
+
+  config->numballs = cfg_balls;
   config->textures = TRUE;
   config->transparent = FALSE;
-  config->explosion = 25.0f;
-  config->ballsize = BALLSIZE;
+  config->explosion = cfg_explosion;
+  config->decay = cfg_decay;
+  config->momentum = cfg_momentum;
+  config->ballsize = cfg_ballsize;
   config->camspeed = 35.0f;
 }
 
@@ -624,15 +692,16 @@ void setdefaultconfig(boxed_config *config) {
 /*
  * draw bottom
  */ 
-static void drawfilledbox(boxedstruct *boxed)
+static int drawfilledbox(boxedstruct *boxed, int wire)
 {   
    /* draws texture filled box, 
       top is drawn using the entire texture, 
       the sides are drawn using the edge of the texture
     */
+   int polys = 0;
    
    /* front */
-   glBegin(GL_QUADS);
+   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
    glTexCoord2f(0,1);
    glVertex3f(-1.0,1.0,1.0);
    glTexCoord2f(1,1);
@@ -641,6 +710,7 @@ static void drawfilledbox(boxedstruct *boxed)
    glVertex3f(1.0,-1.0,1.0);
    glTexCoord2f(0,1);
    glVertex3f(-1.0,-1.0,1.0);
+   polys++;
    /* rear */
    glTexCoord2f(0,1);
    glVertex3f(1.0,1.0,-1.0);
@@ -650,6 +720,7 @@ static void drawfilledbox(boxedstruct *boxed)
    glVertex3f(-1.0,-1.0,-1.0);
    glTexCoord2f(0,1);
    glVertex3f(1.0,-1.0,-1.0);
+   polys++;
    /* left */
    glTexCoord2f(1,1);
    glVertex3f(-1.0,1.0,1.0);
@@ -659,6 +730,7 @@ static void drawfilledbox(boxedstruct *boxed)
    glVertex3f(-1.0,-1.0,-1.0);
    glTexCoord2f(0,1);
    glVertex3f(-1.0,1.0,-1.0);
+   polys++;
    /* right */
    glTexCoord2f(0,1);
    glVertex3f(1.0,1.0,1.0);
@@ -668,6 +740,7 @@ static void drawfilledbox(boxedstruct *boxed)
    glVertex3f(1.0,-1.0,-1.0);
    glTexCoord2f(0,1);
    glVertex3f(1.0,-1.0,1.0);
+   polys++;
    /* top */
    glTexCoord2f(0.0,0.0);
    glVertex3f(-1.0,1.0,1.0);
@@ -677,6 +750,7 @@ static void drawfilledbox(boxedstruct *boxed)
    glVertex3f(1.0,1.0,-1.0);
    glTexCoord2f(1.0,0.0);
    glVertex3f(1.0,1.0,1.0);
+   polys++;
    /* bottom */
    glTexCoord2f(0,0);
    glVertex3f(-1.0,-1.0,1.0);
@@ -686,42 +760,47 @@ static void drawfilledbox(boxedstruct *boxed)
    glVertex3f(1.0,-1.0,-1.0);
    glTexCoord2f(1,0);
    glVertex3f(1.0,-1.0,1.0);
+   polys++;
    glEnd();
+
+   return polys;
 }
 
 
 /*
  * Draw a box made of lines
  */ 
-static void drawbox(boxedstruct *boxed)
+static int drawbox(boxedstruct *boxed)
 {
+   int polys = 0;
    /* top */
    glBegin(GL_LINE_STRIP);
    glVertex3f(-1.0,1.0,1.0);
-   glVertex3f(-1.0,1.0,-1.0);
-   glVertex3f(1.0,1.0,-1.0);
-   glVertex3f(1.0,1.0,1.0);
-   glVertex3f(-1.0,1.0,1.0);
+   glVertex3f(-1.0,1.0,-1.0); polys++;
+   glVertex3f(1.0,1.0,-1.0); polys++;
+   glVertex3f(1.0,1.0,1.0); polys++;
+   glVertex3f(-1.0,1.0,1.0); polys++;
    glEnd();
    /* bottom */
    glBegin(GL_LINE_STRIP);
    glVertex3f(-1.0,-1.0,1.0);
-   glVertex3f(1.0,-1.0,1.0);
-   glVertex3f(1.0,-1.0,-1.0);
-   glVertex3f(-1.0,-1.0,-1.0);
-   glVertex3f(-1.0,-1.0,1.0);
+   glVertex3f(1.0,-1.0,1.0); polys++;
+   glVertex3f(1.0,-1.0,-1.0); polys++;
+   glVertex3f(-1.0,-1.0,-1.0); polys++;
+   glVertex3f(-1.0,-1.0,1.0); polys++;
    glEnd();
    /* connect top & bottom */
    glBegin(GL_LINES);
    glVertex3f(-1.0,1.0,1.0);
-   glVertex3f(-1.0,-1.0,1.0);
+   glVertex3f(-1.0,-1.0,1.0); polys++;
    glVertex3f(1.0,1.0,1.0);
-   glVertex3f(1.0,-1.0,1.0);
+   glVertex3f(1.0,-1.0,1.0); polys++;
    glVertex3f(1.0,1.0,-1.0);
-   glVertex3f(1.0,-1.0,-1.0);
+   glVertex3f(1.0,-1.0,-1.0); polys++;
    glVertex3f(-1.0,1.0,-1.0);
-   glVertex3f(-1.0,-1.0,-1.0);
+   glVertex3f(-1.0,-1.0,-1.0); polys++;
    glEnd();
+   return polys;
 }
 
 
@@ -729,8 +808,9 @@ static void drawbox(boxedstruct *boxed)
 /* 
  * Draw ball
  */
-static void drawball(boxedstruct *gp, ball *b)
+static int drawball(boxedstruct *gp, ball *b, int wire)
 {
+   int polys = 0;
    int i,pos,cnt;
    GLint *spherei = gp->spherei;
    vectorf *spherev = gp->spherev;
@@ -752,35 +832,62 @@ static void drawball(boxedstruct *gp, ball *b)
 
    if (!gp->gllists[GLL_BALL]) {
       glNewList(gp->listobjects + GLL_BALL,GL_COMPILE);
+      glBegin(wire ? GL_LINES : GL_TRIANGLES);
       cnt = SPHERE_INDICES/3;
       for (i=0; i<cnt; i++) {
         pos = i * 3;
-        glBegin(GL_TRIANGLES);
         glNormal3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
         glVertex3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
         glNormal3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
+         gp->list_polys[GLL_BALL]++;
         glVertex3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
+        if (wire)
+           glVertex3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
         glNormal3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
         glVertex3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
-        glEnd();
+         gp->list_polys[GLL_BALL]++;
       }
+      glEnd();
       glEndList();
       gp->gllists[GLL_BALL] = 1;
    } else {
       glCallList(gp->listobjects + GLL_BALL);
+      polys += gp->list_polys[GLL_BALL];
    }
    
    glPopMatrix();
+   return polys;
+}
+
+
+/*
+ * Draw a single triangle
+ */
+static void drawtri(triman *t, int wire, int i)
+{
+   const vectorf *spherev = t->vertices + i*3;
+   const vectorf *loc = &t->tris[i].loc;
+
+   glNormal3f(t->normals[i].x,t->normals[i].y,t->normals[i].z);
+   glVertex3f(spherev[0].x+loc->x,spherev[0].y+loc->y,spherev[0].z+loc->z);
+   glVertex3f(spherev[1].x+loc->x,spherev[1].y+loc->y,spherev[1].z+loc->z);
+   if (wire)
+      glVertex3f(spherev[1].x+loc->x,spherev[1].y+loc->y,spherev[1].z+loc->z);
+   glVertex3f(spherev[2].x+loc->x,spherev[2].y+loc->y,spherev[2].z+loc->z);
+   if (wire) {
+      glVertex3f(spherev[2].x+loc->x,spherev[2].y+loc->y,spherev[2].z+loc->z);
+      glVertex3f(spherev[0].x+loc->x,spherev[0].y+loc->y,spherev[0].z+loc->z);
+  }
 }
 
     
 /* 
  * Draw all triangles in triman
  */
-static void drawtriman(triman *t
+static int drawtriman(triman *t, int wire
 {
-   int i,pos;
-   vectorf *spherev = t->vertices;
+   int polys = 0;
+   int i;
    GLfloat col[3];
    
    glPushMatrix();
@@ -793,76 +900,103 @@ static void drawtriman(triman *t)
    col[1] *= 0.3;
    col[2] *= 0.3;
    glMaterialfv(GL_FRONT, GL_EMISSION,col);
+   glBegin(wire ? GL_LINES : GL_TRIANGLES);
    
    for (i=0; i<t->num_tri; i++) {
-      pos = i*3;
-      glPushMatrix();
-      glTranslatef(t->tris[i].loc.x,t->tris[i].loc.y,t->tris[i].loc.z);
-      glBegin(GL_TRIANGLES);
-      glNormal3f(t->normals[i].x,t->normals[i].y,t->normals[i].z);
-      glVertex3f(spherev[pos+0].x,spherev[pos+0].y,spherev[pos+0].z);
-      glVertex3f(spherev[pos+1].x,spherev[pos+1].y,spherev[pos+1].z);
-      glVertex3f(spherev[pos+2].x,spherev[pos+2].y,spherev[pos+2].z);
-      glEnd();
-      glPopMatrix();
-   }   
-   glPopMatrix();   
+      if (t->tris[i].gone > 3) { continue; }
+      if (t->tris[i].gone > 0) {
+         glColor3f(t->color.x,t->color.y,t->color.z);
+         col[0] = 1.0f;
+         col[1] = 1.0f;
+         col[2] = 1.0f;
+         glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
+         col[0] *= 0.8;
+         col[1] *= 0.8;
+         col[2] *= 0.8;
+         glMaterialfv(GL_FRONT, GL_EMISSION,col);
+
+         drawtri(t, wire, i);
+         polys++;
+
+         glColor3f(t->color.x,t->color.y,t->color.z);
+         col[0] = t->color.x;
+         col[1] = t->color.y;
+         col[2] = t->color.z;
+         glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
+         col[0] *= 0.3;
+         col[1] *= 0.3;
+         col[2] *= 0.3;
+         glMaterialfv(GL_FRONT, GL_EMISSION,col);
+
+         t->tris[i].gone++;
+         continue;
+      }
+
+      drawtri(t, wire, i);
+      polys++;
+   }
+   glEnd();
+   glPopMatrix();
+   return polys;
 }
       
 /* 
  * draw floor pattern
  */   
-static void drawpattern(boxedstruct *boxed)
+static int drawpattern(boxedstruct *gp)
 {
-   if (!boxed->gllists[GLL_PATTERN]) {
-      glNewList(boxed->listobjects + GLL_PATTERN, GL_COMPILE);
+   int polys = 0;
+   if (!gp->gllists[GLL_PATTERN]) {
+      glNewList(gp->listobjects + GLL_PATTERN, GL_COMPILE);
      
       glBegin(GL_LINE_STRIP);
       glVertex3f(-25.0f, 0.0f, 35.0f);
-      glVertex3f(-15.0f, 0.0f, 35.0f);
-      glVertex3f(-5.0f, 0.0f, 25.0f);
-      glVertex3f(5.0f, 0.0f, 25.0f);
-      glVertex3f(15.0f, 0.0f, 35.0f);
-      glVertex3f(25.0f, 0.0f, 35.0f);
-      glVertex3f(35.0f, 0.0f, 25.0f);
-      glVertex3f(35.0f, 0.0f, 15.0f);
-      glVertex3f(25.0f, 0.0f, 5.0f);
-      glVertex3f(25.0f, 0.0f, -5.0f);
-      glVertex3f(35.0f, 0.0f, -15.0f);
-      glVertex3f(35.0f, 0.0f, -25.0f);
-      glVertex3f(25.0f, 0.0f, -35.0f);
-      glVertex3f(15.0f, 0.0f,-35.0f);
-      glVertex3f(5.0f, 0.0f, -25.0f);
-      glVertex3f(-5.0f, 0.0f, -25.0f);
-      glVertex3f(-15.0f, 0.0f,-35.0f);
-      glVertex3f(-25.0f, 0.0f,-35.0f);
-      glVertex3f(-35.0f, 0.0f, -25.0f);
-      glVertex3f(-35.0f, 0.0f, -15.0f);
-      glVertex3f(-25.0f, 0.0f, -5.0f);
-      glVertex3f(-25.0f, 0.0f, 5.0f);
-      glVertex3f(-35.0f, 0.0f, 15.0f);
-      glVertex3f(-35.0f, 0.0f, 25.0f);
-      glVertex3f(-25.0f, 0.0f, 35.0f);
+      glVertex3f(-15.0f, 0.0f, 35.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-5.0f, 0.0f, 25.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(5.0f, 0.0f, 25.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(15.0f, 0.0f, 35.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(25.0f, 0.0f, 35.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(35.0f, 0.0f, 25.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(35.0f, 0.0f, 15.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(25.0f, 0.0f, 5.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(25.0f, 0.0f, -5.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(35.0f, 0.0f, -15.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(35.0f, 0.0f, -25.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(25.0f, 0.0f, -35.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(15.0f, 0.0f,-35.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(5.0f, 0.0f, -25.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-5.0f, 0.0f, -25.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-15.0f, 0.0f,-35.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-25.0f, 0.0f,-35.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-35.0f, 0.0f, -25.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-35.0f, 0.0f, -15.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-25.0f, 0.0f, -5.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-25.0f, 0.0f, 5.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-35.0f, 0.0f, 15.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-35.0f, 0.0f, 25.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-25.0f, 0.0f, 35.0f); gp->list_polys[GLL_PATTERN]++;
       glEnd();
       
       glBegin(GL_LINE_STRIP);
       glVertex3f(-5.0f, 0.0f, 15.0f);
-      glVertex3f(5.0f, 0.0f, 15.0f);
-      glVertex3f(15.0f, 0.0f, 5.0f);
-      glVertex3f(15.0f, 0.0f, -5.0f);
-      glVertex3f(5.0f, 0.0f, -15.0f);
-      glVertex3f(-5.0f, 0.0f, -15.0f);
-      glVertex3f(-15.0f, 0.0f, -5.0f);
-      glVertex3f(-15.0f, 0.0f, 5.0f);
-      glVertex3f(-5.0f, 0.0f, 15.0f);
+      glVertex3f(5.0f, 0.0f, 15.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(15.0f, 0.0f, 5.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(15.0f, 0.0f, -5.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(5.0f, 0.0f, -15.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-5.0f, 0.0f, -15.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-15.0f, 0.0f, -5.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-15.0f, 0.0f, 5.0f); gp->list_polys[GLL_PATTERN]++;
+      glVertex3f(-5.0f, 0.0f, 15.0f); gp->list_polys[GLL_PATTERN]++;
       glEnd();
 
       glEndList();
-      boxed->gllists[GLL_PATTERN] = 1;
+      gp->gllists[GLL_PATTERN] = 1;
    } else {
-      glCallList(boxed->listobjects + GLL_PATTERN);
-   }   
+      glCallList(gp->listobjects + GLL_PATTERN);
+      polys += gp->list_polys[GLL_PATTERN];
+   }
 
+   return polys;
 }
       
       
@@ -872,8 +1006,9 @@ static void drawpattern(boxedstruct *boxed)
 static void draw(ModeInfo * mi)
 {
    boxedstruct *gp = &boxed[MI_SCREEN(mi)];
-   vectorf v1;
-   GLfloat dcam;
+   int wire = MI_IS_WIREFRAME (mi);
+   vectorf v1,v2;
+   GLfloat r;
    int dx, dz;
    int i;   
    
@@ -890,35 +1025,55 @@ static void draw(ModeInfo * mi)
    GLfloat l1_diffuse[] =    {0.5, 0.5, 0.5, 1.0};
    GLfloat l1_position[] =  {0.0, 1.0, 0.0, 0.0}; /* w = 0 -> directional light */
    
+   mi->polygon_count = 0;
+
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    
-   gp->tic += 0.01f;
+# ifdef HAVE_MOBILE    /* Keep it the same relative size when rotated. */
+  {
+    GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
+    int o = (int) current_device_rotation();
+    if (o != 0 && o != 180 && o != -180)
+      glScalef (1/h, 1/h, 1/h);
+    glRotatef(o, 0, 0, 1);
+  }
+# endif
 
+   gp->tic += 0.01f;
+   gp->camtic += 0.01f + 0.01f * sin(gp->tic * speed);
+   
    /* rotate camera around (0,0,0), looking at (0,0,0), up is (0,1,0) */
-   dcam = CAMDISTANCE_MIN + (CAMDISTANCE_MAX - CAMDISTANCE_MIN) + (CAMDISTANCE_MAX - CAMDISTANCE_MIN)*cos(gp->tic/CAMDISTANCE_SPEED);
-   v1.x = dcam * sin(gp->tic/gp->cam_x_speed);
-   v1.z = dcam * cos(gp->tic/gp->cam_z_speed);
-   v1.y = CAM_HEIGHT * sin(gp->tic/gp->cam_y_speed) + 1.02 * CAM_HEIGHT;
-   gluLookAt(v1.x,v1.y,v1.z,0.0,0.0,0.0,0.0,1.0,0.0); 
-
-   glLightfv(GL_LIGHT0, GL_AMBIENT, l0_ambient); 
-   glLightfv(GL_LIGHT0, GL_DIFFUSE, l0_diffuse); 
-   glLightfv(GL_LIGHT0, GL_SPECULAR, l0_specular); 
-   glLightfv(GL_LIGHT0, GL_POSITION, l0_position);
-   glLightfv(GL_LIGHT1, GL_AMBIENT, l1_ambient); 
-   glLightfv(GL_LIGHT1, GL_DIFFUSE, l1_diffuse); 
-   glLightfv(GL_LIGHT1, GL_SPECULAR, l1_specular); 
-   glLightfv(GL_LIGHT1, GL_POSITION, l1_position);
-   glEnable(GL_LIGHT0);
-   glEnable(GL_LIGHT1);
+   r = CAMDISTANCE_MIN + (CAMDISTANCE_MAX - CAMDISTANCE_MIN) + (CAMDISTANCE_MAX - CAMDISTANCE_MIN)*cos((gp->camtic/CAMDISTANCE_SPEED) * speed);
+   v1.x = r * sin((gp->camtic/gp->cam_x_speed) * speed);
+   v1.z = r * cos((gp->camtic/gp->cam_x_speed) * speed);
+   v1.y = CAM_HEIGHT * sin((gp->camtic/gp->cam_y_speed) * speed) + 1.02 * CAM_HEIGHT;
+
+   v2.x = LOOKAT_R * sin((gp->camtic/(gp->cam_x_speed * 5.0f)) * speed);
+   v2.z = LOOKAT_R * cos((gp->camtic/(gp->cam_x_speed * 5.0f)) * speed);
+   v2.y = (CAM_HEIGHT * sin((gp->camtic/gp->cam_y_speed) * speed) + 1.02 * CAM_HEIGHT)/10.0;
+
+   gluLookAt(v1.x,v1.y,v1.z,v2.x,v2.y,v2.x,0.0,1.0,0.0); 
+
+   if (!wire) {
+     glLightfv(GL_LIGHT0, GL_AMBIENT, l0_ambient); 
+     glLightfv(GL_LIGHT0, GL_DIFFUSE, l0_diffuse); 
+     glLightfv(GL_LIGHT0, GL_SPECULAR, l0_specular); 
+     glLightfv(GL_LIGHT0, GL_POSITION, l0_position);
+     glLightfv(GL_LIGHT1, GL_AMBIENT, l1_ambient); 
+     glLightfv(GL_LIGHT1, GL_DIFFUSE, l1_diffuse); 
+     glLightfv(GL_LIGHT1, GL_SPECULAR, l1_specular); 
+     glLightfv(GL_LIGHT1, GL_POSITION, l1_position);
+     glEnable(GL_LIGHT0);
+     glEnable(GL_LIGHT1);
    
-   glFrontFace(GL_CW);
+     glFrontFace(GL_CW);
    
-   glMaterialfv(GL_FRONT, GL_SPECULAR, black);
-   glMaterialfv(GL_FRONT, GL_EMISSION, lblue);
-   glMaterialfv(GL_FRONT,GL_AMBIENT,black);
-   glMaterialf(GL_FRONT, GL_SHININESS, 5.0);
+     glMaterialfv(GL_FRONT, GL_SPECULAR, black);
+     glMaterialfv(GL_FRONT, GL_EMISSION, lblue);
+     glMaterialfv(GL_FRONT,GL_AMBIENT,black);
+     glMaterialf(GL_FRONT, GL_SHININESS, 5.0);
+   }
    
    
    /* draw ground grid */
@@ -937,12 +1092,12 @@ static void draw(ModeInfo * mi)
    
    /* Set drawing mode for the boxes */
    glEnable(GL_DEPTH_TEST);
-   glEnable(GL_TEXTURE_2D);
+   if (!wire) glEnable(GL_TEXTURE_2D);
    glPushMatrix();
    glColor3f(1.0,1.0,1.0);
    glScalef(20.0,0.25,20.0);
    glTranslatef(0.0,2.0,0.0);
-   drawfilledbox(gp);
+   mi->polygon_count += drawfilledbox(gp, wire);
    glPopMatrix();
    glDisable(GL_TEXTURE_2D);
 
@@ -950,34 +1105,36 @@ static void draw(ModeInfo * mi)
    glColor3f(0.2,0.5,0.2);
    glScalef(20.0,20.0,0.25);
    glTranslatef(0.0,1.0,81.0);
-   drawbox(gp);
+   mi->polygon_count += drawbox(gp);
    glPopMatrix();
 
    glPushMatrix();
    glColor3f(0.2,0.5,0.2);
    glScalef(20.0,20.0,0.25);
    glTranslatef(0.0,1.0,-81.0);
-   drawbox(gp);
+   mi->polygon_count += drawbox(gp);
    glPopMatrix();
 
    glPushMatrix();
    glColor3f(0.2,0.5,0.2);
    glScalef(.25,20.0,20.0);
    glTranslatef(-81.0,1.0,0.0);
-   drawbox(gp);
+   mi->polygon_count += drawbox(gp);
    glPopMatrix();
 
    glPushMatrix();
    glColor3f(0.2,0.5,0.2);
    glScalef(.25,20.0,20.0);
    glTranslatef(81.0,1.0,0.0);
-   drawbox(gp);
+   mi->polygon_count += drawbox(gp);
    glPopMatrix();
 
-   glEnable(GL_LIGHTING);
+   if (!wire) {
+     glEnable(GL_LIGHTING);
    
-   glMaterialfv(GL_FRONT, GL_DIFFUSE, dgray);
-   glMaterialfv(GL_FRONT, GL_EMISSION, black); /* turn it off before painting the balls */
+     glMaterialfv(GL_FRONT, GL_DIFFUSE, dgray);
+     glMaterialfv(GL_FRONT, GL_EMISSION, black); /* turn it off before painting the balls */
+   }
 
    /* move the balls and shrapnel */
    updateballs(&gp->bman);
@@ -995,10 +1152,10 @@ static void draw(ModeInfo * mi)
            updatetris(&gp->tman[i]);
         }
         glDisable(GL_CULL_FACE);
-        drawtriman(&gp->tman[i]);
-        glEnable(GL_CULL_FACE);
+        mi->polygon_count += drawtriman(&gp->tman[i], wire);
+        if (!wire) glEnable(GL_CULL_FACE);
       } else {
-        drawball(gp, &gp->bman.balls[i]);
+         mi->polygon_count += drawball(gp, &gp->bman.balls[i], wire);
       }
    }
       
@@ -1010,7 +1167,7 @@ static void draw(ModeInfo * mi)
 /* 
  * new window size or exposure 
  */
-void reshape_boxed(ModeInfo *mi, int width, int height)
+ENTRYPOINT void reshape_boxed(ModeInfo *mi, int width, int height)
 {
    GLfloat     h = (GLfloat) height / (GLfloat) width;
    
@@ -1029,6 +1186,7 @@ static void
 pinit(ModeInfo * mi)
 {
    boxedstruct *gp = &boxed[MI_SCREEN(mi)];
+   int wire = MI_IS_WIREFRAME (mi);
    ballman *bman;
    int i,texpixels;
    char *texpixeldata;
@@ -1036,11 +1194,14 @@ pinit(ModeInfo * mi)
 
    glShadeModel(GL_SMOOTH);
    glClearDepth(1.0);
-   glClearColor(0.0,0.05,0.1,0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    /* Load configuration */
    setdefaultconfig(&gp->config);
+
+   /* give the decay parameter a better curve */
+   if (gp->config.decay <= 0.8182) { gp->config.decay = gp->config.decay / 3; }
+   else                            { gp->config.decay = (gp->config.decay - 0.75) * 4; }
    
    bman = &gp->bman;
    
@@ -1054,6 +1215,8 @@ pinit(ModeInfo * mi)
    
    for(i=0;i<bman->num_balls;i++) {
       gp->tman[i].explosion = (float) (((int)gp->config.explosion) / 15.0f );
+      gp->tman[i].decay = gp->config.decay;
+      gp->tman[i].momentum = gp->config.momentum;
       gp->tman[i].vertices = NULL;
       gp->tman[i].normals = NULL;
       gp->tman[i].tris = NULL;
@@ -1061,10 +1224,12 @@ pinit(ModeInfo * mi)
       bman->balls[i].loc.y *= rnd();
    }
 
-   generatesphere();
+   generatesphere(gp);
    
-   glEnable(GL_CULL_FACE);
-   glEnable(GL_LIGHTING);
+   if (!wire) {
+     glEnable(GL_CULL_FACE);
+     glEnable(GL_LIGHTING);
+   }
 
    /* define cam path */
    gp->cam_x_speed = 1.0f/((float)gp->config.camspeed/50.0 + rnd()*((float)gp->config.camspeed/50.0));
@@ -1072,8 +1237,11 @@ pinit(ModeInfo * mi)
    gp->cam_y_speed = 1.0f/((float)gp->config.camspeed/250.0 + rnd()*((float)gp->config.camspeed/250.0));
    if (rnd() < 0.5f) gp->cam_x_speed = -gp->cam_x_speed;
    if (rnd() < 0.5f) gp->cam_z_speed = -gp->cam_z_speed;
+
+   /* define initial cam position */
+   gp->tic = gp->camtic = rnd() * 100.0f;
    
-   
+   /* define tex1 (bottom plate) */
    gp->tex1 = (char *)malloc(3*width*height*sizeof(GLuint));
    texpixels = 256*256; /*width*height;*/
    texpixeldata = header_data;
@@ -1087,6 +1255,7 @@ pinit(ModeInfo * mi)
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
    clear_gl_error();
+#if 0
    i = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 256, 256,
                          GL_RGB, GL_UNSIGNED_BYTE, gp->tex1);
    if (i)
@@ -1097,6 +1266,12 @@ pinit(ModeInfo * mi)
        exit (1);
      }
    check_gl_error("mipmapping");
+#else
+   glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0,
+                      GL_RGB, GL_UNSIGNED_BYTE,
+                 gp->tex1);
+   check_gl_error("texture");
+#endif
 
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
@@ -1108,7 +1283,9 @@ pinit(ModeInfo * mi)
 
  
 
-void
+static void free_boxed(ModeInfo * mi);
+
+ENTRYPOINT void
 init_boxed(ModeInfo * mi)
 {
    int screen = MI_SCREEN(mi);
@@ -1117,9 +1294,7 @@ init_boxed(ModeInfo * mi)
    /* Boolean     rgba, doublebuffer, cmap_installed; */
    boxedstruct *gp;
 
-   if (boxed == NULL) {
-      if ((boxed = (boxedstruct *) calloc(MI_NUM_SCREENS(mi),sizeof (boxedstruct))) == NULL) return;
-   }
+   MI_INIT(mi, boxed, free_boxed);
    gp = &boxed[screen];
    gp->window = MI_WINDOW(mi);
    
@@ -1139,7 +1314,7 @@ init_boxed(ModeInfo * mi)
 }
 
 
-void
+ENTRYPOINT void
 draw_boxed(ModeInfo * mi)
 {
    boxedstruct *gp = &boxed[MI_SCREEN(mi)];
@@ -1159,41 +1334,33 @@ draw_boxed(ModeInfo * mi)
    glXSwapBuffers(display, window);
 }
 
-void
-release_boxed(ModeInfo * mi)
+ENTRYPOINT void
+free_boxed(ModeInfo * mi)
 {
+   boxedstruct *gp = &boxed[MI_SCREEN(mi)];
    int i;
+
+   if (gp->glx_context) {
+      /* Display lists MUST be freed while their glXContext is current. */
+      glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
    
-   if (boxed != NULL) {
-      int screen;
-      
-      for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
-        boxedstruct *gp = &boxed[screen];
-        
-        if (gp->glx_context) {
-           /* Display lists MUST be freed while their glXContext is current. */
-           glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
-           
-           if (glIsList(gp->listobjects))
-             glDeleteLists(gp->listobjects, 3);
-           
-           for (i=0;i<gp->bman.num_balls;i++) {
-              if (gp->bman.balls[i].bounced) freetris(&gp->tman[i]);
-           }
-           free (gp->bman.balls);
-           free (gp->tman);
-           free (gp->tex1);
-                
-           
-        }
+      if (glIsList(gp->listobjects))
+        glDeleteLists(gp->listobjects, 3);
+
+      for (i=0;i<gp->bman.num_balls;i++) {
+         if (gp->bman.balls[i].bounced) freetris(&gp->tman[i]);
       }
-      (void) free((void *) boxed);
-      boxed = NULL;
+      free (gp->bman.balls);
+      free (gp->tman);
+      free (gp->tex1);
+
+
    }
-   FreeAllGL(mi);
 }
 
 
+XSCREENSAVER_MODULE ("Boxed", boxed)
+
 /*********************************************************/
 
 #endif