http://packetstorm.tacticalflex.com/UNIX/admin/xscreensaver-3.27.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 gasket_opts                            xlockmore_opts
42 # define DEFAULTS       "*count:                1       \n"                     \
43                         "*cycles:               9999    \n"                     \
44                         "*delay:                20000   \n"                     \
45                         "*maxDepth:             5       \n"                     \
46                         "*speed:                150     \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     view_rotx, view_roty, view_rotz;
90   GLfloat     light_colour[4];/* = {6.0, 6.0, 6.0, 1.0}; */
91   GLfloat     pos[3];/* = {0.0, 0.0, 0.0}; */
92   GLfloat     xinc,yinc,zinc;
93   GLfloat     angle;
94   GLuint      gasket1;
95   GLXContext *glx_context;
96   Window      window;
97
98   int current_depth;
99
100 } gasketstruct;
101
102 static gasketstruct *gasket = NULL;
103
104 #include <GL/glu.h>
105
106 /* static GLuint limit; */
107
108 \f
109 /* Computing normal vectors (thanks to Nat Friedman <ndf@mit.edu>)
110  */
111
112 typedef struct vector {
113   GLfloat x, y, z;
114 } vector;
115
116 typedef struct plane {
117   vector p1, p2, p3;
118 } plane;
119
120 static void
121 vector_set(vector *v, GLfloat x, GLfloat y, GLfloat z)
122 {
123   v->x = x;
124   v->y = y;
125   v->z = z;
126 }
127
128 static void
129 vector_cross(vector v1, vector v2, vector *v3)
130 {
131   v3->x = (v1.y * v2.z) - (v1.z * v2.y);
132   v3->y = (v1.z * v2.x) - (v1.x * v2.z);
133   v3->z = (v1.x * v2.y) - (v1.y * v2.x);
134 }
135
136 static void
137 vector_subtract(vector v1, vector v2, vector *res)
138 {
139   res->x = v1.x - v2.x;
140   res->y = v1.y - v2.y;
141   res->z = v1.z - v2.z;
142 }
143
144 static void
145 plane_normal(plane p, vector *n)
146 {
147   vector v1, v2;
148   vector_subtract(p.p1, p.p2, &v1);
149   vector_subtract(p.p1, p.p3, &v2);
150   vector_cross(v2, v1, n);
151 }
152
153 static void
154 do_normal(GLfloat x1, GLfloat y1, GLfloat z1,
155           GLfloat x2, GLfloat y2, GLfloat z2,
156           GLfloat x3, GLfloat y3, GLfloat z3)
157 {
158   plane plane;
159   vector n;
160   vector_set(&plane.p1, x1, y1, z1);
161   vector_set(&plane.p2, x2, y2, z2);
162   vector_set(&plane.p3, x3, y3, z3);
163   plane_normal(plane, &n);
164   n.x = -n.x; n.y = -n.y; n.z = -n.z;
165
166   glNormal3f(n.x, n.y, n.z);
167
168 #ifdef DEBUG
169   /* Draw a line in the direction of this face's normal. */
170   {
171     GLfloat ax = n.x > 0 ? n.x : -n.x;
172     GLfloat ay = n.y > 0 ? n.y : -n.y;
173     GLfloat az = n.z > 0 ? n.z : -n.z;
174     GLfloat mx = (x1 + x2 + x3) / 3;
175     GLfloat my = (y1 + y2 + y3) / 3;
176     GLfloat mz = (z1 + z2 + z3) / 3;
177     GLfloat xx, yy, zz;
178
179     GLfloat max = ax > ay ? ax : ay;
180     if (az > max) max = az;
181     max *= 2;
182     xx = n.x / max;
183     yy = n.y / max;
184     zz = n.z / max;
185
186     glBegin(GL_LINE_LOOP);
187     glVertex3f(mx, my, mz);
188     glVertex3f(mx+xx, my+yy, mz+zz);
189     glEnd();
190   }
191 #endif /* DEBUG */
192 }
193
194 \f
195
196 static void
197 triangle (GLfloat x1, GLfloat y1, GLfloat z1,
198           GLfloat x2, GLfloat y2, GLfloat z2,
199           GLfloat x3, GLfloat y3, GLfloat z3,
200           Bool wireframe_p)
201 {
202   if (wireframe_p)
203     glBegin (GL_LINE_LOOP);
204   else
205     {
206       do_normal (x1, y1, z1,  x2, y2, z2,  x3, y3, z3);
207       glBegin (GL_TRIANGLES);
208     }
209   glVertex3f (x1, y1, z1);
210   glVertex3f (x2, y2, z2);
211   glVertex3f (x3, y3, z3);
212   glEnd();
213 }
214
215 static void
216 four_tetras (GL_VECTOR *outer, Bool wireframe_p, int countdown)
217 {
218   if (countdown <= 0)
219     {
220       triangle (outer[0].x, outer[0].y, outer[0].z,
221                 outer[1].x, outer[1].y, outer[1].z,
222                 outer[2].x, outer[2].y, outer[2].z,
223                 wireframe_p);
224       triangle (outer[0].x, outer[0].y, outer[0].z,
225                 outer[3].x, outer[3].y, outer[3].z,
226                 outer[1].x, outer[1].y, outer[1].z,
227                 wireframe_p);
228       triangle (outer[0].x, outer[0].y, outer[0].z,
229                 outer[2].x, outer[2].y, outer[2].z,
230                 outer[3].x, outer[3].y, outer[3].z,
231                 wireframe_p);
232       triangle (outer[1].x, outer[1].y, outer[1].z,
233                 outer[3].x, outer[3].y, outer[3].z,
234                 outer[2].x, outer[2].y, outer[2].z,
235                 wireframe_p);
236     }
237   else
238     {
239 #     define M01 0
240 #     define M02 1
241 #     define M03 2
242 #     define M12 3
243 #     define M13 4
244 #     define M23 5
245       GL_VECTOR inner[M23+1];
246       GL_VECTOR corner[4];
247
248       inner[M01].x = (outer[0].x + outer[1].x) / 2.0;
249       inner[M01].y = (outer[0].y + outer[1].y) / 2.0;
250       inner[M01].z = (outer[0].z + outer[1].z) / 2.0;
251
252       inner[M02].x = (outer[0].x + outer[2].x) / 2.0;
253       inner[M02].y = (outer[0].y + outer[2].y) / 2.0;
254       inner[M02].z = (outer[0].z + outer[2].z) / 2.0;
255
256       inner[M03].x = (outer[0].x + outer[3].x) / 2.0;
257       inner[M03].y = (outer[0].y + outer[3].y) / 2.0;
258       inner[M03].z = (outer[0].z + outer[3].z) / 2.0;
259
260       inner[M12].x = (outer[1].x + outer[2].x) / 2.0;
261       inner[M12].y = (outer[1].y + outer[2].y) / 2.0;
262       inner[M12].z = (outer[1].z + outer[2].z) / 2.0;
263
264       inner[M13].x = (outer[1].x + outer[3].x) / 2.0;
265       inner[M13].y = (outer[1].y + outer[3].y) / 2.0;
266       inner[M13].z = (outer[1].z + outer[3].z) / 2.0;
267
268       inner[M23].x = (outer[2].x + outer[3].x) / 2.0;
269       inner[M23].y = (outer[2].y + outer[3].y) / 2.0;
270       inner[M23].z = (outer[2].z + outer[3].z) / 2.0;
271
272       countdown--;
273
274       corner[0] = outer[0];
275       corner[1] = inner[M01];
276       corner[2] = inner[M02];
277       corner[3] = inner[M03];
278       four_tetras (corner, wireframe_p, countdown);
279
280       corner[0] = inner[M01];
281       corner[1] = outer[1];
282       corner[2] = inner[M12];
283       corner[3] = inner[M13];
284       four_tetras (corner, wireframe_p, countdown);
285
286       corner[0] = inner[M02];
287       corner[1] = inner[M12];
288       corner[2] = outer[2];
289       corner[3] = inner[M23];
290       four_tetras (corner, wireframe_p, countdown);
291
292       corner[0] = inner[M03];
293       corner[1] = inner[M13];
294       corner[2] = inner[M23];
295       corner[3] = outer[3];
296       four_tetras (corner, wireframe_p, countdown);
297     }
298 }
299
300
301 static void
302 compile_gasket(ModeInfo *mi)
303 {
304   Bool wireframe_p = MI_IS_WIREFRAME(mi);
305   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
306
307   GL_VECTOR   vertex[5];
308
309   /* define verticies */
310   vertex[0].x =  0.5; 
311   vertex[0].y = -(1.0/3.0)*sqrt((2.0/3.0));
312   vertex[0].z = -sqrt(3.0)/6.0;
313
314   vertex[1].x = -0.5; 
315   vertex[1].y = -(1.0/3.0)*sqrt((2.0/3.0)); 
316   vertex[1].z = -sqrt(3.0)/6.0; 
317
318   vertex[2].x = 0.0; 
319   vertex[2].y = (2.0/3.0)*sqrt((2.0/3.0));
320   vertex[2].z = -sqrt(3.0)/6.0; 
321
322   vertex[3].x = 0.0; 
323   vertex[3].y = 0.0; 
324   vertex[3].z = sqrt(3.0)/3.0; 
325
326   vertex[4].x = 0.0;
327   vertex[4].y = 0.0; 
328   vertex[4].z = 0.0;
329   
330   four_tetras (vertex, wireframe_p,
331                (gp->current_depth < 0
332                 ? -gp->current_depth : gp->current_depth));
333 }
334
335 static void
336 draw(ModeInfo *mi)
337 {
338   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
339   static int tick = 0;
340   
341   static float position0[] = {-0.5,  1.2, 0.5, 0.0};
342   static float ambient0[]  = {0.4, 0.6, 0.4, 1.0};
343   static float spec[]      = {0.7, 0.7, 0.7, 1.0};
344
345   glLightfv(GL_LIGHT0, GL_POSITION,  position0);
346   glLightfv(GL_LIGHT0, GL_AMBIENT,   ambient0);
347   glLightfv(GL_LIGHT0, GL_SPECULAR,  spec);
348   glLightfv(GL_LIGHT0, GL_DIFFUSE,   gp->light_colour);
349
350   glShadeModel(GL_SMOOTH);
351
352   glEnable(GL_LIGHTING);
353   glEnable(GL_LIGHT0);
354
355   glEnable(GL_DEPTH_TEST);
356   glEnable(GL_NORMALIZE);
357   glEnable(GL_CULL_FACE);
358
359   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
360
361   glPushMatrix();
362   glTranslatef( gp->pos[0], gp->pos[1], gp->pos[2] );  
363
364   glPushMatrix();
365   glRotatef(2*gp->angle, 1.0, 0.0, 0.0);
366   glRotatef(3*gp->angle, 0.0, 1.0, 0.0);
367   glRotatef(  gp->angle, 0.0, 0.0, 1.0);
368   glScalef( 8.0, 8.0, 8.0 );
369   glCallList(gp->gasket1);
370   
371   glPopMatrix();
372
373   glPopMatrix();
374
375
376   if (tick++ >= speed)
377     {
378       tick = 0;
379       if (gp->current_depth >= max_depth)
380         gp->current_depth = -max_depth;
381       gp->current_depth++;
382
383       glDeleteLists (gp->gasket1, 1);
384       glNewList (gp->gasket1, GL_COMPILE);
385       compile_gasket (mi);
386       glEndList();
387
388       /* do the colour change */
389       gp->light_colour[0] = 3.0*SINF(gp->angle/20.0) + 4.0;
390       gp->light_colour[1] = 3.0*SINF(gp->angle/30.0) + 4.0;
391       gp->light_colour[2] = 3.0*SINF(gp->angle/60.0) + 4.0;
392     }
393 }
394
395
396 /* new window size or exposure */
397 static void
398 reshape(int width, int height)
399 {
400   GLfloat h = (GLfloat) height / (GLfloat) width;
401
402   glViewport(0, 0, (GLint) width, (GLint) height);
403   glMatrixMode(GL_PROJECTION);
404   glLoadIdentity();
405
406   gluPerspective( 30.0, 1/h, 1.0, 100.0 );
407   gluLookAt( 0.0, 0.0, 15.0,
408              0.0, 0.0, 0.0,
409              0.0, 1.0, 0.0);
410   glMatrixMode(GL_MODELVIEW);
411   glLoadIdentity();
412   glTranslatef(0.0, 0.0, -15.0);
413   
414   /* The depth buffer will be cleared, if needed, before the
415   * next frame.  Right now we just want to black the screen.
416   */
417   glClear(GL_COLOR_BUFFER_BIT);
418 }
419
420 static void
421 pinit(ModeInfo *mi)
422 {
423   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
424
425   gp->xinc = 0.1*(1.0*random()/RAND_MAX);
426   gp->yinc = 0.1*(1.0*random()/RAND_MAX);
427   gp->zinc = 0.1*(1.0*random()/RAND_MAX);
428   gp->light_colour[0] = 6.0;
429   gp->light_colour[1] = 6.0;
430   gp->light_colour[2] = 6.0;
431   gp->light_colour[3] = 1.0;
432   gp->pos[0] = 0.0;     
433   gp->pos[1] = 0.0;
434   gp->pos[2] = 0.0;    
435   /* draw the gasket */
436   gp->gasket1 = glGenLists(1);
437   gp->current_depth = 1;       /* start out at level 1, not 0 */
438   glNewList(gp->gasket1, GL_COMPILE);
439     compile_gasket(mi);
440   glEndList();
441 }
442
443 void
444 init_gasket(ModeInfo *mi)
445 {
446   int           screen = MI_SCREEN(mi);
447   gasketstruct *gp;
448
449   if (gasket == NULL)
450   {
451     if ((gasket = (gasketstruct *) calloc(MI_NUM_SCREENS(mi),
452                                               sizeof (gasketstruct))) == NULL)
453         return;
454   }
455   gp = &gasket[screen];
456
457   gp->window = MI_WINDOW(mi);
458   gp->view_rotx = NRAND(360);
459   gp->view_roty = NRAND(360);
460   gp->view_rotz = NRAND(360);
461   gp->angle = NRAND(360)/90.0;
462
463   if ((gp->glx_context = init_GL(mi)) != NULL)
464   {
465     reshape(MI_WIDTH(mi), MI_HEIGHT(mi));
466     pinit(mi);
467   }
468   else
469   {
470     MI_CLEARWINDOW(mi);
471   }
472 }
473
474 void
475 draw_gasket(ModeInfo * mi)
476 {
477   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
478   Display      *display = MI_DISPLAY(mi);
479   Window        window = MI_WINDOW(mi);
480   int           angle_incr = 1;
481   int           rot_incr = 1;/*MI_COUNT(mi) ? MI_COUNT(mi) : 1;*/
482
483   if (!gp->glx_context) return;
484
485   glDrawBuffer(GL_BACK);
486
487   if (max_depth > 10)
488     max_depth = 10;
489
490   glXMakeCurrent(display, window, *(gp->glx_context));
491   draw(mi);
492
493   /* rotate */
494   gp->angle = (int) (gp->angle + angle_incr) % 360;
495   if ( FABSF( gp->pos[0] ) > 8.0 ) gp->xinc = -1.0 * gp->xinc;
496   if ( FABSF( gp->pos[1] ) > 6.0 ) gp->yinc = -1.0 * gp->yinc;
497   if ( FABSF( gp->pos[2] ) >15.0 ) gp->zinc = -1.0 * gp->zinc;
498   gp->pos[0] += gp->xinc;
499   gp->pos[1] += gp->yinc;
500   gp->pos[2] += gp->zinc;    
501   gp->view_rotx = (int) (gp->view_rotx + rot_incr) % 360;
502   gp->view_roty = (int) (gp->view_roty +(rot_incr/2.0)) % 360;
503   gp->view_rotz = (int) (gp->view_rotz +(rot_incr/3.0)) % 360;
504
505   glFinish();
506   glXSwapBuffers(display, window);
507 }
508
509 void
510 release_gasket(ModeInfo * mi)
511 {
512   if (gasket != NULL)
513   {
514     int         screen;
515
516     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
517     {
518       gasketstruct *gp = &gasket[screen];
519
520       if (gp->glx_context)
521       {
522         /* Display lists MUST be freed while their glXContext is current. */
523         glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
524
525         if (glIsList(gp->gasket1)) glDeleteLists(gp->gasket1, 1);
526       }
527     }
528     (void) free((void *) gasket);
529     gasket = NULL;
530   }
531   FreeAllGL(mi);
532 }
533
534
535 /*********************************************************/
536
537 #endif