http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.05.tar.gz
[xscreensaver] / hacks / glx / timetunnel.c
1 /* timetunnel. Based on dangerball.c, hack by Sean Brennan <zettix@yahoo.com>*/
2 /* dangerball, Copyright (c) 2001-2004 Jamie Zawinski <jwz@jwz.org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13 #include <math.h> /* for log2 */
14
15 #define DEFAULTS        "*delay:        30000       \n" \
16                         "*count:        30          \n" \
17                         "*showFPS:      False       \n" \
18                         "*timeStart:     0.0       \n" \
19                         "*timeEnd:       27.79       \n" \
20                         "*wireframe:    False       \n" \
21
22
23
24 # define refresh_tunnel 0
25 # define release_tunnel 0
26 #undef countof
27 #define countof(x) (sizeof((x))/sizeof((*x)))
28
29 #include "xlockmore.h"
30 #include "colors.h"
31 #include "rotator.h"
32 #include "gltrackball.h"
33
34
35 #define DEF_START       "0.00"
36 #define DEF_DILATE      "1.00"
37 #define DEF_END         "27.79"
38 #define DEF_LOCKLOGO    "False"
39 #define DEF_DRAWLOGO    "True"
40 #define DEF_REVERSE     "False"
41 #define DEF_FOG         "True"
42 #define DEF_TEXTURE     "True"
43 #define MAX_TEXTURE 10
44 #define CYL_LEN         14.0
45 #define DIAMOND_LEN     10.0
46
47 static float start, end, dilate;
48 static Bool do_texture, drawlogo, wire, reverse, do_fog;
49 #ifdef GET_SUED_BY_THE_BBC
50 static Bool locklogo;
51 #endif
52
53 static XrmOptionDescRec opts[] = {
54   {"-texture"   , ".texture",   XrmoptionNoArg, "true" },
55   {"-start"     , ".start",     XrmoptionSepArg, 0 },
56   {"-end"       , ".end",       XrmoptionSepArg, 0 },
57   {"-dilate"    , ".dilate",   XrmoptionSepArg, 0 },
58 #ifdef GET_SUED_BY_THE_BBC
59   {"-locklogo"  , ".locklogo",  XrmoptionNoArg, "true" },
60 #endif
61   {"-logo"      , ".drawlogo",   XrmoptionNoArg, "true" },
62   {"+logo"      , ".drawlogo",   XrmoptionNoArg, "false" },
63   {"-reverse"   , ".reverse",   XrmoptionNoArg, "true" },
64   {"-fog"       , ".fog",       XrmoptionNoArg, "false" },
65 };
66
67 static argtype vars[] = {
68   {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
69   {&start, "start", "Start", DEF_START, t_Float},
70   {&end,     "end",   "End", DEF_END  , t_Float},
71   {&dilate,     "dilate",   "Dilate", DEF_DILATE  , t_Float},
72 #ifdef GET_SUED_BY_THE_BBC
73   {&locklogo,     "locklogo",   "LockLogo", DEF_LOCKLOGO  , t_Bool},
74 #endif
75   {&drawlogo,     "drawlogo",   "DrawLogo", DEF_DRAWLOGO  , t_Bool},
76   {&reverse,     "reverse",   "Reverse", DEF_REVERSE  , t_Bool},
77   {&do_fog,     "fog",   "Fog", DEF_FOG  , t_Bool},
78 };
79
80 ENTRYPOINT ModeSpecOpt tunnel_opts = {countof(opts), opts, countof(vars), vars, NULL};
81 #include "xpm-ximage.h"
82 #include "images/logo-180.xpm"
83 #include "images/tunnelstar.xpm"
84 #include "images/timetunnel0.xpm"
85 #include "images/timetunnel1.xpm"
86 #include "images/timetunnel2.xpm"
87 #ifdef GET_SUED_BY_THE_BBC
88 # include "images/tardis.xpm"
89 # include "images/whologo.xpm"
90 # include "images/whohead1.xpm"
91 /* #include "images/whohead_psy.xpm" */
92 # endif /* GET_SUED_BY_THE_BBC */
93
94
95 #ifdef USE_GL /* whole file */
96
97 /* ANIMATION CONTROLS */
98 /* an effect is a collection of floating point variables that vary with time.
99 A knot is a timestamp with an array of floats.  State is the current values of the floats.
100 State is set by linearly interpolating between knots */
101 typedef struct {
102         float *knots, *state;
103         int numknots, knotwidth;
104         float direction;
105 } effect_t;
106
107 typedef struct {
108   GLXContext *glx_context;
109   rotator *rot;
110   trackball_state *trackball;
111   Bool button_down_p;
112
113   int time_oldusec, time_oldsec;
114
115   int num_texshifts; /* animates tunnels. Not an effect. */
116   GLfloat pos, *texshift;
117
118   GLuint texture_binds[MAX_TEXTURE], cyllist, diamondlist;
119
120   float effect_time, effect_maxsecs; /* global time controls */
121   float start_time, end_time;
122
123   int num_effects;
124   effect_t *effects; /* array of all effects */
125
126 } tunnel_configuration;
127
128 static tunnel_configuration *tconf = NULL;
129
130 /* allocate memory and populate effect with knot data */
131 static void init_effect(effect_t *e, int numk, int kwidth, 
132         float dir, float *data ) 
133 {
134         int i, j;
135
136         e->numknots = numk;     
137         e->knotwidth = kwidth;  
138         e->direction = dir;
139         e->knots = calloc(numk * kwidth, sizeof(float));
140         e->state = calloc(numk, sizeof(float));
141         for ( i = 0 ; i < e->numknots ; i++)
142                 for ( j = 0 ; j < e->knotwidth; j++)
143                         e->knots[i * kwidth + j] = data[i * kwidth + j];
144 }
145
146 /* static knot data. each effect is listed and knot data is hard coded. 
147    Knots are linerally interpolated to yield float values, depending on
148    knot width.  knot format is [time, data, data, data...].
149    Data can be alpha, zvalue, etc. */
150 static void init_effects(effect_t *e, int effectnum)
151 {
152         /* effect 1: wall tunnel. percent closed */
153         float e1d[6][2] = 
154                 {{0.0, 0.055}, 
155                  {2.77, 0.055}, 
156                  {3.07,1.0}, 
157                  {8.08, 1.0},
158                  {8.08, 0.0}, 
159                  {10.0, 0.0}};
160         /* effect 2: tardis. distance and alpha */
161         float e2d[8][3] = 
162         {       {0.0, 0.0 , 0.0}, 
163                 {3.44, 0.0 , 0.0},
164                 {3.36, 5.4 , 0.0},
165                 {4.24, 3.66, 1.0},
166                 {6.51, 2.4,  0.94},
167                 {8.08, 0.75 , 0.0}, 
168                 {8.08, 0.0 , 0.0},
169                 {10.0, 0.0, 0.0}};
170         /* effect 3: cylender. alpha  */
171         float e3d[5][2] = 
172                 {{0.0, 0.0}, 
173                  {6.41, 0.00},
174                  {8.08, 1.0}, 
175                  {14.81, 1.0},
176                  {15.65, 0.0}};
177
178         /* effect 4: fog. color, density,  start, end  */
179         float e4d[9][5] = 
180                 {{0.0 , 1.0, 0.45, 3.0, 15.0},
181                  {6.40, 1.0, 0.45, 3.0, 14.0},
182                  {8.08, 1.0, 0.95, 1.0, 14.0},
183                  {15.17, 1.0, 0.95, 1.0, 6.0},
184                  {15.51, 1.0, 0.95, 3.0, 8.0},
185                  {23.35, 1.0, 0.95, 3.0, 8.0},
186                  {24.02, 0.0, 0.95, 2.3, 5.0},
187                  {26.02, 0.0, 0.95, 2.3, 5.0},
188                  {27.72, 0.0, 1.00, 0.3, 0.9}
189                  };
190
191         /* effect 5: logo. dist, alpha  */
192         float e5d[7][3] = 
193                 {{0.0, 0.0, 0.0}, 
194                 {16.52, 0.00, 0.0}, 
195                 {16.52, 0.80, 0.01}, 
196                 {17.18, 1.15, 1.0}, 
197                 {22.36, 5.3, 1.0}, 
198                 {22.69, 5.7, 0.0},
199                 {22.69, 0.0, 0.0}
200                 };
201         /* effect 6: diamond tunnel. alpha */
202         float e6d[3][2] = 
203                 {{0.0, 0.00}, 
204                 {15.17, 0.00},
205                 {15.51,1.0}};
206
207         /* effect 7: tardis cap draw . positive draws cap*/
208         float e7d[3][2] = 
209                 {{0.0, -1.00}, 
210                 {4.24, -1.00},
211                 {4.24, 1.00}};
212
213         /* effect 8: star/asterisk: alpha */
214         float e8d[5][2] = 
215                 {{0.0,    .00}, 
216                 {10.77,   .00},
217                 {11.48,  1.00},
218                 {15.35,  1.00},
219                 {16.12,  0.00}};
220
221         /* effect 9: whohead 1  alpha */
222         float e9d[5][2] = 
223                 {{0.0,    .00}, 
224                 {13.35,   .00},
225                 {14.48,  1.00},
226                 {15.17,  1.00},
227                 {15.97,  0.00}};
228                 /* {14.87,  1.00},
229                 {15.17,  0.00}}; */
230
231         /* effect 10: whohead-brite  alpha */
232         float e10d[5][2] = 
233                 {{0.0,    .00}, 
234                 {11.34,   .00},
235                 {12.34,   .20},
236                 {13.35,  0.60},
237                 {14.48,  0.00}}; 
238                 /* {13.95,  0.00}}; */
239
240         /* effect 11: whohead-psy  alpha */
241         float e11d[5][2] = 
242                 {{0.0,    .00}, 
243                 {14.87,   .00},
244                 {15.17,  1.00},
245                 {15.91,  0.00},
246                 {16.12,  0.00}};
247
248         /* effect 12: whohead-silhouette pos-z,  alpha */
249         float e12d[6][3] = 
250                 {{0.0,   1.0,  .00}, 
251                 {15.07,  1.0, 0.00},
252                 {15.07,  1.0, 1.00},
253                 {16.01,  1.0, 1.00},
254                 {16.78,  0.5, 1.00},
255                 {16.78,  0.1, 0.00} };
256
257         /* effect 1: wall tunnel */
258         if (effectnum == 1)
259                 init_effect(e, 6, 2,  -0.2, (float *) e1d);
260
261         /* effect 2: tardisl */
262         if (effectnum == 2)
263                 init_effect(e, 8, 3, 1.0,  (float *) e2d);
264
265         /* effect 3: cylender tunnel  */
266         if (effectnum == 3)
267                 init_effect(e, 5, 2, 0.889  ,  (float *) e3d);
268
269         /* effect 4: fog color */
270         if (effectnum == 4)
271                 init_effect(e, 9, 5, 1.0,  (float *) e4d);
272         /* effect 5: logo distance, alpha*/
273         if (effectnum == 5)
274                 init_effect(e, 7, 3, 1.0,  (float *) e5d);
275         /* effect 6: diamond tunnel, alpha*/
276         if (effectnum == 6)
277                 init_effect(e, 3, 2, 0.24 ,  (float *) e6d);
278
279         /* effect 7: cap wall tunnel*/
280         if (effectnum == 7)
281                 init_effect(e, 3, 2, 1.0,  (float *) e7d);
282
283         /* effect 8: asterisk */
284         if (effectnum == 8)
285                 init_effect(e, 5, 2, 1.0,  (float *) e8d);
286
287         /* effect 9, 10, 11, 12: whoheads */
288         if (effectnum == 9 )
289                 init_effect(e, 5, 2, 1.0,  (float *) e9d);
290         if (effectnum == 10 )
291                 init_effect(e, 5, 2, 1.0,  (float *) e10d);
292         if (effectnum == 11 )
293                 init_effect(e, 5, 2, 1.0,  (float *) e11d);
294         if (effectnum == 12 )
295                 init_effect(e, 6, 3, 1.0,  (float *) e12d);
296 }
297
298
299 /* set fog parameters, controlled by effect */
300 static void update_fog(float color, float density, float start, float end) 
301 {
302                 GLfloat col[4];
303         
304                 col[0] = col[1] = col[2] = color;
305                 col[3] = 1.0;
306
307                 glFogi(GL_FOG_MODE, GL_LINEAR);
308                 glFogfv(GL_FOG_COLOR, col);
309                 glFogf(GL_FOG_DENSITY, density);
310                 glFogf(GL_FOG_START, start);
311                 glFogf(GL_FOG_END, end);
312 }
313
314 /* set effect's floating point data values by linearally interpolating
315 between two knots whose times bound the current time: eff_time */
316
317 static void update_knots(effect_t *e, float eff_time) 
318 {
319         int i, j;
320         float timedelta, lowknot, highknot, *curknot, *nextknot;
321
322         for ( i = 0 ; i < e->numknots ; i++)
323                 if (e->knots[i * e->knotwidth] <= eff_time) {
324                         if ( i < e->numknots - 1) 
325                                 nextknot = e->knots + (i + 1) * e->knotwidth;
326                         else
327                                 /*repeat last knot to carry knot data forward*/
328                                 nextknot = e->knots + (i) * e->knotwidth;
329                         curknot = e->knots + i * e->knotwidth;
330                         if (*nextknot - *curknot <= 0.0) timedelta = 1.0;
331                         else
332                                 timedelta = (eff_time-*curknot)/(*nextknot-*curknot);
333                         if (timedelta > 1.0) timedelta = 1.0;
334                         for (j = 1 ; j < e->knotwidth ; j++) {
335                                 highknot = (float) *(nextknot + j);
336                                 lowknot  = (float) *(curknot  + j);
337                                 e->state[j - 1 ] = lowknot+(highknot-lowknot)*timedelta;
338                         }
339                 }
340         
341 }
342
343
344 /* Window management, etc
345  */
346 ENTRYPOINT void
347 reshape_tunnel (ModeInfo *mi, int width, int height)
348 {
349   GLfloat h = (GLfloat) height / (GLfloat) width;
350
351   glViewport (0, 0, (GLint) width, (GLint) height);
352
353   glMatrixMode(GL_PROJECTION);
354   glLoadIdentity();
355   gluPerspective (90.0, 1/h, 0.2, 50.0); 
356
357   glMatrixMode(GL_MODELVIEW);
358   glLoadIdentity();
359   gluLookAt( 0.0, 0.0, 0.3,
360              0.0, 0.0, 1.0,
361              0.0, 1.0, 0.0);
362
363   glClear(GL_COLOR_BUFFER_BIT);
364 }
365
366
367
368
369 ENTRYPOINT Bool
370 tunnel_handle_event (ModeInfo *mi, XEvent *event)
371 {
372   tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
373
374   if (event->xany.type == ButtonPress &&
375       event->xbutton.button == Button1)
376     {
377       tc->button_down_p = True;
378       gltrackball_start (tc->trackball,
379                          event->xbutton.x, event->xbutton.y,
380                          MI_WIDTH (mi), MI_HEIGHT (mi));
381       return True;
382     }
383   else if (event->xany.type == ButtonRelease &&
384            event->xbutton.button == Button1)
385     {
386       tc->button_down_p = False;
387       return True;
388     }
389   else if (event->xany.type == ButtonPress &&
390            (event->xbutton.button == Button4 ||
391             event->xbutton.button == Button5 ||
392             event->xbutton.button == Button6 ||
393             event->xbutton.button == Button7))
394     {
395       gltrackball_mousewheel (tc->trackball, event->xbutton.button, 10,
396                               !!event->xbutton.state);
397       return True;
398     }
399   else if (event->xany.type == MotionNotify &&
400            tc->button_down_p)
401     {
402       gltrackball_track (tc->trackball,
403                          event->xmotion.x, event->xmotion.y,
404                          MI_WIDTH (mi), MI_HEIGHT (mi));
405       return True;
406     }
407
408   return False;
409 }
410
411 static void setTexParams(void)
412 {
413         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
414         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
415         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
416         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
417         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
418 }
419
420 static void update_animation(tunnel_configuration *tc) {
421
422         /* time based, of course*/
423         /* shift texture based on elapsed time since previous call*/
424         struct timeval tv;
425         struct timezone tz;
426         int elapsed_usecs, elapsed_secs, i;
427         float computed_timeshift;
428
429         /* get new animation time */
430         gettimeofday(&tv, &tz);
431         elapsed_secs = tv.tv_sec - tc->time_oldsec;
432         elapsed_usecs = tv.tv_usec - tc->time_oldusec;
433         /* store current time */
434         tc->time_oldsec = tv.tv_sec ;
435         tc->time_oldusec = tv.tv_usec;
436         /* elaped time. computed timeshift is tenths of a second */
437         computed_timeshift = (float) (elapsed_secs * 1000000. + elapsed_usecs)/ 
438                                                       100000.0;
439
440         /* calibrate effect time to lie between start and end times */
441         /* loop if time exceeds end time */
442         if (reverse)
443                 tc->effect_time -= computed_timeshift / 10.0 * dilate;
444         else
445                 tc->effect_time += computed_timeshift / 10.0 * dilate;
446         if ( tc->effect_time >= tc->end_time)
447                 tc->effect_time = tc->start_time;
448         if ( tc->effect_time < tc->start_time)
449                 tc->effect_time = tc->end_time;;
450
451         /* move texture shifters in effect's direction, e.g. tardis
452            tunnel moves backward, effect 1's direction */
453          if (reverse) { 
454                 tc->texshift[0] -= tc->effects[1].direction * computed_timeshift/ 10.0; 
455                 tc->texshift[1] -= tc->effects[3].direction * computed_timeshift/ 10.0; 
456                 tc->texshift[2] -= tc->effects[6].direction * computed_timeshift/ 10.0; 
457
458         } else {
459                 tc->texshift[0] += tc->effects[1].direction * computed_timeshift/ 10.0; 
460                 tc->texshift[1] += tc->effects[3].direction * computed_timeshift/ 10.0; 
461                 tc->texshift[2] += tc->effects[6].direction * computed_timeshift/ 10.0; 
462         }
463
464         /* loop texture shifters if necessary */
465         for ( i = 0 ; i < tc->num_texshifts; i++) {
466                 if (tc->texshift[i] > 1.0)
467                         tc->texshift[i] -= (int) tc->texshift[i];
468                 if (tc->texshift[i]< -1.0)
469                         tc->texshift[i] -= (int) tc->texshift[i];
470         }
471
472         /* update effect data with current time. Uses linear interpolation */   
473         for ( i = 1 ; i <= tc->num_effects ; i++)
474                 update_knots(&tc->effects[i], tc->effect_time);
475
476 } /*update_animation*/
477
478 /* draw a textured(tex) quad at a certain depth (z), and certain alpha (alpha), 
479 with aspect ratio (aspect), and blending mode (blend_mode) of either adding
480 or subtracting.  if alpha is zero or less, nothing happens */
481 static void draw_sign(ModeInfo *mi, tunnel_configuration *tc, float z,  float alpha, float aspect,
482                 GLuint tex, int blend_mode)
483 {
484
485         if (alpha > 0.0) {
486                 mi->polygon_count ++;
487                 /* glEnable(GL_BLEND); */
488                 glBlendColor(0.0, 0.0, 0.0, alpha);
489                 /*glBlendColor(0.0, 0.0, 0.0, 0.0); */
490                 if (blend_mode == 1) {
491                         glBlendFunc(GL_CONSTANT_ALPHA,
492                                     GL_ONE);
493                         glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
494                 } else if (blend_mode == 2) {
495                         glBlendFunc(GL_CONSTANT_ALPHA,
496                                     GL_ONE);
497                         glBlendEquation(GL_FUNC_ADD);
498                 } else {
499                         glBlendFunc(GL_CONSTANT_ALPHA,
500                                     GL_ONE_MINUS_CONSTANT_ALPHA);
501                         glBlendEquation(GL_FUNC_ADD);
502                 } /* blend mode switch */
503
504 #ifdef HAVE_GLBINDTEXTURE
505                 if (do_texture)
506                         glBindTexture(GL_TEXTURE_2D, tc->texture_binds[tex]);
507 #endif
508                 glBegin(GL_QUADS);
509                 glTexCoord2f(1.0, 0.0);
510                 glVertex3f(-1.0 , -1.0 * aspect , z);
511                 glTexCoord2f(1.0, 1.0);
512                 glVertex3f(-1.0 , 1.0 * aspect , z);
513                 glTexCoord2f(0.0, 1.0);
514                 glVertex3f(1.0 , 1.0 * aspect , z);
515                 glTexCoord2f(0.0, 0.0);
516                 glVertex3f(1.0 , -1.0 * aspect , z); 
517                 glEnd();
518                 if (blend_mode != 0) {
519                         glBlendFunc(GL_CONSTANT_ALPHA,
520                                     GL_ONE_MINUS_CONSTANT_ALPHA);
521                         glBlendEquation(GL_FUNC_ADD);
522                 }
523                 /* glDisable(GL_BLEND); */
524
525         }
526 } /* draw sign */
527
528
529 /* draw a time tunnel.  used for both cylender and diamond tunnels.
530    uses texture shifter (indexed by shiftnum) to simulate motion.
531    tunnel does not move, and is acutally a display list.  if alpha = 0, skip */
532 static void draw_cyl(ModeInfo *mi, tunnel_configuration *tc, float alpha, int texnum, int listnum, int shiftnum)
533 {
534         if (alpha > 0.0) {
535                 if (listnum  ==  tc->diamondlist)
536                         mi->polygon_count += 4;
537                 if (listnum  ==  tc->cyllist)
538                         mi->polygon_count += 30;
539                 glMatrixMode(GL_TEXTURE);
540                 glLoadIdentity();
541                 glTranslatef(tc->texshift[shiftnum], 0.0, 0.0);
542                 glMatrixMode(GL_MODELVIEW);
543                 /* glEnable(GL_BLEND); */
544                 glBlendColor(0.0, 0.0, 0.0, alpha);
545                 glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
546         
547 #ifdef HAVE_GLBINDTEXTURE
548                 if (do_texture)
549                         glBindTexture(GL_TEXTURE_2D, tc->texture_binds[texnum]);
550 #endif
551                 glCallList(listnum);
552
553                 glMatrixMode(GL_TEXTURE);
554                 glLoadIdentity();
555                 glMatrixMode(GL_MODELVIEW); 
556                 /* glDisable(GL_BLEND); */
557         }
558 }
559
560
561 /* make tardis type tunnel.  Starts as walls and then
562 grows to outline of tardis.  percent is how complete
563 tardis outline is.  cap is to draw cap for nice fog effects */
564
565 static void make_wall_tunnel(ModeInfo *mi, tunnel_configuration *tc, float percent, float cap)
566 {
567         /* tardis is about 2x1, so wrap tex around, starting at the base*/
568         /* tex coords are:
569
570  _tl__tr_
571  |      |
572 l|      |r
573  |      |
574  -bl__br_  
575         that's br=bottom right, etc. ttr is top-top-right */
576
577         float   half_floor= 0.08333333333333333,
578                 full_wall = 0.33333333333333333;
579         float   br1,
580                 r0 , r1 ,
581                 tr0, tr1,
582                 tl0, tl1,
583                 l0 , l1 ,
584                 bl0, depth=0.3, zdepth=15.0;
585         /* zdepth is how far back tunnel goes */
586         /* depth is tex coord scale.  low number = fast texture shifting */
587
588         float textop, texbot;   
589         float height;
590
591         br1 = half_floor;
592         r0 = br1 ;
593         r1 = r0 + full_wall;
594         tr0 = r1;
595         tr1 = r1 + half_floor;
596         tl0 = tr1;
597         tl1 = tl0 + half_floor;
598         l0 = tr1;
599         l1 = l0 + full_wall;
600         bl0 = l1;
601
602         glMatrixMode(GL_TEXTURE);
603         glLoadIdentity();
604         glRotatef(90.0, 0.0, 0.0, 1.0);
605         glTranslatef(tc->texshift[0], 0.0, 0.0);
606         glMatrixMode(GL_MODELVIEW);
607
608 #ifdef HAVE_GLBINDTEXTURE
609         if (do_texture)
610                 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[0]);
611 #endif
612         glColor3f(1.0, 1.0, 0.0);
613         if (cap > 0.0 && percent > 0.0 && drawlogo && do_fog) {
614                 mi->polygon_count += 6;
615                 glBegin(GL_TRIANGLE_FAN);
616                 glVertex3f(0.0, 0.0, zdepth);
617                 glVertex3f(-1.0, -2.0, zdepth);
618                 glVertex3f(1.0, -2.0, zdepth);
619                 glVertex3f(1.0, 2.0, zdepth);
620                 glVertex3f(0.2, 2.0, zdepth);
621                 glVertex3f(0.2, 2.2, zdepth);
622                 glVertex3f(-0.2, 2.2, zdepth);
623                 glVertex3f(-0.2, 2.0, zdepth);
624                 glVertex3f(-1.0, 2.0, zdepth);
625                 glVertex3f(-1.0, -2.0, zdepth);
626                 glEnd();
627         }
628         if (percent > ( full_wall * 2.0)) {
629                 glBegin(GL_QUADS);
630
631                 height = (percent  - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
632                 if (height > 1.0) height = 1.0;
633
634
635                 if ( height > 0.8) {
636                         mi->polygon_count += 2;
637                         if ( height > 0.90) {
638                                 mi->polygon_count += 2;
639                                 /* TTTR */
640                                 texbot = tr0;
641                                 textop = tr0 + half_floor * height;
642                                 glTexCoord2f(0.0, texbot);
643                                 glVertex3f(0.2, 2.2, 0.0);
644                 
645                                 glTexCoord2f(0.0, textop);
646                                 glVertex3f(2.0 - height * 2.0, 2.2, 0.0);
647                 
648                                 glTexCoord2f(depth, textop);
649                                 glVertex3f(2.0 - height * 2.0, 2.2, zdepth);
650         
651                                 glTexCoord2f(depth, texbot);
652                                 glVertex3f(0.2, 2.2, zdepth);
653         
654                                 /* TTTL */
655                                 texbot = tl1 - half_floor * height;
656                                 textop = tl1;
657                                 glTexCoord2f(0.0, texbot);
658                                 glVertex3f(-2.0 + height * 2.0, 2.2, 0.0);
659                 
660                                 glTexCoord2f(0.0, textop);
661                                 glVertex3f(-0.2, 2.2, 0.0);
662                 
663                                 glTexCoord2f(depth, textop);
664                                 glVertex3f(-0.2, 2.2, zdepth);
665                 
666                                 glTexCoord2f(depth, texbot);
667                                 glVertex3f(-2.0 + height * 2.0, 2.2, zdepth);
668                         }
669                         if (height > 0.90) height = 0.90;
670
671                         /* TTR */
672                         texbot = tr0;
673                         textop = tr0 + half_floor * height;
674                         glTexCoord2f(0.0, texbot);
675                         glVertex3f(0.2, 2.0, 0.0);
676         
677                         glTexCoord2f(0.0, textop);
678                         glVertex3f(0.2, 0.4 + height * 2.0, 0.0);
679         
680                         glTexCoord2f(depth, textop);
681                         glVertex3f(0.2, 0.4 + height * 2.0, zdepth);
682         
683                         glTexCoord2f(depth, texbot);
684                         glVertex3f(0.2, 2.0, zdepth);
685
686                         /* TTL */
687                         texbot = tl1 - half_floor * height;
688                         textop = tl1;
689                         glTexCoord2f(0.0, texbot);
690                         /*glVertex3f(-.2, 2.0 + (0.9 - height) * 2.0, 0.0); */
691                         glVertex3f(-.2,  0.4 + height * 2.0, 0.0);
692         
693                         glTexCoord2f(0.0, textop);
694                         glVertex3f(-.2, 2.0, 0.0);
695         
696                         glTexCoord2f(depth, textop);
697                         glVertex3f(-.2, 2.0, zdepth);
698         
699                         glTexCoord2f(depth, texbot);
700                         glVertex3f(-.2, 0.4 + height * 2.0, zdepth);
701                 }
702         
703                 height = (percent  - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
704                 if (height > 0.8) height = 0.8;
705
706
707                 mi->polygon_count += 2;
708                 /* TR */
709                 texbot = tr0;
710                 textop = tr0 + half_floor * height;
711                 glTexCoord2f(0.0, texbot);
712                 glVertex3f(1.0, 2.0, 0.0);
713
714                 glTexCoord2f(0.0, textop);
715                 glVertex3f(1.0 - height, 2.0, 0.0);
716
717                 glTexCoord2f(depth, textop);
718                 glVertex3f(1.0 - height, 2.0, zdepth);
719
720                 glTexCoord2f(depth, texbot);
721                 glVertex3f(1.0, 2.0, zdepth);
722
723                 /* TL */
724                 texbot = tl1 - half_floor * height;
725                 textop = tl1;
726                 glTexCoord2f(0.0, texbot);
727                 glVertex3f(-1.0 + height, 2.0, 0.0);
728
729                 glTexCoord2f(0.0, textop);
730                 glVertex3f(-1.0, 2.0, 0.0);
731
732                 glTexCoord2f(depth, textop);
733                 glVertex3f(-1.0, 2.0, zdepth);
734
735                 glTexCoord2f(depth, texbot);
736                 glVertex3f(-1.0 + height, 2.0, zdepth);
737
738                 height = (percent  - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
739
740                 if (height > 1.0) height = 1.0;
741
742
743                 mi->polygon_count += 2;
744                 /* BR */
745                 texbot = tr0;
746                 textop = tr0 + half_floor * height;
747                 glTexCoord2f(0.0, texbot);
748                 glVertex3f(1.0, -2.0, 0.0);
749
750                 glTexCoord2f(0.0, textop);
751                 glVertex3f(1.0 - height, -2.0, 0.0);
752
753                 glTexCoord2f(depth, textop);
754                 glVertex3f(1.0 - height, -2.0, zdepth);
755
756                 glTexCoord2f(depth, texbot);
757                 glVertex3f(1.0, -2.0, zdepth);
758
759                 /* BL */
760                 texbot = tl1 - half_floor * height;
761                 textop = tl1;
762                 glTexCoord2f(0.0, texbot);
763                 glVertex3f(-1.0 + height, -2.0, 0.0);
764
765                 glTexCoord2f(0.0, textop);
766                 glVertex3f(-1.0, -2.0, 0.0);
767
768                 glTexCoord2f(depth, textop);
769                 glVertex3f(-1.0, -2.0, zdepth);
770
771                 glTexCoord2f(depth, texbot);
772                 glVertex3f(-1.0 + height, -2.0, zdepth);
773
774                 
775                 glEnd();
776         }
777         
778         if (percent > 0.0) {
779                 mi->polygon_count += 2;
780                 glBegin(GL_QUADS);
781                 height = percent / ( full_wall * 2.0);
782                 if (height > 1.0) height = 1.0;
783                 textop = (l0 + l1) / 2.0 - full_wall * 0.5 * height;
784                 texbot = (l0 + l1) / 2.0 + full_wall * 0.5 * height;
785
786                 glTexCoord2f(0.0, textop);
787                 glVertex3f(-1.0, height * 2, 0.0);
788
789                 glTexCoord2f(0.0, texbot);
790                 glVertex3f(-1.0, -height * 2, 0.0);
791
792                 glTexCoord2f(depth, texbot);
793                 glVertex3f(-1.0, -height * 2, zdepth);
794
795                 glTexCoord2f(depth, textop);
796                 glVertex3f(-1.0, height * 2, zdepth);
797
798                 textop = (r0 + r1) / 2.0 - full_wall * 0.5 * height;
799                 texbot = (r0 + r1) / 2.0 + full_wall * 0.5 * height;
800
801                 glTexCoord2f(0.0, texbot);
802                 glVertex3f(1.0, height * 2, 0.0);
803
804                 glTexCoord2f(0.0, textop);
805                 glVertex3f(1.0, -height * 2, 0.0);
806
807                 glTexCoord2f(depth, textop);
808                 glVertex3f(1.0, -height * 2, zdepth);
809
810                 glTexCoord2f(depth, texbot);
811                 glVertex3f(1.0, height * 2, zdepth);
812                 glEnd();
813         }
814
815
816         glMatrixMode(GL_TEXTURE);
817         glLoadIdentity();
818         glMatrixMode(GL_MODELVIEW);
819 } /* make_wall_tunnel */
820
821 /* wraps an int to between min and max.
822    Kind of like the remainder when devided by (max - min).
823    Used to create torus mapping on square array */
824 static int wrapVal(int val, int min, int max)
825 {
826         int ret;
827
828         ret = val;
829         if (val >= max)
830                 ret = min + (val - max ) % (max - min);
831         if (val < min)
832                 ret = max - (min - val) % (max - min);
833         return(ret);
834 }
835
836 /*=================== Load Texture =========================================*/
837 /* ripped from atunnel.c,  Copyright (c) E. Lassauge, 2003-2004. */
838 /* modified like so by Sean Brennan:
839   take texture object for glbind
840   removed xlock stuff
841   Added filters:
842     blur color / alpha channel [3x3 box filter, done [blur] times
843     anegative : create b/w image from zero alpha. zero alpha gets bw_color,
844                 nonzero alpha gets 1.0 - bwcolor, then alpha flipped to 1-alpha.
845
846 */
847
848 static float mylog2(float x) { return ( log(x) / log(2));}
849
850 static void LoadTexture(ModeInfo * mi, char **fn, GLuint texbind, int blur, float bw_color, Bool anegative, Bool onealpha)
851 {
852         /* looping and temporary array index variables */
853         int ix, iy, bx, by, indx, indy, boxsize, cchan, tmpidx, dtaidx;
854
855         float boxdiv, tmpfa, blursum ;
856         unsigned char *tmpbuf, tmpa;
857         Bool rescale;
858
859
860         XImage *teximage;    /* Texture data */
861
862         rescale = False;
863
864         boxsize = 2;
865         boxdiv = 1.0 / ( boxsize * 2.0 + 1.0) / ( boxsize * 2.0 + 1.0);
866
867         if ((teximage = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
868                          MI_COLORMAP(mi), fn)) == None) {
869             fprintf(stderr, "%s: error reading the texture.\n", progname);
870             glDeleteTextures(1, &texbind);
871             do_texture = False;
872             exit(0);
873         }
874
875         /* check if image is 2^kumquat, where kumquat is an integer between 1 and 10. Recale to
876            nearest power of 2. */
877         tmpfa = mylog2((float) teximage->width);
878         bx = 2 << (int) (tmpfa -1);
879         if (bx != teximage->width) {
880                 rescale = True;
881                 if ((tmpfa - (int) tmpfa) >  0.5849)
882                         bx = bx * 2;
883         }
884         tmpfa = mylog2((float) teximage->height);
885         by = 2 << (int) (tmpfa - 1);
886         if (by != teximage->height) {
887                 rescale = True;
888                 if ((tmpfa - (int) tmpfa) >  0.5849)
889                         by = by * 2;
890         }
891
892         if (rescale) {
893                 tmpbuf = calloc(bx * by * 4, sizeof(unsigned char));
894                 if (gluScaleImage(GL_RGBA, teximage->width, teximage->height, GL_UNSIGNED_BYTE, teximage->data,
895                                 bx, by, GL_UNSIGNED_BYTE, tmpbuf))
896                         check_gl_error("scale image");
897                 
898                 free(teximage->data);
899                 teximage->data = (char *) tmpbuf;
900                 teximage->width = bx;
901                 teximage->height= by;
902         }
903         /* end rescale code */
904                 
905         if (anegative ) {
906                 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
907                         {
908                                 if (!teximage->data[ ix * 4 + 3]) {
909                                         teximage->data[ ix * 4 + 3]  = (unsigned char) 0xff;
910                                         tmpa = (unsigned char) (bw_color * 0xff);
911                                 } else  {
912                                         if (onealpha)
913                                                 teximage->data[ ix * 4 + 3]  = (unsigned char) 0xff;
914                                         else
915                                                 teximage->data[ ix * 4 + 3]  = (unsigned char)  0xff - 
916                                                                 teximage->data[ ix * 4 + 3];
917                                         tmpa = (unsigned char) ((1.0 - bw_color) * 0xff);
918                                 }
919                                 /* make texture uniform b/w color */
920                                 teximage->data[ ix * 4 + 0]  =
921                                         (unsigned char) ( tmpa);
922                                 teximage->data[ ix * 4 + 1]  =
923                                         (unsigned char) ( tmpa);
924                                 teximage->data[ ix * 4 + 2]  =
925                                         (unsigned char) ( tmpa);
926                                 /* negate alpha */
927                         }
928         }
929                 
930         if (blur > 0) {
931                 if (! anegative ) /* anegative alread b/w's the whole image */
932                         for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
933                                 if (!teximage->data[ ix * 4 + 3])
934                                 {
935                                         teximage->data[ ix * 4 + 0]  =
936                                                 (unsigned char) ( 255.0 * bw_color);
937                                         teximage->data[ ix * 4 + 1]  =
938                                                 (unsigned char) ( 255.0 * bw_color);
939                                         teximage->data[ ix * 4 + 2]  =
940                                                 (unsigned char) ( 255.0 * bw_color);
941                                 }
942                 ;
943                 tmpbuf = calloc(teximage->height * teximage->width * 4, sizeof(unsigned char)  )        ;
944                 while (blur--) {
945                         /* zero out tmp alpha buffer */
946                         for (iy = 0 ; iy <teximage->height * teximage->width * 4 ; iy++)
947                                 tmpbuf[iy] = 0;
948                         for (cchan = 0; cchan < 4 ; cchan++) {
949                                 for (iy = 0 ; iy < teximage->height ; iy++) {
950                                         for (ix = 0 ; ix < teximage->width ; ix++) {
951                                                 dtaidx = (teximage->width * iy + ix) * 4;
952                                                 tmpa =  teximage->data[dtaidx + cchan];
953                                                 tmpfa = (float) tmpa * boxdiv;
954                                                 /* box filter */
955                                                 blursum = 0.0;
956                                                 for (by = -boxsize ; by <= boxsize; by++) {
957                                                         for (bx = -boxsize ; bx <= boxsize; bx++) {
958                                                                 indx = wrapVal(ix + bx, 0, teximage->width);
959                                                                 indy = wrapVal(iy + by, 0, teximage->height);
960                                                                 tmpidx = (teximage->width * indy + indx) * 4;
961                                                                 blursum = tmpfa;
962                                                                 tmpbuf[tmpidx + cchan] += (unsigned char) blursum;
963                                                         } /* for bx */
964                                                 } /* for by  */
965                                         } /* for ix  */
966                                 } /* for iy */
967                         } /* for cchan */
968                         /* copy back buffer */
969                         for (ix = 0 ; ix < teximage->height * teximage->width * 4; ix++)
970                                 teximage->data[ix] = tmpbuf[ix];
971                 } /*while blur */
972                 free(tmpbuf); /*tidy*/
973         } /* if blur */
974
975                         
976         
977
978         clear_gl_error();
979 #ifdef HAVE_GLBINDTEXTURE
980         glBindTexture(GL_TEXTURE_2D, texbind);
981 #endif
982         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
983         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height,
984                         0, GL_RGBA, GL_UNSIGNED_BYTE, teximage->data);
985         check_gl_error("texture");
986         setTexParams(); 
987         XDestroyImage(teximage);
988 }
989
990 /* creates cylender for time tunnel. sides, zmin, zmax, rad(ius) obvious.
991    stretch scales texture coords; makes tunnel go slower the larger it is.
992    not drawn, but put into display list. */
993 static void makecyl(int sides, float zmin, float zmax, float rad, float stretch) 
994 {
995         int i;
996         float theta;
997
998         /* cap */
999         if (do_fog) {
1000                 glBegin(GL_TRIANGLE_FAN);
1001                 glTexCoord2f(1.0, 0.0);
1002                 glVertex3f(0.0 , 0.0 , zmax); 
1003                 for (i = 0 ; i <= sides; i++) {  
1004                         theta = 2.0 * M_PI * ((float) i / (float) sides);
1005                         glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1006                 }
1007                 glVertex3f(cos(0.0) * rad, sin(0.0) * rad, zmax);
1008                 glEnd(); 
1009         }
1010         
1011         glBegin(GL_QUAD_STRIP);
1012         for (i = 0 ; i <= sides; i++)
1013         {
1014                 if ( i != sides) {
1015                         theta = 2.0 * M_PI * ((float) i / (float) sides);
1016                         glTexCoord2f(0.0, 1.0 * (float) i / (float) sides); 
1017                         glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1018                         glTexCoord2f(stretch, 1.0 * (float) i / (float) sides); 
1019                         glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1020                 } else {
1021                         theta = 0.0;
1022                         glTexCoord2f(0.0, 1.0);
1023                         glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1024                         glTexCoord2f(stretch, 1.0);
1025                         glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1026                 }
1027         }
1028         glEnd();
1029 }
1030
1031 ENTRYPOINT void 
1032 init_tunnel (ModeInfo *mi)
1033 {
1034   int i;
1035
1036   tunnel_configuration *tc;
1037   
1038   wire = MI_IS_WIREFRAME(mi);
1039
1040   if (!tconf) {
1041     tconf = (tunnel_configuration *)
1042       calloc (MI_NUM_SCREENS(mi), sizeof (tunnel_configuration));
1043     if (!tconf) {
1044       fprintf(stderr, "%s: out of memory\n", progname);
1045       exit(1);
1046     }
1047
1048     tc = &tconf[MI_SCREEN(mi)];
1049   }
1050
1051   tc = &tconf[MI_SCREEN(mi)];
1052
1053   tc->glx_context = init_GL(mi);
1054
1055   tc->cyllist = glGenLists(1);
1056   tc->diamondlist = glGenLists(1);
1057   tc->num_effects = 12;
1058   tc->num_texshifts = 3;
1059   tc->effect_time = 0.0;
1060   tc->effect_maxsecs = 30.00;
1061   /* check bounds on cmd line opts */
1062   if (start > tc->effect_maxsecs) start = tc->effect_maxsecs;
1063   if (end > tc->effect_maxsecs) end = tc->effect_maxsecs;
1064   if (start < tc->effect_time) start = tc->effect_time;
1065   if (end < tc->effect_time) end = tc->effect_time;
1066
1067   /* set loop times, in seconds */
1068   tc->start_time = start;
1069   tc->end_time = end;
1070
1071   /* reset animation knots, effect 0 not defined. */
1072   tc->effects = malloc(sizeof(effect_t) * ( tc->num_effects + 1));
1073   for ( i = 1; i <= tc->num_effects ; i++)
1074         init_effects(&tc->effects[i], i);
1075
1076   if (wire) {
1077         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1078         do_texture = False;
1079   }
1080
1081   if (do_texture)
1082   {
1083           glGenTextures(MAX_TEXTURE, tc->texture_binds);
1084           
1085           /*LoadTexture(*mi, **fn, texbind, bluralpha, bw_color,  anegative, onealpha)*/
1086           LoadTexture(mi, timetunnel0_xpm, tc->texture_binds[0], 0, 0.0, False, False);
1087           LoadTexture(mi, timetunnel1_xpm, tc->texture_binds[2], 0, 0.0, False, False);
1088           LoadTexture(mi, timetunnel2_xpm, tc->texture_binds[5], 0, 0.0, False, False);
1089           LoadTexture(mi, tunnelstar_xpm, tc->texture_binds[4], 0, 0.0, False, False);
1090 # ifdef GET_SUED_BY_THE_BBC
1091           if (locklogo) {
1092 # endif /* GET_SUED_BY_THE_BBC */
1093                 LoadTexture(mi, (char **) logo_180_xpm, tc->texture_binds[3],  0,0.0, False, False);
1094                 tc->texture_binds[1] = tc->texture_binds[3];
1095                 tc->texture_binds[6] = tc->texture_binds[3];
1096                 tc->texture_binds[8] = tc->texture_binds[3];
1097                 /* negative */
1098                 LoadTexture(mi, (char **) logo_180_xpm, tc->texture_binds[9],  2,1.0, True, True);
1099 # ifdef GET_SUED_BY_THE_BBC
1100          } else {
1101                 LoadTexture(mi, whologo_xpm, tc->texture_binds[3],  0,0.0, False, False);
1102                 LoadTexture(mi, tardis_xpm, tc->texture_binds[1], 0, 0.0 ,False, False);
1103                 LoadTexture(mi, whohead1_xpm, tc->texture_binds[6], 0, 1.0, False, False);
1104                 /* LoadTexture(mi, whohead_psy_xpm, tc->texture_binds[8], 1, 0.7, False, False); */
1105                 /* negative */
1106                 LoadTexture(mi, whohead1_xpm, tc->texture_binds[9], 2, 1.0, True, True);
1107           }
1108 # endif /* GET_SUED_BY_THE_BBC */
1109           glEnable(GL_TEXTURE_2D);
1110           check_gl_error("tex");
1111   }
1112
1113   reshape_tunnel (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1114
1115   glDisable(GL_DEPTH_TEST);  /* who needs it? ;-) */
1116
1117   if (do_fog)
1118         glEnable(GL_FOG);
1119
1120   if (!wire)
1121     {
1122       glEnable(GL_ALPHA_TEST);
1123       glAlphaFunc(GL_GREATER, 0.5);
1124     }
1125
1126     tc->trackball = gltrackball_init ();
1127
1128
1129   tc->texshift = calloc(tc->num_texshifts, sizeof(GLfloat));
1130   for ( i = 0 ; i < tc->num_texshifts; i++)
1131         tc->texshift[i] = 0.0;
1132
1133   glNewList(tc->cyllist, GL_COMPILE);
1134   makecyl(30, -0.1, CYL_LEN, 1., 10. / 40.0 * CYL_LEN);  
1135   /*makecyl(30, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN); */
1136   glEndList();
1137
1138   glNewList(tc->diamondlist, GL_COMPILE);
1139   makecyl(4, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN);
1140   glEndList();
1141 }
1142
1143
1144 ENTRYPOINT void
1145 draw_tunnel (ModeInfo *mi)
1146 {
1147   tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
1148   Display *dpy = MI_DISPLAY(mi);
1149   Window window = MI_WINDOW(mi);
1150
1151
1152   if (!tc->glx_context)
1153     return;
1154
1155   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tc->glx_context));
1156
1157   glShadeModel(GL_SMOOTH);
1158
1159   glEnable(GL_NORMALIZE);
1160   /* glEnable(GL_CULL_FACE); */
1161
1162   glClear(GL_COLOR_BUFFER_BIT );
1163
1164   update_animation(tc);
1165
1166
1167   glPushMatrix ();
1168
1169         glRotatef(180., 0., 1., 0.);
1170     gltrackball_rotate (tc->trackball);
1171         glRotatef(180., 0., 1., 0.);
1172
1173
1174
1175   mi->polygon_count = 0;
1176
1177   update_fog(tc->effects[4].state[0],  /*color*/
1178              tc->effects[4].state[1],  /*density*/
1179              tc->effects[4].state[2],  /*start*/
1180              tc->effects[4].state[3]); /*end*/
1181
1182   /* --- begin composite image assembly --- */
1183
1184   /* head mask and draw diamond tunnel */
1185
1186   glEnable(GL_BLEND);
1187   draw_cyl(mi, tc, tc->effects[6].state[0], 5, tc->diamondlist, 2); 
1188   if (drawlogo)
1189         draw_sign(mi, tc,tc->effects[12].state[0], tc->effects[12].state[1],  1.0 / 1.33, 9, 1); 
1190   glDisable(GL_BLEND);
1191   /* then tardis tunnel */
1192   make_wall_tunnel(mi, tc, tc->effects[1].state[0], tc->effects[7].state[0]);
1193
1194   /* then cylender tunnel */
1195   glEnable(GL_BLEND);
1196   draw_cyl(mi, tc, tc->effects[3].state[0], 2, tc->cyllist, 1); 
1197
1198        /*void draw_sign(mi, tc,z,alpha,aspect,tex,blendmode)*/
1199   /* tardis */
1200   if (drawlogo)
1201         draw_sign(mi, tc, tc->effects[2].state[0], tc->effects[2].state[1], 2.0, 1, 0);
1202   /* logo */
1203   if (drawlogo)
1204         draw_sign(mi, tc, tc->effects[5].state[0], tc->effects[5].state[1], 1.0, 3, 0);
1205   /*who head brite*/
1206   if (drawlogo)
1207         draw_sign(mi, tc,1.0, tc->effects[10].state[0],  1.0 / 1.33, 6, 2);
1208   /*who head psychadelic REMOVED*/
1209   /* draw_sign(mi, tc,1.0, tc->effects[11].state[0],  1.0 / 1.33, 8, 0); */
1210
1211   /* star */
1212   /* draw_sign(mi, tc, tc->effects[8].state[0]tc->effects[8].state[0], 1.0 , 1.0, 4, 1); */
1213   draw_sign(mi, tc,  tc->effects[8].state[0],  tc->effects[8].state[0],  1.0, 4, 1);
1214  
1215   /* normal head */
1216   if (drawlogo)
1217         draw_sign(mi, tc,1.0, tc->effects[9].state[0], 1.0 /  1.33, 6, 0);
1218
1219   /* --- end composite image assembly --- */
1220
1221
1222   glPopMatrix ();
1223
1224   if (mi->fps_p) do_fps (mi);
1225   glFinish();
1226
1227   check_gl_error("drawing done, calling swap buffers");
1228   glXSwapBuffers(dpy, window);
1229 }
1230
1231 XSCREENSAVER_MODULE_2 ("TimeTunnel", timetunnel, tunnel)
1232
1233 #endif /* USE_GL */