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