http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.03.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              int *countP)
137 {
138   if (countdown <= 0)
139     {
140       (*countP)++;
141       if (which == 0)
142         {
143           glNormal3f (normals[0][0], normals[0][1], normals[0][2]);
144           triangle (outer[0].x, outer[0].y, outer[0].z,
145                     outer[1].x, outer[1].y, outer[1].z,
146                     outer[2].x, outer[2].y, outer[2].z,
147                     wireframe_p);
148         }
149       else if (which == 1)
150         {
151           glNormal3f (normals[1][0], normals[1][1], normals[1][2]);
152           triangle (outer[0].x, outer[0].y, outer[0].z,
153                     outer[3].x, outer[3].y, outer[3].z,
154                     outer[1].x, outer[1].y, outer[1].z,
155                     wireframe_p);
156         }
157       else if (which == 2)
158         {
159           glNormal3f (normals[2][0], normals[2][1], normals[2][2]);
160           triangle (outer[0].x, outer[0].y, outer[0].z,
161                     outer[2].x, outer[2].y, outer[2].z,
162                     outer[3].x, outer[3].y, outer[3].z,
163                     wireframe_p);
164         }
165       else
166         {
167           glNormal3f (normals[3][0], normals[3][1], normals[3][2]);
168           triangle (outer[1].x, outer[1].y, outer[1].z,
169                     outer[3].x, outer[3].y, outer[3].z,
170                     outer[2].x, outer[2].y, outer[2].z,
171                     wireframe_p);
172         }
173     }
174   else
175     {
176 #     define M01 0
177 #     define M02 1
178 #     define M03 2
179 #     define M12 3
180 #     define M13 4
181 #     define M23 5
182       GL_VECTOR inner[M23+1];
183       GL_VECTOR corner[4];
184
185       inner[M01].x = (outer[0].x + outer[1].x) / 2.0;
186       inner[M01].y = (outer[0].y + outer[1].y) / 2.0;
187       inner[M01].z = (outer[0].z + outer[1].z) / 2.0;
188
189       inner[M02].x = (outer[0].x + outer[2].x) / 2.0;
190       inner[M02].y = (outer[0].y + outer[2].y) / 2.0;
191       inner[M02].z = (outer[0].z + outer[2].z) / 2.0;
192
193       inner[M03].x = (outer[0].x + outer[3].x) / 2.0;
194       inner[M03].y = (outer[0].y + outer[3].y) / 2.0;
195       inner[M03].z = (outer[0].z + outer[3].z) / 2.0;
196
197       inner[M12].x = (outer[1].x + outer[2].x) / 2.0;
198       inner[M12].y = (outer[1].y + outer[2].y) / 2.0;
199       inner[M12].z = (outer[1].z + outer[2].z) / 2.0;
200
201       inner[M13].x = (outer[1].x + outer[3].x) / 2.0;
202       inner[M13].y = (outer[1].y + outer[3].y) / 2.0;
203       inner[M13].z = (outer[1].z + outer[3].z) / 2.0;
204
205       inner[M23].x = (outer[2].x + outer[3].x) / 2.0;
206       inner[M23].y = (outer[2].y + outer[3].y) / 2.0;
207       inner[M23].z = (outer[2].z + outer[3].z) / 2.0;
208
209       countdown--;
210
211       corner[0] = outer[0];
212       corner[1] = inner[M01];
213       corner[2] = inner[M02];
214       corner[3] = inner[M03];
215       four_tetras (corner, wireframe_p, countdown, which, countP);
216
217       corner[0] = inner[M01];
218       corner[1] = outer[1];
219       corner[2] = inner[M12];
220       corner[3] = inner[M13];
221       four_tetras (corner, wireframe_p, countdown, which, countP);
222
223       corner[0] = inner[M02];
224       corner[1] = inner[M12];
225       corner[2] = outer[2];
226       corner[3] = inner[M23];
227       four_tetras (corner, wireframe_p, countdown, which, countP);
228
229       corner[0] = inner[M03];
230       corner[1] = inner[M13];
231       corner[2] = inner[M23];
232       corner[3] = outer[3];
233       four_tetras (corner, wireframe_p, countdown, which, countP);
234     }
235 }
236
237
238 static void
239 compile_gasket(ModeInfo *mi, int which)
240 {
241   Bool wireframe_p = MI_IS_WIREFRAME(mi);
242   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
243   int count;
244
245   GL_VECTOR   vertex[5];
246
247   normals[0][0] =  0;
248   normals[0][1] =  0;
249   normals[0][2] = -sqrt(2.0 / 3.0);
250
251   normals[1][0] =  0;
252   normals[1][1] = -sqrt(0.75);
253   normals[1][2] =  sqrt(2.0 / 3.0) / 3.0;
254
255   normals[2][0] =  sqrt (0.5);
256   normals[2][1] =  sqrt(0.75) / 2.0;
257   normals[2][2] =  normals[1][2];
258
259   normals[3][0] = -normals[2][0];
260   normals[3][1] =  normals[2][1];
261   normals[3][2] =  normals[1][2];
262
263
264   /* define verticies */
265   vertex[0].x =  0.5; 
266   vertex[0].y = -(1.0/3.0)*sqrt((2.0/3.0));
267   vertex[0].z = -sqrt(3.0)/6.0;
268
269   vertex[1].x = -0.5; 
270   vertex[1].y = -(1.0/3.0)*sqrt((2.0/3.0)); 
271   vertex[1].z = -sqrt(3.0)/6.0; 
272
273   vertex[2].x = 0.0; 
274   vertex[2].y = (2.0/3.0)*sqrt((2.0/3.0));
275   vertex[2].z = -sqrt(3.0)/6.0; 
276
277   vertex[3].x = 0.0; 
278   vertex[3].y = 0.0; 
279   vertex[3].z = sqrt(3.0)/3.0; 
280
281   vertex[4].x = 0.0;
282   vertex[4].y = 0.0; 
283   vertex[4].z = 0.0;
284   
285   count = 0;
286   four_tetras (vertex, wireframe_p,
287                (gp->current_depth < 0
288                 ? -gp->current_depth : gp->current_depth),
289                which,
290                &count);
291   mi->polygon_count = count;
292 }
293
294 static void
295 draw(ModeInfo *mi)
296 {
297   Bool wireframe_p = MI_IS_WIREFRAME(mi);
298   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
299   static int tick = 999999;
300   
301   static GLfloat pos[4] = {-4.0, 3.0, 10.0, 1.0};
302   static float white[]  = {1.0, 1.0, 1.0, 1.0};
303   static float color0[] = {0.0, 0.0, 0.0, 1.0};
304   static float color1[] = {0.0, 0.0, 0.0, 1.0};
305   static float color2[] = {0.0, 0.0, 0.0, 1.0};
306   static float color3[] = {0.0, 0.0, 0.0, 1.0};
307
308   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
309
310   if (!wireframe_p)
311     {
312       glColor4fv (white);
313
314       glLightfv(GL_LIGHT0, GL_POSITION,  pos);
315
316       color0[0] = gp->colors[gp->ccolor0].red   / 65536.0;
317       color0[1] = gp->colors[gp->ccolor0].green / 65536.0;
318       color0[2] = gp->colors[gp->ccolor0].blue  / 65536.0;
319
320       color1[0] = gp->colors[gp->ccolor1].red   / 65536.0;
321       color1[1] = gp->colors[gp->ccolor1].green / 65536.0;
322       color1[2] = gp->colors[gp->ccolor1].blue  / 65536.0;
323
324       color2[0] = gp->colors[gp->ccolor2].red   / 65536.0;
325       color2[1] = gp->colors[gp->ccolor2].green / 65536.0;
326       color2[2] = gp->colors[gp->ccolor2].blue  / 65536.0;
327
328       color3[0] = gp->colors[gp->ccolor3].red   / 65536.0;
329       color3[1] = gp->colors[gp->ccolor3].green / 65536.0;
330       color3[2] = gp->colors[gp->ccolor3].blue  / 65536.0;
331
332       gp->ccolor0++;
333       gp->ccolor1++;
334       gp->ccolor2++;
335       gp->ccolor3++;
336       if (gp->ccolor0 >= gp->ncolors) gp->ccolor0 = 0;
337       if (gp->ccolor1 >= gp->ncolors) gp->ccolor1 = 0;
338       if (gp->ccolor2 >= gp->ncolors) gp->ccolor2 = 0;
339       if (gp->ccolor3 >= gp->ncolors) gp->ccolor3 = 0;
340
341       glShadeModel(GL_SMOOTH);
342
343       glEnable(GL_LIGHTING);
344       glEnable(GL_LIGHT0);
345     }
346
347   glEnable(GL_DEPTH_TEST);
348   glEnable(GL_NORMALIZE);
349   glEnable(GL_CULL_FACE);
350
351   glPushMatrix();
352
353   {
354     static int frame = 0;
355     GLfloat x, y, z;
356
357 #   define SINOID(SCALE,SIZE) \
358       ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
359     x = SINOID(0.0071, 8.0);
360     y = SINOID(0.0053, 6.0);
361     z = SINOID(0.0037, 15.0);
362     frame++;
363     glTranslatef(x, y, z);
364
365     x = gp->rotx;
366     y = gp->roty;
367     z = gp->rotz;
368     if (x < 0) x = 1 - (x + 1);
369     if (y < 0) y = 1 - (y + 1);
370     if (z < 0) z = 1 - (z + 1);
371     glRotatef(x * 360, 1.0, 0.0, 0.0);
372     glRotatef(y * 360, 0.0, 1.0, 0.0);
373     glRotatef(z * 360, 0.0, 0.0, 1.0);
374   }
375
376   glScalef( 8.0, 8.0, 8.0 );
377
378   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color0);
379   glCallList(gp->gasket0);
380   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color1);
381   glCallList(gp->gasket1);
382   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color2);
383   glCallList(gp->gasket2);
384   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color3);
385   glCallList(gp->gasket3);
386
387   glPopMatrix();
388
389
390   if (tick++ >= speed)
391     {
392       tick = 0;
393       if (gp->current_depth >= max_depth)
394         gp->current_depth = -max_depth;
395       gp->current_depth++;
396
397       /* We make four different lists so that each face of the tetrahedrons
398          can have a different color (all triangles facing in the same
399          direction have the same color, which is different from all
400          triangles facing in other directions.)
401        */
402       glDeleteLists (gp->gasket0, 1);
403       glDeleteLists (gp->gasket1, 1);
404       glDeleteLists (gp->gasket2, 1);
405       glDeleteLists (gp->gasket3, 1);
406
407       mi->polygon_count = 0;
408       glNewList (gp->gasket0, GL_COMPILE); compile_gasket (mi, 0); glEndList();
409       glNewList (gp->gasket1, GL_COMPILE); compile_gasket (mi, 1); glEndList();
410       glNewList (gp->gasket2, GL_COMPILE); compile_gasket (mi, 2); glEndList();
411       glNewList (gp->gasket3, GL_COMPILE); compile_gasket (mi, 3); glEndList();
412
413     }
414 }
415
416
417 /* new window size or exposure */
418 void
419 reshape_gasket(ModeInfo *mi, int width, int height)
420 {
421   GLfloat h = (GLfloat) height / (GLfloat) width;
422
423   glViewport(0, 0, (GLint) width, (GLint) height);
424   glMatrixMode(GL_PROJECTION);
425   glLoadIdentity();
426
427   gluPerspective( 30.0, 1/h, 1.0, 100.0 );
428   gluLookAt( 0.0, 0.0, 15.0,
429              0.0, 0.0, 0.0,
430              0.0, 1.0, 0.0);
431   glMatrixMode(GL_MODELVIEW);
432   glLoadIdentity();
433   glTranslatef(0.0, 0.0, -15.0);
434   
435   glClear(GL_COLOR_BUFFER_BIT);
436 }
437
438 static void
439 pinit(ModeInfo *mi)
440 {
441   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
442
443   /* draw the gasket */
444   gp->gasket0 = glGenLists(1);
445   gp->gasket1 = glGenLists(1);
446   gp->gasket2 = glGenLists(1);
447   gp->gasket3 = glGenLists(1);
448   gp->current_depth = 1;       /* start out at level 1, not 0 */
449 }
450
451
452
453 /* lifted from lament.c */
454 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
455 #define RANDSIGN() ((random() & 1) ? 1 : -1)
456
457 static void
458 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
459 {
460   double ppos = *pos;
461
462   /* tick position */
463   if (ppos < 0)
464     ppos = -(ppos + *v);
465   else
466     ppos += *v;
467
468   if (ppos > 1.0)
469     ppos -= 1.0;
470   else if (ppos < 0)
471     ppos += 1.0;
472
473   if (ppos < 0) abort();
474   if (ppos > 1.0) abort();
475   *pos = (*pos > 0 ? ppos : -ppos);
476
477   /* accelerate */
478   *v += *dv;
479
480   /* clamp velocity */
481   if (*v > max_v || *v < -max_v)
482     {
483       *dv = -*dv;
484     }
485   /* If it stops, start it going in the other direction. */
486   else if (*v < 0)
487     {
488       if (random() % 4)
489         {
490           *v = 0;
491
492           /* keep going in the same direction */
493           if (random() % 2)
494             *dv = 0;
495           else if (*dv < 0)
496             *dv = -*dv;
497         }
498       else
499         {
500           /* reverse gears */
501           *v = -*v;
502           *dv = -*dv;
503           *pos = -*pos;
504         }
505     }
506
507   /* Alter direction of rotational acceleration randomly. */
508   if (! (random() % 120))
509     *dv = -*dv;
510
511   /* Change acceleration very occasionally. */
512   if (! (random() % 200))
513     {
514       if (*dv == 0)
515         *dv = 0.00001;
516       else if (random() & 1)
517         *dv *= 1.2;
518       else
519         *dv *= 0.8;
520     }
521 }
522
523
524 void
525 init_gasket(ModeInfo *mi)
526 {
527   int           screen = MI_SCREEN(mi);
528   gasketstruct *gp;
529
530   if (gasket == NULL)
531   {
532     if ((gasket = (gasketstruct *) calloc(MI_NUM_SCREENS(mi),
533                                               sizeof (gasketstruct))) == NULL)
534         return;
535   }
536   gp = &gasket[screen];
537
538   gp->window = MI_WINDOW(mi);
539
540   gp->rotx = frand(1.0) * RANDSIGN();
541   gp->roty = frand(1.0) * RANDSIGN();
542   gp->rotz = frand(1.0) * RANDSIGN();
543
544   /* bell curve from 0-1.5 degrees, avg 0.75 */
545   gp->dx = (frand(1) + frand(1) + frand(1)) / (360*2);
546   gp->dy = (frand(1) + frand(1) + frand(1)) / (360*2);
547   gp->dz = (frand(1) + frand(1) + frand(1)) / (360*2);
548
549   gp->d_max = gp->dx * 2;
550
551   gp->ddx = 0.00006 + frand(0.00003);
552   gp->ddy = 0.00006 + frand(0.00003);
553   gp->ddz = 0.00006 + frand(0.00003);
554
555   gp->ncolors = 255;
556   gp->colors = (XColor *) calloc(gp->ncolors, sizeof(XColor));
557   make_smooth_colormap (0, 0, 0,
558                         gp->colors, &gp->ncolors,
559                         False, 0, False);
560   gp->ccolor0 = 0;
561   gp->ccolor1 = gp->ncolors * 0.25;
562   gp->ccolor2 = gp->ncolors * 0.5;
563   gp->ccolor3 = gp->ncolors * 0.75;
564
565   if ((gp->glx_context = init_GL(mi)) != NULL)
566   {
567     reshape_gasket(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
568     pinit(mi);
569   }
570   else
571   {
572     MI_CLEARWINDOW(mi);
573   }
574 }
575
576 void
577 draw_gasket(ModeInfo * mi)
578 {
579   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
580   Display      *display = MI_DISPLAY(mi);
581   Window        window = MI_WINDOW(mi);
582   int           angle_incr = 1;
583
584   if (!gp->glx_context) return;
585
586   glDrawBuffer(GL_BACK);
587
588   if (max_depth > 10)
589     max_depth = 10;
590
591   glXMakeCurrent(display, window, *(gp->glx_context));
592   draw(mi);
593
594   /* rotate */
595   gp->angle = (int) (gp->angle + angle_incr) % 360;
596
597   rotate(&gp->rotx, &gp->dx, &gp->ddx, gp->d_max);
598   rotate(&gp->roty, &gp->dy, &gp->ddy, gp->d_max);
599   rotate(&gp->rotz, &gp->dz, &gp->ddz, gp->d_max);
600
601   if (mi->fps_p) do_fps (mi);
602   glFinish();
603   glXSwapBuffers(display, window);
604 }
605
606 void
607 release_gasket(ModeInfo * mi)
608 {
609   if (gasket != NULL)
610   {
611     int         screen;
612
613     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
614     {
615       gasketstruct *gp = &gasket[screen];
616
617       if (gp->glx_context)
618       {
619         /* Display lists MUST be freed while their glXContext is current. */
620         glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
621
622         if (glIsList(gp->gasket0)) glDeleteLists(gp->gasket0, 1);
623         if (glIsList(gp->gasket1)) glDeleteLists(gp->gasket1, 1);
624         if (glIsList(gp->gasket2)) glDeleteLists(gp->gasket2, 1);
625         if (glIsList(gp->gasket3)) glDeleteLists(gp->gasket3, 1);
626       }
627     }
628     (void) free((void *) gasket);
629     gasket = NULL;
630   }
631   FreeAllGL(mi);
632 }
633
634
635 /*********************************************************/
636
637 #endif