http://www.jwz.org/xscreensaver/xscreensaver-5.13.tar.gz
[xscreensaver] / hacks / glx / providence.c
1 /*
2  * Permission to use, copy, modify, and distribute this software and its
3  * documentation for any purpose and without fee is hereby granted,
4  * provided that the above copyright notice appear in all copies and that
5  * both that copyright notice and this permission notice appear in
6  * supporting documentation.
7  *
8  * This file is provided AS IS with no warranties of any kind.  The author
9  * shall have no liability with respect to the infringement of copyrights,
10  * trade secrets or any patents by this file or any part thereof.  In no
11  * event will the author be liable for any lost revenue or profits or
12  * other special, indirect and consequential damages.
13  *
14  * Copyright 2004 Blair Tennessy
15  */
16
17 #ifdef STANDALONE
18 #define DEFAULTS            "*delay:   20000   \n" \
19                             "*showFPS: False   \n" \
20                             "*wireframe: False \n"
21
22 # define refresh_providence 0
23 #include "xlockmore.h"
24 #else
25 #include "xlock.h"
26 #endif
27
28 #include "gltrackball.h"
29
30 #define DEF_SOLIDPROVIDENCE  "False"
31 #define DEF_EYE  "True"
32
33 static int eye;
34
35 static XrmOptionDescRec opts[] = {
36   {"-eye", ".providence.eye", XrmoptionNoArg, "on"},
37   {"+eye", ".providence.eye", XrmoptionNoArg, "off"}
38 };
39
40 static argtype vars[] = {
41   {&eye, "eye", "Eye", DEF_EYE, t_Bool}
42 };
43
44 static OptionStruct desc[] = {
45   {"-/+eye", "turn on/off eye of providence"}
46 };
47
48 ENTRYPOINT ModeSpecOpt providence_opts = {
49   sizeof opts / sizeof opts[0], opts, 
50   sizeof vars / sizeof vars[0], vars, desc
51 };
52
53 #ifdef USE_MODULES
54 ModStruct   providence_description = {
55   "providence", "init_providence", "draw_providence", 
56   "release_providence", "draw_providence", "change_providence", 
57   (char *) NULL, &providence_opts, 1000, 1, 1, 1, 4, 1.0, "",
58   "draws pyramid with glory", 0, NULL
59 };
60 #endif
61
62 #define Scale4Window               0.3
63 #define Scale4Iconic               0.4
64
65 #define sqr(A)                     ((A)*(A))
66
67 #ifndef Pi
68 #define Pi M_PI
69 #endif
70
71 /* brick texture */
72 #define checkImageWidth 64
73 #define checkImageHeight 64
74
75 #define EYE_PARTICLE_COUNT 2000
76
77 #define LOOKUPSIZE 3600
78 #define EYELENGTH 300
79
80 #define EPSILON 0.0001
81 #define PARTICLE_COUNT 2000
82 #define FPS 50
83
84
85 typedef struct {
86   GLint       WindH, WindW;
87   GLXContext *glx_context;
88   trackball_state *trackball;
89   Bool        button_down_p;
90   GLfloat position0[4];
91   GLubyte checkImage[checkImageWidth][checkImageHeight][3];
92   GLuint bricktexture;
93
94   int mono, wire;
95   double camera_velocity;
96   double camera_z;
97
98   int pyramidlist;
99   double currenttime;
100   double theta;
101   double theta_scale;
102
103   double particles[PARTICLE_COUNT][5];
104   int eyeparticles[EYE_PARTICLE_COUNT][2];
105   double lookup[LOOKUPSIZE][EYELENGTH][2];
106   double lookup2[LOOKUPSIZE][EYELENGTH][2];
107
108 } providencestruct;
109
110 /* lighting variables */
111 /*static const GLfloat front_shininess[] = {60.0};*/
112 /*static const GLfloat front_specular[] = {0.2, 0.2, 0.2, 1.0};*/
113 /*static const GLfloat ambient[] = {0.8, 0.8, 0.8, 1.0};*/
114 static const GLfloat ambient2[] = {0.25, 0.25, 0.25, 1.0};
115 static const GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0};
116 static const GLfloat lmodel_ambient[] = {0.5, 0.5, 0.5, 1.0};
117 static const GLfloat lmodel_twoside[] = {GL_TRUE};
118
119 /* gray-gray */
120
121 static const GLfloat MaterialGlory[] = {0.04, 0.30, 0.22, 0.7};
122 static const GLfloat MaterialGloryB[] = {0.07, 0.50, 0.36, 0.6};
123
124 static const GLfloat MaterialGloryF[] = {0.07, 0.50, 0.36, 1.0};
125 /* static const GLfloat MaterialGloryF[] = {0.06, 0.38, 0.27, 1.0}; */
126 /*static const GLfloat MaterialGloryE[] = {0.06, 0.38, 0.27, 0.3};*/
127 static const GLfloat MaterialGloryM[] = {0.5, 0.5, 0.5, 0.5};
128 static const GLfloat MaterialGloryMB[] = {0.36, 0.36, 0.36, 0.4};
129 /*static const GLfloat MaterialGreenback[4] = {0.04, 0.30, 0.22, 1.0};*/
130 /*static const GLfloat MaterialBlack[4] = {0.0, 0.0, 0.0, 1.0};*/
131
132 static const GLfloat MaterialGray5[] = {0.5, 0.5, 0.5, 1.0};
133 /*static const GLfloat MaterialGray6[] = {0.6, 0.6, 0.6, 1.0};*/
134
135 static providencestruct *providence = (providencestruct *) NULL;
136
137 #define NUM_SCENES      2
138
139 /* build brick texture */
140 static void make_brick(providencestruct *mp) 
141 {
142   int i, j, c;
143
144   for (i = 0; i < checkImageWidth; i++) {
145     for (j = 0; j < checkImageHeight; j++) {
146       c = i % 16 == 15 ? 255 : (j + 48*(i / 16))%64 == 0 ? 255 : 
147         102 + random() % 102;
148       mp->checkImage[i][j][0] = (GLubyte) c;
149       mp->checkImage[i][j][1] = (GLubyte) c;
150       mp->checkImage[i][j][2] = (GLubyte) c;
151     }
152   }
153
154   glGenTextures(1, &mp->bricktexture);
155   glBindTexture(GL_TEXTURE_2D, mp->bricktexture);
156
157   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
158   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
159   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
160   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
161   glTexImage2D(GL_TEXTURE_2D, 0, 3, checkImageWidth, 
162                checkImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 
163                &mp->checkImage[0][0]);
164   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
165 }
166
167
168 /* build eye lookup table */
169 static void build_eye(providencestruct *mp) 
170 {
171   int i, j;
172   double x;
173   double inc = 0.1 / EYELENGTH;
174   double inc2 = 2.4*Pi / EYELENGTH;
175
176   /* describe all values tangentially out from pupil */
177   for(i = 0; i < LOOKUPSIZE; ++i) {
178     double r = i * 2*Pi / LOOKUPSIZE;/*x + inc;*/
179     double sr = sin(r);
180     double cr = cos(r);
181     x = 0.07;
182
183     for(j = 0; j < EYELENGTH; ++j) {
184       mp->lookup[i][j][0] = x*sr;
185       mp->lookup[i][j][1] = x*cr;
186       x += inc;
187     }
188   }
189
190   /* lookup2: dollar sign */
191   for(i = 0; i < LOOKUPSIZE; ++i) {
192     double y = -1.2*Pi;
193     
194     for(j = 0; j < EYELENGTH; ++j) {
195       if(i % 2) {
196         mp->lookup2[i][j][0] = sin(y)/6.0 + i/36000.0 - 0.05;
197         mp->lookup2[i][j][1] = i%4 ? y/12.0 - 0.05 : 1.2*Pi-y/12.0 + 0.05;
198       }
199       else {
200         mp->lookup2[i][j][0] = i/36000.0 - 0.05;
201         mp->lookup2[i][j][1] = y/9.0 - 0.05;
202       }
203       y += inc2;
204     }
205   }
206 }
207
208
209 static double min(double a, double b) 
210 {
211   return a < b ? a : b;
212 }
213
214 static double max(double a, double b) 
215 {
216   return a > b ? a : b;
217 }
218
219 static void init_particle(providencestruct *mp, double particle[5]) 
220 {
221   /* position along glory */
222   double p = (random() % 485410) / 100000.0;
223
224   /* on a plane */
225   particle[2] = 0.0;
226   
227   if(p < 1.5) {
228     particle[0] = p - 0.75;
229     particle[1] = -0.75001;
230   }
231   else if(p < 1.5 + sqrt(45)/4.0) {
232     double d = p - 1.5;
233     particle[0] = 0.75 - d*cos(atan(2.0));
234     particle[1] = d*sin(atan(2.0)) - 0.75;
235   }
236   else {
237     double d = 4.8541 - p;
238     particle[0] = -0.75 + d*cos(atan(2.0));
239     particle[1] = d*sin(atan(2.0)) - 0.75;
240   }
241
242   particle[3] = mp->currenttime;
243   particle[4] = 1.25 + (random()%10)/10.0;
244 }
245
246 /* init glory particles */
247 static void init_particles(providencestruct *mp) 
248 {
249   int i;
250   for(i = 0; i < PARTICLE_COUNT; ++i) {
251     init_particle(mp, mp->particles[i]);
252
253     /* set initial time */
254     mp->particles[i][3] = mp->currenttime - (random()%1250)/1000.0;
255   }
256
257   /* init eye particles */
258   for(i = 0; i < EYE_PARTICLE_COUNT; ++i) {
259     mp->eyeparticles[i][0] = random()%LOOKUPSIZE;
260     mp->eyeparticles[i][1] = random()%EYELENGTH;
261   }
262 }
263
264
265 /* ugg, should be a priority queue if next event times known */
266 static void update_particles(providencestruct *mp) 
267 {
268   int i;
269
270   for(i = 0; i < PARTICLE_COUNT; ++i) {
271     /* check for time elapse */
272     if(mp->currenttime > mp->particles[i][3] + mp->particles[i][4])
273       init_particle(mp, mp->particles[i]);
274   }
275
276   /* now update eye particles */
277   for(i = 0; i < EYE_PARTICLE_COUNT; ++i) {
278 /*     int x = eyeparticles[i][1] + random()%16; */
279     int x = mp->eyeparticles[i][1] + random()%(cos(mp->theta) < 0.0 ? 8 : 16);
280
281     /* reset if dead */
282     if(x > EYELENGTH || random()%(cos(mp->theta) < 0.0 ? 40 : 10) == 0) {
283
284 /*     if(x > EYELENGTH || (x > EYELENGTH/(2/3.0) && random()%7 == 0)) { */
285       mp->eyeparticles[i][0] = random()%LOOKUPSIZE;
286       mp->eyeparticles[i][1] = random()%40;
287     }
288     else {
289       mp->eyeparticles[i][1] = x;
290     }    
291   }
292 }
293
294 /* draw the pyramid */
295 static void draw_seal(providencestruct *mp) 
296 {
297   int i;
298   double base = sqrt(2.0);
299   double top = 1.0 / sqrt(2.0);
300   double tmod = 7.0/6.0;
301
302   glPushMatrix();
303
304   /* set options for mono, wireframe */
305   if(mp->wire) {
306     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
307     glDisable(GL_LIGHTING);
308     glDisable(GL_TEXTURE_2D);
309   }
310   else {
311     glEnable(GL_TEXTURE_2D);
312     glBindTexture(GL_TEXTURE_2D, mp->bricktexture);
313
314     glEnable(GL_LIGHTING);
315
316     glColor4fv(mp->mono ? MaterialGray5 : MaterialGloryF);
317     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
318                  mp->mono ? MaterialGray5 : MaterialGloryF);
319   }
320
321   glRotatef(45.0, 0.0, 1.0, 0.0);
322   glTranslatef(0.0, -3.25, 0.0);
323
324   for(i = 0; i < 4; ++i) {
325     glRotatef(i*90.0, 0.0, 1.0, 0.0);
326
327     glBegin(GL_QUADS);
328     glNormal3f(1 / sqrt(6.0), 2 / sqrt(6.0), 1 / sqrt(6.0));
329     glTexCoord2f(-base, 0.0);
330     glVertex3f(-base, 0.0, base);
331     glTexCoord2f(base, 0.0);
332     glVertex3f(base, 0.0, base);
333     glTexCoord2f(top, 13.0/4.0);
334     glVertex3f(top, 2.0, top);
335     glTexCoord2f(-top, 13.0/4.0);
336     glVertex3f(-top, 2.0, top);
337     glEnd();
338   }
339
340   glBegin(GL_QUADS);
341
342   /* top */
343   glNormal3f(0.0, 1.0, 0.0);
344   glTexCoord2f(0.02, 0.0);
345   glVertex3f(-top, 2.0, top);
346   glTexCoord2f(2.0*top, 0.0);
347   glVertex3f(top, 2.0, top);
348   glTexCoord2f(2.0*top, tmod*2.1*top);
349   glVertex3f(top, 2.0, -top);
350   glTexCoord2f(0.02, tmod*2.1*top);
351   glVertex3f(-top, 2.0, -top);
352
353   /* base */
354   glNormal3f(0.0, -1.0, 0.0);
355   glTexCoord2f(-base, 0.0);
356   glVertex3f(-base, 0.0, -base);
357   glTexCoord2f(top, 0.0);
358   glVertex3f(base, 0.0, -base);
359   glTexCoord2f(top, top*13.0/4.0);
360   glVertex3f(base, 0.0, base);
361   glTexCoord2f(-top, top*13.0/4.0);
362   glVertex3f(-base, 0.0, base);
363
364   glEnd();
365
366   glPopMatrix();
367   glDisable(GL_TEXTURE_2D);
368 }
369
370 /* draw glory */
371 static void draw_glory(providencestruct *mp) 
372 {
373   int i;
374
375   if(mp->wire) {
376     glBegin(GL_TRIANGLES);
377     glVertex3f(-0.75, -0.75, 0.0);
378     glVertex3f(0.75, -0.75, 0.0);
379     glVertex3f(0.0, 0.75, 0.0);
380
381     glVertex3f(0.0, 0.75, 0.0);
382     glVertex3f(0.75, -0.75, 0.0);
383     glVertex3f(-0.75, -0.75, 0.0);
384     glEnd();
385     return;
386   }
387
388   /* draw particles */
389   glDisable(GL_LIGHTING);
390   glPushMatrix();
391   glEnable(GL_BLEND);
392
393   /* glory colour lines */
394   glColor4fv(mp->mono ? MaterialGloryM : MaterialGlory);
395   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
396                mp->mono ? MaterialGloryM : MaterialGlory);
397
398   glBegin(GL_LINES);
399   for(i = 0; i < PARTICLE_COUNT/2; ++i) {
400     double t = mp->currenttime - mp->particles[i][3];
401     double th = atan(mp->particles[i][1] / mp->particles[i][0]);
402     if(mp->particles[i][0] < 0.0)
403       th += Pi;
404
405     glVertex3f(mp->particles[i][0], mp->particles[i][1], mp->particles[i][2]);
406     glVertex3f(mp->particles[i][0] + 0.2*cos(th)*t,
407                mp->particles[i][1] + 0.2*sin(th)*t,
408                mp->particles[i][2]);
409   }
410   glEnd();
411   
412   /* gloryb colour lines */
413   glColor4fv(mp->mono ? MaterialGloryMB : MaterialGloryB);
414   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
415                mp->mono ? MaterialGloryMB : MaterialGloryB);
416   glBegin(GL_LINES);
417   for(; i < PARTICLE_COUNT; ++i) {
418     double t = mp->currenttime - mp->particles[i][3];
419     double th = atan(mp->particles[i][1] / mp->particles[i][0]);
420     if(mp->particles[i][0] < 0.0)
421       th += Pi;
422
423     glVertex3f(mp->particles[i][0], mp->particles[i][1], mp->particles[i][2]);
424     glVertex3f(mp->particles[i][0] + 0.2*cos(th)*t,
425                mp->particles[i][1] + 0.2*sin(th)*t,
426                mp->particles[i][2]);
427   }
428   glEnd();
429
430   glPopMatrix();
431   glEnable(GL_LIGHTING);
432 }
433
434 /* draw eye of providence */
435 static void draw_eye(providencestruct *mp) 
436 {
437   int i;
438
439   /* draw wireeye */
440   if(mp->wire) {
441     glBegin(GL_TRIANGLES);
442     glVertex3f(-0.25, -0.25, 0.0);
443     glVertex3f(0.25, -0.25, 0.0);
444     glVertex3f(0.0, 0.25, 0.0);
445     glEnd();
446     return;
447   }
448
449   /* draw particles */
450   glDisable(GL_LIGHTING);
451   glPushMatrix();
452   glEnable(GL_BLEND);
453
454   /* eye */
455   glColor4fv(mp->mono ? MaterialGloryM : MaterialGlory);
456   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
457                mp->mono ? MaterialGloryM : MaterialGlory);
458
459   /* draw eye particles on z = 0 plane */
460   glBegin(GL_POINTS);
461   for(i = 0; i < EYE_PARTICLE_COUNT/2; ++i) {
462     glVertex3f(mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
463                mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
464                0.0);
465   }
466   glEnd();
467
468   /* eye */
469   glColor4fv(mp->mono ? MaterialGloryMB : MaterialGloryB);
470   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
471                mp->mono ? MaterialGloryMB : MaterialGloryB);
472
473   /* draw eye particles on z = 0 plane */
474   glBegin(GL_POINTS);
475   for(; i < EYE_PARTICLE_COUNT; ++i) {
476     glVertex3f(mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
477                mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
478                0.0);
479   }
480   glEnd();
481
482
483   /* draw scaled particles */
484   glPushMatrix();
485   glScalef(3.3, 2.2, 3.3);
486
487   /* eye */
488   glColor4fv(mp->mono ? MaterialGloryMB : MaterialGloryB);
489   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
490                mp->mono ? MaterialGloryMB : MaterialGloryB);
491
492   /* draw eye particles on z = 0 plane */
493   glBegin(GL_POINTS);
494   for(i = 0; i < EYE_PARTICLE_COUNT/2; ++i) {
495     glVertex3f(mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
496                mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
497                0.0);
498   }
499   glEnd();
500
501   glColor4fv(mp->mono ? MaterialGloryM : MaterialGlory);
502   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
503                mp->mono ? MaterialGloryM : MaterialGlory);
504
505   /* draw eye particles on z = 0 plane */
506   glBegin(GL_POINTS);
507   for(; i < EYE_PARTICLE_COUNT; ++i) {
508     glVertex3f(mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
509                mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
510                0.0);
511   }
512   glEnd();
513
514   glPopMatrix();
515
516   glPopMatrix();
517   glEnable(GL_LIGHTING);
518 }
519
520 /* draw eye of providence */
521 static void draw_eye2(providencestruct *mp) 
522 {
523   int i;
524
525   /* draw wireeye */
526   if(mp->wire) {
527     glBegin(GL_TRIANGLES);
528     glVertex3f(0.0, 0.25, 0.0);
529     glVertex3f(0.25, -0.25, 0.0);
530     glVertex3f(-0.25, -0.25, 0.0);
531     glEnd();
532     return;
533   }
534
535   /* draw particles */
536   glDisable(GL_LIGHTING);
537   glPushMatrix();
538   glEnable(GL_BLEND);
539
540   /* eye */
541   glColor4fv(mp->mono ? MaterialGloryM : MaterialGlory);
542   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
543                mp->mono ? MaterialGloryM : MaterialGlory);
544
545   /* draw eye particles on z = 0 plane */
546   glBegin(GL_POINTS);
547   for(i = 0; i < EYE_PARTICLE_COUNT/2; ++i) {
548     glVertex3f(mp->lookup2[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
549                mp->lookup2[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
550                0.0);
551   }
552   glEnd();
553
554   /* eye */
555   glColor4fv(mp->mono ? MaterialGloryMB : MaterialGloryB);
556   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
557                mp->mono ? MaterialGloryMB : MaterialGloryB);
558
559   /* draw eye particles on z = 0 plane */
560   glBegin(GL_POINTS);
561   for(; i < EYE_PARTICLE_COUNT; ++i) {
562     glVertex3f(mp->lookup2[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
563                mp->lookup2[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
564                0.0);
565   }
566   glEnd();
567
568   glPopMatrix();
569   glEnable(GL_LIGHTING);
570 }
571
572 /* draw the scene */
573 static void draw_providence_strip(ModeInfo *mi) 
574 {
575   providencestruct *mp = &providence[MI_SCREEN(mi)];
576   glTranslatef(0.0, 1.414, 0.0);
577
578   mp->position0[0] = 1.6*sin(mp->theta);
579   mp->position0[1] = 1.2;
580   mp->position0[2] = 1.6*cos(mp->theta);
581   mp->position0[3] = 0.0;
582   glLightfv(GL_LIGHT0, GL_POSITION, mp->position0);
583   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient2);
584   glEnable(GL_LIGHTING);
585   glEnable(GL_LIGHT0);
586
587   /* draw pyramid, glory */
588   glDisable(GL_BLEND);
589   glCallList(mp->pyramidlist);
590   draw_glory(mp);
591   if(eye) {
592     if(cos(mp->theta) < 0.0)
593       draw_eye2(mp);
594     else
595       draw_eye(mp);
596   }
597
598   return;
599 }
600
601 ENTRYPOINT void reshape_providence(ModeInfo * mi, int width, int height) 
602 {
603   double h = (GLfloat) height / (GLfloat) width;  
604   providencestruct *mp = &providence[MI_SCREEN(mi)];
605
606   glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
607   glMatrixMode(GL_PROJECTION);
608   glLoadIdentity();
609
610   gluPerspective(45, 1/h, 0.001, 25.0);
611
612   glMatrixMode(GL_MODELVIEW);
613   glLineWidth(2.0);
614   glPointSize(2.0);
615 }
616
617 static void pinit(providencestruct *mp) 
618 {
619   glClearDepth(1.0);
620
621   /* setup twoside lighting */
622   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient2);
623   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
624   glLightfv(GL_LIGHT0, GL_POSITION, mp->position0);
625
626   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
627   glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
628   glEnable(GL_LIGHTING);
629   glEnable(GL_LIGHT0);
630
631   mp->currenttime = 0.0;
632   init_particles(mp);
633   make_brick(mp);
634   build_eye(mp);
635
636   glEnable(GL_NORMALIZE);
637   glFrontFace(GL_CCW);
638 /*   glDisable(GL_CULL_FACE); */
639   glEnable(GL_CULL_FACE);
640   glCullFace(GL_BACK);
641   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
642
643   glShadeModel(GL_SMOOTH);
644   glEnable(GL_DEPTH_TEST);
645   glDepthFunc(GL_LEQUAL);
646
647   /* build pyramid list */
648   mp->pyramidlist = glGenLists(1);
649   glNewList(mp->pyramidlist, GL_COMPILE);
650   draw_seal(mp);
651   glEndList();
652 }
653
654 /* cleanup routine */
655 ENTRYPOINT void release_providence(ModeInfo * mi) 
656 {
657
658   if(providence) {
659     free((void *) providence);
660     providence = (providencestruct *) NULL;
661   }
662
663   FreeAllGL(mi);
664 }
665
666 /* event handling */
667 ENTRYPOINT Bool providence_handle_event(ModeInfo *mi, XEvent *event) 
668 {
669   providencestruct *mp = &providence[MI_SCREEN(mi)];
670
671   switch(event->xany.type) {
672   case ButtonPress:
673
674     switch(event->xbutton.button) {
675
676     case Button1:
677       mp->button_down_p = True;
678       gltrackball_start(mp->trackball, 
679                         event->xbutton.x, event->xbutton.y,
680                         MI_WIDTH (mi), MI_HEIGHT (mi));
681       break;
682       
683     case Button4:
684       mp->camera_velocity += 1.0;
685       break;
686
687     case Button5:
688       mp->camera_velocity -= 1.0;
689       break;
690     }
691
692     break;
693     
694   case ButtonRelease:
695
696     switch(event->xbutton.button) {
697     case Button1:
698       mp->button_down_p = False;
699       break;
700     }
701
702     break;
703
704   case MotionNotify:
705     if(mp->button_down_p)
706       gltrackball_track(mp->trackball,
707                         event->xmotion.x, event->xmotion.y,
708                         MI_WIDTH (mi), MI_HEIGHT (mi));
709     break;
710     
711   default:
712     return False;
713   }
714
715   return True;
716 }
717
718 ENTRYPOINT void init_providence(ModeInfo *mi) 
719 {
720   providencestruct *mp;
721   
722   if(!providence) {
723     if((providence = (providencestruct *) 
724         calloc(MI_NUM_SCREENS(mi), sizeof (providencestruct))) == NULL)
725       return;
726   }
727   mp = &providence[MI_SCREEN(mi)];
728   mp->trackball = gltrackball_init ();
729
730   mp->position0[0] = 1;
731   mp->position0[1] = 5;
732   mp->position0[2] = 1;
733   mp->position0[3] = 1;
734
735   mp->camera_velocity = -8.0;
736
737   mp->mono = MI_IS_MONO(mi);
738   mp->wire = MI_IS_WIREFRAME(mi);
739
740   /* make multiple screens rotate at slightly different rates. */
741   mp->theta_scale = 0.7 + frand(0.6);
742
743   if((mp->glx_context = init_GL(mi)) != NULL) {
744     reshape_providence(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
745     glDrawBuffer(GL_BACK);
746     pinit(mp);
747   }
748   else
749     MI_CLEARWINDOW(mi);
750 }
751
752 ENTRYPOINT void draw_providence(ModeInfo * mi) 
753 {
754   providencestruct *mp;
755   
756   Display    *display = MI_DISPLAY(mi);
757   Window      window = MI_WINDOW(mi);
758   
759   if(!providence)
760     return;
761   mp = &providence[MI_SCREEN(mi)];
762   
763   MI_IS_DRAWN(mi) = True;
764   
765   if(!mp->glx_context)
766     return;
767   
768   glXMakeCurrent(display, window, *(mp->glx_context));
769   
770   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
771
772   glPushMatrix();
773
774   /* modify camera */
775   if(fabs(mp->camera_velocity) > EPSILON) {
776     mp->camera_z = max(min(mp->camera_z + 0.1*mp->camera_velocity, -4.0), -12.0);
777     mp->camera_velocity = 0.95*mp->camera_velocity;
778   }
779   
780   /* rotate providence */
781   glTranslatef(0.0, 0.0, mp->camera_z + sin(mp->theta/4.0));
782   glRotatef(10.0+20.0*sin(mp->theta/2.0), 1.0, 0.0, 0.0);
783   gltrackball_rotate(mp->trackball);
784   glRotatef(mp->theta * 180.0 / Pi, 0.0, -1.0, 0.0);
785
786   /* draw providence */
787   draw_providence_strip(mi);
788   glPopMatrix();
789   
790   if(MI_IS_FPS(mi)) do_fps (mi);
791   glFlush();
792   
793   glXSwapBuffers(display, window);
794
795   /* update */
796   mp->currenttime += 1.0 / FPS;
797   mp->theta = mp->currenttime / 2.0 * mp->theta_scale;
798   update_particles(mp);
799 }
800
801 #ifndef STANDALONE
802 ENTRYPOINT void change_providence(ModeInfo * mi) 
803 {
804   providencestruct *mp = &providence[MI_SCREEN(mi)];
805   
806   if (!mp->glx_context)
807         return;
808   
809   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
810   pinit();
811 }
812 #endif /* !STANDALONE */
813
814 XSCREENSAVER_MODULE ("Providence", providence)