ftp://ftp.linux.ncsu.edu/mirror/ftp.redhat.com/pub/redhat/linux/enterprise/4/en/os...
[xscreensaver] / hacks / glx / gflux.c
index 23fce87c78301571bcdde8ecfbd8311e377ffeca..51aa59778b31c20fecd18daba5bc961b8045cbc4 100644 (file)
@@ -1,9 +1,8 @@
 /* -*- Mode: C; tab-width: 4 -*- emacs friendly */
-
 /* gflux - creates a fluctuating 3D grid 
  * requires OpenGL or MesaGL
  * 
- * Copyright (c) Josiah Pease, 2000
+ * Copyright (c) Josiah Pease, 2000, 2003
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
  * the above copyright notice appear in all copies and that both that
  * 04 July 2000 : majour bug hunt, xscreensaver code rewritten
  * 08 July 2000 : texture mapping, rotation and zoom added
  * 21 July 2000 : cleaned up code from bug hunts, manpage written
+ * 24 November 2000 : fixed x co-ord calculation in solid - textured
+ * 05 March 2001 : put back non pnmlib code with #ifdefs
+ * 11 May 2002 : fixed image problems with large images
  */
 
 
-/*-
- * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
- * otherwise caddr_t is not defined correctly
- */
-
-#include <X11/Intrinsic.h>
-
-
 #ifdef STANDALONE
 # define PROGCLASS                                             "gflux"
 # define HACK_INIT                                             init_gflux
 # define HACK_DRAW                                             draw_gflux
 # define HACK_RESHAPE                                  reshape_gflux
+# define HACK_HANDLE_EVENT                             gflux_handle_event
+# define EVENT_MASK                                            PointerMotionMask
 # define gflux_opts                                            xlockmore_opts
 #define DEFAULTS                        "*delay:               20000   \n" \
                                                                                "*showFPS:      False   \n" \
+                                        "*mode:         light" "\n" \
                                         "*squares:      19      \n" \
                                                                                "*resolution:   0       \n" \
-                                        "*draw:         0       \n" \
                                         "*flat:         0       \n" \
                                         "*speed:        0.05    \n" \
                                         "*rotationx:    0.01    \n" \
@@ -63,9 +59,9 @@
                                         "*rotationz:    0.1     \n" \
                                         "*waves:        3       \n" \
                                         "*waveChange:   50      \n" \
-                                        "*waveHeight:   1.0     \n" \
-                                        "*waveFreq:    3.0     \n" \
-                                        "*zoom:         1.0     \n" 
+                                        "*waveHeight:  0.8      \n" \
+                                        "*waveFreq:    3.0      \n" \
+                                        "*zoom:        1.0      \n" 
 
 
 # include "xlockmore.h"                                /* from the xscreensaver distribution */
 
 #ifdef USE_GL /* whole file */
 
-#ifdef HAVE_XPM
-# include <X11/xpm.h>
-# ifndef PIXEL_ALREADY_TYPEDEFED
-# define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
-# endif
-#endif
-
 #ifdef HAVE_XMU
 # ifndef VMS
 #  include <X11/Xmu/Drawing.h>
 # endif /* VMS */
 #endif
 
+#ifdef HAVE_PPM
+#include <ppm.h>
+#endif
+
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
 
 
 #include <math.h>
 
-static enum {wire=0,solid,light,checker,textured} _draw; /* draw style */
+#include "grab-ximage.h"
+#include "gltrackball.h"
+
+
+static enum {wire=0,solid,light,checker,textured,grab} _draw; /* draw style */
 static int _squares = 19;                                 /* grid size */
 static int _resolution = 4;                    /* wireframe resolution */
 static int _flat = 0;
@@ -118,40 +115,44 @@ static int _waveChange = 50;
 static float _waveHeight = 1.0;
 static float _waveFreq = 3.0;
 
