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