ftp://ftp.linux.ncsu.edu/mirror/ftp.redhat.com/pub/redhat/linux/enterprise/4/en/os...
[xscreensaver] / hacks / glx / gflux.c
index 172f4061925ab86aa9c9b52e63d67502e0c9e1cd..51aa59778b31c20fecd18daba5bc961b8045cbc4 100644 (file)
@@ -2,7 +2,7 @@
 /* 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
  * 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" \
 #include <math.h>
 
 #include "grab-ximage.h"
+#include "gltrackball.h"
 
 
 static enum {wire=0,solid,light,checker,textured,grab} _draw; /* draw style */
@@ -119,41 +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},*/
-    {"-mode", ".gflux.mode", 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", "2", 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},
 };
 
 
@@ -206,7 +205,7 @@ typedef struct {
        int imageMax;
        GLubyte *image;
 #endif
-    GLint texName;
+    GLuint texName;
     GLfloat tex_xscale;
     GLfloat tex_yscale;
     void (*drawFunc)(void);
@@ -239,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)
 {
@@ -342,6 +378,8 @@ void init_gflux(ModeInfo * mi)
     }
     gp = &gflux[screen];
 
+    trackball = gltrackball_init ();
+
     {
       char *s = get_string_resource ("mode", "Mode");
       if (!s || !*s)                       _draw = wire;
@@ -575,19 +613,23 @@ 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);
+                                     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 size = (ximage->width < ximage->height ?
-                  ximage->width : ximage->height);
       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;
 
@@ -614,25 +656,35 @@ grabTexture(void)
   /* 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, real_width-1, i, gray);
+        XPutPixel (ximage, width-1, i, gray);
       }
     for (i = 0; i < real_width; i++)
       {
         XPutPixel (ximage, i, 0, gray);
-        XPutPixel (ximage, i, real_height-1, gray);
+        XPutPixel (ximage, i, height-1, gray);
       }
   }
 
   gflux->imageWidth  = ximage->width;
   gflux->imageHeight = ximage->height;
-  gflux->image = ximage->data;
+  gflux->image = (GLubyte *) ximage->data;
 
-  gflux->tex_xscale = ((GLfloat) real_width  / (GLfloat) ximage->width);
-  gflux->tex_yscale = ((GLfloat) real_height / (GLfloat) ximage->height);
+  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);
@@ -703,6 +755,7 @@ 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);
@@ -742,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)
 {
@@ -763,6 +818,7 @@ 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);
 
@@ -782,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;
+    }
 
 }
 
@@ -805,6 +863,7 @@ 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);
 
@@ -834,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)
@@ -858,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);
 
@@ -882,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 */
@@ -895,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++;