1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* Sierpinski3D --- 3D sierpinski gasket */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)sierpinski3D.c 00.01 99/11/04 xlockmore";
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.
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.
23 * 1999: written by Tim Robinson <the_luggage@bigfoot.com>
24 * a 3-D representation of the Sierpinski gasket fractal.
26 * 10-Dec-99 jwz rewrote to draw a set of tetrahedrons instead of a
27 * random scattering of points.
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
35 #include <X11/Intrinsic.h>
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" \
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 */
56 #define countof(x) (sizeof((x))/sizeof((*x)))
60 static XrmOptionDescRec opts[] = {
61 {"-depth", ".sierpinski3d.maxDepth", XrmoptionSepArg, (caddr_t) 0 },
62 {"-speed", ".sierpinski3d.speed", XrmoptionSepArg, (caddr_t) 0 }
65 static argtype vars[] = {
66 {(caddr_t *) &max_depth, "maxDepth", "MaxDepth", "5", t_Int},
67 {(caddr_t *) &speed, "speed", "Speed", "150", t_Int},
71 ModeSpecOpt gasket_opts = {countof(opts), opts, countof(vars), vars, NULL};
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};
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;
95 GLXContext *glx_context;
102 static gasketstruct *gasket = NULL;
106 /* static GLuint limit; */
109 /* Computing normal vectors (thanks to Nat Friedman <ndf@mit.edu>)
112 typedef struct vector {
116 typedef struct plane {
121 vector_set(vector *v, GLfloat x, GLfloat y, GLfloat z)
129 vector_cross(vector v1, vector v2, vector *v3)
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);
137 vector_subtract(vector v1, vector v2, vector *res)
139 res->x = v1.x - v2.x;
140 res->y = v1.y - v2.y;
141 res->z = v1.z - v2.z;
145 plane_normal(plane p, vector *n)
148 vector_subtract(p.p1, p.p2, &v1);
149 vector_subtract(p.p1, p.p3, &v2);
150 vector_cross(v2, v1, n);
154 do_normal(GLfloat x1, GLfloat y1, GLfloat z1,
155 GLfloat x2, GLfloat y2, GLfloat z2,
156 GLfloat x3, GLfloat y3, GLfloat z3)
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;
166 glNormal3f(n.x, n.y, n.z);
169 /* Draw a line in the direction of this face's normal. */
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;
179 GLfloat max = ax > ay ? ax : ay;
180 if (az > max) max = az;
186 glBegin(GL_LINE_LOOP);
187 glVertex3f(mx, my, mz);
188 glVertex3f(mx+xx, my+yy, mz+zz);
197 triangle (GLfloat x1, GLfloat y1, GLfloat z1,
198 GLfloat x2, GLfloat y2, GLfloat z2,
199 GLfloat x3, GLfloat y3, GLfloat z3,
203 glBegin (GL_LINE_LOOP);
206 do_normal (x1, y1, z1, x2, y2, z2, x3, y3, z3);
207 glBegin (GL_TRIANGLES);
209 glVertex3f (x1, y1, z1);
210 glVertex3f (x2, y2, z2);
211 glVertex3f (x3, y3, z3);
216 four_tetras (GL_VECTOR *outer, Bool wireframe_p, int countdown)
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,
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,
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,
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,
245 GL_VECTOR inner[M23+1];
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;
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;
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;
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;
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;
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;
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);
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);
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);
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);
302 compile_gasket(ModeInfo *mi)
304 Bool wireframe_p = MI_IS_WIREFRAME(mi);
305 gasketstruct *gp = &gasket[MI_SCREEN(mi)];
309 /* define verticies */
311 vertex[0].y = -(1.0/3.0)*sqrt((2.0/3.0));
312 vertex[0].z = -sqrt(3.0)/6.0;
315 vertex[1].y = -(1.0/3.0)*sqrt((2.0/3.0));
316 vertex[1].z = -sqrt(3.0)/6.0;
319 vertex[2].y = (2.0/3.0)*sqrt((2.0/3.0));
320 vertex[2].z = -sqrt(3.0)/6.0;
324 vertex[3].z = sqrt(3.0)/3.0;
330 four_tetras (vertex, wireframe_p,
331 (gp->current_depth < 0
332 ? -gp->current_depth : gp->current_depth));
338 gasketstruct *gp = &gasket[MI_SCREEN(mi)];
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};
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);
350 glShadeModel(GL_SMOOTH);
352 glEnable(GL_LIGHTING);
355 glEnable(GL_DEPTH_TEST);
356 glEnable(GL_NORMALIZE);
357 glEnable(GL_CULL_FACE);
359 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
362 glTranslatef( gp->pos[0], gp->pos[1], gp->pos[2] );
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);
379 if (gp->current_depth >= max_depth)
380 gp->current_depth = -max_depth;
383 glDeleteLists (gp->gasket1, 1);
384 glNewList (gp->gasket1, GL_COMPILE);
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;
396 /* new window size or exposure */
398 reshape(int width, int height)
400 GLfloat h = (GLfloat) height / (GLfloat) width;
402 glViewport(0, 0, (GLint) width, (GLint) height);
403 glMatrixMode(GL_PROJECTION);
406 gluPerspective( 30.0, 1/h, 1.0, 100.0 );
407 gluLookAt( 0.0, 0.0, 15.0,
410 glMatrixMode(GL_MODELVIEW);
412 glTranslatef(0.0, 0.0, -15.0);
414 /* The depth buffer will be cleared, if needed, before the
415 * next frame. Right now we just want to black the screen.
417 glClear(GL_COLOR_BUFFER_BIT);
423 gasketstruct *gp = &gasket[MI_SCREEN(mi)];
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;
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);
444 init_gasket(ModeInfo *mi)
446 int screen = MI_SCREEN(mi);
451 if ((gasket = (gasketstruct *) calloc(MI_NUM_SCREENS(mi),
452 sizeof (gasketstruct))) == NULL)
455 gp = &gasket[screen];
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;
463 if ((gp->glx_context = init_GL(mi)) != NULL)
465 reshape(MI_WIDTH(mi), MI_HEIGHT(mi));
475 draw_gasket(ModeInfo * mi)
477 gasketstruct *gp = &gasket[MI_SCREEN(mi)];
478 Display *display = MI_DISPLAY(mi);
479 Window window = MI_WINDOW(mi);
481 int rot_incr = 1;/*MI_COUNT(mi) ? MI_COUNT(mi) : 1;*/
483 if (!gp->glx_context) return;
485 glDrawBuffer(GL_BACK);
490 glXMakeCurrent(display, window, *(gp->glx_context));
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;
506 glXSwapBuffers(display, window);
510 release_gasket(ModeInfo * mi)
516 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
518 gasketstruct *gp = &gasket[screen];
522 /* Display lists MUST be freed while their glXContext is current. */
523 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
525 if (glIsList(gp->gasket1)) glDeleteLists(gp->gasket1, 1);
528 (void) free((void *) gasket);
535 /*********************************************************/