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