From http://www.jwz.org/xscreensaver/xscreensaver-5.18.tar.gz
[xscreensaver] / hacks / glx / lament.c
index b100a9ce8bf909089c101501bc38f0ba5a09fe4a..ab4bf83e1109ca7d472c34538b13459a8202f401 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1998 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1998-2012 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
         "gold" to me.
 
      *  For some reason, the interior surfaces are shinier than the exterior
-        surfaces.  I don't understand why, but this should be remedied.
+        surfaces.  Not sure why.
 
-     *  Perhaps use a slightly-bumpy or oily texture for the interior surfaces?
+     *  Should use a dark wood-grain texture for the interior surfaces.
 
-     *  Some of the edges don't line up perfectly (since the images are not
-        perfectly symetrical.)  Something should be done about this; either
-        making the edges overlap slightly (instead of leaving gaps) or fixing
-        the images so that the edges may be symmetrical.
+     *  Building a face out of multiple adjacent triangles was a terrible
+        idea and leads to visible seams.  Should re-do the face generation
+        to make all of them out of a single triangle strip instead.
+
+     *  The coordinates are slightly off from the image.  lament512.gif is the
+        "right" one, and "lament512b.gif" is the image corrected to line up
+        with what the code is actually doing.
+
+     *  The "star" slices really don't line up well.
 
      *  I want the gold leaf to seem to be raised up from the surface, but I
         think this isn't possible with OpenGL.  Supposedly, OpenGL only 
         and shading smoothly) but bump-maps only work with Phong shading
         (computing a normal for each rendered pixel.)
 
-     *  As far as I can tell, OpenGL doesn't do shadows.  As a result, the
-        forward-facing interior walls are drawn bright, not dark.  If it was
-        casting shadows properly, it wouldn't matter so much that the edges
-        don't quite line up, because the lines would be black, and thus not
-        visible.  But the edges don't match up, and so the bright interior
-        faces show through, and that sucks.
-
-       But apparently there are tricky ways around this:
-       http://reality.sgi.com/opengl/tips/rts/
-       I think these techniques require GLUT, however, which isn't 
-       (currently) required by any other xscreensaver hacks.
-
      *  There should be strange lighting effects playing across the surface:
         electric sparks, or little glittery blobs of light.  
         http://reality.sgi.com/opengl/tips/lensflare/ might provide guidance.
         to use (or that look like they would take any less than several months
         to become even marginally proficient with...)
 
-     *  Perhaps there should be a table top, on which it casts a shadow?
-        And then multiple light sources (for multiple shadows)?
-
      *  Needs music.  ("Hellraiser Themes" by Coil: TORSO CD161; also
         duplicated on the "Unnatural History 2" compilation, WORLN M04699.)
  */
 
-#include <X11/Intrinsic.h>
-
-#define PROGCLASS      "Lament"
-#define HACK_INIT      init_lament
-#define HACK_DRAW      draw_lament
-#define HACK_RESHAPE   reshape_lament
-#define HACK_HANDLE_EVENT lament_handle_event
-#define EVENT_MASK     PointerMotionMask
-#define lament_opts    xlockmore_opts
-#define DEFAULTS       "*delay:        10000   \n"     \
+#define DEFAULTS       "*delay:        20000   \n"     \
                        "*showFPS:      False   \n"     \
-                       "*wireframe:    False   \n"     \
-                       "*texture:      True    \n"
+                       "*wireframe:    False   \n"
+# define refresh_lament 0
+# define release_lament 0
 #include "xlockmore.h"
 
 #ifdef USE_GL /* whole file */
 #define DEF_TEXTURE "True"
 
 static int do_texture;
