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