From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / glx / gleidescope.c
index e9863a227baf9f5cde874c9ba787f4a0c34029f4..dd6533a6779d227c3d38e1e5ebbb4bb696c27e57 100644 (file)
@@ -1,11 +1,14 @@
 /* -*- Mode: C; tab-width: 4 -*- */
+/* vim: set ai ts=4 sw=4: */
 
-#if !defined( lint ) && !defined( SABER )
+#if 0
 /*static const char sccsid[] = "@(#)gleidescope.c      1.0 03/06/27 xlockmore";*/
 #endif
 
-/* enable -grab switch */
-/*#define      GRAB*/
+/* enable -grab switch for animations */
+#undef GRAB
+
+#undef DISPLAY_TEXTURE
 
 /*-
  * Permission to use, copy, modify, and distribute this software and its
  *                                                                     no preference is given.
  *                                                             Made grid slightly bigger so you can't see
  *                                                                     the edge when zooming and moving.
+ *     20061226        1.4             acd             Now uses GL Display Lists.
+ *     20070318        1.5             acd             Generates textures.
+ *                                                             Fixed texture size problem (and introduced another).
+ *     20070412        1.6             acd             Textures now have independant sizes.
+ *     20070413        1.7             acd             Added Lissajous movement pattern.
+ *     20070414        1.8             acd             Added corners movement pattern.
+ *     20080319        1.9             acd             Changes to arguments for saner gleidescope.xml.
+ *
+ * TODO
+ * generate textures myself - render random shapes to 256x256 texture. (done)
+ * lower res for checks and random - use 256 and 4x4 or 8x8 pixels. (disabled for now)
+ * gnome-saver doesn't let you specify source directory so add that to this.
+ * image loading routine is too slow - rotation grinds to a halt - stop using it. (better in version 5)
+ * image loading also looks bad for non-square images - edges are black. (fixed)
+ * possible to see edge of the world on widescreen terminals - use larger grid and hidden hex removal?
+ * fading textures may have different max_tx - use two sets. (done)
+ * choice of movement patterns. (3 implemented, chooseable at compile time)
+ * look into rangle and tangle.
  */
 
-#include <X11/Intrinsic.h>
-#include "colors.h"
-
-#include "xpm-ximage.h"
-
 /*
 **----------------------------------------------------------------------------
 ** Defines
 */
 
 #ifdef STANDALONE
-# define PROGCLASS                             "gleidescope"
-# define HACK_INIT                             init_gleidescope
-# define HACK_DRAW                             draw_gleidescope
-# define HACK_RESHAPE                  reshape_gleidescope
-# define HACK_HANDLE_EVENT             gleidescope_handle_event
-# define EVENT_MASK                            PointerMotionMask
-# define gleidescope_opts              xlockmore_opts
 # define DEFAULTS \
                "*delay:                20000           \n"     \
                "*showFPS:              False           \n"     \
-               "*move:                 False           \n"     \
-               "*rotate:               False           \n"     \
-               "*zoom:                 False           \n"     \
-               "*image:                DEFAULT         \n"     \
-               "*size:                 -1                      \n"     \
-               "*duration:             30                      \n" \
-               "*useSHM:               True            \n"
+               "*size:                 0                       \n"     \
+               "*useSHM:               True            \n" \
+               "*suppressRotationAnimation: True\n" \
 
+# define refresh_gleidescope 0
+# define release_gleidescope 0
 # include "xlockmore.h"                                /* from the xscreensaver distribution */
 #else  /* !STANDALONE */
 # include "xlock.h"                                    /* from the xlockmore distribution */
 
 #ifdef USE_GL
 
-#include <GL/glu.h>
+#include "colors.h"
+#include "xpm-ximage.h"
+#include "grab-ximage.h"
+
+#ifdef GRAB
+void grab_frame(Display *display, Window window);
+#endif
 
 /* acd TODO should all these be in gleidestruct? */
+/* they can't be, because of the idiotic way the xlockmore "argtype vars"
+   interface works. -jwz */
 #ifdef GRAB
 static Bool            grab;                   /* grab images */
 #endif
@@ -89,23 +104,31 @@ static Bool                move;                   /* moving camera */
 static Bool            nomove;                 /* no moving camera */
 static Bool            rotate;                 /* rotate in place */
 static Bool            norotate;               /* no rotate in place */
-static int             size = -1;              /* size */
 static Bool            zoom;                   /* zooming camera */
 static Bool            nozoom;                 /* no zooming camera */
-static char            *image;                 /* name of texture to load */
+static char            *image_str;             /* name of texture to load */
 static int             duration;               /* length of time to display grabbed image */
 
-#define        MAX_TANGLE_VEL  2.0
+#define MAX_CAM_SPEED                  1.0
+#define MAX_ANGLE_VEL                  1.0
+#define INITIAL_ANGLE_VEL              0.2
+#define INITIAL_ANGLE_ACC              0.001
+#define        TWISTING_PROBABILITY    1000    /* 1 in ... of change of acceleration */
 
-static float   tangle = 0;                     /* texture angle */
-static float   tangle_vel = 0.0;       /* texture velocity */
-static float   tangle_acc = 0.0;       /* texture acceleration */
+#define RADIANS        (M_PI / 180)
+#define ANGLE_120      (M_PI * 2 / 3)
+#define ANGLE_240      (M_PI * 4 / 3)
 
-#define        MAX_RANGLE_VEL  1.5
+#define DEF_GRAB       "False"
+#define DEF_MOVE       "False"
+#define DEF_NOMOVE     "False"
+#define DEF_ROTATE     "False"
+#define DEF_NOROTATE   "False"
+#define DEF_ZOOM       "False"
+#define DEF_NOZOOM     "False"
+#define DEF_IMAGE      "DEFAULT"
+#define DEF_DURATION   "30"
 
