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