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