-static float   rangle = 0;                     /* rotate angle */
-static float   rangle_vel = 0.0;       /* rotate velocity */
-static float   rangle_acc = 0.0;       /* rotate acceleration */
 
 static XrmOptionDescRec opts[] =
 {
@@ -116,7 +139,6 @@ static XrmOptionDescRec opts[] =
        {"-no-move",    ".gleidescope.nomove",          XrmoptionNoArg,         "true"},
        {"-rotate",             ".gleidescope.rotate",          XrmoptionNoArg,         "true"},
        {"-no-rotate",  ".gleidescope.norotate",        XrmoptionNoArg,         "true"},
-       /*{"-size",             ".gleidescope.size",            XrmoptionNoArg,         "-1"},*/
        {"-zoom",               ".gleidescope.zoom",            XrmoptionNoArg,         "true"},
        {"-no-zoom",    ".gleidescope.nozoom",          XrmoptionNoArg,         "true"},
        {"-image",              ".gleidescope.image",           XrmoptionSepArg,        "DEFAULT"},
@@ -126,17 +148,16 @@ static XrmOptionDescRec opts[] =
 
 static argtype vars[] = {
 #ifdef GRAB
-       {&grab,                 "grab",         "Grab",         "False",        t_Bool},
+       {&grab,                 "grab",         "Grab",         DEF_GRAB,       t_Bool},
 #endif
-       {&move,                 "move",         "Move",         "False",        t_Bool},
-       {&nomove,               "nomove",       "noMove",       "False",        t_Bool},
-       {&rotate,               "rotate",       "Rotate",       "False",        t_Bool},
-       {&norotate,             "norotate",     "noRotate",     "False",        t_Bool},
-       /*{&size,               "size",         "Size",         "-1",           t_Int},*/
-       {&zoom,                 "zoom",         "Zoom",         "False",        t_Bool},
-       {&nozoom,               "nozoom",       "noZoom",       "False",        t_Bool},
-       {&image,                "image",        "Image",        "DEFAULT",      t_String},
-       {&duration,             "duration",     "Duration",     "30",           t_Int},
+       {&move,                 "move",         "Move",         DEF_MOVE,       t_Bool},
+       {&nomove,               "nomove",       "noMove",       DEF_NOMOVE,     t_Bool},
+       {&rotate,               "rotate",       "Rotate",       DEF_ROTATE,     t_Bool},
+       {&norotate,             "norotate",     "noRotate",     DEF_NOROTATE,   t_Bool},
+       {&zoom,                 "zoom",         "Zoom",         DEF_ZOOM,       t_Bool},
+       {&nozoom,               "nozoom",       "noZoom",       DEF_NOZOOM,     t_Bool},
+       {&image_str,            "image",        "Image",        DEF_IMAGE,      t_String},
+       {&duration,             "duration",     "Duration",     DEF_DURATION,           t_Int},
 };
 
 static OptionStruct desc[] = {
@@ -147,14 +168,13 @@ static OptionStruct desc[] = {
        {"-no-move",    "camera won't move"},
        {"-rotate",             "camera will rotate"},
        {"-no-rotate",  "camera won't rotate"},
-       /*{"-size",             "size of the hexagons (1-10)"},*/
        {"-zoom",               "camera will zoom"},
        {"-no-zoom",    "camera won't zoom"},
        {"-image",              "xpm / xbm image file to use for texture"},
        {"-duration",   "length of time texture will be used"},
 };
 
-ModeSpecOpt gleidescope_opts = {
+ENTRYPOINT ModeSpecOpt gleidescope_opts = {
        sizeof opts / sizeof opts[0], opts,
        sizeof vars / sizeof vars[0], vars,
        desc
@@ -162,7 +182,7 @@ ModeSpecOpt gleidescope_opts = {
 
 #ifdef USE_MODULES
 ModStruct   gleidescope_description = { 
-     "gleidescope", "init_gleidescope", "draw_gleidescope", "release_gleidescope",
+     "gleidescope", "init_gleidescope", "draw_gleidescope", NULL,
      "draw_gleidescope", "init_gleidescope", NULL, &gleidescope_opts,
      1000, 1, 2, 1, 4, 1.0, "",
      "GL Kaleidescope", 0, NULL};
@@ -184,6 +204,25 @@ typedef struct {
        GLfloat z;
 } vectorf;
 
+typedef struct {
+       GLfloat x;
+       GLfloat y;
+} vector2f;
+
+typedef struct {
+       GLuint                  id;                             /* opengl texture id */
+       GLfloat                 width, height;  /* texture width and height */
+       GLfloat                 min_tx, min_ty; /* minimum texture sizes */
+       GLfloat                 max_tx, max_ty; /* maximum texture sizes */
+       time_t                  start_time;
+       Bool                    button_down_p;
+    Bool                       mipmap_p;
+    Bool                       waiting_for_image_p;
+       /* r_phase is for triangle rotation speed */
+       GLfloat                 x_period, y_period, r_period;
+       GLfloat                 x_phase, y_phase, r_phase;
+} texture;
+
 #define        MAX_FADE        500     /* number of fade cycles */
 
 typedef struct {
@@ -192,14 +231,36 @@ typedef struct {
        float                   tic;
        GLXContext              *glx_context;
        Window                  window;
-       GLfloat                 max_tx, max_ty; /* maximum texture sizes */
-       GLuint                  textures[2];    /* texture handles */
-       GLuint                  visible;                /* texture handle for new texture */
+       texture                 textures[2];    /* texture handles */
+       GLuint                  visible;                /* index for current texture */
        GLint                   fade;
        time_t                  start_time;
        Bool                    button_down_p;
+
+    int                size;
+       int             list;
+
+    float      tangle;         /* texture angle (degrees) */
+    float      tangle_vel;     /* texture velocity */
+    float      tangle_acc;     /* texture acceleration */
+
+    float      rangle;         /* rotate angle */
+    float      rangle_vel;     /* rotate velocity */
+    float      rangle_acc;     /* rotate acceleration */
+
+    /* mouse */
+    int xstart;
+    int ystart;
+    double xmouse;
+    double ymouse;
+
+    Bool mipmap_p;
+    Bool waiting_for_image_p;
+
 } gleidestruct;
 
+#define frandrange(x, y)       (x + frand(y - x))
+
 #define        XOFFSET (0.8660254f)    /* sin 60' */
 #define        YOFFSET (1.5000000f)    /* cos 60' + 1 */
 
@@ -215,9 +276,9 @@ generate_grid(int size)
 
        int     i, x, y;
 
-       size--;
+       gp->size--;
 
-       i = size;
+       i = gp->size;
        for (y = -size ; y <= size ; y++) {
                for (x = -i ; x <= i ; x += 2) {
                        printf("{XOFFSET * %d, YOFFSET * %d, 0},\n", x, y);
@@ -233,7 +294,8 @@ generate_grid(int size)
 }
 #endif
 
-hex_t hex[] = {
+/* acd - this is terrible - 120+ hexes */
+static const hex_t hex[] = {
        /* edges of size 7 */
        /* number of hexagons required to cover screen depends on camera distance */
        /* at a distance of 10 this is just about enough. */
@@ -386,10 +448,11 @@ hex_t hex[] = {
 
 static gleidestruct *gleidescope = NULL;
 
+#if 0
 /*
  *load defaults in config structure
  */
-void setdefaultconfig(void)
+static void setdefaultconfig(void)
 {
 #ifdef GRAB
        grab = False;
@@ -399,13 +462,9 @@ void setdefaultconfig(void)
        zoom = False;
        image = NULL;
 }
+#endif
 
-static int xstart;
-static int ystart;
-static double xmouse = 0.0;
-static double ymouse = 0.0;
-
-Bool
+ENTRYPOINT Bool
 gleidescope_handle_event(ModeInfo *mi, XEvent *event)
 {
        gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
@@ -414,16 +473,14 @@ gleidescope_handle_event(ModeInfo *mi, XEvent *event)
        printf("event:%d\n", event->xany.type);
        printf("button:%d\n", event->xbutton.button);
        */
-       switch(event->xany.type)
-       {
-               case ButtonPress:
-
+       if (event->xany.type == ButtonPress)
+      {
                        if (event->xbutton.button == Button1 ||
                 event->xbutton.button == Button3)
                        {
                                /* store initial values of mouse */
-                               xstart = event->xbutton.x;
-                               ystart = event->xbutton.y;
+                               gp->xstart = event->xbutton.x;
+                               gp->ystart = event->xbutton.y;
 
                                /* button is down */
                                gp->button_down_p = True;
@@ -441,10 +498,8 @@ gleidescope_handle_event(ModeInfo *mi, XEvent *event)
                                return True;
                        }
 #endif
-                       break;
-
-               case ButtonRelease:
-
+            } else if (event->xany.type == ButtonRelease)
+      {
                        if (event->xbutton.button == Button1 ||
                 event->xbutton.button == Button3)
                        {
@@ -452,56 +507,377 @@ gleidescope_handle_event(ModeInfo *mi, XEvent *event)
                                gp->button_down_p = False;
                                return True;
                        }
-                       break;
-
-               case MotionNotify:
-
+            } else if (event->xany.type == MotionNotify)
+      {
                        if (gp->button_down_p)
                        {
                                /* update mouse position */
-                               xmouse += (double)(event->xmotion.x - xstart) / MI_WIDTH(mi);
-                               ymouse += (double)(event->xmotion.y - ystart) / MI_HEIGHT(mi);
-                               xstart = event->xmotion.x;
-                               ystart = event->xmotion.y;
+                               gp->xmouse += (double)(event->xmotion.x - gp->xstart) / MI_WIDTH(mi);
+                               gp->ymouse += (double)(event->xmotion.y - gp->ystart) / MI_HEIGHT(mi);
+                               gp->xstart = event->xmotion.x;
+                               gp->ystart = event->xmotion.y;
 
                                return True;
                        }
-                       break;
-       }
+      }
+  else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
+    {
+      gp->start_time = -1;
+      gp->fade = 0;
+      return True;
+    }
 
        return False;
 }
 
-#include "grab-ximage.h"
 
 static void
-getSnapshot(ModeInfo *mi, GLuint name)
+image_loaded_cb (const char *filename, XRectangle *geometry,
+                 int image_width, int image_height, 
+                 int texture_width, int texture_height,
+                 void *closure)
+{
+       texture *tp = (texture *) closure;
+
+#if 0
+       gp->max_tx = (GLfloat) image_width  / texture_width;
+       gp->max_ty = (GLfloat) image_height / texture_height;
+#endif
+
+       /* new - taken from flipscreen */
+       tp->width = texture_width;
+       tp->height = texture_height;
+       tp->min_tx = (GLfloat) geometry->x / tp->width;
+       tp->min_ty = (GLfloat) geometry->y / tp->height;
+       tp->max_tx = (GLfloat) (geometry->x + geometry->width)  / tp->width;
+       tp->max_ty = (GLfloat) (geometry->y + geometry->height) / tp->height;
+
+#ifdef DEBUG
+       printf("Image w,h: (%d, %d)\n", image_width, image_height);
+       printf("Texture w,h: (%d, %d)\n", texture_width, texture_height);
+       printf("Geom x,y: (%d, %d)\n", geometry->x, geometry->y);
+       printf("Geom w,h: (%d, %d)\n", geometry->width, geometry->height);
+       printf("Max Tx,Ty: (%f, %f)\n", tp->max_tx, tp->max_ty);
+#endif
+
+       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                       (tp->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
+
+       tp->waiting_for_image_p = False;
+       tp->start_time = time ((time_t *) 0);
+}
+
+static void
+getSnapshot(ModeInfo *mi, texture *texture)
 {
-    Bool mipmap_p = True;
-       int     iw, ih, tw, th;
        gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
 
+#ifdef DEBUG
+       printf("getSnapshot");
+#endif
+
        if (MI_IS_WIREFRAME(mi))
                return;
 
-       glBindTexture (GL_TEXTURE_2D, name);
-    if (! screen_to_texture (mi->xgwa.screen, mi->window, 0, 0,
-                             mipmap_p, NULL, NULL, &iw, &ih, &tw, &th))
-      exit (1);
+    gp->mipmap_p = True;
+    load_texture_async (mi->xgwa.screen, mi->window,
+                        *gp->glx_context, 0, 0, gp->mipmap_p, 
+                        texture->id, image_loaded_cb, texture);
+       texture->start_time = time((time_t *)0);
+}
 
-    gp->max_tx = (GLfloat) iw / tw;
-    gp->max_ty = (GLfloat) ih / th;
+#define TEXTURE_SIZE   256
 
-    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-                     (mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
+static void
+plot(unsigned char *buffer, int x, int y, int r, int g, int b, int a) {
+       int c;
+       if (x < 0 || x >= TEXTURE_SIZE || y < 0 || y >= TEXTURE_SIZE) {
+               return;
+       }
+       c = ((x * TEXTURE_SIZE) + y) * 4;
+       /*printf("(%d,%d)[%d]\n", x, y, c);*/
+       buffer[c + 0] = r;
+       buffer[c + 1] = g;
+       buffer[c + 2] = b;
+       buffer[c + 3] = a;
+}
+
+#if 0
+static void
+plot2(unsigned char *buffer, int x, int y, int r, int g, int b, int a) {
+       int c;
+       if (x < 0 || x >= TEXTURE_SIZE || y < 0 || y >= TEXTURE_SIZE) {
+               return;
+       }
+       c = ((x * TEXTURE_SIZE) + y) * 4;
+       /*printf("(%d,%d)[%d]\n", x, y, c);*/
+       buffer[c + 0] = r;
+       buffer[c + 1] = g;
+       buffer[c + 2] = b;
+       buffer[c + 3] = a;
+       
+       if (y + 1 < TEXTURE_SIZE) {
+               buffer[c + 4] = r;
+               buffer[c + 5] = g;
+               buffer[c + 6] = b;
+               buffer[c + 7] = a;
+       }
 
-       /* remember time of last image change */
-       gp->start_time = time ((time_t *) 0);
+       if (x + 1 < TEXTURE_SIZE) {
+               c += (TEXTURE_SIZE * 4);
+               buffer[c + 0] = r;
+               buffer[c + 1] = g;
+               buffer[c + 2] = b;
+               buffer[c + 3] = a;
+               if (y + 1 < TEXTURE_SIZE) {
+                       buffer[c + 4] = r;
+                       buffer[c + 5] = g;
+                       buffer[c + 6] = b;
+                       buffer[c + 7] = a;
+               }
+       }
 }
+#endif
 
+/* draw geometric shapes to texture */
+/* modifies passed in buffer */
 static void
-setup_file_texture (ModeInfo *mi, char *filename, GLuint name)
+draw_shapes (unsigned char *buffer) {
+       int a = 0xff;
+       int x, y, w, h;
+       int i, j;
+       int s;
+       float left, right;
+
+       for (i = 0 ; i < TEXTURE_SIZE * TEXTURE_SIZE * 4 ; i += 4) {
+               buffer[i + 0] = 0x00;
+               buffer[i + 1] = 0x00;
+               buffer[i + 2] = 0x00;
+               buffer[i + 3] = 0xff;
+       }
+
+       for (s = 0 ; s < 25 ; s++) {
+               int shape = random() % 3;
+
+               /* 8 bits */
+               int r = (random() & 0xff);
+               int g = (random() & 0xff);
+               int b = (random() & 0xff);
+
+               switch (shape) {
+                       case 0:
+                               /* rectangle */
+                               x = (random() % TEXTURE_SIZE) - (TEXTURE_SIZE / 4);     /* top left */
+                               y = (random() % TEXTURE_SIZE) - (TEXTURE_SIZE / 4);
+                               w = 10 + random() % (TEXTURE_SIZE / 4); /* size */
+                               h = 10 + random() % (TEXTURE_SIZE / 4);
+#ifdef DEBUG
+                               printf("Rectangle: (%d, %d)(%d, %d)\n", x, y, w, h);
+#endif
+                               if (x < 0) {
+                                       x = 0;
+                               }
+                               if (y < 0) {
+                                       y = 0;
+                               }
+                               for (i = x ; i < x + w && i < TEXTURE_SIZE; i++) {
+                                       for (j = y ; j < y + h && j < TEXTURE_SIZE; j++) {
+                                               plot(buffer, i, j, r, g, b, a);
+                                       }
+                               }
+                               break;
+
+                       case 1:
+                               /* circle */
+                               x = random() % TEXTURE_SIZE;    /* centre */
+                               y = random() % TEXTURE_SIZE;
+                               h = 10 + random() % (TEXTURE_SIZE / 8); /* radius */
+#ifdef DEBUG
+                               printf("Circle: %d, %d, %d\n", x, y, h);
+#endif
+                               for (i = 0 ; i < h ; i++) {
+                                       int xdist = i * i;
+                                       for (j = 0 ; j < h ; j++) {
+                                               int ydist = j * j;
+                                               /*
+                                               printf("xdist: %d\n", xdist);
+                                               printf("ydist: %d\n", ydist);
+                                               printf("radius: %d\n", h * h);
+                                               */
+                                               if ((xdist + ydist) < (h * h)) {
+                                                       plot(buffer, x + i, y + j, r, b, g, a);
+                                                       /* check we haven't already done these */
+                                                       if (j != 0) {
+                                                               plot(buffer, x + i, y - j, r, b, g, a);
+                                                       }
+                                                       if (i != 0) {
+                                                               plot(buffer, x - i, y + j, r, b, g, a);
+                                                               if (j != 0) {
+                                                               plot(buffer, x - i, y - j, r, b, g, a);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               break;
+
+                       case 2:
+                               /* triangle */
+                               x = random() % TEXTURE_SIZE;    /* top */
+                               y = random() % TEXTURE_SIZE;
+                               h = 10 + random() % (TEXTURE_SIZE / 4); /* height */
+#ifdef DEBUG
+                               printf("Triangle: %d, %d, %d\n", x, y, h);
+#endif
+                               left = x;
+                               right = x;
+                               for (i = 0 ; i < h ; i++) {
+                                       for (j = left ; j < right ; j++) {
+                                               plot(buffer, j, y + i, r, g, b, a);
+                                       }
+                                       left -= .5;
+                                       right += .5;
+                               }
+                               break;
+               }
+       }
+}
+
+static void
+setup_random_texture (ModeInfo *mi, texture *texture)
+{
+       int width = 0, height = 0;
+       char buf[1024];
+       unsigned char *my_data = NULL;
+#if 0
+       int i, j, c;
+       int style;
+       int r0, g0, b0, a0, r1, g1, b1, a1;
+#endif
+
+#ifdef DEBUG
+       printf("RandomTexture\n");
+#endif
+
+       /* use this texture */
+       glBindTexture(GL_TEXTURE_2D, texture->id);
+
+       clear_gl_error();
+
+       /*
+        * code for various generated patterns - noise, stripes, checks etc.
+        * random geometric shapes looked the best.
+        */
+
+#if 0
+       style = random() & 0x3;
+       r0 = random() & 0xff; 
+       g0 = random() & 0xff; 
+       b0 = random() & 0xff; 
+       a0 = 0xff;
+       r1 = random() & 0xff; 
+       g1 = random() & 0xff; 
+       b1 = random() & 0xff; 
+       a1 = 0xff;
+
+       switch (style) {
+               case 0: /* random */
+                       printf("Random0\n");
+                       height = width = TEXTURE_SIZE;
+                       my_data = (void *)malloc(width * height * 4);
+                       for (i = 0 ; i < width ; i += 2) {
+                               for (j = 0 ; j < height ; j += 2) {
+                                       r0 = random() & 0xff; 
+                                       g0 = random() & 0xff; 
+                                       b0 = random() & 0xff; 
+                                       a0 = 0xff;
+                                       plot2(my_data, i, j, r0, g0, b0, a0);
+                               }
+                       }
+                       break;
+
+               case 1: /* shapes */
+#endif
+#ifdef DEBUG
+                       printf("Shapes\n");
+#endif
+                       height = width = TEXTURE_SIZE;
+                       my_data = (void *)malloc(width * height * 4);
+                       draw_shapes(my_data);
+#if 0
+                       break;
+
+               case 2: /* check */
+                       printf("Check\n");
+                       height = width = TEXTURE_SIZE;
+                       my_data = (void *)malloc(width * height * 4);
+                       for (i = 0 ; i < height ; i += 2) {
+                               for (j = 0 ; j < width ; j += 2) {
+                                       if (((i + j) & 0x3) == 0) {
+                                               plot2(my_data, i, j, r0, g0, b0, a0);
+                                       } else {
+                                               plot2(my_data, i, j, r1, g1, b1, a1);
+                                       }
+                               }
+                       }
+                       break;
+
+               case 3: /* random stripes */
+                       printf("Stripes 2\n");
+                       height = width = TEXTURE_SIZE;
+                       my_data = (void *)malloc(width * height * 4);
+                       for (i = 0 ; i < height ; i += 2) {
+                               r0 = random() & 0xff; 
+                               g0 = random() & 0xff; 
+                               b0 = random() & 0xff; 
+                               a0 = 0xff;
+                               for (j = 0 ; j < width ; j += 2) {
+                                       plot2(my_data, i, j, r0, g0, b0, a0);
+                               }
+                       }
+                       break;
+       }
+#endif
+
+       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+                       width, height, 0,
+                       GL_RGBA, GL_UNSIGNED_BYTE, my_data);
+       sprintf (buf, "random texture: (%dx%d)",
+                       width, height);
+       check_gl_error(buf);
+
+       /* setup parameters for texturing */
+       glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+       glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
+
+       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+       if (random() & 0x1) {
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+       } else {
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+       }
+
+       if (my_data != NULL) {
+               free(my_data);
+               my_data = NULL;
+       }
+
+       /* use full texture */
+       /* acd - was 1.0 */
+       texture->min_tx = 0.0;
+       texture->max_tx = 2.0;
+       texture->min_ty = 0.0;
+       texture->max_ty = 2.0;
+       texture->start_time = time((time_t *)0);
+}
+
+static Bool
+setup_file_texture (ModeInfo *mi, char *filename, texture *texture)
 {
        Display *dpy = mi->dpy;
        Visual *visual = mi->xgwa.visual;
@@ -509,9 +885,14 @@ setup_file_texture (ModeInfo *mi, char *filename, GLuint name)
 
        Colormap cmap = mi->xgwa.colormap;
        XImage *image = xpm_file_to_ximage (dpy, visual, cmap, filename);
+    if (!image) return False;
+
+#ifdef DEBUG
+       printf("FileTexture\n");
+#endif
 
        /* use this texture */
-       glBindTexture(GL_TEXTURE_2D, name);
+       glBindTexture(GL_TEXTURE_2D, texture->id);
 
        clear_gl_error();
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
@@ -530,32 +911,65 @@ setup_file_texture (ModeInfo *mi, char *filename, GLuint name)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+       /* use full texture */
+       texture->min_tx = 0.0;
+       texture->max_tx = 1.0;
+       texture->min_ty = 0.0;
+       texture->max_ty = 1.0;
+       texture->start_time = time((time_t *)0);
+    return True;
 }
 
 static void
-setup_texture(ModeInfo * mi, GLuint id)
+setup_texture(ModeInfo * mi, texture *texture)
 {
        gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
 
-       if (!image || !*image || !strcmp(image, "DEFAULT")) {
-               /* no image specified - grab screen */
-               getSnapshot(mi, id);
-               /* max_tx and max_ty set in getSnapshot() */
+       if (!image_str || !*image_str || !strcmp(image_str, "DEFAULT")) {
+    BUILTIN:
+               /* no image specified - use system settings */
+#ifdef DEBUG
+               printf("SetupTexture: get_snapshot\n");
+#endif
+               getSnapshot(mi, texture);
        } else {
-               /* use supplied image file */
-               setup_file_texture(mi, image, id);
-
-               /* set tx params to use whole image */
-               gp->max_tx = 1.0f;
-               gp->max_ty = 1.0f;
+               if (strcmp(image_str, "GENERATE") == 0) {
+#ifdef DEBUG
+                       printf("SetupTexture: random_texture\n");
+#endif
+                       setup_random_texture(mi, texture);
+               } else {
+                       /* use supplied image file */
+#ifdef DEBUG
+                       printf("SetupTexture: file_texture\n");
+#endif
+                       if (! setup_file_texture(mi, image_str, texture))
+              goto BUILTIN;
+               }
        }
+       /* copy start time from texture */
+       gp->start_time = texture->start_time;
 
        check_gl_error("texture initialization");
 
-       /* Need to flip the texture top for bottom for some reason. */
-       glMatrixMode (GL_TEXTURE);
-       glScalef (1, -1, 1);
-       glMatrixMode (GL_MODELVIEW);
+       /* acd 
+        * resultant loaded image is upside down BUT
+        * it's a kaledescope and half of the hexagon is backwards anyway...
+        */
+
+       /* TODO: values for lissajous movement */
+       texture->x_period = frandrange(-2.0, 2.0);
+       texture->y_period = frandrange(-2.0, 2.0);
+       texture->r_period = frandrange(-2.0, 2.0);
+       texture->x_phase = frand(M_PI * 2);
+       texture->y_phase = frand(M_PI * 2);
+       texture->r_phase = frand(M_PI * 2);
+#ifdef DEBUG
+       printf("XPeriod %f XPhase %f\n", texture->x_period, texture->x_phase);
+       printf("YPeriod %f YPhase %f\n", texture->y_period, texture->y_phase);
+       printf("RPeriod %f RPhase %f\n", texture->r_period, texture->r_phase);
+#endif
 }
 
 #define        VERTEX0 glVertex3f( 0.0000f,  0.000f, 0.0f);
@@ -566,99 +980,226 @@ setup_texture(ModeInfo * mi, GLuint id)
 #define        VERTEX5 glVertex3f(-XOFFSET, -0.500f, 0.0f);
 #define        VERTEX6 glVertex3f(-XOFFSET,  0.500f, 0.0f);
 
+/*
+** Three different functions for calculating texture coordinates
+** which modify how the texture triangle moves over the source image.
+** Choose one.
+*/
+
+#if 0
+/* the classic equilateral triangle rotating around centre */
+static void
+calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) {
+
+       gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
+       GLfloat centre_x = 0.5;
+       GLfloat centre_y = 0.5;
+       GLfloat radius_x = (texture->max_tx - texture->min_tx) / 2;
+       GLfloat radius_y = (texture->max_ty - texture->min_ty) / 2;
+       GLfloat tangle2;
+       t[0].x = centre_x;
+       t[0].y = centre_y;
+
+       /* t[1] */
+       t[1].x = centre_x + .95 * radius_x * cos((gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS));
+       t[1].y = centre_y + .95 * radius_y * sin((gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS));
+
+       /* t[2] is always 60' further around than t2 */
+       tangle2 = (gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS) + (M_PI * 2 / 6);
+       t[2].x = centre_x + .95 * radius_x * cos(tangle2);
+       t[2].y = centre_y + .95 * radius_y * sin(tangle2);
+#if 0
+       printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t[0].x, t[0].y, t[1].x, t[1].y, texture->max_tx, texture->max_ty);
+#endif
+}
+#endif
+
+#if 1
+/* new lissajous movement pattern */
+static void
+calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) {
+
+       /* equilateral triangle rotating around centre */
+       gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
+       GLfloat width = texture->max_tx - texture->min_tx;
+       GLfloat height = texture->max_ty - texture->min_ty;
+       /* centre */
+       GLfloat centre_x = texture->min_tx + (width * .5);
+       GLfloat centre_y = texture->min_ty + (height * .5);
+       /* m radius and t radius should be = .5 */
+       /* triangle radius is 30% available space */
+       GLfloat t_radius_x = width * .3;
+       GLfloat t_radius_y = height * .3;
+       /* movement radius is 30% available space */
+       GLfloat m_radius_x = width * .2;
+       GLfloat m_radius_y = height * .2;
+       GLfloat angle2;
+
+       /* centre of triangle */
+       GLfloat angle = (gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS);       /* to radians */
+       GLfloat t_centre_x = centre_x + m_radius_x * cos(texture->x_period * angle + texture->x_phase);
+       GLfloat t_centre_y = centre_y + m_radius_y * sin(texture->y_period * angle + texture->y_phase);
+
+#if 0
+       printf("WH: %f, %f - tWH: %f, %f\n", width, height, texture->width, texture->height);
+       printf("size: (%f, %f)\n", width, height);
+       printf("centre: (%f, %f)\n", centre_x, centre_y);
+#endif
+
+       angle2 = texture->r_period * angle + texture->r_phase;
+       t[0].x = t_centre_x + t_radius_x * cos(angle2);
+       t[0].y = t_centre_y + t_radius_y * sin(angle2);
+       t[1].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_120);
+       t[1].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_120);
+       t[2].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_240);
+       t[2].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_240);
+
+#if 0
+       printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t[0].x, t[0].y, t[1].x, t[1].y, texture->max_tx, texture->max_ty);
+#endif
+}
+#endif
+#if 0
+/* corners into corners - meant to maximise coverage */
 static void
-draw_hexagons(ModeInfo *mi, int translucency, GLuint texture)
+calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) {
+
+       /* equilateral triangle rotating around centre */
+       gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
+       GLfloat width = texture->max_tx - texture->min_tx;
+       GLfloat height = texture->max_ty - texture->min_ty;
+       /* centre */
+       GLfloat centre_x = texture->min_tx + (width * .5);
+       GLfloat centre_y = texture->min_ty + (height * .5);
+       /* m radius and t radius should be = .5 */
+       /* triangle radius calculated using maths 8) */
+#define TRADIUS (M_SQRT2 - 1.0)
+#define MRADIUS (1.0 - (M_SQRT2 / 2.0))
+       GLfloat t_radius_x = width * TRADIUS * .95;
+       GLfloat t_radius_y = height * TRADIUS * .95;
+       /* movement radius also calculated using maths */
+       GLfloat m_radius_x = width * MRADIUS * .95;
+       GLfloat m_radius_y = height * MRADIUS * .95;
+       GLfloat angle, angle2;
+       GLfloat t_centre_x, t_centre_y;
+
+       /* centre of triangle */
+       angle = gp->tangle * RADIANS;   /* to radians */
+       t_centre_x = centre_x + m_radius_x * cos(angle);
+       t_centre_y = centre_y + m_radius_y * sin(angle);
+#if 0
+       printf("angle: %f, %f\n", angle, gp->tangle);
+       printf("tcentre: %f,%f\n", t_centre_x, t_centre_y);
+       printf("tradius: %f,%f\n", t_radius_x, t_radius_y);
+
+       printf("size: (%f, %f)\n", width, height);
+       printf("centre: (%f, %f)\n", centre_x, centre_y);
+       printf("centre: (%f, %f)\n", centre_x, centre_y);
+       printf("TRADIUS: %f\n", TRADIUS);
+       printf("MRADIUS: %f\n", MRADIUS);
+#endif
+
+       /* angle2 is tied to tangle */
+       angle2 = (180.0 - ((30.0 / 90.0) * gp->tangle)) * RADIANS; 
+#if 0
+       printf("Angle1: %f\tAngle2: %f\n", angle / RADIANS, angle2 / RADIANS);
+#endif
+       t[0].x = t_centre_x + t_radius_x * cos(angle2);
+       t[0].y = t_centre_y + t_radius_y * sin(angle2);
+       t[1].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_120);
+       t[1].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_120);
+       t[2].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_240);
+       t[2].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_240);
+
+#if 0
+       printf("texcoords:[%f,%f][%f,%f][%f,%f]\n", t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y);
+#endif
+}
+#endif
+
+static int
+draw_hexagons(ModeInfo *mi, int translucency, texture *texture)
 {
+    int polys = 0;
        int             i;
-       GLfloat col[4];
-       GLfloat t1x, t1y, t2x, t2y, t3x, t3y;
+       vector2f t[3];
        gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
-       GLfloat tangle2;
 
-       col[0] = 1.0;
-       col[1] = 1.0;
-       col[2] = 1.0;
-       col[3] = (float)translucency / MAX_FADE;
-
-       /* calculate vertices of equilateral triangle within image. */
-       /* t1 is always in centre */
-       t1x = gp->max_tx / 2;
-       t1y = gp->max_ty / 2;
-       /* t2 rotates */
-       t2x = (gp->max_tx / 2) * (1 + cos((ymouse * 2 * M_PI) + (tangle * M_PI / 180)));
-       t2y = (gp->max_ty / 2) * (1 + sin((ymouse * 2 * M_PI) + (tangle * M_PI / 180)));
-       /* t3 is always 60' further around than t2 */
-       tangle2 = (ymouse * 2 * M_PI) + (tangle * M_PI / 180) + (M_PI * 2 / 6);
-       t3x = (gp->max_tx / 2) * (1 + (cos(tangle2)));
-       t3y = (gp->max_ty / 2) * (1 + (sin(tangle2)));
-       /* NB image is flipped vertically hence: */
-       t1y = 1 - t1y;
-       t2y = 1 - t2y;
-       t3y = 1 - t3y;
-       /*printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t1x, t1y, t2x, t2y, gp->max_tx, gp->max_ty);*/
+       calculate_texture_coords(mi, texture, t);
 
        glColor4f(1.0, 1.0, 1.0, (float)translucency / MAX_FADE);
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDepthMask(GL_FALSE);
-       glBindTexture(GL_TEXTURE_2D, gp->textures[texture]);
+       glBindTexture(GL_TEXTURE_2D, texture->id);
 
+       if (gp->list == -1) {
+               gp->list = glGenLists(1);
+       }
+
+       /* compile new list */
+       glNewList(gp->list, GL_COMPILE);
+       glBegin(GL_TRIANGLES);
+
+       /*
+       ** six triangles to each hexagon
+       */
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX1;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX6;
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX6;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX5;
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX5;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX4;
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX4;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX3;
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX3;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX2;
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX2;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX1;
+
+       glEnd();
+       glEndList();
+
+       /* call the list n times */
        for (i = 0 ; i < sizeof(hex) / sizeof(hex[0]) ; i++) {
 
                glPushMatrix();
 
                glTranslatef(hex[i].x, hex[i].y, 0.0);
-
-               glBegin(GL_TRIANGLES);
-
-               /*
-               ** six triangles to each hexagon
-               */
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t2x, t2y);
-               VERTEX1;
-               glTexCoord2f(t3x, t3y);
-               VERTEX6;
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t3x, t3y);
-               VERTEX6;
-               glTexCoord2f(t2x, t2y);
-               VERTEX5;
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t2x, t2y);
-               VERTEX5;
-               glTexCoord2f(t3x, t3y);
-               VERTEX4;
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t3x, t3y);
-               VERTEX4;
-               glTexCoord2f(t2x, t2y);
-               VERTEX3;
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t2x, t2y);
-               VERTEX3;
-               glTexCoord2f(t3x, t3y);
-               VERTEX2;
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t3x, t3y);
-               VERTEX2;
-               glTexCoord2f(t2x, t2y);
-               VERTEX1;
-
-               glEnd();
+               glCallList(gp->list);
+        polys += 6;
 
                glPopMatrix();
        }
