1 /* -*- Mode: C; tab-width: 4 -*- emacs friendly */
2 /* gflux - creates a fluctuating 3D grid
3 * requires OpenGL or MesaGL
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
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
18 * Personal thanks to Kevin Moss, Paul Sheahee and Jamie Zawinski
20 * some xscreensaver code lifted from superquadrics. Most other glx hacks
21 * used as reference at some time.
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
27 * Josiah Pease <gfluxcode@jpease.force9.co.uk> 21 July 2000
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
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
46 #include <X11/Intrinsic.h>
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" \
62 "*rotationx: 0.01 \n" \
63 "*rotationy: 0.0 \n" \
64 "*rotationz: 0.1 \n" \
66 "*waveChange: 50 \n" \
67 "*waveHeight: 1.0 \n" \
72 # include "xlockmore.h" /* from the xscreensaver distribution */
73 #else /* !STANDALONE */
74 # include "xlock.h" /* from the xlockmore distribution */
75 #endif /* !STANDALONE */
77 #ifdef USE_GL /* whole file */
81 # ifndef PIXEL_ALREADY_TYPEDEFED
82 # define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
88 # include <X11/Xmu/Drawing.h>
90 # include <Xmu/Drawing.h>
99 #define countof(x) (sizeof((x))/sizeof((*x)))
110 static enum {wire=0,solid,light,checker,textured} _draw; /* draw style */
111 static int _squares = 19; /* grid size */
112 static int _resolution = 4; /* wireframe resolution */
113 static int _flat = 0;
115 static float _speed = 0.05;
116 static float _rotationx = 0.01;
117 static float _rotationy = 0.0;
118 static float _rotationz = 0.1;
119 static float _zoom = 1.0;
121 static int _waves = 3;
122 static int _waveChange = 50;
123 static float _waveHeight = 1.0;
124 static float _waveFreq = 3.0;
129 static XrmOptionDescRec opts[] = {
130 {"-squares", ".gflux.squares", XrmoptionSepArg, (caddr_t) NULL},
131 {"-resolution", ".gflux.resolution", XrmoptionSepArg, (caddr_t) NULL},
132 {"-draw", ".gflux.draw", XrmoptionSepArg, (caddr_t) NULL},
133 {"-flat", ".gflux.flat", XrmoptionSepArg, (caddr_t) NULL},
134 {"-speed", ".gflux.speed", XrmoptionSepArg, (caddr_t) NULL},
135 {"-rotationx", ".gflux.rotationx", XrmoptionSepArg, (caddr_t) NULL},
136 {"-rotationy", ".gflux.rotationy", XrmoptionSepArg, (caddr_t) NULL},
137 {"-rotationz", ".gflux.rotationz", XrmoptionSepArg, (caddr_t) NULL},
138 {"-waves", ".gflux.waves", XrmoptionSepArg, (caddr_t) NULL},
139 {"-waveChange", ".gflux.waveChange", XrmoptionSepArg, (caddr_t) NULL},
140 {"-waveHeight", ".gflux.waveHeight", XrmoptionSepArg, (caddr_t) NULL},
141 {"-waveFreq", ".gflux.waveFreq", XrmoptionSepArg, (caddr_t) NULL},
142 {"-zoom", ".gflux.zoom", XrmoptionSepArg, (caddr_t) NULL},
146 static argtype vars[] = {
147 {(caddr_t *) & _squares, "squares", "Squares", "19", t_Int},
148 {(caddr_t *) & _resolution, "resolution", "Resolution", "4", t_Int},
149 {(caddr_t *) & _draw, "draw", "Draw", "2", t_Int},
150 {(caddr_t *) & _flat, "flat", "Flat", "0", t_Int},
151 {(caddr_t *) & _speed, "speed", "Speed", "0.05", t_Float},
152 {(caddr_t *) & _rotationx, "rotationx", "Rotationx", "0.01", t_Float},
153 {(caddr_t *) & _rotationy, "rotationy", "Rotationy", "0.0", t_Float},
154 {(caddr_t *) & _rotationz, "rotationz", "Rotationz", "0.1", t_Float},
155 {(caddr_t *) & _waves, "waves", "Waves", "3", t_Int},
156 {(caddr_t *) & _waveChange, "waveChange", "WaveChange", "50", t_Int},
157 {(caddr_t *) & _waveHeight, "waveHeight", "WaveHeight", "1.0", t_Float},
158 {(caddr_t *) & _waveFreq, "waveFreq", "WaveFreq", "3.0", t_Float},
159 {(caddr_t *) & _zoom, "zoom", "Zoom", "1.0", t_Float},
163 static OptionStruct desc[] =
165 {"-squares num", "size of grid in squares (19)"},
166 {"-resolution num", "detail of lines making grid, wireframe only (4)"},
167 {"-draw num", "draw method to use: 0=wireframe 1=solid 2=lit (0)"},
168 {"-flat num", "shading method, not wireframe: 0=smooth 1=flat (0)"},
169 {"-speed num", "speed of waves (0.05)"},
170 {"-rotationx num", "speed of xrotation (0.01)"},
171 {"-rotationy num", "speed of yrotation (0.00)"},
172 {"-rotationz num", "speed of zrotation (0.10)"},
173 {"-waves num", "number of simultanious waves (3)"},
174 {"-waveChange num", "number of cyles for a wave to change (50)"},
175 {"-waveHeight num", "height of waves (1.0)"},
176 {"-waveFreq num", "max frequency of a wave (3.0)"},
177 {"-zoom num", "camera control (1.0)"},
180 ModeSpecOpt gflux_opts = {countof(opts), opts, countof(vars), vars, desc};
183 ModStruct gflux_description =
184 {"gflux", "init_gflux", "draw_gflux", "release_gflux",
185 "draw_gflux", "init_gflux", NULL, &gflux_opts,
186 1000, 1, 2, 1, 4, 1.0, "",
187 "Gflux: an OpenGL gflux", 0, NULL};
190 /* structure for holding the gflux data */
192 int screen_width, screen_height;
193 GLXContext *glx_context;
196 #define MAXWAVES 10 /* should be dynamic */
198 double freq[MAXWAVES];
199 double dispy[MAXWAVES];
200 double dispx[MAXWAVES];
212 void (*drawFunc)(void);
214 static gfluxstruct *gflux = NULL;
217 void initLighting(void);
218 void initTexture(void);
219 void loadTexture(void);
220 void createTexture(void);
221 void displaySolid(void); /* drawFunc implementations */
222 void displayLight(void);
223 void displayTexture(void);
224 void displayWire(void);
226 double getGrid(double,double,double);
228 /* as macro for speed */
229 /* could do with colour cycling here */
230 /* void genColour(double);*/
231 #define genColour(X) \
233 gflux->colour[0] = 0.0;\
234 gflux->colour[1] = 0.5+0.5*(X);\
235 gflux->colour[2] = 0.5-0.5*(X);\
238 /* BEGINNING OF FUNCTIONS */
241 /* draw the gflux once */
242 void draw_gflux(ModeInfo * mi)
244 gfluxstruct *gp = &gflux[MI_SCREEN(mi)];
245 Display *display = MI_DISPLAY(mi);
246 Window window = MI_WINDOW(mi);
248 if (!gp->glx_context) return;
250 glXMakeCurrent(display, window, *(gp->glx_context));
254 if (mi->fps_p) do_fps (mi);
255 glXSwapBuffers(display, window);
259 /* reset the projection matrix */
260 void resetProjection(void) {
261 glMatrixMode(GL_PROJECTION);
263 glFrustum(-_zoom,_zoom,-0.8*_zoom,0.8*_zoom,2,6);
264 glTranslatef(0.0,0.0,-4.0);
265 glMatrixMode(GL_MODELVIEW);
269 /* Standard reshape function */
271 reshape_gflux(ModeInfo *mi, int width, int height)
273 glViewport( 0, 0, width, height );
278 /* main OpenGL initialization routine */
279 void initializeGL(ModeInfo *mi, GLsizei width, GLsizei height)
281 reshape_gflux(mi, width, height);
282 glViewport( 0, 0, width, height );
285 gflux->drawFunc = (displaySolid);
286 glEnable(GL_DEPTH_TEST);
289 gflux->drawFunc = (displayLight);
290 glEnable(GL_DEPTH_TEST);
294 gflux->drawFunc = (displayTexture);
295 glEnable(GL_DEPTH_TEST);
301 gflux->drawFunc = (displayTexture);
302 glEnable(GL_DEPTH_TEST);
309 gflux->drawFunc = (displayWire);
310 glDisable(GL_DEPTH_TEST);
314 if(_flat) glShadeModel(GL_FLAT);
315 else glShadeModel(GL_SMOOTH);
320 /* xgflux initialization routine */
321 void init_gflux(ModeInfo * mi)
323 int screen = MI_SCREEN(mi);
327 if ((gflux = (gfluxstruct *)
328 calloc(MI_NUM_SCREENS(mi), sizeof (gfluxstruct))) == NULL)
333 gp->window = MI_WINDOW(mi);
334 if ((gp->glx_context = init_GL(mi)) != NULL) {
335 reshape_gflux(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
336 initializeGL(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
343 void release_gflux(ModeInfo * mi)
345 if(gflux->image!=NULL) free(gflux->image);
346 if(gflux->glx_context!=NULL) free(gflux->glx_context);
348 (void) free((void *) gflux);
356 /* load pnm from stdin using pnm libs */
357 void loadTexture(void)
360 gflux->image = ppm_readppm( file,
361 &(gflux->imageHeight), &(gflux->imageWidth), &(gflux->imageMax) );
364 /* creates an image for texture mapping */
365 void createTexture(void)
370 gflux->imageHeight = gflux->imageWidth = 8;
372 result = ppm_allocarray(gflux->imageHeight,gflux->imageWidth);
373 for(i=0;i<gflux->imageHeight;i++) {
374 for(j=0;j<gflux->imageWidth;j++) {
375 c = (((i)%2 ^ (j)%2) ? 100 : 200 );
376 PPM_ASSIGN( result[i][j] , c, c, c );
379 gflux->image = result;
382 /* specifies image as texture */
383 void initTexture(void)
385 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
386 glGenTextures(1, &gflux->texName);
387 glBindTexture(GL_TEXTURE_2D, gflux->texName);
388 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
389 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
390 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
391 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
392 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, gflux->imageWidth,
393 gflux->imageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, *(gflux->image));
397 #else /* HAVE_PPM FALSE */
399 #define presult(A,B,C) (*(result+(A)*(gflux->imageWidth)*4+(B)*4+(C)))
400 void loadTexture(void)
402 int i, j, levels, width, height;
411 if(!strncmp(s,"P6",2)) ppmType=6;
412 if(!strncmp(s,"P5",2)) ppmType=5;
413 if(!strncmp(s,"P3",2)) ppmType=3;
414 if(!strncmp(s,"P2",2)) ppmType=2;
417 while((i=getc(file))=='#')
419 while(getc(file)!='\n');
423 fscanf(file,"%d %d %d",&width,&height,&levels);
425 result = malloc(sizeof(GLubyte)*4*width*height);
426 gflux->imageWidth = width;
427 gflux->imageHeight = height;
430 case 2 : /* ASCII grey */
431 for(i=0;i<height;i++) {
432 for(j=0;j<width;j++) {
433 fscanf(file,"%d",&red);
434 presult(j,i,0) = red;
435 presult(j,i,1) = red;
436 presult(j,i,2) = red;
440 case 3 : /* ASCII rgb */
441 for(i=0;i<height;i++) {
442 for(j=0;j<width;j++) {
443 fscanf(file,"%d %d %d",&red,&green,&blue);
444 presult(j,i,0) = red;
445 presult(j,i,1) = green;
446 presult(j,i,2) = blue;
450 case 5 : /* Binary grey */
451 getc(file); /* seems nessessary */
452 for(i=0;i<height;i++) {
453 for(j=0;j<width;j++) {
455 presult(j,i,0) = red;
456 presult(j,i,1) = red;
457 presult(j,i,2) = red;
461 case 6 : /* Binary rgb */
462 getc(file); /* seems nessessary */
463 for(i=0;i<height;i++) {
464 for(j=0;j<width;j++) {
468 presult(j,i,0) = red;
469 presult(j,i,1) = green;
470 presult(j,i,2) = blue;
475 gflux->image = result;
478 void createTexture(void)
483 gflux->imageHeight = gflux->imageWidth = 8;
485 result = malloc(sizeof(GLubyte)*4*gflux->imageHeight*gflux->imageWidth);
486 for(i=0;i<gflux->imageHeight;i++) {
487 for(j=0;j<gflux->imageWidth;j++) {
488 c = (((i)%2 ^ (j)%2) ? 100 : 200 );
489 presult(i,j,0) = (GLubyte) c;
490 presult(i,j,1) = (GLubyte) c;
491 presult(i,j,2) = (GLubyte) c;
492 presult(i,j,3) = (GLubyte) 255;
495 gflux->image = result;
498 /* specifies image as texture */
499 void initTexture(void)
501 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
502 glGenTextures(1, &gflux->texName);
503 glBindTexture(GL_TEXTURE_2D, gflux->texName);
504 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
505 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
506 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
507 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
508 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gflux->imageWidth,
509 gflux->imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, gflux->image);
516 void initLighting(void)
518 static float ambientA[] = {0.0, 0.0, 0.0, 1.0};
519 static float diffuseA[] = {1.0, 1.0, 1.0, 1.0};
520 static float positionA[] = {5.0, 5.0, 15.0, 1.0};
522 static float front_mat_shininess[] = {30.0};
523 static float front_mat_specular[] = {0.5, 0.5, 0.5, 1.0};
525 static float mat_diffuse[] = {0.5, 0.5, 0.5, 1.0};
527 glMaterialfv(GL_FRONT, GL_SHININESS, front_mat_shininess);
528 glMaterialfv(GL_FRONT, GL_SPECULAR, front_mat_specular);
530 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
532 glLightfv(GL_LIGHT0, GL_AMBIENT, ambientA);
533 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseA);
534 glLightfv(GL_LIGHT0, GL_POSITION, positionA);
535 glEnable(GL_LIGHTING);
537 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,1);
539 glEnable(GL_NORMALIZE); /* would it be faster ... */
540 glEnable(GL_COLOR_MATERIAL);
541 glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
544 /************************************/
545 /* draw implementations */
546 /* somewhat inefficient since they */
547 /* all calculate previously */
548 /* calculated values again */
549 /* storing the values in an array */
550 /* is a posibility */
551 /************************************/
552 void displayTexture(void)
554 static double time = 0.0;
555 static double anglex = 0.0;
556 static double angley = 0.0;
557 static double anglez = 0.0;
561 double dx = 2.0/((double)_squares);
562 double dy = 2.0/((double)_squares);
564 double du = 2.0/((double)_squares);
565 double dv = 2.0/((double)_squares);
567 glMatrixMode (GL_TEXTURE);
569 glTranslatef(-1,-1,0);
571 glMatrixMode (GL_MODELVIEW);
574 glRotatef(anglex,1,0,0);
575 glRotatef(angley,0,1,0);
576 glRotatef(anglez,0,0,1);
577 glScalef(1,1,(GLfloat)_waveHeight);
578 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
579 glEnable(GL_TEXTURE_2D);
580 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
581 glBindTexture(GL_TEXTURE_2D, gflux->texName);
582 glColor3f(0.5,0.5,0.5);
584 for(x=-1,u= 0;x<0.9999;x+=dx,u+=du) {
585 glBegin(GL_QUAD_STRIP);
586 for(y=-1,v= 0;y<=1;y+=dy,v+=dv) {
587 z = getGrid(x,y,time);
589 glColor3fv(gflux->colour);
590 */ glTexCoord2f(u,v);
592 getGrid(x+dx,y,time)-getGrid(x-dx,y,time),
593 getGrid(x,y+dy,time)-getGrid(x,y-dy,time),
598 z = getGrid(x+dx,y,time);
600 glColor3fv(gflux->colour);
601 */ glTexCoord2f(u+du,v);
603 getGrid(x+dx+dx,y,time)-getGrid(x,y,time),
604 getGrid(x+dx,y+dy,time)-getGrid(x+dx,y-dy,time),
607 glVertex3f(x+dx,y,z);
613 anglex -= _rotationx;
614 angley -= _rotationy;
615 anglez -= _rotationz;
617 void displaySolid(void)
619 static double time = 0.0;
620 static double anglex = 0.0;
621 static double angley = 0.0;
622 static double anglez = 0.0;
626 double dx = 2.0/((double)_squares);
627 double dy = 2.0/((double)_squares);
630 glRotatef(anglex,1,0,0);
631 glRotatef(angley,0,1,0);
632 glRotatef(anglez,0,0,1);
633 glScalef(1,1,(GLfloat)_waveHeight);
634 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
636 for(x=-1;x<0.9999;x+=dx) {
637 glBegin(GL_QUAD_STRIP);
638 for(y=-1;y<=1;y+=dy) {
639 z = getGrid(x,y,time);
641 glColor3fv(gflux->colour);
644 z = getGrid(x+dx,y,time);
646 glColor3fv(gflux->colour);
647 glVertex3f(x+dx,y,z);
653 anglex -= _rotationx;
654 angley -= _rotationy;
655 anglez -= _rotationz;
659 void displayLight(void)
661 static double time = 0.0;
662 static double anglex = 0.0;
663 static double angley = 0.0;
664 static double anglez = 0.0;
668 double dx = 2.0/((double)_squares);
669 double dy = 2.0/((double)_squares);
672 glRotatef(anglex,1,0,0);
673 glRotatef(angley,0,1,0);
674 glRotatef(anglez,0,0,1);
675 glScalef(1,1,(GLfloat)_waveHeight);
676 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
678 for(x=-1;x<0.9999;x+=dx) {
679 glBegin(GL_QUAD_STRIP);
680 for(y=-1;y<=1;y+=dy) {
681 z = getGrid(x,y,time);
683 glColor3fv(gflux->colour);
685 getGrid(x+dx,y,time)-getGrid(x-dx,y,time),
686 getGrid(x,y+dy,time)-getGrid(x,y-dy,time),
691 z = getGrid(x+dx,y,time);
693 glColor3fv(gflux->colour);
695 getGrid(x+dx+dx,y,time)-getGrid(x,y,time),
696 getGrid(x+dx,y+dy,time)-getGrid(x+dx,y-dy,time),
699 glVertex3f(x+dx,y,z);
705 anglex -= _rotationx;
706 angley -= _rotationy;
707 anglez -= _rotationz;
710 void displayWire(void)
712 static double time = 0.0;
713 static double anglex = 0.0;
714 static double angley = 0.0;
715 static double anglez = 0.0;
719 double dx1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
720 double dy1 = 2.0/((double)(_squares*_resolution)) - 0.00001;
721 double dx2 = 2.0/((double)_squares) - 0.00001;
722 double dy2 = 2.0/((double)_squares) - 0.00001;
725 glRotatef(anglex,1,0,0);
726 glRotatef(angley,0,1,0);
727 glRotatef(anglez,0,0,1);
728 glScalef(1,1,(GLfloat)_waveHeight);
729 glClear(GL_COLOR_BUFFER_BIT);
731 for(x=-1;x<=1;x+=dx2) {
732 glBegin(GL_LINE_STRIP);
733 for(y=-1;y<=1;y+=dy1) {
734 z = getGrid(x,y,time);
736 glColor3fv(gflux->colour);
741 for(y=-1;y<=1;y+=dy2) {
742 glBegin(GL_LINE_STRIP);
743 for(x=-1;x<=1;x+=dx1) {
744 z = getGrid(x,y,time);
746 glColor3fv(gflux->colour);
753 anglex -= _rotationx;
754 angley -= _rotationy;
755 anglez -= _rotationz;
758 /* generates new ripples */
761 static int counter=0;
765 tmp = 1.0/((double)_waveChange);
766 if(!(counter%_waveChange)) {
767 newWave = ((int)(counter*tmp))%_waves;
768 gflux->dispx[newWave] = 1.0 - ((double)random())/RAND_MAX;
769 gflux->dispy[newWave] = 1.0 - ((double)random())/RAND_MAX;
770 gflux->freq[newWave] = _waveFreq * ((float)random())/RAND_MAX;
771 gflux->wa[newWave] = 0.0;
774 gflux->wa[newWave] += tmp;
775 gflux->wa[(newWave+1)%_waves] -= tmp;
778 /* returns a height for the grid given time and x,y space co-ords */
779 double getGrid(double x, double y, double a)
785 tmp = 1.0/((float)_waves);
786 for(i=0;i<_waves;i++) {
787 retval += gflux->wa[i] * tmp * sin( gflux->freq[i]
788 * ( (x+gflux->dispx[i]) * (x+gflux->dispx[i])
789 + (y+gflux->dispy[i]) * (y+gflux->dispy[i]) +a ) );