9052f4bcc6c3e83ff08af3e20484ae960bd5ad5e
[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 0
5 static const char sccsid[] = "@(#)moebius.c     5.01 2001/03/01 xlockmore";
6 #endif
7
8 /*-
9  * Permission to use, copy, modify, and distribute this software and its
10  * documentation for any purpose and without fee is hereby granted,
11  * provided that the above copyright notice appear in all copies and that
12  * both that copyright notice and this permission notice appear in
13  * supporting documentation.
14  *
15  * This file is provided AS IS with no warranties of any kind.  The author
16  * shall have no liability with respect to the infringement of copyrights,
17  * trade secrets or any patents by this file or any part thereof.  In no
18  * event will the author be liable for any lost revenue or profits or
19  * other special, indirect and consequential damages.
20  *
21  * The RotateAroundU() routine was adapted from the book
22  *    "Computer Graphics Principles and Practice
23  *     Foley - vanDam - Feiner - Hughes
24  *     Second Edition" Pag. 227, exercise 5.15.
25  *
26  * This mode shows some interesting scenes that are impossible OR very
27  * wierd to build in the real universe. Much of the scenes are inspirated
28  * on Mauritz Cornelis Escher's works which derivated the mode's name.
29  * M.C. Escher (1898-1972) was a dutch artist and many people prefer to
30  * say he was a mathematician.
31  *
32  * Thanks goes to Brian Paul for making it possible and inexpensive to use
33  * OpenGL at home.
34  *
35  * Since I'm not a native English speaker, my apologies for any grammatical
36  * mistakes.
37  *
38  * My e-mail address is
39  * mfvianna@centroin.com.br
40  *
41  * Marcelo F. Vianna (Jun-01-1997)
42  *
43  * Revision History:
44  * 05-Apr-2002: Removed all gllist uses (fix some bug with nvidia driver)
45  * 01-Mar-2001: backported from xscreensaver by lassauge@mail.dotcom.fr
46  *    Feb-2001: Made motion and rotation be smoother Jamie Zawinski
47  *              <jwz@jwz.org>
48  * 01-Nov-2000: Allocation checks
49  * 01-Jan-1998: Mode separated from escher and renamed
50  * 08-Jun-1997: New scene implemented: "Impossible Cage" based in a M.C.
51  *              Escher's painting with the same name (quite similar). The
52  *              first GL mode 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-1997: Speed ups in Moebius Strip using GL_CULL_FACE.
58  *              Marcelo F. Vianna.
59  * 03-Jun-1997: 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  * Texture mapping is only available on RGBA contexts, Mono and color index
70  * visuals DO NOT support texture mapping in OpenGL.
71  *
72  * BUT Mesa do implements RGBA contexts in pseudo color visuals, so texture
73  * mapping shuld work on PseudoColor, DirectColor, TrueColor using Mesa. Mono
74  * is not officially supported for both OpenGL and Mesa, but seems to not crash
75  * Mesa.
76  *
77  * In real OpenGL, PseudoColor DO NOT support texture map (as far as I know).
78  */
79
80 #ifdef VMS
81 #include <X11/Intrinsic.h>
82 #endif
83
84 #ifdef STANDALONE
85 # define MODE_moebius
86 # define PROGCLASS                      "Moebius"
87 # define HACK_INIT                      init_moebius
88 # define HACK_DRAW                      draw_moebius
89 # define HACK_RESHAPE           reshape_moebius
90 # define HACK_HANDLE_EVENT      moebius_handle_event
91 # define EVENT_MASK                     PointerMotionMask
92 # define moebius_opts           xlockmore_opts
93 # define DEFAULTS                       "*delay:                20000   \n"                     \
94                                                         "*showFPS:      False   \n"                     \
95                                                         "*wireframe:    False   \n"
96 # include "xlockmore.h"         /* from the xscreensaver distribution */
97 #else /* !STANDALONE */
98 # include "xlock.h"             /* from the xlockmore distribution */
99
100 #endif /* !STANDALONE */
101
102 #ifdef MODE_moebius
103
104
105 #include <GL/glu.h>
106 #include "e_textures.h"
107 #include "rotator.h"
108 #include "gltrackball.h"
109
110 #define DEF_SOLIDMOEBIUS  "False"
111 #define DEF_NOANTS  "False"
112
113 static int  solidmoebius;
114 static int  noants;
115
116 static XrmOptionDescRec opts[] =
117 {
118   {"-solidmoebius", ".moebius.solidmoebius", XrmoptionNoArg, "on"},
119   {"+solidmoebius", ".moebius.solidmoebius", XrmoptionNoArg, "off"},
120   {"-noants", ".moebius.noants", XrmoptionNoArg, "on"},
121   {"+noants", ".moebius.noants", XrmoptionNoArg, "off"}
122 };
123 static argtype vars[] =
124 {
125   {&solidmoebius, "solidmoebius", "Solidmoebius", DEF_SOLIDMOEBIUS, t_Bool},
126   {&noants, "noants", "Noants", DEF_NOANTS, t_Bool}
127
128 };
129 static OptionStruct desc[] =
130 {
131         {"-/+solidmoebius", "select between a SOLID or a NET Moebius Strip"},
132         {"-/+noants", "turn on/off walking ants"}
133 };
134
135 ModeSpecOpt moebius_opts =
136 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
137
138 #ifdef USE_MODULES
139 ModStruct   moebius_description =
140 {"moebius", "init_moebius", "draw_moebius", "release_moebius",
141  "draw_moebius", "change_moebius", (char *) NULL, &moebius_opts,
142  1000, 1, 1, 1, 4, 1.0, "",
143  "Shows Moebius Strip II, an Escher-like GL scene with ants", 0, NULL};
144
145 #endif
146
147 #define Scale4Window               0.3
148 #define Scale4Iconic               0.4
149
150 #define sqr(A)                     ((A)*(A))
151
152 #ifndef Pi
153 #define Pi                         M_PI
154 #endif
155
156 #define ObjMoebiusStrip 0
157 #define ObjAntBody      1
158 #define MaxObj          2
159
160 /*************************************************************************/
161
162 typedef struct {
163         GLint       WindH, WindW;
164         GLfloat     step;
165         GLfloat     ant_position;
166         GLXContext *glx_context;
167     rotator    *rot;
168     trackball_state *trackball;
169     Bool        button_down_p;
170 } moebiusstruct;
171
172 static float front_shininess[] =
173 {60.0};
174 static float front_specular[] =
175 {0.7, 0.7, 0.7, 1.0};
176 static float ambient[] =
177 {0.0, 0.0, 0.0, 1.0};
178 static float diffuse[] =
179 {1.0, 1.0, 1.0, 1.0};
180 static float position0[] =
181 {1.0, 1.0, 1.0, 0.0};
182 static float position1[] =
183 {-1.0, -1.0, 1.0, 0.0};
184 static float lmodel_ambient[] =
185 {0.5, 0.5, 0.5, 1.0};
186 static float lmodel_twoside[] =
187 {GL_TRUE};
188
189 static float MaterialRed[] =
190 {0.7, 0.0, 0.0, 1.0};
191 static float MaterialGreen[] =
192 {0.1, 0.5, 0.2, 1.0};
193 static float MaterialBlue[] =
194 {0.0, 0.0, 0.7, 1.0};
195 static float MaterialCyan[] =
196 {0.2, 0.5, 0.7, 1.0};
197 static float MaterialYellow[] =
198 {0.7, 0.7, 0.0, 1.0};
199 static float MaterialMagenta[] =
200 {0.6, 0.2, 0.5, 1.0};
201 static float MaterialWhite[] =
202 {0.7, 0.7, 0.7, 1.0};
203 static float MaterialGray[] =
204 {0.2, 0.2, 0.2, 1.0};
205 static float MaterialGray5[] =
206 {0.5, 0.5, 0.5, 1.0};
207 static float MaterialGray6[] =
208 {0.6, 0.6, 0.6, 1.0};
209 static float MaterialGray8[] =
210 {0.8, 0.8, 0.8, 1.0};
211
212 static moebiusstruct *moebius = (moebiusstruct *) NULL;
213
214 #define NUM_SCENES      2
215
216 static Bool
217 mySphere(float radius)
218 {
219         GLUquadricObj *quadObj;
220
221         if ((quadObj = gluNewQuadric()) == 0)
222                 return False;
223         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
224         gluSphere(quadObj, radius, 16, 16);
225         gluDeleteQuadric(quadObj);
226         return True;
227 }
228
229 static Bool
230 myCone(float radius)
231 {
232         GLUquadricObj *quadObj;
233
234         if ((quadObj = gluNewQuadric()) == 0)
235                 return False;
236         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
237         gluCylinder(quadObj, radius, 0, radius * 3, 8, 1);
238         gluDeleteQuadric(quadObj);
239         return True;
240 }
241
242 static Bool
243 draw_moebius_ant(moebiusstruct * mp, float *Material, int mono)
244 {
245         static float ant_step = 0;
246         float       cos1 = cos(ant_step);
247         float       cos2 = cos(ant_step + 2 * Pi / 3);
248         float       cos3 = cos(ant_step + 4 * Pi / 3);
249         float       sin1 = sin(ant_step);
250         float       sin2 = sin(ant_step + 2 * Pi / 3);
251         float       sin3 = sin(ant_step + 4 * Pi / 3);
252
253         if (mono)
254                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
255         else
256                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Material);
257         glEnable(GL_CULL_FACE);
258         glPushMatrix();
259         glScalef(1, 1.3, 1);
260         if (!mySphere(0.18))
261                 return False;
262         glScalef(1, 1 / 1.3, 1);
263         glTranslatef(0.00, 0.30, 0.00);
264         if (!mySphere(0.2))
265                 return False;
266
267         glTranslatef(-0.05, 0.17, 0.05);
268         glRotatef(-90, 1, 0, 0);
269         glRotatef(-25, 0, 1, 0);
270         if (!myCone(0.05))
271                 return False;
272         glTranslatef(0.00, 0.10, 0.00);
273         if (!myCone(0.05))
274                 return False;
275         glRotatef(25, 0, 1, 0);
276         glRotatef(90, 1, 0, 0);
277
278         glScalef(1, 1.3, 1);
279         glTranslatef(0.15, -0.65, 0.05);
280         if (!mySphere(0.25))
281                 return False;
282         glScalef(1, 1 / 1.3, 1);
283         glPopMatrix();
284         glDisable(GL_CULL_FACE);
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         return True;
402 }
403
404 static void
405 RotateAaroundU(float Ax, float Ay, float Az,
406                float Ux, float Uy, float Uz,
407                float *Cx, float *Cy, float *Cz,
408                float Theta)
409 {
410         float       cosO = cos(Theta);
411         float       sinO = sin(Theta);
412         float       one_cosO = 1 - cosO;
413         float       Ux2 = sqr(Ux);
414         float       Uy2 = sqr(Uy);
415         float       Uz2 = sqr(Uz);
416         float       UxUy = Ux * Uy;
417         float       UxUz = Ux * Uz;
418         float       UyUz = Uy * Uz;
419
420         *Cx = (Ux2 + cosO * (1 - Ux2)) * Ax + (UxUy * one_cosO - Uz * sinO) * Ay + (UxUz * one_cosO + Uy * sinO) * Az;
421         *Cy = (UxUy * one_cosO + Uz * sinO) * Ax + (Uy2 + cosO * (1 - Uy2)) * Ay + (UyUz * one_cosO - Ux * sinO) * Az;
422         *Cz = (UxUz * one_cosO - Uy * sinO) * Ax + (UyUz * one_cosO + Ux * sinO) * Ay + (Uz2 + cosO * (1 - Uz2)) * Az;
423 }
424
425 #define MoebiusDivisions 40
426 #define MoebiusTransversals 4
427 static Bool
428 draw_moebius_strip(ModeInfo * mi)
429 {
430         GLfloat     Phi, Theta;
431         GLfloat     cPhi, sPhi;
432         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
433         int         i, j;
434         int         mono = MI_IS_MONO(mi);
435
436         float       Cx, Cy, Cz;
437
438         if (solidmoebius) {
439                 glBegin(GL_QUAD_STRIP);
440                 Phi = 0;
441                 i = 0;
442                 while (i < (MoebiusDivisions * 2 + 1)) {
443                         Theta = Phi / 2;
444                         cPhi = cos(Phi);
445                         sPhi = sin(Phi);
446
447                         i++;
448                         if (mono)
449                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
450                         else if (i % 2)
451                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
452                         else
453                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
454
455                         RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
456                         glNormal3f(Cx, Cy, Cz);
457                         RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
458                         glVertex3f(cPhi * 3 + Cx, sPhi * 3 + Cy, +Cz);
459                         glVertex3f(cPhi * 3 - Cx, sPhi * 3 - Cy, -Cz);
460
461                         Phi += Pi / MoebiusDivisions;
462                 }
463                 glEnd();
464         } else {
465                 for (j = -MoebiusTransversals; j < MoebiusTransversals; j++) {
466                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
467                         glBegin(GL_QUAD_STRIP);
468                         Phi = 0;
469                         i = 0;
470                         while (i < (MoebiusDivisions * 2 + 1)) {
471                                 Theta = Phi / 2;
472                                 cPhi = cos(Phi);
473                                 sPhi = sin(Phi);
474
475                                 RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
476                                 glNormal3f(Cx, Cy, Cz);
477                                 RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
478                                 j++;
479                                 if (j == MoebiusTransversals || mono)
480                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
481                                 else if (i % 2)
482                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
483                                 else
484                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
485                                 glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
486                                 j--;
487                                 if (j == -MoebiusTransversals || mono)
488                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
489                                 else if (i % 2)
490                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
491                                 else
492                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
493                                 glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
494
495                                 Phi += Pi / MoebiusDivisions;
496                                 i++;
497                         }
498                         glEnd();
499                 }
500                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
501         }
502
503         if (!noants) {
504                 /* DRAW BLUE ANT */
505                 glPushMatrix();
506                 glRotatef(mp->ant_position + 180, 0, 0, 1);
507                 glTranslatef(3, 0, 0);
508                 glRotatef(mp->ant_position / 2 + 90, 0, 1, 0);
509                 glTranslatef(0.28, 0, -0.45);
510                 if (!draw_moebius_ant(mp, MaterialYellow, mono))
511                         return False;
512                 glPopMatrix();
513
514                 /* DRAW YELLOW ANT */
515                 glPushMatrix();
516                 glRotatef(mp->ant_position, 0, 0, 1);
517                 glTranslatef(3, 0, 0);
518                 glRotatef(mp->ant_position / 2, 0, 1, 0);
519                 glTranslatef(0.28, 0, -0.45);
520                 if (!draw_moebius_ant(mp, MaterialBlue, mono))
521                         return False;
522                 glPopMatrix();
523
524                 /* DRAW GREEN ANT */
525                 glPushMatrix();
526                 glRotatef(-mp->ant_position, 0, 0, 1);
527                 glTranslatef(3, 0, 0);
528                 glRotatef(-mp->ant_position / 2, 0, 1, 0);
529                 glTranslatef(0.28, 0, 0.45);
530                 glRotatef(180, 1, 0, 0);
531                 if (!draw_moebius_ant(mp, MaterialGreen, mono))
532                         return False;
533                 glPopMatrix();
534
535                 /* DRAW CYAN ANT */
536                 glPushMatrix();
537                 glRotatef(-mp->ant_position + 180, 0, 0, 1);
538                 glTranslatef(3, 0, 0);
539                 glRotatef(-mp->ant_position / 2 + 90, 0, 1, 0);
540                 glTranslatef(0.28, 0, 0.45);
541                 glRotatef(180, 1, 0, 0);
542                 if (!draw_moebius_ant(mp, MaterialCyan, mono))
543                         return False;
544                 glPopMatrix();
545         }
546         mp->ant_position += 1;
547         return True;
548 }
549 #undef MoebiusDivisions
550 #undef MoebiusTransversals
551
552 void
553 reshape_moebius(ModeInfo * mi, int width, int height)
554 {
555         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
556
557         glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
558         glMatrixMode(GL_PROJECTION);
559         glLoadIdentity();
560         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
561         glMatrixMode(GL_MODELVIEW);
562         if (width >= 1024) {
563                 glLineWidth(3);
564                 glPointSize(3);
565         } else if (width >= 512) {
566                 glLineWidth(2);
567                 glPointSize(2);
568         } else {
569                 glLineWidth(1);
570                 glPointSize(1);
571         }
572 }
573
574 static void
575 pinit(void)
576 {
577     int status;
578         glClearDepth(1.0);
579         glClearColor(0.0, 0.0, 0.0, 1.0);
580
581         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
582         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
583         glLightfv(GL_LIGHT0, GL_POSITION, position0);
584         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
585         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
586         glLightfv(GL_LIGHT1, GL_POSITION, position1);
587         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
588         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
589         glEnable(GL_LIGHTING);
590         glEnable(GL_LIGHT0);
591         glEnable(GL_LIGHT1);
592         glEnable(GL_NORMALIZE);
593         glFrontFace(GL_CCW);
594         glCullFace(GL_BACK);
595
596         /* moebius */
597         glShadeModel(GL_SMOOTH);
598         glEnable(GL_DEPTH_TEST);
599         glDisable(GL_TEXTURE_2D);
600         glDisable(GL_CULL_FACE);
601
602         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
603
604     clear_gl_error();
605         status = gluBuild2DMipmaps(GL_TEXTURE_2D, 3,
606                                WoodTextureWidth, WoodTextureHeight,
607                                GL_RGB, GL_UNSIGNED_BYTE, WoodTextureData);
608     if (status)
609       {
610         const char *s = (char *) gluErrorString (status);
611         fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
612                  progname, WoodTextureWidth, WoodTextureHeight,
613                  (s ? s : "(unknown)"));
614         exit (1);
615       }
616     check_gl_error("mipmapping");
617
618         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
619         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
620         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
621         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
622         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
623
624         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
625         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
626 }
627
628
629
630 void
631 release_moebius(ModeInfo * mi)
632 {
633         if (moebius != NULL) {
634                 (void) free((void *) moebius);
635                 moebius = (moebiusstruct *) NULL;
636         }
637         FreeAllGL(mi);
638 }
639
640 Bool
641 moebius_handle_event (ModeInfo *mi, XEvent *event)
642 {
643   moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
644
645   if (event->xany.type == ButtonPress &&
646       event->xbutton.button & Button1)
647     {
648       mp->button_down_p = True;
649       gltrackball_start (mp->trackball,
650                          event->xbutton.x, event->xbutton.y,
651                          MI_WIDTH (mi), MI_HEIGHT (mi));
652       return True;
653     }
654   else if (event->xany.type == ButtonRelease &&
655            event->xbutton.button & Button1)
656     {
657       mp->button_down_p = False;
658       return True;
659     }
660   else if (event->xany.type == MotionNotify &&
661            mp->button_down_p)
662     {
663       gltrackball_track (mp->trackball,
664                          event->xmotion.x, event->xmotion.y,
665                          MI_WIDTH (mi), MI_HEIGHT (mi));
666       return True;
667     }
668
669   return False;
670 }
671
672
673 void
674 init_moebius(ModeInfo * mi)
675 {
676         moebiusstruct *mp;
677
678         if (moebius == NULL) {
679                 if ((moebius = (moebiusstruct *) calloc(MI_NUM_SCREENS(mi),
680                                             sizeof (moebiusstruct))) == NULL)
681                         return;
682         }
683         mp = &moebius[MI_SCREEN(mi)];
684         mp->step = NRAND(90);
685         mp->ant_position = NRAND(90);
686
687     {
688       double rot_speed = 0.3;
689       mp->rot = make_rotator (rot_speed, rot_speed, rot_speed, 1, 0, True);
690       mp->trackball = gltrackball_init ();
691     }
692
693         if ((mp->glx_context = init_GL(mi)) != NULL) {
694
695                 reshape_moebius(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
696                 glDrawBuffer(GL_BACK);
697                 pinit();
698         } else {
699                 MI_CLEARWINDOW(mi);
700         }
701 }
702
703 void
704 draw_moebius(ModeInfo * mi)
705 {
706         moebiusstruct *mp;
707
708         Display    *display = MI_DISPLAY(mi);
709         Window      window = MI_WINDOW(mi);
710
711         if (moebius == NULL)
712             return;
713         mp = &moebius[MI_SCREEN(mi)];
714
715         MI_IS_DRAWN(mi) = True;
716
717         if (!mp->glx_context)
718                 return;
719
720         glXMakeCurrent(display, window, *(mp->glx_context));
721
722         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
723
724         glPushMatrix();
725
726         glTranslatef(0.0, 0.0, -10.0);
727
728     gltrackball_rotate (mp->trackball);
729
730         if (!MI_IS_ICONIC(mi)) {
731                 glScalef(Scale4Window * mp->WindH / mp->WindW, Scale4Window, Scale4Window);
732         } else {
733                 glScalef(Scale4Iconic * mp->WindH / mp->WindW, Scale4Iconic, Scale4Iconic);
734         }
735
736     {
737       double x, y, z;
738       get_rotation (mp->rot, &x, &y, &z, !mp->button_down_p);
739       glRotatef (x * 360, 1.0, 0.0, 0.0);
740       glRotatef (y * 360, 0.0, 1.0, 0.0);
741       glRotatef (z * 360, 0.0, 0.0, 1.0);
742     }
743
744         /* moebius */
745         if (!draw_moebius_strip(mi)) {
746                 release_moebius(mi);
747                 return;
748         }
749
750         glPopMatrix();
751
752     if (MI_IS_FPS(mi)) do_fps (mi);
753         glFlush();
754
755         glXSwapBuffers(display, window);
756
757         mp->step += 0.025;
758 }
759
760 void
761 change_moebius(ModeInfo * mi)
762 {
763         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
764
765         if (!mp->glx_context)
766                 return;
767
768         glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
769         pinit();
770 }
771
772 #endif