ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-4.22.tar.gz
[xscreensaver] / hacks / glx / gflux.c
1 /* -*- Mode: C; tab-width: 4 -*- emacs friendly */
2 /* gflux - creates a fluctuating 3D grid 
3  * requires OpenGL or MesaGL
4  * 
5  * Copyright (c) Josiah Pease, 2000, 2003
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation.  No representations are made about the suitability of this
11  * software for any purpose.  It is provided "as is" without express or 
12  * implied warranty.
13  *
14  * Thanks go to all those who worked on...
15  * MesaGL, OpenGL, UtahGLX, XFree86, gcc, vim, rxvt, the PNM (anymap) format
16  * xscreensaver and the thousands of other tools, apps and daemons that make
17  * linux usable  
18  * Personal thanks to Kevin Moss, Paul Sheahee and Jamie Zawinski
19  * 
20  * some xscreensaver code lifted from superquadrics.  Most other glx hacks 
21  * used as reference at some time.
22  *
23  * This hack and others can cause UtahGLX to crash my X server
24  * wireframe looks good with software only rendering anyway
25  * If anyone can work out why and supply a fix I'd love to hear from them
26  * 
27  * Josiah Pease <gfluxcode@jpease.force9.co.uk> 21 July 2000
28  * 
29  * History 
30  * 10 June 2000 : wireframe rippling grid standalone written
31  * 18 June 2000 : xscreensaver code added
32  * 25 June 2000 : solid and light added
33  * 04 July 2000 : majour bug hunt, xscreensaver code rewritten
34  * 08 July 2000 : texture mapping, rotation and zoom added
35  * 21 July 2000 : cleaned up code from bug hunts, manpage written
36  * 24 November 2000 : fixed x co-ord calculation in solid - textured
37  * 05 March 2001 : put back non pnmlib code with #ifdefs
38  * 11 May 2002 : fixed image problems with large images
39  */
40
41
42 #ifdef STANDALONE
43 # define PROGCLASS                                              "gflux"
44 # define HACK_INIT                                              init_gflux
45 # define HACK_DRAW                                              draw_gflux
46 # define HACK_RESHAPE                                   reshape_gflux
47 # define HACK_HANDLE_EVENT                              gflux_handle_event
48 # define EVENT_MASK                                             PointerMotionMask
49 # define gflux_opts                                             xlockmore_opts
50 #define DEFAULTS                        "*delay:                20000   \n" \
51                                                                                 "*showFPS:      False   \n" \
52                                         "*mode:         light" "\n" \
53                                         "*useSHM:      True     \n" 
54
55
56 # include "xlockmore.h"                         /* from the xscreensaver distribution */
57 #else /* !STANDALONE */
58 # include "xlock.h"                                     /* from the xlockmore distribution */
59 #endif /* !STANDALONE */
60
61 #ifdef USE_GL /* whole file */
62
63 #ifdef HAVE_XMU
64 # ifndef VMS
65 #  include <X11/Xmu/Drawing.h>
66 #else  /* VMS */
67 #  include <Xmu/Drawing.h>
68 # endif /* VMS */
69 #endif
70
71 #undef countof
72 #define countof(x) (sizeof((x))/sizeof((*x)))
73
74 #include <stdlib.h>
75 #include <stdio.h>
76
77 #include <GL/gl.h>
78 #include <GL/glu.h>
79 #include <GL/glx.h>
80
81 #include <math.h>
82
83 #include "grab-ximage.h"
84 #include "gltrackball.h"
85
86
87 static enum {wire=0,solid,light,checker,grab} _draw; /* draw style */
88 static int _squares = 19;                                 /* grid size */
89 static int _resolution = 4;                    /* wireframe resolution */
90 static int _flat = 0;
91
92 static float _speed = 0.05;
93 static float _rotationx = 0.01;
94 static float _rotationy = 0.0;
95 static float _rotationz = 0.1;
96 static float _zoom = 1.0;
97
98 static int _waves = 3;
99 static int _waveChange = 50;
100 static float _waveHeight = 1.0;
101 static float _waveFreq = 3.0;
102
103 static trackball_state *trackball;
104 static Bool button_down_p = False;
105
106 #define WIDTH 320
107 #define HEIGHT 240
108
109 static XrmOptionDescRec opts[] = {
110     {"-squares", ".gflux.squares", XrmoptionSepArg, 0},
111     {"-resolution", ".gflux.resolution", XrmoptionSepArg, 0},
112 /*    {"-draw", ".gflux.draw", XrmoptionSepArg, 0},*/
113     {"-mode", ".gflux.mode", XrmoptionSepArg, 0},
114     {"-wireframe", ".gflux.mode", XrmoptionNoArg, "wire"},
115     {"-flat", ".gflux.flat", XrmoptionSepArg, 0},
116     {"-speed", ".gflux.speed", XrmoptionSepArg, 0},
117     {"-rotationx", ".gflux.rotationx", XrmoptionSepArg, 0},
118     {"-rotationy", ".gflux.rotationy", XrmoptionSepArg, 0},
119     {"-rotationz", ".gflux.rotationz", XrmoptionSepArg, 0},
120     {"-waves", ".gflux.waves", XrmoptionSepArg, 0},
121     {"-waveChange", ".gflux.waveChange", XrmoptionSepArg, 0},
122     {"-waveHeight", ".gflux.waveHeight", XrmoptionSepArg, 0},
123     {"-waveFreq", ".gflux.waveFreq", XrmoptionSepArg, 0},
124     {"-zoom", ".gflux.zoom", XrmoptionSepArg, 0},
125 };
126
127
128 static argtype vars[] = {
129     {&_squares, "squares", "Squares", "19", t_Int},
130     {&_resolution, "resolution", "Resolution", "4", t_Int},
131 /*    {&_draw, "draw", "Draw", "2", t_Int},*/
132     {&_flat, "flat", "Flat", "0", t_Int},
133     {&_speed, "speed", "Speed", "0.05", t_Float},
134     {&_rotationx, "rotationx", "Rotationx", "0.01", t_Float},
135     {&_rotationy, "rotationy", "Rotationy", "0.0", t_Float},
136     {&_rotationz, "rotationz", "Rotationz", "0.1", t_Float},
137     {&_waves, "waves", "Waves", "3", t_Int},
138     {&_waveChange, "waveChange", "WaveChange", "50", t_Int},
139     {&_waveHeight, "waveHeight", "WaveHeight", "1.0", t_Float},
140     {&_waveFreq, "waveFreq", "WaveFreq", "3.0", t_Float},
141     {&_zoom, "zoom", "Zoom", "1.0", t_Float},
142 };
143
144
145 static OptionStruct desc[] =
146 {
147     {"-squares num", "size of grid in squares (19)"},
148     {"-resolution num", "detail of lines making grid, wireframe only (4)"},
149 /*    {"-draw num", "draw method to use: 0=wireframe 1=solid 2=lit (0)"},*/
150     {"-flat num", "shading method, not wireframe: 0=smooth 1=flat (0)"},
151     {"-speed num", "speed of waves (0.05)"},
152     {"-rotationx num", "speed of xrotation (0.01)"},
153     {"-rotationy num", "speed of yrotation (0.00)"},
154     {"-rotationz num", "speed of zrotation (0.10)"},
155     {"-waves num", "number of simultanious waves (3)"},
156     {"-waveChange num", "number of cyles for a wave to change (50)"},
157     {"-waveHeight num", "height of waves (1.0)"},
158     {"-waveFreq num", "max frequency of a wave (3.0)"},
159     {"-zoom num", "camera control (1.0)"},
160 };
161
162 ModeSpecOpt gflux_opts = {countof(opts), opts, countof(vars), vars, desc};
163
164 #ifdef USE_MODULES
165 ModStruct   gflux_description =
166 {"gflux", "init_gflux", "draw_gflux", "release_gflux",
167  "draw_gflux", "init_gflux", NULL, &gflux_opts,
168  1000, 1, 2, 1, 4, 1.0, "",
169  "Gflux: an OpenGL gflux", 0, NULL};
170 #endif
171
172 /* structure for holding the gflux data */
173 typedef struct {
174     ModeInfo *modeinfo;
175     int screen_width, screen_height;
176     GLXContext *glx_context;
177     Window window;
178     XColor fg, bg;
179 #define MAXWAVES 10   /* should be dynamic    */
180     double wa[MAXWAVES];
181     double freq[MAXWAVES];
182     double dispy[MAXWAVES];
183     double dispx[MAXWAVES];
184     GLfloat colour[3];
185     GLuint texName;
186     GLfloat tex_xscale;
187     GLfloat tex_yscale;
188     XRectangle img_geom;
189     int img_width, img_height;
190     void (*drawFunc)(void);
191 } gfluxstruct;
192 static gfluxstruct *gflux = NULL;
193
194 /* prototypes */
195 void initLighting(void);
196 void grabTexture(void);
197 void createTexture(void);
198 void displaySolid(void);            /* drawFunc implementations */
199 void displayLight(void);
200 void displayTexture(void);
201 void displayWire(void);
202 void calcGrid(void);
203 double getGrid(double,double,double);
204
205 /* as macro for speed */
206 /* could do with colour cycling here */
207 /* void genColour(double);*/
208 #define genColour(X) \
209 {\
210     gflux->colour[0] = 0.0;\
211     gflux->colour[1] = 0.5+0.5*(X);\
212     gflux->colour[2] = 0.5-0.5*(X);\
213 }
214
215 /* BEGINNING OF FUNCTIONS */
216
217
218 Bool
219 gflux_handle_event (ModeInfo *mi, XEvent *event)
220 {
221   if (event->xany.type == ButtonPress &&
222       event->xbutton.button == Button1)
223     {
224       button_down_p = True;
225       gltrackball_start (trackball,
226                          event->xbutton.x, event->xbutton.y,
227                          MI_WIDTH (mi), MI_HEIGHT (mi));
228       return True;
229     }
230   else if (event->xany.type == ButtonRelease &&
231            event->xbutton.button == Button1)
232     {
233       button_down_p = False;
234       return True;
235     }
236   else if (event->xany.type == ButtonPress &&
237            (event->xbutton.button == Button4 ||
238             event->xbutton.button == Button5))
239     {
240       gltrackball_mousewheel (trackball, event->xbutton.button, 10,
241                               !!event->xbutton.state);
242       return True;
243     }
244   else if (event->xany.type == MotionNotify &&
245            button_down_p)
246     {
247       gltrackball_track (trackball,
248                          event->xmotion.x, event->xmotion.y,
249                          MI_WIDTH (mi), MI_HEIGHT (mi));
250       return True;
251     }
252
253   return False;
254 }
255
256
257 static void
258 userRot(void)
259 {
260   gltrackball_rotate (trackball);
261 }
262
263 /* draw the gflux once */
264 void draw_gflux(ModeInfo * mi)
265 {
266     gfluxstruct *gp = &gflux[MI_SCREEN(mi)];
267     Display    *display = MI_DISPLAY(mi);
268     Window      window = MI_WINDOW(mi);
269
270     if (!gp->glx_context) return;
271
272     glXMakeCurrent(display, window, *(gp->glx_context));
273
274     calcGrid();
275     gflux->drawFunc();
276     if (mi->fps_p) do_fps (mi);
277     glXSwapBuffers(display, window);
278 }
279
280
281 /* reset the projection matrix */
282 void resetProjection(void) {
283     glMatrixMode(GL_PROJECTION);
284     glLoadIdentity();
285     glFrustum(-_zoom,_zoom,-0.8*_zoom,0.8*_zoom,2,6);
286     glTranslatef(0.0,0.0,-4.0);
287     glMatrixMode(GL_MODELVIEW);
288     glLoadIdentity();
289 }
290
291 /* Standard reshape function */
292 void
293 reshape_gflux(ModeInfo *mi, int width, int height)
294 {
295     glViewport( 0, 0, width, height );
296     resetProjection();
297 }
298
299
300 /* main OpenGL initialization routine */
301 void initializeGL(ModeInfo *mi, GLsizei width, GLsizei height) 
302 {
303   reshape_gflux(mi, width, height);
304   glViewport( 0, 0, width, height ); 
305
306   gflux->tex_xscale = 1.0;  /* maybe changed later */
307   gflux->tex_yscale = 1.0;
308
309   switch(_draw) {
310     case solid :
311       gflux->drawFunc = (displaySolid);
312       glEnable(GL_DEPTH_TEST);
313     break;
314     case light :
315       gflux->drawFunc = (displayLight);
316       glEnable(GL_DEPTH_TEST);
317       initLighting();
318         break;
319         case checker :
320       gflux->drawFunc = (displayTexture);
321       glEnable(GL_DEPTH_TEST);
322       createTexture();
323       initLighting();
324     break;
325         case grab :
326       gflux->drawFunc = (displayTexture);
327       glEnable(GL_DEPTH_TEST);
328       grabTexture();
329       initLighting();
330     break;
331     case wire :
332         default :
333       gflux->drawFunc = (displayWire);
334       glDisable(GL_DEPTH_TEST);
335     break;
336   }
337
338   if(_flat) glShadeModel(GL_FLAT);
339   else glShadeModel(GL_SMOOTH);
340
341 }
342
343
344 /* xgflux initialization routine */
345 void init_gflux(ModeInfo * mi)
346 {
347     int screen = MI_SCREEN(mi);
348     gfluxstruct *gp;
349
350     if (gflux == NULL) {
351         if ((gflux = (gfluxstruct *) 
352                  calloc(MI_NUM_SCREENS(mi), sizeof (gfluxstruct))) == NULL)
353             return;
354     }
355     gp = &gflux[screen];
356
357     trackball = gltrackball_init ();
358
359     {
360       char *s = get_string_resource ("mode", "Mode");
361       if (!s || !*s)                       _draw = wire;
362       else if (!strcasecmp (s, "wire"))    _draw = wire;
363       else if (!strcasecmp (s, "solid"))   _draw = solid;
364       else if (!strcasecmp (s, "light"))   _draw = light;
365       else if (!strcasecmp (s, "checker")) _draw = checker;
366       else if (!strcasecmp (s, "grab"))    _draw = grab;
367       else
368         {
369           fprintf (stderr,
370                    "%s: mode must be one of: wire, solid, "
371                    "light, checker, or grab; not \"%s\"\n",
372                    progname, s);
373           exit (1);
374         }
375     }
376
377     gp->modeinfo = mi;
378     gp->window = MI_WINDOW(mi);
379     if ((gp->glx_context = init_GL(mi)) != NULL) {
380         reshape_gflux(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
381         initializeGL(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
382     } else {
383         MI_CLEARWINDOW(mi);
384     }
385 }
386
387 /* cleanup code */
388 void release_gflux(ModeInfo * mi)
389 {
390     if(gflux->glx_context!=NULL) free(gflux->glx_context);
391     if (gflux != NULL) {
392         (void) free((void *) gflux);
393         gflux = NULL;
394     }
395     FreeAllGL(mi);
396 }
397
398
399
400 void createTexture(void)
401 {
402   int size = 4;
403   unsigned int data[] = { 0xFFFFFFFF, 0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAAA,
404                           0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAAA, 0xFFFFFFFF,
405                           0xFFFFFFFF, 0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAAA,
406                           0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAAA, 0xFFFFFFFF };
407
408   gflux->tex_xscale = size;
409   gflux->tex_yscale = size;
410
411   glGenTextures (1, &gflux->texName);
412   glBindTexture (GL_TEXTURE_2D, gflux->texName);
413
414   glTexImage2D (GL_TEXTURE_2D, 0, 3, size, size, 0,
415                 GL_RGBA, GL_UNSIGNED_BYTE, data);
416
417   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
418   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
419
420   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
421   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
422 }
423
424
425 void
426 grabTexture(void)
427 {
428   Bool mipmap_p = True;
429   int iw, ih, tw, th;
430
431   if (MI_IS_WIREFRAME(gflux->modeinfo))
432     return;
433
434   if (! screen_to_texture (gflux->modeinfo->xgwa.screen,
435                            gflux->modeinfo->window, 0, 0, mipmap_p,
436                            NULL, &gflux->img_geom, &iw, &ih, &tw, &th))
437     exit (1);
438
439   gflux->tex_xscale =  (GLfloat) iw / tw;
440   gflux->tex_yscale = -(GLfloat) ih / th;
441   gflux->img_width  = iw;
442   gflux->img_height = ih;
443    
444   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
445   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
446                    (mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
447 }
448
449
450 void initLighting(void)
451 {
452     static float ambientA[] = {0.0, 0.0, 0.0, 1.0};
453     static float diffuseA[] = {1.0, 1.0, 1.0, 1.0};
454     static float positionA[] = {5.0, 5.0, 15.0, 1.0};
455
456     static float front_mat_shininess[] = {30.0};
457     static float front_mat_specular[] = {0.5, 0.5, 0.5, 1.0};
458
459     static float mat_diffuse[] = {0.5, 0.5, 0.5, 1.0};
460
461     glMaterialfv(GL_FRONT, GL_SHININESS, front_mat_shininess);
462     glMaterialfv(GL_FRONT, GL_SPECULAR, front_mat_specular);
463
464     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
465
466     glLightfv(GL_LIGHT0, GL_AMBIENT, ambientA);
467     glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseA);
468     glLightfv(GL_LIGHT0, GL_POSITION, positionA);
469     glEnable(GL_LIGHTING);
470     glEnable(GL_LIGHT0);
471     glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,1);
472
473     glEnable(GL_NORMALIZE);         /* would it be faster ...   */
474     glEnable(GL_COLOR_MATERIAL);
475     glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
476 }
477
478 /************************************/
479 /* draw implementations             */
480 /* somewhat inefficient since they  */
481 /* all calculate previously         */
482 /* calculated values again          */
483 /* storing the values in an array   */
484 /* is a posibility                  */
485 /************************************/
486 void displayTexture(void)
487 {
488     static double time = 0.0;
489     static double anglex = 0.0;
490     static double angley = 0.0;
491     static double anglez = 0.0;
492
493     double x,y,u,v;
494     double z;
495     double dx = 2.0/((double)_squares);
496     double dy = 2.0/((double)_squares);
497
498     double du = 2.0/((double)_squares);
499     double dv = 2.0/((double)_squares);
500
501     double xs = gflux->tex_xscale;
502     double ys = gflux->tex_yscale;
503
504     double minx, miny, maxx, maxy;
505     double minu, minv;
506
507 #if 0
508     minx = (GLfloat) gflux->img_geom.x / gflux->img_width;
509     miny = (GLfloat) gflux->img_geom.y / gflux->img_height;
510     maxx = ((GLfloat) (gflux->img_geom.x + gflux->img_geom.width) /
511             gflux->img_width);
512     maxy = ((GLfloat) (gflux->img_geom.y + gflux->img_geom.height) /
513             gflux->img_height);
514     minu = minx;
515     minv = miny;
516     minx = (minx * 2) - 1;
517     miny = (miny * 2) - 1;
518     maxx = (maxx * 2) - 1;
519     maxy = (maxy * 2) - 1;
520 #else
521     minx = -1;
522     miny = -1;
523     maxx = 1;
524     maxy = 1;
525     minv = 0;
526     minu = 0;
527 #endif
528
529         glMatrixMode (GL_TEXTURE);
530         glLoadIdentity ();
531         glTranslatef(-1,-1,0);
532         glScalef(0.5,0.5,1);
533         glMatrixMode (GL_MODELVIEW);
534
535     glLoadIdentity();
536     userRot();
537     glRotatef(anglex,1,0,0);
538     glRotatef(angley,0,1,0);
539     glRotatef(anglez,0,0,1);
540     glScalef(1,1,(GLfloat)_waveHeight);
541     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
542         glEnable(GL_TEXTURE_2D);
543
544     clear_gl_error();
545         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
546         glBindTexture(GL_TEXTURE_2D, gflux->texName);
547     check_gl_error("texture binding");
548
549         glColor3f(0.5,0.5,0.5);
550  
551     for(x = minx, u = minu; x < maxx - 0.01; x += dx, u += du) {
552         glBegin(GL_QUAD_STRIP);
553         for (y = miny, v = minv; y <= maxy + 0.01; y += dy, v += dv) {
554             z = getGrid(x,y,time);
555             glTexCoord2f(u*xs,v*ys);
556             glNormal3f(
557                 getGrid(x+dx,y,time)-getGrid(x-dx,y,time),
558                 getGrid(x,y+dy,time)-getGrid(x,y-dy,time),
559                 1
560             );
561             glVertex3f(x,y,z);
562
563             z = getGrid(x+dx,y,time);
564             glTexCoord2f((u+du)*xs,v*ys);
565             glNormal3f(
566                 getGrid(x+dx+dx,y,time)-getGrid(x,y,time),
567                 getGrid(x+dx,y+dy,time)-getGrid(x+dx,y-dy,time),
568                 1
569             );
570             glVertex3f(x+dx,y,z);
571         }
572         glEnd();
573     }
574
575     /* Draw a border around the grid.
576      */
577     glColor3f(0.4, 0.4, 0.4);
578     glDisable(GL_TEXTURE_2D);
579     glEnable (GL_LINE_SMOOTH);
580
581     glBegin(GL_LINE_LOOP);
582     y = miny;
583     for (x = minx; x <= maxx; x += dx)
584       glVertex3f (x, y, getGrid (x, y, time));
585     x = maxx;
586     for (y = miny; y <= maxy; y += dy)
587       glVertex3f (x, y, getGrid (x, y, time));
588     y = maxy;
589     for (x = maxx; x >= minx; x -= dx)
590       glVertex3f (x, y, getGrid (x, y, time));
591     x = minx;
592     for (y = maxy; y >= miny; y -= dy)
593       glVertex3f (x, y, getGrid (x, y, time));
594
595     glEnd();
596     glEnable(GL_TEXTURE_2D);
597
598     if (! button_down_p) {
599       time -= _speed;
600       anglex -= _rotationx;
601       angley -= _rotationy;
602       anglez -= _rotationz;
603     }
604 }
605 void displaySolid(void)
606 {
607     static double time = 0.0;
608     static double anglex = 0.0;
609     static double angley = 0.0;
610     static double anglez = 0.0;
611
612     double x,y;
613     double z;
614     double dx = 2.0/((double)_squares);
615     double dy = 2.0/((double)_squares);
616
617     glLoadIdentity();
618     glRotatef(anglex,1,0,0);
619     glRotatef(angley,0,1,0);
620     glRotatef(anglez,0,0,1);
621     userRot();
622     glScalef(1,1,(GLfloat)_waveHeight);
623     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
624
625     for(x=-1;x<0.9999;x+=dx) {
626         glBegin(GL_QUAD_STRIP);
627         for(y=-1;y<=1;y+=dy) {
628             z = getGrid(x,y,time);
629             genColour(z);
630             glColor3fv(gflux->colour);
631             glVertex3f(x,y,z);
632
633             z = getGrid(x+dx,y,time);
634             genColour(z);
635             glColor3fv(gflux->colour);
636             glVertex3f(x+dx,y,z);
637         }
638         glEnd();
639     }
640
641     if (! button_down_p) {
642       time -= _speed;
643       anglex -= _rotationx;
644       angley -= _rotationy;
645       anglez -= _rotationz;
646     }
647
648 }
649
650 void displayLight(void)
651 {
652     static double time = 0.0;
653     static double anglex = 0.0;
654     static double angley = 0.0;
655     static double anglez = 0.0;
656
657     double x,y;
658     double z;
659     double dx = 2.0/((double)_squares);
660     double dy = 2.0/((double)_squares);
661
662     glLoadIdentity();
663     glRotatef(anglex,1,0,0);
664     glRotatef(angley,0,1,0);
665     glRotatef(anglez,0,0,1);
666     userRot();
667     glScalef(1,1,(GLfloat)_waveHeight);
668     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
669
670     for(x=-1;x<0.9999;x+=dx) {
671         glBegin(GL_QUAD_STRIP);
672         for(y=-1;y<=1;y+=dy) {
673             z = getGrid(x,y,time);
674             genColour(z);
675             glColor3fv(gflux->colour);
676             glNormal3f(
677                 getGrid(x+dx,y,time)-getGrid(x-dx,y,time),
678                 getGrid(x,y+dy,time)-getGrid(x,y-dy,time),
679                 1
680             );
681             glVertex3f(x,y,z);
682
683             z = getGrid(x+dx,y,time);
684             genColour(z);
685             glColor3fv(gflux->colour);
686             glNormal3f(
687                 getGrid(x+dx+dx,y,time)-getGrid(x,y,time),
688                 getGrid(x+dx,y+dy,time)-getGrid(x+dx,y-dy,time),
689                 1
690             );
691             glVertex3f(x+dx,y,z);
692         }
693         glEnd();
694     }
695
696     if (! button_down_p) {
697       time -= _speed;
698       anglex -= _rotationx;
699       angley -= _rotationy;
700       anglez -= _rotationz;
701     }
702 }
703
704 void displayWire(void)
705 {
706     static double time = 0.0;
707     static double anglex = 0.0;
708     static double angley = 0.0;
709     static double anglez = 0.0;
710
711     double x,y;
712     double z;
713     double dx1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
714     double dy1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
715     double dx2 = 2.0/((double)_squares) - 0.00001;
716     double dy2 = 2.0/((double)_squares) - 0.00001;
717
718     glLoadIdentity();
719     glRotatef(anglex,1,0,0);
720     glRotatef(angley,0,1,0);
721     glRotatef(anglez,0,0,1);
722     userRot();
723     glScalef(1,1,(GLfloat)_waveHeight);
724     glClear(GL_COLOR_BUFFER_BIT);
725
726     for(x=-1;x<=1;x+=dx2) {
727         glBegin(GL_LINE_STRIP);
728         for(y=-1;y<=1;y+=dy1) {
729             z = getGrid(x,y,time);
730             genColour(z);
731             glColor3fv(gflux->colour);
732             glVertex3f(x,y,z);
733         }
734         glEnd();
735     }
736     for(y=-1;y<=1;y+=dy2) {
737         glBegin(GL_LINE_STRIP);
738         for(x=-1;x<=1;x+=dx1) {
739             z = getGrid(x,y,time);
740             genColour(z);
741             glColor3fv(gflux->colour);
742             glVertex3f(x,y,z);
743         }
744         glEnd();
745     }
746
747     if (! button_down_p) {
748       time -= _speed;
749       anglex -= _rotationx;
750       angley -= _rotationy;
751       anglez -= _rotationz;
752     }
753 }
754
755 /* generates new ripples */
756 void calcGrid(void)
757 {
758     static int counter=0;
759     double tmp;
760     static int newWave;
761
762     if (button_down_p) return;
763
764     tmp = 1.0/((double)_waveChange);
765     if(!(counter%_waveChange)) {
766         newWave = ((int)(counter*tmp))%_waves;
767         gflux->dispx[newWave] = -frand(1.0);
768         gflux->dispy[newWave] = -frand(1.0);
769         gflux->freq[newWave] = _waveFreq * frand(1.0);
770         gflux->wa[newWave] = 0.0;
771     }
772     counter++;
773     gflux->wa[newWave] += tmp;
774     gflux->wa[(newWave+1)%_waves] -= tmp;
775 }
776
777 /* returns a height for the grid given time and x,y space co-ords */
778 double getGrid(double x, double y, double a)
779 {
780     register int i;
781     double retval=0.0;
782     double tmp;
783
784     tmp = 1.0/((float)_waves);
785     for(i=0;i<_waves;i++) {
786       retval += gflux->wa[i] * tmp * sin( gflux->freq[i]
787               * ( (x+gflux->dispx[i]) * (x+gflux->dispx[i]) 
788                 + (y+gflux->dispy[i]) * (y+gflux->dispy[i]) +a ) );
789     }
790     return(retval);
791 }
792
793 #endif
794