+static trackball_state *trackball;
+static Bool button_down_p = False;
+
 #define WIDTH 320
 #define HEIGHT 240
 
 static XrmOptionDescRec opts[] = {
-    {"-squares", ".gflux.squares", XrmoptionSepArg, (caddr_t) NULL},
-    {"-resolution", ".gflux.resolution", XrmoptionSepArg, (caddr_t) NULL},
-    {"-draw", ".gflux.draw", XrmoptionSepArg, (caddr_t) NULL},
-    {"-flat", ".gflux.flat", XrmoptionSepArg, (caddr_t) NULL},
-    {"-speed", ".gflux.speed", XrmoptionSepArg, (caddr_t) NULL},
-    {"-rotationx", ".gflux.rotationx", XrmoptionSepArg, (caddr_t) NULL},
-    {"-rotationy", ".gflux.rotationy", XrmoptionSepArg, (caddr_t) NULL},
-    {"-rotationz", ".gflux.rotationz", XrmoptionSepArg, (caddr_t) NULL},
-    {"-waves", ".gflux.waves", XrmoptionSepArg, (caddr_t) NULL},
-    {"-waveChange", ".gflux.waveChange", XrmoptionSepArg, (caddr_t) NULL},
-    {"-waveHeight", ".gflux.waveHeight", XrmoptionSepArg, (caddr_t) NULL},
-    {"-waveFreq", ".gflux.waveFreq", XrmoptionSepArg, (caddr_t) NULL},
-    {"-zoom", ".gflux.zoom", XrmoptionSepArg, (caddr_t) NULL},
+    {"-squares", ".gflux.squares", XrmoptionSepArg, 0},
+    {"-resolution", ".gflux.resolution", XrmoptionSepArg, 0},
+/*    {"-draw", ".gflux.draw", XrmoptionSepArg, 0},*/
+    {"-mode", ".gflux.mode", XrmoptionSepArg, 0},
+    {"-flat", ".gflux.flat", XrmoptionSepArg, 0},
+    {"-speed", ".gflux.speed", XrmoptionSepArg, 0},
+    {"-rotationx", ".gflux.rotationx", XrmoptionSepArg, 0},
+    {"-rotationy", ".gflux.rotationy", XrmoptionSepArg, 0},
+    {"-rotationz", ".gflux.rotationz", XrmoptionSepArg, 0},
+    {"-waves", ".gflux.waves", XrmoptionSepArg, 0},
+    {"-waveChange", ".gflux.waveChange", XrmoptionSepArg, 0},
+    {"-waveHeight", ".gflux.waveHeight", XrmoptionSepArg, 0},
+    {"-waveFreq", ".gflux.waveFreq", XrmoptionSepArg, 0},
+    {"-zoom", ".gflux.zoom", XrmoptionSepArg, 0},
 };
 
 
 static argtype vars[] = {
-    {(caddr_t *) & _squares, "squares", "Squares", "19", t_Int},
-    {(caddr_t *) & _resolution, "resolution", "Resolution", "4", t_Int},
-    {(caddr_t *) & _draw, "draw", "Draw", "0", t_Int},
-    {(caddr_t *) & _flat, "flat", "Flat", "0", t_Int},
-    {(caddr_t *) & _speed, "speed", "Speed", "0.05", t_Float},
-    {(caddr_t *) & _rotationx, "rotationx", "Rotationx", "0.01", t_Float},
-    {(caddr_t *) & _rotationy, "rotationy", "Rotationy", "0.0", t_Float},
-    {(caddr_t *) & _rotationz, "rotationz", "Rotationz", "0.1", t_Float},
-    {(caddr_t *) & _waves, "waves", "Waves", "3", t_Int},
-    {(caddr_t *) & _waveChange, "waveChange", "WaveChange", "50", t_Int},
-    {(caddr_t *) & _waveHeight, "waveHeight", "WaveHeight", "1.0", t_Float},
-    {(caddr_t *) & _waveFreq, "waveFreq", "WaveFreq", "3.0", t_Float},
-    {(caddr_t *) & _zoom, "zoom", "Zoom", "1.0", t_Float},
+    {&_squares, "squares", "Squares", "19", t_Int},
+    {&_resolution, "resolution", "Resolution", "4", t_Int},
+/*    {&_draw, "draw", "Draw", "2", t_Int},*/
+    {&_flat, "flat", "Flat", "0", t_Int},
+    {&_speed, "speed", "Speed", "0.05", t_Float},
+    {&_rotationx, "rotationx", "Rotationx", "0.01", t_Float},
+    {&_rotationy, "rotationy", "Rotationy", "0.0", t_Float},
+    {&_rotationz, "rotationz", "Rotationz", "0.1", t_Float},
+    {&_waves, "waves", "Waves", "3", t_Int},
+    {&_waveChange, "waveChange", "WaveChange", "50", t_Int},
+    {&_waveHeight, "waveHeight", "WaveHeight", "1.0", t_Float},
+    {&_waveFreq, "waveFreq", "WaveFreq", "3.0", t_Float},
+    {&_zoom, "zoom", "Zoom", "1.0", t_Float},
 };
 
 
