http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.01.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 /*-
44  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
45  * otherwise caddr_t is not defined correctly
46  */
47
48 #include <X11/Intrinsic.h>
49
50 #ifdef STANDALONE
51 # define PROGCLASS                                              "Screensaver"
52 # define HACK_INIT                                              init_screensaver
53 # define HACK_DRAW                                              draw_screensaver
54 # define HACK_RESHAPE                                   reshape_screensaver
55 # define screensaver_opts                               xlockmore_opts
56 #define DEFAULTS                        "*delay:                        10000   \n" \
57                                                                                 "*showFPS:          False   \n" \
58                                                                                 "*light:                        False   \n" \
59                                         "*wire:                         False   \n" \
60                                         "*quads:                        5       \n" \
61                                         "*blend:                        True    \n" \
62                                         "*fog:                          False   \n" \
63                                         "*antialias:            False   \n" \
64                                         "*texture:                      False   \n" \
65                                         "*texture_quality:      False   \n" \
66                                         "*mipmap:                       False   \n" \
67                                         "*doDepth:                      False   \n" \
68                                                                                 "*image:                        BUILTIN \n"
69
70 # include "xlockmore.h"                         /* from the xscreensaver distribution */
71 #else /* !STANDALONE */
72 # include "xlock.h"                                     /* from the xlockmore distribution */
73 #endif /* !STANDALONE */
74
75 #ifdef USE_GL /* whole file */
76
77 #ifdef HAVE_XMU
78 # ifndef VMS
79 #  include <X11/Xmu/Drawing.h>
80 #else  /* VMS */
81 #  include <Xmu/Drawing.h>
82 # endif /* VMS */
83 #endif
84
85
86 #include <GL/gl.h>
87 #include <GL/glu.h>
88
89 #include <stdlib.h>
90 #include <stdio.h>
91 #include <string.h>
92
93 /* Functions for loading and storing textures */
94
95 #define checkImageWidth 64
96 #define checkImageHeight 64
97
98 /* Functions for handling the frames per second timer */
99 #include "GL/glx.h"
100
101 #undef countof
102 #define countof(x) (sizeof((x))/sizeof((*x)))
103
104 #define WIDTH 800
105 #define HEIGHT 600
106
107 #define NUM_QUADS 5
108 #define DEF_NUM_QUADS   "5"
109 #define DEF_LIGHT               "False"
110 #define DEF_WIRE                "False"
111 #define DEF_BLEND       "True"
112 #define DEF_FOG                 "False"
113 #define DEF_ANTIALIAS   "False"
114 #define DEF_TEXTURE     "False"
115 #define DEF_TEXTURE_QUALITY   "False"
116 #define DEF_MIPMAP      "False"
117 #define DEF_DO_DEPTH    "False"
118 #define DEF_IMAGE       "BUILTIN"
119
120 static int num_quads;
121 static int do_light;
122 static int do_wire;
123 static int do_blend;
124 static int do_fog;
125 static int do_antialias;
126 static int do_texture;
127 static int do_texture_quality;
128 static int do_mipmap;
129 static int do_depth;
130 static char *which_image;
131
132
133 static XrmOptionDescRec opts[] = {
134   {"-quads",   ".pulsar.quads",   XrmoptionSepArg, (caddr_t) NULL },
135   {"-light",   ".pulsar.light",   XrmoptionNoArg, (caddr_t) "true" },
136   {"+light",   ".pulsar.light",   XrmoptionNoArg, (caddr_t) "false" },
137   {"-wire",   ".pulsar.wire",   XrmoptionNoArg, (caddr_t) "true" },
138   {"+wire",   ".pulsar.wire",   XrmoptionNoArg, (caddr_t) "false" },
139   {"-blend",   ".pulsar.blend",   XrmoptionNoArg, (caddr_t) "true" },
140   {"+blend",   ".pulsar.blend",   XrmoptionNoArg, (caddr_t) "false" },
141   {"-fog",   ".pulsar.fog",   XrmoptionNoArg, (caddr_t) "true" },
142   {"+fog",   ".pulsar.fog",   XrmoptionNoArg, (caddr_t) "false" },
143   {"-antialias",   ".pulsar.antialias",   XrmoptionNoArg, (caddr_t) "true" },
144   {"+antialias",   ".pulsar.antialias",   XrmoptionNoArg, (caddr_t) "false" },
145   {"-texture",   ".pulsar.texture",   XrmoptionNoArg, (caddr_t) "true" },
146   {"+texture",   ".pulsar.texture",   XrmoptionNoArg, (caddr_t) "false" },
147   {"-texture_quality",   ".pulsar.texture_quality",   XrmoptionNoArg, (caddr_t) "true" },
148   {"+texture_quality",   ".pulsar.texture_quality",   XrmoptionNoArg, (caddr_t) "false" },
149   {"-mipmap",   ".pulsar.mipmap",   XrmoptionNoArg, (caddr_t) "true" },
150   {"+mipmap",   ".pulsar.mipmap",   XrmoptionNoArg, (caddr_t) "false" },
151   {"-do_depth",   ".pulsar.doDepth",   XrmoptionNoArg, (caddr_t) "true" },
152   {"+do_depth",   ".pulsar.doDepth",   XrmoptionNoArg, (caddr_t) "false" },
153   {"-image",   ".pulsar.image",  XrmoptionSepArg, (caddr_t) NULL },
154 };
155
156
157 static argtype vars[] = {
158   {(caddr_t *) &num_quads, "quads", "Quads", DEF_NUM_QUADS, t_Int},
159   {(caddr_t *) &do_light,    "light",   "Light",   DEF_LIGHT,   t_Bool},
160   {(caddr_t *) &do_wire,    "wire",   "Wire",   DEF_WIRE,   t_Bool},
161   {(caddr_t *) &do_blend,    "blend",   "Blend",   DEF_BLEND,   t_Bool},
162   {(caddr_t *) &do_fog,    "fog",   "Fog",   DEF_FOG,   t_Bool},
163   {(caddr_t *) &do_antialias,    "antialias",   "Antialias",   DEF_ANTIALIAS,   t_Bool},
164   {(caddr_t *) &do_texture,    "texture",   "Texture",   DEF_TEXTURE,   t_Bool},
165   {(caddr_t *) &do_texture_quality,    "texture_quality",   "Texture_quality",   DEF_TEXTURE_QUALITY,   t_Bool},
166   {(caddr_t *) &do_mipmap,    "mipmap",   "Mipmap",   DEF_MIPMAP,   t_Bool},
167   {(caddr_t *) &do_depth,    "doDepth",   "DoDepth",   DEF_DO_DEPTH,   t_Bool},
168   {(caddr_t *) &which_image, "image",   "Image",   DEF_IMAGE,   t_String},
169 };
170
171
172 static OptionStruct desc[] =
173 {
174         {"-quads num", "how many quads to draw"},
175         {"-/+ light", "whether to do enable lighting (slower)"},
176         {"-/+ wire", "whether to do use wireframe instead of filled (faster)"},
177         {"-/+ blend", "whether to do enable blending (slower)"},
178         {"-/+ fog", "whether to do enable fog (?)"},
179         {"-/+ antialias", "whether to do enable antialiased lines (slower)"},
180         {"-/+ texture", "whether to do enable texturing (much slower)"},
181         {"-/+ texture_quality", "whether to do enable linear/mipmap filtering (much much slower)"},
182         {"-/+ mipmap", "whether to do enable mipmaps (much slower)"},
183         {"-/+ depth", "whether to do enable depth buffer checking (slower)"},
184         {"-image <filename>", "texture image to load (PPM, PPM4, TIFF(?), XPM(?))"},
185 };
186
187 ModeSpecOpt screensaver_opts = {countof(opts), opts, countof(vars), vars, desc};
188
189 #ifdef USE_MODULES
190 ModStruct   screensaver_description =
191 {"screensaver", "init_screensaver", "draw_screensaver", "release_screensaver",
192  "draw_screensaver", "init_screensaver", NULL, &screensaver_opts,
193  1000, 1, 2, 1, 4, 1.0, "",
194  "OpenGL screensaver", 0, NULL};
195 #endif
196
197
198 /* structure for holding the screensaver data */
199 typedef struct {
200   int screen_width, screen_height;
201   GLXContext *glx_context;
202   Window window;
203   XColor fg, bg;
204 } screensaverstruct;
205
206 static screensaverstruct *Screensaver = NULL;
207
208 struct quad
209 {
210   GLfloat tx, ty, tz;
211   GLfloat rx, ry, rz;
212
213   GLfloat dtx, dty, dtz;
214   GLfloat drx, dry, drz;
215
216 };
217
218
219 GLint quad_list;
220
221 static float scale_x=1, scale_y=1, scale_z=1;
222 static int frame = 0;
223
224 struct quad *quads;
225
226 GLubyte *Generate_Image(int *width, int *height, int *format)
227 {
228   GLubyte *result;
229   int i, j, c;
230   int counter=0;
231
232   *width = checkImageWidth;
233   *height = checkImageHeight;
234   result = (GLubyte *)malloc(4 * *width * *height);
235
236   counter = 0;
237   for (i = 0; i < checkImageWidth; i++) {
238     for (j = 0; j < checkImageHeight; j++) {
239       c = (((((i&0x8)==0))^(((j&0x8))==0)))*255;
240       result[counter++] = (GLubyte) c;
241       result[counter++] = (GLubyte) c;
242       result[counter++] = (GLubyte) c;
243       result[counter++] = (GLubyte) 255;
244     }
245   }
246
247   *format = GL_RGBA;
248   return result;
249 }
250
251
252
253 #ifdef TIFF
254 #include <tiffio>
255 /* Load a TIFF texture: requires libtiff */
256 uint32 *LoadTIFF(char *filename, int *width, int *height, int *format)
257 {
258   TIFF *tif;
259   char emsg[1024];
260   uint32 *raster;
261   TIFFRGBAImage img;
262   tsize_t npixels;
263
264   tif = TIFFOpen(filename, "r");
265   if (tif == NULL) {
266     fprintf(stderr, "Problem showing %s\n", filename);
267     return Generate_Image(&width, &height, &format);
268   }
269   if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
270     npixels = (tsize_t) (img.width * img.height);
271     raster = (uint32 *) _TIFFmalloc(npixels * (tsize_t) sizeof(uint32));
272     if (raster != NULL) {
273       if (TIFFRGBAImageGet(&img, raster, img.width, img.height) == 0) {
274         TIFFError(filename, emsg);
275         return Generate_Image(&width, &height, &format);
276       }
277     }
278     TIFFRGBAImageEnd(&img);
279   } else {
280     TIFFError(filename, emsg);
281     return Generate_Image(&width, &height, &format);
282   }
283
284   *width = img.width;
285   *height = img.height;
286   *format = GL_RGBA;
287
288   TIFFClose(tif);
289   return raster;
290 }
291 #endif
292
293 /* Load a modified version of PPM format with an extra byte for alpha */
294 GLubyte *LoadPPM4(const char *filename, int *width, int *height, int *format)
295 {
296   char buff[1024];
297   GLubyte *data;
298   int sizeX, sizeY;
299   FILE *fp;
300   int maxval;
301
302   fp = fopen(filename, "rb");
303   if (!fp)
304     {
305       fprintf(stderr, "Unable to open file '%s'\n", filename);
306       return  Generate_Image(width, height, format);
307     }
308
309   if (!fgets(buff, sizeof(buff), fp))
310     {
311       perror("Unable to read header filename\n");
312       return  Generate_Image(width, height, format);
313     }
314
315   if (buff[0] != '6' || buff[1] != 'P')
316     {
317       fprintf(stderr, "Invalid image format (must be `6P')\n");
318       return  Generate_Image(width, height, format);
319     }
320
321   do
322     {
323       fgets(buff, sizeof(buff), fp);
324     }
325   while (buff[0] == '#');
326     
327   if (sscanf(buff, "%d %d", &sizeX, &sizeY) != 2)
328     {
329       fprintf(stderr, "Error loading image `%s'\n", filename);
330       return  Generate_Image(width, height, format);
331     }
332
333   if (fscanf(fp, "%d", &maxval) != 1)
334     {
335       fprintf(stderr, "Error loading image `%s'\n", filename);
336       return  Generate_Image(width, height, format);
337     }
338
339   while (fgetc(fp) != '\n')
340     ;
341
342   data = (GLubyte *)malloc(4 * sizeX * sizeY);
343   if (data == NULL)
344     {
345       fprintf(stderr, "Unable to allocate memory\n");
346           exit(1);
347     }
348
349   if (fread(data, 4 * sizeX, sizeY, fp) != sizeY)
350     {
351       fprintf(stderr, "Error loading image `%s'\n", filename);
352       return  Generate_Image(width, height, format);
353     }
354
355   fclose(fp);
356
357   *width = sizeX;
358   *height = sizeY;
359   *format = GL_RGBA;
360   return data;
361 }
362
363 /* Load a plain PPM image */
364 GLubyte *LoadPPM(const char *filename, int *width, int *height, int *format)
365 {
366   char buff[1024];
367   GLubyte *data;
368   GLint sizeX, sizeY;
369   FILE *fp;
370   int maxval;
371
372   fp = fopen(filename, "rb");
373   if (!fp)
374     {
375       fprintf(stderr, "Unable to open file '%s'\n", filename);
376       return  Generate_Image(width, height, format);
377       exit(1);
378     }
379   if (!fgets(buff, sizeof(buff), fp))
380     {
381       perror(filename);
382       return  Generate_Image(width, height, format);
383     }
384
385   if (buff[0] != 'P' || buff[1] != '6')
386     {
387       fprintf(stderr, "Invalid image format (must be `P6')\n");
388       return  Generate_Image(width, height, format);
389     }
390
391   do
392     {
393       fgets(buff, sizeof(buff), fp);
394     }
395   while (buff[0] == '#');
396     
397   if (sscanf(buff, "%d %d", &sizeX, &sizeY) != 2)
398     {
399       fprintf(stderr, "Error loading image `%s'\n", filename);
400       return  Generate_Image(width, height, format);
401     }
402
403   if (fscanf(fp, "%d", &maxval) != 1)
404     {
405       fprintf(stderr, "Error loading image `%s'\n", filename);
406       return  Generate_Image(width, height, format);
407     }
408
409   while (fgetc(fp) != '\n')
410     ;
411
412   data = (GLubyte *)malloc(3 * sizeX * sizeY);
413   if (data == NULL)
414     {
415       fprintf(stderr, "Unable to allocate memory\n");
416           exit(1);
417     }
418
419   if (fread(data, 3 * sizeX, sizeY, fp) != sizeY)
420     {
421       fprintf(stderr, "Error loading image `%s'\n", filename);
422       return  Generate_Image(width, height, format);
423     }
424
425   fclose(fp);
426
427   *width = sizeX;
428   *height = sizeY;
429   *format = GL_RGB;
430   return data;
431 }
432
433 /* Create a texture in OpenGL.  First an image is loaded 
434    and stored in a raster buffer, then it's  */
435 void Create_Texture(char *filename)
436 {
437   int height, width;
438   GLubyte *image;
439   GLint a;
440   int format;
441
442   if ( !strncmp(filename, "BUILTIN", 7))
443     image = Generate_Image(&width, &height, &format);
444   else if ( !strncmp((filename+strlen(filename)-3), "ppm", 3))
445     image = LoadPPM(filename, &width, &height, &format);
446   else if ( !strncmp((filename+strlen(filename)-4), "ppm4", 4))
447     image = LoadPPM4(filename, &width, &height, &format);
448 #ifdef TIFF
449   else if ( !strncmp((filename+strlen(filename)-4), "tiff", 4))
450     image = (GLubyte *)LoadTIFF(filename, &width, &height, &format);
451 #endif
452   else {
453     fprintf(stderr, "Unknown file format extension: '%s'\n", filename);
454     image = Generate_Image(&width, &height, &format);
455   }
456
457   /* GL_MODULATE or GL_DECAL depending on what you want */
458   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
459   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
460   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
461   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
462   /* perhaps we can edge a bit more speed at the expense of quality */
463   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
464
465   if (do_texture_quality) {
466         /* with texture_quality, the min and mag filters look *much* nice but are *much* slower */
467         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
468         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
469   }
470   else {
471         /* default is to do it quick and dirty */
472         /* if you have mipmaps turned on, but not texture quality, nothing will happen! */
473         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
474         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
475   }
476
477   /* mipmaps make the image look much nicer */
478   if (do_mipmap)
479         a=gluBuild2DMipmaps(GL_TEXTURE_2D, format, width, height, format, GL_UNSIGNED_BYTE, image);
480   else
481     {
482       clear_gl_error();
483       glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
484                    format, GL_UNSIGNED_BYTE, image);
485       check_gl_error("texture");
486     }
487
488   free(image);
489 }
490
491 void resetProjection(void) {
492   glMatrixMode(GL_PROJECTION);
493   glLoadIdentity();
494   glFrustum(-1, 1, -1, 1, 1, 100); 
495   glMatrixMode(GL_MODELVIEW);
496   glLoadIdentity();
497 }
498
499
500 void GenerateQuad(void)
501 {
502   int i;
503
504   quad_list = glGenLists(1);
505   glNewList(quad_list,GL_COMPILE);
506 #if 1
507   glBegin(GL_QUADS);
508   glColor4f(1,0,0,.4); glNormal3f(0,0,1);  glTexCoord2f(0,0); glVertex2f(-1, -1);
509   glColor4f(0,1,0,.4); glNormal3f(0,0,1);  glTexCoord2f(0,1); glVertex2f(-1,  1);
510   glColor4f(0,0,1,.4); glNormal3f(0,0,1);  glTexCoord2f(1,1); glVertex2f( 1,  1);
511   glColor4f(1,1,1,1); glNormal3f(0,0,1);  glTexCoord2f(1,0); glVertex2f( 1,  -1);
512 #else
513   glBegin(GL_TRIANGLE_STRIP);
514   glColor4f(0,1,0,.4); glNormal3f(0,0,1);  glTexCoord2f(0,1); glVertex2f(-1,  1);
515   glColor4f(1,0,0,.4); glNormal3f(0,0,1);  glTexCoord2f(0,0); glVertex2f(-1, -1);
516   glColor4f(0,0,1,.4); glNormal3f(0,0,1);  glTexCoord2f(1,1); glVertex2f( 1,  1);
517   glColor4f(1,1,1,.4); glNormal3f(0,0,1);  glTexCoord2f(1,0); glVertex2f( 1,  -1);
518 #endif
519   glEnd();
520   glEndList();
521
522   quads = (struct quad *) malloc(sizeof(struct quad) * num_quads);
523   for (i=0; i < num_quads; i++)
524     {
525       quads[i].rx = 0.;
526       quads[i].ry = 0.;
527       quads[i].rz = 0.;
528       quads[i].tx = 0.;
529       quads[i].ty = 0.;
530       quads[i].tz = -10;
531
532       quads[i].drx = frand(5.0);
533       quads[i].dry = frand(5.0);
534       quads[i].drz = 0;
535     }
536 }
537
538 void initializeGL(GLsizei width, GLsizei height) 
539 {
540   GLfloat fogColor[4] = { 0.1, 0.1, 0.1, 0.1 };
541
542   glViewport( 0, 0, width, height ); 
543   resetProjection();
544
545   if (do_depth)
546         glEnable(GL_DEPTH_TEST);
547
548   if (do_antialias) {
549         do_blend = 1;
550         glEnable(GL_LINE_SMOOTH);
551   }
552
553   if (do_blend) {
554         glEnable(GL_BLEND);
555         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
556   }
557
558
559   if (do_light) {
560         glShadeModel(GL_SMOOTH);
561         glEnable(GL_COLOR_MATERIAL);
562         glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
563   }
564
565   if (do_wire)
566         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
567   else 
568         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
569
570   if (do_fog) {
571         glEnable(GL_FOG);
572         glFogi(GL_FOG_MODE, GL_LINEAR);
573         glFogfv(GL_FOG_COLOR, fogColor);
574         glFogf(GL_FOG_DENSITY, 0.35);
575 /*      glHint(GL_FOG_HINT, GL_FASTEST); */
576         glFogf(GL_FOG_START, 50.0);
577         glFogf(GL_FOG_END, 100.0);
578   }
579         
580
581   if (do_texture)
582           Create_Texture(which_image); 
583
584   GenerateQuad();
585 }
586 void drawQuads(void) {
587   int i;
588   for (i=0; i < num_quads; i++)
589     {
590       glPushMatrix();
591       glTranslatef(quads[i].tx,0,0);
592       glTranslatef(0,quads[i].ty,0);
593       glTranslatef(0,0,quads[i].tz);
594       glRotatef(quads[i].rx, 1,0,0);
595       glRotatef(quads[i].ry, 0,1,0);
596       glRotatef(quads[i].rz, 0,0,1);
597       glCallList(quad_list);
598       glPopMatrix();
599
600       quads[i].rx += quads[i].drx;
601       quads[i].ry += quads[i].dry;
602       quads[i].rz += quads[i].drz;
603
604     }
605 }
606
607 GLvoid drawScene(ModeInfo * mi) 
608 {
609 /*  check_gl_error ("drawScene"); */
610   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
611
612   /* we have to do this here because the FPS meter turns these 3 features off!! */
613   {
614         if (do_light) {
615           glEnable(GL_LIGHTING);
616           glEnable(GL_LIGHT0);
617         }
618         
619         if (do_texture) {
620           glEnable(GL_TEXTURE_2D);
621         }
622         
623         if (do_blend) {
624           glEnable(GL_BLEND);
625           glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
626         }
627   }
628
629   resetProjection();
630
631   /* use XYZ scaling factors to change the size of the pulsar */
632   glScalef(scale_x, scale_y, scale_z);
633   drawQuads();
634
635   /* update the scaling factors- cyclic */
636   scale_x = cos(frame/360.)*10.;
637   scale_y = sin(frame/360.)*10.;
638   scale_z = 1;
639
640   /* increment frame-counter */
641   frame++;
642
643 /*  check_gl_error ("drawScene"); */
644 }
645
646
647 void draw_screensaver(ModeInfo * mi)
648 {
649   screensaverstruct *gp = &Screensaver[MI_SCREEN(mi)];
650   Display    *display = MI_DISPLAY(mi);
651   Window      window = MI_WINDOW(mi);
652
653   if (!gp->glx_context)
654         return;
655
656   glXMakeCurrent(display, window, *(gp->glx_context));
657   drawScene(mi);
658   if (mi->fps_p) do_fps (mi);
659   glXSwapBuffers(display, window);
660 }
661
662 /* Standard reshape function */
663 void
664 reshape_screensaver(ModeInfo *mi, int width, int height)
665 {
666   glViewport( 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi) );
667   resetProjection();
668 }
669
670 void
671 init_screensaver(ModeInfo * mi)
672 {
673   int screen = MI_SCREEN(mi);
674
675   screensaverstruct *gp;
676
677   if (Screensaver == NULL) {
678         if ((Screensaver = (screensaverstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (screensaverstruct))) == NULL)
679           return;
680   }
681   gp = &Screensaver[screen];
682
683   gp->window = MI_WINDOW(mi);
684   if ((gp->glx_context = init_GL(mi)) != NULL) {
685         reshape_screensaver(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
686         initializeGL(MI_WIDTH(mi), MI_HEIGHT(mi));
687   } else {
688         MI_CLEARWINDOW(mi);
689   }
690 }
691
692
693 /* all sorts of nice cleanup code should go here! */
694 void release_screensaver(ModeInfo * mi)
695 {
696   int screen;
697   if (Screensaver != NULL) {
698         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
699 /*        screensaverstruct *gp = &Screensaver[screen];*/
700         }
701         (void) free((void *) Screensaver);
702         Screensaver = NULL;
703   }
704   free(quads);
705   FreeAllGL(mi);
706 }
707 #endif