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