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.
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.
14 * Copyright 2004 Blair Tennessy
17 #include <X11/Intrinsic.h>
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"
31 #include "xlockmore.h"
37 #include "gltrackball.h"
39 #define DEF_SOLIDPROVIDENCE "False"
40 #define DEF_EYE "True"
44 static XrmOptionDescRec opts[] = {
46 (char *) ".providence.eye", XrmoptionNoArg, (caddr_t) "on"},
49 (char *) ".providence.eye", XrmoptionNoArg, (caddr_t) "off"}
52 static argtype vars[] = {
54 (char *) "eye", (char *) "Eye", (char *) DEF_EYE, t_Bool}
57 static OptionStruct desc[] = {
59 (char *) "turn on/off eye of providence"}
62 ModeSpecOpt providence_opts = {
63 sizeof opts / sizeof opts[0], opts,
64 sizeof vars / sizeof vars[0], vars, desc
68 ModStruct providence_description = {
69 "providence", "init_providence", "draw_providence",
70 "release_providence", "draw_providence", "change_providence",
71 (char *) NULL, &providence_opts, 1000, 1, 1, 1, 4, 1.0, "",
72 "draws pyramid with glory", 0, NULL
76 #define Scale4Window 0.3
77 #define Scale4Iconic 0.4
79 #define sqr(A) ((A)*(A))
85 int mono = 0, wire = 0;
86 double camera_velocity = 0.0;
87 double camera_z = -8.0;
92 GLXContext *glx_context;
93 trackball_state *trackball;
97 /* lighting variables */
98 GLfloat front_shininess[] = {60.0};
99 GLfloat front_specular[] = {0.2, 0.2, 0.2, 1.0};
100 GLfloat ambient[] = {0.8, 0.8, 0.8, 1.0};
101 GLfloat ambient2[] = {0.25, 0.25, 0.25, 1.0};
102 GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0};
103 GLfloat position0[] = {1.0, 5.0, 1.0, 1.0};
104 GLfloat position1[] = {-1.0, -5.0, 1.0, 1.0};
105 GLfloat lmodel_ambient[] = {0.5, 0.5, 0.5, 1.0};
106 GLfloat lmodel_twoside[] = {GL_TRUE};
110 GLfloat MaterialGlory[] = {0.04, 0.30, 0.22, 0.7};
111 GLfloat MaterialGloryB[] = {0.07, 0.50, 0.36, 0.6};
113 GLfloat MaterialGloryF[] = {0.07, 0.50, 0.36, 1.0};
114 /* GLfloat MaterialGloryF[] = {0.06, 0.38, 0.27, 1.0}; */
115 GLfloat MaterialGloryE[] = {0.06, 0.38, 0.27, 0.3};
116 GLfloat MaterialGloryM[] = {0.5, 0.5, 0.5, 0.5};
117 GLfloat MaterialGloryMB[] = {0.36, 0.36, 0.36, 0.4};
118 GLfloat MaterialGreenback[4] = {0.04, 0.30, 0.22, 1.0};
119 GLfloat MaterialBlack[4] = {0.0, 0.0, 0.0, 1.0};
121 GLfloat MaterialGray5[] = {0.5, 0.5, 0.5, 1.0};
122 GLfloat MaterialGray6[] = {0.6, 0.6, 0.6, 1.0};
126 static providencestruct *providence = (providencestruct *) NULL;
131 #define checkImageWidth 64
132 #define checkImageHeight 64
133 GLubyte checkImage[checkImageWidth][checkImageHeight][3];
136 /* build brick texture */
137 void make_brick(void) {
140 for (i = 0; i < checkImageWidth; i++) {
141 for (j = 0; j < checkImageHeight; j++) {
142 c = i % 16 == 15 ? 255 : (j + 48*(i / 16))%64 == 0 ? 255 :
143 102 + random() % 102;
144 checkImage[i][j][0] = (GLubyte) c;
145 checkImage[i][j][1] = (GLubyte) c;
146 checkImage[i][j][2] = (GLubyte) c;
150 glGenTextures(1, &bricktexture);
151 glBindTexture(GL_TEXTURE_2D, bricktexture);
153 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
154 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
155 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
156 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
157 glTexImage2D(GL_TEXTURE_2D, 0, 3, checkImageWidth,
158 checkImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE,
160 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
164 int mini(int a, int b) { return a < b ? a : b; }
167 #define EYE_PARTICLE_COUNT 2000
168 int eyeparticles[EYE_PARTICLE_COUNT][2];
170 /* lookup table for the eye */
171 #define LOOKUPSIZE 3600
172 #define EYELENGTH 300
173 double lookup[LOOKUPSIZE][EYELENGTH][2];
174 double lookup2[LOOKUPSIZE][EYELENGTH][2];
176 /* build eye lookup table */
177 void build_eye(void) {
180 double inc = 0.1 / EYELENGTH;
181 double inc2 = 2.4*Pi / EYELENGTH;
183 /* describe all values tangentially out from pupil */
184 for(i = 0; i < LOOKUPSIZE; ++i) {
185 double r = i * 2*Pi / LOOKUPSIZE;/*x + inc;*/
190 for(j = 0; j < EYELENGTH; ++j) {
191 lookup[i][j][0] = x*sr;
192 lookup[i][j][1] = x*cr;
197 /* lookup2: dollar sign */
198 for(i = 0; i < LOOKUPSIZE; ++i) {
201 for(j = 0; j < EYELENGTH; ++j) {
203 lookup2[i][j][0] = sin(y)/6.0 + i/36000.0 - 0.05;
204 lookup2[i][j][1] = i%4 ? y/12.0 - 0.05 : 1.2*Pi-y/12.0 + 0.05;
207 lookup2[i][j][0] = i/36000.0 - 0.05;
208 lookup2[i][j][1] = y/9.0 - 0.05;
216 #define EPSILON 0.0001
218 double min(double a, double b) {
219 return a < b ? a : b;
222 double max(double a, double b) {
223 return a > b ? a : b;
226 #define PARTICLE_COUNT 2000
227 double particles[PARTICLE_COUNT][5];
229 void init_particle(double particle[5]) {
230 /* position along glory */
231 double p = (random() % 485410) / 100000.0;
237 particle[0] = p - 0.75;
238 particle[1] = -0.75001;
240 else if(p < 1.5 + sqrt(45)/4.0) {
242 particle[0] = 0.75 - d*cos(atan(2.0));
243 particle[1] = d*sin(atan(2.0)) - 0.75;
246 double d = 4.8541 - p;
247 particle[0] = -0.75 + d*cos(atan(2.0));
248 particle[1] = d*sin(atan(2.0)) - 0.75;
251 particle[3] = currenttime;
252 particle[4] = 1.25 + (random()%10)/10.0;
255 /* init glory particles */
256 void init_particles(void) {
258 for(i = 0; i < PARTICLE_COUNT; ++i) {
259 init_particle(particles[i]);
261 /* set initial time */
262 particles[i][3] = currenttime - (random()%1250)/1000.0;
265 /* init eye particles */
266 for(i = 0; i < EYE_PARTICLE_COUNT; ++i) {
267 eyeparticles[i][0] = random()%LOOKUPSIZE;
268 eyeparticles[i][1] = random()%EYELENGTH;
275 /* ugg, should be a priority queue if next event times known */
276 void update_particles(void) {
279 for(i = 0; i < PARTICLE_COUNT; ++i) {
280 /* check for time elapse */
281 if(currenttime > particles[i][3] + particles[i][4])
282 init_particle(particles[i]);
285 /* now update eye particles */
286 for(i = 0; i < EYE_PARTICLE_COUNT; ++i) {
287 /* int x = eyeparticles[i][1] + random()%16; */
288 int x = eyeparticles[i][1] + random()%(cos(theta) < 0.0 ? 8 : 16);
291 if(x > EYELENGTH || random()%(cos(theta) < 0.0 ? 40 : 10) == 0) {
293 /* if(x > EYELENGTH || (x > EYELENGTH/(2/3.0) && random()%7 == 0)) { */
294 eyeparticles[i][0] = random()%LOOKUPSIZE;
295 eyeparticles[i][1] = random()%40;
298 eyeparticles[i][1] = x;
303 /* draw the pyramid */
304 void draw_seal(void) {
306 double base = sqrt(2.0);
307 double top = 1.0 / sqrt(2.0);
308 double tmod = 7.0/6.0;
312 /* set options for mono, wireframe */
314 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
315 glDisable(GL_LIGHTING);
316 glDisable(GL_TEXTURE_2D);
319 glEnable(GL_TEXTURE_2D);
320 glBindTexture(GL_TEXTURE_2D, bricktexture);
322 glEnable(GL_LIGHTING);
324 glColor4fv(mono ? MaterialGray5 : MaterialGloryF);
325 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
326 mono ? MaterialGray5 : MaterialGloryF);
329 glRotatef(45.0, 0.0, 1.0, 0.0);
330 glTranslatef(0.0, -3.25, 0.0);
332 for(i = 0; i < 4; ++i) {
333 glRotatef(i*90.0, 0.0, 1.0, 0.0);
336 glNormal3f(1 / sqrt(6.0), 2 / sqrt(6.0), 1 / sqrt(6.0));
337 glTexCoord2f(-base, 0.0);
338 glVertex3f(-base, 0.0, base);
339 glTexCoord2f(base, 0.0);
340 glVertex3f(base, 0.0, base);
341 glTexCoord2f(top, 13.0/4.0);
342 glVertex3f(top, 2.0, top);
343 glTexCoord2f(-top, 13.0/4.0);
344 glVertex3f(-top, 2.0, top);
351 glNormal3f(0.0, 1.0, 0.0);
352 glTexCoord2f(0.02, 0.0);
353 glVertex3f(-top, 2.0, top);
354 glTexCoord2f(2.0*top, 0.0);
355 glVertex3f(top, 2.0, top);
356 glTexCoord2f(2.0*top, tmod*2.1*top);
357 glVertex3f(top, 2.0, -top);
358 glTexCoord2f(0.02, tmod*2.1*top);
359 glVertex3f(-top, 2.0, -top);
362 glNormal3f(0.0, -1.0, 0.0);
363 glTexCoord2f(-base, 0.0);
364 glVertex3f(-base, 0.0, -base);
365 glTexCoord2f(top, 0.0);
366 glVertex3f(base, 0.0, -base);
367 glTexCoord2f(top, top*13.0/4.0);
368 glVertex3f(base, 0.0, base);
369 glTexCoord2f(-top, top*13.0/4.0);
370 glVertex3f(-base, 0.0, base);
375 glDisable(GL_TEXTURE_2D);
379 void draw_glory(void) {
383 glBegin(GL_TRIANGLES);
384 glVertex3f(-0.75, -0.75, 0.0);
385 glVertex3f(0.75, -0.75, 0.0);
386 glVertex3f(0.0, 0.75, 0.0);
392 glDisable(GL_LIGHTING);
396 /* glory colour lines */
397 glColor4fv(mono ? MaterialGloryM : MaterialGlory);
398 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
399 mono ? MaterialGloryM : MaterialGlory);
402 for(i = 0; i < PARTICLE_COUNT/2; ++i) {
403 double t = currenttime - particles[i][3];
404 double th = atan(particles[i][1] / particles[i][0]);
405 if(particles[i][0] < 0.0)
408 glVertex3f(particles[i][0], particles[i][1], particles[i][2]);
409 glVertex3f(particles[i][0] + 0.2*cos(th)*t,
410 particles[i][1] + 0.2*sin(th)*t,
415 /* gloryb colour lines */
416 glColor4fv(mono ? MaterialGloryMB : MaterialGloryB);
417 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
418 mono ? MaterialGloryMB : MaterialGloryB);
420 for(; i < PARTICLE_COUNT; ++i) {
421 double t = currenttime - particles[i][3];
422 double th = atan(particles[i][1] / particles[i][0]);
423 if(particles[i][0] < 0.0)
426 glVertex3f(particles[i][0], particles[i][1], particles[i][2]);
427 glVertex3f(particles[i][0] + 0.2*cos(th)*t,
428 particles[i][1] + 0.2*sin(th)*t,
434 glEnable(GL_LIGHTING);
437 /* draw eye of providence */
438 void draw_eye(void) {
443 glBegin(GL_TRIANGLES);
444 glVertex3f(-0.25, -0.25, 0.0);
445 glVertex3f(0.25, -0.25, 0.0);
446 glVertex3f(0.0, 0.25, 0.0);
452 glDisable(GL_LIGHTING);
457 glColor4fv(mono ? MaterialGloryM : MaterialGlory);
458 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
459 mono ? MaterialGloryM : MaterialGlory);
461 /* draw eye particles on z = 0 plane */
463 for(i = 0; i < EYE_PARTICLE_COUNT/2; ++i) {
464 glVertex3f(lookup[eyeparticles[i][0]][eyeparticles[i][1]][0],
465 lookup[eyeparticles[i][0]][eyeparticles[i][1]][1],
471 glColor4fv(mono ? MaterialGloryMB : MaterialGloryB);
472 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
473 mono ? MaterialGloryMB : MaterialGloryB);
475 /* draw eye particles on z = 0 plane */
477 for(; i < EYE_PARTICLE_COUNT; ++i) {
478 glVertex3f(lookup[eyeparticles[i][0]][eyeparticles[i][1]][0],
479 lookup[eyeparticles[i][0]][eyeparticles[i][1]][1],
485 /* draw scaled particles */
487 glScalef(3.3, 2.2, 3.3);
490 glColor4fv(mono ? MaterialGloryMB : MaterialGloryB);
491 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
492 mono ? MaterialGloryMB : MaterialGloryB);
494 /* draw eye particles on z = 0 plane */
496 for(i = 0; i < EYE_PARTICLE_COUNT/2; ++i) {
497 glVertex3f(lookup[eyeparticles[i][0]][eyeparticles[i][1]][0],
498 lookup[eyeparticles[i][0]][eyeparticles[i][1]][1],
503 glColor4fv(mono ? MaterialGloryM : MaterialGlory);
504 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
505 mono ? MaterialGloryM : MaterialGlory);
507 /* draw eye particles on z = 0 plane */
509 for(; i < EYE_PARTICLE_COUNT; ++i) {
510 glVertex3f(lookup[eyeparticles[i][0]][eyeparticles[i][1]][0],
511 lookup[eyeparticles[i][0]][eyeparticles[i][1]][1],
519 glEnable(GL_LIGHTING);
522 /* draw eye of providence */
523 void draw_eye2(void) {
528 glBegin(GL_TRIANGLES);
529 glVertex3f(-0.25, -0.25, 0.0);
530 glVertex3f(0.25, -0.25, 0.0);
531 glVertex3f(0.0, 0.25, 0.0);
537 glDisable(GL_LIGHTING);
542 glColor4fv(mono ? MaterialGloryM : MaterialGlory);
543 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
544 mono ? MaterialGloryM : MaterialGlory);
546 /* draw eye particles on z = 0 plane */
548 for(i = 0; i < EYE_PARTICLE_COUNT/2; ++i) {
549 glVertex3f(lookup2[eyeparticles[i][0]][eyeparticles[i][1]][0],
550 lookup2[eyeparticles[i][0]][eyeparticles[i][1]][1],
556 glColor4fv(mono ? MaterialGloryMB : MaterialGloryB);
557 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
558 mono ? MaterialGloryMB : MaterialGloryB);
560 /* draw eye particles on z = 0 plane */
562 for(; i < EYE_PARTICLE_COUNT; ++i) {
563 glVertex3f(lookup2[eyeparticles[i][0]][eyeparticles[i][1]][0],
564 lookup2[eyeparticles[i][0]][eyeparticles[i][1]][1],
570 glEnable(GL_LIGHTING);
574 void draw_providence_strip(ModeInfo *mi) {
575 glTranslatef(0.0, 1.414, 0.0);
577 position0[0] = 1.6*sin(theta);
579 position0[2] = 1.6*cos(theta);
581 glLightfv(GL_LIGHT0, GL_POSITION, position0);
582 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient2);
583 glEnable(GL_LIGHTING);
586 /* draw pyramid, glory */
588 glCallList(pyramidlist);
600 void reshape_providence(ModeInfo * mi, int width, int height) {
601 double h = (GLfloat) height / (GLfloat) width;
602 providencestruct *mp = &providence[MI_SCREEN(mi)];
604 glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
605 glMatrixMode(GL_PROJECTION);
608 gluPerspective(45, 1/h, 0.001, 25.0);
610 glMatrixMode(GL_MODELVIEW);
615 static void pinit(void) {
617 glClearColor(0.0, 0.0, 0.0, 1.0);
619 /* setup twoside lighting */
620 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient2);
621 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
622 glLightfv(GL_LIGHT0, GL_POSITION, position0);
624 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
625 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
626 glEnable(GL_LIGHTING);
634 glEnable(GL_NORMALIZE);
636 /* glDisable(GL_CULL_FACE); */
637 glEnable(GL_CULL_FACE);
639 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
641 glShadeModel(GL_SMOOTH);
642 glEnable(GL_DEPTH_TEST);
643 glDepthFunc(GL_LEQUAL);
645 /* build pyramid list */
646 pyramidlist = glGenLists(1);
647 glNewList(pyramidlist, GL_COMPILE);
652 /* cleanup routine */
653 void release_providence(ModeInfo * mi) {
656 free((void *) providence);
657 providence = (providencestruct *) NULL;
664 Bool providence_handle_event(ModeInfo *mi, XEvent *event) {
665 providencestruct *mp = &providence[MI_SCREEN(mi)];
667 switch(event->xany.type) {
670 switch(event->xbutton.button) {
673 mp->button_down_p = True;
674 gltrackball_start(mp->trackball,
675 event->xbutton.x, event->xbutton.y,
676 MI_WIDTH (mi), MI_HEIGHT (mi));
680 camera_velocity += 1.0;
684 camera_velocity -= 1.0;
692 switch(event->xbutton.button) {
694 mp->button_down_p = False;
701 if(mp->button_down_p)
702 gltrackball_track(mp->trackball,
703 event->xmotion.x, event->xmotion.y,
704 MI_WIDTH (mi), MI_HEIGHT (mi));
714 void init_providence(ModeInfo *mi) {
715 providencestruct *mp;
718 if((providence = (providencestruct *)
719 calloc(MI_NUM_SCREENS(mi), sizeof (providencestruct))) == NULL)
722 mp = &providence[MI_SCREEN(mi)];
723 mp->trackball = gltrackball_init ();
725 mono = MI_IS_MONO(mi);
726 wire = MI_IS_WIREFRAME(mi);
728 if((mp->glx_context = init_GL(mi)) != NULL) {
729 reshape_providence(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
730 glDrawBuffer(GL_BACK);
737 void draw_providence(ModeInfo * mi) {
738 providencestruct *mp;
740 Display *display = MI_DISPLAY(mi);
741 Window window = MI_WINDOW(mi);
745 mp = &providence[MI_SCREEN(mi)];
747 MI_IS_DRAWN(mi) = True;
752 glXMakeCurrent(display, window, *(mp->glx_context));
754 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
759 if(fabs(camera_velocity) > EPSILON) {
760 camera_z = max(min(camera_z + 0.1*camera_velocity, -4.0), -12.0);
761 camera_velocity = 0.95*camera_velocity;
764 /* rotate providence */
765 glTranslatef(0.0, 0.0, camera_z + sin(theta/4.0));
766 glRotatef(10.0+20.0*sin(theta/2.0), 1.0, 0.0, 0.0);
767 gltrackball_rotate(mp->trackball);
768 glRotatef(theta * 180.0 / Pi, 0.0, -1.0, 0.0);
770 /* draw providence */
771 draw_providence_strip(mi);
774 if(MI_IS_FPS(mi)) do_fps (mi);
777 glXSwapBuffers(display, window);
780 currenttime += 1.0 / FPS;
781 theta = currenttime / 2.0;
785 void change_providence(ModeInfo * mi) {
786 providencestruct *mp = &providence[MI_SCREEN(mi)];
788 if (!mp->glx_context)
791 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));