From http://www.jwz.org/xscreensaver/xscreensaver-5.18.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   /* Do it twice because we don't track the device's orientation. */
285   glRotatef( current_device_rotation(), 0, 0, 1);
286   gltrackball_rotate (gp->trackball);
287   glRotatef(-current_device_rotation(), 0, 0, 1);
288 }
289
290 /* draw the gflux once */
291 ENTRYPOINT void draw_gflux(ModeInfo * mi)
292 {
293     gfluxstruct *gp = &gfluxes[MI_SCREEN(mi)];
294     Display    *display = MI_DISPLAY(mi);
295     Window      window = MI_WINDOW(mi);
296
297     if (!gp->glx_context) return;
298
299     /* Just keep running before the texture has come in. */
300     /* if (gp->waiting_for_image_p) return; */
301
302     glXMakeCurrent(display, window, *(gp->glx_context));
303
304     calcGrid(gp);
305     mi->polygon_count = gp->drawFunc(gp);
306     if (mi->fps_p) do_fps (mi);
307     glXSwapBuffers(display, window);
308 }
309
310
311 /* reset the projection matrix */
312 static void resetProjection(void) 
313 {
314     glMatrixMode(GL_PROJECTION);
315     glLoadIdentity();
316     glFrustum(-_zoom,_zoom,-0.8*_zoom,0.8*_zoom,2,6);
317     glTranslatef(0.0,0.0,-4.0);
318     glMatrixMode(GL_MODELVIEW);
319     glLoadIdentity();
320 }
321
322 /* Standard reshape function */
323 ENTRYPOINT void
324 reshape_gflux(ModeInfo *mi, int width, int height)
325 {
326     glViewport( 0, 0, width, height );
327     resetProjection();
328 }
329
330
331 /* main OpenGL initialization routine */
332 static void initializeGL(ModeInfo *mi, GLsizei width, GLsizei height) 
333 {
334   gfluxstruct *gp = &gfluxes[MI_SCREEN(mi)];
335
336   reshape_gflux(mi, width, height);
337   glViewport( 0, 0, width, height ); 
338
339   gp->tex_xscale = 1.0;  /* maybe changed later */
340   gp->tex_yscale = 1.0;
341
342   switch(_draw) {
343     case solid :
344       gp->drawFunc = (displaySolid);
345       glEnable(GL_DEPTH_TEST);
346     break;
347     case light :
348       gp->drawFunc = (displayLight);
349       glEnable(GL_DEPTH_TEST);
350       initLighting();
351         break;
352         case checker :
353       gp->drawFunc = (displayTexture);
354       glEnable(GL_DEPTH_TEST);
355       createTexture(gp);
356       initLighting();
357     break;
358         case grab :
359       gp->drawFunc = (displayTexture);
360       glEnable(GL_DEPTH_TEST);
361       grabTexture(gp);
362       initLighting();
363     break;
364     case wire :
365         default :
366       gp->drawFunc = (displayWire);
367       glDisable(GL_DEPTH_TEST);
368     break;
369   }
370
371   if(_flat) glShadeModel(GL_FLAT);
372   else glShadeModel(GL_SMOOTH);
373
374 }
375
376
377 /* xgflux initialization routine */
378 ENTRYPOINT void init_gflux(ModeInfo * mi)
379 {
380     int screen = MI_SCREEN(mi);
381     gfluxstruct *gp;
382
383     if (gfluxes == NULL) {
384         if ((gfluxes = (gfluxstruct *) 
385                  calloc(MI_NUM_SCREENS(mi), sizeof (gfluxstruct))) == NULL)
386             return;
387     }
388     gp = &gfluxes[screen];
389
390     gp->trackball = gltrackball_init ();
391
392     gp->time = frand(1000.0);  /* don't run two screens in lockstep */
393
394     {
395       char *s = get_string_resource (mi->dpy, "mode", "Mode");
396       if (!s || !*s)                       _draw = wire;
397       else if (!strcasecmp (s, "wire"))    _draw = wire;
398       else if (!strcasecmp (s, "solid"))   _draw = solid;
399       else if (!strcasecmp (s, "light"))   _draw = light;
400       else if (!strcasecmp (s, "checker")) _draw = checker;
401       else if (!strcasecmp (s, "grab"))    _draw = grab;
402       else
403         {
404           fprintf (stderr,
405                    "%s: mode must be one of: wire, solid, "
406                    "light, checker, or grab; not \"%s\"\n",
407                    progname, s);
408           exit (1);
409         }
410     }
411
412     gp->modeinfo = mi;
413     gp->window = MI_WINDOW(mi);
414     if ((gp->glx_context = init_GL(mi)) != NULL) {
415         reshape_gflux(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
416         initializeGL(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
417     } else {
418         MI_CLEARWINDOW(mi);
419     }
420 }
421
422 /* cleanup code */
423 ENTRYPOINT void release_gflux(ModeInfo * mi)
424 {
425     if (gfluxes != NULL) {
426       free((void *) gfluxes);
427       gfluxes = NULL;
428     }
429     FreeAllGL(mi);
430 }
431
432
433 static void createTexture(gfluxstruct *gp)
434 {
435   int size = 4;
436   unsigned int data[] = { 0xFFFFFFFF, 0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAAA,
437                           0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAAA, 0xFFFFFFFF,
438                           0xFFFFFFFF, 0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAAA,
439                           0xAAAAAAAA, 0xFFFFFFFF, 0xAAAAAAAA, 0xFFFFFFFF };
440
441   gp->tex_xscale = size;
442   gp->tex_yscale = size;
443
444   glGenTextures (1, &gp->texName);
445   glBindTexture (GL_TEXTURE_2D, gp->texName);
446
447   glTexImage2D (GL_TEXTURE_2D, 0, 3, size, size, 0,
448                 GL_RGBA, GL_UNSIGNED_BYTE, data);
449
450   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
451   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
452
453   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
454   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
455 }
456
457
458 static void
459 image_loaded_cb (const char *filename, XRectangle *geometry,
460                  int image_width, int image_height, 
461                  int texture_width, int texture_height,
462                  void *closure)
463 {
464   gfluxstruct *gp = (gfluxstruct *) closure;
465   gp->img_geom = *geometry;
466
467   gp->tex_xscale =  (GLfloat) image_width  / texture_width;
468   gp->tex_yscale = -(GLfloat) image_height / texture_height;
469   gp->img_width  = image_width;
470   gp->img_height = image_height;
471    
472   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
473   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
474                    (gp->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
475
476   gp->waiting_for_image_p = False;
477 }
478
479 static void
480 grabTexture(gfluxstruct *gp)
481 {
482   if (MI_IS_WIREFRAME(gp->modeinfo))
483     return;
484
485   gp->waiting_for_image_p = True;
486   gp->mipmap_p = True;
487   load_texture_async (gp->modeinfo->xgwa.screen, gp->modeinfo->window,
488                       *gp->glx_context, 0, 0, gp->mipmap_p, gp->texName,
489                       image_loaded_cb, gp);
490 }
491
492
493 static void initLighting(void)
494 {
495     static const float ambientA[]  = {0.0, 0.0, 0.0, 1.0};
496     static const float diffuseA[]  = {1.0, 1.0, 1.0, 1.0};
497     static const float positionA[] = {5.0, 5.0, 15.0, 1.0};
498
499     static const float front_mat_shininess[] = {30.0};
500     static const float front_mat_specular[]  = {0.5, 0.5, 0.5, 1.0};
501
502     static const float mat_diffuse[] = {0.5, 0.5, 0.5, 1.0};
503
504     glMaterialfv(GL_FRONT, GL_SHININESS, front_mat_shininess);
505     glMaterialfv(GL_FRONT, GL_SPECULAR, front_mat_specular);
506
507     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
508
509     glLightfv(GL_LIGHT0, GL_AMBIENT, ambientA);
510     glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseA);
511     glLightfv(GL_LIGHT0, GL_POSITION, positionA);
512     glEnable(GL_LIGHTING);
513     glEnable(GL_LIGHT0);
514     glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,1);
515
516     glEnable(GL_NORMALIZE);         /* would it be faster ...   */
517     glEnable(GL_COLOR_MATERIAL);
518     glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
519 }
520
521 /************************************/
522 /* draw implementations             */
523 /* somewhat inefficient since they  */
524 /* all calculate previously         */
525 /* calculated values again          */
526 /* storing the values in an array   */
527 /* is a posibility                  */
528 /************************************/
529 static int displayTexture(gfluxstruct *gp)
530 {
531     int polys = 0;
532     double x,y,u,v;
533     double z;
534     double dx = 2.0/((double)_squares);
535     double dy = 2.0/((double)_squares);
536
537     double du = 2.0/((double)_squares);
538     double dv = 2.0/((double)_squares);
539
540     double xs = gp->tex_xscale;
541     double ys = gp->tex_yscale;
542
543     double minx, miny, maxx, maxy;
544     double minu, minv;
545
546 #if 0
547     minx = (GLfloat) gp->img_geom.x / gp->img_width;
548     miny = (GLfloat) gp->img_geom.y / gp->img_height;
549     maxx = ((GLfloat) (gp->img_geom.x + gp->img_geom.width) /
550             gp->img_width);
551     maxy = ((GLfloat) (gp->img_geom.y + gp->img_geom.height) /
552             gp->img_height);
553     minu = minx;
554     minv = miny;
555     minx = (minx * 2) - 1;
556     miny = (miny * 2) - 1;
557     maxx = (maxx * 2) - 1;
558     maxy = (maxy * 2) - 1;
559 #else
560     minx = -1;
561     miny = -1;
562     maxx = 1;
563     maxy = 1;
564     minv = 0;
565     minu = 0;
566 #endif
567
568         glMatrixMode (GL_TEXTURE);
569         glLoadIdentity ();
570         glTranslatef(-1,-1,0);
571         glScalef(0.5,0.5,1);
572         glMatrixMode (GL_MODELVIEW);
573
574     glLoadIdentity();
575     userRot(gp);
576     glRotatef(gp->anglex,1,0,0);
577     glRotatef(gp->angley,0,1,0);
578     glRotatef(gp->anglez,0,0,1);
579     glScalef(1,1,(GLfloat)_waveHeight);
580     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
581         glEnable(GL_TEXTURE_2D);
582
583     clear_gl_error();
584         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
585         glBindTexture(GL_TEXTURE_2D, gp->texName);
586     check_gl_error("texture binding");
587
588         glColor3f(0.5,0.5,0.5);
589  
590     for(x = minx, u = minu; x < maxx - 0.01; x += dx, u += du) {
591         glBegin(GL_QUAD_STRIP);
592         for (y = miny, v = minv; y <= maxy + 0.01; y += dy, v += dv) {
593             z = getGrid(gp,x,y,gp->time);
594             glTexCoord2f(u*xs,v*ys);
595             glNormal3f(
596                 getGrid(gp,x+dx,y,gp->time)-getGrid(gp, x-dx,y,gp->time),
597                 getGrid(gp,x,y+dy,gp->time)-getGrid(gp, x,y-dy,gp->time),
598                 1
599             );
600             glVertex3f(x,y,z);
601
602             z = getGrid(gp,x+dx,y,gp->time);
603             glTexCoord2f((u+du)*xs,v*ys);
604             glNormal3f(
605                 getGrid(gp,x+dx+dx,y,gp->time)-getGrid(gp, x,y,gp->time),
606                 getGrid(gp,x+dx,y+dy,gp->time)-getGrid(gp, x+dx,y-dy,gp->time),
607                 1
608             );
609             glVertex3f(x+dx,y,z);
610             polys++;
611         }
612         glEnd();
613     }
614
615     /* Draw a border around the grid.
616      */
617     glColor3f(0.4, 0.4, 0.4);
618     glDisable(GL_TEXTURE_2D);
619     glEnable (GL_LINE_SMOOTH);
620
621     glBegin(GL_LINE_LOOP);
622     y = miny;
623     for (x = minx; x <= maxx; x += dx) {
624       glVertex3f (x, y, getGrid (gp, x, y, gp->time));
625       polys++;
626     }
627     x = maxx;
628     for (y = miny; y <= maxy; y += dy) {
629       glVertex3f (x, y, getGrid (gp, x, y, gp->time));
630       polys++;
631     }
632     y = maxy;
633     for (x = maxx; x >= minx; x -= dx) {
634       glVertex3f (x, y, getGrid (gp, x, y, gp->time));
635       polys++;
636     }
637     x = minx;
638     for (y = maxy; y >= miny; y -= dy) {
639       glVertex3f (x, y, getGrid (gp, x, y, gp->time));
640       polys++;
641     }
642     glEnd();
643     glEnable(GL_TEXTURE_2D);
644
645     if (! gp->button_down_p) {
646       gp->time -= _speed;
647       gp->anglex -= _rotationx;
648       gp->angley -= _rotationy;
649       gp->anglez -= _rotationz;
650     }
651     return polys;
652 }
653
654 static int displaySolid(gfluxstruct *gp)
655 {
656     int polys = 0;
657     double x,y;
658     double z;
659     double dx = 2.0/((double)_squares);
660     double dy = 2.0/((double)_squares);
661
662     glLoadIdentity();
663     glRotatef(gp->anglex,1,0,0);
664     glRotatef(gp->angley,0,1,0);
665     glRotatef(gp->anglez,0,0,1);
666     userRot(gp);
667     glScalef(1,1,(GLfloat)_waveHeight);
668     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
669
670     for(x=-1;x<0.9999;x+=dx) {
671         glBegin(GL_QUAD_STRIP);
672         for(y=-1;y<=1;y+=dy) {
673             z = getGrid(gp, x,y,gp->time);
674             genColour(z);
675             glColor3fv(gp->colour);
676             glVertex3f(x,y,z);
677
678             z = getGrid(gp, x+dx,y,gp->time);
679             genColour(z);
680             glColor3fv(gp->colour);
681             glVertex3f(x+dx,y,z);
682             polys++;
683         }
684         glEnd();
685     }
686
687     if (! gp->button_down_p) {
688       gp->time -= _speed;
689       gp->anglex -= _rotationx;
690       gp->angley -= _rotationy;
691       gp->anglez -= _rotationz;
692     }
693
694     return polys;
695 }
696
697 static int displayLight(gfluxstruct *gp)
698 {
699     int polys = 0;
700     double x,y;
701     double z;
702     double dx = 2.0/((double)_squares);
703     double dy = 2.0/((double)_squares);
704
705     glLoadIdentity();
706     glRotatef(gp->anglex,1,0,0);
707     glRotatef(gp->angley,0,1,0);
708     glRotatef(gp->anglez,0,0,1);
709     userRot(gp);
710     glScalef(1,1,(GLfloat)_waveHeight);
711     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
712
713     for(x=-1;x<0.9999;x+=dx) {
714         glBegin(GL_QUAD_STRIP);
715         for(y=-1;y<=1;y+=dy) {
716             z = getGrid(gp, x,y,gp->time);
717             genColour(z);
718             glColor3fv(gp->colour);
719             glNormal3f(
720                 getGrid(gp, x+dx,y,gp->time)-getGrid(gp, x-dx,y,gp->time),
721                 getGrid(gp, x,y+dy,gp->time)-getGrid(gp, x,y-dy,gp->time),
722                 1
723             );
724             glVertex3f(x,y,z);
725
726             z = getGrid(gp, x+dx,y,gp->time);
727             genColour(z);
728             glColor3fv(gp->colour);
729             glNormal3f(
730                 getGrid(gp, x+dx+dx,y,gp->time)-getGrid(gp, x,y,gp->time),
731                 getGrid(gp, x+dx,y+dy,gp->time)-getGrid(gp, x+dx,y-dy,gp->time),
732                 1
733             );
734             glVertex3f(x+dx,y,z);
735             polys++;
736         }
737         glEnd();
738     }
739
740     if (! gp->button_down_p) {
741       gp->time -= _speed;
742       gp->anglex -= _rotationx;
743       gp->angley -= _rotationy;
744       gp->anglez -= _rotationz;
745     }
746     return polys;
747 }
748
749 static int displayWire(gfluxstruct *gp)
750 {
751     int polys = 0;
752     double x,y;
753     double z;
754     double dx1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
755     double dy1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
756     double dx2 = 2.0/((double)_squares) - 0.00001;
757     double dy2 = 2.0/((double)_squares) - 0.00001;
758
759     glLoadIdentity();
760     glRotatef(gp->anglex,1,0,0);
761     glRotatef(gp->angley,0,1,0);
762     glRotatef(gp->anglez,0,0,1);
763     userRot(gp);
764     glScalef(1,1,(GLfloat)_waveHeight);
765     glClear(GL_COLOR_BUFFER_BIT);
766
767     for(x=-1;x<=1;x+=dx2) {
768         glBegin(GL_LINE_STRIP);
769         for(y=-1;y<=1;y+=dy1) {
770             z = getGrid(gp, x,y,gp->time);
771             genColour(z);
772             glColor3fv(gp->colour);
773             glVertex3f(x,y,z);
774             polys++;
775         }
776         glEnd();
777     }
778     for(y=-1;y<=1;y+=dy2) {
779         glBegin(GL_LINE_STRIP);
780         for(x=-1;x<=1;x+=dx1) {
781             z = getGrid(gp, x,y,gp->time);
782             genColour(z);
783             glColor3fv(gp->colour);
784             glVertex3f(x,y,z);
785             polys++;
786         }
787         glEnd();
788     }
789
790     if (! gp->button_down_p) {
791       gp->time -= _speed;
792       gp->anglex -= _rotationx;
793       gp->angley -= _rotationy;
794       gp->anglez -= _rotationz;
795     }
796     return polys;
797 }
798
799 /* generates new ripples */
800 static void calcGrid(gfluxstruct *gp)
801 {
802     double tmp;
803
804     if (gp->button_down_p) return;
805
806     tmp = 1.0/((double)_waveChange);
807     if(!(gp->counter%_waveChange)) {
808         gp->newWave = ((int)(gp->counter*tmp))%_waves;
809         gp->dispx[gp->newWave] = -frand(1.0);
810         gp->dispy[gp->newWave] = -frand(1.0);
811         gp->freq[gp->newWave] = _waveFreq * frand(1.0);
812         gp->wa[gp->newWave] = 0.0;
813     }
814     gp->counter++;
815     gp->wa[gp->newWave] += tmp;
816     gp->wa[(gp->newWave+1)%_waves] -= tmp;
817 }
818
819 /* returns a height for the grid given time and x,y space co-ords */
820 static double getGrid(gfluxstruct *gp, double x, double y, double a)
821 {
822     register int i;
823     double retval=0.0;
824     double tmp;
825
826     tmp = 1.0/((float)_waves);
827     for(i=0;i<_waves;i++) {
828       retval += gp->wa[i] * tmp * sin( gp->freq[i]
829               * ( (x+gp->dispx[i]) * (x+gp->dispx[i]) 
830                 + (y+gp->dispy[i]) * (y+gp->dispy[i]) +a ) );
831     }
832     return(retval);
833 }
834
835
836 XSCREENSAVER_MODULE ("GFlux", gflux)
837
838 #endif