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