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