From http://www.jwz.org/xscreensaver/xscreensaver-5.35.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/5)  /* 3600 was way too much RAM on iOS */
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   glTexImage2D(GL_TEXTURE_2D, 0, 3, checkImageWidth, 
158                checkImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 
159                &mp->checkImage[0][0]);
160 }
161
162
163 /* build eye lookup table */
164 static void build_eye(providencestruct *mp) 
165 {
166   int i, j;
167   double x;
168   double inc = 0.1 / EYELENGTH;
169   double inc2 = 2.4*Pi / EYELENGTH;
170
171   /* describe all values tangentially out from pupil */
172   for(i = 0; i < LOOKUPSIZE; ++i) {
173     double r = i * 2*Pi / LOOKUPSIZE;/*x + inc;*/
174     double sr = sin(r);
175     double cr = cos(r);
176     x = 0.07;
177
178     for(j = 0; j < EYELENGTH; ++j) {
179       mp->lookup[i][j][0] = x*sr;
180       mp->lookup[i][j][1] = x*cr;
181       x += inc;
182     }
183   }
184
185   /* lookup2: dollar sign */
186   for(i = 0; i < LOOKUPSIZE; ++i) {
187     double y = -1.2*Pi;
188     
189     for(j = 0; j < EYELENGTH; ++j) {
190       if(i % 2) {
191         mp->lookup2[i][j][0] = sin(y)/6.0 + i/36000.0 - 0.05;
192         mp->lookup2[i][j][1] = i%4 ? y/12.0 - 0.05 : 1.2*Pi-y/12.0 + 0.05;
193       }
194       else {
195         mp->lookup2[i][j][0] = i/36000.0 - 0.05;
196         mp->lookup2[i][j][1] = y/9.0 - 0.05;
197       }
198       y += inc2;
199     }
200   }
201 }
202
203
204 static double min(double a, double b) 
205 {
206   return a < b ? a : b;
207 }
208
209 static double max(double a, double b) 
210 {
211   return a > b ? a : b;
212 }
213
214 static void init_particle(providencestruct *mp, double particle[5]) 
215 {
216   /* position along glory */
217   double p = (random() % 485410) / 100000.0;
218
219   /* on a plane */
220   particle[2] = 0.0;
221   
222   if(p < 1.5) {
223     particle[0] = p - 0.75;
224     particle[1] = -0.75001;
225   }
226   else if(p < 1.5 + sqrt(45)/4.0) {
227     double d = p - 1.5;
228     particle[0] = 0.75 - d*cos(atan(2.0));
229     particle[1] = d*sin(atan(2.0)) - 0.75;
230   }
231   else {
232     double d = 4.8541 - p;
233     particle[0] = -0.75 + d*cos(atan(2.0));
234     particle[1] = d*sin(atan(2.0)) - 0.75;
235   }
236
237   particle[3] = mp->currenttime;
238   particle[4] = 1.25 + (random()%10)/10.0;
239 }
240
241 /* init glory particles */
242 static void init_particles(providencestruct *mp) 
243 {
244   int i;
245   for(i = 0; i < PARTICLE_COUNT; ++i) {
246     init_particle(mp, mp->particles[i]);
247
248     /* set initial time */
249     mp->particles[i][3] = mp->currenttime - (random()%1250)/1000.0;
250   }
251
252   /* init eye particles */
253   for(i = 0; i < EYE_PARTICLE_COUNT; ++i) {
254     mp->eyeparticles[i][0] = random()%LOOKUPSIZE;
255     mp->eyeparticles[i][1] = random()%EYELENGTH;
256   }
257 }
258
259
260 /* ugg, should be a priority queue if next event times known */
261 static void update_particles(providencestruct *mp) 
262 {
263   int i;
264
265   for(i = 0; i < PARTICLE_COUNT; ++i) {
266     /* check for time elapse */
267     if(mp->currenttime > mp->particles[i][3] + mp->particles[i][4])
268       init_particle(mp, mp->particles[i]);
269   }
270
271   /* now update eye particles */
272   for(i = 0; i < EYE_PARTICLE_COUNT; ++i) {
273 /*     int x = eyeparticles[i][1] + random()%16; */
274     int x = mp->eyeparticles[i][1] + random()%(cos(mp->theta) < 0.0 ? 8 : 16);
275
276     /* reset if dead */
277     if(x >= EYELENGTH || random()%(cos(mp->theta) < 0.0 ? 40 : 10) == 0) {
278
279 /*     if(x > EYELENGTH || (x > EYELENGTH/(2/3.0) && random()%7 == 0)) { */
280       mp->eyeparticles[i][0] = random()%LOOKUPSIZE;
281       mp->eyeparticles[i][1] = random()%40;
282     }
283     else {
284       mp->eyeparticles[i][1] = x;
285     }    
286   }
287 }
288
289 /* draw the pyramid */
290 static void draw_seal(providencestruct *mp) 
291 {
292   int i;
293   double base = sqrt(2.0);
294   double top = 1.0 / sqrt(2.0);
295   double tmod = 7.0/6.0;
296
297   glPushMatrix();
298
299   /* set options for mono, wireframe */
300   if(mp->wire) {
301     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
302     glDisable(GL_LIGHTING);
303     glDisable(GL_TEXTURE_2D);
304   }
305   else {
306     glEnable(GL_TEXTURE_2D);
307     glBindTexture(GL_TEXTURE_2D, mp->bricktexture);
308
309     glEnable(GL_LIGHTING);
310
311     glColor4fv(mp->mono ? MaterialGray5 : MaterialGloryF);
312     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
313                  mp->mono ? MaterialGray5 : MaterialGloryF);
314   }
315
316   glRotatef(45.0, 0.0, 1.0, 0.0);
317   glTranslatef(0.0, -3.25, 0.0);
318
319   for(i = 0; i < 4; ++i) {
320     glRotatef(i*90.0, 0.0, 1.0, 0.0);
321
322     glBegin(GL_QUADS);
323     glNormal3f(1 / sqrt(6.0), 2 / sqrt(6.0), 1 / sqrt(6.0));
324     glTexCoord2f(-base, 0.0);
325     glVertex3f(-base, 0.0, base);
326     glTexCoord2f(base, 0.0);
327     glVertex3f(base, 0.0, base);
328     glTexCoord2f(top, 13.0/4.0);
329     glVertex3f(top, 2.0, top);
330     glTexCoord2f(-top, 13.0/4.0);
331     glVertex3f(-top, 2.0, top);
332     glEnd();
333   }
334
335   glBegin(GL_QUADS);
336
337   /* top */
338   glNormal3f(0.0, 1.0, 0.0);
339   glTexCoord2f(0.02, 0.0);
340   glVertex3f(-top, 2.0, top);
341   glTexCoord2f(2.0*top, 0.0);
342   glVertex3f(top, 2.0, top);
343   glTexCoord2f(2.0*top, tmod*2.1*top);
344   glVertex3f(top, 2.0, -top);
345   glTexCoord2f(0.02, tmod*2.1*top);
346   glVertex3f(-top, 2.0, -top);
347
348   /* base */
349   glNormal3f(0.0, -1.0, 0.0);
350   glTexCoord2f(-base, 0.0);
351   glVertex3f(-base, 0.0, -base);
352   glTexCoord2f(top, 0.0);
353   glVertex3f(base, 0.0, -base);
354   glTexCoord2f(top, top*13.0/4.0);
355   glVertex3f(base, 0.0, base);
356   glTexCoord2f(-top, top*13.0/4.0);
357   glVertex3f(-base, 0.0, base);
358
359   glEnd();
360
361   glPopMatrix();
362   glDisable(GL_TEXTURE_2D);
363 }
364
365 /* draw glory */
366 static void draw_glory(providencestruct *mp) 
367 {
368   int i;
369
370   if(mp->wire) {
371     glBegin(GL_TRIANGLES);
372     glVertex3f(-0.75, -0.75, 0.0);
373     glVertex3f(0.75, -0.75, 0.0);
374     glVertex3f(0.0, 0.75, 0.0);
375
376     glVertex3f(0.0, 0.75, 0.0);
377     glVertex3f(0.75, -0.75, 0.0);
378     glVertex3f(-0.75, -0.75, 0.0);
379     glEnd();
380     return;
381   }
382
383   /* draw particles */
384   glDisable(GL_LIGHTING);
385   glPushMatrix();
386   glEnable(GL_BLEND);
387
388   /* glory colour lines */
389   glColor4fv(mp->mono ? MaterialGloryM : MaterialGlory);
390   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
391                mp->mono ? MaterialGloryM : MaterialGlory);
392
393   glBegin(GL_LINES);
394   for(i = 0; i < PARTICLE_COUNT/2; ++i) {
395     double t = mp->currenttime - mp->particles[i][3];
396     double th = atan(mp->particles[i][1] / mp->particles[i][0]);
397     if(mp->particles[i][0] < 0.0)
398       th += Pi;
399
400     glVertex3f(mp->particles[i][0], mp->particles[i][1], mp->particles[i][2]);
401     glVertex3f(mp->particles[i][0] + 0.2*cos(th)*t,
402                mp->particles[i][1] + 0.2*sin(th)*t,
403                mp->particles[i][2]);
404   }
405   glEnd();
406   
407   /* gloryb colour lines */
408   glColor4fv(mp->mono ? MaterialGloryMB : MaterialGloryB);
409   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
410                mp->mono ? MaterialGloryMB : MaterialGloryB);
411   glBegin(GL_LINES);
412   for(; i < PARTICLE_COUNT; ++i) {
413     double t = mp->currenttime - mp->particles[i][3];
414     double th = atan(mp->particles[i][1] / mp->particles[i][0]);
415     if(mp->particles[i][0] < 0.0)
416       th += Pi;
417
418     glVertex3f(mp->particles[i][0], mp->particles[i][1], mp->particles[i][2]);
419     glVertex3f(mp->particles[i][0] + 0.2*cos(th)*t,
420                mp->particles[i][1] + 0.2*sin(th)*t,
421                mp->particles[i][2]);
422   }
423   glEnd();
424
425   glPopMatrix();
426   glEnable(GL_LIGHTING);
427 }
428
429 /* draw eye of providence */
430 static void draw_eye(providencestruct *mp) 
431 {
432   int i;
433
434   /* draw wireeye */
435   if(mp->wire) {
436     glBegin(GL_TRIANGLES);
437     glVertex3f(-0.25, -0.25, 0.0);
438     glVertex3f(0.25, -0.25, 0.0);
439     glVertex3f(0.0, 0.25, 0.0);
440     glEnd();
441     return;
442   }
443
444   /* draw particles */
445   glDisable(GL_LIGHTING);
446   glPushMatrix();
447   glEnable(GL_BLEND);
448
449   /* eye */
450   glColor4fv(mp->mono ? MaterialGloryM : MaterialGlory);
451   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
452                mp->mono ? MaterialGloryM : MaterialGlory);
453
454   /* draw eye particles on z = 0 plane */
455   glBegin(GL_POINTS);
456   for(i = 0; i < EYE_PARTICLE_COUNT/2; ++i) {
457     glVertex3f(mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
458                mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
459                0.0);
460   }
461   glEnd();
462
463   /* eye */
464   glColor4fv(mp->mono ? MaterialGloryMB : MaterialGloryB);
465   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
466                mp->mono ? MaterialGloryMB : MaterialGloryB);
467
468   /* draw eye particles on z = 0 plane */
469   glBegin(GL_POINTS);
470   for(; i < EYE_PARTICLE_COUNT; ++i) {
471     glVertex3f(mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
472                mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
473                0.0);
474   }
475   glEnd();
476
477
478   /* draw scaled particles */
479   glPushMatrix();
480   glScalef(3.3, 2.2, 3.3);
481
482   /* eye */
483   glColor4fv(mp->mono ? MaterialGloryMB : MaterialGloryB);
484   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
485                mp->mono ? MaterialGloryMB : MaterialGloryB);
486
487   /* draw eye particles on z = 0 plane */
488   glBegin(GL_POINTS);
489   for(i = 0; i < EYE_PARTICLE_COUNT/2; ++i) {
490     glVertex3f(mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
491                mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
492                0.0);
493   }
494   glEnd();
495
496   glColor4fv(mp->mono ? MaterialGloryM : MaterialGlory);
497   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
498                mp->mono ? MaterialGloryM : MaterialGlory);
499
500   /* draw eye particles on z = 0 plane */
501   glBegin(GL_POINTS);
502   for(; i < EYE_PARTICLE_COUNT; ++i) {
503     glVertex3f(mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
504                mp->lookup[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
505                0.0);
506   }
507   glEnd();
508
509   glPopMatrix();
510
511   glPopMatrix();
512   glEnable(GL_LIGHTING);
513 }
514
515 /* draw eye of providence */
516 static void draw_eye2(providencestruct *mp) 
517 {
518   int i;
519
520   /* draw wireeye */
521   if(mp->wire) {
522     glBegin(GL_TRIANGLES);
523     glVertex3f(0.0, 0.25, 0.0);
524     glVertex3f(0.25, -0.25, 0.0);
525     glVertex3f(-0.25, -0.25, 0.0);
526     glEnd();
527     return;
528   }
529
530   /* draw particles */
531   glDisable(GL_LIGHTING);
532   glPushMatrix();
533   glEnable(GL_BLEND);
534
535   /* eye */
536   glColor4fv(mp->mono ? MaterialGloryM : MaterialGlory);
537   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
538                mp->mono ? MaterialGloryM : MaterialGlory);
539
540   /* draw eye particles on z = 0 plane */
541   glBegin(GL_POINTS);
542   for(i = 0; i < EYE_PARTICLE_COUNT/2; ++i) {
543     glVertex3f(mp->lookup2[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
544                mp->lookup2[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
545                0.0);
546   }
547   glEnd();
548
549   /* eye */
550   glColor4fv(mp->mono ? MaterialGloryMB : MaterialGloryB);
551   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
552                mp->mono ? MaterialGloryMB : MaterialGloryB);
553
554   /* draw eye particles on z = 0 plane */
555   glBegin(GL_POINTS);
556   for(; i < EYE_PARTICLE_COUNT; ++i) {
557     glVertex3f(mp->lookup2[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][0], 
558                mp->lookup2[mp->eyeparticles[i][0]][mp->eyeparticles[i][1]][1],
559                0.0);
560   }
561   glEnd();
562
563   glPopMatrix();
564   glEnable(GL_LIGHTING);
565 }
566
567 /* draw the scene */
568 static void draw_providence_strip(ModeInfo *mi) 
569 {
570   providencestruct *mp = &providence[MI_SCREEN(mi)];
571   glTranslatef(0.0, 1.414, 0.0);
572
573   mp->position0[0] = 1.6*sin(mp->theta);
574   mp->position0[1] = 1.2;
575   mp->position0[2] = 1.6*cos(mp->theta);
576   mp->position0[3] = 0.0;
577   glLightfv(GL_LIGHT0, GL_POSITION, mp->position0);
578   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient2);
579   glEnable(GL_LIGHTING);
580   glEnable(GL_LIGHT0);
581
582   /* draw pyramid, glory */
583   glDisable(GL_BLEND);
584   glCallList(mp->pyramidlist);
585   draw_glory(mp);
586   if(eye) {
587     if(cos(mp->theta) < 0.0)
588       draw_eye2(mp);
589     else
590       draw_eye(mp);
591   }
592
593   return;
594 }
595
596 ENTRYPOINT void reshape_providence(ModeInfo * mi, int width, int height) 
597 {
598   double h = (GLfloat) height / (GLfloat) width;  
599   providencestruct *mp = &providence[MI_SCREEN(mi)];
600
601   glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
602   glMatrixMode(GL_PROJECTION);
603   glLoadIdentity();
604
605   gluPerspective(45, 1/h, 0.001, 25.0);
606
607   glMatrixMode(GL_MODELVIEW);
608   glLineWidth(2.0);
609   glPointSize(2.0);
610 }
611
612 static void pinit(providencestruct *mp) 
613 {
614   glClearDepth(1.0);
615
616   mp->currenttime = 0.0;
617   init_particles(mp);
618   make_brick(mp);
619   build_eye(mp);
620
621   /* build pyramid list */
622   mp->pyramidlist = glGenLists(1);
623   glNewList(mp->pyramidlist, GL_COMPILE);
624   draw_seal(mp);
625   glEndList();
626 }
627
628 /* cleanup routine */
629 ENTRYPOINT void release_providence(ModeInfo * mi) 
630 {
631
632   if(providence) {
633     free((void *) providence);
634     providence = (providencestruct *) NULL;
635   }
636
637   FreeAllGL(mi);
638 }
639
640 /* event handling */
641 ENTRYPOINT Bool providence_handle_event(ModeInfo *mi, XEvent *event) 
642 {
643   providencestruct *mp = &providence[MI_SCREEN(mi)];
644
645   switch(event->xany.type) {
646   case ButtonPress:
647     switch(event->xbutton.button) {
648     case Button4:
649       mp->camera_velocity += 1.0;
650       return True;
651     case Button5:
652       mp->camera_velocity -= 1.0;
653       return True;
654     default:
655       break;
656     }
657     break;
658   default:
659     break;
660   }
661
662   if (gltrackball_event_handler (event, mp->trackball,
663                                  MI_WIDTH (mi), MI_HEIGHT (mi),
664                                  &mp->button_down_p))
665     return True;
666
667   return False;
668 }
669
670 ENTRYPOINT void init_providence(ModeInfo *mi) 
671 {
672   providencestruct *mp;
673   
674   if(!providence) {
675     if((providence = (providencestruct *) 
676         calloc(MI_NUM_SCREENS(mi), sizeof (providencestruct))) == NULL)
677       return;
678   }
679   mp = &providence[MI_SCREEN(mi)];
680   mp->trackball = gltrackball_init (False);
681
682   mp->position0[0] = 1;
683   mp->position0[1] = 5;
684   mp->position0[2] = 1;
685   mp->position0[3] = 1;
686
687   mp->camera_velocity = -8.0;
688
689   mp->mono = MI_IS_MONO(mi);
690   mp->wire = MI_IS_WIREFRAME(mi);
691
692 # ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
693   mp->wire = 0;
694 # endif
695
696   /* make multiple screens rotate at slightly different rates. */
697   mp->theta_scale = 0.7 + frand(0.6);
698
699   if((mp->glx_context = init_GL(mi)) != NULL) {
700     reshape_providence(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
701     /* glDrawBuffer(GL_BACK); */
702     pinit(mp);
703   }
704   else
705     MI_CLEARWINDOW(mi);
706 }
707
708 ENTRYPOINT void draw_providence(ModeInfo * mi) 
709 {
710   providencestruct *mp;
711   
712   Display    *display = MI_DISPLAY(mi);
713   Window      window = MI_WINDOW(mi);
714   
715   if(!providence)
716     return;
717   mp = &providence[MI_SCREEN(mi)];
718   
719   MI_IS_DRAWN(mi) = True;
720   
721   if(!mp->glx_context)
722     return;
723   
724   glXMakeCurrent(display, window, *(mp->glx_context));
725   
726   /* setup twoside lighting */
727   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient2);
728   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
729   glLightfv(GL_LIGHT0, GL_POSITION, mp->position0);
730
731   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
732   glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
733   glEnable(GL_LIGHTING);
734   glEnable(GL_LIGHT0);
735
736   glEnable(GL_NORMALIZE);
737   glFrontFace(GL_CCW);
738 /*   glDisable(GL_CULL_FACE); */
739   glEnable(GL_CULL_FACE);
740   glCullFace(GL_BACK);
741   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
742
743   glShadeModel(GL_SMOOTH);
744   glEnable(GL_DEPTH_TEST);
745   glDepthFunc(GL_LEQUAL);
746
747   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
748   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
749   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
750   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
751   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
752
753   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
754
755   glPushMatrix();
756   glRotatef(current_device_rotation(), 0, 0, 1);
757
758   /* modify camera */
759   if(fabs(mp->camera_velocity) > EPSILON) {
760     mp->camera_z = max(min(mp->camera_z + 0.1*mp->camera_velocity, -4.0), -12.0);
761     mp->camera_velocity = 0.95*mp->camera_velocity;
762   }
763   
764   /* rotate providence */
765   glTranslatef(0.0, 0.0, mp->camera_z + sin(mp->theta/4.0));
766   glRotatef(10.0+20.0*sin(mp->theta/2.0), 1.0, 0.0, 0.0);
767   gltrackball_rotate(mp->trackball);
768   glRotatef(mp->theta * 180.0 / Pi, 0.0, -1.0, 0.0);
769
770 # ifdef HAVE_MOBILE     /* Keep it the same relative size when rotated. */
771   {
772     GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
773     int o = (int) current_device_rotation();
774     if (o != 0 && o != 180 && o != -180)
775       glScalef (1/h, 1/h, 1/h);
776   }
777 # endif
778
779   /* draw providence */
780   draw_providence_strip(mi);
781   glPopMatrix();
782   
783   if(MI_IS_FPS(mi)) do_fps (mi);
784   glFlush();
785   
786   glXSwapBuffers(display, window);
787
788   /* update */
789   mp->currenttime += 1.0 / FPS;
790   mp->theta = mp->currenttime / 2.0 * mp->theta_scale;
791   update_particles(mp);
792 }
793
794 #ifndef STANDALONE
795 ENTRYPOINT void change_providence(ModeInfo * mi) 
796 {
797   providencestruct *mp = &providence[MI_SCREEN(mi)];
798   
799   if (!mp->glx_context)
800         return;
801   
802   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
803   pinit();
804 }
805 #endif /* !STANDALONE */
806
807 XSCREENSAVER_MODULE ("Providence", providence)