http://ftp.x.org/contrib/applications/xscreensaver-2.17.tar.gz
[xscreensaver] / hacks / glx / stairs.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* stairs --- Infinite Stairs, and Escher-like scene. */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)stairs.c      4.07 97/11/24 xlockmore";
6
7 #endif
8
9 #undef DEBUG_LISTS
10
11 /*-
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.
17  *
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.
23  *
24  * This mode shows some interesting scenes that are impossible OR very
25  * weird to build in the real universe. Much of the scenes are inspirated
26  * on Mauritz Cornelis stairs's works which derivated the mode's name.
27  * M.C. Escher (1898-1972) was a dutch artist and many people prefer to
28  * say he was a mathematician.
29  *
30  * Thanks goes to Brian Paul for making it possible and inexpensive to use 
31  * OpenGL at home.
32  *
33  * Since I'm not a native English speaker, my apologies for any grammatical
34  * mistake.
35  *
36  * My e-mail addresses are
37  * vianna@cat.cbpf.br 
38  *         and
39  * m-vianna@usa.net
40  *
41  * Marcelo F. Vianna (Jun-01-1997)
42  *
43  * Revision History:
44  * 07-Jan-98: This would be a scene for the escher mode, but now escher mode
45  *            was splitted in different modes for each scene. This is the
46  *            initial release and is not working yet.
47  *            Marcelo F. Vianna.
48  *
49  */
50
51 /*-
52  * Texture mapping is only available on RGBA contexts, Mono and color index
53  * visuals DO NOT support texture mapping in OpenGL.
54  *
55  * BUT Mesa do implements RGBA contexts in pseudo color visuals, so texture
56  * mapping shuld work on PseudoColor, DirectColor, TrueColor using Mesa. Mono
57  * is not officially supported for both OpenGL and Mesa, but seems to not crash
58  * Mesa.
59  *
60  * In real OpenGL, PseudoColor DO NOT support texture map (as far as I know).
61  */
62
63 #include <X11/Intrinsic.h>
64
65 #ifdef STANDALONE
66 # define PROGCLASS                      "Stairs"
67 # define HACK_INIT                      init_stairs
68 # define HACK_DRAW                      draw_stairs
69 # define stairs_opts            xlockmore_opts
70 # define DEFAULTS                       "*cycles:               1       \n"                     \
71                                                         "*delay:                200000  \n"                     \
72                                                         "*wireframe:    False   \n"
73 # include "xlockmore.h"         /* from the xscreensaver distribution */
74 #else /* !STANDALONE */
75 # include "xlock.h"                     /* from the xlockmore distribution */
76
77 #endif /* !STANDALONE */
78
79 #ifdef USE_GL
80
81 #include <GL/glu.h>
82 #include "e_textures.h"
83
84 ModeSpecOpt stairs_opts =
85 {0, NULL, 0, NULL, NULL};
86
87 #ifdef USE_MODULES
88 ModStruct   stairs_description =
89 {"stairs", "init_stairs", "draw_stairs", "release_stairs",
90  "draw_stairs", "change_stairs", NULL, &stairs_opts,
91  1000, 1, 1, 1, 4, 1.0, "",
92  "Shows Infinite Stairs, an Escher-like scene", 0, NULL};
93
94 #endif
95
96 #define Scale4Window               0.3
97 #define Scale4Iconic               0.4
98
99 #define sqr(A)                     ((A)*(A))
100
101 #ifndef Pi
102 #define Pi                         M_PI
103 #endif
104
105 /*************************************************************************/
106
107 typedef struct {
108         GLint       WindH, WindW;
109         GLfloat     step;
110         Bool        direction;
111         int         AreObjectsDefined[1];
112         int         sphere_position;
113         GLXContext *glx_context;
114 } stairsstruct;
115
116 static float front_shininess[] =
117 {60.0};
118 static float front_specular[] =
119 {0.7, 0.7, 0.7, 1.0};
120 static float ambient[] =
121 {0.0, 0.0, 0.0, 1.0};
122 static float diffuse[] =
123 {1.0, 1.0, 1.0, 1.0};
124 static float position0[] =
125 {1.0, 1.0, 1.0, 0.0};
126 static float position1[] =
127 {-1.0, -1.0, 1.0, 0.0};
128 static float lmodel_ambient[] =
129 {0.5, 0.5, 0.5, 1.0};
130 static float lmodel_twoside[] =
131 {GL_TRUE};
132
133 #if 0
134 static float MaterialRed[] =
135 {0.7, 0.0, 0.0, 1.0};
136 static float MaterialGreen[] =
137 {0.1, 0.5, 0.2, 1.0};
138 static float MaterialBlue[] =
139 {0.0, 0.0, 0.7, 1.0};
140 static float MaterialCyan[] =
141 {0.2, 0.5, 0.7, 1.0};
142 static float MaterialMagenta[] =
143 {0.6, 0.2, 0.5, 1.0};
144 static float MaterialGray[] =
145 {0.2, 0.2, 0.2, 1.0};
146 static float MaterialGray5[] =
147 {0.5, 0.5, 0.5, 1.0};
148 static float MaterialGray6[] =
149 {0.6, 0.6, 0.6, 1.0};
150 static float MaterialGray8[] =
151 {0.8, 0.8, 0.8, 1.0};
152
153 #endif
154 static float MaterialYellow[] =
155 {0.7, 0.7, 0.0, 1.0};
156 static float MaterialWhite[] =
157 {0.7, 0.7, 0.7, 1.0};
158
159 static float positions[] =
160 {
161         -2.5, 4.0, 0.0,         /* First one is FUDGED :) */
162         -3.0, 3.25, 1.0,
163         -3.0, 4.4, 1.5,
164         -3.0, 3.05, 2.0,
165         -3.0, 4.2, 2.5,
166
167         -3.0, 2.85, 3.0,
168         -2.5, 4.0, 3.0,
169         -2.0, 2.75, 3.0,
170         -1.5, 3.9, 3.0,
171         -1.0, 2.65, 3.0,
172         -0.5, 3.8, 3.0,
173         0.0, 2.55, 3.0,
174         0.5, 3.7, 3.0,
175         1.0, 2.45, 3.0,
176         1.5, 3.6, 3.0,
177         2.0, 2.35, 3.0,
178
179         2.0, 3.5, 2.5,
180         2.0, 2.25, 2.0,
181         2.0, 3.4, 1.5,
182         2.0, 2.15, 1.0,
183         2.0, 3.3, 0.5,
184         2.0, 2.05, 0.0,
185         2.0, 3.2, -0.5,
186         2.0, 1.95, -1.0,
187         2.0, 3.1, -1.5,
188         2.0, 1.85, -2.0,
189
190         1.5, 2.9, -2.0,
191         1.0, 1.65, -2.0,
192         0.5, 2.7, -2.0,
193         0.0, 1.55, -2.0,
194         -0.5, 2.5, -2.0,
195         -1.0, 1.45, -2.0,
196 };
197
198 #define NPOSITIONS ((sizeof positions) / (sizeof positions[0]))
199
200 static stairsstruct *stairs = NULL;
201 static GLuint objects;
202
203 #define ObjSphere    0
204
205 #define PlankWidth      3.0
206 #define PlankHeight     0.35
207 #define PlankThickness  0.15
208
209 static void
210 mySphere(float radius)
211 {
212         GLUquadricObj *quadObj;
213
214         quadObj = gluNewQuadric();
215         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
216         gluSphere(quadObj, radius, 16, 16);
217         gluDeleteQuadric(quadObj);
218 }
219
220 static void
221 draw_block(GLfloat width, GLfloat height, GLfloat thickness)
222 {
223         glBegin(GL_QUADS);
224         glNormal3f(0, 0, 1);
225         glTexCoord2f(0, 0);
226         glVertex3f(-width, -height, thickness);
227         glTexCoord2f(1, 0);
228         glVertex3f(width, -height, thickness);
229         glTexCoord2f(1, 1);
230         glVertex3f(width, height, thickness);
231         glTexCoord2f(0, 1);
232         glVertex3f(-width, height, thickness);
233         glNormal3f(0, 0, -1);
234         glTexCoord2f(0, 0);
235         glVertex3f(-width, height, -thickness);
236         glTexCoord2f(1, 0);
237         glVertex3f(width, height, -thickness);
238         glTexCoord2f(1, 1);
239         glVertex3f(width, -height, -thickness);
240         glTexCoord2f(0, 1);
241         glVertex3f(-width, -height, -thickness);
242         glNormal3f(0, 1, 0);
243         glTexCoord2f(0, 0);
244         glVertex3f(-width, height, thickness);
245         glTexCoord2f(1, 0);
246         glVertex3f(width, height, thickness);
247         glTexCoord2f(1, 1);
248         glVertex3f(width, height, -thickness);
249         glTexCoord2f(0, 1);
250         glVertex3f(-width, height, -thickness);
251         glNormal3f(0, -1, 0);
252         glTexCoord2f(0, 0);
253         glVertex3f(-width, -height, -thickness);
254         glTexCoord2f(1, 0);
255         glVertex3f(width, -height, -thickness);
256         glTexCoord2f(1, 1);
257         glVertex3f(width, -height, thickness);
258         glTexCoord2f(0, 1);
259         glVertex3f(-width, -height, thickness);
260         glNormal3f(1, 0, 0);
261         glTexCoord2f(0, 0);
262         glVertex3f(width, -height, thickness);
263         glTexCoord2f(1, 0);
264         glVertex3f(width, -height, -thickness);
265         glTexCoord2f(1, 1);
266         glVertex3f(width, height, -thickness);
267         glTexCoord2f(0, 1);
268         glVertex3f(width, height, thickness);
269         glNormal3f(-1, 0, 0);
270         glTexCoord2f(0, 0);
271         glVertex3f(-width, height, thickness);
272         glTexCoord2f(1, 0);
273         glVertex3f(-width, height, -thickness);
274         glTexCoord2f(1, 1);
275         glVertex3f(-width, -height, -thickness);
276         glTexCoord2f(0, 1);
277         glVertex3f(-width, -height, thickness);
278         glEnd();
279 }
280
281 static void
282 draw_stairs_internal(ModeInfo * mi)
283 {
284         stairsstruct *sp = &stairs[MI_SCREEN(mi)];
285         GLfloat     X;
286
287         glPushMatrix();
288         glPushMatrix();
289         glTranslatef(-3.0, 0.1, 2.0);
290         for (X = 0; X < 2; X++) {
291                 draw_block(0.5, 2.7 + 0.1 * X, 0.5);
292                 glTranslatef(0.0, 0.1, -1.0);
293         }
294         glPopMatrix();
295         glTranslatef(-3.0, 0.0, 3.0);
296         glPushMatrix();
297
298         for (X = 0; X < 6; X++) {
299                 draw_block(0.5, 2.6 - 0.1 * X, 0.5);
300                 glTranslatef(1.0, -0.1, 0.0);
301         }
302         glTranslatef(-1.0, -0.9, -1.0);
303         for (X = 0; X < 5; X++) {
304                 draw_block(0.5, 3.0 - 0.1 * X, 0.5);
305                 glTranslatef(0.0, 0.0, -1.0);
306         }
307         glTranslatef(-1.0, -1.1, 1.0);
308         for (X = 0; X < 3; X++) {
309                 draw_block(0.5, 3.5 - 0.1 * X, 0.5);
310                 glTranslatef(-1.0, -0.1, 0.0);
311         }
312         glPopMatrix();
313         glPopMatrix();
314
315         glPushMatrix();
316         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
317
318         glTranslatef((GLfloat) positions[sp->sphere_position],
319                      (GLfloat) positions[sp->sphere_position + 1],
320                      (GLfloat) positions[sp->sphere_position + 2]);
321         if (sp->sphere_position == 0)   /* FUDGE soo its not so obvious */
322                 mySphere(0.48);
323         else
324                 mySphere(0.5);
325         glPopMatrix();
326         sp->sphere_position += 3;
327         if (sp->sphere_position >= NPOSITIONS)
328                 sp->sphere_position = 0;
329 }
330
331 static void
332 reshape(ModeInfo * mi, int width, int height)
333 {
334         stairsstruct *sp = &stairs[MI_SCREEN(mi)];
335
336         glViewport(0, 0, sp->WindW = (GLint) width, sp->WindH = (GLint) height);
337         glMatrixMode(GL_PROJECTION);
338         glLoadIdentity();
339         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
340         glMatrixMode(GL_MODELVIEW);
341         if (width >= 1024) {
342                 glLineWidth(3);
343                 glPointSize(3);
344         } else if (width >= 512) {
345                 glLineWidth(2);
346                 glPointSize(2);
347         } else {
348                 glLineWidth(1);
349                 glPointSize(1);
350         }
351 }
352
353 static void
354 pinit(void)
355 {
356         glClearDepth(1.0);
357         glClearColor(0.0, 0.0, 0.0, 1.0);
358
359         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
360         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
361         glLightfv(GL_LIGHT0, GL_POSITION, position0);
362         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
363         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
364         glLightfv(GL_LIGHT1, GL_POSITION, position1);
365         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
366         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
367         glEnable(GL_LIGHTING);
368         glEnable(GL_LIGHT0);
369         glEnable(GL_LIGHT1);
370         glEnable(GL_NORMALIZE);
371         glFrontFace(GL_CCW);
372         glCullFace(GL_BACK);
373
374         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
375         glShadeModel(GL_FLAT);
376         glEnable(GL_DEPTH_TEST);
377         glEnable(GL_TEXTURE_2D);
378         glEnable(GL_CULL_FACE);
379
380         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
381         gluBuild2DMipmaps(GL_TEXTURE_2D, 3, WoodTextureWidth, WoodTextureHeight,
382                           GL_RGB, GL_UNSIGNED_BYTE, WoodTextureData);
383         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
384         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
385         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
386         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
387         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
388
389         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
390         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
391 }
392
393 void
394 init_stairs(ModeInfo * mi)
395 {
396         int         screen = MI_SCREEN(mi);
397         stairsstruct *sp;
398
399         if (stairs == NULL) {
400                 if ((stairs = (stairsstruct *) calloc(MI_NUM_SCREENS(mi),
401                                              sizeof (stairsstruct))) == NULL)
402                         return;
403         }
404         sp = &stairs[screen];
405         sp->step = 0.0;
406         sp->direction = LRAND() & 1;
407         sp->sphere_position = NRAND(NPOSITIONS / 3) * 3;
408
409         if ((sp->glx_context = init_GL(mi)) != NULL) {
410
411                 reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
412                 glDrawBuffer(GL_BACK);
413                 if (!glIsList(objects))
414                         objects = glGenLists(1);
415                 pinit();
416         } else {
417                 MI_CLEARWINDOW(mi);
418         }
419 }
420
421 void
422 draw_stairs(ModeInfo * mi)
423 {
424         stairsstruct *sp = &stairs[MI_SCREEN(mi)];
425
426         Display    *display = MI_DISPLAY(mi);
427         Window      window = MI_WINDOW(mi);
428
429         if (!sp->glx_context)
430                 return;
431
432         glXMakeCurrent(display, window, *(sp->glx_context));
433
434         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
435
436         glPushMatrix();
437
438         glTranslatef(0.0, 0.0, -10.0);
439
440         if (!MI_IS_ICONIC(mi)) {
441                 glScalef(Scale4Window * sp->WindH / sp->WindW, Scale4Window, Scale4Window);
442         } else {
443                 glScalef(Scale4Iconic * sp->WindH / sp->WindW, Scale4Iconic, Scale4Iconic);
444         }
445
446         glRotatef(44.5, 1, 0, 0);
447         glRotatef(50 + ((sp->direction) ? 1 : -1) *
448                ((sp->step * 100 > 120) ? sp->step * 100 - 120 : 0), 0, 1, 0);
449         if (sp->step * 100 >= 360 + 120) {      /* stop showing secrets */
450                 sp->step = 0;
451                 sp->direction = LRAND() & 1;
452         }
453         draw_stairs_internal(mi);
454
455         glPopMatrix();
456
457         glFlush();
458
459         glXSwapBuffers(display, window);
460
461         sp->step += 0.025;
462 }
463
464 void
465 change_stairs(ModeInfo * mi)
466 {
467         stairsstruct *sp = &stairs[MI_SCREEN(mi)];
468
469         if (!sp->glx_context)
470                 return;
471
472         glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(sp->glx_context));
473         pinit();
474 }
475
476 void
477 release_stairs(ModeInfo * mi)
478 {
479         if (stairs != NULL) {
480                 (void) free((void *) stairs);
481                 stairs = NULL;
482         }
483         if (glIsList(objects)) {
484                 glDeleteLists(objects, 1);
485         }
486         FreeAllGL(mi);
487 }
488
489 #endif