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