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