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