1 /* -*- Mode: C; tab-width: 4 -*- emacs friendly */
3 /* gflux - creates a fluctuating 3D grid
4 * requires OpenGL or MesaGL
6 * Copyright (c) Josiah Pease, 2000
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation. No representations are made about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
15 * Thanks go to all those who worked on...
16 * MesaGL, OpenGL, UtahGLX, XFree86, gcc, vim, rxvt, the PNM (anymap) format
17 * xscreensaver and the thousands of other tools, apps and daemons that make
19 * Personal thanks to Kevin Moss, Paul Sheahee and Jamie Zawinski
21 * some xscreensaver code lifted from superquadrics. Most other glx hacks
22 * used as reference at some time.
24 * This hack and others can cause UtahGLX to crash my X server
25 * wireframe looks good with software only rendering anyway
26 * If anyone can work out why and supply a fix I'd love to hear from them
28 * Josiah Pease <gfluxcode@jpease.force9.co.uk> 21 July 2000
31 * 10 June 2000 : wireframe rippling grid standalone written
32 * 18 June 2000 : xscreensaver code added
33 * 25 June 2000 : solid and light added
34 * 04 July 2000 : majour bug hunt, xscreensaver code rewritten
35 * 08 July 2000 : texture mapping, rotation and zoom added
36 * 21 July 2000 : cleaned up code from bug hunts, manpage written
41 * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
42 * otherwise caddr_t is not defined correctly
45 #include <X11/Intrinsic.h>
49 # define PROGCLASS "gflux"
50 # define HACK_INIT init_gflux
51 # define HACK_DRAW draw_gflux
52 # define HACK_RESHAPE reshape_gflux
53 # define gflux_opts xlockmore_opts
54 #define DEFAULTS "*delay: 20000 \n" \
55 "*showFPS: False \n" \
61 "*rotationx: 0.01 \n" \
62 "*rotationy: 0.0 \n" \
63 "*rotationz: 0.1 \n" \
65 "*waveChange: 50 \n" \
66 "*waveHeight: 1.0 \n" \
71 # include "xlockmore.h" /* from the xscreensaver distribution */
72 #else /* !STANDALONE */
73 # include "xlock.h" /* from the xlockmore distribution */
74 #endif /* !STANDALONE */
76 #ifdef USE_GL /* whole file */
80 # ifndef PIXEL_ALREADY_TYPEDEFED
81 # define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
87 # include <X11/Xmu/Drawing.h>
89 # include <Xmu/Drawing.h>
94 #define countof(x) (sizeof((x))/sizeof((*x)))
105 static enum {wire=0,solid,light,checker,textured} _draw; /* draw style */
106 static int _squares = 19; /* grid size */
107 static int _resolution = 4; /* wireframe resolution */
108 static int _flat = 0;
110 static float _speed = 0.05;
111 static float _rotationx = 0.01;
112 static float _rotationy = 0.0;
113 static float _rotationz = 0.1;
114 static float _zoom = 1.0;
116 static int _waves = 3;
117 static int _waveChange = 50;
118 static float _waveHeight = 1.0;
119 static float _waveFreq = 3.0;
124 static XrmOptionDescRec opts[] = {
125 {"-squares", ".gflux.squares", XrmoptionSepArg, (caddr_t) NULL},
126 {"-resolution", ".gflux.resolution", XrmoptionSepArg, (caddr_t) NULL},
127 {"-draw", ".gflux.draw", XrmoptionSepArg, (caddr_t) NULL},
128 {"-flat", ".gflux.flat", XrmoptionSepArg, (caddr_t) NULL},
129 {"-speed", ".gflux.speed", XrmoptionSepArg, (caddr_t) NULL},
130 {"-rotationx", ".gflux.rotationx", XrmoptionSepArg, (caddr_t) NULL},
131 {"-rotationy", ".gflux.rotationy", XrmoptionSepArg, (caddr_t) NULL},
132 {"-rotationz", ".gflux.rotationz", XrmoptionSepArg, (caddr_t) NULL},
133 {"-waves", ".gflux.waves", XrmoptionSepArg, (caddr_t) NULL},
134 {"-waveChange", ".gflux.waveChange", XrmoptionSepArg, (caddr_t) NULL},
135 {"-waveHeight", ".gflux.waveHeight", XrmoptionSepArg, (caddr_t) NULL},
136 {"-waveFreq", ".gflux.waveFreq", XrmoptionSepArg, (caddr_t) NULL},
137 {"-zoom", ".gflux.zoom", XrmoptionSepArg, (caddr_t) NULL},
141 static argtype vars[] = {
142 {(caddr_t *) & _squares, "squares", "Squares", "19", t_Int},
143 {(caddr_t *) & _resolution, "resolution", "Resolution", "4", t_Int},
144 {(caddr_t *) & _draw, "draw", "Draw", "0", t_Int},
145 {(caddr_t *) & _flat, "flat", "Flat", "0", t_Int},
146 {(caddr_t *) & _speed, "speed", "Speed", "0.05", t_Float},
147 {(caddr_t *) & _rotationx, "rotationx", "Rotationx", "0.01", t_Float},
148 {(caddr_t *) & _rotationy, "rotationy", "Rotationy", "0.0", t_Float},
149 {(caddr_t *) & _rotationz, "rotationz", "Rotationz", "0.1", t_Float},
150 {(caddr_t *) & _waves, "waves", "Waves", "3", t_Int},
151 {(caddr_t *) & _waveChange, "waveChange", "WaveChange", "50", t_Int},
152 {(caddr_t *) & _waveHeight, "waveHeight", "WaveHeight", "1.0", t_Float},
153 {(caddr_t *) & _waveFreq, "waveFreq", "WaveFreq", "3.0", t_Float},
154 {(caddr_t *) & _zoom, "zoom", "Zoom", "1.0", t_Float},
158 static OptionStruct desc[] =
160 {"-squares num", "size of grid in squares (19)"},
161 {"-resolution num", "detail of lines making grid, wireframe only (4)"},
162 {"-draw num", "draw method to use: 0=wireframe 1=solid 2=lit (0)"},
163 {"-flat num", "shading method, not wireframe: 0=smooth 1=flat (0)"},
164 {"-speed num", "speed of waves (0.05)"},
165 {"-rotationx num", "speed of xrotation (0.01)"},
166 {"-rotationy num", "speed of yrotation (0.00)"},
167 {"-rotationz num", "speed of zrotation (0.10)"},
168 {"-waves num", "number of simultanious waves (3)"},
169 {"-waveChange num", "number of cyles for a wave to change (50)"},
170 {"-waveHeight num", "height of waves (1.0)"},
171 {"-waveFreq num", "max frequency of a wave (3.0)"},
172 {"-zoom num", "camera control (1.0)"},
175 ModeSpecOpt gflux_opts = {countof(opts), opts, countof(vars), vars, desc};
178 ModStruct gflux_description =
179 {"gflux", "init_gflux", "draw_gflux", "release_gflux",
180 "draw_gflux", "init_gflux", NULL, &gflux_opts,
181 1000, 1, 2, 1, 4, 1.0, "",
182 "Gflux: an OpenGL gflux", 0, NULL};
185 /* structure for holding the gflux data */
187 int screen_width, screen_height;
188 GLXContext *glx_context;
191 #define MAXWAVES 10 /* should be dynamic */
193 double freq[MAXWAVES];
194 double dispy[MAXWAVES];
195 double dispx[MAXWAVES];
201 void (*drawFunc)(void);
203 static gfluxstruct *gflux = NULL;
206 void initLighting(void);
207 void initTexture(void);
208 void loadTexture(void);
209 void createTexture(void);
210 void displaySolid(void); /* drawFunc implementations */
211 void displayLight(void);
212 void displayTexture(void);
213 void displayWire(void);
215 double getGrid(double,double,double);
217 /* as macro for speed */
218 /* could do with colour cycling here */
219 /* void genColour(double);*/
220 #define genColour(X) \
222 gflux->colour[0] = 0.0;\
223 gflux->colour[1] = 0.5+0.5*(X);\
224 gflux->colour[2] = 0.5-0.5*(X);\
227 /* BEGINNING OF FUNCTIONS */
230 /* draw the gflux once */
231 void draw_gflux(ModeInfo * mi)
233 gfluxstruct *gp = &gflux[MI_SCREEN(mi)];
234 Display *display = MI_DISPLAY(mi);
235 Window window = MI_WINDOW(mi);
237 if (!gp->glx_context) return;
239 glXMakeCurrent(display, window, *(gp->glx_context));
243 if (mi->fps_p) do_fps (mi);
244 glXSwapBuffers(display, window);
248 /* reset the projection matrix */
249 void resetProjection(void) {
250 glMatrixMode(GL_PROJECTION);
252 glFrustum(-_zoom,_zoom,-0.8*_zoom,0.8*_zoom,2,6);
253 glTranslatef(0.0,0.0,-4.0);
254 glMatrixMode(GL_MODELVIEW);
258 /* Standard reshape function */
260 reshape_gflux(ModeInfo *mi, int width, int height)
262 glViewport( 0, 0, width, height );
267 /* main OpenGL initialization routine */
268 void initializeGL(ModeInfo *mi, GLsizei width, GLsizei height)
270 reshape_gflux(mi, width, height);
271 glViewport( 0, 0, width, height );
274 gflux->drawFunc = (displaySolid);
275 glEnable(GL_DEPTH_TEST);
278 gflux->drawFunc = (displayLight);
279 glEnable(GL_DEPTH_TEST);
283 gflux->drawFunc = (displayTexture);
284 glEnable(GL_DEPTH_TEST);
290 gflux->drawFunc = (displayTexture);
291 glEnable(GL_DEPTH_TEST);
298 gflux->drawFunc = (displayWire);
299 glDisable(GL_DEPTH_TEST);
303 if(_flat) glShadeModel(GL_FLAT);
304 else glShadeModel(GL_SMOOTH);
309 /* xgflux initialization routine */
310 void init_gflux(ModeInfo * mi)
312 int screen = MI_SCREEN(mi);
316 if ((gflux = (gfluxstruct *)
317 calloc(MI_NUM_SCREENS(mi), sizeof (gfluxstruct))) == NULL)
322 gp->window = MI_WINDOW(mi);
323 if ((gp->glx_context = init_GL(mi)) != NULL) {
324 reshape_gflux(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
325 initializeGL(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
332 void release_gflux(ModeInfo * mi)
334 if(gflux->image!=NULL) free(gflux->image);
335 if(gflux->glx_context!=NULL) free(gflux->glx_context);
337 (void) free((void *) gflux);
343 /* loads several different types of PNM image from stdin */
344 #define presult(A,B,C) (*(result+(A)*(gflux->imageWidth)*4+(B)*4+(C)))
345 void loadTexture(void)
347 int i, j, levels, width, height;
356 if(!strncmp(s,"P6",2)) ppmType=6;
357 if(!strncmp(s,"P5",2)) ppmType=5;
358 if(!strncmp(s,"P3",2)) ppmType=3;
359 if(!strncmp(s,"P2",2)) ppmType=2;
362 while((i=getc(file))=='#')
364 while(getc(file)!='\n');
368 fscanf(file,"%d %d %d",&width,&height,&levels);
370 result = malloc(sizeof(GLubyte)*4*width*height);
371 gflux->imageWidth = width;
372 gflux->imageHeight = height;
375 case 2 : /* ASCII grey */
376 for(i=0;i<height;i++) {
377 for(j=0;j<width;j++) {
378 fscanf(file,"%d",&red);
379 presult(j,i,0) = red;
380 presult(j,i,1) = red;
381 presult(j,i,2) = red;
385 case 3 : /* ASCII rgb */
386 for(i=0;i<height;i++) {
387 for(j=0;j<width;j++) {
388 fscanf(file,"%d %d %d",&red,&green,&blue);
389 presult(j,i,0) = red;
390 presult(j,i,1) = green;
391 presult(j,i,2) = blue;
395 case 5 : /* Binary grey */
396 getc(file); /* seems nessessary */
397 for(i=0;i<height;i++) {
398 for(j=0;j<width;j++) {
400 presult(j,i,0) = red;
401 presult(j,i,1) = red;
402 presult(j,i,2) = red;
406 case 6 : /* Binary rgb */
407 getc(file); /* seems nessessary */
408 for(i=0;i<height;i++) {
409 for(j=0;j<width;j++) {
413 presult(j,i,0) = red;
414 presult(j,i,1) = green;
415 presult(j,i,2) = blue;
420 gflux->image = result;
423 /* creates an image for texture mapping */
424 void createTexture(void)
429 gflux->imageHeight = gflux->imageWidth = 8;
431 result = malloc(sizeof(GLubyte)*4*gflux->imageHeight*gflux->imageWidth);
432 for(i=0;i<gflux->imageHeight;i++) {
433 for(j=0;j<gflux->imageWidth;j++) {
434 c = (((i)%2 ^ (j)%2) ? 100 : 200 );
435 presult(i,j,0) = (GLubyte) c;
436 presult(i,j,1) = (GLubyte) c;
437 presult(i,j,2) = (GLubyte) c;
438 presult(i,j,3) = (GLubyte) 255;
441 gflux->image = result;
445 /* specifies image as texture */
446 void initTexture(void)
448 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
449 glGenTextures(1, &gflux->texName);
450 glBindTexture(GL_TEXTURE_2D, gflux->texName);
451 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
452 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
453 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
454 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
456 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gflux->imageWidth,
457 gflux->imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, gflux->image);
458 check_gl_error("texture");
461 void initLighting(void)
463 static float ambientA[] = {0.0, 0.0, 0.0, 1.0};
464 static float diffuseA[] = {1.0, 1.0, 1.0, 1.0};
465 static float positionA[] = {5.0, 5.0, 15.0, 1.0};
467 static float front_mat_shininess[] = {30.0};
468 static float front_mat_specular[] = {0.5, 0.5, 0.5, 1.0};
470 static float mat_diffuse[] = {0.5, 0.5, 0.5, 1.0};
472 glMaterialfv(GL_FRONT, GL_SHININESS, front_mat_shininess);
473 glMaterialfv(GL_FRONT, GL_SPECULAR, front_mat_specular);
475 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
477 glLightfv(GL_LIGHT0, GL_AMBIENT, ambientA);
478 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseA);
479 glLightfv(GL_LIGHT0, GL_POSITION, positionA);
480 glEnable(GL_LIGHTING);
482 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,1);
484 glEnable(GL_NORMALIZE); /* would it be faster ... */
485 glEnable(GL_COLOR_MATERIAL);
486 glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
489 /************************************/
490 /* draw implementations */
491 /* somewhat inefficient since they */
492 /* all calculate previously */
493 /* calculated values again */
494 /* storing the values in an array */
495 /* is a posibility */
496 /************************************/
497 void displayTexture(void)
499 static double time = 0.0;
500 static double anglex = 0.0;
501 static double angley = 0.0;
502 static double anglez = 0.0;
506 double dx = 2.0/((double)_squares);
507 double dy = 2.0/((double)_squares);
509 glMatrixMode (GL_TEXTURE);
511 glTranslatef(-1,-1,0);
513 glMatrixMode (GL_MODELVIEW);
516 glRotatef(anglex,1,0,0);
517 glRotatef(angley,0,1,0);
518 glRotatef(anglez,0,0,1);
519 glScalef(1,1,(GLfloat)_waveHeight);
520 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
521 glEnable(GL_TEXTURE_2D);
522 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
523 glBindTexture(GL_TEXTURE_2D, gflux->texName);
524 glColor3f(0.5,0.5,0.5);
526 for(x=-1,u=0;x<=1;x+=dx,u+=dx) {
527 glBegin(GL_QUAD_STRIP);
528 for(y=-1,v=0;y<=1;y+=dy,v+=dx) {
529 z = getGrid(x,y,time);
531 glColor3fv(gflux->colour);
532 */ glTexCoord2f(u,v);
534 getGrid(x+dx,y,time)-getGrid(x-dx,y,time),
535 getGrid(x,y+dy,time)-getGrid(x,y-dy,time),
540 z = getGrid(x+dx,y,time);
542 glColor3fv(gflux->colour);
543 */ glTexCoord2f(u+dx,v);
545 getGrid(x+dx+dx,y,time)-getGrid(x,y,time),
546 getGrid(x+dx,y+dy,time)-getGrid(x+dx,y-dy,time),
549 glVertex3f(x+dx,y,z);
555 anglex -= _rotationx;
556 angley -= _rotationy;
557 anglez -= _rotationz;
559 void displaySolid(void)
561 static double time = 0.0;
562 static double anglex = 0.0;
563 static double angley = 0.0;
564 static double anglez = 0.0;
568 double dx = 2.0/((double)_squares);
569 double dy = 2.0/((double)_squares);
572 glRotatef(anglex,1,0,0);
573 glRotatef(angley,0,1,0);
574 glRotatef(anglez,0,0,1);
575 glScalef(1,1,(GLfloat)_waveHeight);
576 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
578 for(x=-1;x<=1;x+=dx) {
579 glBegin(GL_QUAD_STRIP);
580 for(y=-1;y<=1;y+=dy) {
581 z = getGrid(x,y,time);
583 glColor3fv(gflux->colour);
586 z = getGrid(x+dx,y,time);
588 glColor3fv(gflux->colour);
589 glVertex3f(x+dx,y,z);
595 anglex -= _rotationx;
596 angley -= _rotationy;
597 anglez -= _rotationz;
601 void displayLight(void)
603 static double time = 0.0;
604 static double anglex = 0.0;
605 static double angley = 0.0;
606 static double anglez = 0.0;
610 double dx = 2.0/((double)_squares);
611 double dy = 2.0/((double)_squares);
614 glRotatef(anglex,1,0,0);
615 glRotatef(angley,0,1,0);
616 glRotatef(anglez,0,0,1);
617 glScalef(1,1,(GLfloat)_waveHeight);
618 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
620 for(x=-1;x<=1;x+=dx) {
621 glBegin(GL_QUAD_STRIP);
622 for(y=-1;y<=1;y+=dy) {
623 z = getGrid(x,y,time);
625 glColor3fv(gflux->colour);
627 getGrid(x+dx,y,time)-getGrid(x-dx,y,time),
628 getGrid(x,y+dy,time)-getGrid(x,y-dy,time),
633 z = getGrid(x+dx,y,time);
635 glColor3fv(gflux->colour);
637 getGrid(x+dx+dx,y,time)-getGrid(x,y,time),
638 getGrid(x+dx,y+dy,time)-getGrid(x+dx,y-dy,time),
641 glVertex3f(x+dx,y,z);
647 anglex -= _rotationx;
648 angley -= _rotationy;
649 anglez -= _rotationz;
652 void displayWire(void)
654 static double time = 0.0;
655 static double anglex = 0.0;
656 static double angley = 0.0;
657 static double anglez = 0.0;
661 double dx1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
662 double dy1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
663 double dx2 = 2.0/((double)_squares) - 0.00001;
664 double dy2 = 2.0/((double)_squares) - 0.00001;
667 glRotatef(anglex,1,0,0);
668 glRotatef(angley,0,1,0);
669 glRotatef(anglez,0,0,1);
670 glScalef(1,1,(GLfloat)_waveHeight);
671 glClear(GL_COLOR_BUFFER_BIT);
673 for(x=-1;x<=1;x+=dx2) {
674 glBegin(GL_LINE_STRIP);
675 for(y=-1;y<=1;y+=dy1) {
676 z = getGrid(x,y,time);
678 glColor3fv(gflux->colour);
683 for(y=-1;y<=1;y+=dy2) {
684 glBegin(GL_LINE_STRIP);
685 for(x=-1;x<=1;x+=dx1) {
686 z = getGrid(x,y,time);
688 glColor3fv(gflux->colour);
695 anglex -= _rotationx;
696 angley -= _rotationy;
697 anglez -= _rotationz;
700 /* generates new ripples */
703 static int counter=0;
707 tmp = 1.0/((double)_waveChange);
708 if(!(counter%_waveChange)) {
709 newWave = ((int)(counter*tmp))%_waves;
710 gflux->dispx[newWave] = 1.0 - ((double)random())/RAND_MAX;
711 gflux->dispy[newWave] = 1.0 - ((double)random())/RAND_MAX;
712 gflux->freq[newWave] = _waveFreq * ((float)random())/RAND_MAX;
713 gflux->wa[newWave] = 0.0;
716 gflux->wa[newWave] += tmp;
717 gflux->wa[(newWave+1)%_waves] -= tmp;
720 /* returns a height for the grid given time and x,y space co-ords */
721 double getGrid(double x, double y, double a)
727 tmp = 1.0/((float)_waves);
728 for(i=0;i<_waves;i++) {
729 retval += gflux->wa[i] * tmp * sin( gflux->freq[i]
730 * ( (x+gflux->dispx[i]) * (x+gflux->dispx[i])
731 + (y+gflux->dispy[i]) * (y+gflux->dispy[i]) +a ) );