1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* atunnels --- OpenGL Advanced Tunnel Demo */
5 static const char sccsid[] = "@(#)tunnel_draw.c 5.13 2004/05/25 xlockmore";
8 /* Copyright (c) E. Lassauge, 2002-2004. */
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.
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.
23 * The original code for this mode was written by Roman Podobedov
25 * WEB: http://romka.demonews.com
27 * Eric Lassauge (May-25-2004) <lassauge@users.sourceforge.net>
28 * http://lassauge.free.fr/linux.html
31 * E.Lassauge - 25-May-2004:
32 * - added more texture
33 * - random texture init
41 #ifdef USE_GL /* whole file */
49 # include <OpenGL/gl.h>
50 # include <OpenGL/glu.h>
57 #include "tunnel_draw.h"
59 #ifdef STANDALONE /* For NRAND() */
60 #include "xlockmoreI.h" /* in xscreensaver distribution */
61 #else /* STANDALONE */
62 #include "xlock.h" /* in xlockmore distribution */
63 #endif /* STANDALONE */
67 float x, y, z; /* Point coordinates */
70 typedef struct _tnPath
77 static const cvPoint initpath[]={
78 {0.000000, 0.000000, 0.000000},
79 {2.000000, 1.000000, 0.000000},
80 {4.000000, 0.000000, 0.000000},
81 {6.000000, 1.000000, 0.000000},
82 {8.000000, 0.000000, 1.000000},
83 {10.000000, 1.000000, 1.000000},
84 {12.000000, 1.500000, 0.000000},
85 {14.000000, 0.000000, 0.000000},
86 {16.000000, 1.000000, 0.000000},
87 {18.000000, 0.000000, 0.000000},
88 {20.000000, 0.000000, 1.000000},
89 {22.000000, 1.000000, 0.000000},
90 {24.000000, 0.000000, 1.000000},
91 {26.000000, 0.000000, 1.000000},
92 {28.000000, 1.000000, 0.000000},
93 {30.000000, 0.000000, 2.000000},
94 {32.000000, 1.000000, 0.000000},
95 {34.000000, 0.000000, 2.000000},
96 {-1.000000, -1.000000, -1.000000}
100 struct tunnel_state {
104 float cam_t; /* Camera variables */
108 int tFlag; /* Tunnel Drawing Variables */
109 cvPoint prev_points[10];
112 float ModeX; /* Modes */
116 /*=================== Vector normalization ==================================*/
117 static void normalize(cvPoint *V)
122 d = (float)sqrt(V->x*V->x + V->y*V->y + V->z*V->z);
129 /*=================== C = A x B (Vector multiply) ==========================*/
131 static void vect_mult(cvPoint *A, cvPoint *B, cvPoint *C)
133 /* Vector multiply */
134 C->x = A->y*B->z - A->z*B->y;
135 C->y = A->z*B->x - A->x*B->z;
136 C->z = A->x*B->y - A->y*B->x;
140 /* Catmull-Rom Curve calculations */
141 static void cvCatmullRom(cvPoint *p, float t, cvPoint *outp)
149 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;
150 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;
151 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;
154 /*=================== Point Rotating Around Line ===========================
155 // p - original point
157 // pl - pivot line (vector)
158 // a - angle to rotate in radians
159 // outp - output point
160 //==========================================================================
162 static void RotateAroundLine(cvPoint *p, cvPoint *pp, cvPoint *pl, float a, cvPoint *outp)
165 float l, m, n, ca, sa;
178 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);
179 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);
180 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));
182 outp->x = p2.x + pp->x;
183 outp->y = p2.y + pp->y;
184 outp->z = p2.z + pp->z;
188 /*=================== Load camera and tunnel path ==========================*/
189 static void LoadPath(struct tunnel_state *st)
192 tnPath *path1=NULL, *path2=NULL;
194 cvPoint *f = (cvPoint *)initpath;
203 if (st->path == NULL)
205 st->path = (tnPath *)malloc(sizeof(tnPath));
210 if (!path1) path1 = st->path;
211 path2 = (tnPath *)malloc(sizeof(tnPath));
222 st->cam_pos = st->path;
226 /*=================== Tunnel Initialization ================================*/
227 struct tunnel_state *
230 struct tunnel_state *st = (struct tunnel_state *) calloc (1, sizeof(*st));
232 st->current_texture = NRAND(MAX_TEXTURE);
236 void DrawTunnel(struct tunnel_state *st,
237 int do_texture, int do_light, GLuint *textures)
239 tnPath *p, *p1, *cmpos;
240 cvPoint op, p4[4], T, ppp, ppp1, op1, op2;
244 GLfloat light_position[4];
247 /* Select current tunnel texture */
249 glBindTexture(GL_TEXTURE_2D, textures[st->current_texture]);
252 /* Get current curve */
253 if (st->cam_pos->next &&
254 st->cam_pos->next->next &&
255 st->cam_pos->next->next->next)
274 /* Get current camera position */
275 cvCatmullRom(p4, st->cam_t, &op);
277 /* Next camera position */
281 st->cam_t = st->cam_t - 1;
282 cmpos = st->cam_pos->next;
285 /* Get curve for next camera position */
286 if (cmpos->next->next->next)
305 /* Get next camera position */
306 cvCatmullRom(p4, st->cam_t, &op1);
309 glRotatef(st->alpha, 0, 0, -1);
311 /* Set camera position */
312 gluLookAt(op.x, op.y, op.z, op1.x, op1.y, op1.z, 0, 1, 0);
314 /* Set light position */
317 light_position[0] = op.x;
318 light_position[1] = op.y;
319 light_position[2] = op.z;
320 light_position[3] = 1;
321 glLightfv(GL_LIGHT0, GL_POSITION, light_position);
328 /* Draw tunnel from current curve and next 2 curves */
332 if (p->next->next->next)
350 cvCatmullRom(p4, t, &op);
364 if (p->next->next->next)
383 cvCatmullRom(p4, t, &op1);
387 ppp1.z = op1.z + 0.25;
397 RotateAroundLine(&ppp, &op, &T, ((float)i*36.0*M_PI/180.0), &op2);
403 st->prev_points[i].x = op2.x;
404 st->prev_points[i].y = op2.y;
405 st->prev_points[i].z = op2.z;
415 /* Draw 10 polygons for current point */
420 glNormal3f(0, 0, 1); /* Normal for lighting */
421 glTexCoord2f(0, 0); glVertex3f(st->prev_points[i].x, st->prev_points[i].y, st->prev_points[i].z);
423 glTexCoord2f(1, 0); glVertex3f(points[i].x, points[i].y, points[i].z);
425 glTexCoord2f(1, 1); glVertex3f(points[j].x, points[j].y, points[j].z);
427 glTexCoord2f(0, 1); glVertex3f(st->prev_points[j].x, st->prev_points[j].y, st->prev_points[j].z);
429 /* Save current polygon coordinates for next position */
432 st->prev_points[i].x = points[i].x;
433 st->prev_points[i].y = points[i].y;
434 st->prev_points[i].z = points[i].z;
441 /* =================== Show splash screen =================================== */
442 void SplashScreen(struct tunnel_state *st,
443 int do_wire, int do_texture, int do_light)
447 /* Reset tunnel and camera position */
450 st->cam_pos = st->path;
454 st->current_texture++;
455 if (st->current_texture >= MAX_TEXTURE) st->current_texture = 0;
457 /* Now we want to draw splash screen */
459 /* Disable all unused features */
460 glDisable(GL_DEPTH_TEST);
461 glDisable(GL_LIGHTING);
463 glDisable(GL_CULL_FACE);
465 glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
467 glDisable(GL_TEXTURE_2D);
468 glColor4f(1, 1, 1, st->ModeX);
470 /* Draw splash screen (simply quad) */
472 glVertex3f(-10, -10, -1);
473 glVertex3f(10, -10, -1);
474 glVertex3f(10, 10, -1);
475 glVertex3f(-10, 10, -1);
479 if (st->ModeX <= 0) st->ModeX = 0;
483 glEnable(GL_CULL_FACE);
484 glEnable(GL_DEPTH_TEST);
488 glEnable(GL_LIGHTING);
493 glEnable(GL_TEXTURE_2D);
496 glColor4f(1, 1, 1, 1);
500 void FreeTunnel(struct tunnel_state *st)