d1c8dbbb825e0838f56e219496615e3c53006f61
[xscreensaver] / hacks / glx / extrusion.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* extrusion --- extrusion 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  * Tue Oct 19 22:24:47 PDT 1999    Initial creation by David Konerding
18  *                                 <dek@cgl.ucsf.edu>
19  *                                                                 
20  * Notes:
21  * This screensaver requires the GLE ("OpenGL Tubing and Extrusion Library")
22  * which can be obtained from http://www.linas.org/gle/index.html
23   */
24
25 /*-
26  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
27  * otherwise caddr_t is not defined correctly
28  */
29
30 #include <X11/Intrinsic.h>
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35
36 #ifdef STANDALONE
37 # define PROGCLASS                                              "Screensaver"
38 # define HACK_INIT                                              init_screensaver
39 # define HACK_DRAW                                              draw_screensaver
40 # define HACK_RESHAPE                                   reshape_screensaver
41 # define screensaver_opts                               xlockmore_opts
42 #define DEFAULTS                        "*delay:                        10000   \n" \
43                                                                                 "*showFPS:              False   \n" \
44                                                                                 "*light:                        True    \n" \
45                                         "*wire:                         False   \n" \
46                                         "*texture:                      False   \n" \
47                                                                                 "*image:                        BUILTIN \n" \
48                                         "*name:             RANDOM  \n" \
49                                         "*example:          0       \n"
50
51 # include "xlockmore.h"                         /* from the xscreensaver distribution */
52 #else /* !STANDALONE */
53 # include "xlock.h"                                     /* from the xlockmore distribution */
54 #endif /* !STANDALONE */
55
56 #ifdef USE_GL /* whole file */
57
58 #ifdef HAVE_XPM
59 # include <X11/xpm.h>
60 # ifndef PIXEL_ALREADY_TYPEDEFED
61 # define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
62 # endif
63 #endif
64
65 #ifdef HAVE_XMU
66 # ifndef VMS
67 #  include <X11/Xmu/Drawing.h>
68 #else  /* VMS */
69 #  include <Xmu/Drawing.h>
70 # endif /* VMS */
71 #endif
72
73 #include <malloc.h>
74 #include <string.h>
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <malloc.h>
78 #include <GL/gl.h>
79 #include <GL/glu.h>
80 #ifdef HAVE_GLE3
81 #include <GL/gle.h>
82 #else
83 #include <GL/tube.h>
84 #endif
85
86 #undef countof
87 #define countof(x) (sizeof((x))/sizeof((*x)))
88
89
90 #define checkImageWidth 64
91 #define checkImageHeight 64
92
93
94 extern void InitStuff_helix2(void);
95 extern void DrawStuff_helix2(void);
96 extern void InitStuff_helix3(void);
97 extern void DrawStuff_helix3(void);
98 extern void InitStuff_helix4(void);
99 extern void DrawStuff_helix4(void);
100 extern void InitStuff_joinoffset(void);
101 extern void DrawStuff_joinoffset(void);
102 extern void InitStuff_screw(void);
103 extern void DrawStuff_screw(void);
104 extern void InitStuff_taper(void);
105 extern void DrawStuff_taper(void);
106 extern void InitStuff_twistoid(void);
107 extern void DrawStuff_twistoid(void);
108
109
110
111 #define WIDTH 640
112 #define HEIGHT 480
113
114 #define DEF_LIGHT               "True"
115 #define DEF_WIRE                "False"
116 #define DEF_TEXTURE             "False"
117 #define DEF_TEXTURE_QUALITY   "False"
118 #define DEF_MIPMAP      "False"
119 #define DEF_NAME        "RANDOM"
120 #define DEF_IMAGE       "BUILTIN"
121
122 static int do_light;
123 static int do_wire;
124 static int do_texture;
125 static int do_texture_quality;
126 static int do_mipmap;
127 static char *which_name;
128 static char *which_image;
129
130 static XrmOptionDescRec opts[] = {
131   {"-light",   ".extrusion.light",     XrmoptionNoArg, (caddr_t) "true" },
132   {"+light",   ".extrusion.light",     XrmoptionNoArg, (caddr_t) "false" },
133   {"-wire",    ".extrusion.wire",      XrmoptionNoArg, (caddr_t) "true" },
134   {"+wire",    ".extrusion.wire",      XrmoptionNoArg, (caddr_t) "false" },
135   {"-texture", ".extrusion.texture",   XrmoptionNoArg, (caddr_t) "true" },
136   {"+texture", ".extrusion.texture",   XrmoptionNoArg, (caddr_t) "false" },
137   {"-texture", ".extrusion.texture",   XrmoptionNoArg, (caddr_t) "true" },
138   {"+texture_quality", ".extrusion.texture",   XrmoptionNoArg, (caddr_t) "false" },
139   {"-texture_quality", ".extrusion.texture",   XrmoptionNoArg, (caddr_t) "true" },
140   {"+mipmap", ".extrusion.mipmap",   XrmoptionNoArg, (caddr_t) "false" },
141   {"-mipmap", ".extrusion.mipmap",   XrmoptionNoArg, (caddr_t) "true" },
142   {"-name",   ".extrusion.name",  XrmoptionSepArg, (caddr_t) NULL },
143   {"-image",   ".extrusion.image",  XrmoptionSepArg, (caddr_t) NULL },
144 };
145
146
147 static argtype vars[] = {
148   {(caddr_t *) &do_light,    "light",   "Light",   DEF_LIGHT,   t_Bool},
149   {(caddr_t *) &do_wire,    "wire",   "Wire",   DEF_WIRE,   t_Bool},
150   {(caddr_t *) &do_texture,    "texture",   "Texture",   DEF_TEXTURE,   t_Bool},
151   {(caddr_t *) &do_texture_quality,    "texture_quality",   "Texture_Quality",   DEF_TEXTURE_QUALITY,   t_Bool},
152   {(caddr_t *) &do_mipmap,    "mipmap",   "Mipmap",   DEF_MIPMAP,   t_Bool},
153   {(caddr_t *) &which_name, "name",   "Name",   DEF_NAME,   t_String},
154   {(caddr_t *) &which_image, "image",   "Image",   DEF_IMAGE,   t_String},
155 };
156
157
158 static OptionStruct desc[] =
159 {
160   {"-name num", "example 'name' to draw (helix2, helix3, helix4, joinoffset, screw, taper, twistoid)"},
161   {"-/+ light", "whether to do enable lighting (slower)"},
162   {"-/+ wire", "whether to do use wireframe instead of filled (faster)"},
163   {"-/+ texture", "whether to apply a texture (slower)"},
164   {"-image <filename>", "texture image to load (PPM or PPM4)"},
165   {"-/+ texture_quality", "whether to use texture smoothing (slower)"},
166   {"-/+ mipmap", "whether to use texture mipmap (slower)"},
167 };
168
169 ModeSpecOpt screensaver_opts = {countof(opts), opts, countof(vars), vars, desc};
170
171 #ifdef USE_MODULES
172 ModStruct   screensaver_description =
173 {"screensaver", "init_screensaver", "draw_screensaver", "release_screensaver",
174  "draw_screensaver", "init_screensaver", NULL, &screensaver_opts,
175  1000, 1, 2, 1, 4, 1.0, "",
176  "OpenGL screensaver", 0, NULL};
177 #endif
178
179
180 /* structure for holding the screensaver data */
181 typedef struct {
182   int screen_width, screen_height;
183   GLXContext *glx_context;
184   Window window;
185   XColor fg, bg;
186 } screensaverstruct;
187 static screensaverstruct *Screensaver = NULL;
188
189
190
191
192 /* convenient access to the screen width */
193 static int global_width=640, global_height=480;
194
195 /* set up a light */
196 static GLfloat lightOnePosition[] = {40.0, 40, 100.0, 0.0};
197 static GLfloat lightOneColor[] = {0.99, 0.99, 0.99, 1.0}; 
198
199 static GLfloat lightTwoPosition[] = {-40.0, 40, 100.0, 0.0};
200 static GLfloat lightTwoColor[] = {0.99, 0.99, 0.99, 1.0}; 
201
202 float rot_x=0, rot_y=0, rot_z=0;
203 static float dx=0, dy=0, dz=0;
204 static float ddx=0, ddy=0, ddz=0;
205 static float d_max = 0;
206 static int screensaver_number;
207
208 static float max_lastx=300, max_lasty=400;
209 static float min_lastx=-400, min_lasty=-400;
210 static float d_lastx=0, d_lasty=0;
211 static float dd_lastx=0, dd_lasty=0;
212 static float max_dlastx=0, max_dlasty=0;
213 float lastx=0, lasty=0;
214
215 static int errCode;
216 static GLubyte * errString;
217
218 struct functions {
219   void (*InitStuff)(void);
220   void (*DrawStuff)(void);
221   char *name;
222 };
223
224 /* currently joinoffset and twistoid look funny-
225    like we're looking at them from the back or something
226 */
227
228 struct functions funcs_ptr[] = {
229   {InitStuff_helix2, DrawStuff_helix2, "helix2"},
230   {InitStuff_helix3, DrawStuff_helix3, "helix3"},
231   {InitStuff_helix4, DrawStuff_helix4, "helix4"},
232   {InitStuff_joinoffset, DrawStuff_joinoffset, "joinoffset"},
233   {InitStuff_screw, DrawStuff_screw, "screw"},
234   {InitStuff_taper, DrawStuff_taper, "taper"},
235   {InitStuff_twistoid, DrawStuff_twistoid, "twistoid"},
236 };
237
238 static int num_screensavers = countof(funcs_ptr);
239
240
241 /* BEGINNING OF FUNCTIONS */
242
243
244 /* check for errors, bail if any.  useful for debugging */
245 int checkError(int line, char *file)
246 {
247   if((errCode = glGetError()) != GL_NO_ERROR) {
248     errString = (GLubyte *)gluErrorString(errCode);
249     fprintf(stderr, "%s: OpenGL error: %s detected at line %d in file %s\n",
250             progname, errString, line, file);
251     exit(1);
252   }
253   return 0;
254 }
255
256
257 /* generate a checkered image for texturing */
258 GLubyte *Generate_Image(int *width, int *height, int *format)
259 {
260   GLubyte *result;
261   int i, j, c;
262   int counter=0;
263
264   *width = checkImageWidth;
265   *height = checkImageHeight;
266   result = (GLubyte *)malloc(4 * *width * *height);
267
268   counter = 0;
269   for (i = 0; i < checkImageWidth; i++) {
270     for (j = 0; j < checkImageHeight; j++) {
271       c = (((((i&0x8)==0))^(((j&0x8))==0)))*255;
272       result[counter++] = (GLubyte) c;
273       result[counter++] = (GLubyte) c;
274       result[counter++] = (GLubyte) c;
275       result[counter++] = (GLubyte) 255;
276     }
277   }
278
279   *format = GL_RGBA;
280   return result;
281 }
282 /* Load a modified version of PPM format with an extra byte for alpha */
283 GLubyte *LoadPPM4(const char *filename, int *width, int *height, int *format)
284 {
285   char buff[1024];
286   GLubyte *data;
287   int sizeX, sizeY;
288   FILE *fp;
289   int maxval;
290
291   fp = fopen(filename, "rb");
292   if (!fp)
293     {
294       fprintf(stderr, "%s: unable to open file '%s'\n", progname, filename);
295       return  Generate_Image(width, height, format);
296     }
297
298   if (!fgets(buff, sizeof(buff), fp))
299     {
300       perror("Unable to read header filename\n");
301       return  Generate_Image(width, height, format);
302     }
303
304   if (buff[0] != '6' || buff[1] != 'P')
305     {
306       fprintf(stderr, "%s: Invalid image format (must be `6P')\n", progname);
307       return  Generate_Image(width, height, format);
308     }
309
310   do
311     {
312       fgets(buff, sizeof(buff), fp);
313     }
314   while (buff[0] == '#');
315     
316   if (sscanf(buff, "%d %d", &sizeX, &sizeY) != 2)
317     {
318       fprintf(stderr, "%s: error loading image `%s'\n", progname, filename);
319       return  Generate_Image(width, height, format);
320     }
321
322   if (fscanf(fp, "%d", &maxval) != 1)
323     {
324       fprintf(stderr, "%s: error loading image `%s'\n", progname, filename);
325       return  Generate_Image(width, height, format);
326     }
327
328   while (fgetc(fp) != '\n')
329     ;
330
331   data = (GLubyte *)malloc(4 * sizeX * sizeY);
332   if (data == NULL)
333     {
334       fprintf(stderr, "%s: unable to allocate memory\n", progname);
335           exit(1);
336     }
337
338   if (fread(data, 4 * sizeX, sizeY, fp) != sizeY)
339     {
340       fprintf(stderr, "%s: error loading image `%s'\n", progname, filename);
341       return  Generate_Image(width, height, format);
342     }
343
344   fclose(fp);
345
346   *width = sizeX;
347   *height = sizeY;
348   *format = GL_RGBA;
349   return data;
350 }
351
352 /* Load a plain PPM image */
353 GLubyte *LoadPPM(const char *filename, int *width, int *height, int *format)
354 {
355   char buff[1024];
356   GLubyte *data;
357   GLint sizeX, sizeY;
358   FILE *fp;
359   int maxval;
360
361   fp = fopen(filename, "rb");
362   if (!fp)
363     {
364       fprintf(stderr, "%s: unable to open file '%s'\n", progname, filename);
365       return  Generate_Image(width, height, format);
366       exit(1);
367     }
368   if (!fgets(buff, sizeof(buff), fp))
369     {
370       perror(filename);
371       return  Generate_Image(width, height, format);
372     }
373
374   if (buff[0] != 'P' || buff[1] != '6')
375     {
376       fprintf(stderr, "%s: invalid image format (must be `P6')\n", progname);
377       return  Generate_Image(width, height, format);
378     }
379
380   do
381     {
382       fgets(buff, sizeof(buff), fp);
383     }
384   while (buff[0] == '#');
385     
386   if (sscanf(buff, "%d %d", &sizeX, &sizeY) != 2)
387     {
388       fprintf(stderr, "%s: error loading image `%s'\n", progname, filename);
389       return  Generate_Image(width, height, format);
390     }
391
392   if (fscanf(fp, "%d", &maxval) != 1)
393     {
394       fprintf(stderr, "%s: error loading image `%s'\n", progname, filename);
395       return  Generate_Image(width, height, format);
396     }
397
398   while (fgetc(fp) != '\n')
399     ;
400
401   data = (GLubyte *)malloc(3 * sizeX * sizeY);
402   if (data == NULL)
403     {
404       fprintf(stderr, "%s: unable to allocate memory\n", progname);
405           exit(1);
406     }
407
408   if (fread(data, 3 * sizeX, sizeY, fp) != sizeY)
409     {
410       fprintf(stderr, "%s: error loading image `%s'\n", progname, filename);
411       return  Generate_Image(width, height, format);
412     }
413
414   fclose(fp);
415
416   *width = sizeX;
417   *height = sizeY;
418   *format = GL_RGB;
419   return data;
420 }
421
422 /* create a texture to be applied to the surface
423    this function loads a file using a loader depending on
424    that extension of the file. there is very little error
425    checking.  
426 */
427
428 void Create_Texture(char *filename, int do_mipmap, int do_texture_quality)
429 {
430   int height, width;
431   GLubyte *image;
432   int format;
433
434   if ( !strncmp(filename, "BUILTIN", 7))
435     image = Generate_Image(&width, &height, &format);
436   else if ( !strncmp((filename+strlen(filename)-3), "ppm", 3))
437     image = LoadPPM(filename, &width, &height, &format);
438   else if ( !strncmp((filename+strlen(filename)-4), "ppm4", 4))
439     image = LoadPPM4(filename, &width, &height, &format);
440   else {
441     fprintf(stderr, "%s: unknown file format extension: '%s'\n",
442             progname, filename);
443         exit(1);
444   }
445
446   /* GL_MODULATE or GL_DECAL depending on what you want */
447   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
448   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
449   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
450   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
451
452   /* default is to do it quick and dirty */
453   /* if you have mipmaps turned on, but not texture quality, nothing will happen! */
454   if (do_texture_quality) {
455     /* with texture_quality, the min and mag filters look *much* nice but are *much* slower */
456     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
457     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
458   } else {
459     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
460     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
461   }
462
463   if (do_mipmap) {
464     gluBuild2DMipmaps(GL_TEXTURE_2D, format, width, height, 
465                       format, GL_UNSIGNED_BYTE, image);
466   }
467   else {
468     clear_gl_error();
469     glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
470                  format, GL_UNSIGNED_BYTE, image);
471     check_gl_error("texture");
472   }
473   free(image);
474 }
475
476
477 /* mostly lifted from lament.c */
478 static void
479 rotate (float *pos, float *v, float *dv, float max_v)
480 {
481   double ppos = *pos;
482
483   /* tick position */
484   if (ppos < 0)
485     ppos = -(ppos + *v);
486   else
487     ppos += *v;
488
489   if (ppos > 360)
490     ppos -= 360;
491   else if (ppos < 0)
492     ppos += 360;
493
494   if (ppos < 0) abort();
495   if (ppos > 360) abort();
496   *pos = (*pos > 0 ? ppos : -ppos);
497
498   /* accelerate */
499   *v += *dv;
500
501   /* clamp velocity */
502   if (*v > max_v || *v < -max_v)
503     {
504       *dv = -*dv;
505     }
506   /* If it stops, start it going in the other direction. */
507   else if (*v < 0)
508     {
509       if (random() % 4)
510         {
511           *v = 0;
512
513           /* keep going in the same direction */
514           if (random() % 2)
515             *dv = 0;
516           else if (*dv < 0)
517             *dv = -*dv;
518         }
519       else
520         {
521           /* reverse gears */
522           *v = -*v;
523           *dv = -*dv;
524           *pos = -*pos;
525         }
526     }
527
528   /* Alter direction of rotational acceleration randomly. */
529   if (! (random() % 120))
530     *dv = -*dv;
531
532   /* Change acceleration very occasionally. */
533   if (! (random() % 200))
534     {
535       if (*dv == 0)
536         *dv = 0.00001;
537       else if (random() & 1)
538         *dv *= 1.2;
539       else
540         *dv *= 0.8;
541     }
542 }
543
544
545 static void
546 bounce (float *pos, float *v, float *dv, float max_v)
547 {
548   *pos += *v;
549
550   if (*pos > 1.0)
551     *pos = 1.0, *v = -*v, *dv = -*dv;
552   else if (*pos < 0)
553     *pos = 0, *v = -*v, *dv = -*dv;
554
555   if (*pos < 0.0) abort();
556   if (*pos > 1.0) abort();
557
558   /* accelerate */
559   *v += *dv;
560
561   /* clamp velocity */
562   if (*v > max_v || *v < -max_v)
563     {
564       *dv = -*dv;
565     }
566
567   /* Alter direction of rotational acceleration randomly. */
568   if (! (random() % 120))
569     *dv = -*dv;
570
571   /* Change acceleration very occasionally. */
572   if (! (random() % 200))
573     {
574       if (*dv == 0)
575         *dv = 0.00001;
576       else if (random() & 1)
577         *dv *= 1.2;
578       else
579         *dv *= 0.8;
580     }
581 }
582
583
584 static void
585 init_rotation (void)
586 {
587   rot_x = (float) (random() % (360 * 2)) - 360;  /* -360 - 360 */
588   rot_y = (float) (random() % (360 * 2)) - 360;
589   rot_z = (float) (random() % (360 * 2)) - 360;
590
591   /* bell curve from 0-1.5 degrees, avg 0.75 */
592   dx = (frand(1) + frand(1) + frand(1)) / 2.0;
593   dy = (frand(1) + frand(1) + frand(1)) / 2.0;
594   dz = (frand(1) + frand(1) + frand(1)) / 2.0;
595
596   d_max = dx * 2;
597
598   ddx = 0.004;
599   ddy = 0.004;
600   ddz = 0.004;
601
602   lastx = (random() % (int) (max_lastx - min_lastx)) + min_lastx;
603   lasty = (random() % (int) (max_lasty - min_lasty)) + min_lasty;
604   d_lastx = (frand(1) + frand(1) + frand(1));
605   d_lasty = (frand(1) + frand(1) + frand(1));
606   max_dlastx = d_lastx * 2;
607   max_dlasty = d_lasty * 2;
608   dd_lastx = 0.004;
609   dd_lasty = 0.004;
610 }
611
612
613 /* draw the screensaver once */
614 void draw_screensaver(ModeInfo * mi)
615 {
616   screensaverstruct *gp = &Screensaver[MI_SCREEN(mi)];
617   Display    *display = MI_DISPLAY(mi);
618   Window      window = MI_WINDOW(mi);
619
620   Window root, child;
621   int rootx, rooty, winx, winy;
622   unsigned int mask;
623   XEvent event;
624
625   if (!gp->glx_context)
626         return;
627
628   glXMakeCurrent(display, window, *(gp->glx_context));
629
630   funcs_ptr[screensaver_number].DrawStuff();
631           
632   rotate(&rot_x, &dx, &ddx, d_max);
633   rotate(&rot_y, &dy, &ddy, d_max);
634   rotate(&rot_z, &dz, &ddz, d_max);
635
636   /* swallow any ButtonPress events */
637   while (XCheckMaskEvent (MI_DISPLAY(mi), ButtonPressMask, &event))
638     ;
639   /* check the pointer position and button state. */
640   XQueryPointer (MI_DISPLAY(mi), MI_WINDOW(mi),
641                  &root, &child, &rootx, &rooty, &winx, &winy, &mask);
642
643   /* track the mouse only if a button is down. */
644   if (mask & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask))
645     {
646       lastx = winx;
647       lasty = winy;
648     }
649   else
650     {
651       float scale = (max_lastx - min_lastx);
652       lastx -= min_lastx;
653       lasty -= min_lasty;
654       lastx /= scale;
655       lasty /= scale;
656       d_lastx /= scale;
657       d_lasty /= scale;
658       dd_lastx /= scale;
659       dd_lasty /= scale;
660       bounce(&lastx, &d_lastx, &dd_lastx, max_dlastx);
661       bounce(&lasty, &d_lasty, &dd_lasty, max_dlasty);
662       lastx *= scale;
663       lasty *= scale;
664       lastx += min_lastx;
665       lasty += min_lasty;
666       d_lastx *= scale;
667       d_lasty *= scale;
668       dd_lastx *= scale;
669       dd_lasty *= scale;
670     }
671
672   if (mi->fps_p) do_fps (mi);
673   glXSwapBuffers(display, window);
674 }
675
676
677 /* set up lighting conditions */
678 void SetupLight(void)
679 {
680   glLightfv (GL_LIGHT0, GL_POSITION, lightOnePosition);
681   glLightfv (GL_LIGHT0, GL_DIFFUSE, lightOneColor);
682   glLightfv (GL_LIGHT1, GL_POSITION, lightTwoPosition);
683   glLightfv (GL_LIGHT1, GL_DIFFUSE, lightTwoColor);
684
685   glEnable (GL_LIGHT0);
686   glEnable (GL_LIGHT1);
687   glEnable (GL_LIGHTING);
688
689   glColorMaterial (GL_FRONT, GL_DIFFUSE);
690   glColorMaterial (GL_BACK, GL_DIFFUSE);
691   glEnable (GL_COLOR_MATERIAL);
692 }
693
694 /* reset the projection matrix */
695 void resetProjection(void) {
696   glMatrixMode(GL_PROJECTION);
697   glLoadIdentity();
698   glFrustum (-9, 9, -9, 9, 50, 150.0);
699   glMatrixMode(GL_MODELVIEW);
700   glLoadIdentity();
701 }
702
703 /* Standard reshape function */
704 void
705 reshape_screensaver(ModeInfo *mi, int width, int height)
706 {
707   global_width=width;
708   global_height=height;
709   glViewport( 0, 0, global_width, global_height );
710   resetProjection();
711 }
712
713
714 /* decide which screensaver example to run */
715 void chooseScreensaverExample(void) {
716   int i;
717   /* call the extrusion init routine */
718
719   if (!strncmp(which_name, "RANDOM", strlen(which_name))) {
720     screensaver_number = random() % num_screensavers;
721   }
722   else {
723         screensaver_number=-1;
724         for (i=0; i < num_screensavers; i++) {
725           if (!strncmp(which_name, funcs_ptr[i].name, strlen(which_name))) {
726                 screensaver_number = i;
727           }
728         }         
729   }
730         
731   if (screensaver_number < 0 || screensaver_number >= num_screensavers) {
732         fprintf(stderr, "%s: invalid screensaver example number!\n", progname);
733         fprintf(stderr, "%s: known screensavers:\n", progname);
734         for (i=0; i < num_screensavers; i++)
735           fprintf(stderr,"\t%s\n", funcs_ptr[i].name);
736         exit(1);
737   }
738   init_rotation();
739   funcs_ptr[screensaver_number].InitStuff();
740 }
741
742 /* main OpenGL initialization routine */
743 void
744 initializeGL(ModeInfo *mi, GLsizei width, GLsizei height) 
745 {
746   int style;
747   int mode;
748
749   reshape_screensaver(mi, width, height);
750   glViewport( 0, 0, width, height ); 
751
752   glEnable(GL_DEPTH_TEST);
753   glClearColor(0,0,0,0);
754 /*    glCullFace(GL_BACK); */
755 /*    glEnable(GL_CULL_FACE); */
756   glShadeModel(GL_SMOOTH);
757
758   if (do_light)
759         SetupLight();
760   if (do_wire) {
761         glPolygonMode(GL_FRONT,GL_LINE);
762         glPolygonMode(GL_BACK,GL_LINE);
763   }
764   if (do_texture) {
765         Create_Texture(which_image, do_mipmap, do_texture_quality);
766         glEnable(GL_TEXTURE_2D);
767
768         /* configure the pipeline */
769         style = TUBE_JN_CAP;
770         style |= TUBE_CONTOUR_CLOSED;
771         style |= TUBE_NORM_FACET;
772         style |= TUBE_JN_ANGLE;
773         gleSetJoinStyle (style);
774
775         if (do_texture) {
776           mode = GLE_TEXTURE_ENABLE | GLE_TEXTURE_VERTEX_MODEL_FLAT;
777           glMatrixMode (GL_TEXTURE); glLoadIdentity ();
778           glScalef (0.25, 0.1, 1); glMatrixMode (GL_MODELVIEW);
779           gleTextureMode (mode);
780         }
781   }
782
783 }
784
785 /* xscreensaver initialization routine */
786 void init_screensaver(ModeInfo * mi)
787 {
788   int screen = MI_SCREEN(mi);
789   screensaverstruct *gp;
790
791   if (Screensaver == NULL) {
792         if ((Screensaver = (screensaverstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (screensaverstruct))) == NULL)
793           return;
794   }
795   gp = &Screensaver[screen];
796
797   gp->window = MI_WINDOW(mi);
798   if ((gp->glx_context = init_GL(mi)) != NULL) {
799         reshape_screensaver(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
800         initializeGL(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
801         chooseScreensaverExample();
802   } else {
803         MI_CLEARWINDOW(mi);
804   }
805
806 }
807
808 /* all sorts of nice cleanup code should go here! */
809 void release_screensaver(ModeInfo * mi)
810 {
811   int screen;
812   if (Screensaver != NULL) {
813         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
814           /*      screensaverstruct *gp = &Screensaver[screen];*/
815         }
816         (void) free((void *) Screensaver);
817         Screensaver = NULL;
818   }
819   FreeAllGL(mi);
820 }
821 #endif
822