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 <math.h> /* for log2 */
15 #define DEFAULTS "*delay: 30000 \n" \
17 "*showFPS: False \n" \
18 "*timeStart: 0.0 \n" \
19 "*timeEnd: 27.79 \n" \
20 "*wireframe: False \n" \
24 # define refresh_tunnel 0
25 # define release_tunnel 0
27 #define countof(x) (sizeof((x))/sizeof((*x)))
29 #include "xlockmore.h"
32 #include "gltrackball.h"
35 #define DEF_START "0.00"
36 #define DEF_DILATE "1.00"
37 #define DEF_END "27.79"
38 #define DEF_LOCKLOGO "False"
39 #define DEF_DRAWLOGO "True"
40 #define DEF_REVERSE "False"
41 #define DEF_FOG "True"
42 #define DEF_TEXTURE "True"
43 #define MAX_TEXTURE 10
45 #define DIAMOND_LEN 10.0
47 static float start, end, dilate;
48 static Bool do_texture, drawlogo, wire, reverse, do_fog;
49 #ifdef GET_SUED_BY_THE_BBC
53 static XrmOptionDescRec opts[] = {
54 {"-texture" , ".texture", XrmoptionNoArg, "true" },
55 {"-start" , ".start", XrmoptionSepArg, 0 },
56 {"-end" , ".end", XrmoptionSepArg, 0 },
57 {"-dilate" , ".dilate", XrmoptionSepArg, 0 },
58 #ifdef GET_SUED_BY_THE_BBC
59 {"-locklogo" , ".locklogo", XrmoptionNoArg, "true" },
61 {"-logo" , ".drawlogo", XrmoptionNoArg, "true" },
62 {"+logo" , ".drawlogo", XrmoptionNoArg, "false" },
63 {"-reverse" , ".reverse", XrmoptionNoArg, "true" },
64 {"-fog" , ".fog", XrmoptionNoArg, "false" },
67 static argtype vars[] = {
68 {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
69 {&start, "start", "Start", DEF_START, t_Float},
70 {&end, "end", "End", DEF_END , t_Float},
71 {&dilate, "dilate", "Dilate", DEF_DILATE , t_Float},
72 #ifdef GET_SUED_BY_THE_BBC
73 {&locklogo, "locklogo", "LockLogo", DEF_LOCKLOGO , t_Bool},
75 {&drawlogo, "drawlogo", "DrawLogo", DEF_DRAWLOGO , t_Bool},
76 {&reverse, "reverse", "Reverse", DEF_REVERSE , t_Bool},
77 {&do_fog, "fog", "Fog", DEF_FOG , t_Bool},
80 ENTRYPOINT ModeSpecOpt tunnel_opts = {countof(opts), opts, countof(vars), vars, NULL};
81 #include "xpm-ximage.h"
82 #include "images/logo-180.xpm"
83 #include "images/tunnelstar.xpm"
84 #include "images/timetunnel0.xpm"
85 #include "images/timetunnel1.xpm"
86 #include "images/timetunnel2.xpm"
87 #ifdef GET_SUED_BY_THE_BBC
88 # include "images/tardis.xpm"
89 # include "images/whologo.xpm"
90 # include "images/whohead1.xpm"
91 /* #include "images/whohead_psy.xpm" */
92 # endif /* GET_SUED_BY_THE_BBC */
95 #ifdef USE_GL /* whole file */
97 /* ANIMATION CONTROLS */
98 /* an effect is a collection of floating point variables that vary with time.
99 A knot is a timestamp with an array of floats. State is the current values of the floats.
100 State is set by linearly interpolating between knots */
102 float *knots, *state;
103 int numknots, knotwidth;
108 GLXContext *glx_context;
110 trackball_state *trackball;
113 int time_oldusec, time_oldsec;
115 int num_texshifts; /* animates tunnels. Not an effect. */
116 GLfloat pos, *texshift;
118 GLuint texture_binds[MAX_TEXTURE], cyllist, diamondlist;
120 float effect_time, effect_maxsecs; /* global time controls */
121 float start_time, end_time;
124 effect_t *effects; /* array of all effects */
126 } tunnel_configuration;
128 static tunnel_configuration *tconf = NULL;
130 /* allocate memory and populate effect with knot data */
131 static void init_effect(effect_t *e, int numk, int kwidth,
132 float dir, float *data )
137 e->knotwidth = kwidth;
139 e->knots = calloc(numk * kwidth, sizeof(float));
140 e->state = calloc(numk, sizeof(float));
141 for ( i = 0 ; i < e->numknots ; i++)
142 for ( j = 0 ; j < e->knotwidth; j++)
143 e->knots[i * kwidth + j] = data[i * kwidth + j];
146 /* static knot data. each effect is listed and knot data is hard coded.
147 Knots are linerally interpolated to yield float values, depending on
148 knot width. knot format is [time, data, data, data...].
149 Data can be alpha, zvalue, etc. */
150 static void init_effects(effect_t *e, int effectnum)
152 /* effect 1: wall tunnel. percent closed */
160 /* effect 2: tardis. distance and alpha */
170 /* effect 3: cylender. alpha */
178 /* effect 4: fog. color, density, start, end */
180 {{0.0 , 1.0, 0.45, 3.0, 15.0},
181 {6.40, 1.0, 0.45, 3.0, 14.0},
182 {8.08, 1.0, 0.95, 1.0, 14.0},
183 {15.17, 1.0, 0.95, 1.0, 6.0},
184 {15.51, 1.0, 0.95, 3.0, 8.0},
185 {23.35, 1.0, 0.95, 3.0, 8.0},
186 {24.02, 0.0, 0.95, 2.3, 5.0},
187 {26.02, 0.0, 0.95, 2.3, 5.0},
188 {27.72, 0.0, 1.00, 0.3, 0.9}
191 /* effect 5: logo. dist, alpha */
201 /* effect 6: diamond tunnel. alpha */
207 /* effect 7: tardis cap draw . positive draws cap*/
213 /* effect 8: star/asterisk: alpha */
221 /* effect 9: whohead 1 alpha */
231 /* effect 10: whohead-brite alpha */
238 /* {13.95, 0.00}}; */
240 /* effect 11: whohead-psy alpha */
248 /* effect 12: whohead-silhouette pos-z, alpha */
255 {16.78, 0.1, 0.00} };
257 /* effect 1: wall tunnel */
259 init_effect(e, 6, 2, -0.2, (float *) e1d);
261 /* effect 2: tardisl */
263 init_effect(e, 8, 3, 1.0, (float *) e2d);
265 /* effect 3: cylender tunnel */
267 init_effect(e, 5, 2, 0.889 , (float *) e3d);
269 /* effect 4: fog color */
271 init_effect(e, 9, 5, 1.0, (float *) e4d);
272 /* effect 5: logo distance, alpha*/
274 init_effect(e, 7, 3, 1.0, (float *) e5d);
275 /* effect 6: diamond tunnel, alpha*/
277 init_effect(e, 3, 2, 0.24 , (float *) e6d);
279 /* effect 7: cap wall tunnel*/
281 init_effect(e, 3, 2, 1.0, (float *) e7d);
283 /* effect 8: asterisk */
285 init_effect(e, 5, 2, 1.0, (float *) e8d);
287 /* effect 9, 10, 11, 12: whoheads */
289 init_effect(e, 5, 2, 1.0, (float *) e9d);
290 if (effectnum == 10 )
291 init_effect(e, 5, 2, 1.0, (float *) e10d);
292 if (effectnum == 11 )
293 init_effect(e, 5, 2, 1.0, (float *) e11d);
294 if (effectnum == 12 )
295 init_effect(e, 6, 3, 1.0, (float *) e12d);
299 /* set fog parameters, controlled by effect */
300 static void update_fog(float color, float density, float start, float end)
304 col[0] = col[1] = col[2] = color;
307 glFogi(GL_FOG_MODE, GL_LINEAR);
308 glFogfv(GL_FOG_COLOR, col);
309 glFogf(GL_FOG_DENSITY, density);
310 glFogf(GL_FOG_START, start);
311 glFogf(GL_FOG_END, end);
314 /* set effect's floating point data values by linearally interpolating
315 between two knots whose times bound the current time: eff_time */
317 static void update_knots(effect_t *e, float eff_time)
320 float timedelta, lowknot, highknot, *curknot, *nextknot;
322 for ( i = 0 ; i < e->numknots ; i++)
323 if (e->knots[i * e->knotwidth] <= eff_time) {
324 if ( i < e->numknots - 1)
325 nextknot = e->knots + (i + 1) * e->knotwidth;
327 /*repeat last knot to carry knot data forward*/
328 nextknot = e->knots + (i) * e->knotwidth;
329 curknot = e->knots + i * e->knotwidth;
330 if (*nextknot - *curknot <= 0.0) timedelta = 1.0;
332 timedelta = (eff_time-*curknot)/(*nextknot-*curknot);
333 if (timedelta > 1.0) timedelta = 1.0;
334 for (j = 1 ; j < e->knotwidth ; j++) {
335 highknot = (float) *(nextknot + j);
336 lowknot = (float) *(curknot + j);
337 e->state[j - 1 ] = lowknot+(highknot-lowknot)*timedelta;
344 /* Window management, etc
347 reshape_tunnel (ModeInfo *mi, int width, int height)
349 GLfloat h = (GLfloat) height / (GLfloat) width;
351 glViewport (0, 0, (GLint) width, (GLint) height);
353 glMatrixMode(GL_PROJECTION);
355 gluPerspective (90.0, 1/h, 0.2, 50.0);
357 glMatrixMode(GL_MODELVIEW);
359 gluLookAt( 0.0, 0.0, 0.3,
363 glClear(GL_COLOR_BUFFER_BIT);
370 tunnel_handle_event (ModeInfo *mi, XEvent *event)
372 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
374 if (event->xany.type == ButtonPress &&
375 event->xbutton.button == Button1)
377 tc->button_down_p = True;
378 gltrackball_start (tc->trackball,
379 event->xbutton.x, event->xbutton.y,
380 MI_WIDTH (mi), MI_HEIGHT (mi));
383 else if (event->xany.type == ButtonRelease &&
384 event->xbutton.button == Button1)
386 tc->button_down_p = False;
389 else if (event->xany.type == ButtonPress &&
390 (event->xbutton.button == Button4 ||
391 event->xbutton.button == Button5 ||
392 event->xbutton.button == Button6 ||
393 event->xbutton.button == Button7))
395 gltrackball_mousewheel (tc->trackball, event->xbutton.button, 10,
396 !!event->xbutton.state);
399 else if (event->xany.type == MotionNotify &&
402 gltrackball_track (tc->trackball,
403 event->xmotion.x, event->xmotion.y,
404 MI_WIDTH (mi), MI_HEIGHT (mi));
411 static void setTexParams(void)
413 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
414 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
415 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
416 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
417 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
420 static void update_animation(tunnel_configuration *tc) {
422 /* time based, of course*/
423 /* shift texture based on elapsed time since previous call*/
426 int elapsed_usecs, elapsed_secs, i;
427 float computed_timeshift;
429 /* get new animation time */
430 gettimeofday(&tv, &tz);
431 elapsed_secs = tv.tv_sec - tc->time_oldsec;
432 elapsed_usecs = tv.tv_usec - tc->time_oldusec;
433 /* store current time */
434 tc->time_oldsec = tv.tv_sec ;
435 tc->time_oldusec = tv.tv_usec;
436 /* elaped time. computed timeshift is tenths of a second */
437 computed_timeshift = (float) (elapsed_secs * 1000000. + elapsed_usecs)/
440 /* calibrate effect time to lie between start and end times */
441 /* loop if time exceeds end time */
443 tc->effect_time -= computed_timeshift / 10.0 * dilate;
445 tc->effect_time += computed_timeshift / 10.0 * dilate;
446 if ( tc->effect_time >= tc->end_time)
447 tc->effect_time = tc->start_time;
448 if ( tc->effect_time < tc->start_time)
449 tc->effect_time = tc->end_time;;
451 /* move texture shifters in effect's direction, e.g. tardis
452 tunnel moves backward, effect 1's direction */
454 tc->texshift[0] -= tc->effects[1].direction * computed_timeshift/ 10.0;
455 tc->texshift[1] -= tc->effects[3].direction * computed_timeshift/ 10.0;
456 tc->texshift[2] -= tc->effects[6].direction * computed_timeshift/ 10.0;
459 tc->texshift[0] += tc->effects[1].direction * computed_timeshift/ 10.0;
460 tc->texshift[1] += tc->effects[3].direction * computed_timeshift/ 10.0;
461 tc->texshift[2] += tc->effects[6].direction * computed_timeshift/ 10.0;
464 /* loop texture shifters if necessary */
465 for ( i = 0 ; i < tc->num_texshifts; i++) {
466 if (tc->texshift[i] > 1.0)
467 tc->texshift[i] -= (int) tc->texshift[i];
468 if (tc->texshift[i]< -1.0)
469 tc->texshift[i] -= (int) tc->texshift[i];
472 /* update effect data with current time. Uses linear interpolation */
473 for ( i = 1 ; i <= tc->num_effects ; i++)
474 update_knots(&tc->effects[i], tc->effect_time);
476 } /*update_animation*/
478 /* draw a textured(tex) quad at a certain depth (z), and certain alpha (alpha),
479 with aspect ratio (aspect), and blending mode (blend_mode) of either adding
480 or subtracting. if alpha is zero or less, nothing happens */
481 static void draw_sign(ModeInfo *mi, tunnel_configuration *tc, float z, float alpha, float aspect,
482 GLuint tex, int blend_mode)
486 mi->polygon_count ++;
487 /* glEnable(GL_BLEND); */
488 glBlendColor(0.0, 0.0, 0.0, alpha);
489 /*glBlendColor(0.0, 0.0, 0.0, 0.0); */
490 if (blend_mode == 1) {
491 glBlendFunc(GL_CONSTANT_ALPHA,
493 glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
494 } else if (blend_mode == 2) {
495 glBlendFunc(GL_CONSTANT_ALPHA,
497 glBlendEquation(GL_FUNC_ADD);
499 glBlendFunc(GL_CONSTANT_ALPHA,
500 GL_ONE_MINUS_CONSTANT_ALPHA);
501 glBlendEquation(GL_FUNC_ADD);
502 } /* blend mode switch */
504 #ifdef HAVE_GLBINDTEXTURE
506 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[tex]);
509 glTexCoord2f(1.0, 0.0);
510 glVertex3f(-1.0 , -1.0 * aspect , z);
511 glTexCoord2f(1.0, 1.0);
512 glVertex3f(-1.0 , 1.0 * aspect , z);
513 glTexCoord2f(0.0, 1.0);
514 glVertex3f(1.0 , 1.0 * aspect , z);
515 glTexCoord2f(0.0, 0.0);
516 glVertex3f(1.0 , -1.0 * aspect , z);
518 if (blend_mode != 0) {
519 glBlendFunc(GL_CONSTANT_ALPHA,
520 GL_ONE_MINUS_CONSTANT_ALPHA);
521 glBlendEquation(GL_FUNC_ADD);
523 /* glDisable(GL_BLEND); */
529 /* draw a time tunnel. used for both cylender and diamond tunnels.
530 uses texture shifter (indexed by shiftnum) to simulate motion.
531 tunnel does not move, and is acutally a display list. if alpha = 0, skip */
532 static void draw_cyl(ModeInfo *mi, tunnel_configuration *tc, float alpha, int texnum, int listnum, int shiftnum)
535 if (listnum == tc->diamondlist)
536 mi->polygon_count += 4;
537 if (listnum == tc->cyllist)
538 mi->polygon_count += 30;
539 glMatrixMode(GL_TEXTURE);
541 glTranslatef(tc->texshift[shiftnum], 0.0, 0.0);
542 glMatrixMode(GL_MODELVIEW);
543 /* glEnable(GL_BLEND); */
544 glBlendColor(0.0, 0.0, 0.0, alpha);
545 glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
547 #ifdef HAVE_GLBINDTEXTURE
549 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[texnum]);
553 glMatrixMode(GL_TEXTURE);
555 glMatrixMode(GL_MODELVIEW);
556 /* glDisable(GL_BLEND); */
561 /* make tardis type tunnel. Starts as walls and then
562 grows to outline of tardis. percent is how complete
563 tardis outline is. cap is to draw cap for nice fog effects */
565 static void make_wall_tunnel(ModeInfo *mi, tunnel_configuration *tc, float percent, float cap)
567 /* tardis is about 2x1, so wrap tex around, starting at the base*/
575 that's br=bottom right, etc. ttr is top-top-right */
577 float half_floor= 0.08333333333333333,
578 full_wall = 0.33333333333333333;
584 bl0, depth=0.3, zdepth=15.0;
585 /* zdepth is how far back tunnel goes */
586 /* depth is tex coord scale. low number = fast texture shifting */
588 float textop, texbot;
595 tr1 = r1 + half_floor;
597 tl1 = tl0 + half_floor;
602 glMatrixMode(GL_TEXTURE);
604 glRotatef(90.0, 0.0, 0.0, 1.0);
605 glTranslatef(tc->texshift[0], 0.0, 0.0);
606 glMatrixMode(GL_MODELVIEW);
608 #ifdef HAVE_GLBINDTEXTURE
610 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[0]);
612 glColor3f(1.0, 1.0, 0.0);
613 if (cap > 0.0 && percent > 0.0 && drawlogo && do_fog) {
614 mi->polygon_count += 6;
615 glBegin(GL_TRIANGLE_FAN);
616 glVertex3f(0.0, 0.0, zdepth);
617 glVertex3f(-1.0, -2.0, zdepth);
618 glVertex3f(1.0, -2.0, zdepth);
619 glVertex3f(1.0, 2.0, zdepth);
620 glVertex3f(0.2, 2.0, zdepth);
621 glVertex3f(0.2, 2.2, zdepth);
622 glVertex3f(-0.2, 2.2, zdepth);
623 glVertex3f(-0.2, 2.0, zdepth);
624 glVertex3f(-1.0, 2.0, zdepth);
625 glVertex3f(-1.0, -2.0, zdepth);
628 if (percent > ( full_wall * 2.0)) {
631 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
632 if (height > 1.0) height = 1.0;
636 mi->polygon_count += 2;
637 if ( height > 0.90) {
638 mi->polygon_count += 2;
641 textop = tr0 + half_floor * height;
642 glTexCoord2f(0.0, texbot);
643 glVertex3f(0.2, 2.2, 0.0);
645 glTexCoord2f(0.0, textop);
646 glVertex3f(2.0 - height * 2.0, 2.2, 0.0);
648 glTexCoord2f(depth, textop);
649 glVertex3f(2.0 - height * 2.0, 2.2, zdepth);
651 glTexCoord2f(depth, texbot);
652 glVertex3f(0.2, 2.2, zdepth);
655 texbot = tl1 - half_floor * height;
657 glTexCoord2f(0.0, texbot);
658 glVertex3f(-2.0 + height * 2.0, 2.2, 0.0);
660 glTexCoord2f(0.0, textop);
661 glVertex3f(-0.2, 2.2, 0.0);
663 glTexCoord2f(depth, textop);
664 glVertex3f(-0.2, 2.2, zdepth);
666 glTexCoord2f(depth, texbot);
667 glVertex3f(-2.0 + height * 2.0, 2.2, zdepth);
669 if (height > 0.90) height = 0.90;
673 textop = tr0 + half_floor * height;
674 glTexCoord2f(0.0, texbot);
675 glVertex3f(0.2, 2.0, 0.0);
677 glTexCoord2f(0.0, textop);
678 glVertex3f(0.2, 0.4 + height * 2.0, 0.0);
680 glTexCoord2f(depth, textop);
681 glVertex3f(0.2, 0.4 + height * 2.0, zdepth);
683 glTexCoord2f(depth, texbot);
684 glVertex3f(0.2, 2.0, zdepth);
687 texbot = tl1 - half_floor * height;
689 glTexCoord2f(0.0, texbot);
690 /*glVertex3f(-.2, 2.0 + (0.9 - height) * 2.0, 0.0); */
691 glVertex3f(-.2, 0.4 + height * 2.0, 0.0);
693 glTexCoord2f(0.0, textop);
694 glVertex3f(-.2, 2.0, 0.0);
696 glTexCoord2f(depth, textop);
697 glVertex3f(-.2, 2.0, zdepth);
699 glTexCoord2f(depth, texbot);
700 glVertex3f(-.2, 0.4 + height * 2.0, zdepth);
703 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
704 if (height > 0.8) height = 0.8;
707 mi->polygon_count += 2;
710 textop = tr0 + half_floor * height;
711 glTexCoord2f(0.0, texbot);
712 glVertex3f(1.0, 2.0, 0.0);
714 glTexCoord2f(0.0, textop);
715 glVertex3f(1.0 - height, 2.0, 0.0);
717 glTexCoord2f(depth, textop);
718 glVertex3f(1.0 - height, 2.0, zdepth);
720 glTexCoord2f(depth, texbot);
721 glVertex3f(1.0, 2.0, zdepth);
724 texbot = tl1 - half_floor * height;
726 glTexCoord2f(0.0, texbot);
727 glVertex3f(-1.0 + height, 2.0, 0.0);
729 glTexCoord2f(0.0, textop);
730 glVertex3f(-1.0, 2.0, 0.0);
732 glTexCoord2f(depth, textop);
733 glVertex3f(-1.0, 2.0, zdepth);
735 glTexCoord2f(depth, texbot);
736 glVertex3f(-1.0 + height, 2.0, zdepth);
738 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
740 if (height > 1.0) height = 1.0;
743 mi->polygon_count += 2;
746 textop = tr0 + half_floor * height;
747 glTexCoord2f(0.0, texbot);
748 glVertex3f(1.0, -2.0, 0.0);
750 glTexCoord2f(0.0, textop);
751 glVertex3f(1.0 - height, -2.0, 0.0);
753 glTexCoord2f(depth, textop);
754 glVertex3f(1.0 - height, -2.0, zdepth);
756 glTexCoord2f(depth, texbot);
757 glVertex3f(1.0, -2.0, zdepth);
760 texbot = tl1 - half_floor * height;
762 glTexCoord2f(0.0, texbot);
763 glVertex3f(-1.0 + height, -2.0, 0.0);
765 glTexCoord2f(0.0, textop);
766 glVertex3f(-1.0, -2.0, 0.0);
768 glTexCoord2f(depth, textop);
769 glVertex3f(-1.0, -2.0, zdepth);
771 glTexCoord2f(depth, texbot);
772 glVertex3f(-1.0 + height, -2.0, zdepth);
779 mi->polygon_count += 2;
781 height = percent / ( full_wall * 2.0);
782 if (height > 1.0) height = 1.0;
783 textop = (l0 + l1) / 2.0 - full_wall * 0.5 * height;
784 texbot = (l0 + l1) / 2.0 + full_wall * 0.5 * height;
786 glTexCoord2f(0.0, textop);
787 glVertex3f(-1.0, height * 2, 0.0);
789 glTexCoord2f(0.0, texbot);
790 glVertex3f(-1.0, -height * 2, 0.0);
792 glTexCoord2f(depth, texbot);
793 glVertex3f(-1.0, -height * 2, zdepth);
795 glTexCoord2f(depth, textop);
796 glVertex3f(-1.0, height * 2, zdepth);
798 textop = (r0 + r1) / 2.0 - full_wall * 0.5 * height;
799 texbot = (r0 + r1) / 2.0 + full_wall * 0.5 * height;
801 glTexCoord2f(0.0, texbot);
802 glVertex3f(1.0, height * 2, 0.0);
804 glTexCoord2f(0.0, textop);
805 glVertex3f(1.0, -height * 2, 0.0);
807 glTexCoord2f(depth, textop);
808 glVertex3f(1.0, -height * 2, zdepth);
810 glTexCoord2f(depth, texbot);
811 glVertex3f(1.0, height * 2, zdepth);
816 glMatrixMode(GL_TEXTURE);
818 glMatrixMode(GL_MODELVIEW);
819 } /* make_wall_tunnel */
821 /* wraps an int to between min and max.
822 Kind of like the remainder when devided by (max - min).
823 Used to create torus mapping on square array */
824 static int wrapVal(int val, int min, int max)
830 ret = min + (val - max ) % (max - min);
832 ret = max - (min - val) % (max - min);
836 /*=================== Load Texture =========================================*/
837 /* ripped from atunnel.c, Copyright (c) E. Lassauge, 2003-2004. */
838 /* modified like so by Sean Brennan:
839 take texture object for glbind
842 blur color / alpha channel [3x3 box filter, done [blur] times
843 anegative : create b/w image from zero alpha. zero alpha gets bw_color,
844 nonzero alpha gets 1.0 - bwcolor, then alpha flipped to 1-alpha.
848 static float mylog2(float x) { return ( log(x) / log(2));}
850 static void LoadTexture(ModeInfo * mi, char **fn, GLuint texbind, int blur, float bw_color, Bool anegative, Bool onealpha)
852 /* looping and temporary array index variables */
853 int ix, iy, bx, by, indx, indy, boxsize, cchan, tmpidx, dtaidx;
855 float boxdiv, tmpfa, blursum ;
856 unsigned char *tmpbuf, tmpa;
860 XImage *teximage; /* Texture data */
865 boxdiv = 1.0 / ( boxsize * 2.0 + 1.0) / ( boxsize * 2.0 + 1.0);
867 if ((teximage = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
868 MI_COLORMAP(mi), fn)) == None) {
869 fprintf(stderr, "%s: error reading the texture.\n", progname);
870 glDeleteTextures(1, &texbind);
875 /* check if image is 2^kumquat, where kumquat is an integer between 1 and 10. Recale to
876 nearest power of 2. */
877 tmpfa = mylog2((float) teximage->width);
878 bx = 2 << (int) (tmpfa -1);
879 if (bx != teximage->width) {
881 if ((tmpfa - (int) tmpfa) > 0.5849)
884 tmpfa = mylog2((float) teximage->height);
885 by = 2 << (int) (tmpfa - 1);
886 if (by != teximage->height) {
888 if ((tmpfa - (int) tmpfa) > 0.5849)
893 tmpbuf = calloc(bx * by * 4, sizeof(unsigned char));
894 if (gluScaleImage(GL_RGBA, teximage->width, teximage->height, GL_UNSIGNED_BYTE, teximage->data,
895 bx, by, GL_UNSIGNED_BYTE, tmpbuf))
896 check_gl_error("scale image");
898 free(teximage->data);
899 teximage->data = (char *) tmpbuf;
900 teximage->width = bx;
901 teximage->height= by;
903 /* end rescale code */
906 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
908 if (!teximage->data[ ix * 4 + 3]) {
909 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
910 tmpa = (unsigned char) (bw_color * 0xff);
913 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
915 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff -
916 teximage->data[ ix * 4 + 3];
917 tmpa = (unsigned char) ((1.0 - bw_color) * 0xff);
919 /* make texture uniform b/w color */
920 teximage->data[ ix * 4 + 0] =
921 (unsigned char) ( tmpa);
922 teximage->data[ ix * 4 + 1] =
923 (unsigned char) ( tmpa);
924 teximage->data[ ix * 4 + 2] =
925 (unsigned char) ( tmpa);
931 if (! anegative ) /* anegative alread b/w's the whole image */
932 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
933 if (!teximage->data[ ix * 4 + 3])
935 teximage->data[ ix * 4 + 0] =
936 (unsigned char) ( 255.0 * bw_color);
937 teximage->data[ ix * 4 + 1] =
938 (unsigned char) ( 255.0 * bw_color);
939 teximage->data[ ix * 4 + 2] =
940 (unsigned char) ( 255.0 * bw_color);
943 tmpbuf = calloc(teximage->height * teximage->width * 4, sizeof(unsigned char) ) ;
945 /* zero out tmp alpha buffer */
946 for (iy = 0 ; iy <teximage->height * teximage->width * 4 ; iy++)
948 for (cchan = 0; cchan < 4 ; cchan++) {
949 for (iy = 0 ; iy < teximage->height ; iy++) {
950 for (ix = 0 ; ix < teximage->width ; ix++) {
951 dtaidx = (teximage->width * iy + ix) * 4;
952 tmpa = teximage->data[dtaidx + cchan];
953 tmpfa = (float) tmpa * boxdiv;
956 for (by = -boxsize ; by <= boxsize; by++) {
957 for (bx = -boxsize ; bx <= boxsize; bx++) {
958 indx = wrapVal(ix + bx, 0, teximage->width);
959 indy = wrapVal(iy + by, 0, teximage->height);
960 tmpidx = (teximage->width * indy + indx) * 4;
962 tmpbuf[tmpidx + cchan] += (unsigned char) blursum;
968 /* copy back buffer */
969 for (ix = 0 ; ix < teximage->height * teximage->width * 4; ix++)
970 teximage->data[ix] = tmpbuf[ix];
972 free(tmpbuf); /*tidy*/
979 #ifdef HAVE_GLBINDTEXTURE
980 glBindTexture(GL_TEXTURE_2D, texbind);
982 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
983 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height,
984 0, GL_RGBA, GL_UNSIGNED_BYTE, teximage->data);
985 check_gl_error("texture");
987 XDestroyImage(teximage);
990 /* creates cylender for time tunnel. sides, zmin, zmax, rad(ius) obvious.
991 stretch scales texture coords; makes tunnel go slower the larger it is.
992 not drawn, but put into display list. */
993 static void makecyl(int sides, float zmin, float zmax, float rad, float stretch)
1000 glBegin(GL_TRIANGLE_FAN);
1001 glTexCoord2f(1.0, 0.0);
1002 glVertex3f(0.0 , 0.0 , zmax);
1003 for (i = 0 ; i <= sides; i++) {
1004 theta = 2.0 * M_PI * ((float) i / (float) sides);
1005 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1007 glVertex3f(cos(0.0) * rad, sin(0.0) * rad, zmax);
1011 glBegin(GL_QUAD_STRIP);
1012 for (i = 0 ; i <= sides; i++)
1015 theta = 2.0 * M_PI * ((float) i / (float) sides);
1016 glTexCoord2f(0.0, 1.0 * (float) i / (float) sides);
1017 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1018 glTexCoord2f(stretch, 1.0 * (float) i / (float) sides);
1019 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1022 glTexCoord2f(0.0, 1.0);
1023 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1024 glTexCoord2f(stretch, 1.0);
1025 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1032 init_tunnel (ModeInfo *mi)
1036 tunnel_configuration *tc;
1038 wire = MI_IS_WIREFRAME(mi);
1041 tconf = (tunnel_configuration *)
1042 calloc (MI_NUM_SCREENS(mi), sizeof (tunnel_configuration));
1044 fprintf(stderr, "%s: out of memory\n", progname);
1048 tc = &tconf[MI_SCREEN(mi)];
1051 tc = &tconf[MI_SCREEN(mi)];
1053 tc->glx_context = init_GL(mi);
1055 tc->cyllist = glGenLists(1);
1056 tc->diamondlist = glGenLists(1);
1057 tc->num_effects = 12;
1058 tc->num_texshifts = 3;
1059 tc->effect_time = 0.0;
1060 tc->effect_maxsecs = 30.00;
1061 /* check bounds on cmd line opts */
1062 if (start > tc->effect_maxsecs) start = tc->effect_maxsecs;
1063 if (end > tc->effect_maxsecs) end = tc->effect_maxsecs;
1064 if (start < tc->effect_time) start = tc->effect_time;
1065 if (end < tc->effect_time) end = tc->effect_time;
1067 /* set loop times, in seconds */
1068 tc->start_time = start;
1071 /* reset animation knots, effect 0 not defined. */
1072 tc->effects = malloc(sizeof(effect_t) * ( tc->num_effects + 1));
1073 for ( i = 1; i <= tc->num_effects ; i++)
1074 init_effects(&tc->effects[i], i);
1077 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1083 glGenTextures(MAX_TEXTURE, tc->texture_binds);
1085 /*LoadTexture(*mi, **fn, texbind, bluralpha, bw_color, anegative, onealpha)*/
1086 LoadTexture(mi, timetunnel0_xpm, tc->texture_binds[0], 0, 0.0, False, False);
1087 LoadTexture(mi, timetunnel1_xpm, tc->texture_binds[2], 0, 0.0, False, False);
1088 LoadTexture(mi, timetunnel2_xpm, tc->texture_binds[5], 0, 0.0, False, False);
1089 LoadTexture(mi, tunnelstar_xpm, tc->texture_binds[4], 0, 0.0, False, False);
1090 # ifdef GET_SUED_BY_THE_BBC
1092 # endif /* GET_SUED_BY_THE_BBC */
1093 LoadTexture(mi, (char **) logo_180_xpm, tc->texture_binds[3], 0,0.0, False, False);
1094 tc->texture_binds[1] = tc->texture_binds[3];
1095 tc->texture_binds[6] = tc->texture_binds[3];
1096 tc->texture_binds[8] = tc->texture_binds[3];
1098 LoadTexture(mi, (char **) logo_180_xpm, tc->texture_binds[9], 2,1.0, True, True);
1099 # ifdef GET_SUED_BY_THE_BBC
1101 LoadTexture(mi, whologo_xpm, tc->texture_binds[3], 0,0.0, False, False);
1102 LoadTexture(mi, tardis_xpm, tc->texture_binds[1], 0, 0.0 ,False, False);
1103 LoadTexture(mi, whohead1_xpm, tc->texture_binds[6], 0, 1.0, False, False);
1104 /* LoadTexture(mi, whohead_psy_xpm, tc->texture_binds[8], 1, 0.7, False, False); */
1106 LoadTexture(mi, whohead1_xpm, tc->texture_binds[9], 2, 1.0, True, True);
1108 # endif /* GET_SUED_BY_THE_BBC */
1109 glEnable(GL_TEXTURE_2D);
1110 check_gl_error("tex");
1113 reshape_tunnel (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1115 glDisable(GL_DEPTH_TEST); /* who needs it? ;-) */
1122 glEnable(GL_ALPHA_TEST);
1123 glAlphaFunc(GL_GREATER, 0.5);
1126 tc->trackball = gltrackball_init ();
1129 tc->texshift = calloc(tc->num_texshifts, sizeof(GLfloat));
1130 for ( i = 0 ; i < tc->num_texshifts; i++)
1131 tc->texshift[i] = 0.0;
1133 glNewList(tc->cyllist, GL_COMPILE);
1134 makecyl(30, -0.1, CYL_LEN, 1., 10. / 40.0 * CYL_LEN);
1135 /*makecyl(30, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN); */
1138 glNewList(tc->diamondlist, GL_COMPILE);
1139 makecyl(4, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN);
1145 draw_tunnel (ModeInfo *mi)
1147 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
1148 Display *dpy = MI_DISPLAY(mi);
1149 Window window = MI_WINDOW(mi);
1152 if (!tc->glx_context)
1155 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tc->glx_context));
1157 glShadeModel(GL_SMOOTH);
1159 glEnable(GL_NORMALIZE);
1160 /* glEnable(GL_CULL_FACE); */
1162 glClear(GL_COLOR_BUFFER_BIT );
1164 update_animation(tc);
1169 glRotatef(180., 0., 1., 0.);
1170 gltrackball_rotate (tc->trackball);
1171 glRotatef(180., 0., 1., 0.);
1175 mi->polygon_count = 0;
1177 update_fog(tc->effects[4].state[0], /*color*/
1178 tc->effects[4].state[1], /*density*/
1179 tc->effects[4].state[2], /*start*/
1180 tc->effects[4].state[3]); /*end*/
1182 /* --- begin composite image assembly --- */
1184 /* head mask and draw diamond tunnel */
1187 draw_cyl(mi, tc, tc->effects[6].state[0], 5, tc->diamondlist, 2);
1189 draw_sign(mi, tc,tc->effects[12].state[0], tc->effects[12].state[1], 1.0 / 1.33, 9, 1);
1190 glDisable(GL_BLEND);
1191 /* then tardis tunnel */
1192 make_wall_tunnel(mi, tc, tc->effects[1].state[0], tc->effects[7].state[0]);
1194 /* then cylender tunnel */
1196 draw_cyl(mi, tc, tc->effects[3].state[0], 2, tc->cyllist, 1);
1198 /*void draw_sign(mi, tc,z,alpha,aspect,tex,blendmode)*/
1201 draw_sign(mi, tc, tc->effects[2].state[0], tc->effects[2].state[1], 2.0, 1, 0);
1204 draw_sign(mi, tc, tc->effects[5].state[0], tc->effects[5].state[1], 1.0, 3, 0);
1207 draw_sign(mi, tc,1.0, tc->effects[10].state[0], 1.0 / 1.33, 6, 2);
1208 /*who head psychadelic REMOVED*/
1209 /* draw_sign(mi, tc,1.0, tc->effects[11].state[0], 1.0 / 1.33, 8, 0); */
1212 /* draw_sign(mi, tc, tc->effects[8].state[0]tc->effects[8].state[0], 1.0 , 1.0, 4, 1); */
1213 draw_sign(mi, tc, tc->effects[8].state[0], tc->effects[8].state[0], 1.0, 4, 1);
1217 draw_sign(mi, tc,1.0, tc->effects[9].state[0], 1.0 / 1.33, 6, 0);
1219 /* --- end composite image assembly --- */
1224 if (mi->fps_p) do_fps (mi);
1227 check_gl_error("drawing done, calling swap buffers");
1228 glXSwapBuffers(dpy, window);
1231 XSCREENSAVER_MODULE_2 ("TimeTunnel", timetunnel, tunnel)