http://ftp.x.org/contrib/applications/xscreensaver-2.17.tar.gz
[xscreensaver] / hacks / glx / morph3d.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* morph3d --- Shows 3D morphing objects */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)morph3d.c     4.07 97/11/24 xlockmore";
6
7 #endif
8
9 #undef DEBUG_CULL_FACE
10
11 /*-
12  * Permission to use, copy, modify, and distribute this software and its
13  * documentation for any purpose and without fee is hereby granted,
14  * provided that the above copyright notice appear in all copies and that
15  * both that copyright notice and this permission notice appear in
16  * supporting documentation.
17  *
18  * This file is provided AS IS with no warranties of any kind.  The author
19  * shall have no liability with respect to the infringement of copyrights,
20  * trade secrets or any patents by this file or any part thereof.  In no
21  * event will the author be liable for any lost revenue or profits or
22  * other special, indirect and consequential damages.
23  *
24  * The original code for this mode was written by Marcelo Fernandes Vianna 
25  * (me...) and was inspired on a WindowsNT(R)'s screen saver (Flower Box).
26  * It was written from scratch and it was not based on any other source code. 
27  * 
28  * Porting it to xlock (the final objective of this code since the moment I 
29  * decided to create it) was possible by comparing the original Mesa's gear 
30  * demo with it's ported version to xlock, so thanks for Danny Sung (look at
31  * gear.c) for his indirect help.
32  *
33  * Thanks goes also to Brian Paul for making it possible and inexpensive
34  * to use OpenGL at home.
35  *
36  * If you are interested in the original version of this program (not a xlock
37  * mode, please refer to the Mesa package (ftp iris.ssec.wisc.edu on /pub/Mesa)
38  *
39  * Since I'm not a native English speaker, my apologies for any grammatical
40  * mistake.
41  *
42  * My e-mail addresses are
43  * vianna@cat.cbpf.br 
44  *         and
45  * m-vianna@usa.net
46  *
47  * Marcelo F. Vianna (Feb-13-1997)
48  *
49  * Revision History:
50  * 27-Jul-97: Speed ups by Marcelo F. Vianna.
51  * 08-May-97: Speed ups by Marcelo F. Vianna.
52  *
53  */
54
55 /*-
56  * PURIFY 3.0a on SunOS4 reports an unitialized memory read on each of
57  * the glCallList() functions below when using MesaGL 2.1.  This has
58  * been fixed in MesaGL 2.2 and later releases.
59  */
60
61 /*-
62  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
63  * otherwise caddr_t is not defined correctly
64  */
65
66 #include <X11/Intrinsic.h>
67
68 #ifdef STANDALONE
69 # define PROGCLASS              "Morph3d"
70 # define HACK_INIT              init_morph3d
71 # define HACK_DRAW              draw_morph3d
72 # define morph3d_opts           xlockmore_opts
73 # define DEFAULTS               "*delay: 1000 \n" \
74                                 "*count: 0 \n"
75 # include "xlockmore.h"         /* from the xscreensaver distribution */
76 #else /* !STANDALONE */
77 # include "xlock.h"             /* from the xlockmore distribution */
78 #endif /* !STANDALONE */
79
80 #ifdef USE_GL
81
82 ModeSpecOpt morph3d_opts =
83 {0, NULL, 0, NULL, NULL};
84
85 #ifdef USE_MODULES
86 ModStruct   morph3d_description =
87 {"morph3d", "init_morph3d", "draw_morph3d", "release_morph3d",
88  "draw_morph3d", "change_morph3d", NULL, &morph3d_opts,
89  1000, 0, 1, 1, 4, 1.0, "",
90  "Shows GL morphing polyhedra", 0, NULL};
91
92 #endif
93
94 #define Scale4Window               0.3
95 #define Scale4Iconic               1.0
96
97 #define VectMul(X1,Y1,Z1,X2,Y2,Z2) (Y1)*(Z2)-(Z1)*(Y2),(Z1)*(X2)-(X1)*(Z2),(X1)*(Y2)-(Y1)*(X2)
98 #define sqr(A)                     ((A)*(A))
99
100 /* Increasing this values produces better image quality, the price is speed. */
101 #define tetradivisions             23
102 #define cubedivisions              20
103 #define octadivisions              21
104 #define dodecadivisions            10
105 #define icodivisions               15
106
107 #define tetraangle                 109.47122063449069174
108 #define cubeangle                  90.000000000000000000
109 #define octaangle                  109.47122063449069174
110 #define dodecaangle                63.434948822922009981
111 #define icoangle                   41.810314895778596167
112
113 #ifndef Pi
114 #define Pi                         M_PI
115 #endif
116 #define SQRT2                      1.4142135623730951455
117 #define SQRT3                      1.7320508075688771932
118 #define SQRT5                      2.2360679774997898051
119 #define SQRT6                      2.4494897427831778813
120 #define SQRT15                     3.8729833462074170214
121 #define cossec36_2                 0.8506508083520399322
122 #define cos72                      0.3090169943749474241
123 #define sin72                      0.9510565162951535721
124 #define cos36                      0.8090169943749474241
125 #define sin36                      0.5877852522924731292
126
127 /*************************************************************************/
128
129 typedef struct {
130         GLint       WindH, WindW;
131         GLfloat     step;
132         GLfloat     seno;
133         int         object;
134         int         edgedivisions;
135         int         VisibleSpikes;
136         void        (*draw_object) (ModeInfo * mi);
137         float       Magnitude;
138         float      *MaterialColor[20];
139         GLXContext *glx_context;
140 } morph3dstruct;
141
142 static float front_shininess[] =
143 {60.0};
144 static float front_specular[] =
145 {0.7, 0.7, 0.7, 1.0};
146 static float ambient[] =
147 {0.0, 0.0, 0.0, 1.0};
148 static float diffuse[] =
149 {1.0, 1.0, 1.0, 1.0};
150 static float position0[] =
151 {1.0, 1.0, 1.0, 0.0};
152 static float position1[] =
153 {-1.0, -1.0, 1.0, 0.0};
154 static float lmodel_ambient[] =
155 {0.5, 0.5, 0.5, 1.0};
156 static float lmodel_twoside[] =
157 {GL_TRUE};
158
159 static float MaterialRed[] =
160 {0.7, 0.0, 0.0, 1.0};
161 static float MaterialGreen[] =
162 {0.1, 0.5, 0.2, 1.0};
163 static float MaterialBlue[] =
164 {0.0, 0.0, 0.7, 1.0};
165 static float MaterialCyan[] =
166 {0.2, 0.5, 0.7, 1.0};
167 static float MaterialYellow[] =
168 {0.7, 0.7, 0.0, 1.0};
169 static float MaterialMagenta[] =
170 {0.6, 0.2, 0.5, 1.0};
171 static float MaterialWhite[] =
172 {0.7, 0.7, 0.7, 1.0};
173 static float MaterialGray[] =
174 {0.5, 0.5, 0.5, 1.0};
175
176 static morph3dstruct *morph3d = NULL;
177
178 #define TRIANGLE(Edge, Amp, Divisions, Z, VS)                                                                    \
179 {                                                                                                                \
180   GLfloat   Xf,Yf,Xa,Yb,Xf2,Yf2,Yf_2,Yb2,Yb_2;                                                                   \
181   GLfloat   Factor=0.0,Factor1,Factor2;                                                                          \
182   GLfloat   VertX,VertY,VertZ,NeiAX,NeiAY,NeiAZ,NeiBX,NeiBY,NeiBZ;                                               \
183   GLfloat   Ax,Ay;                                                                                               \
184   int       Ri,Ti;                                                                                               \
185   GLfloat   Vr=(Edge)*SQRT3/3;                                                                                   \
186   GLfloat   AmpVr2=(Amp)/sqr(Vr);                                                                                \
187   GLfloat   Zf=(Edge)*(Z);                                                                                       \
188                                                                                                                  \
189   Ax=(Edge)*(+0.5/(Divisions)), Ay=(Edge)*(-SQRT3/(2*Divisions));                                                \
190                                                                                                                  \
191   Yf=Vr+Ay; Yb=Yf+0.001;                                                                                         \
192   for (Ri=1; Ri<=(Divisions); Ri++) {                                                                            \
193     glBegin(GL_TRIANGLE_STRIP);                                                                                  \
194     Xf=(float)Ri*Ax; Xa=Xf+0.001;                                                                                \
195     Yf2=sqr(Yf); Yf_2=sqr(Yf-Ay);                                                                                \
196     Yb2=sqr(Yb); Yb_2=sqr(Yb-Ay);                                                                                \
197     for (Ti=0; Ti<Ri; Ti++) {                                                                                    \
198       Factor=1-(((Xf2=sqr(Xf))+Yf2)*AmpVr2);                                                                     \
199       Factor1=1-((sqr(Xa)+Yf2)*AmpVr2);                                                                          \
200       Factor2=1-((Xf2+Yb2)*AmpVr2);                                                                              \
201       VertX=Factor*Xf;        VertY=Factor*Yf;        VertZ=Factor*Zf;                                           \
202       NeiAX=Factor1*Xa-VertX; NeiAY=Factor1*Yf-VertY; NeiAZ=Factor1*Zf-VertZ;                                    \
203       NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                    \
204       glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                             \
205       glVertex3f(VertX, VertY, VertZ);                                                                           \
206                                                                                                                  \
207       Xf-=Ax; Yf-=Ay; Xa-=Ax; Yb-=Ay;                                                                            \
208                                                                                                                  \
209       Factor=1-(((Xf2=sqr(Xf))+Yf_2)*AmpVr2);                                                                    \
210       Factor1=1-((sqr(Xa)+Yf_2)*AmpVr2);                                                                         \
211       Factor2=1-((Xf2+Yb_2)*AmpVr2);                                                                             \
212       VertX=Factor*Xf;        VertY=Factor*Yf;        VertZ=Factor*Zf;                                           \
213       NeiAX=Factor1*Xa-VertX; NeiAY=Factor1*Yf-VertY; NeiAZ=Factor1*Zf-VertZ;                                    \
214       NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                    \
215       glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                             \
216       glVertex3f(VertX, VertY, VertZ);                                                                           \
217                                                                                                                  \
218       Xf-=Ax; Yf+=Ay; Xa-=Ax; Yb+=Ay;                                                                            \
219     }                                                                                                            \
220     Factor=1-(((Xf2=sqr(Xf))+(Yf2=sqr(Yf)))*AmpVr2);                                                             \
221     Factor1=1-((sqr(Xa)+Yf2)*AmpVr2);                                                                            \
222     Factor2=1-((Xf2+sqr(Yb))*AmpVr2);                                                                            \
223     VertX=Factor*Xf;        VertY=Factor*Yf;        VertZ=Factor*Zf;                                             \
224     NeiAX=Factor1*Xa-VertX; NeiAY=Factor1*Yf-VertY; NeiAZ=Factor1*Zf-VertZ;                                      \
225     NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                      \
226     glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                               \
227     glVertex3f(VertX, VertY, VertZ);                                                                             \
228     Yf+=Ay; Yb+=Ay;                                                                                              \
229     glEnd();                                                                                                     \
230   }                                                                                                              \
231   VS=(Factor<0);                                                                                                 \
232 }
233
234 #define SQUARE(Edge, Amp, Divisions, Z, VS)                                                                      \
235 {                                                                                                                \
236   int       Xi,Yi;                                                                                               \
237   GLfloat   Xf,Yf,Y,Xf2,Yf2,Y2,Xa,Xa2,Yb;                                                                        \
238   GLfloat   Factor=0.0,Factor1,Factor2;                                                                          \
239   GLfloat   VertX,VertY,VertZ,NeiAX,NeiAY,NeiAZ,NeiBX,NeiBY,NeiBZ;                                               \
240   GLfloat   Zf=(Edge)*(Z);                                                                                       \
241   GLfloat   AmpVr2=(Amp)/sqr((Edge)*SQRT2/2);                                                                    \
242                                                                                                                  \
243   for (Yi=0; Yi<(Divisions); Yi++) {                                                                             \
244     Yf=-((Edge)/2.0) + ((float)Yi)/(Divisions)*(Edge);                                                           \
245     Yf2=sqr(Yf);                                                                                                 \
246     Y=Yf+1.0/(Divisions)*(Edge);                                                                                 \
247     Y2=sqr(Y);                                                                                                   \
248     glBegin(GL_QUAD_STRIP);                                                                                      \
249     for (Xi=0; Xi<=(Divisions); Xi++) {                                                                          \
250       Xf=-((Edge)/2.0) + ((float)Xi)/(Divisions)*(Edge);                                                         \
251       Xf2=sqr(Xf);                                                                                               \
252                                                                                                                  \
253       Xa=Xf+0.001; Yb=Y+0.001;                                                                                   \
254       Factor=1-((Xf2+Y2)*AmpVr2);                                                                                \
255       Factor1=1-(((Xa2=sqr(Xa))+Y2)*AmpVr2);                                                                     \
256       Factor2=1-((Xf2+sqr(Yb))*AmpVr2);                                                                          \
257       VertX=Factor*Xf;        VertY=Factor*Y;         VertZ=Factor*Zf;                                           \
258       NeiAX=Factor1*Xa-VertX; NeiAY=Factor1*Y-VertY;  NeiAZ=Factor1*Zf-VertZ;                                    \
259       NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                    \
260       glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                             \
261       glVertex3f(VertX, VertY, VertZ);                                                                           \
262                                                                                                                  \
263       Yb=Yf+0.001;                                                                                               \
264       Factor=1-((Xf2+Yf2)*AmpVr2);                                                                               \
265       Factor1=1-((Xa2+Yf2)*AmpVr2);                                                                              \
266       Factor2=1-((Xf2+sqr(Yb))*AmpVr2);                                                                          \
267       VertX=Factor*Xf;        VertY=Factor*Yf;        VertZ=Factor*Zf;                                           \
268       NeiAX=Factor1*Xa-VertX; NeiAY=Factor1*Yf-VertY; NeiAZ=Factor1*Zf-VertZ;                                    \
269       NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                    \
270       glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                             \
271       glVertex3f(VertX, VertY, VertZ);                                                                           \
272     }                                                                                                            \
273     glEnd();                                                                                                     \
274   }                                                                                                              \
275   VS=(Factor<0);                                                                                                 \
276 }
277
278 #define PENTAGON(Edge, Amp, Divisions, Z, VS)                                                                    \
279 {                                                                                                                \
280   int       Ri,Ti,Fi;                                                                                            \
281   GLfloat   Xf,Yf,Xa,Yb,Xf2,Yf2;                                                                                 \
282   GLfloat   Factor=0.0,Factor1,Factor2;                                                                          \
283   GLfloat   VertX,VertY,VertZ,NeiAX,NeiAY,NeiAZ,NeiBX,NeiBY,NeiBZ;                                               \
284   GLfloat   Zf=(Edge)*(Z);                                                                                       \
285   GLfloat   AmpVr2=(Amp)/sqr((Edge)*cossec36_2);                                                                 \
286                                                                                                                  \
287   static    GLfloat x[6],y[6];                                                                                   \
288   static    int arrayninit=1;                                                                                    \
289                                                                                                                  \
290   if (arrayninit) {                                                                                              \
291     for(Fi=0;Fi<6;Fi++) {                                                                                        \
292       x[Fi]=-cos( Fi*2*Pi/5 + Pi/10 )/(Divisions)*cossec36_2*(Edge);                                             \
293       y[Fi]=sin( Fi*2*Pi/5 + Pi/10 )/(Divisions)*cossec36_2*(Edge);                                              \
294     }                                                                                                            \
295     arrayninit=0;                                                                                                \
296   }                                                                                                              \
297                                                                                                                  \
298   for (Ri=1; Ri<=(Divisions); Ri++) {                                                                            \
299     for (Fi=0; Fi<5; Fi++) {                                                                                     \
300       glBegin(GL_TRIANGLE_STRIP);                                                                                \
301       for (Ti=0; Ti<Ri; Ti++) {                                                                                  \
302         Xf=(float)(Ri-Ti)*x[Fi] + (float)Ti*x[Fi+1];                                                             \
303         Yf=(float)(Ri-Ti)*y[Fi] + (float)Ti*y[Fi+1];                                                             \
304         Xa=Xf+0.001; Yb=Yf+0.001;                                                                                \
305         Factor=1-(((Xf2=sqr(Xf))+(Yf2=sqr(Yf)))*AmpVr2);                                                         \
306         Factor1=1-((sqr(Xa)+Yf2)*AmpVr2);                                                                        \
307         Factor2=1-((Xf2+sqr(Yb))*AmpVr2);                                                                        \
308         VertX=Factor*Xf;        VertY=Factor*Yf;        VertZ=Factor*Zf;                                         \
309         NeiAX=Factor1*Xa-VertX; NeiAY=Factor1*Yf-VertY; NeiAZ=Factor1*Zf-VertZ;                                  \
310         NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                  \
311         glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                           \
312         glVertex3f(VertX, VertY, VertZ);                                                                         \
313                                                                                                                  \
314         Xf-=x[Fi]; Yf-=y[Fi]; Xa-=x[Fi]; Yb-=y[Fi];                                                              \
315                                                                                                                  \
316         Factor=1-(((Xf2=sqr(Xf))+(Yf2=sqr(Yf)))*AmpVr2);                                                         \
317         Factor1=1-((sqr(Xa)+Yf2)*AmpVr2);                                                                        \
318         Factor2=1-((Xf2+sqr(Yb))*AmpVr2);                                                                        \
319         VertX=Factor*Xf;        VertY=Factor*Yf;        VertZ=Factor*Zf;                                         \
320         NeiAX=Factor1*Xa-VertX; NeiAY=Factor1*Yf-VertY; NeiAZ=Factor1*Zf-VertZ;                                  \
321         NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                  \
322         glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                           \
323         glVertex3f(VertX, VertY, VertZ);                                                                         \
324                                                                                                                  \
325       }                                                                                                          \
326       Xf=(float)Ri*x[Fi+1];                                                                                      \
327       Yf=(float)Ri*y[Fi+1];                                                                                      \
328       Xa=Xf+0.001; Yb=Yf+0.001;                                                                                  \
329       Factor=1-(((Xf2=sqr(Xf))+(Yf2=sqr(Yf)))*AmpVr2);                                                           \
330       Factor1=1-((sqr(Xa)+Yf2)*AmpVr2);                                                                          \
331       Factor2=1-((Xf2+sqr(Yb))*AmpVr2);                                                                          \
332       VertX=Factor*Xf;        VertY=Factor*Yf;        VertZ=Factor*Zf;                                           \
333       NeiAX=Factor1*Xa-VertX; NeiAY=Factor1*Yf-VertY; NeiAZ=Factor1*Zf-VertZ;                                    \
334       NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                    \
335       glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                             \
336       glVertex3f(VertX, VertY, VertZ);                                                                           \
337       glEnd();                                                                                                   \
338     }                                                                                                            \
339   }                                                                                                              \
340   VS=(Factor<0);                                                                                             \
341 }
342
343 static void
344 draw_tetra(ModeInfo * mi)
345 {
346         GLuint      list;
347
348         morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
349
350         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[0]);
351
352         list = glGenLists(1);
353         glNewList(list, GL_COMPILE_AND_EXECUTE);
354         TRIANGLE(2, mp->seno, mp->edgedivisions, 0.5 / SQRT6, mp->VisibleSpikes);
355         glEndList();
356
357         glPushMatrix();
358         glRotatef(180, 0, 0, 1);
359         glRotatef(-tetraangle, 1, 0, 0);
360         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[1]);
361         glCallList(list);
362         glPopMatrix();
363         glPushMatrix();
364         glRotatef(180, 0, 1, 0);
365         glRotatef(-180 + tetraangle, 0.5, SQRT3 / 2, 0);
366         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[2]);
367         glCallList(list);
368         glPopMatrix();
369         glRotatef(180, 0, 1, 0);
370         glRotatef(-180 + tetraangle, 0.5, -SQRT3 / 2, 0);
371         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[3]);
372         glCallList(list);
373
374         glDeleteLists(list, 1);
375 }
376
377 static void
378 draw_cube(ModeInfo * mi)
379 {
380         GLuint      list;
381
382         morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
383
384
385         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[0]);
386
387         list = glGenLists(1);
388         glNewList(list, GL_COMPILE_AND_EXECUTE);
389         SQUARE(2, mp->seno, mp->edgedivisions, 0.5, mp->VisibleSpikes)
390                 glEndList();
391
392         glRotatef(cubeangle, 1, 0, 0);
393         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[1]);
394         glCallList(list);
395         glRotatef(cubeangle, 1, 0, 0);
396         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[2]);
397         glCallList(list);
398         glRotatef(cubeangle, 1, 0, 0);
399         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[3]);
400         glCallList(list);
401         glRotatef(cubeangle, 0, 1, 0);
402         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[4]);
403         glCallList(list);
404         glRotatef(2 * cubeangle, 0, 1, 0);
405         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[5]);
406         glCallList(list);
407
408         glDeleteLists(list, 1);
409 }
410
411 static void
412 draw_octa(ModeInfo * mi)
413 {
414         GLuint      list;
415
416         morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
417
418         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[0]);
419
420         list = glGenLists(1);
421         glNewList(list, GL_COMPILE_AND_EXECUTE);
422         TRIANGLE(2, mp->seno, mp->edgedivisions, 1 / SQRT6, mp->VisibleSpikes);
423         glEndList();
424
425         glPushMatrix();
426         glRotatef(180, 0, 0, 1);
427         glRotatef(-180 + octaangle, 1, 0, 0);
428         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[1]);
429         glCallList(list);
430         glPopMatrix();
431         glPushMatrix();
432         glRotatef(180, 0, 1, 0);
433         glRotatef(-octaangle, 0.5, SQRT3 / 2, 0);
434         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[2]);
435         glCallList(list);
436         glPopMatrix();
437         glPushMatrix();
438         glRotatef(180, 0, 1, 0);
439         glRotatef(-octaangle, 0.5, -SQRT3 / 2, 0);
440         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[3]);
441         glCallList(list);
442         glPopMatrix();
443         glRotatef(180, 1, 0, 0);
444         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[4]);
445         glCallList(list);
446         glPushMatrix();
447         glRotatef(180, 0, 0, 1);
448         glRotatef(-180 + octaangle, 1, 0, 0);
449         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[5]);
450         glCallList(list);
451         glPopMatrix();
452         glPushMatrix();
453         glRotatef(180, 0, 1, 0);
454         glRotatef(-octaangle, 0.5, SQRT3 / 2, 0);
455         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[6]);
456         glCallList(list);
457         glPopMatrix();
458         glRotatef(180, 0, 1, 0);
459         glRotatef(-octaangle, 0.5, -SQRT3 / 2, 0);
460         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[7]);
461         glCallList(list);
462
463         glDeleteLists(list, 1);
464 }
465
466 static void
467 draw_dodeca(ModeInfo * mi)
468 {
469         GLuint      list;
470
471         morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
472
473 #define TAU ((SQRT5+1)/2)
474
475         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[0]);
476
477         list = glGenLists(1);
478         glNewList(list, GL_COMPILE_AND_EXECUTE);
479         PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
480         glEndList();
481
482         glPushMatrix();
483         glRotatef(180, 0, 0, 1);
484         glPushMatrix();
485         glRotatef(-dodecaangle, 1, 0, 0);
486         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[1]);
487         glCallList(list);
488         glPopMatrix();
489         glPushMatrix();
490         glRotatef(-dodecaangle, cos72, sin72, 0);
491         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[2]);
492         glCallList(list);
493         glPopMatrix();
494         glPushMatrix();
495         glRotatef(-dodecaangle, cos72, -sin72, 0);
496         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[3]);
497         glCallList(list);
498         glPopMatrix();
499         glPushMatrix();
500         glRotatef(dodecaangle, cos36, -sin36, 0);
501         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[4]);
502         glCallList(list);
503         glPopMatrix();
504         glRotatef(dodecaangle, cos36, sin36, 0);
505         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[5]);
506         glCallList(list);
507         glPopMatrix();
508         glRotatef(180, 1, 0, 0);
509         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[6]);
510         glCallList(list);
511         glRotatef(180, 0, 0, 1);
512         glPushMatrix();
513         glRotatef(-dodecaangle, 1, 0, 0);
514         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[7]);
515         glCallList(list);
516         glPopMatrix();
517         glPushMatrix();
518         glRotatef(-dodecaangle, cos72, sin72, 0);
519         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[8]);
520         glCallList(list);
521         glPopMatrix();
522         glPushMatrix();
523         glRotatef(-dodecaangle, cos72, -sin72, 0);
524         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[9]);
525         glCallList(list);
526         glPopMatrix();
527         glPushMatrix();
528         glRotatef(dodecaangle, cos36, -sin36, 0);
529         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[10]);
530         glCallList(list);
531         glPopMatrix();
532         glRotatef(dodecaangle, cos36, sin36, 0);
533         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[11]);
534         glCallList(list);
535
536         glDeleteLists(list, 1);
537 }
538
539 static void
540 draw_icosa(ModeInfo * mi)
541 {
542         GLuint      list;
543
544         morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
545
546         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[0]);
547
548         list = glGenLists(1);
549         glNewList(list, GL_COMPILE_AND_EXECUTE);
550         TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
551         glEndList();
552
553         glPushMatrix();
554
555         glPushMatrix();
556         glRotatef(180, 0, 0, 1);
557         glRotatef(-icoangle, 1, 0, 0);
558         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[1]);
559         glCallList(list);
560         glPushMatrix();
561         glRotatef(180, 0, 1, 0);
562         glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
563         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[2]);
564         glCallList(list);
565         glPopMatrix();
566         glRotatef(180, 0, 1, 0);
567         glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
568         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[3]);
569         glCallList(list);
570         glPopMatrix();
571         glPushMatrix();
572         glRotatef(180, 0, 1, 0);
573         glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
574         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[4]);
575         glCallList(list);
576         glPushMatrix();
577         glRotatef(180, 0, 1, 0);
578         glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
579         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[5]);
580         glCallList(list);
581         glPopMatrix();
582         glRotatef(180, 0, 0, 1);
583         glRotatef(-icoangle, 1, 0, 0);
584         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[6]);
585         glCallList(list);
586         glPopMatrix();
587         glRotatef(180, 0, 1, 0);
588         glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
589         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[7]);
590         glCallList(list);
591         glPushMatrix();
592         glRotatef(180, 0, 1, 0);
593         glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
594         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[8]);
595         glCallList(list);
596         glPopMatrix();
597         glRotatef(180, 0, 0, 1);
598         glRotatef(-icoangle, 1, 0, 0);
599         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[9]);
600         glCallList(list);
601         glPopMatrix();
602         glRotatef(180, 1, 0, 0);
603         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[10]);
604         glCallList(list);
605         glPushMatrix();
606         glRotatef(180, 0, 0, 1);
607         glRotatef(-icoangle, 1, 0, 0);
608         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[11]);
609         glCallList(list);
610         glPushMatrix();
611         glRotatef(180, 0, 1, 0);
612         glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
613         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[12]);
614         glCallList(list);
615         glPopMatrix();
616         glRotatef(180, 0, 1, 0);
617         glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
618         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[13]);
619         glCallList(list);
620         glPopMatrix();
621         glPushMatrix();
622         glRotatef(180, 0, 1, 0);
623         glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
624         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[14]);
625         glCallList(list);
626         glPushMatrix();
627         glRotatef(180, 0, 1, 0);
628         glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
629         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[15]);
630         glCallList(list);
631         glPopMatrix();
632         glRotatef(180, 0, 0, 1);
633         glRotatef(-icoangle, 1, 0, 0);
634         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[16]);
635         glCallList(list);
636         glPopMatrix();
637         glRotatef(180, 0, 1, 0);
638         glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
639         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[17]);
640         glCallList(list);
641         glPushMatrix();
642         glRotatef(180, 0, 1, 0);
643         glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
644         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[18]);
645         glCallList(list);
646         glPopMatrix();
647         glRotatef(180, 0, 0, 1);
648         glRotatef(-icoangle, 1, 0, 0);
649         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[19]);
650         glCallList(list);
651
652         glDeleteLists(list, 1);
653 }
654
655 static void
656 reshape(ModeInfo * mi, int width, int height)
657 {
658         morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
659
660         glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
661         glMatrixMode(GL_PROJECTION);
662         glLoadIdentity();
663         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
664         glMatrixMode(GL_MODELVIEW);
665 }
666
667 static void
668 pinit(ModeInfo * mi)
669 {
670         morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
671
672         glClearDepth(1.0);
673         glClearColor(0.0, 0.0, 0.0, 1.0);
674         glColor3f(1.0, 1.0, 1.0);
675
676         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
677         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
678         glLightfv(GL_LIGHT0, GL_POSITION, position0);
679         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
680         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
681         glLightfv(GL_LIGHT1, GL_POSITION, position1);
682         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
683         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
684         glEnable(GL_LIGHTING);
685         glEnable(GL_LIGHT0);
686         glEnable(GL_LIGHT1);
687         glEnable(GL_DEPTH_TEST);
688         glEnable(GL_NORMALIZE);
689
690         glShadeModel(GL_SMOOTH);
691         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
692         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
693
694         switch (mp->object) {
695                 case 2:
696                         mp->draw_object = draw_cube;
697                         mp->MaterialColor[0] = MaterialRed;
698                         mp->MaterialColor[1] = MaterialGreen;
699                         mp->MaterialColor[2] = MaterialCyan;
700                         mp->MaterialColor[3] = MaterialMagenta;
701                         mp->MaterialColor[4] = MaterialYellow;
702                         mp->MaterialColor[5] = MaterialBlue;
703                         mp->edgedivisions = cubedivisions;
704                         mp->Magnitude = 2.0;
705                         break;
706                 case 3:
707                         mp->draw_object = draw_octa;
708                         mp->MaterialColor[0] = MaterialRed;
709                         mp->MaterialColor[1] = MaterialGreen;
710                         mp->MaterialColor[2] = MaterialBlue;
711                         mp->MaterialColor[3] = MaterialWhite;
712                         mp->MaterialColor[4] = MaterialCyan;
713                         mp->MaterialColor[5] = MaterialMagenta;
714                         mp->MaterialColor[6] = MaterialGray;
715                         mp->MaterialColor[7] = MaterialYellow;
716                         mp->edgedivisions = octadivisions;
717                         mp->Magnitude = 2.5;
718                         break;
719                 case 4:
720                         mp->draw_object = draw_dodeca;
721                         mp->MaterialColor[0] = MaterialRed;
722                         mp->MaterialColor[1] = MaterialGreen;
723                         mp->MaterialColor[2] = MaterialCyan;
724                         mp->MaterialColor[3] = MaterialBlue;
725                         mp->MaterialColor[4] = MaterialMagenta;
726                         mp->MaterialColor[5] = MaterialYellow;
727                         mp->MaterialColor[6] = MaterialGreen;
728                         mp->MaterialColor[7] = MaterialCyan;
729                         mp->MaterialColor[8] = MaterialRed;
730                         mp->MaterialColor[9] = MaterialMagenta;
731                         mp->MaterialColor[10] = MaterialBlue;
732                         mp->MaterialColor[11] = MaterialYellow;
733                         mp->edgedivisions = dodecadivisions;
734                         mp->Magnitude = 2.0;
735                         break;
736                 case 5:
737                         mp->draw_object = draw_icosa;
738                         mp->MaterialColor[0] = MaterialRed;
739                         mp->MaterialColor[1] = MaterialGreen;
740                         mp->MaterialColor[2] = MaterialBlue;
741                         mp->MaterialColor[3] = MaterialCyan;
742                         mp->MaterialColor[4] = MaterialYellow;
743                         mp->MaterialColor[5] = MaterialMagenta;
744                         mp->MaterialColor[6] = MaterialRed;
745                         mp->MaterialColor[7] = MaterialGreen;
746                         mp->MaterialColor[8] = MaterialBlue;
747                         mp->MaterialColor[9] = MaterialWhite;
748                         mp->MaterialColor[10] = MaterialCyan;
749                         mp->MaterialColor[11] = MaterialYellow;
750                         mp->MaterialColor[12] = MaterialMagenta;
751                         mp->MaterialColor[13] = MaterialRed;
752                         mp->MaterialColor[14] = MaterialGreen;
753                         mp->MaterialColor[15] = MaterialBlue;
754                         mp->MaterialColor[16] = MaterialCyan;
755                         mp->MaterialColor[17] = MaterialYellow;
756                         mp->MaterialColor[18] = MaterialMagenta;
757                         mp->MaterialColor[19] = MaterialGray;
758                         mp->edgedivisions = icodivisions;
759                         mp->Magnitude = 2.5;
760                         break;
761                 default:
762                         mp->draw_object = draw_tetra;
763                         mp->MaterialColor[0] = MaterialRed;
764                         mp->MaterialColor[1] = MaterialGreen;
765                         mp->MaterialColor[2] = MaterialBlue;
766                         mp->MaterialColor[3] = MaterialWhite;
767                         mp->edgedivisions = tetradivisions;
768                         mp->Magnitude = 2.5;
769                         break;
770         }
771         if (MI_IS_MONO(mi)) {
772                 int         loop;
773
774                 for (loop = 0; loop < 20; loop++)
775                         mp->MaterialColor[loop] = MaterialGray;
776         }
777 }
778
779 void
780 init_morph3d(ModeInfo * mi)
781 {
782         int         screen = MI_SCREEN(mi);
783         morph3dstruct *mp;
784
785         if (morph3d == NULL) {
786                 if ((morph3d = (morph3dstruct *) calloc(MI_NUM_SCREENS(mi),
787                                             sizeof (morph3dstruct))) == NULL)
788                         return;
789         }
790         mp = &morph3d[screen];
791         mp->step = NRAND(90);
792         mp->VisibleSpikes = 1;
793
794         if ((mp->glx_context = init_GL(mi)) != NULL) {
795
796                 reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
797                 mp->object = MI_COUNT(mi);
798                 if (mp->object <= 0 || mp->object > 5)
799                         mp->object = NRAND(5) + 1;
800                 pinit(mi);
801         } else {
802                 MI_CLEARWINDOW(mi);
803         }
804 }
805
806 void
807 draw_morph3d(ModeInfo * mi)
808 {
809         morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
810
811         Display    *display = MI_DISPLAY(mi);
812         Window      window = MI_WINDOW(mi);
813
814         if (!mp->glx_context)
815                 return;
816
817         glDrawBuffer(GL_BACK);
818         glXMakeCurrent(display, window, *(mp->glx_context));
819
820         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
821
822         glPushMatrix();
823
824         glTranslatef(0.0, 0.0, -10.0);
825
826         if (!MI_IS_ICONIC(mi)) {
827                 glScalef(Scale4Window * mp->WindH / mp->WindW, Scale4Window, Scale4Window);
828                 glTranslatef(2.5 * mp->WindW / mp->WindH * sin(mp->step * 1.11), 2.5 * cos(mp->step * 1.25 * 1.11), 0);
829         } else {
830                 glScalef(Scale4Iconic * mp->WindH / mp->WindW, Scale4Iconic, Scale4Iconic);
831         }
832
833         glRotatef(mp->step * 100, 1, 0, 0);
834         glRotatef(mp->step * 95, 0, 1, 0);
835         glRotatef(mp->step * 90, 0, 0, 1);
836
837         mp->seno = (sin(mp->step) + 1.0 / 3.0) * (4.0 / 5.0) * mp->Magnitude;
838
839         if (mp->VisibleSpikes) {
840 #ifdef DEBUG_CULL_FACE
841                 int         loop;
842
843                 for (loop = 0; loop < 20; loop++)
844                         mp->MaterialColor[loop] = MaterialGray;
845 #endif
846                 glDisable(GL_CULL_FACE);
847         } else {
848 #ifdef DEBUG_CULL_FACE
849                 int         loop;
850
851                 for (loop = 0; loop < 20; loop++)
852                         mp->MaterialColor[loop] = MaterialWhite;
853 #endif
854                 glEnable(GL_CULL_FACE);
855         }
856
857         mp->draw_object(mi);
858
859         glPopMatrix();
860
861         glFlush();
862
863         glXSwapBuffers(display, window);
864
865         mp->step += 0.05;
866 }
867
868 void
869 change_morph3d(ModeInfo * mi)
870 {
871         morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
872
873         if (!mp->glx_context)
874                 return;
875
876         mp->object = (mp->object) % 5 + 1;
877         pinit(mi);
878 }
879
880 void
881 release_morph3d(ModeInfo * mi)
882 {
883         if (morph3d != NULL) {
884                 (void) free((void *) morph3d);
885                 morph3d = NULL;
886         }
887         FreeAllGL(mi);
888 }
889
890 #endif