1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* moebius --- Moebius Strip II, an Escher-like GL scene with ants. */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)moebius.c 4.08 97/01/04 xlockmore";
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
24 * The RotateAroundU() routine was adapted from the book
25 * "Computer Graphics Principles and Practice
26 * Foley - vanDam - Feiner - Hughes
27 * Second Edition" Pag. 227, exercise 5.15.
29 * This mode shows some interesting scenes that are impossible OR very
30 * wierd to build in the real universe. Much of the scenes are inspirated
31 * on Mauritz Cornelis Escher's works which derivated the mode's name.
32 * M.C. Escher (1898-1972) was a dutch artist and many people prefer to
33 * say he was a mathematician.
35 * Thanks goes to Brian Paul for making it possible and inexpensive to use
38 * Since I'm not a native English speaker, my apologies for any grammatical
41 * My e-mail addresses are
46 * Marcelo F. Vianna (Jun-01-1997)
49 * 01-Jan-98: Mode separated from escher and renamed
50 * 08-Jun-97: New scene implemented: "Impossible Cage" based in a M.C. Escher's
51 * painting with the same name (quite similar). The first GL mode
52 * to use texture mapping.
53 * The "Impossible Cage" scene doesn't use DEPTH BUFFER, the
54 * wood planks are drawn consistently using GL_CULL_FACE, and
55 * the painter's algorithm is used to sort the planks.
57 * 07-Jun-97: Speed ups in Moebius Strip using GL_CULL_FACE.
59 * 03-Jun-97: Initial Release (Only one scene: "Moebius Strip")
60 * The Moebius Strip scene was inspirated in a M.C. Escher's
61 * painting named Moebius Strip II in wich ants walk across a
62 * Moebius Strip path, sometimes meeting each other and sometimes
63 * being in "opposite faces" (note that the moebius strip has
64 * only one face and one edge).
70 * Texture mapping is only available on RGBA contexts, Mono and color index
71 * visuals DO NOT support texture mapping in OpenGL.
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
78 * In real OpenGL, PseudoColor DO NOT support texture map (as far as I know).
81 #include <X11/Intrinsic.h>
84 # define PROGCLASS "Moebius"
85 # define HACK_INIT init_moebius
86 # define HACK_DRAW draw_moebius
87 # define moebius_opts xlockmore_opts
88 # define DEFAULTS "*cycles: 1 \n" \
90 "*wireframe: False \n"
91 # include "xlockmore.h" /* from the xscreensaver distribution */
92 #else /* !STANDALONE */
93 # include "xlock.h" /* from the xlockmore distribution */
95 #endif /* !STANDALONE */
101 #include "e_textures.h"
103 #define DEF_SOLIDMOEBIUS "False"
104 #define DEF_NOANTS "False"
106 static int solidmoebius;
109 static XrmOptionDescRec opts[] =
111 {"-solidmoebius", ".moebius.solidmoebius", XrmoptionNoArg, (caddr_t) "on"},
112 {"+solidmoebius", ".moebius.solidmoebius", XrmoptionNoArg, (caddr_t) "off"},
113 {"-noants", ".moebius.noants", XrmoptionNoArg, (caddr_t) "on"},
114 {"+noants", ".moebius.noants", XrmoptionNoArg, (caddr_t) "off"}
116 static argtype vars[] =
118 {(caddr_t *) & solidmoebius, "solidmoebius", "Solidmoebius", DEF_SOLIDMOEBIUS, t_Bool},
119 {(caddr_t *) & noants, "noants", "Noants", DEF_NOANTS, t_Bool}
121 static OptionStruct desc[] =
123 {"-/+solidmoebius", "select between a SOLID or a NET Moebius Strip"},
124 {"-/+noants", "turn on/off walking ants"}
127 ModeSpecOpt moebius_opts =
128 {4, opts, 2, vars, desc};
131 ModStruct moebius_description =
132 {"moebius", "init_moebius", "draw_moebius", "release_moebius",
133 "draw_moebius", "change_moebius", NULL, &moebius_opts,
134 1000, 1, 1, 1, 1.0, "",
135 "Shows Moebius Strip II, an Escher-like GL scene with ants", 0, NULL};
139 #define Scale4Window 0.3
140 #define Scale4Iconic 0.4
142 #define sqr(A) ((A)*(A))
148 /*************************************************************************/
153 GLfloat ant_position;
154 int AreObjectsDefined[2];
155 GLXContext *glx_context;
158 static float front_shininess[] =
160 static float front_specular[] =
161 {0.7, 0.7, 0.7, 1.0};
162 static float ambient[] =
163 {0.0, 0.0, 0.0, 1.0};
164 static float diffuse[] =
165 {1.0, 1.0, 1.0, 1.0};
166 static float position0[] =
167 {1.0, 1.0, 1.0, 0.0};
168 static float position1[] =
169 {-1.0, -1.0, 1.0, 0.0};
170 static float lmodel_ambient[] =
171 {0.5, 0.5, 0.5, 1.0};
172 static float lmodel_twoside[] =
175 static float MaterialRed[] =
176 {0.7, 0.0, 0.0, 1.0};
177 static float MaterialGreen[] =
178 {0.1, 0.5, 0.2, 1.0};
179 static float MaterialBlue[] =
180 {0.0, 0.0, 0.7, 1.0};
181 static float MaterialCyan[] =
182 {0.2, 0.5, 0.7, 1.0};
183 static float MaterialYellow[] =
184 {0.7, 0.7, 0.0, 1.0};
185 static float MaterialMagenta[] =
186 {0.6, 0.2, 0.5, 1.0};
187 static float MaterialWhite[] =
188 {0.7, 0.7, 0.7, 1.0};
189 static float MaterialGray[] =
190 {0.2, 0.2, 0.2, 1.0};
191 static float MaterialGray5[] =
192 {0.5, 0.5, 0.5, 1.0};
193 static float MaterialGray6[] =
194 {0.6, 0.6, 0.6, 1.0};
195 static float MaterialGray8[] =
196 {0.8, 0.8, 0.8, 1.0};
198 static moebiusstruct *moebius = NULL;
199 static GLuint objects;
203 #define ObjMoebiusStrip 0
207 mySphere(float radius)
209 GLUquadricObj *quadObj;
211 quadObj = gluNewQuadric();
212 gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
213 gluSphere(quadObj, radius, 16, 16);
214 gluDeleteQuadric(quadObj);
220 GLUquadricObj *quadObj;
222 quadObj = gluNewQuadric();
223 gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
224 gluCylinder(quadObj, radius, 0, radius * 3, 8, 1);
225 gluDeleteQuadric(quadObj);
229 draw_moebius_ant(moebiusstruct * mp, float *Material, int mono)
231 static float ant_step = 0;
232 float cos1 = cos(ant_step);
233 float cos2 = cos(ant_step + 2 * Pi / 3);
234 float cos3 = cos(ant_step + 4 * Pi / 3);
235 float sin1 = sin(ant_step);
236 float sin2 = sin(ant_step + 2 * Pi / 3);
237 float sin3 = sin(ant_step + 4 * Pi / 3);
240 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
242 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Material);
243 if (!mp->AreObjectsDefined[ObjAntBody]) {
244 glNewList(objects + ObjAntBody, GL_COMPILE_AND_EXECUTE);
245 glEnable(GL_CULL_FACE);
249 glScalef(1, 1 / 1.3, 1);
250 glTranslatef(0.00, 0.30, 0.00);
253 glTranslatef(-0.05, 0.17, 0.05);
254 glRotatef(-90, 1, 0, 0);
255 glRotatef(-25, 0, 1, 0);
257 glTranslatef(0.00, 0.10, 0.00);
259 glRotatef(25, 0, 1, 0);
260 glRotatef(90, 1, 0, 0);
263 glTranslatef(0.15, -0.65, 0.05);
265 glScalef(1, 1 / 1.3, 1);
267 glDisable(GL_CULL_FACE);
269 mp->AreObjectsDefined[ObjAntBody] = 1;
271 (void) printf("Ant drawn SLOWLY\n");
274 glCallList(objects + ObjAntBody);
276 (void) printf("Ant drawn quickly\n");
280 glDisable(GL_LIGHTING);
284 glColor3fv(MaterialGray5);
286 glColor3fv(Material);
287 glVertex3f(0.00, 0.30, 0.00);
288 glColor3fv(MaterialGray);
289 glVertex3f(0.40, 0.70, 0.40);
291 glColor3fv(MaterialGray5);
293 glColor3fv(Material);
294 glVertex3f(0.00, 0.30, 0.00);
295 glColor3fv(MaterialGray);
296 glVertex3f(0.40, 0.70, -0.40);
300 glColor3fv(MaterialGray6);
302 glColor3fv(MaterialRed);
303 glVertex3f(0.40, 0.70, 0.40);
304 glVertex3f(0.40, 0.70, -0.40);
308 glBegin(GL_LINE_STRIP);
310 glColor3fv(MaterialGray5);
312 glColor3fv(Material);
313 glVertex3f(0.00, 0.05, 0.18);
314 glVertex3f(0.35 + 0.05 * cos1, 0.15, 0.25);
315 glColor3fv(MaterialGray);
316 glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
319 /* LEFT-CENTER ARM */
320 glBegin(GL_LINE_STRIP);
322 glColor3fv(MaterialGray5);
324 glColor3fv(Material);
325 glVertex3f(0.00, 0.00, 0.18);
326 glVertex3f(0.35 + 0.05 * cos2, 0.00, 0.25);
327 glColor3fv(MaterialGray);
328 glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
332 glBegin(GL_LINE_STRIP);
334 glColor3fv(MaterialGray5);
336 glColor3fv(Material);
337 glVertex3f(0.00, -0.05, 0.18);
338 glVertex3f(0.35 + 0.05 * cos3, -0.15, 0.25);
339 glColor3fv(MaterialGray);
340 glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
343 /* RIGHT-FRONT ARM */
344 glBegin(GL_LINE_STRIP);
346 glColor3fv(MaterialGray5);
348 glColor3fv(Material);
349 glVertex3f(0.00, 0.05, -0.18);
350 glVertex3f(0.35 - 0.05 * sin1, 0.15, -0.25);
351 glColor3fv(MaterialGray);
352 glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
355 /* RIGHT-CENTER ARM */
356 glBegin(GL_LINE_STRIP);
358 glColor3fv(MaterialGray5);
360 glColor3fv(Material);
361 glVertex3f(0.00, 0.00, -0.18);
362 glVertex3f(0.35 - 0.05 * sin2, 0.00, -0.25);
363 glColor3fv(MaterialGray);
364 glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
368 glBegin(GL_LINE_STRIP);
370 glColor3fv(MaterialGray5);
372 glColor3fv(Material);
373 glVertex3f(0.00, -0.05, -0.18);
374 glVertex3f(0.35 - 0.05 * sin3, -0.15, -0.25);
375 glColor3fv(MaterialGray);
376 glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
381 glColor3fv(MaterialGray8);
383 glColor3fv(MaterialMagenta);
384 glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
385 glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
386 glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
387 glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
388 glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
389 glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
392 glEnable(GL_LIGHTING);
398 RotateAaroundU(float Ax, float Ay, float Az,
399 float Ux, float Uy, float Uz,
400 float *Cx, float *Cy, float *Cz,
403 float cosO = cos(Theta);
404 float sinO = sin(Theta);
405 float one_cosO = 1 - cosO;
409 float UxUy = Ux * Uy;
410 float UxUz = Ux * Uz;
411 float UyUz = Uy * Uz;
413 *Cx = (Ux2 + cosO * (1 - Ux2)) * Ax + (UxUy * one_cosO - Uz * sinO) * Ay + (UxUz * one_cosO + Uy * sinO) * Az;
414 *Cy = (UxUy * one_cosO + Uz * sinO) * Ax + (Uy2 + cosO * (1 - Uy2)) * Ay + (UyUz * one_cosO - Ux * sinO) * Az;
415 *Cz = (UxUz * one_cosO - Uy * sinO) * Ax + (UyUz * one_cosO + Ux * sinO) * Ay + (Uz2 + cosO * (1 - Uz2)) * Az;
418 #define MoebiusDivisions 40
419 #define MoebiusTransversals 4
421 draw_moebius_strip(ModeInfo * mi)
425 moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
427 int mono = MI_WIN_IS_MONO(mi);
431 if (!mp->AreObjectsDefined[ObjMoebiusStrip]) {
432 glNewList(objects + ObjMoebiusStrip, GL_COMPILE_AND_EXECUTE);
435 glBegin(GL_QUAD_STRIP);
438 while (i < (MoebiusDivisions * 2 + 1)) {
445 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
447 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
449 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
451 RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
452 glNormal3f(Cx, Cy, Cz);
453 RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
454 glVertex3f(cPhi * 3 + Cx, sPhi * 3 + Cy, +Cz);
455 glVertex3f(cPhi * 3 - Cx, sPhi * 3 - Cy, -Cz);
457 Phi += Pi / MoebiusDivisions;
461 for (j = -MoebiusTransversals; j < MoebiusTransversals; j++) {
462 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
463 glBegin(GL_QUAD_STRIP);
466 while (i < (MoebiusDivisions * 2 + 1)) {
471 RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
472 glNormal3f(Cx, Cy, Cz);
473 RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
475 if (j == MoebiusTransversals || mono)
476 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
478 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
480 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
481 glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
483 if (j == -MoebiusTransversals || mono)
484 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
486 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
488 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
489 glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
491 Phi += Pi / MoebiusDivisions;
496 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
500 mp->AreObjectsDefined[ObjMoebiusStrip] = 1;
502 (void) printf("Strip drawn SLOWLY\n");
505 glCallList(objects + ObjMoebiusStrip);
507 (void) printf("Strip drawn quickly\n");
514 glRotatef(mp->ant_position + 180, 0, 0, 1);
515 glTranslatef(3, 0, 0);
516 glRotatef(mp->ant_position / 2 + 90, 0, 1, 0);
517 glTranslatef(0.28, 0, -0.45);
518 draw_moebius_ant(mp, MaterialYellow, mono);
521 /* DRAW YELLOW ANT */
523 glRotatef(mp->ant_position, 0, 0, 1);
524 glTranslatef(3, 0, 0);
525 glRotatef(mp->ant_position / 2, 0, 1, 0);
526 glTranslatef(0.28, 0, -0.45);
527 draw_moebius_ant(mp, MaterialBlue, mono);
532 glRotatef(-mp->ant_position, 0, 0, 1);
533 glTranslatef(3, 0, 0);
534 glRotatef(-mp->ant_position / 2, 0, 1, 0);
535 glTranslatef(0.28, 0, 0.45);
536 glRotatef(180, 1, 0, 0);
537 draw_moebius_ant(mp, MaterialGreen, mono);
542 glRotatef(-mp->ant_position + 180, 0, 0, 1);
543 glTranslatef(3, 0, 0);
544 glRotatef(-mp->ant_position / 2 + 90, 0, 1, 0);
545 glTranslatef(0.28, 0, 0.45);
546 glRotatef(180, 1, 0, 0);
547 draw_moebius_ant(mp, MaterialCyan, mono);
550 mp->ant_position += 1;
552 #undef MoebiusDivisions
553 #undef MoebiusTransversals
556 reshape(ModeInfo * mi, int width, int height)
558 moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
560 glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
561 glMatrixMode(GL_PROJECTION);
563 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
564 glMatrixMode(GL_MODELVIEW);
568 } else if (width >= 512) {
575 mp->AreObjectsDefined[ObjMoebiusStrip] = 0;
576 mp->AreObjectsDefined[ObjAntBody] = 0;
583 glClearColor(0.0, 0.0, 0.0, 1.0);
585 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
586 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
587 glLightfv(GL_LIGHT0, GL_POSITION, position0);
588 glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
589 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
590 glLightfv(GL_LIGHT1, GL_POSITION, position1);
591 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
592 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
593 glEnable(GL_LIGHTING);
596 glEnable(GL_NORMALIZE);
601 glShadeModel(GL_SMOOTH);
602 glEnable(GL_DEPTH_TEST);
603 glDisable(GL_TEXTURE_2D);
604 glDisable(GL_CULL_FACE);
606 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
607 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, WoodTextureWidth, WoodTextureHeight,
608 GL_RGB, GL_UNSIGNED_BYTE, WoodTextureData);
609 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
610 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
611 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
612 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
613 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
615 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
616 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
620 init_moebius(ModeInfo * mi)
622 int screen = MI_SCREEN(mi);
625 if (moebius == NULL) {
626 if ((moebius = (moebiusstruct *) calloc(MI_NUM_SCREENS(mi),
627 sizeof (moebiusstruct))) == NULL)
630 mp = &moebius[screen];
631 mp->step = NRAND(90);
632 mp->ant_position = NRAND(90);
634 if ((mp->glx_context = init_GL(mi)) != NULL) {
636 reshape(mi, MI_WIN_WIDTH(mi), MI_WIN_HEIGHT(mi));
637 glDrawBuffer(GL_BACK);
638 if (!glIsList(objects))
639 objects = glGenLists(3);
647 draw_moebius(ModeInfo * mi)
649 moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
651 Display *display = MI_DISPLAY(mi);
652 Window window = MI_WINDOW(mi);
654 if (!mp->glx_context)
657 glXMakeCurrent(display, window, *(mp->glx_context));
659 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
663 glTranslatef(0.0, 0.0, -10.0);
665 if (!MI_WIN_IS_ICONIC(mi)) {
666 glScalef(Scale4Window * mp->WindH / mp->WindW, Scale4Window, Scale4Window);
668 glScalef(Scale4Iconic * mp->WindH / mp->WindW, Scale4Iconic, Scale4Iconic);
672 glRotatef(mp->step * 100, 1, 0, 0);
673 glRotatef(mp->step * 95, 0, 1, 0);
674 glRotatef(mp->step * 90, 0, 0, 1);
675 draw_moebius_strip(mi);
681 glXSwapBuffers(display, window);
687 change_moebius(ModeInfo * mi)
689 moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
691 if (!mp->glx_context)
694 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
699 release_moebius(ModeInfo * mi)
701 if (moebius != NULL) {
702 (void) free((void *) moebius);
705 if (glIsList(objects)) {
706 glDeleteLists(objects, 3);