http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[xscreensaver] / hacks / glx / pulsar.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* pulsar --- pulsar module for xpulsar */
3 /*-
4  * Permission to use, copy, modify, and distribute this software and its
5  * documentation for any purpose and without fee is hereby granted,
6  * provided that the above copyright notice appear in all copies and that
7  * both that copyright notice and this permission notice appear in
8  * supporting documentation.
9  *
10  * This file is provided AS IS with no warranties of any kind.  The author
11  * shall have no liability with respect to the infringement of copyrights,
12  * trade secrets or any patents by this file or any part thereof.  In no
13  * event will the author be liable for any lost revenue or profits or
14  * other special, indirect and consequential damages.
15
16  * Revision History:
17  * 4-Apr-1999:  dek@cgl.ucsf.edu  Created module "pulsar"
18  * 27-Apr-1999:  dek@cgl.ucsf.edu  Submitted module "pulsar"
19  * 4-May-1999:  jwz@jwz.org  Added module "pulsar"
20  * 4-May-1999:  dek@cgl.ucsf.edu  Submitted module "pulsar" updates
21  *
22  * Notes:
23  * The pulsar pulsar draws a number of rotating, pulsing rectangles
24  * on your screen.  Depending on the options you choose, you can set a number
25  * of interesting OpenGL parameters, including alpha blending, depth testing, fog,
26  * lighting, texturing, mipmapping, bilinear filtering, and line antialiasing.  
27  * Additionally, there is a "frames per second" meter which gives an estimate of
28  * the speed of your graphics card.  
29  *
30  * Example command-line switches:
31  * Only draw a single quad, and don't fill it (boring but fast)
32  * pulsar -wire -quads 1 -fps
33  *
34  * Only try this with hardware graphics acceleration (PPro 200 w/ a Voodoo 2 runs great)
35  * pulsar -quads 10 -texture -mipmap -texture_quality -light -fog -fps
36  *                                                                 
37  */
38
39 #include <math.h> 
40 #include <stdio.h>
41 #include <stdlib.h>
42
43 #ifdef STANDALONE
44 #define DEFAULTS                        "*delay:                        10000   \n" \
45                                                                                 "*showFPS:          False   \n" \
46
47 # define refresh_pulsar 0
48 # define pulsar_handle_event 0
49 # include "xlockmore.h"                         /* from the xpulsar distribution */
50 #else /* !STANDALONE */
51 # include "xlock.h"                                     /* from the xlockmore distribution */
52 #endif /* !STANDALONE */
53
54 #ifdef USE_GL /* whole file */
55
56 #ifdef HAVE_XMU
57 # ifndef VMS
58 #  include <X11/Xmu/Drawing.h>
59 #else  /* VMS */
60 #  include <Xmu/Drawing.h>
61 # endif /* VMS */
62 #endif
63
64 #include "xpm-ximage.h"
65
66 /* Functions for loading and storing textures */
67
68 #define checkImageWidth 64
69 #define checkImageHeight 64
70
71 /* Functions for handling the frames per second timer */
72
73 #undef countof
74 #define countof(x) (sizeof((x))/sizeof((*x)))
75
76 #define WIDTH 800
77 #define HEIGHT 600
78
79 #define NUM_QUADS 5
80 #define DEF_NUM_QUADS   "5"
81 #define DEF_LIGHT               "False"
82 #define DEF_WIRE                "False"
83 #define DEF_BLEND       "True"
84 #define DEF_FOG                 "False"
85 #define DEF_ANTIALIAS   "False"
86 #define DEF_TEXTURE     "False"
87 #define DEF_TEXTURE_QUALITY   "False"
88 #define DEF_MIPMAP      "False"
89 #define DEF_DO_DEPTH    "False"
90 #define DEF_IMAGE       "BUILTIN"
91
92 static int num_quads;
93 static int do_light;
94 static int do_wire;
95 static int do_blend;
96 static int do_fog;
97 static int do_antialias;
98 static int do_texture;
99 static int do_texture_quality;
100 static int do_mipmap;
101 static int do_depth;
102 static char *which_image;
103
104
105 static XrmOptionDescRec opts[] = {
106   {"-quads",   ".pulsar.quads",   XrmoptionSepArg, 0 },
107   {"-light",   ".pulsar.light",   XrmoptionNoArg, "true" },
108   {"+light",   ".pulsar.light",   XrmoptionNoArg, "false" },
109   {"-wire",   ".pulsar.wire",   XrmoptionNoArg, "true" },
110   {"+wire",   ".pulsar.wire",   XrmoptionNoArg, "false" },
111   {"-blend",   ".pulsar.blend",   XrmoptionNoArg, "true" },
112   {"+blend",   ".pulsar.blend",   XrmoptionNoArg, "false" },
113   {"-fog",   ".pulsar.fog",   XrmoptionNoArg, "true" },
114   {"+fog",   ".pulsar.fog",   XrmoptionNoArg, "false" },
115   {"-antialias",   ".pulsar.antialias",   XrmoptionNoArg, "true" },
116   {"+antialias",   ".pulsar.antialias",   XrmoptionNoArg, "false" },
117   {"-texture",   ".pulsar.texture",   XrmoptionNoArg, "true" },
118   {"+texture",   ".pulsar.texture",   XrmoptionNoArg, "false" },
119   {"-texture_quality",   ".pulsar.texture_quality",   XrmoptionNoArg, "true" },
120   {"+texture_quality",   ".pulsar.texture_quality",   XrmoptionNoArg, "false" },
121   {"-mipmap",   ".pulsar.mipmap",   XrmoptionNoArg, "true" },
122   {"+mipmap",   ".pulsar.mipmap",   XrmoptionNoArg, "false" },
123   {"-do_depth",   ".pulsar.doDepth",   XrmoptionNoArg, "true" },
124   {"+do_depth",   ".pulsar.doDepth",   XrmoptionNoArg, "false" },
125   {"-image",   ".pulsar.image",  XrmoptionSepArg, 0 },
126 };
127
128
129 static argtype vars[] = {
130   {&num_quads,    "quads",     "Quads",     DEF_NUM_QUADS, t_Int},
131   {&do_light,     "light",     "Light",     DEF_LIGHT,     t_Bool},
132   {&do_wire,      "wire",      "Wire",      DEF_WIRE,      t_Bool},
133   {&do_blend,     "blend",     "Blend",     DEF_BLEND,     t_Bool},
134   {&do_fog,       "fog",       "Fog",       DEF_FOG,       t_Bool},
135   {&do_antialias, "antialias", "Antialias", DEF_ANTIALIAS, t_Bool},
136   {&do_texture,   "texture",   "Texture",   DEF_TEXTURE,   t_Bool},
137   {&do_texture_quality, "texture_quality", "Texture_quality", DEF_TEXTURE_QUALITY,   t_Bool},
138   {&do_mipmap,    "mipmap",    "Mipmap",    DEF_MIPMAP,    t_Bool},
139   {&do_depth,    "doDepth",    "DoDepth",   DEF_DO_DEPTH,  t_Bool},
140   {&which_image, "image",      "Image",     DEF_IMAGE,     t_String},
141 };
142
143
144 static OptionStruct desc[] =
145 {
146         {"-quads num", "how many quads to draw"},
147         {"-/+ light", "whether to do enable lighting (slower)"},
148         {"-/+ wire", "whether to do use wireframe instead of filled (faster)"},
149         {"-/+ blend", "whether to do enable blending (slower)"},
150         {"-/+ fog", "whether to do enable fog (?)"},
151         {"-/+ antialias", "whether to do enable antialiased lines (slower)"},
152         {"-/+ texture", "whether to do enable texturing (much slower)"},
153         {"-/+ texture_quality", "whether to do enable linear/mipmap filtering (much much slower)"},
154         {"-/+ mipmap", "whether to do enable mipmaps (much slower)"},
155         {"-/+ depth", "whether to do enable depth buffer checking (slower)"},
156         {"-image <filename>", "texture image to load"},
157 };
158
159 ENTRYPOINT ModeSpecOpt pulsar_opts = {countof(opts), opts, countof(vars), vars, desc};
160
161 #ifdef USE_MODULES
162 ModStruct   pulsar_description =
163 {"pulsar", "init_pulsar", "draw_pulsar", "release_pulsar",
164  "draw_pulsar", "init_pulsar", NULL, &pulsar_opts,
165  1000, 1, 2, 1, 4, 1.0, "",
166  "OpenGL pulsar", 0, NULL};
167 #endif
168
169 struct quad
170 {
171   GLfloat tx, ty, tz;
172   GLfloat rx, ry, rz;
173
174   GLfloat dtx, dty, dtz;
175   GLfloat drx, dry, drz;
176
177 };
178
179
180 /* structure for holding the pulsar data */
181 typedef struct {
182   int screen_width, screen_height;
183   GLXContext *glx_context;
184   Window window;
185   XColor fg, bg;
186
187   GLint quad_list;
188   float scale_x, scale_y, scale_z;
189   int frame;
190
191   struct quad *quads;
192
193 } pulsarstruct;
194
195 static pulsarstruct *Pulsar = NULL;
196
197 static GLubyte *
198 Generate_Image(int *width, int *height, int *format)
199 {
200   GLubyte *result;
201   int i, j, c;
202   int counter=0;
203
204   *width = checkImageWidth;
205   *height = checkImageHeight;
206   result = (GLubyte *)malloc(4 * (*width) * (*height));
207
208   counter = 0;
209   for (i = 0; i < checkImageWidth; i++) {
210     for (j = 0; j < checkImageHeight; j++) {
211       c = (((((i&0x8)==0))^(((j&0x8))==0)))*255;
212       result[counter++] = (GLubyte) c;
213       result[counter++] = (GLubyte) c;
214       result[counter++] = (GLubyte) c;
215       result[counter++] = (GLubyte) 255;
216     }
217   }
218
219   *format = GL_RGBA;
220   return result;
221 }
222
223
224 /* Create a texture in OpenGL.  First an image is loaded 
225    and stored in a raster buffer, then it's  */
226 static void Create_Texture(ModeInfo *mi, const char *filename)
227 {
228   int height, width;
229   GLubyte *image;
230   int format;
231
232   if ( !strncmp(filename, "BUILTIN", 7))
233     image = Generate_Image(&width, &height, &format);
234   else
235     {
236       XImage *ximage = xpm_file_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
237                                            MI_COLORMAP (mi), filename);
238       image  = (GLubyte *) ximage->data;
239       width  = ximage->width;
240       height = ximage->height;
241       format = GL_RGBA;
242     }
243
244   /* GL_MODULATE or GL_DECAL depending on what you want */
245   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
246   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
247   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
248   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
249   /* perhaps we can edge a bit more speed at the expense of quality */
250   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
251
252   if (do_texture_quality) {
253         /* with texture_quality, the min and mag filters look *much* nice but are *much* slower */
254         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
255         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
256   }
257   else {
258         /* default is to do it quick and dirty */
259         /* if you have mipmaps turned on, but not texture quality, nothing will happen! */
260         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
261         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
262   }
263
264   /* mipmaps make the image look much nicer */
265   if (do_mipmap)
266     {
267       int status;
268       clear_gl_error();
269       status = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, format,
270                                  GL_UNSIGNED_BYTE, image);
271       if (status)
272         {
273           const char *s = (char *) gluErrorString (status);
274           fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
275                    progname, width, height,
276                    (s ? s : "(unknown)"));
277           exit (1);
278         }
279       check_gl_error("mipmapping");
280     }
281   else
282     {
283       clear_gl_error();
284       glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
285                    format, GL_UNSIGNED_BYTE, image);
286       check_gl_error("texture");
287     }
288 }
289
290 static void resetProjection(void) 
291 {
292   glMatrixMode(GL_PROJECTION);
293   glLoadIdentity();
294   glFrustum(-1, 1, -1, 1, 1, 100); 
295   glMatrixMode(GL_MODELVIEW);
296   glLoadIdentity();
297 }
298
299
300 static void GenerateQuad(pulsarstruct *gp)
301 {
302   int i;
303
304   gp->quad_list = glGenLists(1);
305   glNewList(gp->quad_list,GL_COMPILE);
306 #if 1
307   glBegin(GL_QUADS);
308   glColor4f(1,0,0,.4); glNormal3f(0,0,1);  glTexCoord2f(0,0); glVertex2f(-1, -1);
309   glColor4f(0,1,0,.4); glNormal3f(0,0,1);  glTexCoord2f(0,1); glVertex2f(-1,  1);
310   glColor4f(0,0,1,.4); glNormal3f(0,0,1);  glTexCoord2f(1,1); glVertex2f( 1,  1);
311   glColor4f(1,1,1,1); glNormal3f(0,0,1);  glTexCoord2f(1,0); glVertex2f( 1,  -1);
312 #else
313   glBegin(GL_TRIANGLE_STRIP);
314   glColor4f(0,1,0,.4); glNormal3f(0,0,1);  glTexCoord2f(0,1); glVertex2f(-1,  1);
315   glColor4f(1,0,0,.4); glNormal3f(0,0,1);  glTexCoord2f(0,0); glVertex2f(-1, -1);
316   glColor4f(0,0,1,.4); glNormal3f(0,0,1);  glTexCoord2f(1,1); glVertex2f( 1,  1);
317   glColor4f(1,1,1,.4); glNormal3f(0,0,1);  glTexCoord2f(1,0); glVertex2f( 1,  -1);
318 #endif
319   glEnd();
320   glEndList();
321
322   gp->quads = (struct quad *) malloc(sizeof(struct quad) * num_quads);
323   for (i=0; i < num_quads; i++)
324     {
325       gp->quads[i].rx = 0.;
326       gp->quads[i].ry = 0.;
327       gp->quads[i].rz = 0.;
328       gp->quads[i].tx = 0.;
329       gp->quads[i].ty = 0.;
330       gp->quads[i].tz = -10;
331
332       gp->quads[i].drx = frand(5.0);
333       gp->quads[i].dry = frand(5.0);
334       gp->quads[i].drz = 0;
335     }
336 }
337
338 static void initializeGL(ModeInfo *mi, GLsizei width, GLsizei height) 
339 {
340   pulsarstruct *gp = &Pulsar[MI_SCREEN(mi)];
341   GLfloat fogColor[4] = { 0.1, 0.1, 0.1, 0.1 };
342
343   glViewport( 0, 0, width, height ); 
344   resetProjection();
345
346   if (do_depth)
347         glEnable(GL_DEPTH_TEST);
348
349   if (do_antialias) {
350         do_blend = 1;
351         glEnable(GL_LINE_SMOOTH);
352   }
353
354   if (do_blend) {
355         glEnable(GL_BLEND);
356         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
357   }
358
359
360   if (do_light) {
361         glShadeModel(GL_SMOOTH);
362         glEnable(GL_COLOR_MATERIAL);
363         glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
364   }
365
366   if (do_wire)
367         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
368   else 
369         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
370
371   if (do_fog) {
372         glEnable(GL_FOG);
373         glFogi(GL_FOG_MODE, GL_LINEAR);
374         glFogfv(GL_FOG_COLOR, fogColor);
375         glFogf(GL_FOG_DENSITY, 0.35);
376 /*      glHint(GL_FOG_HINT, GL_FASTEST); */
377         glFogf(GL_FOG_START, 50.0);
378         glFogf(GL_FOG_END, 100.0);
379   }
380         
381
382   if (do_texture)
383           Create_Texture(mi, which_image); 
384
385   GenerateQuad(gp);
386 }
387
388 static void drawQuads(pulsarstruct *gp) 
389 {
390   int i;
391   for (i=0; i < num_quads; i++)
392     {
393       glPushMatrix();
394       glTranslatef(gp->quads[i].tx,0,0);
395       glTranslatef(0,gp->quads[i].ty,0);
396       glTranslatef(0,0,gp->quads[i].tz);
397       glRotatef(gp->quads[i].rx, 1,0,0);
398       glRotatef(gp->quads[i].ry, 0,1,0);
399       glRotatef(gp->quads[i].rz, 0,0,1);
400       glCallList(gp->quad_list);
401       glPopMatrix();
402
403       gp->quads[i].rx += gp->quads[i].drx;
404       gp->quads[i].ry += gp->quads[i].dry;
405       gp->quads[i].rz += gp->quads[i].drz;
406
407     }
408 }
409
410 static GLvoid drawScene(ModeInfo * mi) 
411 {
412   pulsarstruct *gp = &Pulsar[MI_SCREEN(mi)];
413 /*  check_gl_error ("drawScene"); */
414   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
415
416   /* we have to do this here because the FPS meter turns these 3 features off!! */
417   {
418         if (do_light) {
419           glEnable(GL_LIGHTING);
420           glEnable(GL_LIGHT0);
421         }
422         
423         if (do_texture) {
424           glEnable(GL_TEXTURE_2D);
425         }
426         
427         if (do_blend) {
428           glEnable(GL_BLEND);
429           glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
430         }
431   }
432
433   resetProjection();
434
435   /* use XYZ scaling factors to change the size of the pulsar */
436   glScalef(gp->scale_x, gp->scale_y, gp->scale_z);
437   drawQuads(gp);
438
439   /* update the scaling factors- cyclic */
440   gp->scale_x = cos(gp->frame/360.)*10.;
441   gp->scale_y = sin(gp->frame/360.)*10.;
442   gp->scale_z = 1;
443
444   /* increment frame-counter */
445   gp->frame++;
446
447 /*  check_gl_error ("drawScene"); */
448 }
449
450
451 ENTRYPOINT void draw_pulsar(ModeInfo * mi)
452 {
453   pulsarstruct *gp = &Pulsar[MI_SCREEN(mi)];
454   Display    *display = MI_DISPLAY(mi);
455   Window      window = MI_WINDOW(mi);
456
457   if (!gp->glx_context)
458         return;
459
460   glXMakeCurrent(display, window, *(gp->glx_context));
461   drawScene(mi);
462   if (mi->fps_p) do_fps (mi);
463   glXSwapBuffers(display, window);
464 }
465
466 /* Standard reshape function */
467 ENTRYPOINT void
468 reshape_pulsar(ModeInfo *mi, int width, int height)
469 {
470   glViewport( 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi) );
471   resetProjection();
472 }
473
474 ENTRYPOINT void
475 init_pulsar(ModeInfo * mi)
476 {
477   int screen = MI_SCREEN(mi);
478
479   pulsarstruct *gp;
480
481   if (Pulsar == NULL) {
482         if ((Pulsar = (pulsarstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (pulsarstruct))) == NULL)
483           return;
484   }
485   gp = &Pulsar[screen];
486
487   gp->window = MI_WINDOW(mi);
488
489   gp->scale_x = gp->scale_y = gp->scale_z = 1;
490
491   if ((gp->glx_context = init_GL(mi)) != NULL) {
492         reshape_pulsar(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
493         initializeGL(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
494   } else {
495         MI_CLEARWINDOW(mi);
496   }
497 }
498
499
500 /* all sorts of nice cleanup code should go here! */
501 ENTRYPOINT void release_pulsar(ModeInfo * mi)
502 {
503   int screen;
504   if (Pulsar != NULL) {
505         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
506           pulsarstruct *gp = &Pulsar[screen];
507       free(gp->quads);
508         }
509         (void) free((void *) Pulsar);
510         Pulsar = NULL;
511   }
512   FreeAllGL(mi);
513 }
514 #endif
515
516 XSCREENSAVER_MODULE ("Pulsar", pulsar)