http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.29.tar.gz
[xscreensaver] / hacks / glx / moebius.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* moebius --- Moebius Strip II, an Escher-like GL scene with ants. */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)moebius.c     4.08 97/01/04 xlockmore";
6
7 #endif
8
9 #undef DEBUG_LISTS
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 RotateAroundU() routine was adapted from the book
25  *    "Computer Graphics Principles and Practice 
26  *     Foley - vanDam - Feiner - Hughes
27  *     Second Edition" Pag. 227, exercise 5.15.
28  * 
29  * This mode shows some interesting scenes that are impossible OR very
30  * wierd to build in the real universe. Much of the scenes are inspirated
31  * on Mauritz Cornelis Escher's works which derivated the mode's name.
32  * M.C. Escher (1898-1972) was a dutch artist and many people prefer to
33  * say he was a mathematician.
34  *
35  * Thanks goes to Brian Paul for making it possible and inexpensive to use 
36  * OpenGL at home.
37  *
38  * Since I'm not a native English speaker, my apologies for any grammatical
39  * mistake.
40  *
41  * My e-mail address is
42  * m-vianna@usa.net
43  *
44  * Marcelo F. Vianna (Jun-01-1997)
45  *
46  * Revision History:
47  * 01-Jan-98: Mode separated from escher and renamed
48  * 08-Jun-97: New scene implemented: "Impossible Cage" based in a M.C. Escher's
49  *            painting with the same name (quite similar). The first GL mode
50  *            to use texture mapping.
51  *            The "Impossible Cage" scene doesn't use DEPTH BUFFER, the 
52  *            wood planks are drawn consistently using GL_CULL_FACE, and
53  *            the painter's algorithm is used to sort the planks.
54  *            Marcelo F. Vianna.
55  * 07-Jun-97: Speed ups in Moebius Strip using GL_CULL_FACE.
56  *            Marcelo F. Vianna.
57  * 03-Jun-97: Initial Release (Only one scene: "Moebius Strip")
58  *            The Moebius Strip scene was inspirated in a M.C. Escher's
59  *            painting named Moebius Strip II in wich ants walk across a
60  *            Moebius Strip path, sometimes meeting each other and sometimes
61  *            being in "opposite faces" (note that the moebius strip has
62  *            only one face and one edge).
63  *            Marcelo F. Vianna.
64  *
65  */
66
67 /*-
68  * Texture mapping is only available on RGBA contexts, Mono and color index
69  * visuals DO NOT support texture mapping in OpenGL.
70  *
71  * BUT Mesa do implements RGBA contexts in pseudo color visuals, so texture
72  * mapping shuld work on PseudoColor, DirectColor, TrueColor using Mesa. Mono
73  * is not officially supported for both OpenGL and Mesa, but seems to not crash
74  * Mesa.
75  *
76  * In real OpenGL, PseudoColor DO NOT support texture map (as far as I know).
77  */
78
79 #include <X11/Intrinsic.h>
80
81 #ifdef STANDALONE
82 # define PROGCLASS                      "Moebius"
83 # define HACK_INIT                      init_moebius
84 # define HACK_DRAW                      draw_moebius
85 # define HACK_RESHAPE           reshape_moebius
86 # define moebius_opts           xlockmore_opts
87 # define DEFAULTS                       "*cycles:               1       \n"                     \
88                                                         "*delay:                20000   \n"                     \
89                                                         "*showFPS:      False   \n"                     \
90                                                         "*wireframe:    False   \n"
91 # include "xlockmore.h"         /* from the xscreensaver distribution */
92 #else /* !STANDALONE */
93 # include "xlock.h"             /* from the xlockmore distribution */
94
95 #endif /* !STANDALONE */
96
97 #ifdef USE_GL
98
99
100 #include <GL/glu.h>
101 #include "e_textures.h"
102
103 #define DEF_SOLIDMOEBIUS  "False"
104 #define DEF_NOANTS  "False"
105
106 static int  solidmoebius;
107 static int  noants;
108
109 static XrmOptionDescRec opts[] =
110 {
111   {"-solidmoebius", ".moebius.solidmoebius", XrmoptionNoArg, (caddr_t) "on"},
112  {"+solidmoebius", ".moebius.solidmoebius", XrmoptionNoArg, (caddr_t) "off"},
113         {"-noants", ".moebius.noants", XrmoptionNoArg, (caddr_t) "on"},
114         {"+noants", ".moebius.noants", XrmoptionNoArg, (caddr_t) "off"}
115 };
116 static argtype vars[] =
117 {
118         {(caddr_t *) & solidmoebius, "solidmoebius", "Solidmoebius", DEF_SOLIDMOEBIUS, t_Bool},
119         {(caddr_t *) & noants, "noants", "Noants", DEF_NOANTS, t_Bool}
120 };
121 static OptionStruct desc[] =
122 {
123         {"-/+solidmoebius", "select between a SOLID or a NET Moebius Strip"},
124         {"-/+noants", "turn on/off walking ants"}
125 };
126
127 ModeSpecOpt moebius_opts =
128 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
129
130 #ifdef USE_MODULES
131 ModStruct   moebius_description =
132 {"moebius", "init_moebius", "draw_moebius", "release_moebius",
133  "draw_moebius", "change_moebius", NULL, &moebius_opts,
134  1000, 1, 1, 1, 4, 1.0, "",
135  "Shows Moebius Strip II, an Escher-like GL scene with ants", 0, NULL};
136
137 #endif
138
139 #define Scale4Window               0.3
140 #define Scale4Iconic               0.4
141
142 #define sqr(A)                     ((A)*(A))
143
144 #ifndef Pi
145 #define Pi                         M_PI
146 #endif
147
148 /*************************************************************************/
149
150 typedef struct {
151         GLint       WindH, WindW;
152         GLfloat     step;
153         GLfloat     ant_position;
154         int         AreObjectsDefined[2];
155         GLXContext *glx_context;
156
157   GLfloat rotx, roty, rotz;        /* current object rotation */
158   GLfloat dx, dy, dz;              /* current rotational velocity */
159   GLfloat ddx, ddy, ddz;           /* current rotational acceleration */
160   GLfloat d_max;                           /* max velocity */
161
162 } moebiusstruct;
163
164 static float front_shininess[] =
165 {60.0};
166 static float front_specular[] =
167 {0.7, 0.7, 0.7, 1.0};
168 static float ambient[] =
169 {0.0, 0.0, 0.0, 1.0};
170 static float diffuse[] =
171 {1.0, 1.0, 1.0, 1.0};
172 static float position0[] =
173 {1.0, 1.0, 1.0, 0.0};
174 static float position1[] =
175 {-1.0, -1.0, 1.0, 0.0};
176 static float lmodel_ambient[] =
177 {0.5, 0.5, 0.5, 1.0};
178 static float lmodel_twoside[] =
179 {GL_TRUE};
180
181 static float MaterialRed[] =
182 {0.7, 0.0, 0.0, 1.0};
183 static float MaterialGreen[] =
184 {0.1, 0.5, 0.2, 1.0};
185 static float MaterialBlue[] =
186 {0.0, 0.0, 0.7, 1.0};
187 static float MaterialCyan[] =
188 {0.2, 0.5, 0.7, 1.0};
189 static float MaterialYellow[] =
190 {0.7, 0.7, 0.0, 1.0};
191 static float MaterialMagenta[] =
192 {0.6, 0.2, 0.5, 1.0};
193 static float MaterialWhite[] =
194 {0.7, 0.7, 0.7, 1.0};
195 static float MaterialGray[] =
196 {0.2, 0.2, 0.2, 1.0};
197 static float MaterialGray5[] =
198 {0.5, 0.5, 0.5, 1.0};
199 static float MaterialGray6[] =
200 {0.6, 0.6, 0.6, 1.0};
201 static float MaterialGray8[] =
202 {0.8, 0.8, 0.8, 1.0};
203
204 static moebiusstruct *moebius = NULL;
205 static GLuint objects;
206
207 #define NUM_SCENES      2
208
209 #define ObjMoebiusStrip 0
210 #define ObjAntBody      1
211
212 static void
213 mySphere(float radius)
214 {
215         GLUquadricObj *quadObj;
216
217         quadObj = gluNewQuadric();
218         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
219         gluSphere(quadObj, radius, 16, 16);
220         gluDeleteQuadric(quadObj);
221 }
222
223 static void
224 myCone(float radius)
225 {
226         GLUquadricObj *quadObj;
227
228         quadObj = gluNewQuadric();
229         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
230         gluCylinder(quadObj, radius, 0, radius * 3, 8, 1);
231         gluDeleteQuadric(quadObj);
232 }
233
234 static void
235 draw_moebius_ant(moebiusstruct * mp, float *Material, int mono)
236 {
237         static float ant_step = 0;
238         float       cos1 = cos(ant_step);
239         float       cos2 = cos(ant_step + 2 * Pi / 3);
240         float       cos3 = cos(ant_step + 4 * Pi / 3);
241         float       sin1 = sin(ant_step);
242         float       sin2 = sin(ant_step + 2 * Pi / 3);
243         float       sin3 = sin(ant_step + 4 * Pi / 3);
244
245         if (mono)
246                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
247         else
248                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Material);
249         if (!mp->AreObjectsDefined[ObjAntBody]) {
250                 glNewList(objects + ObjAntBody, GL_COMPILE_AND_EXECUTE);
251                 glEnable(GL_CULL_FACE);
252                 glPushMatrix();
253                 glScalef(1, 1.3, 1);
254                 mySphere(0.18);
255                 glScalef(1, 1 / 1.3, 1);
256                 glTranslatef(0.00, 0.30, 0.00);
257                 mySphere(0.2);
258
259                 glTranslatef(-0.05, 0.17, 0.05);
260                 glRotatef(-90, 1, 0, 0);
261                 glRotatef(-25, 0, 1, 0);
262                 myCone(0.05);
263                 glTranslatef(0.00, 0.10, 0.00);
264                 myCone(0.05);
265                 glRotatef(25, 0, 1, 0);
266                 glRotatef(90, 1, 0, 0);
267
268                 glScalef(1, 1.3, 1);
269                 glTranslatef(0.15, -0.65, 0.05);
270                 mySphere(0.25);
271                 glScalef(1, 1 / 1.3, 1);
272                 glPopMatrix();
273                 glDisable(GL_CULL_FACE);
274                 glEndList();
275                 mp->AreObjectsDefined[ObjAntBody] = 1;
276 #ifdef DEBUG_LISTS
277                 (void) printf("Ant drawn SLOWLY\n");
278 #endif
279         } else {
280                 glCallList(objects + ObjAntBody);
281 #ifdef DEBUG_LISTS
282                 (void) printf("Ant drawn quickly\n");
283 #endif
284         }
285
286         glDisable(GL_LIGHTING);
287         /* ANTENNAS */
288         glBegin(GL_LINES);
289         if (mono)
290                 glColor3fv(MaterialGray5);
291         else
292                 glColor3fv(Material);
293         glVertex3f(0.00, 0.30, 0.00);
294         glColor3fv(MaterialGray);
295         glVertex3f(0.40, 0.70, 0.40);
296         if (mono)
297                 glColor3fv(MaterialGray5);
298         else
299                 glColor3fv(Material);
300         glVertex3f(0.00, 0.30, 0.00);
301         glColor3fv(MaterialGray);
302         glVertex3f(0.40, 0.70, -0.40);
303         glEnd();
304         glBegin(GL_POINTS);
305         if (mono)
306                 glColor3fv(MaterialGray6);
307         else
308                 glColor3fv(MaterialRed);
309         glVertex3f(0.40, 0.70, 0.40);
310         glVertex3f(0.40, 0.70, -0.40);
311         glEnd();
312
313         /* LEFT-FRONT ARM */
314         glBegin(GL_LINE_STRIP);
315         if (mono)
316                 glColor3fv(MaterialGray5);
317         else
318                 glColor3fv(Material);
319         glVertex3f(0.00, 0.05, 0.18);
320         glVertex3f(0.35 + 0.05 * cos1, 0.15, 0.25);
321         glColor3fv(MaterialGray);
322         glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
323         glEnd();
324
325         /* LEFT-CENTER ARM */
326         glBegin(GL_LINE_STRIP);
327         if (mono)
328                 glColor3fv(MaterialGray5);
329         else
330                 glColor3fv(Material);
331         glVertex3f(0.00, 0.00, 0.18);
332         glVertex3f(0.35 + 0.05 * cos2, 0.00, 0.25);
333         glColor3fv(MaterialGray);
334         glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
335         glEnd();
336
337         /* LEFT-BACK ARM */
338         glBegin(GL_LINE_STRIP);
339         if (mono)
340                 glColor3fv(MaterialGray5);
341         else
342                 glColor3fv(Material);
343         glVertex3f(0.00, -0.05, 0.18);
344         glVertex3f(0.35 + 0.05 * cos3, -0.15, 0.25);
345         glColor3fv(MaterialGray);
346         glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
347         glEnd();
348
349         /* RIGHT-FRONT ARM */
350         glBegin(GL_LINE_STRIP);
351         if (mono)
352                 glColor3fv(MaterialGray5);
353         else
354                 glColor3fv(Material);
355         glVertex3f(0.00, 0.05, -0.18);
356         glVertex3f(0.35 - 0.05 * sin1, 0.15, -0.25);
357         glColor3fv(MaterialGray);
358         glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
359         glEnd();
360
361         /* RIGHT-CENTER ARM */
362         glBegin(GL_LINE_STRIP);
363         if (mono)
364                 glColor3fv(MaterialGray5);
365         else
366                 glColor3fv(Material);
367         glVertex3f(0.00, 0.00, -0.18);
368         glVertex3f(0.35 - 0.05 * sin2, 0.00, -0.25);
369         glColor3fv(MaterialGray);
370         glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
371         glEnd();
372
373         /* RIGHT-BACK ARM */
374         glBegin(GL_LINE_STRIP);
375         if (mono)
376                 glColor3fv(MaterialGray5);
377         else
378                 glColor3fv(Material);
379         glVertex3f(0.00, -0.05, -0.18);
380         glVertex3f(0.35 - 0.05 * sin3, -0.15, -0.25);
381         glColor3fv(MaterialGray);
382         glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
383         glEnd();
384
385         glBegin(GL_POINTS);
386         if (mono)
387                 glColor3fv(MaterialGray8);
388         else
389                 glColor3fv(MaterialMagenta);
390         glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
391         glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
392         glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
393         glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
394         glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
395         glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
396         glEnd();
397
398         glEnable(GL_LIGHTING);
399
400         ant_step += 0.3;
401 }
402
403 static void
404 RotateAaroundU(float Ax, float Ay, float Az,
405                float Ux, float Uy, float Uz,
406                float *Cx, float *Cy, float *Cz,
407                float Theta)
408 {
409         float       cosO = cos(Theta);
410         float       sinO = sin(Theta);
411         float       one_cosO = 1 - cosO;
412         float       Ux2 = sqr(Ux);
413         float       Uy2 = sqr(Uy);
414         float       Uz2 = sqr(Uz);
415         float       UxUy = Ux * Uy;
416         float       UxUz = Ux * Uz;
417         float       UyUz = Uy * Uz;
418
419         *Cx = (Ux2 + cosO * (1 - Ux2)) * Ax + (UxUy * one_cosO - Uz * sinO) * Ay + (UxUz * one_cosO + Uy * sinO) * Az;
420         *Cy = (UxUy * one_cosO + Uz * sinO) * Ax + (Uy2 + cosO * (1 - Uy2)) * Ay + (UyUz * one_cosO - Ux * sinO) * Az;
421         *Cz = (UxUz * one_cosO - Uy * sinO) * Ax + (UyUz * one_cosO + Ux * sinO) * Ay + (Uz2 + cosO * (1 - Uz2)) * Az;
422 }
423
424 #define MoebiusDivisions 40
425 #define MoebiusTransversals 4
426 static void
427 draw_moebius_strip(ModeInfo * mi)
428 {
429         GLfloat     Phi, Theta;
430         GLfloat     cPhi, sPhi;
431         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
432         int         i, j;
433         int         mono = MI_IS_MONO(mi);
434
435         float       Cx, Cy, Cz;
436
437         if (!mp->AreObjectsDefined[ObjMoebiusStrip]) {
438                 glNewList(objects + ObjMoebiusStrip, GL_COMPILE_AND_EXECUTE);
439
440                 if (solidmoebius) {
441                         glBegin(GL_QUAD_STRIP);
442                         Phi = 0;
443                         i = 0;
444                         while (i < (MoebiusDivisions * 2 + 1)) {
445                                 Theta = Phi / 2;
446                                 cPhi = cos(Phi);
447                                 sPhi = sin(Phi);
448
449                                 i++;
450                                 if (mono)
451                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
452                                 else if (i % 2)
453                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
454                                 else
455                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
456
457                                 RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
458                                 glNormal3f(Cx, Cy, Cz);
459                                 RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
460                                 glVertex3f(cPhi * 3 + Cx, sPhi * 3 + Cy, +Cz);
461                                 glVertex3f(cPhi * 3 - Cx, sPhi * 3 - Cy, -Cz);
462
463                                 Phi += Pi / MoebiusDivisions;
464                         }
465                         glEnd();
466                 } else {
467                         for (j = -MoebiusTransversals; j < MoebiusTransversals; j++) {
468                                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
469                                 glBegin(GL_QUAD_STRIP);
470                                 Phi = 0;
471                                 i = 0;
472                                 while (i < (MoebiusDivisions * 2 + 1)) {
473                                         Theta = Phi / 2;
474                                         cPhi = cos(Phi);
475                                         sPhi = sin(Phi);
476
477                                         RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
478                                         glNormal3f(Cx, Cy, Cz);
479                                         RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
480                                         j++;
481                                         if (j == MoebiusTransversals || mono)
482                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
483                                         else if (i % 2)
484                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
485                                         else
486                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
487                                         glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
488                                         j--;
489                                         if (j == -MoebiusTransversals || mono)
490                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
491                                         else if (i % 2)
492                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
493                                         else
494                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
495                                         glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
496
497                                         Phi += Pi / MoebiusDivisions;
498                                         i++;
499                                 }
500                                 glEnd();
501                         }
502                         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
503                 }
504
505                 glEndList();
506                 mp->AreObjectsDefined[ObjMoebiusStrip] = 1;
507 #ifdef DEBUG_LISTS
508                 (void) printf("Strip drawn SLOWLY\n");
509 #endif
510         } else {
511                 glCallList(objects + ObjMoebiusStrip);
512 #ifdef DEBUG_LISTS
513                 (void) printf("Strip drawn quickly\n");
514 #endif
515         }
516
517         if (!noants) {
518                 /* DRAW BLUE ANT */
519                 glPushMatrix();
520                 glRotatef(mp->ant_position + 180, 0, 0, 1);
521                 glTranslatef(3, 0, 0);
522                 glRotatef(mp->ant_position / 2 + 90, 0, 1, 0);
523                 glTranslatef(0.28, 0, -0.45);
524                 draw_moebius_ant(mp, MaterialYellow, mono);
525                 glPopMatrix();
526
527                 /* DRAW YELLOW ANT */
528                 glPushMatrix();
529                 glRotatef(mp->ant_position, 0, 0, 1);
530                 glTranslatef(3, 0, 0);
531                 glRotatef(mp->ant_position / 2, 0, 1, 0);
532                 glTranslatef(0.28, 0, -0.45);
533                 draw_moebius_ant(mp, MaterialBlue, mono);
534                 glPopMatrix();
535
536                 /* DRAW GREEN ANT */
537                 glPushMatrix();
538                 glRotatef(-mp->ant_position, 0, 0, 1);
539                 glTranslatef(3, 0, 0);
540                 glRotatef(-mp->ant_position / 2, 0, 1, 0);
541                 glTranslatef(0.28, 0, 0.45);
542                 glRotatef(180, 1, 0, 0);
543                 draw_moebius_ant(mp, MaterialGreen, mono);
544                 glPopMatrix();
545
546                 /* DRAW CYAN ANT */
547                 glPushMatrix();
548                 glRotatef(-mp->ant_position + 180, 0, 0, 1);
549                 glTranslatef(3, 0, 0);
550                 glRotatef(-mp->ant_position / 2 + 90, 0, 1, 0);
551                 glTranslatef(0.28, 0, 0.45);
552                 glRotatef(180, 1, 0, 0);
553                 draw_moebius_ant(mp, MaterialCyan, mono);
554                 glPopMatrix();
555         }
556         mp->ant_position += 1;
557 }
558 #undef MoebiusDivisions
559 #undef MoebiusTransversals
560
561 void
562 reshape_moebius(ModeInfo * mi, int width, int height)
563 {
564         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
565
566         glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
567         glMatrixMode(GL_PROJECTION);
568         glLoadIdentity();
569         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
570         glMatrixMode(GL_MODELVIEW);
571         if (width >= 1024) {
572                 glLineWidth(3);
573                 glPointSize(3);
574         } else if (width >= 512) {
575                 glLineWidth(2);
576                 glPointSize(2);
577         } else {
578                 glLineWidth(1);
579                 glPointSize(1);
580         }
581         mp->AreObjectsDefined[ObjMoebiusStrip] = 0;
582         mp->AreObjectsDefined[ObjAntBody] = 0;
583 }
584
585 static void
586 pinit(void)
587 {
588         glClearDepth(1.0);
589         glClearColor(0.0, 0.0, 0.0, 1.0);
590
591         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
592         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
593         glLightfv(GL_LIGHT0, GL_POSITION, position0);
594         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
595         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
596         glLightfv(GL_LIGHT1, GL_POSITION, position1);
597         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
598         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
599         glEnable(GL_LIGHTING);
600         glEnable(GL_LIGHT0);
601         glEnable(GL_LIGHT1);
602         glEnable(GL_NORMALIZE);
603         glFrontFace(GL_CCW);
604         glCullFace(GL_BACK);
605
606         /* moebius */
607         glShadeModel(GL_SMOOTH);
608         glEnable(GL_DEPTH_TEST);
609         glDisable(GL_TEXTURE_2D);
610         glDisable(GL_CULL_FACE);
611
612         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
613         gluBuild2DMipmaps(GL_TEXTURE_2D, 3, WoodTextureWidth, WoodTextureHeight,
614                           GL_RGB, GL_UNSIGNED_BYTE, WoodTextureData);
615         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
616         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
617         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
618         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
619         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
620
621         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
622         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
623 }
624
625
626
627 /* lifted from lament.c */
628 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
629 #define RANDSIGN() ((random() & 1) ? 1 : -1)
630
631 static void
632 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
633 {
634   double ppos = *pos;
635
636   /* tick position */
637   if (ppos < 0)
638     ppos = -(ppos + *v);
639   else
640     ppos += *v;
641
642   if (ppos > 1.0)
643     ppos -= 1.0;
644   else if (ppos < 0)
645     ppos += 1.0;
646
647   if (ppos < 0) abort();
648   if (ppos > 1.0) abort();
649   *pos = (*pos > 0 ? ppos : -ppos);
650
651   /* accelerate */
652   *v += *dv;
653
654   /* clamp velocity */
655   if (*v > max_v || *v < -max_v)
656     {
657       *dv = -*dv;
658     }
659   /* If it stops, start it going in the other direction. */
660   else if (*v < 0)
661     {
662       if (random() % 4)
663         {
664           *v = 0;
665
666           /* keep going in the same direction */
667           if (random() % 2)
668             *dv = 0;
669           else if (*dv < 0)
670             *dv = -*dv;
671         }
672       else
673         {
674           /* reverse gears */
675           *v = -*v;
676           *dv = -*dv;
677           *pos = -*pos;
678         }
679     }
680
681   /* Alter direction of rotational acceleration randomly. */
682   if (! (random() % 120))
683     *dv = -*dv;
684
685   /* Change acceleration very occasionally. */
686   if (! (random() % 200))
687     {
688       if (*dv == 0)
689         *dv = 0.00001;
690       else if (random() & 1)
691         *dv *= 1.2;
692       else
693         *dv *= 0.8;
694     }
695 }
696
697
698 void
699 init_moebius(ModeInfo * mi)
700 {
701         int         screen = MI_SCREEN(mi);
702         moebiusstruct *mp;
703
704         if (moebius == NULL) {
705                 if ((moebius = (moebiusstruct *) calloc(MI_NUM_SCREENS(mi),
706                                             sizeof (moebiusstruct))) == NULL)
707                         return;
708         }
709         mp = &moebius[screen];
710         mp->step = NRAND(90);
711         mp->ant_position = NRAND(90);
712
713     mp->rotx = frand(1.0) * RANDSIGN();
714     mp->roty = frand(1.0) * RANDSIGN();
715     mp->rotz = frand(1.0) * RANDSIGN();
716
717     /* bell curve from 0-1.5 degrees, avg 0.75 */
718     mp->dx = (frand(1) + frand(1) + frand(1)) / (360*2);
719     mp->dy = (frand(1) + frand(1) + frand(1)) / (360*2);
720     mp->dz = (frand(1) + frand(1) + frand(1)) / (360*2);
721
722     mp->d_max = mp->dx * 2;
723
724     mp->ddx = 0.00006 + frand(0.00003);
725     mp->ddy = 0.00006 + frand(0.00003);
726     mp->ddz = 0.00006 + frand(0.00003);
727
728     mp->ddx = 0.00001;
729     mp->ddy = 0.00001;
730     mp->ddz = 0.00001;
731
732         if ((mp->glx_context = init_GL(mi)) != NULL) {
733
734                 reshape_moebius(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
735                 glDrawBuffer(GL_BACK);
736                 if (!glIsList(objects))
737                         objects = glGenLists(3);
738                 pinit();
739         } else {
740                 MI_CLEARWINDOW(mi);
741         }
742 }
743
744 void
745 draw_moebius(ModeInfo * mi)
746 {
747         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
748
749         Display    *display = MI_DISPLAY(mi);
750         Window      window = MI_WINDOW(mi);
751
752         if (!mp->glx_context)
753                 return;
754
755         glXMakeCurrent(display, window, *(mp->glx_context));
756
757         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
758
759         glPushMatrix();
760
761         glTranslatef(0.0, 0.0, -10.0);
762
763         if (!MI_IS_ICONIC(mi)) {
764                 glScalef(Scale4Window * mp->WindH / mp->WindW, Scale4Window, Scale4Window);
765         } else {
766                 glScalef(Scale4Iconic * mp->WindH / mp->WindW, Scale4Iconic, Scale4Iconic);
767         }
768
769     {
770       GLfloat x = mp->rotx;
771       GLfloat y = mp->roty;
772       GLfloat z = mp->rotz;
773       if (x < 0) x = 1 - (x + 1);
774       if (y < 0) y = 1 - (y + 1);
775       if (z < 0) z = 1 - (z + 1);
776       glRotatef(x * 360, 1.0, 0.0, 0.0);
777       glRotatef(y * 360, 0.0, 1.0, 0.0);
778       glRotatef(z * 360, 0.0, 0.0, 1.0);
779     }
780
781         /* moebius */
782         draw_moebius_strip(mi);
783
784         glPopMatrix();
785
786     rotate(&mp->rotx, &mp->dx, &mp->ddx, mp->d_max);
787     rotate(&mp->roty, &mp->dy, &mp->ddy, mp->d_max);
788     rotate(&mp->rotz, &mp->dz, &mp->ddz, mp->d_max);
789
790     if (mi->fps_p) do_fps (mi);
791         glFlush();
792
793         glXSwapBuffers(display, window);
794
795         mp->step += 0.025;
796 }
797
798 void
799 change_moebius(ModeInfo * mi)
800 {
801         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
802
803         if (!mp->glx_context)
804                 return;
805
806         glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
807         pinit();
808 }
809
810 void
811 release_moebius(ModeInfo * mi)
812 {
813         if (moebius != NULL) {
814                 (void) free((void *) moebius);
815                 moebius = NULL;
816         }
817         if (glIsList(objects)) {
818                 glDeleteLists(objects, 3);
819         }
820         FreeAllGL(mi);
821 }
822
823 #endif