ftp://ftp.linux.ncsu.edu/mirror/ftp.redhat.com/pub/redhat/linux/enterprise/4/en/os...
[xscreensaver] / hacks / glx / tunnel_draw.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* atunnels --- OpenGL Advanced Tunnel Demo */
3
4 #if 0
5 static const char sccsid[] = "@(#)tunnel_draw.c 5.13 2004/05/25 xlockmore";
6 #endif
7
8 /* Copyright (c) E. Lassauge, 2002-2004. */
9
10 /*
11  * Permission to use, copy, modify, and distribute this software and its
12  * documentation for any purpose and without fee is hereby granted,
13  * provided that the above copyright notice appear in all copies and that
14  * both that copyright notice and this permission notice appear in
15  * supporting documentation.
16  *
17  * This file is provided AS IS with no warranties of any kind.  The author
18  * shall have no liability with respect to the infringement of copyrights,
19  * trade secrets or any patents by this file or any part thereof.  In no
20  * event will the author be liable for any lost revenue or profits or
21  * other special, indirect and consequential damages.
22  *
23  * The original code for this mode was written by Roman Podobedov
24  * Email: romka@ut.ee
25  * WEB: http://romka.demonews.com
26  *
27  * Eric Lassauge  (May-25-2004) <lassauge@users.sourceforge.net>
28  *                                  http://lassauge.free.fr/linux.html
29  *
30  * REVISION HISTORY:
31  * E.Lassauge - 25-May-2004:
32  *      - added more texture
33  *      - random texture init
34  *
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifdef USE_GL /* whole file */
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <math.h>
46
47 #include <GL/gl.h>
48 #include <GL/glu.h>
49
50 #include "tunnel_draw.h"
51
52 #ifdef STANDALONE /* For NRAND() */
53 #include "xlockmoreI.h"          /* in xscreensaver distribution */
54 #else /* STANDALONE */
55 #include "xlock.h"              /* in xlockmore distribution */
56 #endif /* STANDALONE */
57
58 typedef struct 
59 {
60   float x, y, z; /* Point coordinates */
61 } cvPoint;
62
63 typedef struct _tnPath
64 {
65         cvPoint p;
66         struct _tnPath *next;
67 } tnPath;
68
69
70 tnPath *path = NULL;
71
72 const cvPoint initpath[]={
73 {0.000000, 0.000000, 0.000000},
74 {2.000000, 1.000000, 0.000000},
75 {4.000000, 0.000000, 0.000000},
76 {6.000000, 1.000000, 0.000000},
77 {8.000000, 0.000000, 1.000000},
78 {10.000000, 1.000000, 1.000000},
79 {12.000000, 1.500000, 0.000000},
80 {14.000000, 0.000000, 0.000000},
81 {16.000000, 1.000000, 0.000000},
82 {18.000000, 0.000000, 0.000000},
83 {20.000000, 0.000000, 1.000000},
84 {22.000000, 1.000000, 0.000000},
85 {24.000000, 0.000000, 1.000000},
86 {26.000000, 0.000000, 1.000000},
87 {28.000000, 1.000000, 0.000000},
88 {30.000000, 0.000000, 2.000000},
89 {32.000000, 1.000000, 0.000000},
90 {34.000000, 0.000000, 2.000000},
91 {-1.000000, -1.000000, -1.000000}
92 };
93
94 /* Camera variables */
95 static float cam_t=0;
96 static tnPath *cam_pos;
97 static float alpha=0;
98
99 /* Tunnel Drawing Variables */
100 static int tFlag=0;
101 static cvPoint prev_points[10];
102 static int current_texture;
103
104 /* Modes */
105 static float ModeX=0;
106 static int ModeXFlag=0;
107
108 /*=================== Vector normalization ==================================*/
109 void normalize(cvPoint *V)
110 {
111   float d;
112
113   /* Vector length */
114   d = (float)sqrt(V->x*V->x + V->y*V->y + V->z*V->z);
115
116   /* Normalization */
117   V->x /= d; 
118   V->y /= d; 
119   V->z /= d; 
120 }
121 /*=================== C = A x B  (Vector multiply) ==========================*/
122 void vect_mult(cvPoint *A, cvPoint *B, cvPoint *C)
123 {
124         /* Vector multiply */
125         C->x = A->y*B->z - A->z*B->y;
126         C->y = A->z*B->x - A->x*B->z;
127         C->z = A->x*B->y - A->y*B->x;
128 }
129
130 /* Catmull-Rom Curve calculations */
131 void cvCatmullRom(cvPoint *p, float t, cvPoint *outp)
132 {
133         float t2, t3, t1;
134
135         t2 = t*t;
136         t3 = t*t*t;
137         t1 = (1-t)*(1-t);
138
139         outp->x = (-t*t1*p[0].x + (2-5*t2+3*t3)*p[1].x + t*(1+4*t-3*t2)*p[2].x - t2*(1-t)*p[3].x)/2;
140         outp->y = (-t*t1*p[0].y + (2-5*t2+3*t3)*p[1].y + t*(1+4*t-3*t2)*p[2].y - t2*(1-t)*p[3].y)/2;
141         outp->z = (-t*t1*p[0].z + (2-5*t2+3*t3)*p[1].z + t*(1+4*t-3*t2)*p[2].z - t2*(1-t)*p[3].z)/2;
142 }
143
144 /*=================== Point Rotating Around Line ===========================
145 // p    - original point
146 // pp   - pivot point
147 // pl   - pivot line (vector)
148 // a    - angle to rotate in radians
149 // outp - output point
150 //==========================================================================
151 */
152 void RotateAroundLine(cvPoint *p, cvPoint *pp, cvPoint *pl, float a, cvPoint *outp)
153 {
154         cvPoint p1, p2;
155         float l, m, n, ca, sa;
156
157         p1.x = p->x - pp->x;
158         p1.y = p->y - pp->y;
159         p1.z = p->z - pp->z;
160
161         l = pl->x;
162         m = pl->y;
163         n = pl->z;
164
165         ca = cos(a);
166         sa = sin(a);
167
168         p2.x = p1.x*((l*l)+ca*(1-l*l)) + p1.y*(l*(1-ca)*m+n*sa) + p1.z*(l*(1-ca)*n-m*sa);
169         p2.y = p1.x*(l*(1-ca)*m-n*sa) + p1.y*(m*m+ca*(1-m*m)) + p1.z*(m*(1-ca)*n+l*sa);
170         p2.z = p1.x*(l*(1-ca)*n+m*sa) + p1.y*(m*(1-ca)*n-l*sa) + p1.z*(n*n+ca*(1-n*n));
171
172         outp->x = p2.x + pp->x;
173         outp->y = p2.y + pp->y;
174         outp->z = p2.z + pp->z;
175 }
176
177
178 /*=================== Load camera and tunnel path ==========================*/
179 static void LoadPath(void)
180 {
181         float x, y, z;
182         tnPath *path1=NULL, *path2=NULL;
183
184         cvPoint *f = (cvPoint *)initpath;
185         
186         while (f->x != -1.0)
187         {
188                 x = f->x;
189                 y = f->y;
190                 z = f->z;
191                 f++;
192
193                 if (path == NULL)
194                 {
195                         path = (tnPath *)malloc(sizeof(tnPath));
196                         path1 = path;
197                 }
198                 else
199                 {
200                         path2 = (tnPath *)malloc(sizeof(tnPath));
201                         path1->next = path2;
202                         path1 = path2;
203                 }
204                 
205                 path1->next = NULL;
206                 path1->p.x = x;
207                 path1->p.y = y;
208                 path1->p.z = z;
209         }
210
211         cam_pos = path;
212         cam_t = 0;
213 }
214
215 /*=================== Tunnel Initialization ================================*/
216 void InitTunnel(void)
217 {
218         LoadPath();
219         current_texture = NRAND(MAX_TEXTURE);
220 }
221
222 void DrawTunnel(int do_texture, int do_light, GLuint *textures)
223 {
224         tnPath *p, *p1, *cmpos;
225         cvPoint op, p4[4], T, ppp, ppp1, op1, op2;
226         float t;
227         int i, j, k, flag;
228         cvPoint points[10];
229         GLfloat light_position[4];
230
231
232         /* Select current tunnel texture */
233         if (do_texture)
234                 glBindTexture(GL_TEXTURE_2D, textures[current_texture]);
235         
236         cmpos = cam_pos;
237         /* Get current curve */
238         if (cam_pos->next->next->next)
239         {
240                 p1 = cam_pos;
241                 for (i=0; i<4; i++)
242                 {
243                         p4[i].x = p1->p.x;
244                         p4[i].y = p1->p.y;
245                         p4[i].z = p1->p.z;
246                         p1 = p1->next;
247                 }
248         }
249         else 
250         {
251                 /* End of tunnel */
252                 ModeX = 1.0;
253                 ModeXFlag = 0;
254                 return;
255         };
256                 
257         /* Get current camera position */
258         cvCatmullRom(p4, cam_t, &op);
259
260         /* Next camera position */
261         cam_t += 0.02f;
262         if (cam_t >= 1)
263         {
264                 cam_t = cam_t - 1;
265                 cmpos = cam_pos->next;
266         }
267                 
268         /* Get curve for next camera position */
269         if (cmpos->next->next->next)
270         {
271                 p1 = cmpos;
272                 for (i=0; i<4; i++)
273                 {
274                         p4[i].x = p1->p.x;
275                         p4[i].y = p1->p.y;
276                         p4[i].z = p1->p.z;
277                         p1 = p1->next;
278                 }
279         }
280         else 
281         {       
282                 /*  End of tunnel */
283                 ModeX = 1.0;
284                 ModeXFlag = 0;
285                 return;
286         }
287         
288         /*  Get next camera position */
289         cvCatmullRom(p4, cam_t, &op1);
290         
291         /*  Rotate camera */
292         glRotatef(alpha, 0, 0, -1);
293         alpha += 1;
294         /*  Set camera position */
295         gluLookAt(op.x, op.y, op.z, op1.x, op1.y, op1.z, 0, 1, 0);
296
297         /*  Set light position */
298         if (do_light)
299         {
300                 light_position[0] = op.x;
301                 light_position[1] = op.y;
302                 light_position[2] = op.z;
303                 light_position[3] = 1;
304                 glLightfv(GL_LIGHT0, GL_POSITION, light_position);
305         }
306         
307         p = cam_pos;
308         flag = 0;
309         t = 0;
310         k = 0;
311         /*  Draw tunnel from current curve and next 2 curves */
312         glBegin(GL_QUADS);
313         while (k < 3)
314         {
315                 if (p->next->next->next)
316                 {
317                         p1 = p;
318                         for (i=0; i<4; i++)
319                         {
320                                 p4[i].x = p1->p.x;
321                                 p4[i].y = p1->p.y;
322                                 p4[i].z = p1->p.z;
323                                 p1 = p1->next;
324                         }
325                 }
326                 else
327                 {
328                         /*  End of tunnel */
329                         ModeX = 1.0;
330                         ModeXFlag = 0;
331                         return;
332                 }
333                 cvCatmullRom(p4, t, &op);
334
335                 ppp.x = op.x;
336                 ppp.y = op.y;
337                 ppp.z = op.z + 0.25;
338
339                 t += 0.1;
340                 if (t >= 1.0)
341                 {
342                         t = t - 1;
343                         k++;
344                         p = p->next;
345                 }
346         
347                 if (p->next->next->next)
348                 {
349                         p1 = p;
350                         for (i=0; i<4; i++)
351                         {
352                                 p4[i].x = p1->p.x;
353                                 p4[i].y = p1->p.y;
354                                 p4[i].z = p1->p.z;
355                                 p1 = p1->next;
356                         }
357                 } 
358                 else
359                 {
360                         /*  End of tunnel */
361                         ModeX = 1.0;
362                         ModeXFlag = 0;
363                         return;
364                 }
365                         
366                 cvCatmullRom(p4, t, &op1);
367
368                 ppp1.x = op1.x;
369                 ppp1.y = op1.y;
370                 ppp1.z = op1.z + 0.25;
371
372                 T.x = op1.x - op.x;
373                 T.y = op1.y - op.y;
374                 T.z = op1.z - op.z;
375                         
376                 normalize(&T);
377
378                 for (i=0; i<10; i++)
379                 {
380                         RotateAroundLine(&ppp, &op, &T, ((float)i*36.0*M_PI/180.0), &op2);
381                         points[i].x = op2.x;
382                         points[i].y = op2.y;
383                         points[i].z = op2.z;
384                         if (!flag)
385                         {
386                                 prev_points[i].x = op2.x;
387                                 prev_points[i].y = op2.y;
388                                 prev_points[i].z = op2.z;
389                         }
390                 }
391         
392                 if (!flag)
393                 {
394                         flag = 1;
395                         continue;
396                 }
397                 
398                 /*  Draw 10 polygons for current point */
399                 for (i=0; i<10; i++)
400                 {
401                         j = i+1;
402                         if (j > 9) j = 0;
403                         glNormal3f(0, 0, 1); /*  Normal for lighting */
404                         glTexCoord2f(0, 0); glVertex3f(prev_points[i].x, prev_points[i].y, prev_points[i].z);
405                         glNormal3f(0, 0, 1);
406                         glTexCoord2f(1, 0); glVertex3f(points[i].x, points[i].y, points[i].z);
407                         glNormal3f(0, 0, 1);
408                         glTexCoord2f(1, 1); glVertex3f(points[j].x, points[j].y, points[j].z);
409                         glNormal3f(0, 0, 1);
410                         glTexCoord2f(0, 1); glVertex3f(prev_points[j].x, prev_points[j].y, prev_points[j].z);
411                 }
412                 /*  Save current polygon coordinates for next position */
413                 for (i=0; i<10; i++)
414                 {
415                         prev_points[i].x = points[i].x;
416                         prev_points[i].y = points[i].y;
417                         prev_points[i].z = points[i].z;
418                 }
419         }
420         glEnd();
421         cam_pos = cmpos;
422 }
423
424 /* =================== Show splash screen =================================== */
425 void SplashScreen(int do_wire, int do_texture, int do_light)
426 {
427         if (ModeX > 0)
428         {
429                 /*  Reset tunnel and camera position */
430                 if (!ModeXFlag)
431                 {
432                         cam_pos = path;                 
433                         cam_t = 0;
434                         tFlag = 0;
435                         ModeXFlag = 1;
436                         current_texture++;
437                         if (current_texture >= MAX_TEXTURE) current_texture = 0;
438                 }
439                 /*  Now we want to draw splash screen */
440                 glLoadIdentity();
441                 /*  Disable all unused features */
442                 glDisable(GL_DEPTH_TEST);
443                 glDisable(GL_LIGHTING);
444                 glDisable(GL_FOG);
445                 glDisable(GL_CULL_FACE);
446
447                 glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
448                 glEnable(GL_BLEND);
449                 glDisable(GL_TEXTURE_2D);
450                 glColor4f(1, 1, 1, ModeX);
451                 
452                 /*  Draw splash screen (simply quad) */
453                 glBegin(GL_QUADS);
454                 glVertex3f(-10, -10, -1);
455                 glVertex3f(10, -10, -1);
456                 glVertex3f(10, 10, -1);
457                 glVertex3f(-10, 10, -1);
458                 glEnd();
459
460                 ModeX -= 0.05;
461                 if (ModeX <= 0) ModeX = 0;
462
463                 if (!do_wire)
464                 {
465                         glEnable(GL_CULL_FACE);
466                         glEnable(GL_DEPTH_TEST);
467                 }
468                 if (do_light)
469                 {
470                         glEnable(GL_LIGHTING);
471                         glEnable(GL_FOG);
472                 }
473                 if (do_texture)
474                 {
475                         glEnable(GL_TEXTURE_2D);
476                 }
477                 glDisable(GL_BLEND);
478                 glColor4f(1, 1, 1, 1);
479         }
480 }
481 #endif