http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.29.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 HACK_RESHAPE           reshape_stairs
68 # define stairs_opts            xlockmore_opts
69 # define DEFAULTS                       "*cycles:               1       \n"                     \
70                                                         "*delay:                20000   \n"                     \
71                                                         "*showFPS:      False   \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         int         sphere_tick;
114         GLXContext *glx_context;
115 } stairsstruct;
116
117 static float front_shininess[] =
118 {60.0};
119 static float front_specular[] =
120 {0.7, 0.7, 0.7, 1.0};
121 static float ambient[] =
122 {0.0, 0.0, 0.0, 1.0};
123 static float diffuse[] =
124 {1.0, 1.0, 1.0, 1.0};
125 static float position0[] =
126 {1.0, 1.0, 1.0, 0.0};
127 static float position1[] =
128 {-1.0, -1.0, 1.0, 0.0};
129 static float lmodel_ambient[] =
130 {0.5, 0.5, 0.5, 1.0};
131 static float lmodel_twoside[] =
132 {GL_TRUE};
133
134 #if 0
135 static float MaterialRed[] =
136 {0.7, 0.0, 0.0, 1.0};
137 static float MaterialGreen[] =
138 {0.1, 0.5, 0.2, 1.0};
139 static float MaterialBlue[] =
140 {0.0, 0.0, 0.7, 1.0};
141 static float MaterialCyan[] =
142 {0.2, 0.5, 0.7, 1.0};
143 static float MaterialMagenta[] =
144 {0.6, 0.2, 0.5, 1.0};
145 static float MaterialGray[] =
146 {0.2, 0.2, 0.2, 1.0};
147 static float MaterialGray5[] =
148 {0.5, 0.5, 0.5, 1.0};
149 static float MaterialGray6[] =
150 {0.6, 0.6, 0.6, 1.0};
151 static float MaterialGray8[] =
152 {0.8, 0.8, 0.8, 1.0};
153
154 #endif
155 static float MaterialYellow[] =
156 {0.7, 0.7, 0.0, 1.0};
157 static float MaterialWhite[] =
158 {0.7, 0.7, 0.7, 1.0};
159
160 static float positions[] =
161 {
162         -2.5, 4.0, 0.0,         /* First one is FUDGED :) */
163         -3.0, 3.25, 1.0,
164         -3.0, 4.4, 1.5,
165         -3.0, 3.05, 2.0,
166         -3.0, 4.2, 2.5,
167
168         -3.0, 2.85, 3.0,
169         -2.5, 4.0, 3.0,
170         -2.0, 2.75, 3.0,
171         -1.5, 3.9, 3.0,
172         -1.0, 2.65, 3.0,
173         -0.5, 3.8, 3.0,
174         0.0, 2.55, 3.0,
175         0.5, 3.7, 3.0,
176         1.0, 2.45, 3.0,
177         1.5, 3.6, 3.0,
178         2.0, 2.35, 3.0,
179
180         2.0, 3.5, 2.5,
181         2.0, 2.25, 2.0,
182         2.0, 3.4, 1.5,
183         2.0, 2.15, 1.0,
184         2.0, 3.3, 0.5,
185         2.0, 2.05, 0.0,
186         2.0, 3.2, -0.5,
187         2.0, 1.95, -1.0,
188         2.0, 3.1, -1.5,
189         2.0, 1.85, -2.0,
190
191         1.5, 2.9, -2.0,
192         1.0, 1.65, -2.0,
193         0.5, 2.7, -2.0,
194         0.0, 1.55, -2.0,
195         -0.5, 2.5, -2.0,
196         -1.0, 1.45, -2.0,
197 };
198
199 #define NPOSITIONS ((sizeof positions) / (sizeof positions[0]))
200
201 #define SPHERE_TICKS 8
202
203 static stairsstruct *stairs = NULL;
204 static GLuint objects;
205
206 #define ObjSphere    0
207
208 #define PlankWidth      3.0
209 #define PlankHeight     0.35
210 #define PlankThickness  0.15
211
212 static void
213 mySphere(float radius)
214 {
215         GLUquadricObj *quadObj;
216
217         quadObj = gluNewQuadric();
218         gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
219         gluSphere(quadObj, radius, 16, 16);
220         gluDeleteQuadric(quadObj);
221 }
222
223 static void
224 draw_block(GLfloat width, GLfloat height, GLfloat thickness)
225 {
226         glBegin(GL_QUADS);
227         glNormal3f(0, 0, 1);
228         glTexCoord2f(0, 0);
229         glVertex3f(-width, -height, thickness);
230         glTexCoord2f(1, 0);
231         glVertex3f(width, -height, thickness);
232         glTexCoord2f(1, 1);
233         glVertex3f(width, height, thickness);
234         glTexCoord2f(0, 1);
235         glVertex3f(-width, height, thickness);
236         glNormal3f(0, 0, -1);
237         glTexCoord2f(0, 0);
238         glVertex3f(-width, height, -thickness);
239         glTexCoord2f(1, 0);
240         glVertex3f(width, height, -thickness);
241         glTexCoord2f(1, 1);
242         glVertex3f(width, -height, -thickness);
243         glTexCoord2f(0, 1);
244         glVertex3f(-width, -height, -thickness);
245         glNormal3f(0, 1, 0);
246         glTexCoord2f(0, 0);
247         glVertex3f(-width, height, thickness);
248         glTexCoord2f(1, 0);
249         glVertex3f(width, height, thickness);
250         glTexCoord2f(1, 1);
251         glVertex3f(width, height, -thickness);
252         glTexCoord2f(0, 1);
253         glVertex3f(-width, height, -thickness);
254         glNormal3f(0, -1, 0);
255         glTexCoord2f(0, 0);
256         glVertex3f(-width, -height, -thickness);
257         glTexCoord2f(1, 0);
258         glVertex3f(width, -height, -thickness);
259         glTexCoord2f(1, 1);
260         glVertex3f(width, -height, thickness);
261         glTexCoord2f(0, 1);
262         glVertex3f(-width, -height, thickness);
263         glNormal3f(1, 0, 0);
264         glTexCoord2f(0, 0);
265         glVertex3f(width, -height, thickness);
266         glTexCoord2f(1, 0);
267         glVertex3f(width, -height, -thickness);
268         glTexCoord2f(1, 1);
269         glVertex3f(width, height, -thickness);
270         glTexCoord2f(0, 1);
271         glVertex3f(width, height, thickness);
272         glNormal3f(-1, 0, 0);
273         glTexCoord2f(0, 0);
274         glVertex3f(-width, height, thickness);
275         glTexCoord2f(1, 0);
276         glVertex3f(-width, height, -thickness);
277         glTexCoord2f(1, 1);
278         glVertex3f(-width, -height, -thickness);
279         glTexCoord2f(0, 1);
280         glVertex3f(-width, -height, thickness);
281         glEnd();
282 }
283
284 static void
285 draw_stairs_internal(ModeInfo * mi)
286 {
287         stairsstruct *sp = &stairs[MI_SCREEN(mi)];
288         GLfloat     X;
289
290         glPushMatrix();
291         glPushMatrix();
292         glTranslatef(-3.0, 0.1, 2.0);
293         for (X = 0; X < 2; X++) {
294                 draw_block(0.5, 2.7 + 0.1 * X, 0.5);
295                 glTranslatef(0.0, 0.1, -1.0);
296         }
297         glPopMatrix();
298         glTranslatef(-3.0, 0.0, 3.0);
299         glPushMatrix();
300
301         for (X = 0; X < 6; X++) {
302                 draw_block(0.5, 2.6 - 0.1 * X, 0.5);
303                 glTranslatef(1.0, -0.1, 0.0);
304         }
305         glTranslatef(-1.0, -0.9, -1.0);
306         for (X = 0; X < 5; X++) {
307                 draw_block(0.5, 3.0 - 0.1 * X, 0.5);
308                 glTranslatef(0.0, 0.0, -1.0);
309         }
310         glTranslatef(-1.0, -1.1, 1.0);
311         for (X = 0; X < 3; X++) {
312                 draw_block(0.5, 3.5 - 0.1 * X, 0.5);
313                 glTranslatef(-1.0, -0.1, 0.0);
314         }
315         glPopMatrix();
316         glPopMatrix();
317
318         glPushMatrix();
319         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
320
321     {
322       int pos  = sp->sphere_position;
323       int ppos = sp->sphere_position - 3;
324       int npos = sp->sphere_position + 3;
325       GLfloat spx, spy, spz;
326       GLfloat dx, dy, dz;
327       int div;
328
329       if (ppos < 0) ppos += NPOSITIONS;
330       if (npos >= NPOSITIONS) npos -= NPOSITIONS;
331
332       if (sp->sphere_tick < 0)
333         {
334           dx = positions[ppos]   - positions[pos];
335           dy = positions[ppos+1] - positions[pos+1];
336           dz = positions[ppos+2] - positions[pos+2];
337           div = SPHERE_TICKS + sp->sphere_tick;
338         }
339       else
340         {
341           dx = positions[npos]   - positions[pos];
342           dy = positions[npos+1] - positions[pos+1];
343           dz = positions[npos+2] - positions[ppos+2];
344           div = SPHERE_TICKS - sp->sphere_tick;
345         }
346         
347       spx = positions[pos];
348       spy = positions[pos+1];
349       spz = positions[pos+2];
350       if (div != 0)
351         {
352           spx += dx / div;
353           spy += dy / div;
354           spz += dz / div;
355         }
356
357
358       spy -= 0.5;   /* move the bottom of the ball closer to the stairs */
359
360
361 #ifdef DEBUG
362       fprintf(stderr, "%3d %3d   %2.2f %2.2f %2.2f  %2.2f %2.2f %2.2f\n",
363               sp->sphere_position, sp->sphere_tick,
364               dx, dy, dz,
365               spx, spy, spz);
366
367       glBegin(GL_LINE_LOOP);   /* path 1 */
368       glVertex3f(positions[pos],  positions[pos+1],  positions[pos+2]);
369       glVertex3f(positions[npos], positions[npos+1], positions[npos+2]);
370       glEnd();
371
372       glBegin(GL_LINE_LOOP);   /* path 2 */
373       glVertex3f(positions[pos],  positions[pos+1],  positions[pos+2]);
374       glVertex3f(positions[ppos], positions[ppos+1], positions[ppos+2]);
375       glEnd();
376
377       glBegin(GL_LINE_LOOP);  /* base origin */
378       glVertex3f(positions[pos], positions[pos+1]-10, positions[pos+2]);
379       glVertex3f(positions[pos], positions[pos+1]+10, positions[pos+2]);
380       glEnd();
381
382       glBegin(GL_LINE_LOOP);  /* base origin */
383       glVertex3f(positions[pos]-10, positions[pos+1], positions[pos+2]);
384       glVertex3f(positions[pos]+10, positions[pos+1], positions[pos+2]);
385       glEnd();
386
387       glBegin(GL_LINE_LOOP);  /* base origin */
388       glVertex3f(positions[pos], positions[pos+1], positions[pos+2]-10);
389       glVertex3f(positions[pos], positions[pos+1], positions[pos+2]+10);
390       glEnd();
391 #endif /* DEBUG */
392
393       glTranslatef(spx, spy, spz);
394
395 #ifdef DEBUG  /* ball origin */
396       glBegin(GL_LINE_LOOP); glVertex3f(0,-2,0); glVertex3f(0,2,0); glEnd();
397       glBegin(GL_LINE_LOOP); glVertex3f(-2,0,0); glVertex3f(2,0,0); glEnd();
398       glBegin(GL_LINE_LOOP); glVertex3f(0,0,-2); glVertex3f(0,0,2); glEnd();
399 #endif /* DEBUG */
400     }
401
402         if (sp->sphere_position == 0)   /* FUDGE soo its not so obvious */
403                 mySphere(0.48);
404         else
405                 mySphere(0.5);
406         glPopMatrix();
407
408     if (++sp->sphere_tick >= SPHERE_TICKS-1)
409       {
410         sp->sphere_tick = -(SPHERE_TICKS-2);
411         sp->sphere_position += 3;
412         sp->sphere_position += 3;
413       }
414
415         if (sp->sphere_position >= NPOSITIONS)
416                 sp->sphere_position = 0;
417 }
418
419 void
420 reshape_stairs(ModeInfo * mi, int width, int height)
421 {
422         stairsstruct *sp = &stairs[MI_SCREEN(mi)];
423
424         glViewport(0, 0, sp->WindW = (GLint) width, sp->WindH = (GLint) height);
425         glMatrixMode(GL_PROJECTION);
426         glLoadIdentity();
427         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0);
428         glMatrixMode(GL_MODELVIEW);
429         if (width >= 1024) {
430                 glLineWidth(3);
431                 glPointSize(3);
432         } else if (width >= 512) {
433                 glLineWidth(2);
434                 glPointSize(2);
435         } else {
436                 glLineWidth(1);
437                 glPointSize(1);
438         }
439 }
440
441 static void
442 pinit(void)
443 {
444         glClearDepth(1.0);
445         glClearColor(0.0, 0.0, 0.0, 1.0);
446
447         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
448         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
449         glLightfv(GL_LIGHT0, GL_POSITION, position0);
450         glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
451         glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
452         glLightfv(GL_LIGHT1, GL_POSITION, position1);
453         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
454         glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
455         glEnable(GL_LIGHTING);
456         glEnable(GL_LIGHT0);
457         glEnable(GL_LIGHT1);
458         glEnable(GL_NORMALIZE);
459         glFrontFace(GL_CCW);
460         glCullFace(GL_BACK);
461
462         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
463         glShadeModel(GL_FLAT);
464         glEnable(GL_DEPTH_TEST);
465         glEnable(GL_TEXTURE_2D);
466         glEnable(GL_CULL_FACE);
467
468         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
469         gluBuild2DMipmaps(GL_TEXTURE_2D, 3, WoodTextureWidth, WoodTextureHeight,
470                           GL_RGB, GL_UNSIGNED_BYTE, WoodTextureData);
471         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
472         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
473         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
474         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
475         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
476
477         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
478         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
479 }
480
481 void
482 init_stairs(ModeInfo * mi)
483 {
484         int         screen = MI_SCREEN(mi);
485         stairsstruct *sp;
486
487         if (stairs == NULL) {
488                 if ((stairs = (stairsstruct *) calloc(MI_NUM_SCREENS(mi),
489                                              sizeof (stairsstruct))) == NULL)
490                         return;
491         }
492         sp = &stairs[screen];
493         sp->step = 0.0;
494         sp->direction = LRAND() & 1;
495         sp->sphere_position = NRAND(NPOSITIONS / 3) * 3;
496         sp->sphere_tick = 0;
497
498         if ((sp->glx_context = init_GL(mi)) != NULL) {
499
500                 reshape_stairs(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
501                 glDrawBuffer(GL_BACK);
502                 if (!glIsList(objects))
503                         objects = glGenLists(1);
504                 pinit();
505         } else {
506                 MI_CLEARWINDOW(mi);
507         }
508 }
509
510 void
511 draw_stairs(ModeInfo * mi)
512 {
513         stairsstruct *sp = &stairs[MI_SCREEN(mi)];
514
515         Display    *display = MI_DISPLAY(mi);
516         Window      window = MI_WINDOW(mi);
517
518         if (!sp->glx_context)
519                 return;
520
521         glXMakeCurrent(display, window, *(sp->glx_context));
522
523         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
524
525         glPushMatrix();
526
527         glTranslatef(0.0, 0.0, -10.0);
528
529         if (!MI_IS_ICONIC(mi)) {
530                 glScalef(Scale4Window * sp->WindH / sp->WindW, Scale4Window, Scale4Window);
531         } else {
532                 glScalef(Scale4Iconic * sp->WindH / sp->WindW, Scale4Iconic, Scale4Iconic);
533         }
534
535         glRotatef(44.5, 1, 0, 0);
536         glRotatef(50 + ((sp->direction) ? 1 : -1) *
537                ((sp->step * 100 > 120) ? sp->step * 100 - 120 : 0), 0, 1, 0);
538         if (sp->step * 100 >= 360 + 120) {      /* stop showing secrets */
539                 sp->step = 0;
540                 sp->direction = LRAND() & 1;
541         }
542         draw_stairs_internal(mi);
543
544         glPopMatrix();
545
546     if (mi->fps_p) do_fps (mi);
547         glFlush();
548
549         glXSwapBuffers(display, window);
550
551         sp->step += 0.025;
552 }
553
554 void
555 change_stairs(ModeInfo * mi)
556 {
557         stairsstruct *sp = &stairs[MI_SCREEN(mi)];
558
559         if (!sp->glx_context)
560                 return;
561
562         glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(sp->glx_context));
563         pinit();
564 }
565
566 void
567 release_stairs(ModeInfo * mi)
568 {
569         if (stairs != NULL) {
570                 (void) free((void *) stairs);
571                 stairs = NULL;
572         }
573         if (glIsList(objects)) {
574                 glDeleteLists(objects, 1);
575         }
576         FreeAllGL(mi);
577 }
578
579 #endif