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  * weird 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 AT 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 AT users.sourceforge.net
46  *    Feb-2001: Made motion and rotation be smoother Jamie Zawinski
47  *              <jwz AT 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 which 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 should 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 <types.h>
82 #endif
83 
84 #ifdef STANDALONE
85 # define MODE_moebius
86 # define DEFAULTS			"*cycles:	1       \n"	\
87 					"*delay:	30000   \n"	\
88 					"*showFps:      False   \n"	\
89 					"*wireframe:	False	\n"
90 
91 # define free_moebius 0
92 # define moebius_handle_event 0
93 # include "xlockmore.h"		/* from the xscreensaver distribution */
94 #else /* !STANDALONE */
95 # include "xlock.h"		/* from the xlockmore distribution */
96 # include "visgl.h"
97 #endif /* !STANDALONE */
98 
99 #ifdef MODE_moebius
100 
101 #include <GL/glu.h>
102 #include "e_textures.h"
103 
104 #define DEF_SOLIDMOEBIUS  "False"
105 #define DEF_NOANTS  "False"
106 
107 static int  solidmoebius;
108 static int  noants;
109 
110 static XrmOptionDescRec opts[] =
111 {
112 	{(char *) "-solidmoebius", (char *) ".moebius.solidmoebius", XrmoptionNoArg, (caddr_t) "on"},
113 	{(char *) "+solidmoebius", (char *) ".moebius.solidmoebius", XrmoptionNoArg, (caddr_t) "off"},
114 	{(char *) "-noants", (char *) ".moebius.noants", XrmoptionNoArg, (caddr_t) "on"},
115 	{(char *) "+noants", (char *) ".moebius.noants", XrmoptionNoArg, (caddr_t) "off"}
116 };
117 static argtype vars[] =
118 {
119 	{(void *) & solidmoebius, (char *) "solidmoebius", (char *) "Solidmoebius", (char *) DEF_SOLIDMOEBIUS, t_Bool},
120 	{(void *) & noants, (char *) "noants", (char *) "Noants", (char *) DEF_NOANTS, t_Bool}
121 
122 };
123 static OptionStruct desc[] =
124 {
125 	{(char *) "-/+solidmoebius", (char *) "select between a SOLID or a NET Moebius Strip"},
126 	{(char *) "-/+noants", (char *) "turn on/off walking ants"}
127 };
128 
129 ENTRYPOINT ModeSpecOpt moebius_opts =
130 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
131 
132 #ifdef USE_MODULES
133 ModStruct   moebius_description =
134 {"moebius", "init_moebius", "draw_moebius", "release_moebius",
135  "draw_moebius", "change_moebius", (char *) NULL, &moebius_opts,
136  30000, 1, 1, 1, 4, 1.0, "",
137  "Shows Moebius Strip II, an Escher-like GL scene with ants", 0, NULL};
138 
139 #endif
140 
141 #define Scale4Window               0.3
142 #define Scale4Iconic               0.4
143 
144 #define sqr(A)                     ((A)*(A))
145 
146 #ifndef Pi
147 #define Pi                         M_PI
148 #endif
149 
150 #define ObjMoebiusStrip 0
151 #define ObjAntBody      1
152 #define MaxObj          2
153 
154 /*************************************************************************/
155 
156 typedef struct {
157 #ifdef WIN32
158 	HGLRC       glx_context;
159 #else
160 	GLXContext *glx_context;
161 #endif
162 	GLint       WindH, WindW;
163 	GLfloat     step;
164 	GLfloat     ant_position;
165 	GLfloat rotx, roty, rotz;	   /* current object rotation */
166 	GLfloat dx, dy, dz;		   /* current rotational velocity */
167 	GLfloat ddx, ddy, ddz;	   /* current rotational acceleration */
168 	GLfloat d_max;			   /* max velocity */
169 
170 } moebiusstruct;
171 
172 static float front_shininess[] =
173 {60.0};
174 static float front_specular[] =
175 {0.7, 0.7, 0.7, 1.0};
176 static float ambient[] =
177 {0.0, 0.0, 0.0, 1.0};
178 static float diffuse[] =
179 {1.0, 1.0, 1.0, 1.0};
180 static float position0[] =
181 {1.0, 1.0, 1.0, 0.0};
182 static float position1[] =
183 {-1.0, -1.0, 1.0, 0.0};
184 static float lmodel_ambient[] =
185 {0.5, 0.5, 0.5, 1.0};
186 static float lmodel_twoside[] =
187 {GL_TRUE};
188 
189 static float MaterialRed[] =
190 {0.7, 0.0, 0.0, 1.0};
191 static float MaterialGreen[] =
192 {0.1, 0.5, 0.2, 1.0};
193 static float MaterialBlue[] =
194 {0.0, 0.0, 0.7, 1.0};
195 static float MaterialCyan[] =
196 {0.2, 0.5, 0.7, 1.0};
197 static float MaterialYellow[] =
198 {0.7, 0.7, 0.0, 1.0};
199 static float MaterialMagenta[] =
200 {0.6, 0.2, 0.5, 1.0};
201 static float MaterialWhite[] =
202 {0.7, 0.7, 0.7, 1.0};
203 static float MaterialGray[] =
204 {0.2, 0.2, 0.2, 1.0};
205 static float MaterialGray5[] =
206 {0.5, 0.5, 0.5, 1.0};
207 static float MaterialGray6[] =
208 {0.6, 0.6, 0.6, 1.0};
209 static float MaterialGray8[] =
210 {0.8, 0.8, 0.8, 1.0};
211 
212 static moebiusstruct *moebius = (moebiusstruct *) NULL;
213 
214 #define NUM_SCENES      2
215 
216 static Bool
mySphere(float radius)217 mySphere(float radius)
218 {
219 	GLUquadricObj *quadObj;
220 
221 	if ((quadObj = gluNewQuadric()) == 0)
222 		return False;
223 	gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
224 	gluSphere(quadObj, radius, 16, 16);
225 	gluDeleteQuadric(quadObj);
226 	return True;
227 }
228 
229 static Bool
myCone(float radius)230 myCone(float radius)
231 {
232 	GLUquadricObj *quadObj;
233 
234 	if ((quadObj = gluNewQuadric()) == 0)
235 		return False;
236 	gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
237 	gluCylinder(quadObj, radius, 0, radius * 3, 8, 1);
238 	gluDeleteQuadric(quadObj);
239 	return True;
240 }
241 
242 static Bool
draw_moebius_ant(float * Material,int mono)243 draw_moebius_ant(float *Material, int mono)
244 {
245 	static float ant_step = 0;
246 	float       cos1 = cos(ant_step);
247 	float       cos2 = cos(ant_step + 2 * Pi / 3);
248 	float       cos3 = cos(ant_step + 4 * Pi / 3);
249 	float       sin1 = sin(ant_step);
250 	float       sin2 = sin(ant_step + 2 * Pi / 3);
251 	float       sin3 = sin(ant_step + 4 * Pi / 3);
252 
253 	if (mono)
254 		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray5);
255 	else
256 		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Material);
257 	glEnable(GL_CULL_FACE);
258 	glPushMatrix();
259 	glScalef(1, 1.3, 1);
260 	if (!mySphere(0.18))
261 		return False;
262 	glScalef(1, 1 / 1.3, 1);
263 	glTranslatef(0.00, 0.30, 0.00);
264 	if (!mySphere(0.2))
265 		return False;
266 
267 	glTranslatef(-0.05, 0.17, 0.05);
268 	glRotatef(-90, 1, 0, 0);
269 	glRotatef(-25, 0, 1, 0);
270 	if (!myCone(0.05))
271 		return False;
272 	glTranslatef(0.00, 0.10, 0.00);
273 	if (!myCone(0.05))
274 		return False;
275 	glRotatef(25, 0, 1, 0);
276 	glRotatef(90, 1, 0, 0);
277 
278 	glScalef(1, 1.3, 1);
279 	glTranslatef(0.15, -0.65, 0.05);
280 	if (!mySphere(0.25))
281 		return False;
282 	glScalef(1, 1 / 1.3, 1);
283 	glPopMatrix();
284 	glDisable(GL_CULL_FACE);
285 
286 	glDisable(GL_LIGHTING);
287 	/* ANTENNAS */
288 	glBegin(GL_LINES);
289 	if (mono)
290 		glColor3fv(MaterialGray5);
291 	else
292 		glColor3fv(Material);
293 	glVertex3f(0.00, 0.30, 0.00);
294 	glColor3fv(MaterialGray);
295 	glVertex3f(0.40, 0.70, 0.40);
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 	glEnd();
304 	glBegin(GL_POINTS);
305 	if (mono)
306 		glColor3fv(MaterialGray6);
307 	else
308 		glColor3fv(MaterialRed);
309 	glVertex3f(0.40, 0.70, 0.40);
310 	glVertex3f(0.40, 0.70, -0.40);
311 	glEnd();
312 
313 	/* LEFT-FRONT ARM */
314 	glBegin(GL_LINE_STRIP);
315 	if (mono)
316 		glColor3fv(MaterialGray5);
317 	else
318 		glColor3fv(Material);
319 	glVertex3f(0.00, 0.05, 0.18);
320 	glVertex3f(0.35 + 0.05 * cos1, 0.15, 0.25);
321 	glColor3fv(MaterialGray);
322 	glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
323 	glEnd();
324 
325 	/* LEFT-CENTER ARM */
326 	glBegin(GL_LINE_STRIP);
327 	if (mono)
328 		glColor3fv(MaterialGray5);
329 	else
330 		glColor3fv(Material);
331 	glVertex3f(0.00, 0.00, 0.18);
332 	glVertex3f(0.35 + 0.05 * cos2, 0.00, 0.25);
333 	glColor3fv(MaterialGray);
334 	glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
335 	glEnd();
336 
337 	/* LEFT-BACK ARM */
338 	glBegin(GL_LINE_STRIP);
339 	if (mono)
340 		glColor3fv(MaterialGray5);
341 	else
342 		glColor3fv(Material);
343 	glVertex3f(0.00, -0.05, 0.18);
344 	glVertex3f(0.35 + 0.05 * cos3, -0.15, 0.25);
345 	glColor3fv(MaterialGray);
346 	glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
347 	glEnd();
348 
349 	/* RIGHT-FRONT ARM */
350 	glBegin(GL_LINE_STRIP);
351 	if (mono)
352 		glColor3fv(MaterialGray5);
353 	else
354 		glColor3fv(Material);
355 	glVertex3f(0.00, 0.05, -0.18);
356 	glVertex3f(0.35 - 0.05 * sin1, 0.15, -0.25);
357 	glColor3fv(MaterialGray);
358 	glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
359 	glEnd();
360 
361 	/* RIGHT-CENTER ARM */
362 	glBegin(GL_LINE_STRIP);
363 	if (mono)
364 		glColor3fv(MaterialGray5);
365 	else
366 		glColor3fv(Material);
367 	glVertex3f(0.00, 0.00, -0.18);
368 	glVertex3f(0.35 - 0.05 * sin2, 0.00, -0.25);
369 	glColor3fv(MaterialGray);
370 	glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
371 	glEnd();
372 
373 	/* RIGHT-BACK ARM */
374 	glBegin(GL_LINE_STRIP);
375 	if (mono)
376 		glColor3fv(MaterialGray5);
377 	else
378 		glColor3fv(Material);
379 	glVertex3f(0.00, -0.05, -0.18);
380 	glVertex3f(0.35 - 0.05 * sin3, -0.15, -0.25);
381 	glColor3fv(MaterialGray);
382 	glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
383 	glEnd();
384 
385 	glBegin(GL_POINTS);
386 	if (mono)
387 		glColor3fv(MaterialGray8);
388 	else
389 		glColor3fv(MaterialMagenta);
390 	glVertex3f(-0.20 + 0.05 * cos1, 0.25 + 0.1 * sin1, 0.45);
391 	glVertex3f(-0.20 + 0.05 * cos2, 0.00 + 0.1 * sin2, 0.45);
392 	glVertex3f(-0.20 + 0.05 * cos3, -0.25 + 0.1 * sin3, 0.45);
393 	glVertex3f(-0.20 - 0.05 * sin1, 0.25 + 0.1 * cos1, -0.45);
394 	glVertex3f(-0.20 - 0.05 * sin2, 0.00 + 0.1 * cos2, -0.45);
395 	glVertex3f(-0.20 - 0.05 * sin3, -0.25 + 0.1 * cos3, -0.45);
396 	glEnd();
397 
398 	glEnable(GL_LIGHTING);
399 
400 	ant_step += 0.3;
401 	return True;
402 }
403 
404 static void
RotateAaroundU(float Ax,float Ay,float Az,float Ux,float Uy,float Uz,float * Cx,float * Cy,float * Cz,float Theta)405 RotateAaroundU(float Ax, float Ay, float Az,
406 	       float Ux, float Uy, float Uz,
407 	       float *Cx, float *Cy, float *Cz,
408 	       float Theta)
409 {
410 	float       cosO = cos(Theta);
411 	float       sinO = sin(Theta);
412 	float       one_cosO = 1 - cosO;
413 	float       Ux2 = sqr(Ux);
414 	float       Uy2 = sqr(Uy);
415 	float       Uz2 = sqr(Uz);
416 	float       UxUy = Ux * Uy;
417 	float       UxUz = Ux * Uz;
418 	float       UyUz = Uy * Uz;
419 
420 	*Cx = (Ux2 + cosO * (1 - Ux2)) * Ax + (UxUy * one_cosO - Uz * sinO) * Ay + (UxUz * one_cosO + Uy * sinO) * Az;
421 	*Cy = (UxUy * one_cosO + Uz * sinO) * Ax + (Uy2 + cosO * (1 - Uy2)) * Ay + (UyUz * one_cosO - Ux * sinO) * Az;
422 	*Cz = (UxUz * one_cosO - Uy * sinO) * Ax + (UyUz * one_cosO + Ux * sinO) * Ay + (Uz2 + cosO * (1 - Uz2)) * Az;
423 }
424 
425 #define MoebiusDivisions 40
426 #define MoebiusTransversals 4
427 static Bool
draw_moebius_strip(ModeInfo * mi)428 draw_moebius_strip(ModeInfo * mi)
429 {
430 	GLfloat     Phi, Theta;
431 	GLfloat     cPhi, sPhi;
432 	moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
433 	int         i, j;
434 	int         mono = MI_IS_MONO(mi);
435 
436 	float       Cx, Cy, Cz;
437 
438 	if (solidmoebius) {
439 		glBegin(GL_QUAD_STRIP);
440 		Phi = 0;
441 		i = 0;
442 		while (i < (MoebiusDivisions * 2 + 1)) {
443 			Theta = Phi / 2;
444 			cPhi = cos(Phi);
445 			sPhi = sin(Phi);
446 
447 			i++;
448 			if (mono)
449 				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
450 			else if (i % 2)
451 				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
452 			else
453 				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
454 
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);
460 
461 			Phi += Pi / MoebiusDivisions;
462 		}
463 		glEnd();
464 	} else {
465 		for (j = -MoebiusTransversals; j < MoebiusTransversals; j++) {
466 			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
467 			glBegin(GL_QUAD_STRIP);
468 			Phi = 0;
469 			i = 0;
470 			while (i < (MoebiusDivisions * 2 + 1)) {
471 				Theta = Phi / 2;
472 				cPhi = cos(Phi);
473 				sPhi = sin(Phi);
474 
475 				RotateAaroundU(cPhi, sPhi, 0, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
476 				glNormal3f(Cx, Cy, Cz);
477 				RotateAaroundU(0, 0, 1, -sPhi, cPhi, 0, &Cx, &Cy, &Cz, Theta);
478 				j++;
479 				if (j == MoebiusTransversals || mono)
480 					glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
481 				else if (i % 2)
482 					glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
483 				else
484 					glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
485 				glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
486 				j--;
487 				if (j == -MoebiusTransversals || mono)
488 					glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
489 				else if (i % 2)
490 					glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
491 				else
492 					glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
493 				glVertex3f(cPhi * 3 + Cx / MoebiusTransversals * j, sPhi * 3 + Cy / MoebiusTransversals * j, +Cz / MoebiusTransversals * j);
494 
495 				Phi += Pi / MoebiusDivisions;
496 				i++;
497 			}
498 			glEnd();
499 		}
500 		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
501 	}
502 
503 	if (!noants) {
504 		/* DRAW BLUE ANT */
505 		glPushMatrix();
506 		glRotatef(mp->ant_position + 180, 0, 0, 1);
507 		glTranslatef(3, 0, 0);
508 		glRotatef(mp->ant_position / 2 + 90, 0, 1, 0);
509 		glTranslatef(0.28, 0, -0.45);
510 		if (!draw_moebius_ant(MaterialYellow, mono))
511 			return False;
512 		glPopMatrix();
513 
514 		/* DRAW YELLOW ANT */
515 		glPushMatrix();
516 		glRotatef(mp->ant_position, 0, 0, 1);
517 		glTranslatef(3, 0, 0);
518 		glRotatef(mp->ant_position / 2, 0, 1, 0);
519 		glTranslatef(0.28, 0, -0.45);
520 		if (!draw_moebius_ant(MaterialBlue, mono))
521 			return False;
522 		glPopMatrix();
523 
524 		/* DRAW GREEN ANT */
525 		glPushMatrix();
526 		glRotatef(-mp->ant_position, 0, 0, 1);
527 		glTranslatef(3, 0, 0);
528 		glRotatef(-mp->ant_position / 2, 0, 1, 0);
529 		glTranslatef(0.28, 0, 0.45);
530 		glRotatef(180, 1, 0, 0);
531 		if (!draw_moebius_ant(MaterialGreen, mono))
532 			return False;
533 		glPopMatrix();
534 
535 		/* DRAW CYAN ANT */
536 		glPushMatrix();
537 		glRotatef(-mp->ant_position + 180, 0, 0, 1);
538 		glTranslatef(3, 0, 0);
539 		glRotatef(-mp->ant_position / 2 + 90, 0, 1, 0);
540 		glTranslatef(0.28, 0, 0.45);
541 		glRotatef(180, 1, 0, 0);
542 		if (!draw_moebius_ant(MaterialCyan, mono))
543 			return False;
544 		glPopMatrix();
545 	}
546 	mp->ant_position += 1;
547 	return True;
548 }
549 #undef MoebiusDivisions
550 #undef MoebiusTransversals
551 
552 static void
reshape_moebius(ModeInfo * mi,int width,int height)553 reshape_moebius(ModeInfo * mi, int width, int height)
554 {
555 	moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
556 
557 	glViewport(0, 0, mp->WindW = (GLint) width, mp->WindH = (GLint) height);
558 	glMatrixMode(GL_PROJECTION);
559 	glLoadIdentity();
560 	glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
561 	glMatrixMode(GL_MODELVIEW);
562 	if (width >= 1024) {
563 		glLineWidth(3);
564 		glPointSize(3);
565 	} else if (width >= 512) {
566 		glLineWidth(2);
567 		glPointSize(2);
568 	} else {
569 		glLineWidth(1);
570 		glPointSize(1);
571 	}
572 }
573 
574 static void
pinit(void)575 pinit(void)
576 {
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 	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, WoodTextureWidth, WoodTextureHeight,
603 			  GL_RGB, GL_UNSIGNED_BYTE, WoodTextureData);
604 	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
605 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
606 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
607 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
608 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
609 
610 	glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
611 	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
612 }
613 
614 
615 
616 /* lifted from lament.c */
617 #ifndef RANDSIGN
618 #define RANDSIGN() ((LRAND() & 1) ? 1 : -1)
619 #endif
620 #define FLOATRAND(a) (((double)LRAND() / (double)MAXRAND) * a)
621 
622 static void
rotate(GLfloat * pos,GLfloat * v,GLfloat * dv,GLfloat max_v,Bool verbose)623 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v, Bool verbose)
624 {
625   double ppos = *pos;
626 
627   /* tick position */
628   if (ppos < 0)
629     ppos = -(ppos + *v);
630   else
631     ppos += *v;
632 
633   if (ppos > 1.0)
634     ppos -= 1.0;
635   else if (ppos < 0)
636     ppos += 1.0;
637 
638   if ((ppos < 0.0) || (ppos > 1.0)) {
639     if (verbose) {
640       (void) fprintf(stderr, "Weirdness in rotate()\n");
641       (void) fprintf(stderr, "ppos = %g\n", ppos);
642     }
643     return;
644   }
645 
646   *pos = (*pos > 0 ? ppos : -ppos);
647 
648   /* accelerate */
649   *v += *dv;
650 
651   /* clamp velocity */
652   if (*v > max_v || *v < -max_v)
653     {
654       *dv = -*dv;
655     }
656   /* If it stops, start it going in the other direction. */
657   else if (*v < 0)
658     {
659       if (NRAND(4) != 0)
660 	{
661 	  *v = 0;
662 
663 	  /* keep going in the same direction */
664 	  if (LRAND() & 1)
665 	    *dv = 0;
666 	  else if (*dv < 0)
667 	    *dv = -*dv;
668 	}
669       else
670 	{
671 	  /* reverse gears */
672 	  *v = -*v;
673 	  *dv = -*dv;
674 	  *pos = -*pos;
675 	}
676     }
677 
678   /* Alter direction of rotational acceleration randomly. */
679   if (!(NRAND(120)))
680     *dv = -*dv;
681 
682   /* Change acceleration very occasionally. */
683   if (!(NRAND(200)))
684     {
685       if (*dv == 0)
686 	*dv = 0.00001;
687       else if (LRAND() & 1)
688 	*dv *= 1.2;
689       else
690 	*dv *= 0.8;
691     }
692 }
693 
694 ENTRYPOINT void
release_moebius(ModeInfo * mi)695 release_moebius(ModeInfo * mi)
696 {
697 	if (moebius != NULL) {
698 		free(moebius);
699 		moebius = (moebiusstruct *) NULL;
700 	}
701 	FreeAllGL(mi);
702 }
703 
704 ENTRYPOINT void
init_moebius(ModeInfo * mi)705 init_moebius(ModeInfo * mi)
706 {
707 	moebiusstruct *mp;
708 
709 	MI_INIT(mi, moebius);
710 	mp = &moebius[MI_SCREEN(mi)];
711 	mp->step = NRAND(90);
712 	mp->ant_position = NRAND(90);
713 
714 	mp->rotx = FLOATRAND(1.0) * RANDSIGN();
715 	mp->roty = FLOATRAND(1.0) * RANDSIGN();
716 	mp->rotz = FLOATRAND(1.0) * RANDSIGN();
717 
718 	/* bell curve from 0-1.5 degrees, avg 0.75 */
719 	mp->dx = (FLOATRAND(1) + FLOATRAND(1) + FLOATRAND(1)) / (360*2);
720 	mp->dy = (FLOATRAND(1) + FLOATRAND(1) + FLOATRAND(1)) / (360*2);
721 	mp->dz = (FLOATRAND(1) + FLOATRAND(1) + FLOATRAND(1)) / (360*2);
722 
723 	mp->d_max = mp->dx * 2;
724 
725 	mp->ddx = 0.00006 + FLOATRAND(0.00003);
726 	mp->ddy = 0.00006 + FLOATRAND(0.00003);
727 	mp->ddz = 0.00006 + FLOATRAND(0.00003);
728 
729 	mp->ddx = 0.00001;
730 	mp->ddy = 0.00001;
731 	mp->ddz = 0.00001;
732 	if ((mp->glx_context = init_GL(mi)) != NULL) {
733 		reshape_moebius(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
734 		glDrawBuffer(GL_BACK);
735 		pinit();
736 	} else {
737 		MI_CLEARWINDOW(mi);
738 	}
739 }
740 
741 ENTRYPOINT void
draw_moebius(ModeInfo * mi)742 draw_moebius(ModeInfo * mi)
743 {
744 	moebiusstruct *mp;
745 
746 	Display    *display = MI_DISPLAY(mi);
747 	Window      window = MI_WINDOW(mi);
748 
749         if (moebius == NULL)
750 	    return;
751 	mp = &moebius[MI_SCREEN(mi)];
752 	MI_IS_DRAWN(mi) = True;
753 	if (!mp->glx_context)
754 		return;
755 #ifdef WIN32
756 	wglMakeCurrent(hdc, mp->glx_context);
757 #else
758 	glXMakeCurrent(display, window, *(mp->glx_context));
759 #endif
760 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
761 
762 	glPushMatrix();
763 
764 	glTranslatef(0.0, 0.0, -10.0);
765 
766 	if (!MI_IS_ICONIC(mi)) {
767 		glScalef(Scale4Window * mp->WindH / mp->WindW, Scale4Window, Scale4Window);
768 	} else {
769 		glScalef(Scale4Iconic * mp->WindH / mp->WindW, Scale4Iconic, Scale4Iconic);
770 	}
771 
772     {
773       GLfloat x = mp->rotx;
774       GLfloat y = mp->roty;
775       GLfloat z = mp->rotz;
776       if (x < 0) x = 1 - (x + 1);
777       if (y < 0) y = 1 - (y + 1);
778       if (z < 0) z = 1 - (z + 1);
779       glRotatef(x * 360, 1.0, 0.0, 0.0);
780       glRotatef(y * 360, 0.0, 1.0, 0.0);
781       glRotatef(z * 360, 0.0, 0.0, 1.0);
782     }
783 
784 	/* moebius */
785 	if (!draw_moebius_strip(mi)) {
786 		release_moebius(mi);
787 		return;
788 	}
789 
790 	glPopMatrix();
791 
792 	rotate(&mp->rotx, &mp->dx, &mp->ddx, mp->d_max, MI_IS_VERBOSE(mi));
793 	rotate(&mp->roty, &mp->dy, &mp->ddy, mp->d_max, MI_IS_VERBOSE(mi));
794 	rotate(&mp->rotz, &mp->dz, &mp->ddz, mp->d_max, MI_IS_VERBOSE(mi));
795 
796 	if (MI_IS_FPS(mi)) do_fps (mi);
797 	glFlush();
798 
799 	glXSwapBuffers(display, window);
800 
801 	mp->step += 0.025;
802 }
803 
804 #ifndef STANDALONE
805 ENTRYPOINT void
change_moebius(ModeInfo * mi)806 change_moebius(ModeInfo * mi)
807 {
808 	moebiusstruct *mp = &moebius[MI_SCREEN(mi)];
809 
810 	if (!mp->glx_context)
811 		return;
812 
813 #ifdef WIN32
814 	wglMakeCurrent(hdc, mp->glx_context);
815 #else
816 	glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mp->glx_context));
817 #endif
818 	pinit();
819 }
820 #endif
821 
822 XSCREENSAVER_MODULE ("Moebius", moebius)
823 
824 #endif /* MODE_moebius */
825