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