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