@@ -159,7 +160,7 @@ static OptionStruct desc[] =
 {
     {"-squares num", "size of grid in squares (19)"},
     {"-resolution num", "detail of lines making grid, wireframe only (4)"},
-    {"-draw num", "draw method to use: 0=wireframe 1=solid 2=lit (0)"},
+/*    {"-draw num", "draw method to use: 0=wireframe 1=solid 2=lit (0)"},*/
     {"-flat num", "shading method, not wireframe: 0=smooth 1=flat (0)"},
     {"-speed num", "speed of waves (0.05)"},
     {"-rotationx num", "speed of xrotation (0.01)"},
@@ -184,6 +185,7 @@ ModStruct   gflux_description =
 
 /* structure for holding the gflux data */
 typedef struct {
+    ModeInfo *modeinfo;
     int screen_width, screen_height;
     GLXContext *glx_context;
     Window window;
@@ -196,8 +198,16 @@ typedef struct {
     GLfloat colour[3];
     int imageWidth;
     int imageHeight;
-    GLubyte *image;
+#ifdef HAVE_PPM
+       pixval imageMax;
+    pixel **image;
+#else
+       int imageMax;
+       GLubyte *image;
+#endif
     GLuint texName;
+    GLfloat tex_xscale;
+    GLfloat tex_yscale;
     void (*drawFunc)(void);
 } gfluxstruct;
 static gfluxstruct *gflux = NULL;
@@ -206,6 +216,7 @@ static gfluxstruct *gflux = NULL;
 void initLighting(void);
 void initTexture(void);
 void loadTexture(void);
+void grabTexture(void);
 void createTexture(void);
 void displaySolid(void);            /* drawFunc implementations */
 void displayLight(void);
@@ -227,6 +238,43 @@ double getGrid(double,double,double);
 /* BEGINNING OF FUNCTIONS */
 
 
+Bool
+gflux_handle_event (ModeInfo *mi, XEvent *event)
+{
+  if (event->xany.type == ButtonPress &&
+      event->xbutton.button & Button1)
+    {
+      button_down_p = True;
+      gltrackball_start (trackball,
+                         event->xbutton.x, event->xbutton.y,
+                         MI_WIDTH (mi), MI_HEIGHT (mi));
+      return True;
+    }
+  else if (event->xany.type == ButtonRelease &&
+           event->xbutton.button & Button1)
+    {
+      button_down_p = False;
+      return True;
+    }
+  else if (event->xany.type == MotionNotify &&
+           button_down_p)
+    {
+      gltrackball_track (trackball,
+                         event->xmotion.x, event->xmotion.y,
+                         MI_WIDTH (mi), MI_HEIGHT (mi));
+      return True;
+    }
+
+  return False;
+}
+
+
+static void
+userRot(void)
+{
+  gltrackball_rotate (trackball);
+}
+
 /* draw the gflux once */
 void draw_gflux(ModeInfo * mi)
 {
@@ -269,6 +317,10 @@ void initializeGL(ModeInfo *mi, GLsizei width, GLsizei height)
 {
   reshape_gflux(mi, width, height);
   glViewport( 0, 0, width, height ); 
+
+  gflux->tex_xscale = 1.0;  /* maybe changed later */
+  gflux->tex_yscale = 1.0;
+
   switch(_draw) {
     case solid :
       gflux->drawFunc = (displaySolid);
@@ -292,6 +344,13 @@ void initializeGL(ModeInfo *mi, GLsizei width, GLsizei height)
       loadTexture();
       initTexture();
       initLighting();
+    break;
+       case grab :
+      gflux->drawFunc = (displayTexture);
+      glEnable(GL_DEPTH_TEST);
+      grabTexture();
+      initTexture();
+      initLighting();
     break;
     case wire :
        default :
@@ -319,6 +378,28 @@ void init_gflux(ModeInfo * mi)
     }
     gp = &gflux[screen];
 
+    trackball = gltrackball_init ();
+
+    {
+      char *s = get_string_resource ("mode", "Mode");
+      if (!s || !*s)                       _draw = wire;
+      else if (!strcasecmp (s, "wire"))    _draw = wire;
+      else if (!strcasecmp (s, "solid"))   _draw = solid;
+      else if (!strcasecmp (s, "light"))   _draw = light;
+      else if (!strcasecmp (s, "checker")) _draw = checker;
+      else if (!strcasecmp (s, "stdin"))   _draw = textured;
+      else if (!strcasecmp (s, "grab"))    _draw = grab;
+      else
+        {
+          fprintf (stderr,
+                   "%s: mode must be one of: wire, solid, "
+                   "light, checker, or grab; not \"%s\"\n",
+                   progname, s);
+          exit (1);
+        }
+    }
+
+    gp->modeinfo = mi;
     gp->window = MI_WINDOW(mi);
     if ((gp->glx_context = init_GL(mi)) != NULL) {
         reshape_gflux(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
@@ -340,7 +421,53 @@ void release_gflux(ModeInfo * mi)
     FreeAllGL(mi);
 }
 
-/* loads several different types of PNM image from stdin */
+#ifdef HAVE_PPM
+
+/* load pnm from stdin using pnm libs */
+void loadTexture(void)
+{
+    FILE *file = stdin;
+       gflux->image = ppm_readppm( file, 
+                       &(gflux->imageHeight), &(gflux->imageWidth), &(gflux->imageMax) );
+}
+
+/* creates an image for texture mapping */
+void createTexture(void)
+{
+    int i,j,c;
+    pixel **result;
+
+       gflux->imageHeight = gflux->imageWidth = 8;
+
+       result = ppm_allocarray(gflux->imageHeight,gflux->imageWidth);
+    for(i=0;i<gflux->imageHeight;i++) {
+        for(j=0;j<gflux->imageWidth;j++) {
+            c = (((i)%2 ^ (j)%2) ? 100 : 200 );
+                       PPM_ASSIGN( result[i][j] , c, c, c );
+        }
+    }
+       gflux->image = result;
+}
+
+/* specifies image as texture */    
+void initTexture(void)
+{
+       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+       glGenTextures(1, &gflux->texName);
+       glBindTexture(GL_TEXTURE_2D, gflux->texName);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+       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);
+
+    clear_gl_error();
+       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, gflux->imageWidth,
+                       gflux->imageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, *(gflux->image));
+    check_gl_error("texture");
+}
+
+#else /* HAVE_PPM FALSE */
+
 #define presult(A,B,C) (*(result+(A)*(gflux->imageWidth)*4+(B)*4+(C)))
 void loadTexture(void)
 {
@@ -369,7 +496,7 @@ void loadTexture(void)
 
     result = malloc(sizeof(GLubyte)*4*width*height);
     gflux->imageWidth = width;
-       gflux->imageHeight = height;
+    gflux->imageHeight = height;
 
     switch(ppmType) {
         case 2 :    /* ASCII grey */
@@ -385,7 +512,7 @@ void loadTexture(void)
         case 3 :    /* ASCII rgb */
             for(i=0;i<height;i++) {
                 for(j=0;j<width;j++) {
-                    fscanf(file,"%d %d %d",&red,&green,&blue);
+                   fscanf(file,"%d %d %d",&red,&green,&blue);
                     presult(j,i,0) = red;
                     presult(j,i,1) = green;
                     presult(j,i,2) = blue;
@@ -417,18 +544,17 @@ void loadTexture(void)
             }
         break;
     }
-       gflux->image = result;
+    gflux->image = result;
 }
 
-/* creates an image for texture mapping */
 void createTexture(void)
 {
     int i,j,c;
     GLubyte *result;
 
-       gflux->imageHeight = gflux->imageWidth = 8;
+    gflux->imageHeight = gflux->imageWidth = 8;
 
-       result = malloc(sizeof(GLubyte)*4*gflux->imageHeight*gflux->imageWidth);
+    result = malloc(sizeof(GLubyte)*4*gflux->imageHeight*gflux->imageWidth);
     for(i=0;i<gflux->imageHeight;i++) {
         for(j=0;j<gflux->imageWidth;j++) {
             c = (((i)%2 ^ (j)%2) ? 100 : 200 );
@@ -438,26 +564,133 @@ void createTexture(void)
             presult(i,j,3) = (GLubyte) 255;
         }
     }
-       gflux->image = result;
+    gflux->image = result;
 }
-#undef presult
 
-/* specifies image as texture */    
+/* specifies image as texture */
 void initTexture(void)
 {
-       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-       glGenTextures(1, &gflux->texName);
-       glBindTexture(GL_TEXTURE_2D, gflux->texName);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-       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);
     clear_gl_error();
-       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gflux->imageWidth,
-                       gflux->imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, gflux->image);
-    check_gl_error("texture");
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glGenTextures(1, &gflux->texName);
+    glBindTexture(GL_TEXTURE_2D, gflux->texName);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    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);
+    check_gl_error("texture parameter");
+
+    /* Bail out if the texture is too large. */
+    {
+      GLint width;
+      glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, gflux->imageWidth,
+                   gflux->imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+      glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0,
+                                GL_TEXTURE_WIDTH, &width);
+      if (width <= 0)
+        {
+          glGetIntegerv (GL_MAX_TEXTURE_SIZE, &width);
+          fprintf (stderr,
+                   "%s: texture too large (%dx%d -- probable max %dx%d)\n",
+                   progname, gflux->imageWidth, gflux->imageHeight,
+                   width, width);
+          return;
+        }
+    }
+
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gflux->imageWidth,
+            gflux->imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, gflux->image);
+    check_gl_error("texture creation");
 }
 
