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