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