9a783a04794600165780e6b80f64ef05f3fa6b53
[xscreensaver] / 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
27 /*-
28  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
29  * otherwise caddr_t is not defined correctly
30  */
31
32 #include <X11/Intrinsic.h>
33
34 #ifdef STANDALONE
35 # define PROGCLASS                                      "Sierpinski3D"
36 # define HACK_INIT                                      init_gasket
37 # define HACK_DRAW                                      draw_gasket
38 # define gasket_opts                            xlockmore_opts
39 # define DEFAULTS       "*count:                1       \n"                     \
40                         "*cycles:               9999    \n"                     \
41                         "*delay:                100     \n"                     \
42                         "*wireframe:    False   \n"
43 # include "xlockmore.h"         /* from the xscreensaver distribution */
44 #else  /* !STANDALONE */
45 # include "xlock.h"                     /* from the xlockmore distribution */
46 #endif /* !STANDALONE */
47
48 #ifdef USE_GL
49
50 ModeSpecOpt gasket_opts =
51 {0, NULL, 0, NULL, NULL};
52
53 #ifdef USE_MODULES
54 ModStruct   gasket_description =
55 {"gasket", "init_gasket", "draw_gasket", "release_gasket",
56  "draw_gasket", "init_gasket", NULL, &gasket_opts,
57  1000, 1, 2, 1, 4, 1.0, "",
58  "Shows GL's Sierpinski gasket", 0, NULL};
59
60 #endif
61
62 typedef struct{
63   GLfloat x;
64   GLfloat y;
65   GLfloat z;
66 } GL_VECTOR;
67
68 typedef struct {
69   GLfloat     view_rotx, view_roty, view_rotz;
70   GLfloat     light_colour[4];/* = {6.0, 6.0, 6.0, 1.0}; */
71   GLfloat     pos[3];/* = {0.0, 0.0, 0.0}; */
72   GLfloat     xinc,yinc,zinc;
73   GLfloat     angle;
74   GLuint      gasket1;
75   GLXContext *glx_context;
76   Window      window;
77 #if 0
78   Window      win;
79 #endif
80 } gasketstruct;
81
82 static gasketstruct *gasket = NULL;
83
84 #include <GL/glu.h>
85
86 /* static GLuint limit; */
87
88 static void
89 compile_gasket(ModeInfo *mi)
90 {
91   int i,p;
92   int points = MI_CYCLES(mi) ? MI_CYCLES(mi) : 9999;
93   GL_VECTOR   vertex[5];
94
95   /* define verticies */
96   vertex[0].x =  0.5; 
97   vertex[0].y = -(1.0/3.0)*sqrt((2.0/3.0));
98   vertex[0].z = -sqrt(3.0)/6.0;
99
100   vertex[1].x = -0.5; 
101   vertex[1].y = -(1.0/3.0)*sqrt((2.0/3.0)); 
102   vertex[1].z = -sqrt(3.0)/6.0; 
103
104   vertex[2].x = 0.0; 
105   vertex[2].y = (2.0/3.0)*sqrt((2.0/3.0));
106   vertex[2].z = -sqrt(3.0)/6.0; 
107
108   vertex[3].x = 0.0; 
109   vertex[3].y = 0.0; 
110   vertex[3].z = sqrt(3.0)/3.0; 
111
112   vertex[4].x = 0.0;
113   vertex[4].y = 0.0; 
114   vertex[4].z = 0.0;
115   
116   glBegin(GL_POINTS);
117   for( i = 0; i < points ; i++ )
118   { 
119     p = NRAND(4);
120     vertex[4].x = ( vertex[4].x + vertex[p].x )/2.0;
121     vertex[4].y = ( vertex[4].y + vertex[p].y )/2.0;
122     vertex[4].z = ( vertex[4].z + vertex[p].z )/2.0;
123
124     glVertex4f( vertex[4].x, vertex[4].y, vertex[4].z, 1.0 );
125   }
126   glEnd();
127 }
128
129 static void
130 draw(ModeInfo *mi)
131 {
132   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
133   
134   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
135
136   glLightfv(GL_LIGHT0, GL_AMBIENT, gp->light_colour);
137   glEnable(GL_LIGHTING);
138   glEnable(GL_LIGHT0);
139   glEnable(GL_DEPTH_TEST);
140
141   glPushMatrix();
142   glTranslatef( gp->pos[0], gp->pos[1], gp->pos[2] );  
143
144   glPushMatrix();
145   glRotatef(2*gp->angle, 1.0, 0.0, 0.0);
146   glRotatef(3*gp->angle, 0.0, 1.0, 0.0);
147   glRotatef(  gp->angle, 0.0, 0.0, 1.0);
148   glScalef( 8.0, 8.0, 8.0 );
149   glCallList(gp->gasket1);
150   
151   glPopMatrix();
152
153   glPopMatrix();
154
155 }
156
157
158 /* new window size or exposure */
159 static void
160 reshape(int width, int height)
161 {
162   GLfloat h = (GLfloat) height / (GLfloat) width;
163
164   glViewport(0, 0, (GLint) width, (GLint) height);
165   glMatrixMode(GL_PROJECTION);
166   glLoadIdentity();
167
168   gluPerspective( 30.0, 1/h, 1.0, 100.0 );
169   gluLookAt( 0.0, 0.0, 15.0,
170              0.0, 0.0, 0.0,
171              0.0, 1.0, 0.0);
172   glMatrixMode(GL_MODELVIEW);
173   glLoadIdentity();
174   glTranslatef(0.0, 0.0, -40.0);
175   
176   /* The depth buffer will be cleared, if needed, before the
177   * next frame.  Right now we just want to black the screen.
178   */
179   glClear(GL_COLOR_BUFFER_BIT);
180 }
181
182 static void
183 pinit(ModeInfo *mi)
184 {
185   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
186
187   gp->xinc = 0.1*(1.0*random()/RAND_MAX);
188   gp->yinc = 0.1*(1.0*random()/RAND_MAX);
189   gp->zinc = 0.1*(1.0*random()/RAND_MAX);
190   gp->light_colour[0] = 6.0;
191   gp->light_colour[1] = 6.0;
192   gp->light_colour[2] = 6.0;
193   gp->light_colour[3] = 1.0;
194   gp->pos[0] = 0.0;     
195   gp->pos[1] = 0.0;
196   gp->pos[2] = 0.0;    
197   /* draw the gasket */
198   gp->gasket1 = glGenLists(1);
199   glNewList(gp->gasket1, GL_COMPILE);
200     compile_gasket(mi);
201   glEndList();
202 }
203
204 void
205 init_gasket(ModeInfo *mi)
206 {
207   int           screen = MI_SCREEN(mi);
208   gasketstruct *gp;
209
210   if (gasket == NULL)
211   {
212     if ((gasket = (gasketstruct *) calloc(MI_NUM_SCREENS(mi),
213                                               sizeof (gasketstruct))) == NULL)
214         return;
215   }
216   gp = &gasket[screen];
217
218   gp->window = MI_WINDOW(mi);
219   gp->view_rotx = NRAND(360);
220   gp->view_roty = NRAND(360);
221   gp->view_rotz = NRAND(360);
222   gp->angle = NRAND(360)/90.0;
223
224   if ((gp->glx_context = init_GL(mi)) != NULL)
225   {
226     reshape(MI_WIDTH(mi), MI_HEIGHT(mi));
227     pinit(mi);
228   }
229   else
230   {
231     MI_CLEARWINDOW(mi);
232   }
233 }
234
235 void
236 draw_gasket(ModeInfo * mi)
237 {
238   gasketstruct *gp = &gasket[MI_SCREEN(mi)];
239   Display      *display = MI_DISPLAY(mi);
240   Window        window = MI_WINDOW(mi);
241   int           angle_incr = 1;
242   int           rot_incr = 1;/*MI_COUNT(mi) ? MI_COUNT(mi) : 1;*/
243
244   if (!gp->glx_context) return;
245
246   glDrawBuffer(GL_BACK);
247
248   glXMakeCurrent(display, window, *(gp->glx_context));
249   draw(mi);
250
251   /* do the colour change & movement thing */
252   gp->angle = (int) (gp->angle + angle_incr) % 360;
253   gp->light_colour[0] = 3.0*SINF(gp->angle/20.0) + 4.0;
254   gp->light_colour[1] = 3.0*SINF(gp->angle/30.0) + 4.0;
255   gp->light_colour[2] = 3.0*SINF(gp->angle/60.0) + 4.0;
256   if ( FABSF( gp->pos[0] ) > 9.0 ) gp->xinc = -1.0 * gp->xinc;
257   if ( FABSF( gp->pos[1] ) > 7.0 ) gp->yinc = -1.0 * gp->yinc;
258   if ( FABSF( gp->pos[2] ) >15.0 ) gp->zinc = -1.0 * gp->zinc;
259   gp->pos[0] += gp->xinc;
260   gp->pos[1] += gp->yinc;
261   gp->pos[2] += gp->zinc;    
262   gp->view_rotx = (int) (gp->view_rotx + rot_incr) % 360;
263   gp->view_roty = (int) (gp->view_roty +(rot_incr/2.0)) % 360;
264   gp->view_rotz = (int) (gp->view_rotz +(rot_incr/3.0)) % 360;
265
266   glFinish();
267   glXSwapBuffers(display, window);
268 }
269
270 void
271 release_gasket(ModeInfo * mi)
272 {
273   if (gasket != NULL)
274   {
275     int         screen;
276
277     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
278     {
279       gasketstruct *gp = &gasket[screen];
280
281       if (gp->glx_context)
282       {
283         /* Display lists MUST be freed while their glXContext is current. */
284         glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
285
286         if (glIsList(gp->gasket1)) glDeleteLists(gp->gasket1, 1);
287       }
288     }
289     (void) free((void *) gasket);
290     gasket = NULL;
291   }
292   FreeAllGL(mi);
293 }
294
295
296 /*********************************************************/
297
298 #endif