http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.00.tar.gz
[xscreensaver] / hacks / glx / sierpinski3d.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* Sierpinski3D --- 3D sierpinski gasket */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)sierpinski3D.c        00.01 99/11/04 xlockmore";
6
7 #endif
8
9 /*-
10  * Permission to use, copy, modify, and distribute this software and its
11  * documentation for any purpose and without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and that
13  * both that copyright notice and this permission notice appear in
14  * supporting documentation.
15  *
16  * This file is provided AS IS with no warranties of any kind.  The author
17  * shall have no liability with respect to the infringement of copyrights,
18  * trade secrets or any patents by this file or any part thereof.  In no
19  * event will the author be liable for any lost revenue or profits or
20  * other special, indirect and consequential damages.
21  *
22  * Revision History:
23  * 1999: written by Tim Robinson <the_luggage@bigfoot.com>
24  *       a 3-D representation of the Sierpinski gasket fractal.
25  *
26  * 10-Dec-99  jwz   rewrote to draw a set of tetrahedrons instead of a
27  *                  random scattering of points.
28  */
29
30 /*-
31  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
32  * otherwise caddr_t is not defined correctly
33  */
34
35 #include <X11/Intrinsic.h>
36
37 #ifdef STANDALONE
38 # define PROGCLASS                                      "Sierpinski3D"
39 # define HACK_INIT                                      init_gasket
40 # define HACK_DRAW                                      draw_gasket
41 # define HACK_RESHAPE                           reshape_gasket
42 # define gasket_opts                            xlockmore_opts
43 # define DEFAULTS                                       "*delay:                20000   \n"                     \
44                                                                         "*maxDepth:             5       \n"                     \
45                                                                         "*speed:                150     \n"                     \
46                                                                         "*showFPS:      False   \n"                     \
47                                                                         "*wireframe:    False   \n"
48 # include "xlockmore.h"         /* from the xscreensaver distribution */
49 #else  /* !STANDALONE */
50 # include "xlock.h"                     /* from the xlockmore distribution */
51 #endif /* !STANDALONE */
52
53 #ifdef USE_GL
54
55 #undef countof
56 #define countof(x) (sizeof((x))/sizeof((*x)))
57
58 static int max_depth;
59 static int speed;
60 static XrmOptionDescRec opts[] = {
61   {"-depth", ".sierpinski3d.maxDepth", XrmoptionSepArg, (caddr_t) 0 },
62   {"-speed", ".sierpinski3d.speed",    XrmoptionSepArg, (caddr_t) 0 }
63 };
64
65 static argtype vars[] = {
66   {(caddr_t *) &max_depth, "maxDepth", "MaxDepth", "5", t_Int},
67   {(caddr_t *) &speed,     "speed",    "Speed",   "150", t_Int},
68 };
69
70
71 ModeSpecOpt gasket_opts = {countof(opts), opts, countof(vars), vars, NULL};
72
73 #ifdef USE_MODULES
74 ModStruct   gasket_description =
75 {"gasket", "init_gasket", "draw_gasket", "release_gasket",
76  "draw_gasket", "init_gasket", NULL, &gasket_opts,
77  1000, 1, 2, 1, 4, 1.0, "",
78  "Shows GL's Sierpinski gasket", 0, NULL};
79
80 #endif
81
82 typedef struct{
83   GLfloat x;
84   GLfloat y;
85   GLfloat z;
86 } GL_VECTOR;
87
88 typedef struct {
89   GLfloat rotx, roty, rotz;        /* current object rotation */
90   GLfloat dx, dy, dz;              /* current rotational velocity */
91   GLfloat ddx, ddy, ddz;           /* current rotational acceleration */
92   GLfloat d_max;                           /* max velocity */
93
94   GLfloat     angle;
95   GLuint      gasket0, gasket1, gasket2, gasket3;
96   GLXContext *glx_context;
97   Window      window;
98
99   int current_depth;
100
101   int ncolors;
102   XColor *colors;
103   int ccolor0;
104   int ccolor1;
105   int ccolor2;
106   int ccolor3;
107
108 } gasketstruct;
109
110 static gasketstruct *gasket = NULL;
111
112 #include <GL/glu.h>
113
114 static GLfloat normals[4][3];
115
116 \f
117
118 static void
119 triangle (GLfloat x1, GLfloat y1, GLfloat z1,
120           GLfloat x2, GLfloat y2, GLfloat z2,
121           GLfloat x3, GLfloat y3, GLfloat z3,
122           Bool wireframe_p)
123 {
124   if (wireframe_p)
125     glBegin (GL_LINE_LOOP);
126   else
127     glBegin (GL_TRIANGLES);
128   glVertex3f (x1, y1, z1);
129   glVertex3f (x2, y2, z2);
130   glVertex3f (x3, y3, z3);
131   glEnd();
132 }
133
134 static void
135 four_tetras (GL_VECTOR *outer, Bool wireframe_p, int countdown, int which)
136 {
137   if (countdown <= 0)
138     {
139       if (which == 0)
140         {
141           glNormal3f (normals[0][0], normals[0][1], normals[0][2]);
142           triangle (outer[0].x, outer[0].y, outer[0].z,
143                     outer[1].x, outer[1].y, outer[1].z,
144                     outer[2].x, outer[2].y, outer[2].z,
145                     wireframe_p);
146         }
147       else if (which == 1)
148         {
149           glNormal3f (normals[1][0], normals[1][1], normals[1][2]);
150           triangle (outer[0].x, outer[0].y, outer[0].z,
151                     outer[3].x, outer[3].y, outer[3].z,
152                     outer[1].x, outer[1].y, outer[1].z,
153                     wireframe_p);
154         }
155       else if (which == 2)
156         {
157           glNormal3f (normals[2][0], normals[2][1], normals[2][2]);
158           triangle (outer[0].x, outer[0].y, outer[0].z,
159                     outer[2].x, outer[2].y, outer[2].z,
160                     outer[3].x, outer[3].y, outer[3].z,
161                     wireframe_p);
162         }
163       else
164         {
165           glNormal3f (normals[3][0], normals[3][1], normals[3][2]);
166           triangle (outer[1].x, outer[1].y, outer[1].z,
167                     outer[3].x, outer[3].y, outer[3].z,
168                     outer[2].x, outer[2].y, outer[2].z,
169                     wireframe_p);
170         }
171     }
172   else
173     {
174 #     define M01 0
175 #     define M02 1
176 #     define M03 2
177 #     define M12 3
178 #     define M13 4
179 #     define M23 5
180       GL_VECTOR inner[M23+1];
181       GL_VECTOR corner[4];
182
183       inner[M01].x = (outer[0].x + outer[1].x) / 2.0;
184       inner[M01].y = (outer[0].y + outer[1].y) / 2.0;
185       inner[M01].z = (outer[0].z + outer[1].z) / 2.0;
186
187       inner[M02].x = (outer[0].x + outer[2].x) / 2.0;
188       inner[M02].y = (outer[0].y + outer[2].y) / 2.0;
189       inner[M02].z = (outer[0].z + outer[2].z) / 2.0;
190
191       inner[M03].x = (outer[0].x + outer[3].x) / 2.0;
192       inner[M03].y = (outer[0].y + outer[3].y) / 2.0;
193       inner[M03].z = (outer[0].z + outer[3].z) / 2.0;
194
195       inner[M12].x = (outer[1].x + outer[2].x) / 2.0;
196       inner[M12].y = (outer[1].y + outer[2].y) / 2.0;
197       inner[M12].z = (outer[1].z + outer[2].z) / 2.0;
198
199       inner[M13].x = (outer[1].x + outer[3].x) / 2.0;
200       inner[M13].y = (outer[1].y + outer[3].y) / 2.0;
201       inner[M13].z = (outer[1].z + outer[3].z) / 2.0;
202
203       inner[M23].x = (outer[2].x + outer[3].x) / 2.0;
204       inner[M23].y = (outer[2].y + outer[3].y) / 2.0;
205       inner[M23].z = (outer[2].z + outer[3].z) / 2.0;
206
207       countdown--;
208
209       corner[0] = outer[0];
210       corner[1] = inner[M01];
211       corner[2] = inner[M02];
212       corner[3] = inner[M03];
213       four_tetras (corner, wireframe_p, countdown, which);
214
215       corner[0] = inner[M01];
216       corner[1] = outer[1];
217       corner[2] = inner[M12];
218       corner[3] = inner[M13];
219       four_tetras (corner, wireframe_p, countdown, which);
220
221       corner[0] = inner[M02];
222       corner[1] = inner[M12];
223       corner[2] = outer[2];
224       corner[3] = inner[M23];
225       four_tetras (corner, wireframe_p, countdown, which);
226
227       corner[0] = inner[M03];
228       corner[1] = inner[M13];
229       corner[2] = inner[M23];
230       corner[3] = outer[3];
231       four_tetras (corner, wireframe_p, countdown, which);
232     }
233 }
234
235
236 static void
237 compile_gasket(ModeInfo *mi, int which)
238 {
239   Bool wireframe_p = MI_IS_WIREFRAME(mi);
240   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
241
242   GL_VECTOR   vertex[5];
243
244   normals[0][0] =  0;
245   normals[0][1] =  0;
246   normals[0][2] = -sqrt(2.0 / 3.0);
247
248   normals[1][0] =  0;
249   normals[1][1] = -sqrt(0.75);
250   normals[1][2] =  sqrt(2.0 / 3.0) / 3.0;
251
252   normals[2][0] =  sqrt (0.5);
253   normals[2][1] =  sqrt(0.75) / 2.0;
254   normals[2][2] =  normals[1][2];
255
256   normals[3][0] = -normals[2][0];
257   normals[3][1] =  normals[2][1];
258   normals[3][2] =  normals[1][2];
259
260
261   /* define verticies */
262   vertex[0].x =  0.5; 
263   vertex[0].y = -(1.0/3.0)*sqrt((2.0/3.0));
264   vertex[0].z = -sqrt(3.0)/6.0;
265
266   vertex[1].x = -0.5; 
267   vertex[1].y = -(1.0/3.0)*sqrt((2.0/3.0)); 
268   vertex[1].z = -sqrt(3.0)/6.0; 
269
270   vertex[2].x = 0.0; 
271   vertex[2].y = (2.0/3.0)*sqrt((2.0/3.0));
272   vertex[2].z = -sqrt(3.0)/6.0; 
273
274   vertex[3].x = 0.0; 
275   vertex[3].y = 0.0; 
276   vertex[3].z = sqrt(3.0)/3.0; 
277
278   vertex[4].x = 0.0;
279   vertex[4].y = 0.0; 
280   vertex[4].z = 0.0;
281   
282   four_tetras (vertex, wireframe_p,
283                (gp->current_depth < 0
284                 ? -gp->current_depth : gp->current_depth),
285                which);
286 }
287
288 static void
289 draw(ModeInfo *mi)
290 {
291   Bool wireframe_p = MI_IS_WIREFRAME(mi);
292   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
293   static int tick = 999999;
294   
295   static GLfloat pos[4] = {-4.0, 3.0, 10.0, 1.0};
296   static float white[]  = {1.0, 1.0, 1.0, 1.0};
297   static float color0[] = {0.0, 0.0, 0.0, 1.0};
298   static float color1[] = {0.0, 0.0, 0.0, 1.0};
299   static float color2[] = {0.0, 0.0, 0.0, 1.0};
300   static float color3[] = {0.0, 0.0, 0.0, 1.0};
301
302   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
303
304   if (!wireframe_p)
305     {
306       glColor4fv (white);
307
308       glLightfv(GL_LIGHT0, GL_POSITION,  pos);
309
310       color0[0] = gp->colors[gp->ccolor0].red   / 65536.0;
311       color0[1] = gp->colors[gp->ccolor0].green / 65536.0;
312       color0[2] = gp->colors[gp->ccolor0].blue  / 65536.0;
313
314       color1[0] = gp->colors[gp->ccolor1].red   / 65536.0;
315       color1[1] = gp->colors[gp->ccolor1].green / 65536.0;
316       color1[2] = gp->colors[gp->ccolor1].blue  / 65536.0;
317
318       color2[0] = gp->colors[gp->ccolor2].red   / 65536.0;
319       color2[1] = gp->colors[gp->ccolor2].green / 65536.0;
320       color2[2] = gp->colors[gp->ccolor2].blue  / 65536.0;
321
322       color3[0] = gp->colors[gp->ccolor3].red   / 65536.0;
323       color3[1] = gp->colors[gp->ccolor3].green / 65536.0;
324       color3[2] = gp->colors[gp->ccolor3].blue  / 65536.0;
325
326       gp->ccolor0++;
327       gp->ccolor1++;
328       gp->ccolor2++;
329       gp->ccolor3++;
330       if (gp->ccolor0 >= gp->ncolors) gp->ccolor0 = 0;
331       if (gp->ccolor1 >= gp->ncolors) gp->ccolor1 = 0;
332       if (gp->ccolor2 >= gp->ncolors) gp->ccolor2 = 0;
333       if (gp->ccolor3 >= gp->ncolors) gp->ccolor3 = 0;
334
335       glShadeModel(GL_SMOOTH);
336
337       glEnable(GL_LIGHTING);
338       glEnable(GL_LIGHT0);
339     }
340
341   glEnable(GL_DEPTH_TEST);
342   glEnable(GL_NORMALIZE);
343   glEnable(GL_CULL_FACE);
344
345   glPushMatrix();
346
347   {
348     static int frame = 0;
349     GLfloat x, y, z;
350
351 #   define SINOID(SCALE,SIZE) \
352       ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
353     x = SINOID(0.0071, 8.0);
354     y = SINOID(0.0053, 6.0);
355     z = SINOID(0.0037, 15.0);
356     frame++;
357     glTranslatef(x, y, z);
358
359     x = gp->rotx;
360     y = gp->roty;
361     z = gp->rotz;
362     if (x < 0) x = 1 - (x + 1);
363     if (y < 0) y = 1 - (y + 1);
364     if (z < 0) z = 1 - (z + 1);
365     glRotatef(x * 360, 1.0, 0.0, 0.0);
366     glRotatef(y * 360, 0.0, 1.0, 0.0);
367     glRotatef(z * 360, 0.0, 0.0, 1.0);
368   }
369
370   glScalef( 8.0, 8.0, 8.0 );
371
372   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color0);
373   glCallList(gp->gasket0);
374   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color1);
375   glCallList(gp->gasket1);
376   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color2);
377   glCallList(gp->gasket2);
378   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color3);
379   glCallList(gp->gasket3);
380
381   glPopMatrix();
382
383
384   if (tick++ >= speed)
385     {
386       tick = 0;
387       if (gp->current_depth >= max_depth)
388         gp->current_depth = -max_depth;
389       gp->current_depth++;
390
391       /* We make four different lists so that each face of the tetrahedrons
392          can have a different color (all triangles facing in the same
393          direction have the same color, which is different from all
394          triangles facing in other directions.)
395        */
396       glDeleteLists (gp->gasket0, 1);
397       glDeleteLists (gp->gasket1, 1);
398       glDeleteLists (gp->gasket2, 1);
399       glDeleteLists (gp->gasket3, 1);
400       glNewList (gp->gasket0, GL_COMPILE); compile_gasket (mi, 0); glEndList();
401       glNewList (gp->gasket1, GL_COMPILE); compile_gasket (mi, 1); glEndList();
402       glNewList (gp->gasket2, GL_COMPILE); compile_gasket (mi, 2); glEndList();
403       glNewList (gp->gasket3, GL_COMPILE); compile_gasket (mi, 3); glEndList();
404
405     }
406 }
407
408
409 /* new window size or exposure */
410 void
411 reshape_gasket(ModeInfo *mi, int width, int height)
412 {
413   GLfloat h = (GLfloat) height / (GLfloat) width;
414
415   glViewport(0, 0, (GLint) width, (GLint) height);
416   glMatrixMode(GL_PROJECTION);
417   glLoadIdentity();
418
419   gluPerspective( 30.0, 1/h, 1.0, 100.0 );
420   gluLookAt( 0.0, 0.0, 15.0,
421              0.0, 0.0, 0.0,
422              0.0, 1.0, 0.0);
423   glMatrixMode(GL_MODELVIEW);
424   glLoadIdentity();
425   glTranslatef(0.0, 0.0, -15.0);
426   
427   glClear(GL_COLOR_BUFFER_BIT);
428 }
429
430 static void
431 pinit(ModeInfo *mi)
432 {
433   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
434
435   /* draw the gasket */
436   gp->gasket0 = glGenLists(1);
437   gp->gasket1 = glGenLists(1);
438   gp->gasket2 = glGenLists(1);
439   gp->gasket3 = glGenLists(1);
440   gp->current_depth = 1;       /* start out at level 1, not 0 */
441 }
442
443
444
445 /* lifted from lament.c */
446 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
447 #define RANDSIGN() ((random() & 1) ? 1 : -1)
448
449 static void
450 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
451 {
452   double ppos = *pos;
453
454   /* tick position */
455   if (ppos < 0)
456     ppos = -(ppos + *v);
457   else
458     ppos += *v;
459
460   if (ppos > 1.0)
461     ppos -= 1.0;
462   else if (ppos < 0)
463     ppos += 1.0;
464
465   if (ppos < 0) abort();
466   if (ppos > 1.0) abort();
467   *pos = (*pos > 0 ? ppos : -ppos);
468
469   /* accelerate */
470   *v += *dv;
471
472   /* clamp velocity */
473   if (*v > max_v || *v < -max_v)
474     {
475       *dv = -*dv;
476     }
477   /* If it stops, start it going in the other direction. */
478   else if (*v < 0)
479     {
480       if (random() % 4)
481         {
482           *v = 0;
483
484           /* keep going in the same direction */
485           if (random() % 2)
486             *dv = 0;
487           else if (*dv < 0)
488             *dv = -*dv;
489         }
490       else
491         {
492           /* reverse gears */
493           *v = -*v;
494           *dv = -*dv;
495           *pos = -*pos;
496         }
497     }
498
499   /* Alter direction of rotational acceleration randomly. */
500   if (! (random() % 120))
501     *dv = -*dv;
502
503   /* Change acceleration very occasionally. */
504   if (! (random() % 200))
505     {
506       if (*dv == 0)
507         *dv = 0.00001;
508       else if (random() & 1)
509         *dv *= 1.2;
510       else
511         *dv *= 0.8;
512     }
513 }
514
515
516 void
517 init_gasket(ModeInfo *mi)
518 {
519   int           screen = MI_SCREEN(mi);
520   gasketstruct *gp;
521
522   if (gasket == NULL)
523   {
524     if ((gasket = (gasketstruct *) calloc(MI_NUM_SCREENS(mi),
525                                               sizeof (gasketstruct))) == NULL)
526         return;
527   }
528   gp = &gasket[screen];
529
530   gp->window = MI_WINDOW(mi);
531
532   gp->rotx = frand(1.0) * RANDSIGN();
533   gp->roty = frand(1.0) * RANDSIGN();
534   gp->rotz = frand(1.0) * RANDSIGN();
535
536   /* bell curve from 0-1.5 degrees, avg 0.75 */
537   gp->dx = (frand(1) + frand(1) + frand(1)) / (360*2);
538   gp->dy = (frand(1) + frand(1) + frand(1)) / (360*2);
539   gp->dz = (frand(1) + frand(1) + frand(1)) / (360*2);
540
541   gp->d_max = gp->dx * 2;
542
543   gp->ddx = 0.00006 + frand(0.00003);
544   gp->ddy = 0.00006 + frand(0.00003);
545   gp->ddz = 0.00006 + frand(0.00003);
546
547   gp->ncolors = 255;
548   gp->colors = (XColor *) calloc(gp->ncolors, sizeof(XColor));
549   make_smooth_colormap (0, 0, 0,
550                         gp->colors, &gp->ncolors,
551                         False, 0, False);
552   gp->ccolor0 = 0;
553   gp->ccolor1 = gp->ncolors * 0.25;
554   gp->ccolor2 = gp->ncolors * 0.5;
555   gp->ccolor3 = gp->ncolors * 0.75;
556
557   if ((gp->glx_context = init_GL(mi)) != NULL)
558   {
559     reshape_gasket(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
560     pinit(mi);
561   }
562   else
563   {
564     MI_CLEARWINDOW(mi);
565   }
566 }
567
568 void
569 draw_gasket(ModeInfo * mi)
570 {
571   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
572   Display      *display = MI_DISPLAY(mi);
573   Window        window = MI_WINDOW(mi);
574   int           angle_incr = 1;
575
576   if (!gp->glx_context) return;
577
578   glDrawBuffer(GL_BACK);
579
580   if (max_depth > 10)
581     max_depth = 10;
582
583   glXMakeCurrent(display, window, *(gp->glx_context));
584   draw(mi);
585
586   /* rotate */
587   gp->angle = (int) (gp->angle + angle_incr) % 360;
588
589   rotate(&gp->rotx, &gp->dx, &gp->ddx, gp->d_max);
590   rotate(&gp->roty, &gp->dy, &gp->ddy, gp->d_max);
591   rotate(&gp->rotz, &gp->dz, &gp->ddz, gp->d_max);
592
593   if (mi->fps_p) do_fps (mi);
594   glFinish();
595   glXSwapBuffers(display, window);
596 }
597
598 void
599 release_gasket(ModeInfo * mi)
600 {
601   if (gasket != NULL)
602   {
603     int         screen;
604
605     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
606     {
607       gasketstruct *gp = &gasket[screen];
608
609       if (gp->glx_context)
610       {
611         /* Display lists MUST be freed while their glXContext is current. */
612         glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
613
614         if (glIsList(gp->gasket0)) glDeleteLists(gp->gasket0, 1);
615         if (glIsList(gp->gasket1)) glDeleteLists(gp->gasket1, 1);
616         if (glIsList(gp->gasket2)) glDeleteLists(gp->gasket2, 1);
617         if (glIsList(gp->gasket3)) glDeleteLists(gp->gasket3, 1);
618       }
619     }
620     (void) free((void *) gasket);
621     gasket = NULL;
622   }
623   FreeAllGL(mi);
624 }
625
626
627 /*********************************************************/
628
629 #endif