ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-4.22.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 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 # include "xlockmore.h"         /* from the xscreensaver distribution */
96 #else /* !STANDALONE */
97 # include "xlock.h"             /* from the xlockmore distribution */
98
99 #endif /* !STANDALONE */
100
101 #ifdef MODE_moebius
102
103
104 #include <GL/glu.h>
105 #include "e_textures.h"
106 #include "rotator.h"
107 #include "gltrackball.h"
108
109 #define DEF_SOLIDMOEBIUS  "False"
110 #define DEF_NOANTS  "False"
111
112 static int  solidmoebius;
113 static int  noants;
114
115 static XrmOptionDescRec opts[] =
116 {
117   {"-solidmoebius", ".moebius.solidmoebius", XrmoptionNoArg, "on"},
118   {"+solidmoebius", ".moebius.solidmoebius", XrmoptionNoArg, "off"},
119   {"-noants", ".moebius.noants", XrmoptionNoArg, "on"},
120   {"+noants", ".moebius.noants", XrmoptionNoArg, "off"}
121 };
122 static argtype vars[] =
123 {
124   {&solidmoebius, "solidmoebius", "Solidmoebius", DEF_SOLIDMOEBIUS, t_Bool},
125   {&noants, "noants", "Noants", DEF_NOANTS, t_Bool}
126
127 };
128 static OptionStruct desc[] =
129 {
130         {"-/+solidmoebius", "select between a SOLID or a NET Moebius Strip"},
131         {"-/+noants", "turn on/off walking ants"}
132 };
133
134 ModeSpecOpt moebius_opts =
135 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
136
137 #ifdef USE_MODULES
138 ModStruct   moebius_description =
139 {"moebius", "init_moebius", "draw_moebius", "release_moebius",
140  "draw_moebius", "change_moebius", (char *) NULL, &moebius_opts,
141  1000, 1, 1, 1, 4, 1.0, "",
142  "Shows Moebius Strip II, an Escher-like GL scene with ants", 0, NULL};
143
144 #endif
145
146 #define Scale4Window               0.3
147 #define Scale4Iconic               0.4
148
149 #define sqr(A)                     ((A)*(A))
150
151 #ifndef Pi
152 #define Pi                         M_PI
153 #endif
154
155 #define ObjMoebiusStrip 0
156 #define ObjAntBody      1
157 #define MaxObj          2
158
159 /*************************************************************************/
160
161 typedef struct {
162         GLint       WindH, WindW;
163         GLfloat     step;
164         GLfloat     ant_position;
165         GLXContext *glx_context;
166     rotator    *rot;
167     trackball_state *trackball;
168     Bool        button_down_p;
169 } moebiusstruct;
170
171 static float front_shininess[] =
172 {60.0};
173 static float front_specular[] =
174 {0.7, 0.7, 0.7, 1.0};
175 static float ambient[] =
176 {0.0, 0.0, 0.0, 1.0};
177 static float diffuse[] =
178 {1.0, 1.0, 1.0, 1.0};
179 static float position0[] =
180 {1.0, 1.0, 1.0, 0.0};
181 static float position1[] =
182 {-1.0, -1.0, 1.0, 0.0};
183 static float lmodel_ambient[] =
184 {0.5, 0.5, 0.5, 1.0};
185 static float lmodel_twoside[] =
186 {GL_TRUE};
187
188 static float MaterialRed[] =
189 {0.7, 0.0, 0.0, 1.0};
190 static float MaterialGreen[] =
191 {0.1, 0.5, 0.2, 1.0};
192 static float MaterialBlue[] =
193 {0.0, 0.0, 0.7, 1.0};
194 static float MaterialCyan[] =
195 {0.2, 0.5, 0.7, 1.0};
196 static float MaterialYellow[] =
197 {0.7, 0.7, 0.0, 1.0};
198 static float MaterialMagenta[] =
199 {0.6, 0.2, 0.5, 1.0};
200 static float MaterialWhite[] =
201 {0.7, 0.7, 0.7, 1.0};
202 static float MaterialGray[] =
203 {0.2, 0.2, 0.2, 1.0};
204 static float MaterialGray5[] =
205 {0.5, 0.5, 0.5, 1.0};
206 static float MaterialGray6[] =
207 {0.6, 0.6, 0.6, 1.0};
208 static float MaterialGray8[] =
209 {0.8, 0.8, 0.8, 1.0};
210
211 static moebiusstruct *moebius = (moebiusstruct *) NULL;
212
213 #define NUM_SCENES      2
214
215 static Bool
216 mySphere(float radius)
217 {
218         GLUquadricObj *quadObj;
219
220         if ((quadObj = gluNewQuadric()) == 0)
221                 return False;
222         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
223         gluSphere(quadObj, radius, 16, 16);
224         gluDeleteQuadric(quadObj);
225         return True;
226 }
227
228 static Bool
229 myCone(float radius)
230 {
231         GLUquadricObj *quadObj;
232
233         if ((quadObj = gluNewQuadric()) == 0)
234                 return False;
235         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
236         gluCylinder(quadObj, radius, 0, radius * 3, 8, 1);
237         gluDeleteQuadric(quadObj);
238         return True;
239 }
240
241 static Bool
242 draw_moebius_ant(moebiusstruct * mp, float *Material, int mono)
243 {
244         static float ant_step = 0;
245         float       cos1 = cos(ant_step);
246         float       cos2 = cos(ant_step + 2 * Pi / 3);
247         float       cos3 = cos(ant_step + 4 * Pi / 3);
248         float       sin1 = sin(ant_step);
249         float       sin2 = sin(ant_step + 2 * Pi / 3);
250         float       sin3 = sin(ant_step + 4 * Pi / 3);
251
252         if (mono)
253                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
254         else
255                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Material);
256         glEnable(GL_CULL_FACE);
257         glPushMatrix();
258         glScalef(1, 1.3, 1);
259         if (!mySphere(0.18))
260                 return False;
261         glScalef(1, 1 / 1.3, 1);
262         glTranslatef(0.00, 0.30, 0.00);
263         if (!mySphere(0.2))
264                 return False;
265
266         glTranslatef(-0.05, 0.17, 0.05);
267         glRotatef(-90, 1, 0, 0);
268         glRotatef(-25, 0, 1, 0);
269         if (!myCone(0.05))
270                 return False;
271         glTranslatef(0.00, 0.10, 0.00);
272         if (!myCone(0.05))
273                 return False;
274         glRotatef(25, 0, 1, 0);
275         glRotatef(90, 1, 0, 0);
276
277         glScalef(1, 1.3, 1);
278         glTranslatef(0.15, -0.65, 0.05);
279         if (!mySphere(0.25))
280                 return False;
281         glScalef(1, 1 / 1.3, 1);
282         glPopMatrix();
283         glDisable(GL_CULL_FACE);
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         return True;
401 }
402
403 static void
404 RotateAaroundU(float Ax, float Ay, float Az,
405                float Ux, float Uy, float Uz,
406                float *Cx, float *Cy, float *Cz,
407                float Theta)
408 {
409         float       cosO = cos(Theta);
410         float       sinO = sin(Theta);
411         float       one_cosO = 1 - cosO;
412         float       Ux2 = sqr(Ux);
413         float       Uy2 = sqr(Uy);
414         float       Uz2 = sqr(Uz);
415         float       UxUy = Ux * Uy;
416         float       UxUz = Ux * Uz;
417         float       UyUz = Uy * Uz;
418
419         *Cx = (Ux2 + cosO * (1 - Ux2)) * Ax + (UxUy * one_cosO - Uz * sinO) * Ay + (UxUz * one_cosO + Uy * sinO) * Az;
420         *Cy = (UxUy * one_cosO + Uz * sinO) * Ax + (Uy2 + cosO * (1 - Uy2)) * Ay + (UyUz * one_cosO - Ux * sinO) * Az;
421         *Cz = (UxUz * one_cosO - Uy * sinO) * Ax + (UyUz * one_cosO + Ux * sinO) * Ay + (Uz2 + cosO * (1 - Uz2)) * Az;
422 }
423
424 #define MoebiusDivisions 40
425 #define MoebiusTransversals 4
426 static Bool
427 draw_moebius_strip(ModeInfo * mi)
428 {
429         GLfloat     Phi, Theta;
430         GLfloat     cPhi, sPhi;
431         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
432         int         i, j;
433         int         mono = MI_IS_MONO(mi);
434
435         float       Cx, Cy, Cz;
436
437         if (solidmoebius) {
438                 glBegin(GL_QUAD_STRIP);
439                 Phi = 0;
440                 i = 0;
441                 while (i < (MoebiusDivisions * 2 + 1)) {
442                         Theta = Phi / 2;
443                         cPhi = cos(Phi);
444                         sPhi = sin(Phi);
445
446                         i++;
447                         if (mono)
448                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
449                         else if (i % 2)
450                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
451                         else
452                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
453
454                         RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
455                         glNormal3f(Cx, Cy, Cz);
456                         RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
457                         glVertex3f(cPhi * 3 + Cx, sPhi * 3 + Cy, +Cz);
458                         glVertex3f(cPhi * 3 - Cx, sPhi * 3 - Cy, -Cz);
459
460                         Phi += Pi / MoebiusDivisions;
461                 }
462                 glEnd();
463         } else {
464                 for (j = -MoebiusTransversals; j < MoebiusTransversals; j++) {
465                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
466                         glBegin(GL_QUAD_STRIP);
467                         Phi = 0;
468                         i = 0;
469                         while (i < (MoebiusDivisions * 2 + 1)) {
470                                 Theta = Phi / 2;
471                                 cPhi = cos(Phi);
472                                 sPhi = sin(Phi);
473
474                                 RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
475                                 glNormal3f(Cx, Cy, Cz);
476                                 RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
477                                 j++;
478                                 if (j == MoebiusTransversals || mono)
479                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
480                                 else if (i % 2)
481                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
482                                 else
483                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
484                                 glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
485                                 j--;
486                                 if (j == -MoebiusTransversals || mono)
487                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
488                                 else if (i % 2)
489                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
490                                 else
491                                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
492                                 glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
493
494                                 Phi += Pi / MoebiusDivisions;
495                                 i++;
496                         }
497                         glEnd();
498                 }
499                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
500         }
501
502         if (!noants) {
503                 /* DRAW BLUE ANT */
504                 glPushMatrix();
505                 glRotatef(mp->ant_position + 180, 0, 0, 1);
506                 glTranslatef(3, 0, 0);
507                 glRotatef(mp->ant_position / 2 + 90, 0, 1, 0);
508                 glTranslatef(0.28, 0, -0.45);
509                 if (!draw_moebius_ant(mp, MaterialYellow, mono))
510                         return False;
511                 glPopMatrix();
512
513                 /* DRAW YELLOW ANT */
514                 glPushMatrix();
515                 glRotatef(mp->ant_position, 0, 0, 1);
516                 glTranslatef(3, 0, 0);
517                 glRotatef(mp->ant_position / 2, 0, 1, 0);
518                 glTranslatef(0.28, 0, -0.45);
519                 if (!draw_moebius_ant(mp, MaterialBlue, mono))
520                         return False;
521                 glPopMatrix();
522
523                 /* DRAW GREEN ANT */
524                 glPushMatrix();
525                 glRotatef(-mp->ant_position, 0, 0, 1);
526                 glTranslatef(3, 0, 0);
527                 glRotatef(-mp->ant_position / 2, 0, 1, 0);
528                 glTranslatef(0.28, 0, 0.45);
529                 glRotatef(180, 1, 0, 0);
530                 if (!draw_moebius_ant(mp, MaterialGreen, mono))
531                         return False;
532                 glPopMatrix();
533
534                 /* DRAW CYAN ANT */
535                 glPushMatrix();
536                 glRotatef(-mp->ant_position + 180, 0, 0, 1);
537                 glTranslatef(3, 0, 0);
538                 glRotatef(-mp->ant_position / 2 + 90, 0, 1, 0);
539                 glTranslatef(0.28, 0, 0.45);
540                 glRotatef(180, 1, 0, 0);
541                 if (!draw_moebius_ant(mp, MaterialCyan, mono))
542                         return False;
543                 glPopMatrix();
544         }
545         mp->ant_position += 1;
546         return True;
547 }
548 #undef MoebiusDivisions
549 #undef MoebiusTransversals
550
551 void
552 reshape_moebius(ModeInfo * mi, int width, int height)
553 {
554         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
555
556         glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
557         glMatrixMode(GL_PROJECTION);
558         glLoadIdentity();
559         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
560         glMatrixMode(GL_MODELVIEW);
561         if (width >= 1024) {
562                 glLineWidth(3);
563                 glPointSize(3);
564         } else if (width >= 512) {
565                 glLineWidth(2);
566                 glPointSize(2);
567         } else {
568                 glLineWidth(1);
569                 glPointSize(1);
570         }
571 }
572
573 static void
574 pinit(void)
575 {
576     int status;
577         glClearDepth(1.0);
578         glClearColor(0.0, 0.0, 0.0, 1.0);
579
580         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
581         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
582         glLightfv(GL_LIGHT0, GL_POSITION, position0);
583         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
584         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
585         glLightfv(GL_LIGHT1, GL_POSITION, position1);
586         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
587         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
588         glEnable(GL_LIGHTING);
589         glEnable(GL_LIGHT0);
590         glEnable(GL_LIGHT1);
591         glEnable(GL_NORMALIZE);
592         glFrontFace(GL_CCW);
593         glCullFace(GL_BACK);
594
595         /* moebius */
596         glShadeModel(GL_SMOOTH);
597         glEnable(GL_DEPTH_TEST);
598         glDisable(GL_TEXTURE_2D);
599         glDisable(GL_CULL_FACE);
600
601         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
602
603     clear_gl_error();
604         status = gluBuild2DMipmaps(GL_TEXTURE_2D, 3,
605                                WoodTextureWidth, WoodTextureHeight,
606                                GL_RGB, GL_UNSIGNED_BYTE, WoodTextureData);
607     if (status)
608       {
609         const char *s = (char *) gluErrorString (status);
610         fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
611                  progname, WoodTextureWidth, WoodTextureHeight,
612                  (s ? s : "(unknown)"));
613         exit (1);
614       }
615     check_gl_error("mipmapping");
616
617         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
618         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
619         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
620         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
621         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
622
623         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
624         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
625 }
626
627
628
629 void
630 release_moebius(ModeInfo * mi)
631 {
632         if (moebius != NULL) {
633                 (void) free((void *) moebius);
634                 moebius = (moebiusstruct *) NULL;
635         }
636         FreeAllGL(mi);
637 }
638
639 Bool
640 moebius_handle_event (ModeInfo *mi, XEvent *event)
641 {
642   moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
643
644   if (event->xany.type == ButtonPress &&
645       event->xbutton.button == Button1)
646     {
647       mp->button_down_p = True;
648       gltrackball_start (mp->trackball,
649                          event->xbutton.x, event->xbutton.y,
650                          MI_WIDTH (mi), MI_HEIGHT (mi));
651       return True;
652     }
653   else if (event->xany.type == ButtonRelease &&
654            event->xbutton.button == Button1)
655     {
656       mp->button_down_p = False;
657       return True;
658     }
659   else if (event->xany.type == ButtonPress &&
660            (event->xbutton.button == Button4 ||
661             event->xbutton.button == Button5))
662     {
663       gltrackball_mousewheel (mp->trackball, event->xbutton.button, 10,
664                               !!event->xbutton.state);
665       return True;
666     }
667   else if (event->xany.type == MotionNotify &&
668            mp->button_down_p)
669     {
670       gltrackball_track (mp->trackball,
671                          event->xmotion.x, event->xmotion.y,
672                          MI_WIDTH (mi), MI_HEIGHT (mi));
673       return True;
674     }
675
676   return False;
677 }
678
679
680 void
681 init_moebius(ModeInfo * mi)
682 {
683         moebiusstruct *mp;
684
685         if (moebius == NULL) {
686                 if ((moebius = (moebiusstruct *) calloc(MI_NUM_SCREENS(mi),
687                                             sizeof (moebiusstruct))) == NULL)
688                         return;
689         }
690         mp = &moebius[MI_SCREEN(mi)];
691         mp->step = NRAND(90);
692         mp->ant_position = NRAND(90);
693
694     {
695       double rot_speed = 0.3;
696       mp->rot = make_rotator (rot_speed, rot_speed, rot_speed, 1, 0, True);
697       mp->trackball = gltrackball_init ();
698     }
699
700         if ((mp->glx_context = init_GL(mi)) != NULL) {
701
702                 reshape_moebius(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
703                 glDrawBuffer(GL_BACK);
704                 pinit();
705         } else {
706                 MI_CLEARWINDOW(mi);
707         }
708 }
709
710 void
711 draw_moebius(ModeInfo * mi)
712 {
713         moebiusstruct *mp;
714
715         Display    *display = MI_DISPLAY(mi);
716         Window      window = MI_WINDOW(mi);
717
718         if (moebius == NULL)
719             return;
720         mp = &moebius[MI_SCREEN(mi)];
721
722         MI_IS_DRAWN(mi) = True;
723
724         if (!mp->glx_context)
725                 return;
726
727         glXMakeCurrent(display, window, *(mp->glx_context));
728
729         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
730
731         glPushMatrix();
732
733         glTranslatef(0.0, 0.0, -10.0);
734
735     gltrackball_rotate (mp->trackball);
736
737         if (!MI_IS_ICONIC(mi)) {
738                 glScalef(Scale4Window * mp->WindH / mp->WindW, Scale4Window, Scale4Window);
739         } else {
740                 glScalef(Scale4Iconic * mp->WindH / mp->WindW, Scale4Iconic, Scale4Iconic);
741         }
742
743     {
744       double x, y, z;
745       get_rotation (mp->rot, &x, &y, &z, !mp->button_down_p);
746       glRotatef (x * 360, 1.0, 0.0, 0.0);
747       glRotatef (y * 360, 0.0, 1.0, 0.0);
748       glRotatef (z * 360, 0.0, 0.0, 1.0);
749     }
750
751         /* moebius */
752         if (!draw_moebius_strip(mi)) {
753                 release_moebius(mi);
754                 return;
755         }
756
757         glPopMatrix();
758
759     if (MI_IS_FPS(mi)) do_fps (mi);
760         glFlush();
761
762         glXSwapBuffers(display, window);
763
764         mp->step += 0.025;
765 }
766
767 void
768 change_moebius(ModeInfo * mi)
769 {
770         moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
771
772         if (!mp->glx_context)
773                 return;
774
775         glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
776         pinit();
777 }
778
779 #endif