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