From http://www.jwz.org/xscreensaver/xscreensaver-5.29.tar.gz
[xscreensaver] / hacks / glx / lament.c
index 7c6f4b8a211ae6fa380b63d158107e1199627811..77cf156bdc1b060cf5c37cfab6e786e9f9b14815 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1998-2004 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1998-2014 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
  *
  * 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
         "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 
 
      *  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.)
 
         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.
      *  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.
@@ -62,9 +55,6 @@
         to use (or that look like they would take any less than several months
         to become even marginally proficient with...)
 
         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.)
  */
      *  Needs music.  ("Hellraiser Themes" by Coil: TORSO CD161; also
         duplicated on the "Unnatural History 2" compilation, WORLN M04699.)
  */
@@ -100,7 +90,17 @@ ENTRYPOINT ModeSpecOpt lament_opts = {countof(opts), opts, countof(vars), vars,
 #include "xpm-ximage.h"
 #include "rotator.h"
 #include "gltrackball.h"
 #include "xpm-ximage.h"
 #include "rotator.h"
 #include "gltrackball.h"
-#include "../images/lament.xpm"
+
+#ifdef __GNUC__
+ __extension__ /* don't warn about "string length is greater than the length
+                  ISO C89 compilers are required to support" when including
+                  the following XPM file... */
+#endif
+#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)
 
 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
 #define RANDSIGN() ((random() & 1) ? 1 : -1)
@@ -164,6 +164,7 @@ typedef struct {
 
   int anim_pause;                 /* countdown before animating again */
   GLfloat anim_r, anim_y, anim_z;  /* relative position during anims */
 
   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;
 
   int state, nstates;
   lament_type *states;
@@ -329,8 +330,8 @@ star(ModeInfo *mi, Bool top, Bool wire)
   int i;
 
   int points[][2] = {
   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 */
     {  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 */
@@ -1334,7 +1335,9 @@ lament_handle_event (ModeInfo *mi, XEvent *event)
     }
   else if (event->xany.type == ButtonPress &&
            (event->xbutton.button == Button4 ||
     }
   else if (event->xany.type == ButtonPress &&
            (event->xbutton.button == Button4 ||
-            event->xbutton.button == Button5))
+            event->xbutton.button == Button5 ||
+            event->xbutton.button == Button6 ||
+            event->xbutton.button == Button7))
     {
       gltrackball_mousewheel (lc->trackball, event->xbutton.button, 5,
                               !!event->xbutton.state);
     {
       gltrackball_mousewheel (lc->trackball, event->xbutton.button, 5,
                               !!event->xbutton.state);
@@ -1353,6 +1356,69 @@ 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)];
+
+  /* No texture created in -wireframe or -no-texture, so guess. */
+  int target_size = (lc->texture
+                     ? lc->texture->width * 1.4
+                     : 340);
+  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)
 {
 static void
 draw(ModeInfo *mi)
 {
@@ -1366,15 +1432,17 @@ draw(ModeInfo *mi)
 
   glPushMatrix();
 
 
   glPushMatrix();
 
+  /* Do it twice because we don't track the device's orientation. */
+  glRotatef( current_device_rotation(), 0, 0, 1);
   gltrackball_rotate (lc->trackball);
   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);
 
 
   /* 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. */
     glPushMatrix();
     {
       /* Shift to the upper left, and draw the vanilla box. */
@@ -1392,7 +1460,7 @@ draw(ModeInfo *mi)
 
     /* Shift to the lower right, and draw the animated object. */
     glTranslatef(0.6, 0.0, -0.6);
 
     /* Shift to the lower right, and draw the animated object. */
     glTranslatef(0.6, 0.0, -0.6);
-#endif /* DEBUG */
+#endif /* 0 */
 
 
     glPushMatrix();
 
 
     glPushMatrix();
@@ -1405,6 +1473,8 @@ draw(ModeInfo *mi)
       glRotatef (lc->roty * 360, 0.0, 1.0, 0.0);
       glRotatef (lc->rotz * 360, 0.0, 0.0, 1.0);
 
       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:
       switch (lc->type)
        {
        case LAMENT_BOX:
@@ -1660,28 +1730,11 @@ animate(ModeInfo *mi)
 
       if (lc->anim_r >= 112.0)
        {
 
       if (lc->anim_r >= 112.0)
        {
-         GLfloat hysteresis = 0.05;
-
          lc->anim_r = 112.0;
          lc->anim_z = 0.0;
          lc->anim_pause = pause3;
          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:
       break;
 
     case LAMENT_LID_CLOSE:
@@ -1760,42 +1813,15 @@ animate(ModeInfo *mi)
 ENTRYPOINT void
 reshape_lament(ModeInfo *mi, int width, int height)
 {
 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;
   GLfloat h = (GLfloat) height / (GLfloat) width;
-
   glViewport(0, 0, (GLint) width, (GLint) height);
 
   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);
   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 pixelated.
-   */
-  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);
 }
 
   glClear(GL_COLOR_BUFFER_BIT);
 }
 
@@ -1848,7 +1874,8 @@ gl_init(ModeInfo *mi)
       parse_image_data(mi);
 
       glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
       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++)
        {
 
       for (i = 0; i < 6; i++)
        {
@@ -1870,8 +1897,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);
          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 */
        }
 
 #else  /* !HAVE_GLBINDTEXTURE */