/* -*- 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
*/
# 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" \
"*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;
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},
+/* {"-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},
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},
};
{
{"-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)"},
/* structure for holding the gflux data */
typedef struct {
+ ModeInfo *modeinfo;
int screen_width, screen_height;
GLXContext *glx_context;
Window window;
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;
void initLighting(void);
void initTexture(void);
void loadTexture(void);
+void grabTexture(void);
void createTexture(void);
void displaySolid(void); /* drawFunc implementations */
void displayLight(void);
/* 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)
{
{
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);
loadTexture();
initTexture();
initLighting();
+ break;
+ case grab :
+ gflux->drawFunc = (displayTexture);
+ glEnable(GL_DEPTH_TEST);
+ grabTexture();
+ initTexture();
+ initLighting();
break;
case wire :
default :
}
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));
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)
{
result = malloc(sizeof(GLubyte)*4*width*height);
gflux->imageWidth = width;
- gflux->imageHeight = height;
+ gflux->imageHeight = height;
switch(ppmType) {
case 2 : /* ASCII grey */
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;
}
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 );
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};
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);
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),
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),
glEnd();
}
- time -= _speed;
- anglex -= _rotationx;
- angley -= _rotationy;
- anglez -= _rotationz;
+ if (! button_down_p) {
+ time -= _speed;
+ anglex -= _rotationx;
+ angley -= _rotationy;
+ anglez -= _rotationz;
+ }
}
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);
glEnd();
}
- time -= _speed;
- anglex -= _rotationx;
- angley -= _rotationy;
- anglez -= _rotationz;
+ if (! button_down_p) {
+ time -= _speed;
+ anglex -= _rotationx;
+ angley -= _rotationy;
+ anglez -= _rotationz;
+ }
}
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);
glEnd();
}
- time -= _speed;
- anglex -= _rotationx;
- angley -= _rotationy;
- anglez -= _rotationz;
+ if (! button_down_p) {
+ time -= _speed;
+ anglex -= _rotationx;
+ angley -= _rotationy;
+ anglez -= _rotationz;
+ }
}
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);
glEnd();
}
- time -= _speed;
- anglex -= _rotationx;
- angley -= _rotationy;
- anglez -= _rotationz;
+ if (! button_down_p) {
+ time -= _speed;
+ anglex -= _rotationx;
+ angley -= _rotationy;
+ anglez -= _rotationz;
+ }
}
/* generates new ripples */
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++;