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