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