@@ -677,13 +1218,15 @@ draw_hexagons(ModeInfo *mi, int translucency, GLuint texture)
        glVertex3f(1.0, 1.0, -0.1);
        glTexCoord2f(0.0, 1.0);
        glVertex3f(0.0, 1.0, -0.1);
+    polys++;
        glEnd();
        /* acd debug - display texture triangle */
-       glColor4f(1.0, 1.0, 1.0, 1.0);
+       glColor4f(1.0, 0.5, 1.0, 1.0);
        glBegin(GL_LINE_LOOP);
-       glVertex3f(t1x, t1y, -0.11);
-       glVertex3f(t2x, t2y, -0.11);
-       glVertex3f(t3x, t3y, -0.11);
+       glVertex3f(t[0].x, t[0].y, -0.11);
+       glVertex3f(t[1].x, t[1].y, -0.11);
+       glVertex3f(t[2].x, t[2].y, -0.11);
+    polys++;
        glEnd();
        glPopMatrix();
 #endif
@@ -691,6 +1234,7 @@ draw_hexagons(ModeInfo *mi, int translucency, GLuint texture)
        glDisable(GL_TEXTURE_2D);
        glDepthMask(GL_TRUE);
        glDisable(GL_BLEND);
+    return polys;
 }
 
 /*
@@ -702,9 +1246,9 @@ draw(ModeInfo * mi)
        GLfloat x_angle, y_angle, z_angle;
        gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
        vectorf v1;
-       GLfloat pos[4];
 
-       glClearColor(0.5, 0.5, 0.5, 1.0);
+    mi->polygon_count = 0;
+
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
 
@@ -715,27 +1259,27 @@ draw(ModeInfo * mi)
        z_angle = gp->cam_z_phase + gp->tic * gp->cam_z_speed;
 
        if (move) {
-               v1.x = 2 * sin(x_angle);
-               v1.y = 2 * sin(y_angle);
+               v1.x = 1 * sin(x_angle);
+               v1.y = 1 * sin(y_angle);
        } else {
                v1.x = 0;
                v1.y = 0;
        }
 
        /* size is changed in pinit() to be distance from plane */