+
 static XrmOptionDescRec opts[] = {
-  {"-texture", ".lament.texture", XrmoptionNoArg, (caddr_t) "true" },
-  {"+texture", ".lament.texture", XrmoptionNoArg, (caddr_t) "false" },
+  {"-texture", ".lament.texture", XrmoptionNoArg, "true" },
+  {"+texture", ".lament.texture", XrmoptionNoArg, "false" },
 };
 
 static argtype vars[] = {
-  {(caddr_t *) &do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
+  {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
 };
 
-ModeSpecOpt lament_opts = {countof(opts), opts, countof(vars), vars, NULL};
+ENTRYPOINT ModeSpecOpt lament_opts = {countof(opts), opts, countof(vars), vars, NULL};
 
+#include "normals.h"
 #include "xpm-ximage.h"
 #include "rotator.h"
 #include "gltrackball.h"
-#include "../images/lament.xpm"
+#if 0
+# include "../images/lament128.xpm"
+#else
+# include "../images/lament512.xpm"
+#endif
 
 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
 #define RANDSIGN() ((random() & 1) ? 1 : -1)
@@ -137,16 +125,18 @@ typedef enum {
 
 } lament_type;
 
-static GLfloat exterior_color[] = { 0.33, 0.22, 0.03, 1.00,  /* ambient    */
-                                    0.78, 0.57, 0.11, 1.00,  /* specular   */
-                                    0.99, 0.91, 0.81, 1.00,  /* diffuse    */
-                                   27.80                     /* shininess  */
-                                  };
-static GLfloat interior_color[] = { 0.20, 0.20, 0.15, 1.00,  /* ambient    */
-                                    0.40, 0.40, 0.32, 1.00,  /* specular   */
-                                    0.99, 0.99, 0.81, 1.00,  /* diffuse    */
-                                   50.80                     /* shininess  */
-                                  };
+static const GLfloat exterior_color[] =
+ { 0.33, 0.22, 0.03, 1.00,  /* ambient    */
+   0.78, 0.57, 0.11, 1.00,  /* specular   */
+   0.99, 0.91, 0.81, 1.00,  /* diffuse    */
+   27.80                   /* shininess  */
+ };
+static const GLfloat interior_color[] =
+ { 0.20, 0.20, 0.15, 1.00,  /* ambient    */
+   0.40, 0.40, 0.32, 1.00,  /* specular   */
+   0.99, 0.99, 0.81, 1.00,  /* diffuse    */
+   50.80                    /* shininess  */
+ };
 
 
 typedef struct {
@@ -168,6 +158,10 @@ typedef struct {
 
   int anim_pause;                 /* countdown before animating again */
   GLfloat anim_r, anim_y, anim_z;  /* relative position during anims */
+  Bool facing_p;
+
+  int state, nstates;
+  lament_type *states;
 
 } lament_configuration;
 
@@ -190,99 +184,12 @@ parse_image_data(ModeInfo *mi)
                               lament_faces);
 }
 
-\f
-/* Computing normal vectors (thanks to Nat Friedman <ndf@mit.edu>)
- */
-
-typedef struct vector {
-  GLfloat x, y, z;
-} vector;
-
-typedef struct plane {
-  vector p1, p2, p3;
-} plane;
-
-static void
-vector_set(vector *v, GLfloat x, GLfloat y, GLfloat z)
-{
-  v->x = x;
-  v->y = y;
-  v->z = z;
-}
-
-static void
-vector_cross(vector v1, vector v2, vector *v3)
-{
-  v3->x = (v1.y * v2.z) - (v1.z * v2.y);
-  v3->y = (v1.z * v2.x) - (v1.x * v2.z);
-  v3->z = (v1.x * v2.y) - (v1.y * v2.x);
-}
-
-static void
-vector_subtract(vector v1, vector v2, vector *res)
-{
-  res->x = v1.x - v2.x;
-  res->y = v1.y - v2.y;
-  res->z = v1.z - v2.z;
-}
-
-static void
-plane_normal(plane p, vector *n)
-{
-  vector v1, v2;
-  vector_subtract(p.p1, p.p2, &v1);
-  vector_subtract(p.p1, p.p3, &v2);
-  vector_cross(v2, v1, n);
-}
-
-static void
-do_normal(GLfloat x1, GLfloat y1, GLfloat z1,
-         GLfloat x2, GLfloat y2, GLfloat z2,
-         GLfloat x3, GLfloat y3, GLfloat z3)
-{
-  plane plane;
-  vector n;
-  vector_set(&plane.p1, x1, y1, z1);
-  vector_set(&plane.p2, x2, y2, z2);
-  vector_set(&plane.p3, x3, y3, z3);
-  plane_normal(plane, &n);
-  n.x = -n.x; n.y = -n.y; n.z = -n.z;
-
-  glNormal3f(n.x, n.y, n.z);
-
-#ifdef DEBUG
-  /* Draw a line in the direction of this face's normal. */
-  {
-    GLfloat ax = n.x > 0 ? n.x : -n.x;
-    GLfloat ay = n.y > 0 ? n.y : -n.y;
-    GLfloat az = n.z > 0 ? n.z : -n.z;
-    GLfloat mx = (x1 + x2 + x3) / 3;
-    GLfloat my = (y1 + y2 + y3) / 3;
-    GLfloat mz = (z1 + z2 + z3) / 3;
-    GLfloat xx, yy, zz;
-
-    GLfloat max = ax > ay ? ax : ay;
-    if (az > max) max = az;
-    max *= 2;
-    xx = n.x / max;
-    yy = n.y / max;
-    zz = n.z / max;
-
-    glBegin(GL_LINE_LOOP);
-    glVertex3f(mx, my, mz);
-    glVertex3f(mx+xx, my+yy, mz+zz);
-    glEnd();
-  }
-#endif /* DEBUG */
-}
-
-
 \f
 /* Shorthand utilities for making faces, with proper normals.
  */
 
 static void
-set_colors (GLfloat *color)
+set_colors (const GLfloat *color)
 {
   glMaterialfv(GL_FRONT, GL_AMBIENT, color+0);
   glMaterialfv(GL_FRONT, GL_DIFFUSE, color+4);
@@ -291,7 +198,7 @@ set_colors (GLfloat *color)
 }
 
 static void
-face3(GLint texture, GLfloat *color, Bool wire,
+face3(GLint texture, const GLfloat *color, Bool wire,
       GLfloat s1, GLfloat t1, GLfloat x1, GLfloat y1, GLfloat z1,
       GLfloat s2, GLfloat t2, GLfloat x2, GLfloat y2, GLfloat z2,
       GLfloat s3, GLfloat t3, GLfloat x3, GLfloat y3, GLfloat z3)
@@ -310,7 +217,7 @@ face3(GLint texture, GLfloat *color, Bool wire,
 }
 
 static void
-face4(GLint texture, GLfloat *color, Bool wire,
+face4(GLint texture, const GLfloat *color, Bool wire,
       GLfloat s1, GLfloat t1, GLfloat x1, GLfloat y1, GLfloat z1,
       GLfloat s2, GLfloat t2, GLfloat x2, GLfloat y2, GLfloat z2,
       GLfloat s3, GLfloat t3, GLfloat x3, GLfloat y3, GLfloat z3,
@@ -330,7 +237,7 @@ face4(GLint texture, GLfloat *color, Bool wire,
 }
 
 static void
-face5(GLint texture, GLfloat *color, Bool wire,
+face5(GLint texture, const GLfloat *color, Bool wire,
       GLfloat s1, GLfloat t1, GLfloat x1, GLfloat y1, GLfloat z1,
       GLfloat s2, GLfloat t2, GLfloat x2, GLfloat y2, GLfloat z2,
       GLfloat s3, GLfloat t3, GLfloat x3, GLfloat y3, GLfloat z3,
@@ -417,8 +324,8 @@ star(ModeInfo *mi, Bool top, Bool wire)
   int i;
 
   int points[][2] = {
-    {  77,  74 }, {  60,  98 }, {   0,  71 }, {   0,   0 },    /* L1 */
-    {  60,  98 }, {  55, 127 }, {   0, 127 }, {   0,  71 },    /* L2 */
+    {  77,  74 }, {  60,  99 }, {   0,  74 }, {   0,   0 },    /* L1 */
+    {  60,  99 }, {  55, 127 }, {   0, 127 }, {   0,  74 },    /* L2 */
     {  55, 127 }, {  60, 154 }, {   0, 179 }, {   0, 127 },    /* L3 */
     {  60, 154 }, {  76, 176 }, {   0, 255 }, {   0, 179 },    /* L4 */
     {  76, 176 }, { 100, 193 }, {  74, 255 }, {   0, 255 },    /* B1 */
@@ -1400,13 +1307,13 @@ taser(ModeInfo *mi, Bool wire)
 /* Rendering and animating object models
  */
 
-Bool
+ENTRYPOINT Bool
 lament_handle_event (ModeInfo *mi, XEvent *event)
 {
   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
 
   if (event->xany.type == ButtonPress &&
-      event->xbutton.button & Button1)
+      event->xbutton.button == Button1)
     {
       lc->button_down_p = True;
       gltrackball_start (lc->trackball,
@@ -1415,11 +1322,21 @@ lament_handle_event (ModeInfo *mi, XEvent *event)
       return True;
     }
   else if (event->xany.type == ButtonRelease &&
-           event->xbutton.button & Button1)
+           event->xbutton.button == Button1)
     {
       lc->button_down_p = False;
       return True;
     }
+  else if (event->xany.type == ButtonPress &&
+           (event->xbutton.button == Button4 ||
+            event->xbutton.button == Button5 ||
+            event->xbutton.button == Button6 ||
+            event->xbutton.button == Button7))
+    {
+      gltrackball_mousewheel (lc->trackball, event->xbutton.button, 5,
+                              !!event->xbutton.state);
+      return True;
+    }
   else if (event->xany.type == MotionNotify &&
            lc->button_down_p)
     {
@@ -1433,6 +1350,65 @@ lament_handle_event (ModeInfo *mi, XEvent *event)
 }
 
 
+static void
+check_facing(ModeInfo *mi)
+{
+  lament_configuration *lc = &lcs[MI_SCREEN(mi)];
+
+  GLdouble m[16], p[16], x, y, z;
+  GLint v[4];
+  glGetDoublev (GL_MODELVIEW_MATRIX, m);
+  glGetDoublev (GL_PROJECTION_MATRIX, p);
+  glGetIntegerv (GL_VIEWPORT, v);
+       
+  /* See if a coordinate 5 units in front of the door is near the
+     center of the screen. */
+
+  gluProject (-5, 0, 0, m, p, v, &x, &y, &z);
+  x = (x / MI_WIDTH(mi))  - 0.5;
+  y = (y / MI_HEIGHT(mi)) - 0.5;
+  lc->facing_p = (z < 0.9 &&
+                  x > -0.02 && x < 0.02 &&
+                  y > -0.02 && y < 0.02);
+}
+
+
+
+static void
+scale_for_window(ModeInfo *mi)
+{
+  lament_configuration *lc = &lcs[MI_SCREEN(mi)];
+  int target_size = lc->texture->width * 1.4;
+  int win_size = (MI_WIDTH(mi) > MI_HEIGHT(mi) ? MI_HEIGHT(mi) : MI_WIDTH(mi));
+
+  /* This scale makes the box take up most of the window */
+  glScalef(8, 8, 8);
+
+  /* But if the window is more than a little larger than our target size,
+     scale the object back down, so that the bits drawn on the screen end
+     up rougly target_size across (actually it ends up a little larger.)
+     Note that the image-map bits we have are 128x128.  Therefore, if the
+     image is magnified a lot, it looks pretty blocky.  So it's better to
+     have a 128x128 animation on a 1280x1024 screen that looks good, than
+     a 1024x1024 animation that looks really pixelated.
+   */
+
+  {
+    int max = 340;               /* Let's not go larger than life-sized. */
+    if (target_size > max)
+      target_size = max;
+  }
+
+  if (win_size > 640 &&
+      win_size > target_size * 1.5)
+    {
+      GLfloat ratio = ((GLfloat) target_size / (GLfloat) win_size);
+      ratio *= 2.0;
+      glScalef(ratio, ratio, ratio);
+    }
+}
+
+
 static void
 draw(ModeInfo *mi)
 {
@@ -1446,15 +1422,17 @@ draw(ModeInfo *mi)
 
   glPushMatrix();
 
+  /* Do it twice because we don't track the device's orientation. */
+  glRotatef( current_device_rotation(), 0, 0, 1);
   gltrackball_rotate (lc->trackball);
+  glRotatef(-current_device_rotation(), 0, 0, 1);
 
   /* Make into the screen be +Y right be +X, and up be +Z. */
   glRotatef(-90.0, 1.0, 0.0, 0.0);
 
-  /* Scale it up. */
-  glScalef(4.0, 4.0, 4.0);
+  scale_for_window (mi);
 
-#ifdef DEBUG
+#if 0
     glPushMatrix();
     {
       /* Shift to the upper left, and draw the vanilla box. */
@@ -1472,7 +1450,7 @@ draw(ModeInfo *mi)
 
     /* Shift to the lower right, and draw the animated object. */
     glTranslatef(0.6, 0.0, -0.6);
-#endif /* DEBUG */
+#endif /* 0 */
 
 
     glPushMatrix();
@@ -1485,6 +1463,8 @@ draw(ModeInfo *mi)
       glRotatef (lc->roty * 360, 0.0, 1.0, 0.0);
       glRotatef (lc->rotz * 360, 0.0, 0.0, 1.0);
 
+      check_facing(mi);
+
       switch (lc->type)
        {
        case LAMENT_BOX:
@@ -1597,6 +1577,25 @@ draw(ModeInfo *mi)
 }
 
 
+/* Rather than just picking states randomly, pick an ordering randomly, do it,
+   and then re-randomize.  That way one can be assured of seeing all states in
+   a short time period, though not always in the same order (it's frustrating
+   to see it pick the same state 5x in a row.)
+ */
+static void
+shuffle_states (lament_configuration *lc)
+{
+  int i;
+  for (i = 0; i < lc->nstates; i++)
+    {
+      int a = random() % lc->nstates;
+      lament_type swap = lc->states[a];
+      lc->states[a] = lc->states[i];
+      lc->states[i] = swap;
+    }
+}
+
+
 static void
 animate(ModeInfo *mi)
 {
@@ -1609,38 +1608,13 @@ animate(ModeInfo *mi)
     {
     case LAMENT_BOX:
       {
-       /* Rather than just picking states randomly, pick an ordering randomly,
-          do it, and then re-randomize.  That way one can be assured of seeing
-          all states in a short time period, though not always in the same
-          order (it's frustrating to see it pick the same state 5x in a row.)
-        */
-       static lament_type states[] = {
-         LAMENT_STAR_OUT, LAMENT_STAR_OUT,
-         LAMENT_TETRA_UNE, LAMENT_TETRA_USW,
-         LAMENT_TETRA_DWN, LAMENT_TETRA_DSE,
-         LAMENT_LID_OPEN, LAMENT_LID_OPEN, LAMENT_LID_OPEN,
-         LAMENT_TASER_OUT, LAMENT_TASER_OUT,
-         LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX,
-         LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX,
-       };
-       static int state = countof(states);
-
-       if (state < countof(states))
-         {
-           lc->type = states[state++];
-         }
-       else
-         {
-           int i;
-           state = 0;
-           for (i = 0; i < countof(states); i++)
-             {
-               int a = random() % countof(states);
-               lament_type swap = states[a];
-               states[a] = states[i];
-               states[i] = swap;
-             }
-         }
+        lc->state++;
+        if (lc->state >= lc->nstates)
+          {
+            shuffle_states (lc);
+            lc->state = 0;
+          }
+        lc->type = lc->states[lc->state];
 
        if (lc->type == LAMENT_BOX)
          lc->anim_pause = pause3;
@@ -1746,28 +1720,11 @@ animate(ModeInfo *mi)
 
       if (lc->anim_r >= 112.0)
        {
-         GLfloat hysteresis = 0.05;
-
          lc->anim_r = 112.0;
          lc->anim_z = 0.0;
          lc->anim_pause = pause3;
-
-         if (lc->rotx >= -hysteresis &&
-             lc->rotx <=  hysteresis &&
-             ((lc->rotz >=  (0.25 - hysteresis) &&
-               lc->rotz <=  (0.25 + hysteresis)) ||
-              (lc->rotz >= (-0.25 - hysteresis) &&
-               lc->rotz <= (-0.25 + hysteresis))))
-           {
-             lc->type = LAMENT_LID_ZOOM;
-             lc->rotx = 0.00;
-             lc->rotz = (lc->rotz < 0 ? -0.25 : 0.25);
-           }
-         else
-           {
-             lc->type = LAMENT_LID_CLOSE;
-           }
-       }
+          lc->type = (lc->facing_p ? LAMENT_LID_ZOOM : LAMENT_LID_CLOSE);
+        }
       break;
 
     case LAMENT_LID_CLOSE:
@@ -1843,45 +1800,18 @@ animate(ModeInfo *mi)
 /* Window management, etc
  */
 
-void
+ENTRYPOINT void
 reshape_lament(ModeInfo *mi, int width, int height)
 {
-  int target_size = 180;
-  int win_size = (width > height ? height : width);
   GLfloat h = (GLfloat) height / (GLfloat) width;
-
   glViewport(0, 0, (GLint) width, (GLint) height);
 
-/*  glViewport(-600, -600, 1800, 1800); */
-
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glTranslatef(0.0, 0.0, -40.0);
-
-  /* This scale makes the box take up most of the window */
-  glScalef(2.0, 2.0, 2.0);
-
-  /* But if the window is more than a little larger than our target size,
-     scale the object back down, so that the bits drawn on the screen end
-     up rougly target_size across (actually it ends up a little larger.)
-     Note that the image-map bits we have are 128x128.  Therefore, if the
-     image is magnified a lot, it looks pretty blocky.  So it's better to
-     have a 128x128 animation on a 1280x1024 screen that looks good, than
-     a 1024x1024 animation that looks really pixellated.
-   */
-  if (win_size > target_size * 1.5)
-    {
-      GLfloat ratio = ((GLfloat) target_size / (GLfloat) win_size);
-      ratio *= 2.0;
-      glScalef(ratio, ratio, ratio);
-    }
-
-  /* The depth buffer will be cleared, if needed, before the
-   * next frame.  Right now we just want to black the screen.
-   */
   glClear(GL_COLOR_BUFFER_BIT);
 }
 
@@ -1897,13 +1827,13 @@ gl_init(ModeInfo *mi)
 
   if (!wire)
     {
-      static GLfloat pos0[]  = { -4.0,  2.0, 5.0, 1.0 };
-      static GLfloat pos1[]  = {  6.0, -1.0, 3.0, 1.0 };
+      static const GLfloat pos0[]  = { -4.0,  2.0, 5.0, 1.0 };
+      static const GLfloat pos1[]  = {  6.0, -1.0, 3.0, 1.0 };
 
-      static GLfloat amb0[]  = { 0.7, 0.7, 0.7, 1.0 };
-/*    static GLfloat amb1[]  = { 0.7, 0.0, 0.0, 1.0 }; */
-      static GLfloat dif0[]  = { 1.0, 1.0, 1.0, 1.0 };
-      static GLfloat dif1[]  = { 0.3, 0.1, 0.1, 1.0 };
+      static const GLfloat amb0[]  = { 0.7, 0.7, 0.7, 1.0 };
+/*    static const GLfloat amb1[]  = { 0.7, 0.0, 0.0, 1.0 }; */
+      static const GLfloat dif0[]  = { 1.0, 1.0, 1.0, 1.0 };
+      static const GLfloat dif1[]  = { 0.3, 0.1, 0.1, 1.0 };
 
       glLightfv(GL_LIGHT0, GL_POSITION, pos0);
       glLightfv(GL_LIGHT1, GL_POSITION, pos1);
@@ -1934,7 +1864,8 @@ gl_init(ModeInfo *mi)
       parse_image_data(mi);
 
       glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-      glPixelStorei(GL_UNPACK_ROW_LENGTH, lc->texture->width);
+      /* messes up -fps */
+      /* glPixelStorei(GL_UNPACK_ROW_LENGTH, lc->texture->width); */
 
       for (i = 0; i < 6; i++)
        {
@@ -1945,7 +1876,9 @@ gl_init(ModeInfo *mi)
           clear_gl_error();
          glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                       lc->texture->width, height, 0,
-                      GL_RGBA, GL_UNSIGNED_BYTE,
+                      GL_RGBA,
+                       /* GL_UNSIGNED_BYTE, */
+                       GL_UNSIGNED_INT_8_8_8_8_REV,
                       (lc->texture->data +
                        (lc->texture->bytes_per_line * height * i)));
           check_gl_error("texture");
@@ -1954,8 +1887,6 @@ gl_init(ModeInfo *mi)
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-         glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-         glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
        }
 
 #else  /* !HAVE_GLBINDTEXTURE */
@@ -2034,7 +1965,7 @@ handle_signals (void)
 # endif /* HAVE_MESA_GL */
 
 
-void
+ENTRYPOINT void
 init_lament(ModeInfo *mi)
 {
   lament_configuration *lc;
@@ -2066,13 +1997,38 @@ init_lament(ModeInfo *mi)
       gl_init(mi);
     }
 
+  lc->states = (lament_type *) calloc (50, sizeof (*lc->states));
+  lc->nstates = 0;
+  lc->states[lc->nstates++] = LAMENT_STAR_OUT;
+  lc->states[lc->nstates++] = LAMENT_STAR_OUT;
+  lc->states[lc->nstates++] = LAMENT_TETRA_UNE;
+  lc->states[lc->nstates++] = LAMENT_TETRA_USW;
+  lc->states[lc->nstates++] = LAMENT_TETRA_DWN;
+  lc->states[lc->nstates++] = LAMENT_TETRA_DSE;
+  lc->states[lc->nstates++] = LAMENT_LID_OPEN;
+  lc->states[lc->nstates++] = LAMENT_LID_OPEN;
+  lc->states[lc->nstates++] = LAMENT_LID_OPEN;
+  lc->states[lc->nstates++] = LAMENT_TASER_OUT;
+  lc->states[lc->nstates++] = LAMENT_TASER_OUT;
+  lc->states[lc->nstates++] = LAMENT_BOX;
+  lc->states[lc->nstates++] = LAMENT_BOX;
+  lc->states[lc->nstates++] = LAMENT_BOX;
+  lc->states[lc->nstates++] = LAMENT_BOX;
+  lc->states[lc->nstates++] = LAMENT_BOX;
+  lc->states[lc->nstates++] = LAMENT_BOX;
+  lc->states[lc->nstates++] = LAMENT_BOX;
+  lc->states[lc->nstates++] = LAMENT_BOX;
+  lc->states[lc->nstates++] = LAMENT_BOX;
+  lc->states[lc->nstates++] = LAMENT_BOX;
+  shuffle_states (lc);
+
 # ifdef HAVE_MESA_GL
   handle_signals ();
 # endif /* HAVE_MESA_GL */
 }
 
 
-void
+ENTRYPOINT void
 draw_lament(ModeInfo *mi)
 {
   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
@@ -2097,4 +2053,6 @@ draw_lament(ModeInfo *mi)
     animate(mi);
 }
 
+XSCREENSAVER_MODULE ("Lament", lament)
+
 #endif /* USE_GL */