http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.01.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
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  */
39
40
41 /*-
42  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
43  * otherwise caddr_t is not defined correctly
44  */
45
46 #include <X11/Intrinsic.h>
47
48
49 #ifdef STANDALONE
50 # define PROGCLASS                                              "gflux"
51 # define HACK_INIT                                              init_gflux
52 # define HACK_DRAW                                              draw_gflux
53 # define HACK_RESHAPE                                   reshape_gflux
54 # define gflux_opts                                             xlockmore_opts
55 #define DEFAULTS                        "*delay:                20000   \n" \
56                                                                                 "*showFPS:      False   \n" \
57                                         "*mode:         light" "\n" \
58                                         "*squares:      19      \n" \
59                                                                                 "*resolution:   0       \n" \
60                                         "*flat:         0       \n" \
61                                         "*speed:        0.05    \n" \
62                                         "*rotationx:    0.01    \n" \
63                                         "*rotationy:    0.0     \n" \
64                                         "*rotationz:    0.1     \n" \
65                                         "*waves:        3       \n" \
66                                         "*waveChange:   50      \n" \
67                                         "*waveHeight:  0.8      \n" \
68                                         "*waveFreq:    3.0      \n" \
69                                         "*zoom:        1.0      \n" 
70
71
72 # include "xlockmore.h"                         /* from the xscreensaver distribution */
73 #else /* !STANDALONE */
74 # include "xlock.h"                                     /* from the xlockmore distribution */
75 #endif /* !STANDALONE */
76
77 #ifdef USE_GL /* whole file */
78
79 #ifdef HAVE_XMU
80 # ifndef VMS
81 #  include <X11/Xmu/Drawing.h>
82 #else  /* VMS */
83 #  include <Xmu/Drawing.h>
84 # endif /* VMS */
85 #endif
86
87 #ifdef HAVE_PPM
88 #include <ppm.h>
89 #endif
90
91 #undef countof
92 #define countof(x) (sizeof((x))/sizeof((*x)))
93
94 #include <stdlib.h>
95 #include <stdio.h>
96
97 #include <GL/gl.h>
98 #include <GL/glu.h>
99 #include <GL/glx.h>
100
101 #include <math.h>
102
103 #include "grab-ximage.h"
104
105
106 static enum {wire=0,solid,light,checker,textured,grab} _draw; /* draw style */
107 static int _squares = 19;                                 /* grid size */
108 static int _resolution = 4;                    /* wireframe resolution */
109 static int _flat = 0;
110
111 static float _speed = 0.05;
112 static float _rotationx = 0.01;
113 static float _rotationy = 0.0;
114 static float _rotationz = 0.1;
115 static float _zoom = 1.0;
116
117 static int _waves = 3;
118 static int _waveChange = 50;
119 static float _waveHeight = 1.0;
120 static float _waveFreq = 3.0;
121
122 #define WIDTH 320
123 #define HEIGHT 240
124
125 static XrmOptionDescRec opts[] = {
126     {"-squares", ".gflux.squares", XrmoptionSepArg, (caddr_t) NULL},
127     {"-resolution", ".gflux.resolution", XrmoptionSepArg, (caddr_t) NULL},
128 /*    {"-draw", ".gflux.draw", XrmoptionSepArg, (caddr_t) NULL},*/
129     {"-mode", ".gflux.mode", XrmoptionSepArg, (caddr_t) NULL},
130     {"-flat", ".gflux.flat", XrmoptionSepArg, (caddr_t) NULL},
131     {"-speed", ".gflux.speed", XrmoptionSepArg, (caddr_t) NULL},
132     {"-rotationx", ".gflux.rotationx", XrmoptionSepArg, (caddr_t) NULL},
133     {"-rotationy", ".gflux.rotationy", XrmoptionSepArg, (caddr_t) NULL},
134     {"-rotationz", ".gflux.rotationz", XrmoptionSepArg, (caddr_t) NULL},
135     {"-waves", ".gflux.waves", XrmoptionSepArg, (caddr_t) NULL},
136     {"-waveChange", ".gflux.waveChange", XrmoptionSepArg, (caddr_t) NULL},
137     {"-waveHeight", ".gflux.waveHeight", XrmoptionSepArg, (caddr_t) NULL},
138     {"-waveFreq", ".gflux.waveFreq", XrmoptionSepArg, (caddr_t) NULL},
139     {"-zoom", ".gflux.zoom", XrmoptionSepArg, (caddr_t) NULL},
140 };
141
142
143 static argtype vars[] = {
144     {(caddr_t *) & _squares, "squares", "Squares", "19", t_Int},
145     {(caddr_t *) & _resolution, "resolution", "Resolution", "4", t_Int},
146 /*    {(caddr_t *) & _draw, "draw", "Draw", "2", t_Int},*/
147     {(caddr_t *) & _flat, "flat", "Flat", "0", t_Int},
148     {(caddr_t *) & _speed, "speed", "Speed", "0.05", t_Float},
149     {(caddr_t *) & _rotationx, "rotationx", "Rotationx", "0.01", t_Float},
150     {(caddr_t *) & _rotationy, "rotationy", "Rotationy", "0.0", t_Float},
151     {(caddr_t *) & _rotationz, "rotationz", "Rotationz", "0.1", t_Float},
152     {(caddr_t *) & _waves, "waves", "Waves", "3", t_Int},
153     {(caddr_t *) & _waveChange, "waveChange", "WaveChange", "50", t_Int},
154     {(caddr_t *) & _waveHeight, "waveHeight", "WaveHeight", "1.0", t_Float},
155     {(caddr_t *) & _waveFreq, "waveFreq", "WaveFreq", "3.0", t_Float},
156     {(caddr_t *) & _zoom, "zoom", "Zoom", "1.0", t_Float},
157 };
158
159
160 static OptionStruct desc[] =
161 {
162     {"-squares num", "size of grid in squares (19)"},
163     {"-resolution num", "detail of lines making grid, wireframe only (4)"},
164 /*    {"-draw num", "draw method to use: 0=wireframe 1=solid 2=lit (0)"},*/
165     {"-flat num", "shading method, not wireframe: 0=smooth 1=flat (0)"},
166     {"-speed num", "speed of waves (0.05)"},
167     {"-rotationx num", "speed of xrotation (0.01)"},
168     {"-rotationy num", "speed of yrotation (0.00)"},
169     {"-rotationz num", "speed of zrotation (0.10)"},
170     {"-waves num", "number of simultanious waves (3)"},
171     {"-waveChange num", "number of cyles for a wave to change (50)"},
172     {"-waveHeight num", "height of waves (1.0)"},
173     {"-waveFreq num", "max frequency of a wave (3.0)"},
174     {"-zoom num", "camera control (1.0)"},
175 };
176
177 ModeSpecOpt gflux_opts = {countof(opts), opts, countof(vars), vars, desc};
178
179 #ifdef USE_MODULES
180 ModStruct   gflux_description =
181 {"gflux", "init_gflux", "draw_gflux", "release_gflux",
182  "draw_gflux", "init_gflux", NULL, &gflux_opts,
183  1000, 1, 2, 1, 4, 1.0, "",
184  "Gflux: an OpenGL gflux", 0, NULL};
185 #endif
186
187 /* structure for holding the gflux data */
188 typedef struct {
189     ModeInfo *modeinfo;
190     int screen_width, screen_height;
191     GLXContext *glx_context;
192     Window window;
193     XColor fg, bg;
194 #define MAXWAVES 10   /* should be dynamic    */
195     double wa[MAXWAVES];
196     double freq[MAXWAVES];
197     double dispy[MAXWAVES];
198     double dispx[MAXWAVES];
199     GLfloat colour[3];
200     int imageWidth;
201     int imageHeight;
202 #ifdef HAVE_PPM
203         pixval imageMax;
204     pixel **image;
205 #else
206         int imageMax;
207         GLubyte *image;
208 #endif
209     GLint texName;
210     GLfloat tex_xscale;
211     GLfloat tex_yscale;
212     void (*drawFunc)(void);
213 } gfluxstruct;
214 static gfluxstruct *gflux = NULL;
215
216 /* prototypes */
217 void initLighting(void);
218 void initTexture(void);
219 void loadTexture(void);
220 void grabTexture(void);
221 void createTexture(void);
222 void displaySolid(void);            /* drawFunc implementations */
223 void displayLight(void);
224 void displayTexture(void);
225 void displayWire(void);
226 void calcGrid(void);
227 double getGrid(double,double,double);
228
229 /* as macro for speed */
230 /* could do with colour cycling here */
231 /* void genColour(double);*/
232 #define genColour(X) \
233 {\
234     gflux->colour[0] = 0.0;\
235     gflux->colour[1] = 0.5+0.5*(X);\
236     gflux->colour[2] = 0.5-0.5*(X);\
237 }
238
239 /* BEGINNING OF FUNCTIONS */
240
241
242 /* draw the gflux once */
243 void draw_gflux(ModeInfo * mi)
244 {
245     gfluxstruct *gp = &gflux[MI_SCREEN(mi)];
246     Display    *display = MI_DISPLAY(mi);
247     Window      window = MI_WINDOW(mi);
248
249     if (!gp->glx_context) return;
250
251     glXMakeCurrent(display, window, *(gp->glx_context));
252
253     calcGrid();
254     gflux->drawFunc();
255     if (mi->fps_p) do_fps (mi);
256     glXSwapBuffers(display, window);
257 }
258
259
260 /* reset the projection matrix */
261 void resetProjection(void) {
262     glMatrixMode(GL_PROJECTION);
263     glLoadIdentity();
264     glFrustum(-_zoom,_zoom,-0.8*_zoom,0.8*_zoom,2,6);
265     glTranslatef(0.0,0.0,-4.0);
266     glMatrixMode(GL_MODELVIEW);
267     glLoadIdentity();
268 }
269
270 /* Standard reshape function */
271 void
272 reshape_gflux(ModeInfo *mi, int width, int height)
273 {
274     glViewport( 0, 0, width, height );
275     resetProjection();
276 }
277
278
279 /* main OpenGL initialization routine */
280 void initializeGL(ModeInfo *mi, GLsizei width, GLsizei height) 
281 {
282   reshape_gflux(mi, width, height);
283   glViewport( 0, 0, width, height ); 
284
285   gflux->tex_xscale = 1.0;  /* maybe changed later */
286   gflux->tex_yscale = 1.0;
287
288   switch(_draw) {
289     case solid :
290       gflux->drawFunc = (displaySolid);
291       glEnable(GL_DEPTH_TEST);
292     break;
293     case light :
294       gflux->drawFunc = (displayLight);
295       glEnable(GL_DEPTH_TEST);
296       initLighting();
297         break;
298         case checker :
299       gflux->drawFunc = (displayTexture);
300       glEnable(GL_DEPTH_TEST);
301       createTexture();
302       initTexture();
303       initLighting();
304     break;
305         case textured :
306       gflux->drawFunc = (displayTexture);
307       glEnable(GL_DEPTH_TEST);
308       loadTexture();
309       initTexture();
310       initLighting();
311     break;
312         case grab :
313       gflux->drawFunc = (displayTexture);
314       glEnable(GL_DEPTH_TEST);
315       grabTexture();
316       initTexture();
317       initLighting();
318     break;
319     case wire :
320         default :
321       gflux->drawFunc = (displayWire);
322       glDisable(GL_DEPTH_TEST);
323     break;
324   }
325
326   if(_flat) glShadeModel(GL_FLAT);
327   else glShadeModel(GL_SMOOTH);
328
329 }
330
331
332 /* xgflux initialization routine */
333 void init_gflux(ModeInfo * mi)
334 {
335     int screen = MI_SCREEN(mi);
336     gfluxstruct *gp;
337
338     if (gflux == NULL) {
339         if ((gflux = (gfluxstruct *) 
340                  calloc(MI_NUM_SCREENS(mi), sizeof (gfluxstruct))) == NULL)
341             return;
342     }
343     gp = &gflux[screen];
344
345     {
346       char *s = get_string_resource ("mode", "Mode");
347       if (!s || !*s)                       _draw = wire;
348       else if (!strcasecmp (s, "wire"))    _draw = wire;
349       else if (!strcasecmp (s, "solid"))   _draw = solid;
350       else if (!strcasecmp (s, "light"))   _draw = light;
351       else if (!strcasecmp (s, "checker")) _draw = checker;
352       else if (!strcasecmp (s, "stdin"))   _draw = textured;
353       else if (!strcasecmp (s, "grab"))    _draw = grab;
354       else
355         {
356           fprintf (stderr,
357                    "%s: mode must be one of: wire, solid, "
358                    "light, checker, or grab; not \"%s\"\n",
359                    progname, s);
360           exit (1);
361         }
362     }
363
364     gp->modeinfo = mi;
365     gp->window = MI_WINDOW(mi);
366     if ((gp->glx_context = init_GL(mi)) != NULL) {
367         reshape_gflux(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
368         initializeGL(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
369     } else {
370         MI_CLEARWINDOW(mi);
371     }
372 }
373
374 /* cleanup code */
375 void release_gflux(ModeInfo * mi)
376 {
377     if(gflux->image!=NULL) free(gflux->image);
378     if(gflux->glx_context!=NULL) free(gflux->glx_context);
379     if (gflux != NULL) {
380         (void) free((void *) gflux);
381         gflux = NULL;
382     }
383     FreeAllGL(mi);
384 }
385
386 #ifdef HAVE_PPM
387
388 /* load pnm from stdin using pnm libs */
389 void loadTexture(void)
390 {
391     FILE *file = stdin;
392         gflux->image = ppm_readppm( file, 
393                         &(gflux->imageHeight), &(gflux->imageWidth), &(gflux->imageMax) );
394 }
395
396 /* creates an image for texture mapping */
397 void createTexture(void)
398 {
399     int i,j,c;
400     pixel **result;
401
402         gflux->imageHeight = gflux->imageWidth = 8;
403
404         result = ppm_allocarray(gflux->imageHeight,gflux->imageWidth);
405     for(i=0;i<gflux->imageHeight;i++) {
406         for(j=0;j<gflux->imageWidth;j++) {
407             c = (((i)%2 ^ (j)%2) ? 100 : 200 );
408                         PPM_ASSIGN( result[i][j] , c, c, c );
409         }
410     }
411         gflux->image = result;
412 }
413
414 /* specifies image as texture */    
415 void initTexture(void)
416 {
417         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
418         glGenTextures(1, &gflux->texName);
419         glBindTexture(GL_TEXTURE_2D, gflux->texName);
420         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
421         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
422         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
423         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
424
425     clear_gl_error();
426         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, gflux->imageWidth,
427                         gflux->imageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, *(gflux->image));
428     check_gl_error("texture");
429 }
430
431 #else /* HAVE_PPM FALSE */
432
433 #define presult(A,B,C) (*(result+(A)*(gflux->imageWidth)*4+(B)*4+(C)))
434 void loadTexture(void)
435 {
436     int i, j, levels, width, height;
437     int red,green,blue;
438     char s[4];
439     int ppmType=0;
440     FILE *file = stdin;
441     GLubyte *result;
442
443     fgets(s,4,file);
444
445     if(!strncmp(s,"P6",2)) ppmType=6;
446     if(!strncmp(s,"P5",2)) ppmType=5;
447     if(!strncmp(s,"P3",2)) ppmType=3;
448     if(!strncmp(s,"P2",2)) ppmType=2;
449     if(!ppmType)exit(1);
450
451     while((i=getc(file))=='#')
452     {
453         while(getc(file)!='\n');
454     }
455     ungetc(i,file);
456
457     fscanf(file,"%d %d %d",&width,&height,&levels);
458
459     result = malloc(sizeof(GLubyte)*4*width*height);
460     gflux->imageWidth = width;
461     gflux->imageHeight = height;
462
463     switch(ppmType) {
464         case 2 :    /* ASCII grey */
465             for(i=0;i<height;i++) {
466                 for(j=0;j<width;j++) {
467                     fscanf(file,"%d",&red);
468                     presult(j,i,0) = red;
469                     presult(j,i,1) = red;
470                     presult(j,i,2) = red;
471                 }
472             }
473             break;
474         case 3 :    /* ASCII rgb */
475             for(i=0;i<height;i++) {
476                 for(j=0;j<width;j++) {
477                    fscanf(file,"%d %d %d",&red,&green,&blue);
478                     presult(j,i,0) = red;
479                     presult(j,i,1) = green;
480                     presult(j,i,2) = blue;
481                 }
482             }
483             break;
484         case 5 :    /* Binary grey */
485             getc(file); /* seems nessessary */
486             for(i=0;i<height;i++) {
487                 for(j=0;j<width;j++) {
488                     red = getc(file);
489                     presult(j,i,0) = red;
490                     presult(j,i,1) = red;
491                     presult(j,i,2) = red;
492                 }
493             }
494         break;
495         case 6 :    /* Binary rgb */
496             getc(file); /* seems nessessary */
497             for(i=0;i<height;i++) {
498                 for(j=0;j<width;j++) {
499                     red = getc(file);
500                     green = getc(file);
501                     blue = getc(file);
502                     presult(j,i,0) = red;
503                     presult(j,i,1) = green;
504                     presult(j,i,2) = blue;
505                 }
506             }
507         break;
508     }
509     gflux->image = result;
510 }
511
512 void createTexture(void)
513 {
514     int i,j,c;
515     GLubyte *result;
516
517     gflux->imageHeight = gflux->imageWidth = 8;
518
519     result = malloc(sizeof(GLubyte)*4*gflux->imageHeight*gflux->imageWidth);
520     for(i=0;i<gflux->imageHeight;i++) {
521         for(j=0;j<gflux->imageWidth;j++) {
522             c = (((i)%2 ^ (j)%2) ? 100 : 200 );
523             presult(i,j,0) = (GLubyte) c;
524             presult(i,j,1) = (GLubyte) c;
525             presult(i,j,2) = (GLubyte) c;
526             presult(i,j,3) = (GLubyte) 255;
527         }
528     }
529     gflux->image = result;
530 }
531
532 /* specifies image as texture */
533 void initTexture(void)
534 {
535     clear_gl_error();
536     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
537     glGenTextures(1, &gflux->texName);
538     glBindTexture(GL_TEXTURE_2D, gflux->texName);
539     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
540     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
541     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
542     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
543     check_gl_error("texture parameter");
544
545     /* Bail out if the texture is too large. */
546     {
547       GLint width;
548       glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, gflux->imageWidth,
549                    gflux->imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
550       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0,
551                                 GL_TEXTURE_WIDTH, &width);
552       if (width <= 0)
553         {
554           glGetIntegerv (GL_MAX_TEXTURE_SIZE, &width);
555           fprintf (stderr,
556                    "%s: texture too large (%dx%d -- probable max %dx%d)\n",
557                    progname, gflux->imageWidth, gflux->imageHeight,
558                    width, width);
559           return;
560         }
561     }
562
563     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gflux->imageWidth,
564             gflux->imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, gflux->image);
565     check_gl_error("texture creation");
566 }
567
568 #undef presult
569 #endif
570
571
572 void
573 grabTexture(void)
574 {
575   int real_width  = gflux->modeinfo->xgwa.width;
576   int real_height = gflux->modeinfo->xgwa.height;
577   XImage *ximage = screen_to_ximage (gflux->modeinfo->xgwa.screen,
578                                      gflux->window);
579
580   if (ximage->width > 1280 ||   /* that's too damned big... */
581       ximage->height > 1280)
582     {
583       Display *dpy = gflux->modeinfo->dpy;
584       Visual *v = gflux->modeinfo->xgwa.visual;
585       int size = (ximage->width < ximage->height ?
586                   ximage->width : ximage->height);
587       int real_size = (ximage->width < ximage->height ?
588                        real_width : real_height);
589       XImage *x2;
590       int x, y, xoff, yoff;
591
592       if (size > 1024) size = 1024;
593
594       x2 = XCreateImage (dpy, v, 32, ZPixmap, 0, 0, size, size, 32, 0);
595       xoff = (real_width  > size ? (random() % (real_width  - size)) : 0);
596       yoff = (real_height > size ? (random() % (real_height - size)) : 0);
597
598 # if 0
599       fprintf(stderr, "%s: cropping texture from %dx%d to %dx%d @ %d,%d\n",
600               progname, ximage->width, ximage->height, x2->width, x2->height,
601               xoff, yoff);
602 # endif
603       x2->data = ximage->data;  /* we can reuse the same array */
604       for (y = 0; y < x2->height; y++)
605         for (x = 0; x < x2->width; x++)
606           XPutPixel (x2, x, y, XGetPixel (ximage, x+xoff, y+yoff));
607
608       real_width = real_height = real_size;
609       ximage->data = 0;
610       XDestroyImage (ximage);
611       ximage = x2;
612     }
613
614   /* Add a border. */
615   {
616     unsigned long gray = 0xAAAAAAAAL;  /* so shoot me */
617     int i;
618     for (i = 0; i < real_height; i++)
619       {
620         XPutPixel (ximage, 0, i, gray);
621         XPutPixel (ximage, real_width-1, i, gray);
622       }
623     for (i = 0; i < real_width; i++)
624       {
625         XPutPixel (ximage, i, 0, gray);
626         XPutPixel (ximage, i, real_height-1, gray);
627       }
628   }
629
630   gflux->imageWidth  = ximage->width;
631   gflux->imageHeight = ximage->height;
632   gflux->image = ximage->data;
633
634   gflux->tex_xscale = ((GLfloat) real_width  / (GLfloat) ximage->width);
635   gflux->tex_yscale = ((GLfloat) real_height / (GLfloat) ximage->height);
636
637   ximage->data = 0;
638   XDestroyImage (ximage);
639 }
640
641
642 void initLighting(void)
643 {
644     static float ambientA[] = {0.0, 0.0, 0.0, 1.0};
645     static float diffuseA[] = {1.0, 1.0, 1.0, 1.0};
646     static float positionA[] = {5.0, 5.0, 15.0, 1.0};
647
648     static float front_mat_shininess[] = {30.0};
649     static float front_mat_specular[] = {0.5, 0.5, 0.5, 1.0};
650
651     static float mat_diffuse[] = {0.5, 0.5, 0.5, 1.0};
652
653     glMaterialfv(GL_FRONT, GL_SHININESS, front_mat_shininess);
654     glMaterialfv(GL_FRONT, GL_SPECULAR, front_mat_specular);
655
656     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
657
658     glLightfv(GL_LIGHT0, GL_AMBIENT, ambientA);
659     glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseA);
660     glLightfv(GL_LIGHT0, GL_POSITION, positionA);
661     glEnable(GL_LIGHTING);
662     glEnable(GL_LIGHT0);
663     glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,1);
664
665     glEnable(GL_NORMALIZE);         /* would it be faster ...   */
666     glEnable(GL_COLOR_MATERIAL);
667     glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
668 }
669
670 /************************************/
671 /* draw implementations             */
672 /* somewhat inefficient since they  */
673 /* all calculate previously         */
674 /* calculated values again          */
675 /* storing the values in an array   */
676 /* is a posibility                  */
677 /************************************/
678 void displayTexture(void)
679 {
680     static double time = 0.0;
681     static double anglex = 0.0;
682     static double angley = 0.0;
683     static double anglez = 0.0;
684
685     double x,y,u,v;
686     double z;
687     double dx = 2.0/((double)_squares);
688     double dy = 2.0/((double)_squares);
689
690     double du = 2.0/((double)_squares);
691     double dv = 2.0/((double)_squares);
692
693     double xs = gflux->tex_xscale;
694     double ys = gflux->tex_yscale;
695
696         glMatrixMode (GL_TEXTURE);
697         glLoadIdentity ();
698         glTranslatef(-1,-1,0);
699         glScalef(0.5,0.5,1);
700         glMatrixMode (GL_MODELVIEW);
701
702     glLoadIdentity();
703     glRotatef(anglex,1,0,0);
704     glRotatef(angley,0,1,0);
705     glRotatef(anglez,0,0,1);
706     glScalef(1,1,(GLfloat)_waveHeight);
707     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
708         glEnable(GL_TEXTURE_2D);
709
710     clear_gl_error();
711         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
712         glBindTexture(GL_TEXTURE_2D, gflux->texName);
713     check_gl_error("texture binding");
714
715         glColor3f(0.5,0.5,0.5);
716  
717     for(x=-1,u= 0;x<0.9999;x+=dx,u+=du) {
718         glBegin(GL_QUAD_STRIP);
719         for(y=-1,v= 0;y<=1;y+=dy,v+=dv) {
720             z = getGrid(x,y,time);
721         /*  genColour(z);
722             glColor3fv(gflux->colour);
723         */  glTexCoord2f(u*xs,v*ys);
724             glNormal3f(
725                 getGrid(x+dx,y,time)-getGrid(x-dx,y,time),
726                 getGrid(x,y+dy,time)-getGrid(x,y-dy,time),
727                 1
728             );
729             glVertex3f(x,y,z);
730
731             z = getGrid(x+dx,y,time);
732         /*  genColour(z);
733             glColor3fv(gflux->colour);
734         */  glTexCoord2f((u+du)*xs,v*ys);
735             glNormal3f(
736                 getGrid(x+dx+dx,y,time)-getGrid(x,y,time),
737                 getGrid(x+dx,y+dy,time)-getGrid(x+dx,y-dy,time),
738                 1
739             );
740             glVertex3f(x+dx,y,z);
741         }
742         glEnd();
743     }
744
745     time -= _speed;
746     anglex -= _rotationx;
747     angley -= _rotationy;
748     anglez -= _rotationz;
749 }
750 void displaySolid(void)
751 {
752     static double time = 0.0;
753     static double anglex = 0.0;
754     static double angley = 0.0;
755     static double anglez = 0.0;
756
757     double x,y;
758     double z;
759     double dx = 2.0/((double)_squares);
760     double dy = 2.0/((double)_squares);
761
762     glLoadIdentity();
763     glRotatef(anglex,1,0,0);
764     glRotatef(angley,0,1,0);
765     glRotatef(anglez,0,0,1);
766     glScalef(1,1,(GLfloat)_waveHeight);
767     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
768
769     for(x=-1;x<0.9999;x+=dx) {
770         glBegin(GL_QUAD_STRIP);
771         for(y=-1;y<=1;y+=dy) {
772             z = getGrid(x,y,time);
773             genColour(z);
774             glColor3fv(gflux->colour);
775             glVertex3f(x,y,z);
776
777             z = getGrid(x+dx,y,time);
778             genColour(z);
779             glColor3fv(gflux->colour);
780             glVertex3f(x+dx,y,z);
781         }
782         glEnd();
783     }
784
785     time -= _speed;
786     anglex -= _rotationx;
787     angley -= _rotationy;
788     anglez -= _rotationz;
789
790 }
791
792 void displayLight(void)
793 {
794     static double time = 0.0;
795     static double anglex = 0.0;
796     static double angley = 0.0;
797     static double anglez = 0.0;
798
799     double x,y;
800     double z;
801     double dx = 2.0/((double)_squares);
802     double dy = 2.0/((double)_squares);
803
804     glLoadIdentity();
805     glRotatef(anglex,1,0,0);
806     glRotatef(angley,0,1,0);
807     glRotatef(anglez,0,0,1);
808     glScalef(1,1,(GLfloat)_waveHeight);
809     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
810
811     for(x=-1;x<0.9999;x+=dx) {
812         glBegin(GL_QUAD_STRIP);
813         for(y=-1;y<=1;y+=dy) {
814             z = getGrid(x,y,time);
815             genColour(z);
816             glColor3fv(gflux->colour);
817             glNormal3f(
818                 getGrid(x+dx,y,time)-getGrid(x-dx,y,time),
819                 getGrid(x,y+dy,time)-getGrid(x,y-dy,time),
820                 1
821             );
822             glVertex3f(x,y,z);
823
824             z = getGrid(x+dx,y,time);
825             genColour(z);
826             glColor3fv(gflux->colour);
827             glNormal3f(
828                 getGrid(x+dx+dx,y,time)-getGrid(x,y,time),
829                 getGrid(x+dx,y+dy,time)-getGrid(x+dx,y-dy,time),
830                 1
831             );
832             glVertex3f(x+dx,y,z);
833         }
834         glEnd();
835     }
836
837     time -= _speed;
838     anglex -= _rotationx;
839     angley -= _rotationy;
840     anglez -= _rotationz;
841 }
842
843 void displayWire(void)
844 {
845     static double time = 0.0;
846     static double anglex = 0.0;
847     static double angley = 0.0;
848     static double anglez = 0.0;
849
850     double x,y;
851     double z;
852     double dx1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
853     double dy1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
854     double dx2 = 2.0/((double)_squares) - 0.00001;
855     double dy2 = 2.0/((double)_squares) - 0.00001;
856
857     glLoadIdentity();
858     glRotatef(anglex,1,0,0);
859     glRotatef(angley,0,1,0);
860     glRotatef(anglez,0,0,1);
861     glScalef(1,1,(GLfloat)_waveHeight);
862     glClear(GL_COLOR_BUFFER_BIT);
863
864     for(x=-1;x<=1;x+=dx2) {
865         glBegin(GL_LINE_STRIP);
866         for(y=-1;y<=1;y+=dy1) {
867             z = getGrid(x,y,time);
868             genColour(z);
869             glColor3fv(gflux->colour);
870             glVertex3f(x,y,z);
871         }
872         glEnd();
873     }
874     for(y=-1;y<=1;y+=dy2) {
875         glBegin(GL_LINE_STRIP);
876         for(x=-1;x<=1;x+=dx1) {
877             z = getGrid(x,y,time);
878             genColour(z);
879             glColor3fv(gflux->colour);
880             glVertex3f(x,y,z);
881         }
882         glEnd();
883     }
884
885     time -= _speed;
886     anglex -= _rotationx;
887     angley -= _rotationy;
888     anglez -= _rotationz;
889 }
890
891 /* generates new ripples */
892 void calcGrid(void)
893 {
894     static int counter=0;
895     double tmp;
896     static int newWave;
897
898     tmp = 1.0/((double)_waveChange);
899     if(!(counter%_waveChange)) {
900         newWave = ((int)(counter*tmp))%_waves;
901         gflux->dispx[newWave] = 1.0 - ((double)random())/RAND_MAX;
902         gflux->dispy[newWave] = 1.0 - ((double)random())/RAND_MAX;
903         gflux->freq[newWave] = _waveFreq * ((float)random())/RAND_MAX;
904         gflux->wa[newWave] = 0.0;
905     }
906     counter++;
907     gflux->wa[newWave] += tmp;
908     gflux->wa[(newWave+1)%_waves] -= tmp;
909 }
910
911 /* returns a height for the grid given time and x,y space co-ords */
912 double getGrid(double x, double y, double a)
913 {
914     register int i;
915     double retval=0.0;
916     double tmp;
917
918     tmp = 1.0/((float)_waves);
919     for(i=0;i<_waves;i++) {
920       retval += gflux->wa[i] * tmp * sin( gflux->freq[i]
921               * ( (x+gflux->dispx[i]) * (x+gflux->dispx[i]) 
922                 + (y+gflux->dispy[i]) * (y+gflux->dispy[i]) +a ) );
923     }
924     return(retval);
925 }
926
927 #endif
928