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