22
19
* other special, indirect and consequential damages.
24
21
* The RotateAroundU() routine was adapted from the book
25
* "Computer Graphics Principles and Practice
22
* "Computer Graphics Principles and Practice
26
23
* Foley - vanDam - Feiner - Hughes
27
24
* Second Edition" Pag. 227, exercise 5.15.
29
26
* This mode shows some interesting scenes that are impossible OR very
30
27
* wierd to build in the real universe. Much of the scenes are inspirated
31
28
* on Mauritz Cornelis Escher's works which derivated the mode's name.
32
29
* M.C. Escher (1898-1972) was a dutch artist and many people prefer to
33
30
* say he was a mathematician.
35
* Thanks goes to Brian Paul for making it possible and inexpensive to use
32
* Thanks goes to Brian Paul for making it possible and inexpensive to use
38
35
* Since I'm not a native English speaker, my apologies for any grammatical
41
38
* My e-mail address is
39
* mfvianna@centroin.com.br
44
41
* Marcelo F. Vianna (Jun-01-1997)
46
43
* Revision History:
47
* 01-Jan-98: Mode separated from escher and renamed
48
* 08-Jun-97: New scene implemented: "Impossible Cage" based in a M.C. Escher's
49
* painting with the same name (quite similar). The first GL mode
50
* to use texture mapping.
51
* The "Impossible Cage" scene doesn't use DEPTH BUFFER, the
52
* wood planks are drawn consistently using GL_CULL_FACE, and
53
* the painter's algorithm is used to sort the planks.
55
* 07-Jun-97: Speed ups in Moebius Strip using GL_CULL_FACE.
57
* 03-Jun-97: Initial Release (Only one scene: "Moebius Strip")
58
* The Moebius Strip scene was inspirated in a M.C. Escher's
59
* painting named Moebius Strip II in wich ants walk across a
60
* Moebius Strip path, sometimes meeting each other and sometimes
61
* being in "opposite faces" (note that the moebius strip has
62
* only one face and one edge).
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
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.
57
* 07-Jun-1997: Speed ups in Moebius Strip using GL_CULL_FACE.
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).
76
77
* In real OpenGL, PseudoColor DO NOT support texture map (as far as I know).
79
81
#include <X11/Intrinsic.h>
82
86
# define PROGCLASS "Moebius"
83
87
# define HACK_INIT init_moebius
84
88
# define HACK_DRAW draw_moebius
85
89
# define HACK_RESHAPE reshape_moebius
90
# define HACK_HANDLE_EVENT moebius_handle_event
91
# define EVENT_MASK PointerMotionMask
86
92
# define moebius_opts xlockmore_opts
87
# define DEFAULTS "*cycles: 1 \n" \
93
# define DEFAULTS "*delay: 20000 \n" \
89
94
"*showFPS: False \n" \
90
95
"*wireframe: False \n"
91
96
# include "xlockmore.h" /* from the xscreensaver distribution */
109
116
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"}
118
{"-solidmoebius", ".moebius.solidmoebius", XrmoptionNoArg, "on"},
119
{"+solidmoebius", ".moebius.solidmoebius", XrmoptionNoArg, "off"},
120
{"-noants", ".moebius.noants", XrmoptionNoArg, "on"},
121
{"+noants", ".moebius.noants", XrmoptionNoArg, "off"}
116
123
static argtype vars[] =
118
{(caddr_t *) & solidmoebius, "solidmoebius", "Solidmoebius", DEF_SOLIDMOEBIUS, t_Bool},
119
{(caddr_t *) & noants, "noants", "Noants", DEF_NOANTS, t_Bool}
125
{&solidmoebius, "solidmoebius", "Solidmoebius", DEF_SOLIDMOEBIUS, t_Bool},
126
{&noants, "noants", "Noants", DEF_NOANTS, t_Bool}
121
129
static OptionStruct desc[] =
130
138
#ifdef USE_MODULES
131
139
ModStruct moebius_description =
132
140
{"moebius", "init_moebius", "draw_moebius", "release_moebius",
133
"draw_moebius", "change_moebius", NULL, &moebius_opts,
141
"draw_moebius", "change_moebius", (char *) NULL, &moebius_opts,
134
142
1000, 1, 1, 1, 4, 1.0, "",
135
143
"Shows Moebius Strip II, an Escher-like GL scene with ants", 0, NULL};
201
209
static float MaterialGray8[] =
202
210
{0.8, 0.8, 0.8, 1.0};
204
static moebiusstruct *moebius = NULL;
205
static GLuint objects;
212
static moebiusstruct *moebius = (moebiusstruct *) NULL;
207
214
#define NUM_SCENES 2
209
#define ObjMoebiusStrip 0
213
217
mySphere(float radius)
215
219
GLUquadricObj *quadObj;
217
quadObj = gluNewQuadric();
221
if ((quadObj = gluNewQuadric()) == 0)
218
223
gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
219
224
gluSphere(quadObj, radius, 16, 16);
220
225
gluDeleteQuadric(quadObj);
224
230
myCone(float radius)
226
232
GLUquadricObj *quadObj;
228
quadObj = gluNewQuadric();
234
if ((quadObj = gluNewQuadric()) == 0)
229
236
gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
230
237
gluCylinder(quadObj, radius, 0, radius * 3, 8, 1);
231
238
gluDeleteQuadric(quadObj);
235
243
draw_moebius_ant(moebiusstruct * mp, float *Material, int mono)
237
245
static float ant_step = 0;
246
254
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
248
256
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Material);
249
if (!mp->AreObjectsDefined[ObjAntBody]) {
250
glNewList(objects + ObjAntBody, GL_COMPILE_AND_EXECUTE);
251
glEnable(GL_CULL_FACE);
255
glScalef(1, 1 / 1.3, 1);
256
glTranslatef(0.00, 0.30, 0.00);
259
glTranslatef(-0.05, 0.17, 0.05);
260
glRotatef(-90, 1, 0, 0);
261
glRotatef(-25, 0, 1, 0);
263
glTranslatef(0.00, 0.10, 0.00);
265
glRotatef(25, 0, 1, 0);
266
glRotatef(90, 1, 0, 0);
269
glTranslatef(0.15, -0.65, 0.05);
271
glScalef(1, 1 / 1.3, 1);
273
glDisable(GL_CULL_FACE);
275
mp->AreObjectsDefined[ObjAntBody] = 1;
277
(void) printf("Ant drawn SLOWLY\n");
280
glCallList(objects + ObjAntBody);
282
(void) printf("Ant drawn quickly\n");
257
glEnable(GL_CULL_FACE);
262
glScalef(1, 1 / 1.3, 1);
263
glTranslatef(0.00, 0.30, 0.00);
267
glTranslatef(-0.05, 0.17, 0.05);
268
glRotatef(-90, 1, 0, 0);
269
glRotatef(-25, 0, 1, 0);
272
glTranslatef(0.00, 0.10, 0.00);
275
glRotatef(25, 0, 1, 0);
276
glRotatef(90, 1, 0, 0);
279
glTranslatef(0.15, -0.65, 0.05);
282
glScalef(1, 1 / 1.3, 1);
284
glDisable(GL_CULL_FACE);
286
286
glDisable(GL_LIGHTING);
435
436
float Cx, Cy, Cz;
437
if (!mp->AreObjectsDefined[ObjMoebiusStrip]) {
438
glNewList(objects + ObjMoebiusStrip, GL_COMPILE_AND_EXECUTE);
439
glBegin(GL_QUAD_STRIP);
442
while (i < (MoebiusDivisions * 2 + 1)) {
449
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
451
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
453
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
455
RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
456
glNormal3f(Cx, Cy, Cz);
457
RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
458
glVertex3f(cPhi * 3 + Cx, sPhi * 3 + Cy, +Cz);
459
glVertex3f(cPhi * 3 - Cx, sPhi * 3 - Cy, -Cz);
461
Phi += Pi / MoebiusDivisions;
465
for (j = -MoebiusTransversals; j < MoebiusTransversals; j++) {
466
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
441
467
glBegin(GL_QUAD_STRIP);
451
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
453
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
455
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
457
475
RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
458
476
glNormal3f(Cx, Cy, Cz);
459
477
RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
460
glVertex3f(cPhi * 3 + Cx, sPhi * 3 + Cy, +Cz);
461
glVertex3f(cPhi * 3 - Cx, sPhi * 3 - Cy, -Cz);
479
if (j == MoebiusTransversals || mono)
480
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
482
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
484
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
485
glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
487
if (j == -MoebiusTransversals || mono)
488
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
490
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
492
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
493
glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
463
495
Phi += Pi / MoebiusDivisions;
467
for (j = -MoebiusTransversals; j < MoebiusTransversals; j++) {
468
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
469
glBegin(GL_QUAD_STRIP);
472
while (i < (MoebiusDivisions * 2 + 1)) {
477
RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
478
glNormal3f(Cx, Cy, Cz);
479
RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
481
if (j == MoebiusTransversals || mono)
482
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
484
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
486
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
487
glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
489
if (j == -MoebiusTransversals || mono)
490
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
492
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
494
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
495
glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
497
Phi += Pi / MoebiusDivisions;
502
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
506
mp->AreObjectsDefined[ObjMoebiusStrip] = 1;
508
(void) printf("Strip drawn SLOWLY\n");
511
glCallList(objects + ObjMoebiusStrip);
513
(void) printf("Strip drawn quickly\n");
500
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
610
600
glDisable(GL_CULL_FACE);
612
602
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
613
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, WoodTextureWidth, WoodTextureHeight,
614
GL_RGB, GL_UNSIGNED_BYTE, WoodTextureData);
605
status = gluBuild2DMipmaps(GL_TEXTURE_2D, 3,
606
WoodTextureWidth, WoodTextureHeight,
607
GL_RGB, GL_UNSIGNED_BYTE, WoodTextureData);
610
const char *s = (char *) gluErrorString (status);
611
fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
612
progname, WoodTextureWidth, WoodTextureHeight,
613
(s ? s : "(unknown)"));
616
check_gl_error("mipmapping");
615
618
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
616
619
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
617
620
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
627
/* lifted from lament.c */
628
#define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
629
#define RANDSIGN() ((random() & 1) ? 1 : -1)
632
rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
647
if (ppos < 0) abort();
648
if (ppos > 1.0) abort();
649
*pos = (*pos > 0 ? ppos : -ppos);
655
if (*v > max_v || *v < -max_v)
659
/* If it stops, start it going in the other direction. */
666
/* keep going in the same direction */
681
/* Alter direction of rotational acceleration randomly. */
682
if (! (random() % 120))
685
/* Change acceleration very occasionally. */
686
if (! (random() % 200))
690
else if (random() & 1)
631
release_moebius(ModeInfo * mi)
633
if (moebius != NULL) {
634
(void) free((void *) moebius);
635
moebius = (moebiusstruct *) NULL;
641
moebius_handle_event (ModeInfo *mi, XEvent *event)
643
moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
645
if (event->xany.type == ButtonPress &&
646
event->xbutton.button == Button1)
648
mp->button_down_p = True;
649
gltrackball_start (mp->trackball,
650
event->xbutton.x, event->xbutton.y,
651
MI_WIDTH (mi), MI_HEIGHT (mi));
654
else if (event->xany.type == ButtonRelease &&
655
event->xbutton.button == Button1)
657
mp->button_down_p = False;
660
else if (event->xany.type == ButtonPress &&
661
(event->xbutton.button == Button4 ||
662
event->xbutton.button == Button5))
664
gltrackball_mousewheel (mp->trackball, event->xbutton.button, 10,
665
!!event->xbutton.state);
668
else if (event->xany.type == MotionNotify &&
671
gltrackball_track (mp->trackball,
672
event->xmotion.x, event->xmotion.y,
673
MI_WIDTH (mi), MI_HEIGHT (mi));
699
682
init_moebius(ModeInfo * mi)
701
int screen = MI_SCREEN(mi);
702
684
moebiusstruct *mp;
704
686
if (moebius == NULL) {
706
688
sizeof (moebiusstruct))) == NULL)
709
mp = &moebius[screen];
691
mp = &moebius[MI_SCREEN(mi)];
710
692
mp->step = NRAND(90);
711
693
mp->ant_position = NRAND(90);
713
mp->rotx = frand(1.0) * RANDSIGN();
714
mp->roty = frand(1.0) * RANDSIGN();
715
mp->rotz = frand(1.0) * RANDSIGN();
717
/* bell curve from 0-1.5 degrees, avg 0.75 */
718
mp->dx = (frand(1) + frand(1) + frand(1)) / (360*2);
719
mp->dy = (frand(1) + frand(1) + frand(1)) / (360*2);
720
mp->dz = (frand(1) + frand(1) + frand(1)) / (360*2);
722
mp->d_max = mp->dx * 2;
724
mp->ddx = 0.00006 + frand(0.00003);
725
mp->ddy = 0.00006 + frand(0.00003);
726
mp->ddz = 0.00006 + frand(0.00003);
696
double rot_speed = 0.3;
697
mp->rot = make_rotator (rot_speed, rot_speed, rot_speed, 1, 0, True);
698
mp->trackball = gltrackball_init ();
728
701
if ((mp->glx_context = init_GL(mi)) != NULL) {
730
703
reshape_moebius(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
731
704
glDrawBuffer(GL_BACK);
732
if (!glIsList(objects))
733
objects = glGenLists(3);
736
707
MI_CLEARWINDOW(mi);
766
GLfloat x = mp->rotx;
767
GLfloat y = mp->roty;
768
GLfloat z = mp->rotz;
769
if (x < 0) x = 1 - (x + 1);
770
if (y < 0) y = 1 - (y + 1);
771
if (z < 0) z = 1 - (z + 1);
772
glRotatef(x * 360, 1.0, 0.0, 0.0);
773
glRotatef(y * 360, 0.0, 1.0, 0.0);
774
glRotatef(z * 360, 0.0, 0.0, 1.0);
746
get_rotation (mp->rot, &x, &y, &z, !mp->button_down_p);
747
glRotatef (x * 360, 1.0, 0.0, 0.0);
748
glRotatef (y * 360, 0.0, 1.0, 0.0);
749
glRotatef (z * 360, 0.0, 0.0, 1.0);
778
draw_moebius_strip(mi);
753
if (!draw_moebius_strip(mi)) {
782
rotate(&mp->rotx, &mp->dx, &mp->ddx, mp->d_max);
783
rotate(&mp->roty, &mp->dy, &mp->ddy, mp->d_max);
784
rotate(&mp->rotz, &mp->dz, &mp->ddz, mp->d_max);
786
if (mi->fps_p) do_fps (mi);
760
if (MI_IS_FPS(mi)) do_fps (mi);
789
763
glXSwapBuffers(display, window);