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);
993 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
994 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height,
995 0, GL_RGBA, GL_UNSIGNED_BYTE, teximage->data);
996 check_gl_error("texture");
998 XDestroyImage(teximage);
1001 /* creates cylinder for time tunnel. sides, zmin, zmax, rad(ius) obvious.
1002 stretch scales texture coords; makes tunnel go slower the larger it is.
1003 not drawn, but put into display list. */
1004 static void makecyl(int sides, float zmin, float zmax, float rad, float stretch)
1011 glBegin(GL_TRIANGLE_FAN);
1012 glTexCoord2f(1.0, 0.0);
1013 glVertex3f(0.0 , 0.0 , zmax);
1014 for (i = 0 ; i <= sides; i++) {
1015 theta = 2.0 * M_PI * ((float) i / (float) sides);
1016 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1018 glVertex3f(cos(0.0) * rad, sin(0.0) * rad, zmax);
1022 glBegin(GL_QUAD_STRIP);
1023 for (i = 0 ; i <= sides; i++)
1026 theta = 2.0 * M_PI * ((float) i / (float) sides);
1027 glTexCoord2f(0.0, 1.0 * (float) i / (float) sides);
1028 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1029 glTexCoord2f(stretch, 1.0 * (float) i / (float) sides);
1030 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1033 glTexCoord2f(0.0, 1.0);
1034 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1035 glTexCoord2f(stretch, 1.0);
1036 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1043 init_tunnel (ModeInfo *mi)
1047 tunnel_configuration *tc;
1049 wire = MI_IS_WIREFRAME(mi);
1052 tconf = (tunnel_configuration *)
1053 calloc (MI_NUM_SCREENS(mi), sizeof (tunnel_configuration));
1055 fprintf(stderr, "%s: out of memory\n", progname);
1060 tc = &tconf[MI_SCREEN(mi)];
1062 tc->glx_context = init_GL(mi);
1064 tc->cyllist = glGenLists(1);
1065 tc->diamondlist = glGenLists(1);
1066 tc->num_effects = 12;
1067 tc->num_texshifts = 3;
1068 tc->effect_time = 0.0;
1069 tc->effect_maxsecs = 30.00;
1070 /* check bounds on cmd line opts */
1071 if (start > tc->effect_maxsecs) start = tc->effect_maxsecs;
1072 if (end > tc->effect_maxsecs) end = tc->effect_maxsecs;
1073 if (start < tc->effect_time) start = tc->effect_time;
1074 if (end < tc->effect_time) end = tc->effect_time;
1076 /* set loop times, in seconds */
1077 tc->start_time = start;
1080 /* reset animation knots, effect 0 not defined. */
1081 tc->effects = malloc(sizeof(effect_t) * ( tc->num_effects + 1));
1082 for ( i = 1; i <= tc->num_effects ; i++)
1083 init_effects(&tc->effects[i], i);
1086 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1092 /* the following textures are loaded, and possible overridden:
1093 tunnel 1, tunnel 2, tunnel 3, marquee, tardis, head */
1094 glGenTextures(MAX_TEXTURE, tc->texture_binds);
1096 /*LoadTexture(*mi, **fn, *filename, texbind, bluralpha, bw_color, anegative, onealpha)*/
1097 if (strcasecmp (do_tun1, "(none)")) /* tunnel 1 */
1098 LoadTexture(mi, NULL, do_tun1, tc->texture_binds[0], 0,0.0, False, False);
1100 LoadTexture(mi, timetunnel0_xpm, NULL, tc->texture_binds[0], 0, 0.0, False, False);
1101 if (strcasecmp (do_tun2, "(none)")) /* tunnel 2 */
1102 LoadTexture(mi, NULL, do_tun2, tc->texture_binds[2], 0,0.0, False, False);
1104 LoadTexture(mi, timetunnel1_xpm, NULL, tc->texture_binds[2], 0, 0.0, False, False);
1105 if (strcasecmp (do_tun3, "(none)")) /* tunnel 3 */
1106 LoadTexture(mi, NULL, do_tun3, tc->texture_binds[5], 0,0.0, False, False);
1108 LoadTexture(mi, timetunnel2_xpm, NULL, tc->texture_binds[5], 0, 0.0, False, False);
1109 LoadTexture(mi, tunnelstar_xpm, NULL, tc->texture_binds[4], 0, 0.0, False, False);
1110 if (strcasecmp (do_tx1, "(none)")) /* marquee */
1111 LoadTexture(mi, NULL, do_tx1, tc->texture_binds[3], 0,0.0, False, False);
1113 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[3], 0,0.0, False, False);
1114 if (strcasecmp (do_tx2, "(none)")) /* tardis */
1115 LoadTexture(mi, NULL, do_tx2, tc->texture_binds[1], 0, 0.0 ,False, False);
1117 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[1], 0,0.0, False, False);
1118 if (strcasecmp (do_tx3, "(none)")) { /* head */
1119 LoadTexture(mi, NULL, do_tx3, tc->texture_binds[6], 0, 0.0 ,False, False);
1121 LoadTexture(mi, NULL, do_tx3, tc->texture_binds[9], 2,1.0, True, True);
1123 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[6], 0,0.0, False, False);
1125 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[9], 2,1.0, True, True);
1127 glEnable(GL_TEXTURE_2D);
1128 check_gl_error("tex");
1131 reshape_tunnel (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1133 glDisable(GL_DEPTH_TEST); /* who needs it? ;-) */
1140 glEnable(GL_ALPHA_TEST);
1141 glAlphaFunc(GL_GREATER, 0.5);
1144 tc->trackball = gltrackball_init ();
1147 tc->texshift = calloc(tc->num_texshifts, sizeof(GLfloat));
1148 for ( i = 0 ; i < tc->num_texshifts; i++)
1149 tc->texshift[i] = 0.0;
1151 glNewList(tc->cyllist, GL_COMPILE);
1152 makecyl(30, -0.1, CYL_LEN, 1., 10. / 40.0 * CYL_LEN);
1153 /*makecyl(30, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN); */
1156 glNewList(tc->diamondlist, GL_COMPILE);
1157 makecyl(4, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN);
1163 draw_tunnel (ModeInfo *mi)
1165 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
1166 Display *dpy = MI_DISPLAY(mi);
1167 Window window = MI_WINDOW(mi);
1170 if (!tc->glx_context)
1173 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tc->glx_context));
1175 glShadeModel(GL_SMOOTH);
1177 glEnable(GL_NORMALIZE);
1178 /* glEnable(GL_CULL_FACE); */
1180 glClear(GL_COLOR_BUFFER_BIT );
1182 update_animation(tc);
1187 glRotatef(180., 0., 1., 0.);
1188 gltrackball_rotate (tc->trackball);
1189 glRotatef(180., 0., 1., 0.);
1193 mi->polygon_count = 0;
1195 update_fog(tc->effects[4].state[0], /*color*/
1196 tc->effects[4].state[1], /*density*/
1197 tc->effects[4].state[2], /*start*/
1198 tc->effects[4].state[3]); /*end*/
1200 /* --- begin composite image assembly --- */
1202 /* head mask and draw diamond tunnel */
1205 draw_cyl(mi, tc, tc->effects[6].state[0], 5, tc->diamondlist, 2);
1207 draw_sign(mi, tc,tc->effects[12].state[0], tc->effects[12].state[1], 1.0 / 1.33, 9, 1);
1208 glDisable(GL_BLEND);
1209 /* then tardis tunnel */
1210 make_wall_tunnel(mi, tc, tc->effects[1].state[0], tc->effects[7].state[0]);
1212 /* then cylinder tunnel */
1214 draw_cyl(mi, tc, tc->effects[3].state[0], 2, tc->cyllist, 1);
1216 /*void draw_sign(mi, tc,z,alpha,aspect,tex,blendmode)*/
1219 draw_sign(mi, tc, tc->effects[2].state[0], tc->effects[2].state[1], 2.0, 1, 0);
1222 draw_sign(mi, tc, tc->effects[5].state[0], tc->effects[5].state[1], 1.0, 3, 0);
1225 draw_sign(mi, tc,1.0, tc->effects[10].state[0], 1.0 / 1.33, 6, 2);
1226 /*who head psychadelic REMOVED*/
1227 /* draw_sign(mi, tc,1.0, tc->effects[11].state[0], 1.0 / 1.33, 8, 0); */
1230 /* draw_sign(mi, tc, tc->effects[8].state[0]tc->effects[8].state[0], 1.0 , 1.0, 4, 1); */
1231 draw_sign(mi, tc, tc->effects[8].state[0], tc->effects[8].state[0], 1.0, 4, 1);
1235 draw_sign(mi, tc,1.0, tc->effects[9].state[0], 1.0 / 1.33, 6, 0);
1237 /* --- end composite image assembly --- */
1242 if (mi->fps_p) do_fps (mi);
1245 check_gl_error("drawing done, calling swap buffers");
1246 glXSwapBuffers(dpy, window);
1249 XSCREENSAVER_MODULE_2 ("TimeTunnel", timetunnel, tunnel)