+#undef presult
+#endif
+
+
+void
+grabTexture(void)
+{
+  int real_width  = gflux->modeinfo->xgwa.width;
+  int real_height = gflux->modeinfo->xgwa.height;
+  XImage *ximage = screen_to_ximage (gflux->modeinfo->xgwa.screen,
+                                     gflux->window,
+                                     NULL);
+  Bool bigimage = False;
+  int size = 0;
+
+  if (ximage->width > 1280 ||   /* that's too damned big... */
+      ximage->height > 1280)
+    {
+      Display *dpy = gflux->modeinfo->dpy;
+      Visual *v = gflux->modeinfo->xgwa.visual;
+      int real_size = (ximage->width < ximage->height ?
+                       real_width : real_height);
+      XImage *x2;
+      int x, y, xoff, yoff;
+      size = (ximage->width < ximage->height ?
+              ximage->width : ximage->height);
+      bigimage = True;
+
+      if (size > 1024) size = 1024;
+
+      x2 = XCreateImage (dpy, v, 32, ZPixmap, 0, 0, size, size, 32, 0);
+      xoff = (real_width  > size ? (random() % (real_width  - size)) : 0);
+      yoff = (real_height > size ? (random() % (real_height - size)) : 0);
+
+# if 0
+      fprintf(stderr, "%s: cropping texture from %dx%d to %dx%d @ %d,%d\n",
+              progname, ximage->width, ximage->height, x2->width, x2->height,
+              xoff, yoff);
+# endif
+      x2->data = ximage->data;  /* we can reuse the same array */
+      for (y = 0; y < x2->height; y++)
+        for (x = 0; x < x2->width; x++)
+          XPutPixel (x2, x, y, XGetPixel (ximage, x+xoff, y+yoff));
+
+      real_width = real_height = real_size;
+      ximage->data = 0;
+      XDestroyImage (ximage);
+      ximage = x2;
+    }
+
+  /* Add a border. */
+  {
+    unsigned long gray = 0xAAAAAAAAL;  /* so shoot me */
+    int width  = (bigimage ? size : real_width);
+    int height = (bigimage ? size : real_height);
+    int i;
+    for (i = 0; i < real_height; i++)
+      {
+        XPutPixel (ximage, 0, i, gray);
+        XPutPixel (ximage, width-1, i, gray);
+      }
+    for (i = 0; i < real_width; i++)
+      {
+        XPutPixel (ximage, i, 0, gray);
+        XPutPixel (ximage, i, height-1, gray);
+      }
+  }
+
+  gflux->imageWidth  = ximage->width;
+  gflux->imageHeight = ximage->height;
+  gflux->image = (GLubyte *) ximage->data;
+
+  if (bigimage)  /* don't scale really large images */
+    {
+      gflux->tex_xscale = 1;
+      gflux->tex_yscale = 1;
+    }
+  else
+    {
+      gflux->tex_xscale = ((GLfloat) real_width  / (GLfloat) ximage->width);
+      gflux->tex_yscale = ((GLfloat) real_height / (GLfloat) ximage->height);
+    }
+
+  ximage->data = 0;
+  XDestroyImage (ximage);
+}
+
+
 void initLighting(void)
 {
     static float ambientA[] = {0.0, 0.0, 0.0, 1.0};
@@ -506,6 +739,12 @@ void displayTexture(void)
     double dx = 2.0/((double)_squares);
     double dy = 2.0/((double)_squares);
 
+    double du = 2.0/((double)_squares);
+    double dv = 2.0/((double)_squares);
+
+    double xs = gflux->tex_xscale;
+    double ys = gflux->tex_yscale;
+
        glMatrixMode (GL_TEXTURE);
        glLoadIdentity ();
        glTranslatef(-1,-1,0);
@@ -516,20 +755,25 @@ void displayTexture(void)
     glRotatef(anglex,1,0,0);
     glRotatef(angley,0,1,0);
     glRotatef(anglez,0,0,1);
+    userRot();
     glScalef(1,1,(GLfloat)_waveHeight);
     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        glEnable(GL_TEXTURE_2D);
+
+    clear_gl_error();
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
        glBindTexture(GL_TEXTURE_2D, gflux->texName);
-       glColor3f(0.5,0.5,0.5);
+    check_gl_error("texture binding");
 
-    for(x=-1,u=0;x<=1;x+=dx,u+=dx) {
+       glColor3f(0.5,0.5,0.5);
+    for(x=-1,u= 0;x<0.9999;x+=dx,u+=du) {
         glBegin(GL_QUAD_STRIP);
-        for(y=-1,v=0;y<=1;y+=dy,v+=dx) {
+        for(y=-1,v= 0;y<=1;y+=dy,v+=dv) {
             z = getGrid(x,y,time);
         /*  genColour(z);
             glColor3fv(gflux->colour);
-        */  glTexCoord2f(u,v);
+        */  glTexCoord2f(u*xs,v*ys);
             glNormal3f(
                 getGrid(x+dx,y,time)-getGrid(x-dx,y,time),
                 getGrid(x,y+dy,time)-getGrid(x,y-dy,time),
@@ -540,7 +784,7 @@ void displayTexture(void)
             z = getGrid(x+dx,y,time);
         /*  genColour(z);
             glColor3fv(gflux->colour);
-        */  glTexCoord2f(u+dx,v);
+        */  glTexCoord2f((u+du)*xs,v*ys);
             glNormal3f(
                 getGrid(x+dx+dx,y,time)-getGrid(x,y,time),
                 getGrid(x+dx,y+dy,time)-getGrid(x+dx,y-dy,time),
@@ -551,10 +795,12 @@ void displayTexture(void)
         glEnd();
     }
 
-    time -= _speed;
-    anglex -= _rotationx;
-    angley -= _rotationy;
-    anglez -= _rotationz;
+    if (! button_down_p) {
+      time -= _speed;
+      anglex -= _rotationx;
+      angley -= _rotationy;
+      anglez -= _rotationz;
+    }
 }
 void displaySolid(void)
 {
@@ -572,10 +818,11 @@ void displaySolid(void)
     glRotatef(anglex,1,0,0);
     glRotatef(angley,0,1,0);
     glRotatef(anglez,0,0,1);
+    userRot();
     glScalef(1,1,(GLfloat)_waveHeight);
     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
 
-    for(x=-1;x<=1;x+=dx) {
+    for(x=-1;x<0.9999;x+=dx) {
         glBegin(GL_QUAD_STRIP);
         for(y=-1;y<=1;y+=dy) {
             z = getGrid(x,y,time);
@@ -591,10 +838,12 @@ void displaySolid(void)
         glEnd();
     }
 
-    time -= _speed;
-    anglex -= _rotationx;
-    angley -= _rotationy;
-    anglez -= _rotationz;
+    if (! button_down_p) {
+      time -= _speed;
+      anglex -= _rotationx;
+      angley -= _rotationy;
+      anglez -= _rotationz;
+    }
 
 }
 
@@ -614,10 +863,11 @@ void displayLight(void)
     glRotatef(anglex,1,0,0);
     glRotatef(angley,0,1,0);
     glRotatef(anglez,0,0,1);
+    userRot();
     glScalef(1,1,(GLfloat)_waveHeight);
     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
 
-    for(x=-1;x<=1;x+=dx) {
+    for(x=-1;x<0.9999;x+=dx) {
         glBegin(GL_QUAD_STRIP);
         for(y=-1;y<=1;y+=dy) {
             z = getGrid(x,y,time);
@@ -643,10 +893,12 @@ void displayLight(void)
         glEnd();
     }
 
-    time -= _speed;
-    anglex -= _rotationx;
-    angley -= _rotationy;
-    anglez -= _rotationz;
+    if (! button_down_p) {
+      time -= _speed;
+      anglex -= _rotationx;
+      angley -= _rotationy;
+      anglez -= _rotationz;
+    }
 }
 
 void displayWire(void)
@@ -667,6 +919,7 @@ void displayWire(void)
     glRotatef(anglex,1,0,0);
     glRotatef(angley,0,1,0);
     glRotatef(anglez,0,0,1);
+    userRot();
     glScalef(1,1,(GLfloat)_waveHeight);
     glClear(GL_COLOR_BUFFER_BIT);
 
@@ -691,10 +944,12 @@ void displayWire(void)
         glEnd();
     }
 
-    time -= _speed;
-    anglex -= _rotationx;
-    angley -= _rotationy;
-    anglez -= _rotationz;
+    if (! button_down_p) {
+      time -= _speed;
+      anglex -= _rotationx;
+      angley -= _rotationy;
+      anglez -= _rotationz;
+    }
 }
 
 /* generates new ripples */
@@ -704,12 +959,14 @@ void calcGrid(void)
     double tmp;
     static int newWave;
 
+    if (button_down_p) return;
+
     tmp = 1.0/((double)_waveChange);
     if(!(counter%_waveChange)) {
         newWave = ((int)(counter*tmp))%_waves;
-        gflux->dispx[newWave] = 1.0 - ((double)random())/RAND_MAX;
-        gflux->dispy[newWave] = 1.0 - ((double)random())/RAND_MAX;
-        gflux->freq[newWave] = _waveFreq * ((float)random())/RAND_MAX;
+        gflux->dispx[newWave] = -frand(1.0);
+        gflux->dispy[newWave] = -frand(1.0);
+        gflux->freq[newWave] = _waveFreq * frand(1.0);
         gflux->wa[newWave] = 0.0;
     }
     counter++;