23fce87c78301571bcdde8ecfbd8311e377ffeca
[xscreensaver] / hacks / glx / gflux.c
1 /* -*- Mode: C; tab-width: 4 -*- emacs friendly */
2
3 /* gflux - creates a fluctuating 3D grid 
4  * requires OpenGL or MesaGL
5  * 
6  * Copyright (c) Josiah Pease, 2000
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation.  No representations are made about the suitability of this
12  * software for any purpose.  It is provided "as is" without express or 
13  * implied warranty.
14  *
15  * Thanks go to all those who worked on...
16  * MesaGL, OpenGL, UtahGLX, XFree86, gcc, vim, rxvt, the PNM (anymap) format
17  * xscreensaver and the thousands of other tools, apps and daemons that make
18  * linux usable  
19  * Personal thanks to Kevin Moss, Paul Sheahee and Jamie Zawinski
20  * 
21  * some xscreensaver code lifted from superquadrics.  Most other glx hacks 
22  * used as reference at some time.
23  *
24  * This hack and others can cause UtahGLX to crash my X server
25  * wireframe looks good with software only rendering anyway
26  * If anyone can work out why and supply a fix I'd love to hear from them
27  * 
28  * Josiah Pease <gfluxcode@jpease.force9.co.uk> 21 July 2000
29  * 
30  * History 
31  * 10 June 2000 : wireframe rippling grid standalone written
32  * 18 June 2000 : xscreensaver code added
33  * 25 June 2000 : solid and light added
34  * 04 July 2000 : majour bug hunt, xscreensaver code rewritten
35  * 08 July 2000 : texture mapping, rotation and zoom added
36  * 21 July 2000 : cleaned up code from bug hunts, manpage written
37  */
38
39
40 /*-
41  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
42  * otherwise caddr_t is not defined correctly
43  */
44
45 #include <X11/Intrinsic.h>
46
47
48 #ifdef STANDALONE
49 # define PROGCLASS                                              "gflux"
50 # define HACK_INIT                                              init_gflux
51 # define HACK_DRAW                                              draw_gflux
52 # define HACK_RESHAPE                                   reshape_gflux
53 # define gflux_opts                                             xlockmore_opts
54 #define DEFAULTS                        "*delay:                20000   \n" \
55                                                                                 "*showFPS:      False   \n" \
56                                         "*squares:      19      \n" \
57                                                                                 "*resolution:   0       \n" \
58                                         "*draw:         0       \n" \
59                                         "*flat:         0       \n" \
60                                         "*speed:        0.05    \n" \
61                                         "*rotationx:    0.01    \n" \
62                                         "*rotationy:    0.0     \n" \
63                                         "*rotationz:    0.1     \n" \
64                                         "*waves:        3       \n" \
65                                         "*waveChange:   50      \n" \
66                                         "*waveHeight:   1.0     \n" \
67                                         "*waveFreq:    3.0     \n" \
68                                         "*zoom:         1.0     \n" 
69
70
71 # include "xlockmore.h"                         /* from the xscreensaver distribution */
72 #else /* !STANDALONE */
73 # include "xlock.h"                                     /* from the xlockmore distribution */
74 #endif /* !STANDALONE */
75
76 #ifdef USE_GL /* whole file */
77
78 #ifdef HAVE_XPM
79 # include <X11/xpm.h>
80 # ifndef PIXEL_ALREADY_TYPEDEFED
81 # define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
82 # endif
83 #endif
84
85 #ifdef HAVE_XMU
86 # ifndef VMS
87 #  include <X11/Xmu/Drawing.h>
88 #else  /* VMS */
89 #  include <Xmu/Drawing.h>
90 # endif /* VMS */
91 #endif
92
93 #undef countof
94 #define countof(x) (sizeof((x))/sizeof((*x)))
95
96 #include <stdlib.h>
97 #include <stdio.h>
98
99 #include <GL/gl.h>
100 #include <GL/glu.h>
101 #include <GL/glx.h>
102
103 #include <math.h>
104
105 static enum {wire=0,solid,light,checker,textured} _draw; /* draw style */
106 static int _squares = 19;                                 /* grid size */
107 static int _resolution = 4;                    /* wireframe resolution */
108 static int _flat = 0;
109
110 static float _speed = 0.05;
111 static float _rotationx = 0.01;
112 static float _rotationy = 0.0;
113 static float _rotationz = 0.1;
114 static float _zoom = 1.0;
115
116 static int _waves = 3;
117 static int _waveChange = 50;
118 static float _waveHeight = 1.0;
119 static float _waveFreq = 3.0;
120
121 #define WIDTH 320
122 #define HEIGHT 240
123
124 static XrmOptionDescRec opts[] = {
125     {"-squares", ".gflux.squares", XrmoptionSepArg, (caddr_t) NULL},
126     {"-resolution", ".gflux.resolution", XrmoptionSepArg, (caddr_t) NULL},
127     {"-draw", ".gflux.draw", XrmoptionSepArg, (caddr_t) NULL},
128     {"-flat", ".gflux.flat", XrmoptionSepArg, (caddr_t) NULL},
129     {"-speed", ".gflux.speed", XrmoptionSepArg, (caddr_t) NULL},
130     {"-rotationx", ".gflux.rotationx", XrmoptionSepArg, (caddr_t) NULL},
131     {"-rotationy", ".gflux.rotationy", XrmoptionSepArg, (caddr_t) NULL},
132     {"-rotationz", ".gflux.rotationz", XrmoptionSepArg, (caddr_t) NULL},
133     {"-waves", ".gflux.waves", XrmoptionSepArg, (caddr_t) NULL},
134     {"-waveChange", ".gflux.waveChange", XrmoptionSepArg, (caddr_t) NULL},
135     {"-waveHeight", ".gflux.waveHeight", XrmoptionSepArg, (caddr_t) NULL},
136     {"-waveFreq", ".gflux.waveFreq", XrmoptionSepArg, (caddr_t) NULL},
137     {"-zoom", ".gflux.zoom", XrmoptionSepArg, (caddr_t) NULL},
138 };
139
140
141 static argtype vars[] = {
142     {(caddr_t *) & _squares, "squares", "Squares", "19", t_Int},
143     {(caddr_t *) & _resolution, "resolution", "Resolution", "4", t_Int},
144     {(caddr_t *) & _draw, "draw", "Draw", "0", t_Int},
145     {(caddr_t *) & _flat, "flat", "Flat", "0", t_Int},
146     {(caddr_t *) & _speed, "speed", "Speed", "0.05", t_Float},
147     {(caddr_t *) & _rotationx, "rotationx", "Rotationx", "0.01", t_Float},
148     {(caddr_t *) & _rotationy, "rotationy", "Rotationy", "0.0", t_Float},
149     {(caddr_t *) & _rotationz, "rotationz", "Rotationz", "0.1", t_Float},
150     {(caddr_t *) & _waves, "waves", "Waves", "3", t_Int},
151     {(caddr_t *) & _waveChange, "waveChange", "WaveChange", "50", t_Int},
152     {(caddr_t *) & _waveHeight, "waveHeight", "WaveHeight", "1.0", t_Float},
153     {(caddr_t *) & _waveFreq, "waveFreq", "WaveFreq", "3.0", t_Float},
154     {(caddr_t *) & _zoom, "zoom", "Zoom", "1.0", t_Float},
155 };
156
157
158 static OptionStruct desc[] =
159 {
160     {"-squares num", "size of grid in squares (19)"},
161     {"-resolution num", "detail of lines making grid, wireframe only (4)"},
162     {"-draw num", "draw method to use: 0=wireframe 1=solid 2=lit (0)"},
163     {"-flat num", "shading method, not wireframe: 0=smooth 1=flat (0)"},
164     {"-speed num", "speed of waves (0.05)"},
165     {"-rotationx num", "speed of xrotation (0.01)"},
166     {"-rotationy num", "speed of yrotation (0.00)"},
167     {"-rotationz num", "speed of zrotation (0.10)"},
168     {"-waves num", "number of simultanious waves (3)"},
169     {"-waveChange num", "number of cyles for a wave to change (50)"},
170     {"-waveHeight num", "height of waves (1.0)"},
171     {"-waveFreq num", "max frequency of a wave (3.0)"},
172     {"-zoom num", "camera control (1.0)"},
173 };
174
175 ModeSpecOpt gflux_opts = {countof(opts), opts, countof(vars), vars, desc};
176
177 #ifdef USE_MODULES
178 ModStruct   gflux_description =
179 {"gflux", "init_gflux", "draw_gflux", "release_gflux",
180  "draw_gflux", "init_gflux", NULL, &gflux_opts,
181  1000, 1, 2, 1, 4, 1.0, "",
182  "Gflux: an OpenGL gflux", 0, NULL};
183 #endif
184
185 /* structure for holding the gflux data */
186 typedef struct {
187     int screen_width, screen_height;
188     GLXContext *glx_context;
189     Window window;
190     XColor fg, bg;
191 #define MAXWAVES 10   /* should be dynamic    */
192     double wa[MAXWAVES];
193     double freq[MAXWAVES];
194     double dispy[MAXWAVES];
195     double dispx[MAXWAVES];
196     GLfloat colour[3];
197     int imageWidth;
198     int imageHeight;
199     GLubyte *image;
200     GLuint texName;
201     void (*drawFunc)(void);
202 } gfluxstruct;
203 static gfluxstruct *gflux = NULL;
204
205 /* prototypes */
206 void initLighting(void);
207 void initTexture(void);
208 void loadTexture(void);
209 void createTexture(void);
210 void displaySolid(void);            /* drawFunc implementations */
211 void displayLight(void);
212 void displayTexture(void);
213 void displayWire(void);
214 void calcGrid(void);
215 double getGrid(double,double,double);
216
217 /* as macro for speed */
218 /* could do with colour cycling here */
219 /* void genColour(double);*/
220 #define genColour(X) \
221 {\
222     gflux->colour[0] = 0.0;\
223     gflux->colour[1] = 0.5+0.5*(X);\
224     gflux->colour[2] = 0.5-0.5*(X);\
225 }
226
227 /* BEGINNING OF FUNCTIONS */
228
229
230 /* draw the gflux once */
231 void draw_gflux(ModeInfo * mi)
232 {
233     gfluxstruct *gp = &gflux[MI_SCREEN(mi)];
234     Display    *display = MI_DISPLAY(mi);
235     Window      window = MI_WINDOW(mi);
236
237     if (!gp->glx_context) return;
238
239     glXMakeCurrent(display, window, *(gp->glx_context));
240
241     calcGrid();
242     gflux->drawFunc();
243     if (mi->fps_p) do_fps (mi);
244     glXSwapBuffers(display, window);
245 }
246
247
248 /* reset the projection matrix */
249 void resetProjection(void) {
250     glMatrixMode(GL_PROJECTION);
251     glLoadIdentity();
252     glFrustum(-_zoom,_zoom,-0.8*_zoom,0.8*_zoom,2,6);
253     glTranslatef(0.0,0.0,-4.0);
254     glMatrixMode(GL_MODELVIEW);
255     glLoadIdentity();
256 }
257
258 /* Standard reshape function */
259 void
260 reshape_gflux(ModeInfo *mi, int width, int height)
261 {
262     glViewport( 0, 0, width, height );
263     resetProjection();
264 }
265
266
267 /* main OpenGL initialization routine */
268 void initializeGL(ModeInfo *mi, GLsizei width, GLsizei height) 
269 {
270   reshape_gflux(mi, width, height);
271   glViewport( 0, 0, width, height ); 
272   switch(_draw) {
273     case solid :
274       gflux->drawFunc = (displaySolid);
275       glEnable(GL_DEPTH_TEST);
276     break;
277     case light :
278       gflux->drawFunc = (displayLight);
279       glEnable(GL_DEPTH_TEST);
280       initLighting();
281         break;
282         case checker :
283       gflux->drawFunc = (displayTexture);
284       glEnable(GL_DEPTH_TEST);
285       createTexture();
286       initTexture();
287       initLighting();
288     break;
289         case textured :
290       gflux->drawFunc = (displayTexture);
291       glEnable(GL_DEPTH_TEST);
292       loadTexture();
293       initTexture();
294       initLighting();
295     break;
296     case wire :
297         default :
298       gflux->drawFunc = (displayWire);
299       glDisable(GL_DEPTH_TEST);
300     break;
301   }
302
303   if(_flat) glShadeModel(GL_FLAT);
304   else glShadeModel(GL_SMOOTH);
305
306 }
307
308
309 /* xgflux initialization routine */
310 void init_gflux(ModeInfo * mi)
311 {
312     int screen = MI_SCREEN(mi);
313     gfluxstruct *gp;
314
315     if (gflux == NULL) {
316         if ((gflux = (gfluxstruct *) 
317                  calloc(MI_NUM_SCREENS(mi), sizeof (gfluxstruct))) == NULL)
318             return;
319     }
320     gp = &gflux[screen];
321
322     gp->window = MI_WINDOW(mi);
323     if ((gp->glx_context = init_GL(mi)) != NULL) {
324         reshape_gflux(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
325         initializeGL(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
326     } else {
327         MI_CLEARWINDOW(mi);
328     }
329 }
330
331 /* cleanup code */
332 void release_gflux(ModeInfo * mi)
333 {
334     if(gflux->image!=NULL) free(gflux->image);
335     if(gflux->glx_context!=NULL) free(gflux->glx_context);
336     if (gflux != NULL) {
337         (void) free((void *) gflux);
338         gflux = NULL;
339     }
340     FreeAllGL(mi);
341 }
342
343 /* loads several different types of PNM image from stdin */
344 #define presult(A,B,C) (*(result+(A)*(gflux->imageWidth)*4+(B)*4+(C)))
345 void loadTexture(void)
346 {
347     int i, j, levels, width, height;
348     int red,green,blue;
349     char s[4];
350     int ppmType=0;
351     FILE *file = stdin;
352     GLubyte *result;
353
354     fgets(s,4,file);
355
356     if(!strncmp(s,"P6",2)) ppmType=6;
357     if(!strncmp(s,"P5",2)) ppmType=5;
358     if(!strncmp(s,"P3",2)) ppmType=3;
359     if(!strncmp(s,"P2",2)) ppmType=2;
360     if(!ppmType)exit(1);
361
362     while((i=getc(file))=='#')
363     {
364         while(getc(file)!='\n');
365     }
366     ungetc(i,file);
367
368     fscanf(file,"%d %d %d",&width,&height,&levels);
369
370     result = malloc(sizeof(GLubyte)*4*width*height);
371     gflux->imageWidth = width;
372         gflux->imageHeight = height;
373
374     switch(ppmType) {
375         case 2 :    /* ASCII grey */
376             for(i=0;i<height;i++) {
377                 for(j=0;j<width;j++) {
378                     fscanf(file,"%d",&red);
379                     presult(j,i,0) = red;
380                     presult(j,i,1) = red;
381                     presult(j,i,2) = red;
382                 }
383             }
384             break;
385         case 3 :    /* ASCII rgb */
386             for(i=0;i<height;i++) {
387                 for(j=0;j<width;j++) {
388                     fscanf(file,"%d %d %d",&red,&green,&blue);
389                     presult(j,i,0) = red;
390                     presult(j,i,1) = green;
391                     presult(j,i,2) = blue;
392                 }
393             }
394             break;
395         case 5 :    /* Binary grey */
396             getc(file); /* seems nessessary */
397             for(i=0;i<height;i++) {
398                 for(j=0;j<width;j++) {
399                     red = getc(file);
400                     presult(j,i,0) = red;
401                     presult(j,i,1) = red;
402                     presult(j,i,2) = red;
403                 }
404             }
405         break;
406         case 6 :    /* Binary rgb */
407             getc(file); /* seems nessessary */
408             for(i=0;i<height;i++) {
409                 for(j=0;j<width;j++) {
410                     red = getc(file);
411                     green = getc(file);
412                     blue = getc(file);
413                     presult(j,i,0) = red;
414                     presult(j,i,1) = green;
415                     presult(j,i,2) = blue;
416                 }
417             }
418         break;
419     }
420         gflux->image = result;
421 }
422
423 /* creates an image for texture mapping */
424 void createTexture(void)
425 {
426     int i,j,c;
427     GLubyte *result;
428
429         gflux->imageHeight = gflux->imageWidth = 8;
430
431         result = malloc(sizeof(GLubyte)*4*gflux->imageHeight*gflux->imageWidth);
432     for(i=0;i<gflux->imageHeight;i++) {
433         for(j=0;j<gflux->imageWidth;j++) {
434             c = (((i)%2 ^ (j)%2) ? 100 : 200 );
435             presult(i,j,0) = (GLubyte) c;
436             presult(i,j,1) = (GLubyte) c;
437             presult(i,j,2) = (GLubyte) c;
438             presult(i,j,3) = (GLubyte) 255;
439         }
440     }
441         gflux->image = result;
442 }
443 #undef presult
444
445 /* specifies image as texture */    
446 void initTexture(void)
447 {
448         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
449         glGenTextures(1, &gflux->texName);
450         glBindTexture(GL_TEXTURE_2D, gflux->texName);
451         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
452         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
453         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
454         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
455     clear_gl_error();
456         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gflux->imageWidth,
457                         gflux->imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, gflux->image);
458     check_gl_error("texture");
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         glMatrixMode (GL_TEXTURE);
510         glLoadIdentity ();
511         glTranslatef(-1,-1,0);
512         glScalef(0.5,0.5,1);
513         glMatrixMode (GL_MODELVIEW);
514
515     glLoadIdentity();
516     glRotatef(anglex,1,0,0);
517     glRotatef(angley,0,1,0);
518     glRotatef(anglez,0,0,1);
519     glScalef(1,1,(GLfloat)_waveHeight);
520     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
521         glEnable(GL_TEXTURE_2D);
522         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
523         glBindTexture(GL_TEXTURE_2D, gflux->texName);
524         glColor3f(0.5,0.5,0.5);
525
526     for(x=-1,u=0;x<=1;x+=dx,u+=dx) {
527         glBegin(GL_QUAD_STRIP);
528         for(y=-1,v=0;y<=1;y+=dy,v+=dx) {
529             z = getGrid(x,y,time);
530         /*  genColour(z);
531             glColor3fv(gflux->colour);
532         */  glTexCoord2f(u,v);
533             glNormal3f(
534                 getGrid(x+dx,y,time)-getGrid(x-dx,y,time),
535                 getGrid(x,y+dy,time)-getGrid(x,y-dy,time),
536                 1
537             );
538             glVertex3f(x,y,z);
539
540             z = getGrid(x+dx,y,time);
541         /*  genColour(z);
542             glColor3fv(gflux->colour);
543         */  glTexCoord2f(u+dx,v);
544             glNormal3f(
545                 getGrid(x+dx+dx,y,time)-getGrid(x,y,time),
546                 getGrid(x+dx,y+dy,time)-getGrid(x+dx,y-dy,time),
547                 1
548             );
549             glVertex3f(x+dx,y,z);
550         }
551         glEnd();
552     }
553
554     time -= _speed;
555     anglex -= _rotationx;
556     angley -= _rotationy;
557     anglez -= _rotationz;
558 }
559 void displaySolid(void)
560 {
561     static double time = 0.0;
562     static double anglex = 0.0;
563     static double angley = 0.0;
564     static double anglez = 0.0;
565
566     double x,y;
567     double z;
568     double dx = 2.0/((double)_squares);
569     double dy = 2.0/((double)_squares);
570
571     glLoadIdentity();
572     glRotatef(anglex,1,0,0);
573     glRotatef(angley,0,1,0);
574     glRotatef(anglez,0,0,1);
575     glScalef(1,1,(GLfloat)_waveHeight);
576     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
577
578     for(x=-1;x<=1;x+=dx) {
579         glBegin(GL_QUAD_STRIP);
580         for(y=-1;y<=1;y+=dy) {
581             z = getGrid(x,y,time);
582             genColour(z);
583             glColor3fv(gflux->colour);
584             glVertex3f(x,y,z);
585
586             z = getGrid(x+dx,y,time);
587             genColour(z);
588             glColor3fv(gflux->colour);
589             glVertex3f(x+dx,y,z);
590         }
591         glEnd();
592     }
593
594     time -= _speed;
595     anglex -= _rotationx;
596     angley -= _rotationy;
597     anglez -= _rotationz;
598
599 }
600
601 void displayLight(void)
602 {
603     static double time = 0.0;
604     static double anglex = 0.0;
605     static double angley = 0.0;
606     static double anglez = 0.0;
607
608     double x,y;
609     double z;
610     double dx = 2.0/((double)_squares);
611     double dy = 2.0/((double)_squares);
612
613     glLoadIdentity();
614     glRotatef(anglex,1,0,0);
615     glRotatef(angley,0,1,0);
616     glRotatef(anglez,0,0,1);
617     glScalef(1,1,(GLfloat)_waveHeight);
618     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
619
620     for(x=-1;x<=1;x+=dx) {
621         glBegin(GL_QUAD_STRIP);
622         for(y=-1;y<=1;y+=dy) {
623             z = getGrid(x,y,time);
624             genColour(z);
625             glColor3fv(gflux->colour);
626             glNormal3f(
627                 getGrid(x+dx,y,time)-getGrid(x-dx,y,time),
628                 getGrid(x,y+dy,time)-getGrid(x,y-dy,time),
629                 1
630             );
631             glVertex3f(x,y,z);
632
633             z = getGrid(x+dx,y,time);
634             genColour(z);
635             glColor3fv(gflux->colour);
636             glNormal3f(
637                 getGrid(x+dx+dx,y,time)-getGrid(x,y,time),
638                 getGrid(x+dx,y+dy,time)-getGrid(x+dx,y-dy,time),
639                 1
640             );
641             glVertex3f(x+dx,y,z);
642         }
643         glEnd();
644     }
645
646     time -= _speed;
647     anglex -= _rotationx;
648     angley -= _rotationy;
649     anglez -= _rotationz;
650 }
651
652 void displayWire(void)
653 {
654     static double time = 0.0;
655     static double anglex = 0.0;
656     static double angley = 0.0;
657     static double anglez = 0.0;
658
659     double x,y;
660     double z;
661     double dx1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
662     double dy1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
663     double dx2 = 2.0/((double)_squares) - 0.00001;
664     double dy2 = 2.0/((double)_squares) - 0.00001;
665
666     glLoadIdentity();
667     glRotatef(anglex,1,0,0);
668     glRotatef(angley,0,1,0);
669     glRotatef(anglez,0,0,1);
670     glScalef(1,1,(GLfloat)_waveHeight);
671     glClear(GL_COLOR_BUFFER_BIT);
672
673     for(x=-1;x<=1;x+=dx2) {
674         glBegin(GL_LINE_STRIP);
675         for(y=-1;y<=1;y+=dy1) {
676             z = getGrid(x,y,time);
677             genColour(z);
678             glColor3fv(gflux->colour);
679             glVertex3f(x,y,z);
680         }
681         glEnd();
682     }
683     for(y=-1;y<=1;y+=dy2) {
684         glBegin(GL_LINE_STRIP);
685         for(x=-1;x<=1;x+=dx1) {
686             z = getGrid(x,y,time);
687             genColour(z);
688             glColor3fv(gflux->colour);
689             glVertex3f(x,y,z);
690         }
691         glEnd();
692     }
693
694     time -= _speed;
695     anglex -= _rotationx;
696     angley -= _rotationy;
697     anglez -= _rotationz;
698 }
699
700 /* generates new ripples */
701 void calcGrid(void)
702 {
703     static int counter=0;
704     double tmp;
705     static int newWave;
706
707     tmp = 1.0/((double)_waveChange);
708     if(!(counter%_waveChange)) {
709         newWave = ((int)(counter*tmp))%_waves;
710         gflux->dispx[newWave] = 1.0 - ((double)random())/RAND_MAX;
711         gflux->dispy[newWave] = 1.0 - ((double)random())/RAND_MAX;
712         gflux->freq[newWave] = _waveFreq * ((float)random())/RAND_MAX;
713         gflux->wa[newWave] = 0.0;
714     }
715     counter++;
716     gflux->wa[newWave] += tmp;
717     gflux->wa[(newWave+1)%_waves] -= tmp;
718 }
719
720 /* returns a height for the grid given time and x,y space co-ords */
721 double getGrid(double x, double y, double a)
722 {
723     register int i;
724     double retval=0.0;
725     double tmp;
726
727     tmp = 1.0/((float)_waves);
728     for(i=0;i<_waves;i++) {
729       retval += gflux->wa[i] * tmp * sin( gflux->freq[i]
730               * ( (x+gflux->dispx[i]) * (x+gflux->dispx[i]) 
731                 + (y+gflux->dispy[i]) * (y+gflux->dispy[i]) +a ) );
732     }
733     return(retval);
734 }
735
736 #endif
737