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