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