From http://www.jwz.org/xscreensaver/xscreensaver-5.38.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-2014 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 free_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   int y = 0;
356
357   if (width > height * 5) {   /* tiny window: show middle */
358     height = width * 9/16;
359     y = -height/2;
360     h = height / (GLfloat) width;
361   }
362
363   glViewport (0, y, (GLint) width, (GLint) height);
364
365   glMatrixMode(GL_PROJECTION);
366   glLoadIdentity();
367   gluPerspective (90.0, 1/h, 0.2, 50.0); 
368
369   glMatrixMode(GL_MODELVIEW);
370   glLoadIdentity();
371   gluLookAt( 0.0, 0.0, 0.3,
372              0.0, 0.0, 1.0,
373              0.0, 1.0, 0.0);
374
375   glClear(GL_COLOR_BUFFER_BIT);
376 }
377
378
379
380
381 ENTRYPOINT Bool
382 tunnel_handle_event (ModeInfo *mi, XEvent *event)
383 {
384   tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
385
386   if (gltrackball_event_handler (event, tc->trackball,
387                                  MI_WIDTH (mi), MI_HEIGHT (mi),
388                                  &tc->button_down_p))
389     return True;
390
391   return False;
392 }
393
394 static void setTexParams(void)
395 {
396         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
397         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
398         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
399         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
400         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
401 }
402
403 static void update_animation(tunnel_configuration *tc) {
404
405         /* time based, of course*/
406         /* shift texture based on elapsed time since previous call*/
407         struct timeval tv;
408         struct timezone tz;
409         int elapsed_usecs, elapsed_secs, i;
410         float computed_timeshift;
411
412         /* get new animation time */
413         gettimeofday(&tv, &tz);
414         elapsed_secs = tv.tv_sec - tc->time_oldsec;
415         elapsed_usecs = tv.tv_usec - tc->time_oldusec;
416         /* store current time */
417         tc->time_oldsec = tv.tv_sec ;
418         tc->time_oldusec = tv.tv_usec;
419         /* elaped time. computed timeshift is tenths of a second */
420         computed_timeshift = (float) (elapsed_secs * 1000000. + elapsed_usecs)/ 
421                                                       100000.0;
422
423         /* calibrate effect time to lie between start and end times */
424         /* loop if time exceeds end time */
425         if (reverse)
426                 tc->effect_time -= computed_timeshift / 10.0 * dilate;
427         else
428                 tc->effect_time += computed_timeshift / 10.0 * dilate;
429         if ( tc->effect_time >= tc->end_time)
430                 tc->effect_time = tc->start_time;
431         if ( tc->effect_time < tc->start_time)
432                 tc->effect_time = tc->end_time;;
433
434         /* move texture shifters in effect's direction, e.g. tardis
435            tunnel moves backward, effect 1's direction */
436          if (reverse) { 
437                 tc->texshift[0] -= tc->effects[1].direction * computed_timeshift/ 10.0; 
438                 tc->texshift[1] -= tc->effects[3].direction * computed_timeshift/ 10.0; 
439                 tc->texshift[2] -= tc->effects[6].direction * computed_timeshift/ 10.0; 
440
441         } else {
442                 tc->texshift[0] += tc->effects[1].direction * computed_timeshift/ 10.0; 
443                 tc->texshift[1] += tc->effects[3].direction * computed_timeshift/ 10.0; 
444                 tc->texshift[2] += tc->effects[6].direction * computed_timeshift/ 10.0; 
445         }
446
447         /* loop texture shifters if necessary */
448         for ( i = 0 ; i < tc->num_texshifts; i++) {
449                 if (tc->texshift[i] > 1.0)
450                         tc->texshift[i] -= (int) tc->texshift[i];
451                 if (tc->texshift[i]< -1.0)
452                         tc->texshift[i] -= (int) tc->texshift[i];
453         }
454
455         /* update effect data with current time. Uses linear interpolation */   
456         for ( i = 1 ; i <= tc->num_effects ; i++)
457                 update_knots(&tc->effects[i], tc->effect_time);
458
459 } /*update_animation*/
460
461 /* draw a textured(tex) quad at a certain depth (z), and certain alpha (alpha), 
462 with aspect ratio (aspect), and blending mode (blend_mode) of either adding
463 or subtracting.  if alpha is zero or less, nothing happens */
464 static void draw_sign(ModeInfo *mi, tunnel_configuration *tc, float z,  float alpha, float aspect,
465                 GLuint tex, int blend_mode)
466 {
467
468 #ifndef HAVE_JWZGLES
469         if (alpha > 0.0) {
470                 mi->polygon_count ++;
471                 /* glEnable(GL_BLEND); */
472                 glBlendColor(0.0, 0.0, 0.0, alpha);
473                 /*glBlendColor(0.0, 0.0, 0.0, 0.0); */
474                 if (blend_mode == 1) {
475                         glBlendFunc(GL_CONSTANT_ALPHA,
476                                     GL_ONE);
477                         glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
478                 } else if (blend_mode == 2) {
479                         glBlendFunc(GL_CONSTANT_ALPHA,
480                                     GL_ONE);
481                         glBlendEquation(GL_FUNC_ADD);
482                 } else {
483                         glBlendFunc(GL_CONSTANT_ALPHA,
484                                     GL_ONE_MINUS_CONSTANT_ALPHA);
485                         glBlendEquation(GL_FUNC_ADD);
486                 } /* blend mode switch */
487
488 #ifdef HAVE_GLBINDTEXTURE
489                 if (do_texture)
490                         glBindTexture(GL_TEXTURE_2D, tc->texture_binds[tex]);
491 #endif
492                 glBegin(GL_QUADS);
493                 glTexCoord2f(1.0, 0.0);
494                 glVertex3f(-1.0 , -1.0 * aspect , z);
495                 glTexCoord2f(1.0, 1.0);
496                 glVertex3f(-1.0 , 1.0 * aspect , z);
497                 glTexCoord2f(0.0, 1.0);
498                 glVertex3f(1.0 , 1.0 * aspect , z);
499                 glTexCoord2f(0.0, 0.0);
500                 glVertex3f(1.0 , -1.0 * aspect , z); 
501                 glEnd();
502                 if (blend_mode != 0) {
503                         glBlendFunc(GL_CONSTANT_ALPHA,
504                                     GL_ONE_MINUS_CONSTANT_ALPHA);
505                         glBlendEquation(GL_FUNC_ADD);
506                 }
507                 /* glDisable(GL_BLEND); */
508
509         }
510 #endif /* !HAVE_JWZGLES */
511 } /* draw sign */
512
513
514 /* draw a time tunnel.  used for both cylinder and diamond tunnels.
515    uses texture shifter (indexed by shiftnum) to simulate motion.
516    tunnel does not move, and is acutally a display list.  if alpha = 0, skip */
517 static void draw_cyl(ModeInfo *mi, tunnel_configuration *tc, float alpha, int texnum, int listnum, int shiftnum)
518 {
519 #ifndef HAVE_JWZGLES
520         if (alpha > 0.0) {
521                 if (listnum  ==  tc->diamondlist)
522                         mi->polygon_count += 4;
523                 if (listnum  ==  tc->cyllist)
524                         mi->polygon_count += 30;
525                 glMatrixMode(GL_TEXTURE);
526                 glLoadIdentity();
527                 glTranslatef(tc->texshift[shiftnum], 0.0, 0.0);
528                 glMatrixMode(GL_MODELVIEW);
529                 /* glEnable(GL_BLEND); */
530                 glBlendColor(0.0, 0.0, 0.0, alpha);
531                 glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
532         
533 #ifdef HAVE_GLBINDTEXTURE
534                 if (do_texture)
535                         glBindTexture(GL_TEXTURE_2D, tc->texture_binds[texnum]);
536 #endif
537                 glCallList(listnum);
538
539                 glMatrixMode(GL_TEXTURE);
540                 glLoadIdentity();
541                 glMatrixMode(GL_MODELVIEW); 
542                 /* glDisable(GL_BLEND); */
543         }
544 #endif /* HAVE_JWZGLES */
545 }
546
547
548 /* make tardis type tunnel.  Starts as walls and then
549 grows to outline of tardis.  percent is how complete
550 tardis outline is.  cap is to draw cap for nice fog effects */
551
552 static void make_wall_tunnel(ModeInfo *mi, tunnel_configuration *tc, float percent, float cap)
553 {
554         /* tardis is about 2x1, so wrap tex around, starting at the base*/
555         /* tex coords are:
556
557  _tl__tr_
558  |      |
559 l|      |r
560  |      |
561  -bl__br_  
562         that's br=bottom right, etc. ttr is top-top-right */
563
564         float   half_floor= 0.08333333333333333,
565                 full_wall = 0.33333333333333333;
566         float   br1,
567                 r0 , r1 ,
568                 tr0, tr1,
569                 tl0, tl1,
570                 l0 , l1 ,
571                 depth=0.3, zdepth=15.0;
572         /* zdepth is how far back tunnel goes */
573         /* depth is tex coord scale.  low number = fast texture shifting */
574
575         float textop, texbot;   
576         float height;
577
578         br1 = half_floor;
579         r0 = br1 ;
580         r1 = r0 + full_wall;
581         tr0 = r1;
582         tr1 = r1 + half_floor;
583         tl0 = tr1;
584         tl1 = tl0 + half_floor;
585         l0 = tr1;
586         l1 = l0 + full_wall;
587
588         glMatrixMode(GL_TEXTURE);
589         glLoadIdentity();
590         glRotatef(90.0, 0.0, 0.0, 1.0);
591         glTranslatef(tc->texshift[0], 0.0, 0.0);
592         glMatrixMode(GL_MODELVIEW);
593
594 #ifdef HAVE_GLBINDTEXTURE
595         if (do_texture)
596                 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[0]);
597 #endif
598         glColor3f(1.0, 1.0, 0.0);
599         if (cap > 0.0 && percent > 0.0 && drawlogo && do_fog) {
600                 mi->polygon_count += 6;
601                 glBegin(GL_TRIANGLE_FAN);
602                 glVertex3f(0.0, 0.0, zdepth);
603                 glVertex3f(-1.0, -2.0, zdepth);
604                 glVertex3f(1.0, -2.0, zdepth);
605                 glVertex3f(1.0, 2.0, zdepth);
606                 glVertex3f(0.2, 2.0, zdepth);
607                 glVertex3f(0.2, 2.2, zdepth);
608                 glVertex3f(-0.2, 2.2, zdepth);
609                 glVertex3f(-0.2, 2.0, zdepth);
610                 glVertex3f(-1.0, 2.0, zdepth);
611                 glVertex3f(-1.0, -2.0, zdepth);
612                 glEnd();
613         }
614         if (percent > ( full_wall * 2.0)) {
615                 glBegin(GL_QUADS);
616
617                 height = (percent  - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
618                 if (height > 1.0) height = 1.0;
619
620
621                 if ( height > 0.8) {
622                         mi->polygon_count += 2;
623                         if ( height > 0.90) {
624                                 mi->polygon_count += 2;
625                                 /* TTTR */
626                                 texbot = tr0;
627                                 textop = tr0 + half_floor * height;
628                                 glTexCoord2f(0.0, texbot);
629                                 glVertex3f(0.2, 2.2, 0.0);
630                 
631                                 glTexCoord2f(0.0, textop);
632                                 glVertex3f(2.0 - height * 2.0, 2.2, 0.0);
633                 
634                                 glTexCoord2f(depth, textop);
635                                 glVertex3f(2.0 - height * 2.0, 2.2, zdepth);
636         
637                                 glTexCoord2f(depth, texbot);
638                                 glVertex3f(0.2, 2.2, zdepth);
639         
640                                 /* TTTL */
641                                 texbot = tl1 - half_floor * height;
642                                 textop = tl1;
643                                 glTexCoord2f(0.0, texbot);
644                                 glVertex3f(-2.0 + height * 2.0, 2.2, 0.0);
645                 
646                                 glTexCoord2f(0.0, textop);
647                                 glVertex3f(-0.2, 2.2, 0.0);
648                 
649                                 glTexCoord2f(depth, textop);
650                                 glVertex3f(-0.2, 2.2, zdepth);
651                 
652                                 glTexCoord2f(depth, texbot);
653                                 glVertex3f(-2.0 + height * 2.0, 2.2, zdepth);
654                         }
655                         if (height > 0.90) height = 0.90;
656
657                         /* TTR */
658                         texbot = tr0;
659                         textop = tr0 + half_floor * height;
660                         glTexCoord2f(0.0, texbot);
661                         glVertex3f(0.2, 2.0, 0.0);
662         
663                         glTexCoord2f(0.0, textop);
664                         glVertex3f(0.2, 0.4 + height * 2.0, 0.0);
665         
666                         glTexCoord2f(depth, textop);
667                         glVertex3f(0.2, 0.4 + height * 2.0, zdepth);
668         
669                         glTexCoord2f(depth, texbot);
670                         glVertex3f(0.2, 2.0, zdepth);
671
672                         /* TTL */
673                         texbot = tl1 - half_floor * height;
674                         textop = tl1;
675                         glTexCoord2f(0.0, texbot);
676                         /*glVertex3f(-.2, 2.0 + (0.9 - height) * 2.0, 0.0); */
677                         glVertex3f(-.2,  0.4 + height * 2.0, 0.0);
678         
679                         glTexCoord2f(0.0, textop);
680                         glVertex3f(-.2, 2.0, 0.0);
681         
682                         glTexCoord2f(depth, textop);
683                         glVertex3f(-.2, 2.0, zdepth);
684         
685                         glTexCoord2f(depth, texbot);
686                         glVertex3f(-.2, 0.4 + height * 2.0, zdepth);
687                 }
688         
689                 height = (percent  - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
690                 if (height > 0.8) height = 0.8;
691
692
693                 mi->polygon_count += 2;
694                 /* TR */
695                 texbot = tr0;
696                 textop = tr0 + half_floor * height;
697                 glTexCoord2f(0.0, texbot);
698                 glVertex3f(1.0, 2.0, 0.0);
699
700                 glTexCoord2f(0.0, textop);
701                 glVertex3f(1.0 - height, 2.0, 0.0);
702
703                 glTexCoord2f(depth, textop);
704                 glVertex3f(1.0 - height, 2.0, zdepth);
705
706                 glTexCoord2f(depth, texbot);
707                 glVertex3f(1.0, 2.0, zdepth);
708
709                 /* TL */
710                 texbot = tl1 - half_floor * height;
711                 textop = tl1;
712                 glTexCoord2f(0.0, texbot);
713                 glVertex3f(-1.0 + height, 2.0, 0.0);
714
715                 glTexCoord2f(0.0, textop);
716                 glVertex3f(-1.0, 2.0, 0.0);
717
718                 glTexCoord2f(depth, textop);
719                 glVertex3f(-1.0, 2.0, zdepth);
720
721                 glTexCoord2f(depth, texbot);
722                 glVertex3f(-1.0 + height, 2.0, zdepth);
723
724                 height = (percent  - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
725
726                 if (height > 1.0) height = 1.0;
727
728
729                 mi->polygon_count += 2;
730                 /* BR */
731                 texbot = tr0;
732                 textop = tr0 + half_floor * height;
733                 glTexCoord2f(0.0, texbot);
734                 glVertex3f(1.0, -2.0, 0.0);
735
736                 glTexCoord2f(0.0, textop);
737                 glVertex3f(1.0 - height, -2.0, 0.0);
738
739                 glTexCoord2f(depth, textop);
740                 glVertex3f(1.0 - height, -2.0, zdepth);
741
742                 glTexCoord2f(depth, texbot);
743                 glVertex3f(1.0, -2.0, zdepth);
744
745                 /* BL */
746                 texbot = tl1 - half_floor * height;
747                 textop = tl1;
748                 glTexCoord2f(0.0, texbot);
749                 glVertex3f(-1.0 + height, -2.0, 0.0);
750
751                 glTexCoord2f(0.0, textop);
752                 glVertex3f(-1.0, -2.0, 0.0);
753
754                 glTexCoord2f(depth, textop);
755                 glVertex3f(-1.0, -2.0, zdepth);
756
757                 glTexCoord2f(depth, texbot);
758                 glVertex3f(-1.0 + height, -2.0, zdepth);
759
760                 
761                 glEnd();
762         }
763         
764         if (percent > 0.0) {
765                 mi->polygon_count += 2;
766                 glBegin(GL_QUADS);
767                 height = percent / ( full_wall * 2.0);
768                 if (height > 1.0) height = 1.0;
769                 textop = (l0 + l1) / 2.0 - full_wall * 0.5 * height;
770                 texbot = (l0 + l1) / 2.0 + full_wall * 0.5 * height;
771
772                 glTexCoord2f(0.0, textop);
773                 glVertex3f(-1.0, height * 2, 0.0);
774
775                 glTexCoord2f(0.0, texbot);
776                 glVertex3f(-1.0, -height * 2, 0.0);
777
778                 glTexCoord2f(depth, texbot);
779                 glVertex3f(-1.0, -height * 2, zdepth);
780
781                 glTexCoord2f(depth, textop);
782                 glVertex3f(-1.0, height * 2, zdepth);
783
784                 textop = (r0 + r1) / 2.0 - full_wall * 0.5 * height;
785                 texbot = (r0 + r1) / 2.0 + full_wall * 0.5 * height;
786
787                 glTexCoord2f(0.0, texbot);
788                 glVertex3f(1.0, height * 2, 0.0);
789
790                 glTexCoord2f(0.0, textop);
791                 glVertex3f(1.0, -height * 2, 0.0);
792
793                 glTexCoord2f(depth, textop);
794                 glVertex3f(1.0, -height * 2, zdepth);
795
796                 glTexCoord2f(depth, texbot);
797                 glVertex3f(1.0, height * 2, zdepth);
798                 glEnd();
799         }
800
801
802         glMatrixMode(GL_TEXTURE);
803         glLoadIdentity();
804         glMatrixMode(GL_MODELVIEW);
805 } /* make_wall_tunnel */
806
807 /* wraps an int to between min and max.
808    Kind of like the remainder when devided by (max - min).
809    Used to create torus mapping on square array */
810 static int wrapVal(int val, int min, int max)
811 {
812         int ret;
813
814         ret = val;
815         if (val >= max)
816                 ret = min + (val - max ) % (max - min);
817         if (val < min)
818                 ret = max - (min - val) % (max - min);
819         return(ret);
820 }
821
822 /*=================== Load Texture =========================================*/
823 /* ripped from atunnel.c,  Copyright (c) E. Lassauge, 2003-2004. */
824 /* modified like so by Sean Brennan:
825   take texture object for glbind
826   removed xlock stuff
827   Added filters:
828     blur color / alpha channel [3x3 box filter, done [blur] times
829     anegative : create b/w image from zero alpha. zero alpha gets bw_color,
830                 nonzero alpha gets 1.0 - bwcolor, then alpha flipped to 1-alpha.
831
832   Inputs: xpm structure, or filename of xmp image.  if filename == NULL, use structure.
833   Outputs: texture bound to texutre Id texbind.
834
835 */
836
837 static float mylog2(float x) { return ( log(x) / log(2));}
838
839 static void LoadTexture(ModeInfo * mi, char **fn, const char *filename, GLuint texbind, int blur, float bw_color, Bool anegative, Bool onealpha)
840 {
841         /* looping and temporary array index variables */
842         int ix, iy, bx, by, indx, indy, boxsize, cchan, tmpidx, dtaidx;
843
844         float boxdiv, tmpfa, blursum ;
845         unsigned char *tmpbuf, tmpa;
846         Bool rescale;
847
848
849         XImage *teximage;    /* Texture data */
850
851         rescale = False;
852
853         boxsize = 2;
854         boxdiv = 1.0 / ( boxsize * 2.0 + 1.0) / ( boxsize * 2.0 + 1.0);
855
856
857         if (filename) 
858                 teximage = xpm_file_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
859                          MI_COLORMAP(mi), filename);
860         else 
861                 teximage = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
862                          MI_COLORMAP(mi), fn);
863         if (teximage == NULL) {
864             fprintf(stderr, "%s: error reading the texture.\n", progname);
865             glDeleteTextures(1, &texbind);
866             do_texture = False;
867             exit(0);
868         }
869
870         /* check if image is 2^kumquat, where kumquat is an integer between 1 and 10. Recale to
871            nearest power of 2. */
872         tmpfa = mylog2((float) teximage->width);
873         bx = 2 << (int) (tmpfa -1);
874         if (bx != teximage->width) {
875                 rescale = True;
876                 if ((tmpfa - (int) tmpfa) >  0.5849)
877                         bx = bx * 2;
878         }
879         tmpfa = mylog2((float) teximage->height);
880         by = 2 << (int) (tmpfa - 1);
881         if (by != teximage->height) {
882                 rescale = True;
883                 if ((tmpfa - (int) tmpfa) >  0.5849)
884                         by = by * 2;
885         }
886
887         if (rescale) {
888 #ifndef HAVE_JWZGLES
889                 tmpbuf = calloc(bx * by * 4, sizeof(unsigned char));
890                 if (gluScaleImage(GL_RGBA, teximage->width, teximage->height, GL_UNSIGNED_BYTE, teximage->data,
891                                 bx, by, GL_UNSIGNED_BYTE, tmpbuf))
892                         check_gl_error("scale image");
893                 
894                 free(teximage->data);
895                 teximage->data = (char *) tmpbuf;
896                 teximage->width = bx;
897                 teximage->height= by;
898 #endif /* !HAVE_JWZGLES */
899         }
900         /* end rescale code */
901                 
902         if (anegative ) {
903                 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
904                         {
905                                 if (!teximage->data[ ix * 4 + 3]) {
906                                         teximage->data[ ix * 4 + 3]  = (unsigned char) 0xff;
907                                         tmpa = (unsigned char) (bw_color * 0xff);
908                                 } else  {
909                                         if (onealpha)
910                                                 teximage->data[ ix * 4 + 3]  = (unsigned char) 0xff;
911                                         else
912                                                 teximage->data[ ix * 4 + 3]  = (unsigned char)  0xff - 
913                                                                 teximage->data[ ix * 4 + 3];
914                                         tmpa = (unsigned char) ((1.0 - bw_color) * 0xff);
915                                 }
916                                 /* make texture uniform b/w color */
917                                 teximage->data[ ix * 4 + 0]  =
918                                         (unsigned char) ( tmpa);
919                                 teximage->data[ ix * 4 + 1]  =
920                                         (unsigned char) ( tmpa);
921                                 teximage->data[ ix * 4 + 2]  =
922                                         (unsigned char) ( tmpa);
923                                 /* negate alpha */
924                         }
925         }
926                 
927         if (blur > 0) {
928                 if (! anegative ) /* anegative alread b/w's the whole image */
929                         for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
930                                 if (!teximage->data[ ix * 4 + 3])
931                                 {
932                                         teximage->data[ ix * 4 + 0]  =
933                                                 (unsigned char) ( 255.0 * bw_color);
934                                         teximage->data[ ix * 4 + 1]  =
935                                                 (unsigned char) ( 255.0 * bw_color);
936                                         teximage->data[ ix * 4 + 2]  =
937                                                 (unsigned char) ( 255.0 * bw_color);
938                                 }
939                 ;
940                 tmpbuf = calloc(teximage->height * teximage->width * 4, sizeof(unsigned char)  )        ;
941                 while (blur--) {
942                         /* zero out tmp alpha buffer */
943                         for (iy = 0 ; iy <teximage->height * teximage->width * 4 ; iy++)
944                                 tmpbuf[iy] = 0;
945                         for (cchan = 0; cchan < 4 ; cchan++) {
946                                 for (iy = 0 ; iy < teximage->height ; iy++) {
947                                         for (ix = 0 ; ix < teximage->width ; ix++) {
948                                                 dtaidx = (teximage->width * iy + ix) * 4;
949                                                 tmpa =  teximage->data[dtaidx + cchan];
950                                                 tmpfa = (float) tmpa * boxdiv;
951                                                 /* box filter */
952                                                 for (by = -boxsize ; by <= boxsize; by++) {
953                                                         for (bx = -boxsize ; bx <= boxsize; bx++) {
954                                                                 indx = wrapVal(ix + bx, 0, teximage->width);
955                                                                 indy = wrapVal(iy + by, 0, teximage->height);
956                                                                 tmpidx = (teximage->width * indy + indx) * 4;
957                                                                 blursum = tmpfa;
958                                                                 tmpbuf[tmpidx + cchan] += (unsigned char) blursum;
959                                                         } /* for bx */
960                                                 } /* for by  */
961                                         } /* for ix  */
962                                 } /* for iy */
963                         } /* for cchan */
964                         /* copy back buffer */
965                         for (ix = 0 ; ix < teximage->height * teximage->width * 4; ix++)
966                                 teximage->data[ix] = tmpbuf[ix];
967                 } /*while blur */
968                 free(tmpbuf); /*tidy*/
969         } /* if blur */
970
971                         
972         
973
974         clear_gl_error();
975 #ifdef HAVE_GLBINDTEXTURE
976         glBindTexture(GL_TEXTURE_2D, texbind);
977         clear_gl_error(); /* WTF? sometimes "invalid op" from glBindTexture! */
978 #endif
979         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
980         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height,
981                         0, GL_RGBA, GL_UNSIGNED_BYTE, teximage->data);
982         check_gl_error("texture");
983         setTexParams(); 
984         XDestroyImage(teximage);
985 }
986
987 /* creates cylinder for time tunnel. sides, zmin, zmax, rad(ius) obvious.
988    stretch scales texture coords; makes tunnel go slower the larger it is.
989    not drawn, but put into display list. */
990 static void makecyl(int sides, float zmin, float zmax, float rad, float stretch) 
991 {
992         int i;
993         float theta;
994
995         /* cap */
996         if (do_fog) {
997                 glBegin(GL_TRIANGLE_FAN);
998                 glTexCoord2f(1.0, 0.0);
999                 glVertex3f(0.0 , 0.0 , zmax); 
1000                 for (i = 0 ; i <= sides; i++) {  
1001                         theta = 2.0 * M_PI * ((float) i / (float) sides);
1002                         glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1003                 }
1004                 glVertex3f(cos(0.0) * rad, sin(0.0) * rad, zmax);
1005                 glEnd(); 
1006         }
1007         
1008         glBegin(GL_QUAD_STRIP);
1009         for (i = 0 ; i <= sides; i++)
1010         {
1011                 if ( i != sides) {
1012                         theta = 2.0 * M_PI * ((float) i / (float) sides);
1013                         glTexCoord2f(0.0, 1.0 * (float) i / (float) sides); 
1014                         glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1015                         glTexCoord2f(stretch, 1.0 * (float) i / (float) sides); 
1016                         glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1017                 } else {
1018                         theta = 0.0;
1019                         glTexCoord2f(0.0, 1.0);
1020                         glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1021                         glTexCoord2f(stretch, 1.0);
1022                         glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1023                 }
1024         }
1025         glEnd();
1026 }
1027
1028 ENTRYPOINT void 
1029 init_tunnel (ModeInfo *mi)
1030 {
1031   int i;
1032
1033   tunnel_configuration *tc;
1034   
1035   wire = MI_IS_WIREFRAME(mi);
1036
1037 # ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
1038   wire = 0;
1039 # endif
1040
1041   MI_INIT (mi, tconf);
1042
1043   tc = &tconf[MI_SCREEN(mi)];
1044
1045   tc->glx_context = init_GL(mi);
1046
1047   tc->cyllist = glGenLists(1);
1048   tc->diamondlist = glGenLists(1);
1049   tc->num_effects = 12;
1050   tc->num_texshifts = 3;
1051   tc->effect_time = 0.0;
1052   tc->effect_maxsecs = 30.00;
1053   /* check bounds on cmd line opts */
1054   if (start > tc->effect_maxsecs) start = tc->effect_maxsecs;
1055   if (end > tc->effect_maxsecs) end = tc->effect_maxsecs;
1056   if (start < tc->effect_time) start = tc->effect_time;
1057   if (end < tc->effect_time) end = tc->effect_time;
1058
1059   /* set loop times, in seconds */
1060   tc->start_time = start;
1061   tc->end_time = end;
1062
1063   /* reset animation knots, effect 0 not defined. */
1064   tc->effects = malloc(sizeof(effect_t) * ( tc->num_effects + 1));
1065   for ( i = 1; i <= tc->num_effects ; i++)
1066         init_effects(&tc->effects[i], i);
1067
1068   if (wire) {
1069         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1070         do_texture = False;
1071   }
1072
1073   if (do_texture)
1074   {
1075           /* the following textures are loaded, and possible overridden:
1076                 tunnel 1, tunnel 2, tunnel 3, marquee, tardis, head */
1077           glGenTextures(MAX_TEXTURE, tc->texture_binds);
1078           
1079           /*LoadTexture(*mi, **fn, *filename, texbind, bluralpha, bw_color,  anegative, onealpha)*/
1080           if (strcasecmp (do_tun1, "(none)")) /* tunnel 1 */
1081                 LoadTexture(mi, NULL, do_tun1, tc->texture_binds[0],  0,0.0, False, False);
1082           else
1083                 LoadTexture(mi, timetunnel0_xpm, NULL, tc->texture_binds[0], 0, 0.0, False, False);
1084           if (strcasecmp (do_tun2, "(none)")) /* tunnel 2 */
1085                 LoadTexture(mi, NULL, do_tun2, tc->texture_binds[2],  0,0.0, False, False);
1086           else
1087                 LoadTexture(mi, timetunnel1_xpm, NULL, tc->texture_binds[2], 0, 0.0, False, False);
1088           if (strcasecmp (do_tun3, "(none)")) /* tunnel 3 */
1089                 LoadTexture(mi, NULL, do_tun3, tc->texture_binds[5],  0,0.0, False, False);
1090           else
1091                 LoadTexture(mi, timetunnel2_xpm, NULL, tc->texture_binds[5], 0, 0.0, False, False);
1092           LoadTexture(mi, tunnelstar_xpm, NULL, tc->texture_binds[4], 0, 0.0, False, False);
1093           if (strcasecmp (do_tx1, "(none)")) /* marquee */
1094                 LoadTexture(mi, NULL, do_tx1, tc->texture_binds[3],  0,0.0, False, False);
1095 #ifndef HAVE_JWZGLES  /* logo_180_xpm is 180px which is not a power of 2! */
1096           else
1097                 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[3],  0,0.0, False, False);
1098 #endif
1099           if (strcasecmp (do_tx2, "(none)")) /* tardis */
1100                 LoadTexture(mi, NULL, do_tx2, tc->texture_binds[1], 0, 0.0 ,False, False);
1101 #ifndef HAVE_JWZGLES  /* logo_180_xpm is 180px which is not a power of 2! */
1102           else
1103                 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[1],  0,0.0, False, False);
1104 #endif
1105           if (strcasecmp (do_tx3, "(none)")) { /* head */
1106                 LoadTexture(mi,  NULL, do_tx3, tc->texture_binds[6], 0, 0.0 ,False, False);
1107                 /* negative */
1108                 LoadTexture(mi,  NULL, do_tx3, tc->texture_binds[9],  2,1.0, True, True);
1109 #ifndef HAVE_JWZGLES  /* logo_180_xpm is 180px which is not a power of 2! */
1110           } else {
1111                 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[6],  0,0.0, False, False);
1112                 /* negative */
1113                 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[9],  2,1.0, True, True);
1114 #endif
1115           }
1116           glEnable(GL_TEXTURE_2D);
1117           check_gl_error("tex");
1118   }
1119
1120   reshape_tunnel (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1121
1122   glDisable(GL_DEPTH_TEST);  /* who needs it? ;-) */
1123
1124   if (do_fog)
1125         glEnable(GL_FOG);
1126
1127   if (!wire)
1128     {
1129       glEnable(GL_ALPHA_TEST);
1130       glAlphaFunc(GL_GREATER, 0.5);
1131     }
1132
1133     tc->trackball = gltrackball_init (True);
1134
1135
1136   tc->texshift = calloc(tc->num_texshifts, sizeof(GLfloat));
1137   for ( i = 0 ; i < tc->num_texshifts; i++)
1138         tc->texshift[i] = 0.0;
1139
1140   glNewList(tc->cyllist, GL_COMPILE);
1141   makecyl(30, -0.1, CYL_LEN, 1., 10. / 40.0 * CYL_LEN);  
1142   /*makecyl(30, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN); */
1143   glEndList();
1144
1145   glNewList(tc->diamondlist, GL_COMPILE);
1146   makecyl(4, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN);
1147   glEndList();
1148 }
1149
1150
1151 ENTRYPOINT void
1152 draw_tunnel (ModeInfo *mi)
1153 {
1154   tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
1155   Display *dpy = MI_DISPLAY(mi);
1156   Window window = MI_WINDOW(mi);
1157
1158
1159   if (!tc->glx_context)
1160     return;
1161
1162   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tc->glx_context));
1163
1164   glShadeModel(GL_SMOOTH);
1165
1166   glEnable(GL_NORMALIZE);
1167   /* glEnable(GL_CULL_FACE); */
1168
1169   glClear(GL_COLOR_BUFFER_BIT );
1170
1171   update_animation(tc);
1172
1173
1174   glPushMatrix ();
1175
1176         glRotatef(180., 0., 1., 0.);
1177     gltrackball_rotate (tc->trackball);
1178         glRotatef(180., 0., 1., 0.);
1179
1180
1181
1182   mi->polygon_count = 0;
1183
1184   update_fog(tc->effects[4].state[0],  /*color*/
1185              tc->effects[4].state[1],  /*density*/
1186              tc->effects[4].state[2],  /*start*/
1187              tc->effects[4].state[3]); /*end*/
1188
1189   /* --- begin composite image assembly --- */
1190
1191   /* head mask and draw diamond tunnel */
1192
1193   glEnable(GL_BLEND);
1194   draw_cyl(mi, tc, tc->effects[6].state[0], 5, tc->diamondlist, 2); 
1195   if (drawlogo)
1196         draw_sign(mi, tc,tc->effects[12].state[0], tc->effects[12].state[1],  1.0 / 1.33, 9, 1); 
1197   glDisable(GL_BLEND);
1198   /* then tardis tunnel */
1199   make_wall_tunnel(mi, tc, tc->effects[1].state[0], tc->effects[7].state[0]);
1200
1201   /* then cylinder tunnel */
1202   glEnable(GL_BLEND);
1203   draw_cyl(mi, tc, tc->effects[3].state[0], 2, tc->cyllist, 1); 
1204
1205        /*void draw_sign(mi, tc,z,alpha,aspect,tex,blendmode)*/
1206   /* tardis */
1207   if (drawlogo)
1208         draw_sign(mi, tc, tc->effects[2].state[0], tc->effects[2].state[1], 2.0, 1, 0);
1209   /* marquee */
1210   if (drawlogo)
1211         draw_sign(mi, tc, tc->effects[5].state[0], tc->effects[5].state[1], 1.0, 3, 0);
1212   /*who head brite*/
1213   if (drawlogo)
1214         draw_sign(mi, tc,1.0, tc->effects[10].state[0],  1.0 / 1.33, 6, 2);
1215   /*who head psychadelic REMOVED*/
1216   /* draw_sign(mi, tc,1.0, tc->effects[11].state[0],  1.0 / 1.33, 8, 0); */
1217
1218   /* star */
1219   /* draw_sign(mi, tc, tc->effects[8].state[0]tc->effects[8].state[0], 1.0 , 1.0, 4, 1); */
1220   draw_sign(mi, tc,  tc->effects[8].state[0],  tc->effects[8].state[0],  1.0, 4, 1);
1221  
1222   /* normal head */
1223   if (drawlogo)
1224         draw_sign(mi, tc,1.0, tc->effects[9].state[0], 1.0 /  1.33, 6, 0);
1225
1226   /* --- end composite image assembly --- */
1227
1228
1229   glPopMatrix ();
1230
1231   if (mi->fps_p) do_fps (mi);
1232   glFinish();
1233
1234   check_gl_error("drawing done, calling swap buffers");
1235   glXSwapBuffers(dpy, window);
1236 }
1237
1238 XSCREENSAVER_MODULE_2 ("TimeTunnel", timetunnel, tunnel)
1239
1240 #endif /* USE_GL */