1 /* timetunnel. Based on dangerball.c, hack by Sean Brennan <zettix@yahoo.com>*/
2 /* dangerball, Copyright (c) 2001-2004 Jamie Zawinski <jwz@jwz.org>
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
13 #include <X11/Intrinsic.h>
14 #include <math.h> /* for log2 */
16 extern XtAppContext app;
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
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
36 #define DIAMOND_LEN 10.0
38 #define DEFAULTS "*delay: 30000 \n" \
40 "*showFPS: False \n" \
41 "*timeStart: 0.0 \n" \
42 "*timeEnd: 27.79 \n" \
43 "*wireframe: False \n" \
48 #define countof(x) (sizeof((x))/sizeof((*x)))
50 #include "xlockmore.h"
53 #include "gltrackball.h"
55 #include <sys/time.h> /* for time based animations */
57 static float start, end, dilate;
58 static Bool do_texture, tunonly, wire, reverse, do_fog;
59 #ifdef GET_SUED_BY_THE_BBC
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" },
71 {"-tunonly" , ".tunonly", XrmoptionNoArg, "true" },
72 {"-reverse" , ".reverse", XrmoptionNoArg, "true" },
73 {"-fog" , ".fog", XrmoptionNoArg, "false" },
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},
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},
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 */
104 #ifdef USE_GL /* whole file */
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 */
113 float *knots, *state;
114 int numknots, knotwidth;
119 GLXContext *glx_context;
121 trackball_state *trackball;
124 int time_oldusec, time_oldsec;
126 int num_texshifts; /* animates tunnels. Not an effect. */
127 GLfloat pos, *texshift;
129 GLuint texture_binds[MAX_TEXTURE], cyllist, diamondlist;
131 float effect_time, effect_maxsecs; /* global time controls */
132 float start_time, end_time;
135 effect_t *effects; /* array of all effects */
137 } tunnel_configuration;
139 static tunnel_configuration *tconf = NULL;
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 ) {
147 e->knotwidth = kwidth;
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];
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)
162 /* effect 1: wall tunnel. percent closed */
170 /* effect 2: tardis. distance and alpha */
180 /* effect 3: cylender. alpha */
188 /* effect 4: fog. color, density, start, end */
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}
201 /* effect 5: logo. dist, alpha */
211 /* effect 6: diamond tunnel. alpha */
217 /* effect 7: tardis cap draw . positive draws cap*/
223 /* effect 8: star/asterisk: alpha */
231 /* effect 9: whohead 1 alpha */
241 /* effect 10: whohead-brite alpha */
248 /* {13.95, 0.00}}; */
250 /* effect 11: whohead-psy alpha */
258 /* effect 12: whohead-silhouette pos-z, alpha */
265 {16.78, 0.1, 0.00} };
267 /* effect 1: wall tunnel */
269 init_effect(e, 6, 2, -0.2, (float *) e1d);
271 /* effect 2: tardisl */
273 init_effect(e, 8, 3, 1.0, (float *) e2d);
275 /* effect 3: cylender tunnel */
277 init_effect(e, 5, 2, 0.889 , (float *) e3d);
279 /* effect 4: fog color */
281 init_effect(e, 9, 5, 1.0, (float *) e4d);
282 /* effect 5: logo distance, alpha*/
284 init_effect(e, 7, 3, 1.0, (float *) e5d);
285 /* effect 6: diamond tunnel, alpha*/
287 init_effect(e, 3, 2, 0.24 , (float *) e6d);
289 /* effect 7: cap wall tunnel*/
291 init_effect(e, 3, 2, 1.0, (float *) e7d);
293 /* effect 8: asterisk */
295 init_effect(e, 5, 2, 1.0, (float *) e8d);
297 /* effect 9, 10, 11, 12: whoheads */
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);
309 /* set fog parameters, controlled by effect */
310 void update_fog(float color, float density, float start, float end) {
313 col[0] = col[1] = col[2] = color;
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);
323 /* set effect's floating point data values by linearally interpolating
324 between two knots whose times bound the current time: eff_time */
326 void update_knots(effect_t *e, float eff_time) {
328 float timedelta, lowknot, highknot, *curknot, *nextknot;
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;
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;
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;
352 /* Window management, etc
355 reshape_tunnel (ModeInfo *mi, int width, int height)
357 GLfloat h = (GLfloat) height / (GLfloat) width;
359 glViewport (0, 0, (GLint) width, (GLint) height);
361 glMatrixMode(GL_PROJECTION);
363 gluPerspective (90.0, 1/h, 0.2, 50.0);
365 glMatrixMode(GL_MODELVIEW);
367 gluLookAt( 0.0, 0.0, 0.3,
371 glClear(GL_COLOR_BUFFER_BIT);
378 tunnel_handle_event (ModeInfo *mi, XEvent *event)
380 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
382 if (event->xany.type == ButtonPress &&
383 event->xbutton.button == Button1)
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));
391 else if (event->xany.type == ButtonRelease &&
392 event->xbutton.button == Button1)
394 tc->button_down_p = False;
397 else if (event->xany.type == ButtonPress &&
398 (event->xbutton.button == Button4 ||
399 event->xbutton.button == Button5))
401 gltrackball_mousewheel (tc->trackball, event->xbutton.button, 10,
402 !!event->xbutton.state);
405 else if (event->xany.type == MotionNotify &&
408 gltrackball_track (tc->trackball,
409 event->xmotion.x, event->xmotion.y,
410 MI_WIDTH (mi), MI_HEIGHT (mi));
417 void setTexParams(void)
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);
426 void update_animation(tunnel_configuration *tc) {
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;
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)/
446 /* calibrate effect time to lie between start and end times */
447 /* loop if time exceeds end time */
449 tc->effect_time -= computed_timeshift / 10.0 * dilate;
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;;
457 /* move texture shifters in effect's direction, e.g. tardis
458 tunnel moves backward, effect 1's direction */
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;
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;
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];
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);
482 } /*update_animation*/
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)
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,
499 glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
500 } else if (blend_mode == 2) {
501 glBlendFunc(GL_CONSTANT_ALPHA,
503 glBlendEquation(GL_FUNC_ADD);
505 glBlendFunc(GL_CONSTANT_ALPHA,
506 GL_ONE_MINUS_CONSTANT_ALPHA);
507 glBlendEquation(GL_FUNC_ADD);
508 } /* blend mode switch */
510 #ifdef HAVE_GLBINDTEXTURE
512 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[tex]);
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);
524 if (blend_mode != 0) {
525 glBlendFunc(GL_CONSTANT_ALPHA,
526 GL_ONE_MINUS_CONSTANT_ALPHA);
527 glBlendEquation(GL_FUNC_ADD);
529 /* glDisable(GL_BLEND); */
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)
541 if (listnum == tc->diamondlist)
542 mi->polygon_count += 4;
543 if (listnum == tc->cyllist)
544 mi->polygon_count += 30;
545 glMatrixMode(GL_TEXTURE);
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);
553 #ifdef HAVE_GLBINDTEXTURE
555 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[texnum]);
559 glMatrixMode(GL_TEXTURE);
561 glMatrixMode(GL_MODELVIEW);
562 /* glDisable(GL_BLEND); */
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 */
571 void make_wall_tunnel(ModeInfo *mi, tunnel_configuration *tc, float percent, float cap)
573 /* tardis is about 2x1, so wrap tex around, starting at the base*/
581 that's br=bottom right, etc. ttr is top-top-right */
583 float half_floor= 0.08333333333333333,
584 full_wall = 0.33333333333333333;
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 */
594 float textop, texbot;
601 tr1 = r1 + half_floor;
603 tl1 = tl0 + half_floor;
608 glMatrixMode(GL_TEXTURE);
610 glRotatef(90.0, 0.0, 0.0, 1.0);
611 glTranslatef(tc->texshift[0], 0.0, 0.0);
612 glMatrixMode(GL_MODELVIEW);
614 #ifdef HAVE_GLBINDTEXTURE
616 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[0]);
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);
634 if (percent > ( full_wall * 2.0)) {
637 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
638 if (height > 1.0) height = 1.0;
642 mi->polygon_count += 2;
643 if ( height > 0.90) {
644 mi->polygon_count += 2;
647 textop = tr0 + half_floor * height;
648 glTexCoord2f(0.0, texbot);
649 glVertex3f(0.2, 2.2, 0.0);
651 glTexCoord2f(0.0, textop);
652 glVertex3f(2.0 - height * 2.0, 2.2, 0.0);
654 glTexCoord2f(depth, textop);
655 glVertex3f(2.0 - height * 2.0, 2.2, zdepth);
657 glTexCoord2f(depth, texbot);
658 glVertex3f(0.2, 2.2, zdepth);
661 texbot = tl1 - half_floor * height;
663 glTexCoord2f(0.0, texbot);
664 glVertex3f(-2.0 + height * 2.0, 2.2, 0.0);
666 glTexCoord2f(0.0, textop);
667 glVertex3f(-0.2, 2.2, 0.0);
669 glTexCoord2f(depth, textop);
670 glVertex3f(-0.2, 2.2, zdepth);
672 glTexCoord2f(depth, texbot);
673 glVertex3f(-2.0 + height * 2.0, 2.2, zdepth);
675 if (height > 0.90) height = 0.90;
679 textop = tr0 + half_floor * height;
680 glTexCoord2f(0.0, texbot);
681 glVertex3f(0.2, 2.0, 0.0);
683 glTexCoord2f(0.0, textop);
684 glVertex3f(0.2, 0.4 + height * 2.0, 0.0);
686 glTexCoord2f(depth, textop);
687 glVertex3f(0.2, 0.4 + height * 2.0, zdepth);
689 glTexCoord2f(depth, texbot);
690 glVertex3f(0.2, 2.0, zdepth);
693 texbot = tl1 - half_floor * height;
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);
699 glTexCoord2f(0.0, textop);
700 glVertex3f(-.2, 2.0, 0.0);
702 glTexCoord2f(depth, textop);
703 glVertex3f(-.2, 2.0, zdepth);
705 glTexCoord2f(depth, texbot);
706 glVertex3f(-.2, 0.4 + height * 2.0, zdepth);
709 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
710 if (height > 0.8) height = 0.8;
713 mi->polygon_count += 2;
716 textop = tr0 + half_floor * height;
717 glTexCoord2f(0.0, texbot);
718 glVertex3f(1.0, 2.0, 0.0);
720 glTexCoord2f(0.0, textop);
721 glVertex3f(1.0 - height, 2.0, 0.0);
723 glTexCoord2f(depth, textop);
724 glVertex3f(1.0 - height, 2.0, zdepth);
726 glTexCoord2f(depth, texbot);
727 glVertex3f(1.0, 2.0, zdepth);
730 texbot = tl1 - half_floor * height;
732 glTexCoord2f(0.0, texbot);
733 glVertex3f(-1.0 + height, 2.0, 0.0);
735 glTexCoord2f(0.0, textop);
736 glVertex3f(-1.0, 2.0, 0.0);
738 glTexCoord2f(depth, textop);
739 glVertex3f(-1.0, 2.0, zdepth);
741 glTexCoord2f(depth, texbot);
742 glVertex3f(-1.0 + height, 2.0, zdepth);
744 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
746 if (height > 1.0) height = 1.0;
749 mi->polygon_count += 2;
752 textop = tr0 + half_floor * height;
753 glTexCoord2f(0.0, texbot);
754 glVertex3f(1.0, -2.0, 0.0);
756 glTexCoord2f(0.0, textop);
757 glVertex3f(1.0 - height, -2.0, 0.0);
759 glTexCoord2f(depth, textop);
760 glVertex3f(1.0 - height, -2.0, zdepth);
762 glTexCoord2f(depth, texbot);
763 glVertex3f(1.0, -2.0, zdepth);
766 texbot = tl1 - half_floor * height;
768 glTexCoord2f(0.0, texbot);
769 glVertex3f(-1.0 + height, -2.0, 0.0);
771 glTexCoord2f(0.0, textop);
772 glVertex3f(-1.0, -2.0, 0.0);
774 glTexCoord2f(depth, textop);
775 glVertex3f(-1.0, -2.0, zdepth);
777 glTexCoord2f(depth, texbot);
778 glVertex3f(-1.0 + height, -2.0, zdepth);
785 mi->polygon_count += 2;
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;
792 glTexCoord2f(0.0, textop);
793 glVertex3f(-1.0, height * 2, 0.0);
795 glTexCoord2f(0.0, texbot);
796 glVertex3f(-1.0, -height * 2, 0.0);
798 glTexCoord2f(depth, texbot);
799 glVertex3f(-1.0, -height * 2, zdepth);
801 glTexCoord2f(depth, textop);
802 glVertex3f(-1.0, height * 2, zdepth);
804 textop = (r0 + r1) / 2.0 - full_wall * 0.5 * height;
805 texbot = (r0 + r1) / 2.0 + full_wall * 0.5 * height;
807 glTexCoord2f(0.0, texbot);
808 glVertex3f(1.0, height * 2, 0.0);
810 glTexCoord2f(0.0, textop);
811 glVertex3f(1.0, -height * 2, 0.0);
813 glTexCoord2f(depth, textop);
814 glVertex3f(1.0, -height * 2, zdepth);
816 glTexCoord2f(depth, texbot);
817 glVertex3f(1.0, height * 2, zdepth);
822 glMatrixMode(GL_TEXTURE);
824 glMatrixMode(GL_MODELVIEW);
825 } /* make_wall_tunnel */
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)
836 ret = min + (val - max ) % (max - min);
838 ret = max - (min - val) % (max - min);
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
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.
854 float mylog2(float x) { return ( log(x) / log(2));}
856 static void LoadTexture(ModeInfo * mi, char **fn, unsigned int texbind, int blur, float bw_color, Bool anegative, Bool onealpha)
858 /* looping and temporary array index variables */
859 int ix, iy, bx, by, indx, indy, boxsize, cchan, tmpidx, dtaidx;
861 float boxdiv, tmpfa, blursum ;
862 unsigned char *tmpbuf, tmpa;
866 XImage *teximage; /* Texture data */
871 boxdiv = 1.0 / ( boxsize * 2.0 + 1.0) / ( boxsize * 2.0 + 1.0);
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);
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) {
887 if ((tmpfa - (int) tmpfa) > 0.5849)
890 tmpfa = mylog2((float) teximage->height);
891 by = 2 << (int) (tmpfa - 1);
892 if (by != teximage->height) {
894 if ((tmpfa - (int) tmpfa) > 0.5849)
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");
904 free(teximage->data);
905 teximage->data = (char *) tmpbuf;
906 teximage->width = bx;
907 teximage->height= by;
909 /* end rescale code */
912 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
914 if (!teximage->data[ ix * 4 + 3]) {
915 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
916 tmpa = (unsigned char) (bw_color * 0xff);
919 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
921 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff -
922 teximage->data[ ix * 4 + 3];
923 tmpa = (unsigned char) ((1.0 - bw_color) * 0xff);
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);
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])
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);
949 tmpbuf = calloc(teximage->height * teximage->width * 4, sizeof(unsigned char) ) ;
951 /* zero out tmp alpha buffer */
952 for (iy = 0 ; iy <teximage->height * teximage->width * 4 ; iy++)
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;
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;
968 tmpbuf[tmpidx + cchan] += (unsigned char) blursum;
974 /* copy back buffer */
975 for (ix = 0 ; ix < teximage->height * teximage->width * 4; ix++)
976 teximage->data[ix] = tmpbuf[ix];
978 free(tmpbuf); /*tidy*/
985 #ifdef HAVE_GLBINDTEXTURE
986 glBindTexture(GL_TEXTURE_2D, texbind);
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");
993 XDestroyImage(teximage);
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) {
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);
1012 glVertex3f(cos(0.0) * rad, sin(0.0) * rad, zmax);
1016 glBegin(GL_QUAD_STRIP);
1017 for (i = 0 ; i <= sides; i++)
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);
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);
1037 init_tunnel (ModeInfo *mi)
1041 tunnel_configuration *tc;
1043 wire = MI_IS_WIREFRAME(mi);
1046 tconf = (tunnel_configuration *)
1047 calloc (MI_NUM_SCREENS(mi), sizeof (tunnel_configuration));
1049 fprintf(stderr, "%s: out of memory\n", progname);
1053 tc = &tconf[MI_SCREEN(mi)];
1056 tc = &tconf[MI_SCREEN(mi)];
1058 tc->glx_context = init_GL(mi);
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;
1072 /* set loop times, in seconds */
1073 tc->start_time = start;
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);
1082 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1088 glGenTextures(MAX_TEXTURE, tc->texture_binds);
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
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];
1103 LoadTexture(mi, (char **) logo_180_xpm, tc->texture_binds[9], 2,1.0, TRUE, TRUE);
1104 # ifdef GET_SUED_BY_THE_BBC
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); */
1111 LoadTexture(mi, whohead1_xpm, tc->texture_binds[9], 2, 1.0, TRUE, TRUE);
1113 # endif /* GET_SUED_BY_THE_BBC */
1114 glEnable(GL_TEXTURE_2D);
1115 check_gl_error("tex");
1118 reshape_tunnel (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1120 glDisable(GL_DEPTH_TEST); /* who needs it? ;-) */
1127 glEnable(GL_ALPHA_TEST);
1128 glAlphaFunc(GL_GREATER, 0.5);
1131 tc->trackball = gltrackball_init ();
1134 tc->texshift = calloc(tc->num_texshifts, sizeof(GLfloat));
1135 for ( i = 0 ; i < tc->num_texshifts; i++)
1136 tc->texshift[i] = 0.0;
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); */
1143 glNewList(tc->diamondlist, GL_COMPILE);
1144 makecyl(4, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN);
1150 draw_tunnel (ModeInfo *mi)
1152 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
1153 Display *dpy = MI_DISPLAY(mi);
1154 Window window = MI_WINDOW(mi);
1157 if (!tc->glx_context)
1160 glShadeModel(GL_SMOOTH);
1162 glEnable(GL_NORMALIZE);
1163 /* glEnable(GL_CULL_FACE); */
1165 glClear(GL_COLOR_BUFFER_BIT );
1167 update_animation(tc);
1172 glRotatef(180., 0., 1., 0.);
1173 gltrackball_rotate (tc->trackball);
1174 glRotatef(180., 0., 1., 0.);
1178 mi->polygon_count = 0;
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*/
1185 /* --- begin composite image assembly --- */
1187 /* head mask and draw diamond tunnel */
1190 draw_cyl(mi, tc, tc->effects[6].state[0], 5, tc->diamondlist, 2);
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]);
1197 /* then cylender tunnel */
1199 draw_cyl(mi, tc, tc->effects[3].state[0], 2, tc->cyllist, 1);
1201 /*void draw_sign(mi, tc,z,alpha,aspect,tex,blendmode)*/
1204 draw_sign(mi, tc, tc->effects[2].state[0], tc->effects[2].state[1], 2.0, 1, 0);
1207 draw_sign(mi, tc, tc->effects[5].state[0], tc->effects[5].state[1], 1.0, 3, 0);
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); */
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);
1220 draw_sign(mi, tc,1.0, tc->effects[9].state[0], 1.0 / 1.33, 6, 0);
1222 /* --- end composite image assembly --- */
1227 if (mi->fps_p) do_fps (mi);
1230 check_gl_error("drawing done, calling swap buffers");
1231 glXSwapBuffers(dpy, window);