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