http://ftp.x.org/contrib/applications/xscreensaver-2.17.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 addresses are
42  * vianna@cat.cbpf.br 
43  *         and
44  * m-vianna@usa.net
45  *
46  * Marcelo F. Vianna (Jun-01-1997)
47  *
48  * Revision History:
49  * 01-Jan-98: Mode separated from escher and renamed
50  * 08-Jun-97: New scene implemented: "Impossible Cage" based in a M.C. Escher's
51  *            painting with the same name (quite similar). The first GL mode
52  *            to use texture mapping.
53  *            The "Impossible Cage" scene doesn't use DEPTH BUFFER, the 
54  *            wood planks are drawn consistently using GL_CULL_FACE, and
55  *            the painter's algorithm is used to sort the planks.
56  *            Marcelo F. Vianna.
57  * 07-Jun-97: Speed ups in Moebius Strip using GL_CULL_FACE.
58  *            Marcelo F. Vianna.
59  * 03-Jun-97: Initial Release (Only one scene: "Moebius Strip")
60  *            The Moebius Strip scene was inspirated in a M.C. Escher's
61  *            painting named Moebius Strip II in wich ants walk across a
62  *            Moebius Strip path, sometimes meeting each other and sometimes
63  *            being in "opposite faces" (note that the moebius strip has
64  *            only one face and one edge).
65  *            Marcelo F. Vianna.
66  *
67  */
68
69 /*-
70  * Texture mapping is only available on RGBA contexts, Mono and color index
71  * visuals DO NOT support texture mapping in OpenGL.
72  *
73  * BUT Mesa do implements RGBA contexts in pseudo color visuals, so texture
74  * mapping shuld work on PseudoColor, DirectColor, TrueColor using Mesa. Mono
75  * is not officially supported for both OpenGL and Mesa, but seems to not crash
76  * Mesa.
77  *
78  * In real OpenGL, PseudoColor DO NOT support texture map (as far as I know).
79  */
80
81 #include <X11/Intrinsic.h>
82
83 #ifdef STANDALONE
84 # define PROGCLASS                      "Moebius"
85 # define HACK_INIT                      init_moebius
86 # define HACK_DRAW                      draw_moebius
87 # define moebius_opts                   xlockmore_opts
88 # define DEFAULTS                       "*cycles:               1       \n"                     \
89                                                         "*delay:                1000    \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 } moebiusstruct;
157
158 static float front_shininess[] =
159 {60.0};
160 static float front_specular[] =
161 {0.7, 0.7, 0.7, 1.0};
162 static float ambient[] =
163 {0.0, 0.0, 0.0, 1.0};
164 static float diffuse[] =
165 {1.0, 1.0, 1.0, 1.0};
166 static float position0[] =
167 {1.0, 1.0, 1.0, 0.0};
168 static float position1[] =
169 {-1.0, -1.0, 1.0, 0.0};
170 static float lmodel_ambient[] =
171 {0.5, 0.5, 0.5, 1.0};
172 static float lmodel_twoside[] =
173 {GL_TRUE};
174
175 static float MaterialRed[] =
176 {0.7, 0.0, 0.0, 1.0};
177 static float MaterialGreen[] =
178 {0.1, 0.5, 0.2, 1.0};
179 static float MaterialBlue[] =
180 {0.0, 0.0, 0.7, 1.0};
181 static float MaterialCyan[] =
182 {0.2, 0.5, 0.7, 1.0};
183 static float MaterialYellow[] =
184 {0.7, 0.7, 0.0, 1.0};
185 static float MaterialMagenta[] =
186 {0.6, 0.2, 0.5, 1.0};
187 static float MaterialWhite[] =
188 {0.7, 0.7, 0.7, 1.0};
189 static float MaterialGray[] =
190 {0.2, 0.2, 0.2, 1.0};
191 static float MaterialGray5[] =
192 {0.5, 0.5, 0.5, 1.0};
193 static float MaterialGray6[] =
194 {0.6, 0.6, 0.6, 1.0};
195 static float MaterialGray8[] =
196 {0.8, 0.8, 0.8, 1.0};
197
198 static moebiusstruct *moebius = NULL;
199 static GLuint objects;
200
201 #define NUM_SCENES      2
202
203 #define ObjMoebiusStrip 0
204 #define ObjAntBody      1
205
206 static void
207 mySphere(float radius)
208 {
209         GLUquadricObj *quadObj;
210
211         quadObj = gluNewQuadric();
212         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
213         gluSphere(quadObj, radius, 16, 16);
214         gluDeleteQuadric(quadObj);
215 }
216
217 static void
218 myCone(float radius)
219 {
220         GLUquadricObj *quadObj;
221
222         quadObj = gluNewQuadric();
223         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
224         gluCylinder(quadObj, radius, 0, radius * 3, 8, 1);
225         gluDeleteQuadric(quadObj);
226 }
227
228 static void
229 draw_moebius_ant(moebiusstruct * mp, float *Material, int mono)
230 {
231         static float ant_step = 0;
232         float       cos1 = cos(ant_step);
233         float       cos2 = cos(ant_step + 2 * Pi / 3);
234         float       cos3 = cos(ant_step + 4 * Pi / 3);
235         float       sin1 = sin(ant_step);
236         float       sin2 = sin(ant_step + 2 * Pi / 3);
237         float       sin3 = sin(ant_step + 4 * Pi / 3);
238
239         if (mono)
240                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
241         else
242                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Material);
243         if (!mp->AreObjectsDefined[ObjAntBody]) {
244                 glNewList(objects + ObjAntBody, GL_COMPILE_AND_EXECUTE);
245                 glEnable(GL_CULL_FACE);
246                 glPushMatrix();
247                 glScalef(1, 1.3, 1);
248                 mySphere(0.18);
249                 glScalef(1, 1 / 1.3, 1);
250                 glTranslatef(0.00, 0.30, 0.00);
251                 mySphere(0.2);
252
253                 glTranslatef(-0.05, 0.17, 0.05);
254                 glRotatef(-90, 1, 0, 0);
255                 glRotatef(-25, 0, 1, 0);
256                 myCone(0.05);
257                 glTranslatef(0.00, 0.10, 0.00);
258                 myCone(0.05);
259                 glRotatef(25, 0, 1, 0);
260                 glRotatef(90, 1, 0, 0);
261
262                 glScalef(1, 1.3, 1);
263                 glTranslatef(0.15, -0.65, 0.05);
264                 mySphere(0.25);
265                 glScalef(1, 1 / 1.3, 1);
266                 glPopMatrix();
267                 glDisable(GL_CULL_FACE);
268                 glEndList();
269                 mp->AreObjectsDefined[ObjAntBody] = 1;
270 #ifdef DEBUG_LISTS
271                 (void) printf("Ant drawn SLOWLY\n");
272 #endif
273         } else {
274                 glCallList(objects + ObjAntBody);
275 #ifdef DEBUG_LISTS
276                 (void) printf("Ant drawn quickly\n");
277 #endif
278         }
279
280         glDisable(GL_LIGHTING);
281         /* ANTENNAS */
282         glBegin(GL_LINES);
283         if (mono)
284                 glColor3fv(MaterialGray5);
285         else
286                 glColor3fv(Material);
287         glVertex3f(0.00, 0.30, 0.00);
288         glColor3fv(MaterialGray);
289         glVertex3f(0.40, 0.70, 0.40);
290         if (mono)
291                 glColor3fv(MaterialGray5);
292         else
293                 glColor3fv(Material);
294         glVertex3f(0.00, 0.30, 0.00);
295         glColor3fv(MaterialGray);
296         glVertex3f(0.40, 0.70, -0.40);
297         glEnd();
298         glBegin(GL_POINTS);
299         if (mono)
300                 glColor3fv(MaterialGray6);
301         else
302                 glColor3fv(MaterialRed);
303         glVertex3f(0.40, 0.70, 0.40);
304         glVertex3f(0.40, 0.70, -0.40);
305         glEnd();
306
307         /* LEFT-FRONT ARM */
308         glBegin(GL_LINE_STRIP);
309         if (mono)
310                 glColor3fv(MaterialGray5);
311         else
312                 glColor3fv(Material);
313         glVertex3f(0.00, 0.05, 0.18);
314         glVertex3f(0.35 + 0.05 * cos1, 0.15, 0.25);
315         glColor3fv(MaterialGray);
316         glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
317         glEnd();
318
319         /* LEFT-CENTER ARM */
320         glBegin(GL_LINE_STRIP);
321         if (mono)
322                 glColor3fv(MaterialGray5);
323         else
324                 glColor3fv(Material);
325         glVertex3f(0.00, 0.00, 0.18);
326         glVertex3f(0.35 + 0.05 * cos2, 0.00, 0.25);
327         glColor3fv(MaterialGray);
328         glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
329         glEnd();
330
331         /* LEFT-BACK ARM */
332         glBegin(GL_LINE_STRIP);
333         if (mono)
334                 glColor3fv(MaterialGray5);
335         else
336                 glColor3fv(Material);
337         glVertex3f(0.00, -0.05, 0.18);
338         glVertex3f(0.35 + 0.05 * cos3, -0.15, 0.25);
339         glColor3fv(MaterialGray);
340         glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
341         glEnd();
342
343         /* RIGHT-FRONT ARM */
344         glBegin(GL_LINE_STRIP);
345         if (mono)
346                 glColor3fv(MaterialGray5);
347         else
348                 glColor3fv(Material);
349         glVertex3f(0.00, 0.05, -0.18);
350         glVertex3f(0.35 - 0.05 * sin1, 0.15, -0.25);
351         glColor3fv(MaterialGray);
352         glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
353         glEnd();
354
355         /* RIGHT-CENTER ARM */
356         glBegin(GL_LINE_STRIP);
357         if (mono)
358                 glColor3fv(MaterialGray5);
359         else
360                 glColor3fv(Material);
361         glVertex3f(0.00, 0.00, -0.18);
362         glVertex3f(0.35 - 0.05 * sin2, 0.00, -0.25);
363         glColor3fv(MaterialGray);
364         glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
365         glEnd();
366
367         /* RIGHT-BACK ARM */
368         glBegin(GL_LINE_STRIP);
369         if (mono)
370                 glColor3fv(MaterialGray5);
371         else
372                 glColor3fv(Material);
373         glVertex3f(0.00, -0.05, -0.18);
374         glVertex3f(0.35 - 0.05 * sin3, -0.15, -0.25);
375         glColor3fv(MaterialGray);
376         glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
377         glEnd();
378
379         glBegin(GL_POINTS);
380         if (mono)
381                 glColor3fv(MaterialGray8);
382         else
383                 glColor3fv(MaterialMagenta);
384         glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
385         glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
386         glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
387         glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
388         glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
389         glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
390         glEnd();
391
392         glEnable(GL_LIGHTING);
393
394         ant_step += 0.3;
395 }
396
397 static void
398 RotateAaroundU(float Ax, float Ay, float Az,
399                float Ux, float Uy, float Uz,
400                float *Cx, float *Cy, float *Cz,
401                float Theta)
402 {
403         float       cosO = cos(Theta);
404         float       sinO = sin(Theta);
405         float       one_cosO = 1 - cosO;
406         float       Ux2 = sqr(Ux);
407         float       Uy2 = sqr(Uy);
408         float       Uz2 = sqr(Uz);
409         float       UxUy = Ux * Uy;
410         float       UxUz = Ux * Uz;
411         float       UyUz = Uy * Uz;
412
413         *Cx = (Ux2 + cosO * (1 - Ux2)) * Ax + (UxUy * one_cosO - Uz * sinO) * Ay + (UxUz * one_cosO + Uy * sinO) * Az;
414         *Cy = (UxUy * one_cosO + Uz * sinO) * Ax + (Uy2 + cosO * (1 - Uy2)) * Ay + (UyUz * one_cosO - Ux * sinO) * Az;
415         *Cz = (UxUz * one_cosO - Uy * sinO) * Ax + (UyUz * one_cosO + Ux * sinO) * Ay + (Uz2 + cosO * (1 - Uz2)) * Az;
416 }
417
418 #define MoebiusDivisions 40
419 #define MoebiusTransversals 4
420 static void
421 draw_moebius_strip(ModeInfo * mi)
422 {
423         GLfloat     Phi, Theta;
424         GLfloat     cPhi, sPhi;
425         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
426         int         i, j;
427         int         mono = MI_IS_MONO(mi);
428
429         float       Cx, Cy, Cz;
430
431         if (!mp->AreObjectsDefined[ObjMoebiusStrip]) {
432                 glNewList(objects + ObjMoebiusStrip, GL_COMPILE_AND_EXECUTE);
433
434                 if (solidmoebius) {
435                         glBegin(GL_QUAD_STRIP);
436                         Phi = 0;
437                         i = 0;
438                         while (i < (MoebiusDivisions * 2 + 1)) {
439                                 Theta = Phi / 2;
440                                 cPhi = cos(Phi);
441                                 sPhi = sin(Phi);
442
443                                 i++;
444                                 if (mono)
445                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
446                                 else if (i % 2)
447                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
448                                 else
449                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
450
451                                 RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
452                                 glNormal3f(Cx, Cy, Cz);
453                                 RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
454                                 glVertex3f(cPhi * 3 + Cx, sPhi * 3 + Cy, +Cz);
455                                 glVertex3f(cPhi * 3 - Cx, sPhi * 3 - Cy, -Cz);
456
457                                 Phi += Pi / MoebiusDivisions;
458                         }
459                         glEnd();
460                 } else {
461                         for (j = -MoebiusTransversals; j < MoebiusTransversals; j++) {
462                                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
463                                 glBegin(GL_QUAD_STRIP);
464                                 Phi = 0;
465                                 i = 0;
466                                 while (i < (MoebiusDivisions * 2 + 1)) {
467                                         Theta = Phi / 2;
468                                         cPhi = cos(Phi);
469                                         sPhi = sin(Phi);
470
471                                         RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
472                                         glNormal3f(Cx, Cy, Cz);
473                                         RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
474                                         j++;
475                                         if (j == MoebiusTransversals || mono)
476                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
477                                         else if (i % 2)
478                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
479                                         else
480                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
481                                         glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
482                                         j--;
483                                         if (j == -MoebiusTransversals || mono)
484                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
485                                         else if (i % 2)
486                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
487                                         else
488                                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
489                                         glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
490
491                                         Phi += Pi / MoebiusDivisions;
492                                         i++;
493                                 }
494                                 glEnd();
495                         }
496                         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
497                 }
498
499                 glEndList();
500                 mp->AreObjectsDefined[ObjMoebiusStrip] = 1;
501 #ifdef DEBUG_LISTS
502                 (void) printf("Strip drawn SLOWLY\n");
503 #endif
504         } else {
505                 glCallList(objects + ObjMoebiusStrip);
506 #ifdef DEBUG_LISTS
507                 (void) printf("Strip drawn quickly\n");
508 #endif
509         }
510
511         if (!noants) {
512                 /* DRAW BLUE ANT */
513                 glPushMatrix();
514                 glRotatef(mp->ant_position + 180, 0, 0, 1);
515                 glTranslatef(3, 0, 0);
516                 glRotatef(mp->ant_position / 2 + 90, 0, 1, 0);
517                 glTranslatef(0.28, 0, -0.45);
518                 draw_moebius_ant(mp, MaterialYellow, mono);
519                 glPopMatrix();
520
521                 /* DRAW YELLOW ANT */
522                 glPushMatrix();
523                 glRotatef(mp->ant_position, 0, 0, 1);
524                 glTranslatef(3, 0, 0);
525                 glRotatef(mp->ant_position / 2, 0, 1, 0);
526                 glTranslatef(0.28, 0, -0.45);
527                 draw_moebius_ant(mp, MaterialBlue, mono);
528                 glPopMatrix();
529
530                 /* DRAW GREEN ANT */
531                 glPushMatrix();
532                 glRotatef(-mp->ant_position, 0, 0, 1);
533                 glTranslatef(3, 0, 0);
534                 glRotatef(-mp->ant_position / 2, 0, 1, 0);
535                 glTranslatef(0.28, 0, 0.45);
536                 glRotatef(180, 1, 0, 0);
537                 draw_moebius_ant(mp, MaterialGreen, mono);
538                 glPopMatrix();
539
540                 /* DRAW CYAN ANT */
541                 glPushMatrix();
542                 glRotatef(-mp->ant_position + 180, 0, 0, 1);
543                 glTranslatef(3, 0, 0);
544                 glRotatef(-mp->ant_position / 2 + 90, 0, 1, 0);
545                 glTranslatef(0.28, 0, 0.45);
546                 glRotatef(180, 1, 0, 0);
547                 draw_moebius_ant(mp, MaterialCyan, mono);
548                 glPopMatrix();
549         }
550         mp->ant_position += 1;
551 }
552 #undef MoebiusDivisions
553 #undef MoebiusTransversals
554
555 static void
556 reshape(ModeInfo * mi, int width, int height)
557 {
558         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
559
560         glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
561         glMatrixMode(GL_PROJECTION);
562         glLoadIdentity();
563         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
564         glMatrixMode(GL_MODELVIEW);
565         if (width >= 1024) {
566                 glLineWidth(3);
567                 glPointSize(3);
568         } else if (width >= 512) {
569                 glLineWidth(2);
570                 glPointSize(2);
571         } else {
572                 glLineWidth(1);
573                 glPointSize(1);
574         }
575         mp->AreObjectsDefined[ObjMoebiusStrip] = 0;
576         mp->AreObjectsDefined[ObjAntBody] = 0;
577 }
578
579 static void
580 pinit(void)
581 {
582         glClearDepth(1.0);
583         glClearColor(0.0, 0.0, 0.0, 1.0);
584
585         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
586         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
587         glLightfv(GL_LIGHT0, GL_POSITION, position0);
588         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
589         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
590         glLightfv(GL_LIGHT1, GL_POSITION, position1);
591         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
592         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
593         glEnable(GL_LIGHTING);
594         glEnable(GL_LIGHT0);
595         glEnable(GL_LIGHT1);
596         glEnable(GL_NORMALIZE);
597         glFrontFace(GL_CCW);
598         glCullFace(GL_BACK);
599
600         /* moebius */
601         glShadeModel(GL_SMOOTH);
602         glEnable(GL_DEPTH_TEST);
603         glDisable(GL_TEXTURE_2D);
604         glDisable(GL_CULL_FACE);
605
606         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
607         gluBuild2DMipmaps(GL_TEXTURE_2D, 3, WoodTextureWidth, WoodTextureHeight,
608                           GL_RGB, GL_UNSIGNED_BYTE, WoodTextureData);
609         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
610         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
611         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
612         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
613         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
614
615         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
616         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
617 }
618
619 void
620 init_moebius(ModeInfo * mi)
621 {
622         int         screen = MI_SCREEN(mi);
623         moebiusstruct *mp;
624
625         if (moebius == NULL) {
626                 if ((moebius = (moebiusstruct *) calloc(MI_NUM_SCREENS(mi),
627                                             sizeof (moebiusstruct))) == NULL)
628                         return;
629         }
630         mp = &moebius[screen];
631         mp->step = NRAND(90);
632         mp->ant_position = NRAND(90);
633
634         if ((mp->glx_context = init_GL(mi)) != NULL) {
635
636                 reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
637                 glDrawBuffer(GL_BACK);
638                 if (!glIsList(objects))
639                         objects = glGenLists(3);
640                 pinit();
641         } else {
642                 MI_CLEARWINDOW(mi);
643         }
644 }
645
646 void
647 draw_moebius(ModeInfo * mi)
648 {
649         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
650
651         Display    *display = MI_DISPLAY(mi);
652         Window      window = MI_WINDOW(mi);
653
654         if (!mp->glx_context)
655                 return;
656
657         glXMakeCurrent(display, window, *(mp->glx_context));
658
659         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
660
661         glPushMatrix();
662
663         glTranslatef(0.0, 0.0, -10.0);
664
665         if (!MI_IS_ICONIC(mi)) {
666                 glScalef(Scale4Window * mp->WindH / mp->WindW, Scale4Window, Scale4Window);
667         } else {
668                 glScalef(Scale4Iconic * mp->WindH / mp->WindW, Scale4Iconic, Scale4Iconic);
669         }
670
671         /* moebius */
672         glRotatef(mp->step * 100, 1, 0, 0);
673         glRotatef(mp->step * 95, 0, 1, 0);
674         glRotatef(mp->step * 90, 0, 0, 1);
675         draw_moebius_strip(mi);
676
677         glPopMatrix();
678
679         glFlush();
680
681         glXSwapBuffers(display, window);
682
683         mp->step += 0.025;
684 }
685
686 void
687 change_moebius(ModeInfo * mi)
688 {
689         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
690
691         if (!mp->glx_context)
692                 return;
693
694         glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
695         pinit();
696 }
697
698 void
699 release_moebius(ModeInfo * mi)
700 {
701         if (moebius != NULL) {
702                 (void) free((void *) moebius);
703                 moebius = NULL;
704         }
705         if (glIsList(objects)) {
706                 glDeleteLists(objects, 3);
707         }
708         FreeAllGL(mi);
709 }
710
711 #endif