http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.04.2.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 HACK_HANDLE_EVENT                      gasket_handle_event
43 # define EVENT_MASK                                     PointerMotionMask
44 # define gasket_opts                            xlockmore_opts
45
46
47 #define DEF_SPIN                                "True"
48 #define DEF_WANDER                              "True"
49 #define DEF_SPEED                               "150"
50 #define DEF_MAXDEPTH                    "5"
51
52 # define DEFAULTS                                       "*delay:                20000   \n"                     \
53                                                                         "*showFPS:      False   \n"                     \
54                                                                         "*wireframe:    False   \n"                     \
55                                                                         "*maxDepth:        " DEF_MAXDEPTH  "\n" \
56                                                                         "*speed:           " DEF_SPEED     "\n" \
57                                                                         "*spin:        " DEF_SPIN      "\n" \
58                                                                         "*wander:      " DEF_WANDER    "\n" \
59
60 # include "xlockmore.h"         /* from the xscreensaver distribution */
61 #else  /* !STANDALONE */
62 # include "xlock.h"                     /* from the xlockmore distribution */
63 #endif /* !STANDALONE */
64
65 #ifdef USE_GL
66
67 #include <GL/glu.h>
68 #include "rotator.h"
69 #include "gltrackball.h"
70
71 #undef countof
72 #define countof(x) (sizeof((x))/sizeof((*x)))
73
74 static int max_depth;
75 static int speed;
76 static Bool do_spin;
77 static Bool do_wander;
78
79 static XrmOptionDescRec opts[] = {
80   {"-depth", ".sierpinski3d.maxDepth", XrmoptionSepArg, (caddr_t) 0 },
81   {"-speed", ".sierpinski3d.speed",    XrmoptionSepArg, (caddr_t) 0 },
82   { "-spin",   ".spin",   XrmoptionNoArg, "True" },
83   { "+spin",   ".spin",   XrmoptionNoArg, "False" },
84   { "-wander", ".wander", XrmoptionNoArg, "True" },
85   { "+wander", ".wander", XrmoptionNoArg, "False" },
86 };
87
88 static argtype vars[] = {
89   {(caddr_t *) &do_spin,   "spin",   "Spin",   DEF_SPIN,   t_Bool},
90   {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
91   {(caddr_t *) &speed,     "speed",  "Speed",  DEF_SPEED,  t_Int},
92   {(caddr_t *) &max_depth, "maxDepth", "MaxDepth", DEF_MAXDEPTH, t_Int},
93 };
94
95
96 ModeSpecOpt gasket_opts = {countof(opts), opts, countof(vars), vars, NULL};
97
98 #ifdef USE_MODULES
99 ModStruct   gasket_description =
100 {"gasket", "init_gasket", "draw_gasket", "release_gasket",
101  "draw_gasket", "init_gasket", NULL, &gasket_opts,
102  1000, 1, 2, 1, 4, 1.0, "",
103  "Shows GL's Sierpinski gasket", 0, NULL};
104
105 #endif
106
107 typedef struct{
108   GLfloat x;
109   GLfloat y;
110   GLfloat z;
111 } GL_VECTOR;
112
113 typedef struct {
114   GLuint      gasket0, gasket1, gasket2, gasket3;
115   GLXContext *glx_context;
116   Window      window;
117   rotator    *rot;
118   trackball_state *trackball;
119   Bool            button_down_p;
120
121   int current_depth;
122
123   int ncolors;
124   XColor *colors;
125   int ccolor0;
126   int ccolor1;
127   int ccolor2;
128   int ccolor3;
129
130 } gasketstruct;
131
132 static gasketstruct *gasket = NULL;
133
134 static GLfloat normals[4][3];
135
136 \f
137
138 static void
139 triangle (GLfloat x1, GLfloat y1, GLfloat z1,
140           GLfloat x2, GLfloat y2, GLfloat z2,
141           GLfloat x3, GLfloat y3, GLfloat z3,
142           Bool wireframe_p)
143 {
144   if (wireframe_p)
145     glBegin (GL_LINE_LOOP);
146   else
147     glBegin (GL_TRIANGLES);
148   glVertex3f (x1, y1, z1);
149   glVertex3f (x2, y2, z2);
150   glVertex3f (x3, y3, z3);
151   glEnd();
152 }
153
154 static void
155 four_tetras (GL_VECTOR *outer, Bool wireframe_p, int countdown, int which,
156              int *countP)
157 {
158   if (countdown <= 0)
159     {
160       (*countP)++;
161       if (which == 0)
162         {
163           glNormal3f (normals[0][0], normals[0][1], normals[0][2]);
164           triangle (outer[0].x, outer[0].y, outer[0].z,
165                     outer[1].x, outer[1].y, outer[1].z,
166                     outer[2].x, outer[2].y, outer[2].z,
167                     wireframe_p);
168         }
169       else if (which == 1)
170         {
171           glNormal3f (normals[1][0], normals[1][1], normals[1][2]);
172           triangle (outer[0].x, outer[0].y, outer[0].z,
173                     outer[3].x, outer[3].y, outer[3].z,
174                     outer[1].x, outer[1].y, outer[1].z,
175                     wireframe_p);
176         }
177       else if (which == 2)
178         {
179           glNormal3f (normals[2][0], normals[2][1], normals[2][2]);
180           triangle (outer[0].x, outer[0].y, outer[0].z,
181                     outer[2].x, outer[2].y, outer[2].z,
182                     outer[3].x, outer[3].y, outer[3].z,
183                     wireframe_p);
184         }
185       else
186         {
187           glNormal3f (normals[3][0], normals[3][1], normals[3][2]);
188           triangle (outer[1].x, outer[1].y, outer[1].z,
189                     outer[3].x, outer[3].y, outer[3].z,
190                     outer[2].x, outer[2].y, outer[2].z,
191                     wireframe_p);
192         }
193     }
194   else
195     {
196 #     define M01 0
197 #     define M02 1
198 #     define M03 2
199 #     define M12 3
200 #     define M13 4
201 #     define M23 5
202       GL_VECTOR inner[M23+1];
203       GL_VECTOR corner[4];
204
205       inner[M01].x = (outer[0].x + outer[1].x) / 2.0;
206       inner[M01].y = (outer[0].y + outer[1].y) / 2.0;
207       inner[M01].z = (outer[0].z + outer[1].z) / 2.0;
208
209       inner[M02].x = (outer[0].x + outer[2].x) / 2.0;
210       inner[M02].y = (outer[0].y + outer[2].y) / 2.0;
211       inner[M02].z = (outer[0].z + outer[2].z) / 2.0;
212
213       inner[M03].x = (outer[0].x + outer[3].x) / 2.0;
214       inner[M03].y = (outer[0].y + outer[3].y) / 2.0;
215       inner[M03].z = (outer[0].z + outer[3].z) / 2.0;
216
217       inner[M12].x = (outer[1].x + outer[2].x) / 2.0;
218       inner[M12].y = (outer[1].y + outer[2].y) / 2.0;
219       inner[M12].z = (outer[1].z + outer[2].z) / 2.0;
220
221       inner[M13].x = (outer[1].x + outer[3].x) / 2.0;
222       inner[M13].y = (outer[1].y + outer[3].y) / 2.0;
223       inner[M13].z = (outer[1].z + outer[3].z) / 2.0;
224
225       inner[M23].x = (outer[2].x + outer[3].x) / 2.0;
226       inner[M23].y = (outer[2].y + outer[3].y) / 2.0;
227       inner[M23].z = (outer[2].z + outer[3].z) / 2.0;
228
229       countdown--;
230
231       corner[0] = outer[0];
232       corner[1] = inner[M01];
233       corner[2] = inner[M02];
234       corner[3] = inner[M03];
235       four_tetras (corner, wireframe_p, countdown, which, countP);
236
237       corner[0] = inner[M01];
238       corner[1] = outer[1];
239       corner[2] = inner[M12];
240       corner[3] = inner[M13];
241       four_tetras (corner, wireframe_p, countdown, which, countP);
242
243       corner[0] = inner[M02];
244       corner[1] = inner[M12];
245       corner[2] = outer[2];
246       corner[3] = inner[M23];
247       four_tetras (corner, wireframe_p, countdown, which, countP);
248
249       corner[0] = inner[M03];
250       corner[1] = inner[M13];
251       corner[2] = inner[M23];
252       corner[3] = outer[3];
253       four_tetras (corner, wireframe_p, countdown, which, countP);
254     }
255 }
256
257
258 static void
259 compile_gasket(ModeInfo *mi, int which)
260 {
261   Bool wireframe_p = MI_IS_WIREFRAME(mi);
262   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
263   int count;
264
265   GL_VECTOR   vertex[5];
266
267   normals[0][0] =  0;
268   normals[0][1] =  0;
269   normals[0][2] = -sqrt(2.0 / 3.0);
270
271   normals[1][0] =  0;
272   normals[1][1] = -sqrt(0.75);
273   normals[1][2] =  sqrt(2.0 / 3.0) / 3.0;
274
275   normals[2][0] =  sqrt (0.5);
276   normals[2][1] =  sqrt(0.75) / 2.0;
277   normals[2][2] =  normals[1][2];
278
279   normals[3][0] = -normals[2][0];
280   normals[3][1] =  normals[2][1];
281   normals[3][2] =  normals[1][2];
282
283
284   /* define verticies */
285   vertex[0].x =  0.5; 
286   vertex[0].y = -(1.0/3.0)*sqrt((2.0/3.0));
287   vertex[0].z = -sqrt(3.0)/6.0;
288
289   vertex[1].x = -0.5; 
290   vertex[1].y = -(1.0/3.0)*sqrt((2.0/3.0)); 
291   vertex[1].z = -sqrt(3.0)/6.0; 
292
293   vertex[2].x = 0.0; 
294   vertex[2].y = (2.0/3.0)*sqrt((2.0/3.0));
295   vertex[2].z = -sqrt(3.0)/6.0; 
296
297   vertex[3].x = 0.0; 
298   vertex[3].y = 0.0; 
299   vertex[3].z = sqrt(3.0)/3.0; 
300
301   vertex[4].x = 0.0;
302   vertex[4].y = 0.0; 
303   vertex[4].z = 0.0;
304   
305   count = 0;
306   four_tetras (vertex, wireframe_p,
307                (gp->current_depth < 0
308                 ? -gp->current_depth : gp->current_depth),
309                which,
310                &count);
311   mi->polygon_count = count;
312 }
313
314 static void
315 draw(ModeInfo *mi)
316 {
317   Bool wireframe_p = MI_IS_WIREFRAME(mi);
318   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
319   static int tick = 999999;
320   
321   static GLfloat pos[4] = {-4.0, 3.0, 10.0, 1.0};
322   static float white[]  = {1.0, 1.0, 1.0, 1.0};
323   static float color0[] = {0.0, 0.0, 0.0, 1.0};
324   static float color1[] = {0.0, 0.0, 0.0, 1.0};
325   static float color2[] = {0.0, 0.0, 0.0, 1.0};
326   static float color3[] = {0.0, 0.0, 0.0, 1.0};
327
328   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
329
330   if (!wireframe_p)
331     {
332       glColor4fv (white);
333
334       glLightfv(GL_LIGHT0, GL_POSITION,  pos);
335
336       color0[0] = gp->colors[gp->ccolor0].red   / 65536.0;
337       color0[1] = gp->colors[gp->ccolor0].green / 65536.0;
338       color0[2] = gp->colors[gp->ccolor0].blue  / 65536.0;
339
340       color1[0] = gp->colors[gp->ccolor1].red   / 65536.0;
341       color1[1] = gp->colors[gp->ccolor1].green / 65536.0;
342       color1[2] = gp->colors[gp->ccolor1].blue  / 65536.0;
343
344       color2[0] = gp->colors[gp->ccolor2].red   / 65536.0;
345       color2[1] = gp->colors[gp->ccolor2].green / 65536.0;
346       color2[2] = gp->colors[gp->ccolor2].blue  / 65536.0;
347
348       color3[0] = gp->colors[gp->ccolor3].red   / 65536.0;
349       color3[1] = gp->colors[gp->ccolor3].green / 65536.0;
350       color3[2] = gp->colors[gp->ccolor3].blue  / 65536.0;
351
352       gp->ccolor0++;
353       gp->ccolor1++;
354       gp->ccolor2++;
355       gp->ccolor3++;
356       if (gp->ccolor0 >= gp->ncolors) gp->ccolor0 = 0;
357       if (gp->ccolor1 >= gp->ncolors) gp->ccolor1 = 0;
358       if (gp->ccolor2 >= gp->ncolors) gp->ccolor2 = 0;
359       if (gp->ccolor3 >= gp->ncolors) gp->ccolor3 = 0;
360
361       glShadeModel(GL_SMOOTH);
362
363       glEnable(GL_LIGHTING);
364       glEnable(GL_LIGHT0);
365     }
366
367   glEnable(GL_DEPTH_TEST);
368   glEnable(GL_NORMALIZE);
369   glEnable(GL_CULL_FACE);
370
371   glPushMatrix();
372
373   {
374     double x, y, z;
375     get_position (gp->rot, &x, &y, &z, !gp->button_down_p);
376     glTranslatef((x - 0.5) * 10,
377                  (y - 0.5) * 10,
378                  (z - 0.5) * 20);
379
380     gltrackball_rotate (gp->trackball);
381
382     get_rotation (gp->rot, &x, &y, &z, !gp->button_down_p);
383     glRotatef (x * 360, 1.0, 0.0, 0.0);
384     glRotatef (y * 360, 0.0, 1.0, 0.0);
385     glRotatef (z * 360, 0.0, 0.0, 1.0);
386   }
387
388   glScalef( 8.0, 8.0, 8.0 );
389
390   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color0);
391   glCallList(gp->gasket0);
392   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color1);
393   glCallList(gp->gasket1);
394   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color2);
395   glCallList(gp->gasket2);
396   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color3);
397   glCallList(gp->gasket3);
398
399   glPopMatrix();
400
401
402   if (tick++ >= speed)
403     {
404       tick = 0;
405       if (gp->current_depth >= max_depth)
406         gp->current_depth = -max_depth;
407       gp->current_depth++;
408
409       /* We make four different lists so that each face of the tetrahedrons
410          can have a different color (all triangles facing in the same
411          direction have the same color, which is different from all
412          triangles facing in other directions.)
413        */
414       glDeleteLists (gp->gasket0, 1);
415       glDeleteLists (gp->gasket1, 1);
416       glDeleteLists (gp->gasket2, 1);
417       glDeleteLists (gp->gasket3, 1);
418
419       mi->polygon_count = 0;
420       glNewList (gp->gasket0, GL_COMPILE); compile_gasket (mi, 0); glEndList();
421       glNewList (gp->gasket1, GL_COMPILE); compile_gasket (mi, 1); glEndList();
422       glNewList (gp->gasket2, GL_COMPILE); compile_gasket (mi, 2); glEndList();
423       glNewList (gp->gasket3, GL_COMPILE); compile_gasket (mi, 3); glEndList();
424
425     }
426 }
427
428
429 /* new window size or exposure */
430 void
431 reshape_gasket(ModeInfo *mi, int width, int height)
432 {
433   GLfloat h = (GLfloat) height / (GLfloat) width;
434
435   glViewport(0, 0, (GLint) width, (GLint) height);
436   glMatrixMode(GL_PROJECTION);
437   glLoadIdentity();
438   gluPerspective (30.0, 1/h, 1.0, 100.0);
439
440   glMatrixMode(GL_MODELVIEW);
441   glLoadIdentity();
442   gluLookAt( 0.0, 0.0, 30.0,
443              0.0, 0.0, 0.0,
444              0.0, 1.0, 0.0);
445   
446   glClear(GL_COLOR_BUFFER_BIT);
447 }
448
449 static void
450 pinit(ModeInfo *mi)
451 {
452   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
453
454   /* draw the gasket */
455   gp->gasket0 = glGenLists(1);
456   gp->gasket1 = glGenLists(1);
457   gp->gasket2 = glGenLists(1);
458   gp->gasket3 = glGenLists(1);
459   gp->current_depth = 1;       /* start out at level 1, not 0 */
460 }
461
462
463 Bool
464 gasket_handle_event (ModeInfo *mi, XEvent *event)
465 {
466   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
467
468   if (event->xany.type == ButtonPress &&
469       event->xbutton.button & Button1)
470     {
471       gp->button_down_p = True;
472       gltrackball_start (gp->trackball,
473                          event->xbutton.x, event->xbutton.y,
474                          MI_WIDTH (mi), MI_HEIGHT (mi));
475       return True;
476     }
477   else if (event->xany.type == ButtonRelease &&
478            event->xbutton.button & Button1)
479     {
480       gp->button_down_p = False;
481       return True;
482     }
483   else if (event->xany.type == MotionNotify &&
484            gp->button_down_p)
485     {
486       gltrackball_track (gp->trackball,
487                          event->xmotion.x, event->xmotion.y,
488                          MI_WIDTH (mi), MI_HEIGHT (mi));
489       return True;
490     }
491
492   return False;
493 }
494
495
496 void
497 init_gasket(ModeInfo *mi)
498 {
499   int           screen = MI_SCREEN(mi);
500   gasketstruct *gp;
501
502   if (gasket == NULL)
503   {
504     if ((gasket = (gasketstruct *) calloc(MI_NUM_SCREENS(mi),
505                                               sizeof (gasketstruct))) == NULL)
506         return;
507   }
508   gp = &gasket[screen];
509
510   gp->window = MI_WINDOW(mi);
511
512   {
513     double spin_speed   = 1.0;
514     double wander_speed = 0.03;
515     gp->rot = make_rotator (do_spin ? spin_speed : 0,
516                             do_spin ? spin_speed : 0,
517                             do_spin ? spin_speed : 0,
518                             1.0,
519                             do_wander ? wander_speed : 0,
520                             True);
521     gp->trackball = gltrackball_init ();
522   }
523
524   gp->ncolors = 255;
525   gp->colors = (XColor *) calloc(gp->ncolors, sizeof(XColor));
526   make_smooth_colormap (0, 0, 0,
527                         gp->colors, &gp->ncolors,
528                         False, 0, False);
529   gp->ccolor0 = 0;
530   gp->ccolor1 = gp->ncolors * 0.25;
531   gp->ccolor2 = gp->ncolors * 0.5;
532   gp->ccolor3 = gp->ncolors * 0.75;
533
534   if ((gp->glx_context = init_GL(mi)) != NULL)
535   {
536     reshape_gasket(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
537     pinit(mi);
538   }
539   else
540   {
541     MI_CLEARWINDOW(mi);
542   }
543 }
544
545 void
546 draw_gasket(ModeInfo * mi)
547 {
548   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
549   Display      *display = MI_DISPLAY(mi);
550   Window        window = MI_WINDOW(mi);
551
552   if (!gp->glx_context) return;
553
554   glDrawBuffer(GL_BACK);
555
556   if (max_depth > 10)
557     max_depth = 10;
558
559   glXMakeCurrent(display, window, *(gp->glx_context));
560   draw(mi);
561   if (mi->fps_p) do_fps (mi);
562   glFinish();
563   glXSwapBuffers(display, window);
564 }
565
566 void
567 release_gasket(ModeInfo * mi)
568 {
569   if (gasket != NULL)
570   {
571     int         screen;
572
573     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
574     {
575       gasketstruct *gp = &gasket[screen];
576
577       if (gp->glx_context)
578       {
579         /* Display lists MUST be freed while their glXContext is current. */
580         glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
581
582         if (glIsList(gp->gasket0)) glDeleteLists(gp->gasket0, 1);
583         if (glIsList(gp->gasket1)) glDeleteLists(gp->gasket1, 1);
584         if (glIsList(gp->gasket2)) glDeleteLists(gp->gasket2, 1);
585         if (glIsList(gp->gasket3)) glDeleteLists(gp->gasket3, 1);
586       }
587     }
588     (void) free((void *) gasket);
589     gasket = NULL;
590   }
591   FreeAllGL(mi);
592 }
593
594
595 /*********************************************************/
596
597 #endif