-       size = MI_SIZE(mi);
-       if (size > 10) {
-               size = 10;
+       gp->size = MI_SIZE(mi);
+       if (gp->size > 10) {
+               gp->size = 10;
        }
-       if (size < -1) {
-               size = -1;
+       if (gp->size <= 0) {
+               gp->size = 0;
        }
-       if (size != -1) {
+       if (gp->size > 0) {
                /* user defined size */
-               v1.z = size;
+               v1.z = gp->size;
        } else if (zoom) {
                /* max distance given by adding the constant and the multiplier */
-               v1.z = 5.0 + 4.0 * sin(z_angle);
+               v1.z = 5.0 + 3.0 * sin(z_angle);
        } else {
                /* default */
                v1.z = 7.0;
@@ -747,20 +1291,26 @@ draw(ModeInfo * mi)
                float   new_rangle_vel = 0.0;
 
                /* update camera rotation angle and velocity */
-               rangle += rangle_vel;
-               new_rangle_vel = rangle_vel + rangle_acc;
-               if (new_rangle_vel > -MAX_RANGLE_VEL && new_rangle_vel < MAX_RANGLE_VEL)
+               gp->rangle += gp->rangle_vel;
+               new_rangle_vel = gp->rangle_vel + gp->rangle_acc;
+               if (new_rangle_vel > -MAX_ANGLE_VEL && new_rangle_vel < MAX_ANGLE_VEL)
                {
                        /* new velocity is within limits */
-                       rangle_vel = new_rangle_vel;
+                       gp->rangle_vel = new_rangle_vel;
                }
 
-               /* randomly change twisting speed */
-               if ((random() % 1000) < 1)
-               {
-                       rangle_acc = frand(0.002) - 0.001;
+               /* randomly change twisting speed - 3ff = 1024 */
+               if ((random() % TWISTING_PROBABILITY) < 1.0) {
+                       gp->rangle_acc = INITIAL_ANGLE_ACC * frand(1.0);
+                       if (gp->rangle_vel > 0.0) {
+                               gp->rangle_acc = -gp->rangle_acc;
+                       }
                }
        }
+#if 0
+       printf("Rangle: %f : %f : %f\n", gp->rangle, gp->rangle_vel, gp->rangle_acc);
+       printf("Tangle: %f : %f : %f\n", gp->tangle, gp->tangle_vel, gp->tangle_acc);
+#endif
 
 #ifdef WOBBLE
        /* this makes the image wobble - requires -move and a larger grid */
@@ -772,27 +1322,34 @@ draw(ModeInfo * mi)
        gluLookAt(
                        v1.x, v1.y, v1.z,
                        v1.x, v1.y, 0.0,
-                       sin((xmouse * M_PI * 2) + rangle * M_PI / 180),
-                       cos((xmouse * M_PI * 2) + rangle * M_PI / 180),
+                       sin((gp->xmouse * M_PI * 2) + gp->rangle * RADIANS),
+                       cos((gp->xmouse * M_PI * 2) + gp->rangle * RADIANS),
                        0.0);
 #endif
 
-       /* light position same as camera */
-       pos[0] = v1.x;
-       pos[1] = v1.y;
-       pos[2] = v1.z;
-       pos[3] = 0;
+# 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);
+    }
+# endif
 
        if (gp->fade == 0)
        {
                /* not fading */
-               draw_hexagons(mi, MAX_FADE, gp->visible);
+      mi->polygon_count += 
+        draw_hexagons(mi, MAX_FADE, &gp->textures[gp->visible]);
        }
        else
        {
-               /* fading - show both textures with alpha */
-               draw_hexagons(mi, MAX_FADE - gp->fade, gp->visible);
-               draw_hexagons(mi, gp->fade, 1 - gp->visible);
+               /* fading - show both textures with alpha
+               NB first is always max alpha */
+        mi->polygon_count += 
+          draw_hexagons(mi, MAX_FADE, &gp->textures[1 - gp->visible]);
+        mi->polygon_count += 
+                 draw_hexagons(mi, MAX_FADE - gp->fade, &gp->textures[gp->visible]);
 
                /* fade some more */
                gp->fade++;
@@ -812,20 +1369,22 @@ draw(ModeInfo * mi)
        {
                float           new_tangle_vel = 0.0;
 
-               tangle += tangle_vel;
+               gp->tangle += gp->tangle_vel;
 
                /* work out new texture angle velocity */
-               new_tangle_vel = tangle_vel + tangle_acc;
-               if (new_tangle_vel > -MAX_TANGLE_VEL && new_tangle_vel < MAX_TANGLE_VEL)
+               new_tangle_vel = gp->tangle_vel + gp->tangle_acc;
+               if (new_tangle_vel > -MAX_ANGLE_VEL && new_tangle_vel < MAX_ANGLE_VEL)
                {
                        /* new velocity is inside limits */
-                       tangle_vel = new_tangle_vel;
+                       gp->tangle_vel = new_tangle_vel;
                }
 
-               /* randomly change texture angle acceleration */
-               if ((random() % 1000) < 1)
-               {
-                       tangle_acc = frand(0.002) - 0.001;
+               /* randomly change twisting speed - 3ff = 1024 */
+               if ((random() % TWISTING_PROBABILITY) < 1.0) {
+                       gp->tangle_acc = INITIAL_ANGLE_ACC * frand(1.0);
+                       if (gp->tangle_vel > 0.0) {
+                               gp->tangle_acc = -gp->tangle_acc;
+                       }
                }
        }
 
@@ -835,16 +1394,18 @@ draw(ModeInfo * mi)
 /* 
  * new window size or exposure 
  */
-void reshape_gleidescope(ModeInfo *mi, int width, int height)
+ENTRYPOINT void reshape_gleidescope(ModeInfo *mi, int width, int height)
 {
+       gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
        GLfloat         h = (GLfloat) height / (GLfloat) width;
 
+       glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(gp->glx_context));
+
        glViewport(0, 0, (GLint) width, (GLint) height);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(50.0, 1/h, 0.1, 2000.0);
        glMatrixMode (GL_MODELVIEW);
-
        glLineWidth(1);
        glPointSize(1);   
 }
@@ -858,8 +1419,10 @@ pinit(ModeInfo * mi)
        gp->start_time = (time_t)0;
 
        /* set the texture size to default */
+       /*
        gp->max_tx = 1.0;
        gp->max_ty = 1.0;
+       */
 
        /* no fading */
        gp->fade = 0;
@@ -871,11 +1434,11 @@ pinit(ModeInfo * mi)
        glDisable(GL_LIGHTING);
 
        /* space for textures */
-       glGenTextures(1, &gp->textures[0]);
-       glGenTextures(1, &gp->textures[1]);
+       glGenTextures(1, &gp->textures[0].id);
+       glGenTextures(1, &gp->textures[1].id);
        gp->visible = 0;
 
-       setup_texture(mi, gp->textures[gp->visible]);
+       setup_texture(mi, &gp->textures[gp->visible]);
 
        /*
        **      want to choose a value for arg randomly if neither -arg nor -no-arg
@@ -919,40 +1482,42 @@ pinit(ModeInfo * mi)
        }
 
        /* define cam variables */
-       gp->cam_x_speed = frand(3.0) - 1.5;
+       gp->cam_x_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5);
        gp->cam_x_phase = random() % 360;
-       gp->cam_y_speed = frand(3.0) - 1.5;
+       gp->cam_y_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5);
        gp->cam_y_phase = random() % 360;
-       gp->cam_z_speed = frand(3.0) - 1.5;
+       gp->cam_z_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5);
        gp->cam_z_phase = random() % 360;
 
        /* initial angular speeds */
-       rangle_vel = frand(0.2) - 0.1;
-       tangle_vel = frand(0.2) - 0.1;
-       rangle_acc = frand(0.002) - 0.001;
-       tangle_acc = frand(0.002) - 0.001;
+       gp->rangle_vel = INITIAL_ANGLE_VEL * frandrange(-.5, 0.5);
+       gp->tangle_vel = INITIAL_ANGLE_VEL * frandrange(-.5, 0.5);
+       gp->rangle_acc = INITIAL_ANGLE_ACC * frandrange(-.5, 0.5);
+       gp->tangle_acc = INITIAL_ANGLE_ACC * frandrange(-.5, 0.5);
 
     /* jwz */
+#if 0
     {
       GLfloat speed = 15;
-      rangle_vel *= speed;
-      tangle_vel *= speed;
-      rangle_acc *= speed;
-      tangle_acc *= speed;
+      gp->rangle_vel *= speed;
+      gp->tangle_vel *= speed;
+      gp->rangle_acc *= speed;
+      gp->tangle_acc *= speed;
     }
+#endif
 
        /* distance is 11 - size */
-       if (size != -1) {
+       if (gp->size != -1) {
                if (zoom) {
                        fprintf(stderr, "-size given. ignoring -zoom.\n");
                        zoom = False;
                }
-               if (size < 1) {
-                       size = 1;
-               } else if (size >= 10) {
-                       size = 10;
+               if (gp->size < 1) {
+                       gp->size = 1;
+               } else if (gp->size >= 10) {
+                       gp->size = 10;
                }
-               size = 11 - size;
+               gp->size = 11 - gp->size;
        }
 
 #ifdef DEBUG
@@ -960,25 +1525,24 @@ printf("phases [%d, %d, %d]\n", gp->cam_x_phase, gp->cam_y_phase, gp->cam_z_phas
 #endif
 }
 
-void
+static void free_gleidescope(ModeInfo * mi);
+
+ENTRYPOINT void
 init_gleidescope(ModeInfo * mi)
 {
        gleidestruct *gp;
        int screen = MI_SCREEN(mi);
 
-
-       if (gleidescope == NULL) {
-               gleidescope = (gleidestruct *) calloc(MI_NUM_SCREENS(mi), sizeof (gleidestruct));
-               if (gleidescope == NULL) {
-                       return;
-               }
-       }
+       MI_INIT(mi, gleidescope, free_gleidescope);
        gp = &gleidescope[screen];
        gp->window = MI_WINDOW(mi);
+    gp->size = -1;
+    gp->list = -1;
 
        if ((gp->glx_context = init_GL(mi)) != NULL) {
 
                reshape_gleidescope(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
+        clear_gl_error(); /* WTF? sometimes "invalid op" from glViewport! */
 
                glDrawBuffer(GL_BACK);
 
@@ -990,7 +1554,7 @@ init_gleidescope(ModeInfo * mi)
        }
 }
 
-void
+ENTRYPOINT void
 draw_gleidescope(ModeInfo * mi)
 {
        gleidestruct    *gp = &gleidescope[MI_SCREEN(mi)];
@@ -1001,6 +1565,9 @@ draw_gleidescope(ModeInfo * mi)
        if (!gp->glx_context)
                return;
 
+    /* Just keep running before the texture has come in. */
+    /* if (gp->waiting_for_image_p) return; */
+
        glDrawBuffer(GL_BACK);
 
        glXMakeCurrent(display, window, *(gp->glx_context));
@@ -1015,42 +1582,39 @@ draw_gleidescope(ModeInfo * mi)
 
 #ifdef GRAB
        if (grab) {
-               grab_frame(mi);
+               grab_frame(display, window);
        }
 #endif
 
        /* need to change texture? */
        if ((gp->start_time != 0) && (duration != -1) && gp->fade == 0) {
                if (gp->start_time + duration <= time((time_t *)0)) {
+#ifdef DEBUG
+                       printf("Start Time: %lu - Current Time: %lu\n", (unsigned long)gp->start_time, (unsigned long)time((time_t *)0));
+                       printf("Changing Texture\n");
+#endif
                        /* get new snapshot (into back buffer) and start fade count */
-                       getSnapshot(mi, gp->textures[1 - gp->visible]);
+                       setup_texture(mi, &gp->textures[1 - gp->visible]);
+                       /* restart fading */
                        gp->fade = 1;
                }
        }
 }
 
-void
-release_gleidescope(ModeInfo * mi)
+static void
+free_gleidescope(ModeInfo * mi)
 {
-       if (gleidescope != NULL) {
-               int screen;
-
-               for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
-                       gleidestruct *gp = &gleidescope[screen];
+       gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
 
-                       /* acd -  is this needed? */
-                       if (gp->glx_context) {
-                               /* Display lists MUST be freed while their glXContext is current. */
-                               glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
+       /* acd -  is this needed? */
+       if (gp->glx_context) {
+               /* Display lists MUST be freed while their glXContext is current. */
+               glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
 
-                               /* acd - was code here for freeing things that are no longer in struct */
-                       }
-               }
-               (void) free((void *) gleidescope);
-               gleidescope = NULL;
+               /* acd - was code here for freeing things that are no longer in struct */
        }
-       
-       FreeAllGL(mi);
 }
 
+XSCREENSAVER_MODULE ("Gleidescope", gleidescope)
+
 #endif