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 #define GL_GLEXT_PROTOTYPES 1
15 #include <math.h> /* for log2 */
17 #define DEFAULTS "*delay: 30000 \n" \
19 "*showFPS: False \n" \
20 "*timeStart: 0.0 \n" \
21 "*timeEnd: 27.79 \n" \
22 "*wireframe: False \n" \
26 # define refresh_tunnel 0
27 # define release_tunnel 0
29 #define countof(x) (sizeof((x))/sizeof((*x)))
31 #include "xlockmore.h"
34 #include "gltrackball.h"
37 #define DEF_START "0.00"
38 #define DEF_DILATE "1.00"
39 #define DEF_END "27.79"
40 #define DEF_LOCKLOGO "False"
41 #define DEF_DRAWLOGO "True"
42 #define DEF_REVERSE "False"
43 #define DEF_FOG "True"
44 #define DEF_TEXTURE "True"
45 #define MAX_TEXTURE 10
47 #define DIAMOND_LEN 10.0
49 static float start, end, dilate;
50 static Bool do_texture, drawlogo, wire, reverse, do_fog;
51 static const char *do_tx1, *do_tx2, *do_tx3, *do_tun1, *do_tun2, *do_tun3;
53 static XrmOptionDescRec opts[] = {
54 {"-texture" , ".texture", XrmoptionNoArg, "true" },
55 {"+texture" , ".texture", XrmoptionNoArg, "false" },
56 {"-start" , ".start", XrmoptionSepArg, 0 },
57 {"-end" , ".end", XrmoptionSepArg, 0 },
58 {"-dilate" , ".dilate", XrmoptionSepArg, 0 },
59 {"+logo" , ".drawlogo", XrmoptionNoArg, "false" },
60 {"-reverse" , ".reverse", XrmoptionNoArg, "true" },
61 {"+fog" , ".fog", XrmoptionNoArg, "false" },
62 {"-marquee" , ".marquee", XrmoptionSepArg, 0},
63 /* {"+marquee" , ".marquee", XrmoptionNoArg, "(none)"}, */
64 {"-tardis" , ".tardis", XrmoptionSepArg, 0},
65 /* {"+tardis" , ".tardis", XrmoptionNoArg, "(none)"}, */
66 {"-head" , ".head", XrmoptionSepArg, 0},
67 /* {"+head" , ".head", XrmoptionNoArg, "(none)"}, */
68 {"-tun1" , ".tun1", XrmoptionSepArg, 0},
69 /* {"+tun1" , ".tun1", XrmoptionNoArg, "(none)"}, */
70 {"-tun2" , ".tun2", XrmoptionSepArg, 0},
71 /* {"+tun2" , ".tun2", XrmoptionNoArg, "(none)"}, */
72 {"-tun3" , ".tun3", XrmoptionSepArg, 0},
73 /* {"+tun3" , ".tun3", XrmoptionNoArg, "(none)"}, */
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 {&drawlogo, "drawlogo", "DrawLogo", DEF_DRAWLOGO , t_Bool},
82 {&reverse, "reverse", "Reverse", DEF_REVERSE , t_Bool},
83 {&do_fog, "fog", "Fog", DEF_FOG , t_Bool},
84 {&do_tx1, "marquee", "Marquee", "(none)", t_String},
85 {&do_tx2, "tardis", "Tardis", "(none)", t_String},
86 {&do_tx3, "head", "Head", "(none)", t_String},
87 {&do_tun1, "tun1", "Tunnel 1", "(none)", t_String},
88 {&do_tun2, "tun2", "Tunnel 2", "(none)", t_String},
89 {&do_tun3, "tun3", "Tunnel 3", "(none)", t_String},
92 ENTRYPOINT ModeSpecOpt tunnel_opts = {countof(opts), opts, countof(vars), vars, NULL};
93 #include "xpm-ximage.h"
94 #include "images/logo-180.xpm"
95 #include "images/tunnelstar.xpm"
96 #include "images/timetunnel0.xpm"
97 #include "images/timetunnel1.xpm"
98 #include "images/timetunnel2.xpm"
101 #ifdef USE_GL /* whole file */
103 /* ANIMATION CONTROLS */
104 /* an effect is a collection of floating point variables that vary with time.
105 A knot is a timestamp with an array of floats. State is the current values of the floats.
106 State is set by linearly interpolating between knots */
108 float *knots, *state;
109 int numknots, knotwidth;
114 GLXContext *glx_context;
116 trackball_state *trackball;
119 int time_oldusec, time_oldsec;
121 int num_texshifts; /* animates tunnels. Not an effect. */
122 GLfloat pos, *texshift;
124 GLuint texture_binds[MAX_TEXTURE], cyllist, diamondlist;
126 float effect_time, effect_maxsecs; /* global time controls */
127 float start_time, end_time;
130 effect_t *effects; /* array of all effects */
132 } tunnel_configuration;
134 static tunnel_configuration *tconf = NULL;
136 /* allocate memory and populate effect with knot data */
137 static void init_effect(effect_t *e, int numk, int kwidth,
138 float dir, float *data )
143 e->knotwidth = kwidth;
145 e->knots = calloc(numk * kwidth, sizeof(float));
146 e->state = calloc(numk, sizeof(float));
147 for ( i = 0 ; i < e->numknots ; i++)
148 for ( j = 0 ; j < e->knotwidth; j++)
149 e->knots[i * kwidth + j] = data[i * kwidth + j];
152 /* static knot data. each effect is listed and knot data is hard coded.
153 Knots are linerally interpolated to yield float values, depending on
154 knot width. knot format is [time, data, data, data...].
155 Data can be alpha, zvalue, etc. */
156 static void init_effects(effect_t *e, int effectnum)
158 /* effect 1: wall tunnel. percent closed */
166 /* effect 2: tardis. distance and alpha */
176 /* effect 3: cylinder. alpha */
184 /* effect 4: fog. color, density, start, end */
186 {{0.0 , 1.0, 0.45, 3.0, 15.0},
187 {6.40, 1.0, 0.45, 3.0, 14.0},
188 {8.08, 1.0, 0.95, 1.0, 14.0},
189 {15.17, 1.0, 0.95, 1.0, 6.0},
190 {15.51, 1.0, 0.95, 3.0, 8.0},
191 {23.35, 1.0, 0.95, 3.0, 8.0},
192 {24.02, 0.0, 0.95, 2.3, 5.0},
193 {26.02, 0.0, 0.95, 2.3, 5.0},
194 {27.72, 0.0, 1.00, 0.3, 0.9}
197 /* effect 5: logo. dist, alpha */
207 /* effect 6: diamond tunnel. alpha */
213 /* effect 7: tardis cap draw . positive draws cap*/
219 /* effect 8: star/asterisk: alpha */
227 /* effect 9: whohead 1 alpha */
237 /* effect 10: whohead-brite alpha */
244 /* {13.95, 0.00}}; */
246 /* effect 11: whohead-psy alpha */
254 /* effect 12: whohead-silhouette pos-z, alpha */
261 {16.78, 0.1, 0.00} };
263 /* effect 1: wall tunnel */
265 init_effect(e, 6, 2, -0.2, (float *) e1d);
267 /* effect 2: tardisl */
269 init_effect(e, 8, 3, 1.0, (float *) e2d);
271 /* effect 3: cylinder tunnel */
273 init_effect(e, 5, 2, 0.889 , (float *) e3d);
275 /* effect 4: fog color */
277 init_effect(e, 9, 5, 1.0, (float *) e4d);
278 /* effect 5: logo distance, alpha*/
280 init_effect(e, 7, 3, 1.0, (float *) e5d);
281 /* effect 6: diamond tunnel, alpha*/
283 init_effect(e, 3, 2, 0.24 , (float *) e6d);
285 /* effect 7: cap wall tunnel*/
287 init_effect(e, 3, 2, 1.0, (float *) e7d);
289 /* effect 8: asterisk */
291 init_effect(e, 5, 2, 1.0, (float *) e8d);
293 /* effect 9, 10, 11, 12: whoheads */
295 init_effect(e, 5, 2, 1.0, (float *) e9d);
296 if (effectnum == 10 )
297 init_effect(e, 5, 2, 1.0, (float *) e10d);
298 if (effectnum == 11 )
299 init_effect(e, 5, 2, 1.0, (float *) e11d);
300 if (effectnum == 12 )
301 init_effect(e, 6, 3, 1.0, (float *) e12d);
305 /* set fog parameters, controlled by effect */
306 static void update_fog(float color, float density, float start, float end)
310 col[0] = col[1] = col[2] = color;
313 glFogi(GL_FOG_MODE, GL_LINEAR);
314 glFogfv(GL_FOG_COLOR, col);
315 glFogf(GL_FOG_DENSITY, density);
316 glFogf(GL_FOG_START, start);
317 glFogf(GL_FOG_END, end);
320 /* set effect's floating point data values by linearally interpolating
321 between two knots whose times bound the current time: eff_time */
323 static void update_knots(effect_t *e, float eff_time)
326 float timedelta, lowknot, highknot, *curknot, *nextknot;
328 for ( i = 0 ; i < e->numknots ; i++)
329 if (e->knots[i * e->knotwidth] <= eff_time) {
330 if ( i < e->numknots - 1)
331 nextknot = e->knots + (i + 1) * e->knotwidth;
333 /*repeat last knot to carry knot data forward*/
334 nextknot = e->knots + (i) * e->knotwidth;
335 curknot = e->knots + i * e->knotwidth;
336 if (*nextknot - *curknot <= 0.0) timedelta = 1.0;
338 timedelta = (eff_time-*curknot)/(*nextknot-*curknot);
339 if (timedelta > 1.0) timedelta = 1.0;
340 for (j = 1 ; j < e->knotwidth ; j++) {
341 highknot = (float) *(nextknot + j);
342 lowknot = (float) *(curknot + j);
343 e->state[j - 1 ] = lowknot+(highknot-lowknot)*timedelta;
350 /* Window management, etc
353 reshape_tunnel (ModeInfo *mi, int width, int height)
355 GLfloat h = (GLfloat) height / (GLfloat) width;
357 glViewport (0, 0, (GLint) width, (GLint) height);
359 glMatrixMode(GL_PROJECTION);
361 gluPerspective (90.0, 1/h, 0.2, 50.0);
363 glMatrixMode(GL_MODELVIEW);
365 gluLookAt( 0.0, 0.0, 0.3,
369 glClear(GL_COLOR_BUFFER_BIT);
376 tunnel_handle_event (ModeInfo *mi, XEvent *event)
378 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
380 if (event->xany.type == ButtonPress &&
381 event->xbutton.button == Button1)
383 tc->button_down_p = True;
384 gltrackball_start (tc->trackball,
385 event->xbutton.x, event->xbutton.y,
386 MI_WIDTH (mi), MI_HEIGHT (mi));
389 else if (event->xany.type == ButtonRelease &&
390 event->xbutton.button == Button1)
392 tc->button_down_p = False;
395 else if (event->xany.type == ButtonPress &&
396 (event->xbutton.button == Button4 ||
397 event->xbutton.button == Button5))
399 gltrackball_mousewheel (tc->trackball, event->xbutton.button, 10,
400 !!event->xbutton.state);
403 else if (event->xany.type == MotionNotify &&
406 gltrackball_track (tc->trackball,
407 event->xmotion.x, event->xmotion.y,
408 MI_WIDTH (mi), MI_HEIGHT (mi));
415 static void setTexParams(void)
417 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
418 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
419 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
420 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
421 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
424 static void update_animation(tunnel_configuration *tc) {
426 /* time based, of course*/
427 /* shift texture based on elapsed time since previous call*/
430 int elapsed_usecs, elapsed_secs, i;
431 float computed_timeshift;
433 /* get new animation time */
434 gettimeofday(&tv, &tz);
435 elapsed_secs = tv.tv_sec - tc->time_oldsec;
436 elapsed_usecs = tv.tv_usec - tc->time_oldusec;
437 /* store current time */
438 tc->time_oldsec = tv.tv_sec ;
439 tc->time_oldusec = tv.tv_usec;
440 /* elaped time. computed timeshift is tenths of a second */
441 computed_timeshift = (float) (elapsed_secs * 1000000. + elapsed_usecs)/
444 /* calibrate effect time to lie between start and end times */
445 /* loop if time exceeds end time */
447 tc->effect_time -= computed_timeshift / 10.0 * dilate;
449 tc->effect_time += computed_timeshift / 10.0 * dilate;
450 if ( tc->effect_time >= tc->end_time)
451 tc->effect_time = tc->start_time;
452 if ( tc->effect_time < tc->start_time)
453 tc->effect_time = tc->end_time;;
455 /* move texture shifters in effect's direction, e.g. tardis
456 tunnel moves backward, effect 1's direction */
458 tc->texshift[0] -= tc->effects[1].direction * computed_timeshift/ 10.0;
459 tc->texshift[1] -= tc->effects[3].direction * computed_timeshift/ 10.0;
460 tc->texshift[2] -= tc->effects[6].direction * computed_timeshift/ 10.0;
463 tc->texshift[0] += tc->effects[1].direction * computed_timeshift/ 10.0;
464 tc->texshift[1] += tc->effects[3].direction * computed_timeshift/ 10.0;
465 tc->texshift[2] += tc->effects[6].direction * computed_timeshift/ 10.0;
468 /* loop texture shifters if necessary */
469 for ( i = 0 ; i < tc->num_texshifts; i++) {
470 if (tc->texshift[i] > 1.0)
471 tc->texshift[i] -= (int) tc->texshift[i];
472 if (tc->texshift[i]< -1.0)
473 tc->texshift[i] -= (int) tc->texshift[i];
476 /* update effect data with current time. Uses linear interpolation */
477 for ( i = 1 ; i <= tc->num_effects ; i++)
478 update_knots(&tc->effects[i], tc->effect_time);
480 } /*update_animation*/
482 /* draw a textured(tex) quad at a certain depth (z), and certain alpha (alpha),
483 with aspect ratio (aspect), and blending mode (blend_mode) of either adding
484 or subtracting. if alpha is zero or less, nothing happens */
485 static void draw_sign(ModeInfo *mi, tunnel_configuration *tc, float z, float alpha, float aspect,
486 GLuint tex, int blend_mode)
490 mi->polygon_count ++;
491 /* glEnable(GL_BLEND); */
492 glBlendColor(0.0, 0.0, 0.0, alpha);
493 /*glBlendColor(0.0, 0.0, 0.0, 0.0); */
494 if (blend_mode == 1) {
495 glBlendFunc(GL_CONSTANT_ALPHA,
497 glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
498 } else if (blend_mode == 2) {
499 glBlendFunc(GL_CONSTANT_ALPHA,
501 glBlendEquation(GL_FUNC_ADD);
503 glBlendFunc(GL_CONSTANT_ALPHA,
504 GL_ONE_MINUS_CONSTANT_ALPHA);
505 glBlendEquation(GL_FUNC_ADD);
506 } /* blend mode switch */
508 #ifdef HAVE_GLBINDTEXTURE
510 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[tex]);
513 glTexCoord2f(1.0, 0.0);
514 glVertex3f(-1.0 , -1.0 * aspect , z);
515 glTexCoord2f(1.0, 1.0);
516 glVertex3f(-1.0 , 1.0 * aspect , z);
517 glTexCoord2f(0.0, 1.0);
518 glVertex3f(1.0 , 1.0 * aspect , z);
519 glTexCoord2f(0.0, 0.0);
520 glVertex3f(1.0 , -1.0 * aspect , z);
522 if (blend_mode != 0) {
523 glBlendFunc(GL_CONSTANT_ALPHA,
524 GL_ONE_MINUS_CONSTANT_ALPHA);
525 glBlendEquation(GL_FUNC_ADD);
527 /* glDisable(GL_BLEND); */
533 /* draw a time tunnel. used for both cylinder and diamond tunnels.
534 uses texture shifter (indexed by shiftnum) to simulate motion.
535 tunnel does not move, and is acutally a display list. if alpha = 0, skip */
536 static void draw_cyl(ModeInfo *mi, tunnel_configuration *tc, float alpha, int texnum, int listnum, int shiftnum)
539 if (listnum == tc->diamondlist)
540 mi->polygon_count += 4;
541 if (listnum == tc->cyllist)
542 mi->polygon_count += 30;
543 glMatrixMode(GL_TEXTURE);
545 glTranslatef(tc->texshift[shiftnum], 0.0, 0.0);
546 glMatrixMode(GL_MODELVIEW);
547 /* glEnable(GL_BLEND); */
548 glBlendColor(0.0, 0.0, 0.0, alpha);
549 glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
551 #ifdef HAVE_GLBINDTEXTURE
553 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[texnum]);
557 glMatrixMode(GL_TEXTURE);
559 glMatrixMode(GL_MODELVIEW);
560 /* glDisable(GL_BLEND); */
565 /* make tardis type tunnel. Starts as walls and then
566 grows to outline of tardis. percent is how complete
567 tardis outline is. cap is to draw cap for nice fog effects */
569 static void make_wall_tunnel(ModeInfo *mi, tunnel_configuration *tc, float percent, float cap)
571 /* tardis is about 2x1, so wrap tex around, starting at the base*/
579 that's br=bottom right, etc. ttr is top-top-right */
581 float half_floor= 0.08333333333333333,
582 full_wall = 0.33333333333333333;
588 depth=0.3, zdepth=15.0;
589 /* zdepth is how far back tunnel goes */
590 /* depth is tex coord scale. low number = fast texture shifting */
592 float textop, texbot;
599 tr1 = r1 + half_floor;
601 tl1 = tl0 + half_floor;
605 glMatrixMode(GL_TEXTURE);
607 glRotatef(90.0, 0.0, 0.0, 1.0);
608 glTranslatef(tc->texshift[0], 0.0, 0.0);
609 glMatrixMode(GL_MODELVIEW);
611 #ifdef HAVE_GLBINDTEXTURE
613 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[0]);
615 glColor3f(1.0, 1.0, 0.0);
616 if (cap > 0.0 && percent > 0.0 && drawlogo && do_fog) {
617 mi->polygon_count += 6;
618 glBegin(GL_TRIANGLE_FAN);
619 glVertex3f(0.0, 0.0, zdepth);
620 glVertex3f(-1.0, -2.0, zdepth);
621 glVertex3f(1.0, -2.0, zdepth);
622 glVertex3f(1.0, 2.0, zdepth);
623 glVertex3f(0.2, 2.0, zdepth);
624 glVertex3f(0.2, 2.2, zdepth);
625 glVertex3f(-0.2, 2.2, zdepth);
626 glVertex3f(-0.2, 2.0, zdepth);
627 glVertex3f(-1.0, 2.0, zdepth);
628 glVertex3f(-1.0, -2.0, zdepth);
631 if (percent > ( full_wall * 2.0)) {
634 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
635 if (height > 1.0) height = 1.0;
639 mi->polygon_count += 2;
640 if ( height > 0.90) {
641 mi->polygon_count += 2;
644 textop = tr0 + half_floor * height;
645 glTexCoord2f(0.0, texbot);
646 glVertex3f(0.2, 2.2, 0.0);
648 glTexCoord2f(0.0, textop);
649 glVertex3f(2.0 - height * 2.0, 2.2, 0.0);
651 glTexCoord2f(depth, textop);
652 glVertex3f(2.0 - height * 2.0, 2.2, zdepth);
654 glTexCoord2f(depth, texbot);
655 glVertex3f(0.2, 2.2, zdepth);
658 texbot = tl1 - half_floor * height;
660 glTexCoord2f(0.0, texbot);
661 glVertex3f(-2.0 + height * 2.0, 2.2, 0.0);
663 glTexCoord2f(0.0, textop);
664 glVertex3f(-0.2, 2.2, 0.0);
666 glTexCoord2f(depth, textop);
667 glVertex3f(-0.2, 2.2, zdepth);
669 glTexCoord2f(depth, texbot);
670 glVertex3f(-2.0 + height * 2.0, 2.2, zdepth);
672 if (height > 0.90) height = 0.90;
676 textop = tr0 + half_floor * height;
677 glTexCoord2f(0.0, texbot);
678 glVertex3f(0.2, 2.0, 0.0);
680 glTexCoord2f(0.0, textop);
681 glVertex3f(0.2, 0.4 + height * 2.0, 0.0);
683 glTexCoord2f(depth, textop);
684 glVertex3f(0.2, 0.4 + height * 2.0, zdepth);
686 glTexCoord2f(depth, texbot);
687 glVertex3f(0.2, 2.0, zdepth);
690 texbot = tl1 - half_floor * height;
692 glTexCoord2f(0.0, texbot);
693 /*glVertex3f(-.2, 2.0 + (0.9 - height) * 2.0, 0.0); */
694 glVertex3f(-.2, 0.4 + height * 2.0, 0.0);
696 glTexCoord2f(0.0, textop);
697 glVertex3f(-.2, 2.0, 0.0);
699 glTexCoord2f(depth, textop);
700 glVertex3f(-.2, 2.0, zdepth);
702 glTexCoord2f(depth, texbot);
703 glVertex3f(-.2, 0.4 + height * 2.0, zdepth);
706 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
707 if (height > 0.8) height = 0.8;
710 mi->polygon_count += 2;
713 textop = tr0 + half_floor * height;
714 glTexCoord2f(0.0, texbot);
715 glVertex3f(1.0, 2.0, 0.0);
717 glTexCoord2f(0.0, textop);
718 glVertex3f(1.0 - height, 2.0, 0.0);
720 glTexCoord2f(depth, textop);
721 glVertex3f(1.0 - height, 2.0, zdepth);
723 glTexCoord2f(depth, texbot);
724 glVertex3f(1.0, 2.0, zdepth);
727 texbot = tl1 - half_floor * height;
729 glTexCoord2f(0.0, texbot);
730 glVertex3f(-1.0 + height, 2.0, 0.0);
732 glTexCoord2f(0.0, textop);
733 glVertex3f(-1.0, 2.0, 0.0);
735 glTexCoord2f(depth, textop);
736 glVertex3f(-1.0, 2.0, zdepth);
738 glTexCoord2f(depth, texbot);
739 glVertex3f(-1.0 + height, 2.0, zdepth);
741 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
743 if (height > 1.0) height = 1.0;
746 mi->polygon_count += 2;
749 textop = tr0 + half_floor * height;
750 glTexCoord2f(0.0, texbot);
751 glVertex3f(1.0, -2.0, 0.0);
753 glTexCoord2f(0.0, textop);
754 glVertex3f(1.0 - height, -2.0, 0.0);
756 glTexCoord2f(depth, textop);
757 glVertex3f(1.0 - height, -2.0, zdepth);
759 glTexCoord2f(depth, texbot);
760 glVertex3f(1.0, -2.0, zdepth);
763 texbot = tl1 - half_floor * height;
765 glTexCoord2f(0.0, texbot);
766 glVertex3f(-1.0 + height, -2.0, 0.0);
768 glTexCoord2f(0.0, textop);
769 glVertex3f(-1.0, -2.0, 0.0);
771 glTexCoord2f(depth, textop);
772 glVertex3f(-1.0, -2.0, zdepth);
774 glTexCoord2f(depth, texbot);
775 glVertex3f(-1.0 + height, -2.0, zdepth);
782 mi->polygon_count += 2;
784 height = percent / ( full_wall * 2.0);
785 if (height > 1.0) height = 1.0;
786 textop = (l0 + l1) / 2.0 - full_wall * 0.5 * height;
787 texbot = (l0 + l1) / 2.0 + full_wall * 0.5 * height;
789 glTexCoord2f(0.0, textop);
790 glVertex3f(-1.0, height * 2, 0.0);
792 glTexCoord2f(0.0, texbot);
793 glVertex3f(-1.0, -height * 2, 0.0);
795 glTexCoord2f(depth, texbot);
796 glVertex3f(-1.0, -height * 2, zdepth);
798 glTexCoord2f(depth, textop);
799 glVertex3f(-1.0, height * 2, zdepth);
801 textop = (r0 + r1) / 2.0 - full_wall * 0.5 * height;
802 texbot = (r0 + r1) / 2.0 + full_wall * 0.5 * height;
804 glTexCoord2f(0.0, texbot);
805 glVertex3f(1.0, height * 2, 0.0);
807 glTexCoord2f(0.0, textop);
808 glVertex3f(1.0, -height * 2, 0.0);
810 glTexCoord2f(depth, textop);
811 glVertex3f(1.0, -height * 2, zdepth);
813 glTexCoord2f(depth, texbot);
814 glVertex3f(1.0, height * 2, zdepth);
819 glMatrixMode(GL_TEXTURE);
821 glMatrixMode(GL_MODELVIEW);
822 } /* make_wall_tunnel */
824 /* wraps an int to between min and max.
825 Kind of like the remainder when devided by (max - min).
826 Used to create torus mapping on square array */
827 static int wrapVal(int val, int min, int max)
833 ret = min + (val - max ) % (max - min);
835 ret = max - (min - val) % (max - min);
839 /*=================== Load Texture =========================================*/
840 /* ripped from atunnel.c, Copyright (c) E. Lassauge, 2003-2004. */
841 /* modified like so by Sean Brennan:
842 take texture object for glbind
845 blur color / alpha channel [3x3 box filter, done [blur] times
846 anegative : create b/w image from zero alpha. zero alpha gets bw_color,
847 nonzero alpha gets 1.0 - bwcolor, then alpha flipped to 1-alpha.
849 Inputs: xpm structure, or filename of xmp image. if filename == NULL, use structure.
850 Outputs: texture bound to texutre Id texbind.
854 static float mylog2(float x) { return ( log(x) / log(2));}
856 static void LoadTexture(ModeInfo * mi, char **fn, const char *filename, GLuint 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);
875 teximage = xpm_file_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
876 MI_COLORMAP(mi), filename);
878 teximage = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
879 MI_COLORMAP(mi), fn);
880 if (teximage == NULL) {
881 fprintf(stderr, "%s: error reading the texture.\n", progname);
882 glDeleteTextures(1, &texbind);
887 /* check if image is 2^kumquat, where kumquat is an integer between 1 and 10. Recale to
888 nearest power of 2. */
889 tmpfa = mylog2((float) teximage->width);
890 bx = 2 << (int) (tmpfa -1);
891 if (bx != teximage->width) {
893 if ((tmpfa - (int) tmpfa) > 0.5849)
896 tmpfa = mylog2((float) teximage->height);
897 by = 2 << (int) (tmpfa - 1);
898 if (by != teximage->height) {
900 if ((tmpfa - (int) tmpfa) > 0.5849)
905 tmpbuf = calloc(bx * by * 4, sizeof(unsigned char));
906 if (gluScaleImage(GL_RGBA, teximage->width, teximage->height, GL_UNSIGNED_BYTE, teximage->data,
907 bx, by, GL_UNSIGNED_BYTE, tmpbuf))
908 check_gl_error("scale image");
910 free(teximage->data);
911 teximage->data = (char *) tmpbuf;
912 teximage->width = bx;
913 teximage->height= by;
915 /* end rescale code */
918 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
920 if (!teximage->data[ ix * 4 + 3]) {
921 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
922 tmpa = (unsigned char) (bw_color * 0xff);
925 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
927 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff -
928 teximage->data[ ix * 4 + 3];
929 tmpa = (unsigned char) ((1.0 - bw_color) * 0xff);
931 /* make texture uniform b/w color */
932 teximage->data[ ix * 4 + 0] =
933 (unsigned char) ( tmpa);
934 teximage->data[ ix * 4 + 1] =
935 (unsigned char) ( tmpa);
936 teximage->data[ ix * 4 + 2] =
937 (unsigned char) ( tmpa);
943 if (! anegative ) /* anegative alread b/w's the whole image */
944 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
945 if (!teximage->data[ ix * 4 + 3])
947 teximage->data[ ix * 4 + 0] =
948 (unsigned char) ( 255.0 * bw_color);
949 teximage->data[ ix * 4 + 1] =
950 (unsigned char) ( 255.0 * bw_color);
951 teximage->data[ ix * 4 + 2] =
952 (unsigned char) ( 255.0 * bw_color);
955 tmpbuf = calloc(teximage->height * teximage->width * 4, sizeof(unsigned char) ) ;
957 /* zero out tmp alpha buffer */
958 for (iy = 0 ; iy <teximage->height * teximage->width * 4 ; iy++)
960 for (cchan = 0; cchan < 4 ; cchan++) {
961 for (iy = 0 ; iy < teximage->height ; iy++) {
962 for (ix = 0 ; ix < teximage->width ; ix++) {
963 dtaidx = (teximage->width * iy + ix) * 4;
964 tmpa = teximage->data[dtaidx + cchan];
965 tmpfa = (float) tmpa * boxdiv;
967 for (by = -boxsize ; by <= boxsize; by++) {
968 for (bx = -boxsize ; bx <= boxsize; bx++) {
969 indx = wrapVal(ix + bx, 0, teximage->width);
970 indy = wrapVal(iy + by, 0, teximage->height);
971 tmpidx = (teximage->width * indy + indx) * 4;
973 tmpbuf[tmpidx + cchan] += (unsigned char) blursum;
979 /* copy back buffer */
980 for (ix = 0 ; ix < teximage->height * teximage->width * 4; ix++)
981 teximage->data[ix] = tmpbuf[ix];
983 free(tmpbuf); /*tidy*/
990 #ifdef HAVE_GLBINDTEXTURE
991 glBindTexture(GL_TEXTURE_2D, texbind);
992 clear_gl_error(); /* WTF? sometimes "invalid op" from glBindTexture! */
994 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
995 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height,
996 0, GL_RGBA, GL_UNSIGNED_BYTE, teximage->data);
997 check_gl_error("texture");
999 XDestroyImage(teximage);
1002 /* creates cylinder for time tunnel. sides, zmin, zmax, rad(ius) obvious.
1003 stretch scales texture coords; makes tunnel go slower the larger it is.
1004 not drawn, but put into display list. */
1005 static void makecyl(int sides, float zmin, float zmax, float rad, float stretch)
1012 glBegin(GL_TRIANGLE_FAN);
1013 glTexCoord2f(1.0, 0.0);
1014 glVertex3f(0.0 , 0.0 , zmax);
1015 for (i = 0 ; i <= sides; i++) {
1016 theta = 2.0 * M_PI * ((float) i / (float) sides);
1017 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1019 glVertex3f(cos(0.0) * rad, sin(0.0) * rad, zmax);
1023 glBegin(GL_QUAD_STRIP);
1024 for (i = 0 ; i <= sides; i++)
1027 theta = 2.0 * M_PI * ((float) i / (float) sides);
1028 glTexCoord2f(0.0, 1.0 * (float) i / (float) sides);
1029 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1030 glTexCoord2f(stretch, 1.0 * (float) i / (float) sides);
1031 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1034 glTexCoord2f(0.0, 1.0);
1035 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1036 glTexCoord2f(stretch, 1.0);
1037 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1044 init_tunnel (ModeInfo *mi)
1048 tunnel_configuration *tc;
1050 wire = MI_IS_WIREFRAME(mi);
1053 tconf = (tunnel_configuration *)
1054 calloc (MI_NUM_SCREENS(mi), sizeof (tunnel_configuration));
1056 fprintf(stderr, "%s: out of memory\n", progname);
1061 tc = &tconf[MI_SCREEN(mi)];
1063 tc->glx_context = init_GL(mi);
1065 tc->cyllist = glGenLists(1);
1066 tc->diamondlist = glGenLists(1);
1067 tc->num_effects = 12;
1068 tc->num_texshifts = 3;
1069 tc->effect_time = 0.0;
1070 tc->effect_maxsecs = 30.00;
1071 /* check bounds on cmd line opts */
1072 if (start > tc->effect_maxsecs) start = tc->effect_maxsecs;
1073 if (end > tc->effect_maxsecs) end = tc->effect_maxsecs;
1074 if (start < tc->effect_time) start = tc->effect_time;
1075 if (end < tc->effect_time) end = tc->effect_time;
1077 /* set loop times, in seconds */
1078 tc->start_time = start;
1081 /* reset animation knots, effect 0 not defined. */
1082 tc->effects = malloc(sizeof(effect_t) * ( tc->num_effects + 1));
1083 for ( i = 1; i <= tc->num_effects ; i++)
1084 init_effects(&tc->effects[i], i);
1087 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1093 /* the following textures are loaded, and possible overridden:
1094 tunnel 1, tunnel 2, tunnel 3, marquee, tardis, head */
1095 glGenTextures(MAX_TEXTURE, tc->texture_binds);
1097 /*LoadTexture(*mi, **fn, *filename, texbind, bluralpha, bw_color, anegative, onealpha)*/
1098 if (strcasecmp (do_tun1, "(none)")) /* tunnel 1 */
1099 LoadTexture(mi, NULL, do_tun1, tc->texture_binds[0], 0,0.0, False, False);
1101 LoadTexture(mi, timetunnel0_xpm, NULL, tc->texture_binds[0], 0, 0.0, False, False);
1102 if (strcasecmp (do_tun2, "(none)")) /* tunnel 2 */
1103 LoadTexture(mi, NULL, do_tun2, tc->texture_binds[2], 0,0.0, False, False);
1105 LoadTexture(mi, timetunnel1_xpm, NULL, tc->texture_binds[2], 0, 0.0, False, False);
1106 if (strcasecmp (do_tun3, "(none)")) /* tunnel 3 */
1107 LoadTexture(mi, NULL, do_tun3, tc->texture_binds[5], 0,0.0, False, False);
1109 LoadTexture(mi, timetunnel2_xpm, NULL, tc->texture_binds[5], 0, 0.0, False, False);
1110 LoadTexture(mi, tunnelstar_xpm, NULL, tc->texture_binds[4], 0, 0.0, False, False);
1111 if (strcasecmp (do_tx1, "(none)")) /* marquee */
1112 LoadTexture(mi, NULL, do_tx1, tc->texture_binds[3], 0,0.0, False, False);
1114 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[3], 0,0.0, False, False);
1115 if (strcasecmp (do_tx2, "(none)")) /* tardis */
1116 LoadTexture(mi, NULL, do_tx2, tc->texture_binds[1], 0, 0.0 ,False, False);
1118 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[1], 0,0.0, False, False);
1119 if (strcasecmp (do_tx3, "(none)")) { /* head */
1120 LoadTexture(mi, NULL, do_tx3, tc->texture_binds[6], 0, 0.0 ,False, False);
1122 LoadTexture(mi, NULL, do_tx3, tc->texture_binds[9], 2,1.0, True, True);
1124 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[6], 0,0.0, False, False);
1126 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[9], 2,1.0, True, True);
1128 glEnable(GL_TEXTURE_2D);
1129 check_gl_error("tex");
1132 reshape_tunnel (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1134 glDisable(GL_DEPTH_TEST); /* who needs it? ;-) */
1141 glEnable(GL_ALPHA_TEST);
1142 glAlphaFunc(GL_GREATER, 0.5);
1145 tc->trackball = gltrackball_init ();
1148 tc->texshift = calloc(tc->num_texshifts, sizeof(GLfloat));
1149 for ( i = 0 ; i < tc->num_texshifts; i++)
1150 tc->texshift[i] = 0.0;
1152 glNewList(tc->cyllist, GL_COMPILE);
1153 makecyl(30, -0.1, CYL_LEN, 1., 10. / 40.0 * CYL_LEN);
1154 /*makecyl(30, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN); */
1157 glNewList(tc->diamondlist, GL_COMPILE);
1158 makecyl(4, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN);
1164 draw_tunnel (ModeInfo *mi)
1166 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
1167 Display *dpy = MI_DISPLAY(mi);
1168 Window window = MI_WINDOW(mi);
1171 if (!tc->glx_context)
1174 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tc->glx_context));
1176 glShadeModel(GL_SMOOTH);
1178 glEnable(GL_NORMALIZE);
1179 /* glEnable(GL_CULL_FACE); */
1181 glClear(GL_COLOR_BUFFER_BIT );
1183 update_animation(tc);
1188 glRotatef(180., 0., 1., 0.);
1189 gltrackball_rotate (tc->trackball);
1190 glRotatef(180., 0., 1., 0.);
1194 mi->polygon_count = 0;
1196 update_fog(tc->effects[4].state[0], /*color*/
1197 tc->effects[4].state[1], /*density*/
1198 tc->effects[4].state[2], /*start*/
1199 tc->effects[4].state[3]); /*end*/
1201 /* --- begin composite image assembly --- */
1203 /* head mask and draw diamond tunnel */
1206 draw_cyl(mi, tc, tc->effects[6].state[0], 5, tc->diamondlist, 2);
1208 draw_sign(mi, tc,tc->effects[12].state[0], tc->effects[12].state[1], 1.0 / 1.33, 9, 1);
1209 glDisable(GL_BLEND);
1210 /* then tardis tunnel */
1211 make_wall_tunnel(mi, tc, tc->effects[1].state[0], tc->effects[7].state[0]);
1213 /* then cylinder tunnel */
1215 draw_cyl(mi, tc, tc->effects[3].state[0], 2, tc->cyllist, 1);
1217 /*void draw_sign(mi, tc,z,alpha,aspect,tex,blendmode)*/
1220 draw_sign(mi, tc, tc->effects[2].state[0], tc->effects[2].state[1], 2.0, 1, 0);
1223 draw_sign(mi, tc, tc->effects[5].state[0], tc->effects[5].state[1], 1.0, 3, 0);
1226 draw_sign(mi, tc,1.0, tc->effects[10].state[0], 1.0 / 1.33, 6, 2);
1227 /*who head psychadelic REMOVED*/
1228 /* draw_sign(mi, tc,1.0, tc->effects[11].state[0], 1.0 / 1.33, 8, 0); */
1231 /* draw_sign(mi, tc, tc->effects[8].state[0]tc->effects[8].state[0], 1.0 , 1.0, 4, 1); */
1232 draw_sign(mi, tc, tc->effects[8].state[0], tc->effects[8].state[0], 1.0, 4, 1);
1236 draw_sign(mi, tc,1.0, tc->effects[9].state[0], 1.0 / 1.33, 6, 0);
1238 /* --- end composite image assembly --- */
1243 if (mi->fps_p) do_fps (mi);
1246 check_gl_error("drawing done, calling swap buffers");
1247 glXSwapBuffers(dpy, window);
1250 XSCREENSAVER_MODULE_2 ("TimeTunnel", timetunnel, tunnel)