1 /* timetunnel. Based on dangerball.c, hack by Sean Brennan <zettix@yahoo.com>*/
2 /* dangerball, Copyright (c) 2001-2018 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 free_tunnel 0
27 # define release_tunnel 0
29 #define countof(x) (sizeof((x))/sizeof((*x)))
31 #include "xlockmore.h"
34 #include "gltrackball.h"
36 #define DEF_START "0.00"
37 #define DEF_DILATE "1.00"
38 #define DEF_END "27.79"
39 #define DEF_LOCKLOGO "False"
40 #define DEF_DRAWLOGO "True"
41 #define DEF_REVERSE "False"
42 #define DEF_FOG "True"
43 #define DEF_TEXTURE "True"
44 #define MAX_TEXTURE 10
46 #define DIAMOND_LEN 10.0
48 static float start, end, dilate;
49 static Bool do_texture, drawlogo, wire, reverse, do_fog;
50 static const char *do_tx1, *do_tx2, *do_tx3, *do_tun1, *do_tun2, *do_tun3;
52 static XrmOptionDescRec opts[] = {
53 {"-texture" , ".texture", XrmoptionNoArg, "true" },
54 {"+texture" , ".texture", XrmoptionNoArg, "false" },
55 {"-start" , ".start", XrmoptionSepArg, 0 },
56 {"-end" , ".end", XrmoptionSepArg, 0 },
57 {"-dilate" , ".dilate", XrmoptionSepArg, 0 },
58 {"+logo" , ".drawlogo", XrmoptionNoArg, "false" },
59 {"-reverse" , ".reverse", XrmoptionNoArg, "true" },
60 {"+fog" , ".fog", XrmoptionNoArg, "false" },
61 {"-marquee" , ".marquee", XrmoptionSepArg, 0},
62 /* {"+marquee" , ".marquee", XrmoptionNoArg, "(none)"}, */
63 {"-tardis" , ".tardis", XrmoptionSepArg, 0},
64 /* {"+tardis" , ".tardis", XrmoptionNoArg, "(none)"}, */
65 {"-head" , ".head", XrmoptionSepArg, 0},
66 /* {"+head" , ".head", XrmoptionNoArg, "(none)"}, */
67 {"-tun1" , ".tun1", XrmoptionSepArg, 0},
68 /* {"+tun1" , ".tun1", XrmoptionNoArg, "(none)"}, */
69 {"-tun2" , ".tun2", XrmoptionSepArg, 0},
70 /* {"+tun2" , ".tun2", XrmoptionNoArg, "(none)"}, */
71 {"-tun3" , ".tun3", XrmoptionSepArg, 0},
72 /* {"+tun3" , ".tun3", XrmoptionNoArg, "(none)"}, */
75 static argtype vars[] = {
76 {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
77 {&start, "start", "Start", DEF_START, t_Float},
78 {&end, "end", "End", DEF_END , t_Float},
79 {&dilate, "dilate", "Dilate", DEF_DILATE , t_Float},
80 {&drawlogo, "drawlogo", "DrawLogo", DEF_DRAWLOGO , t_Bool},
81 {&reverse, "reverse", "Reverse", DEF_REVERSE , t_Bool},
82 {&do_fog, "fog", "Fog", DEF_FOG , t_Bool},
83 {&do_tx1, "marquee", "Marquee", "(none)", t_String},
84 {&do_tx2, "tardis", "Tardis", "(none)", t_String},
85 {&do_tx3, "head", "Head", "(none)", t_String},
86 {&do_tun1, "tun1", "Tunnel 1", "(none)", t_String},
87 {&do_tun2, "tun2", "Tunnel 2", "(none)", t_String},
88 {&do_tun3, "tun3", "Tunnel 3", "(none)", t_String},
91 ENTRYPOINT ModeSpecOpt tunnel_opts = {countof(opts), opts, countof(vars), vars, NULL};
92 #include "ximage-loader.h"
93 #include "images/gen/logo-180_png.h"
94 #include "images/gen/tunnelstar_png.h"
95 #include "images/gen/timetunnel0_png.h"
96 #include "images/gen/timetunnel1_png.h"
97 #include "images/gen/timetunnel2_png.h"
100 #ifdef USE_GL /* whole file */
102 /* ANIMATION CONTROLS */
103 /* an effect is a collection of floating point variables that vary with time.
104 A knot is a timestamp with an array of floats. State is the current values of the floats.
105 State is set by linearly interpolating between knots */
107 float *knots, *state;
108 int numknots, knotwidth;
113 GLXContext *glx_context;
115 trackball_state *trackball;
118 int time_oldusec, time_oldsec;
120 int num_texshifts; /* animates tunnels. Not an effect. */
121 GLfloat pos, *texshift;
123 GLuint texture_binds[MAX_TEXTURE], cyllist, diamondlist;
125 float effect_time, effect_maxsecs; /* global time controls */
126 float start_time, end_time;
129 effect_t *effects; /* array of all effects */
131 } tunnel_configuration;
133 static tunnel_configuration *tconf = NULL;
135 /* allocate memory and populate effect with knot data */
136 static void init_effect(effect_t *e, int numk, int kwidth,
137 float dir, float *data )
142 e->knotwidth = kwidth;
144 e->knots = calloc(numk * kwidth, sizeof(float));
145 e->state = calloc(numk, sizeof(float));
146 for ( i = 0 ; i < e->numknots ; i++)
147 for ( j = 0 ; j < e->knotwidth; j++)
148 e->knots[i * kwidth + j] = data[i * kwidth + j];
151 /* static knot data. each effect is listed and knot data is hard coded.
152 Knots are linerally interpolated to yield float values, depending on
153 knot width. knot format is [time, data, data, data...].
154 Data can be alpha, zvalue, etc. */
155 static void init_effects(effect_t *e, int effectnum)
157 /* effect 1: wall tunnel. percent closed */
165 /* effect 2: tardis. distance and alpha */
175 /* effect 3: cylinder. alpha */
183 /* effect 4: fog. color, density, start, end */
185 {{0.0 , 1.0, 0.45, 3.0, 15.0},
186 {6.40, 1.0, 0.45, 3.0, 14.0},
187 {8.08, 1.0, 0.95, 1.0, 14.0},
188 {15.17, 1.0, 0.95, 1.0, 6.0},
189 {15.51, 1.0, 0.95, 3.0, 8.0},
190 {23.35, 1.0, 0.95, 3.0, 8.0},
191 {24.02, 0.0, 0.95, 2.3, 5.0},
192 {26.02, 0.0, 0.95, 2.3, 5.0},
193 {27.72, 0.0, 1.00, 0.3, 0.9}
196 /* effect 5: logo. dist, alpha */
206 /* effect 6: diamond tunnel. alpha */
212 /* effect 7: tardis cap draw . positive draws cap*/
218 /* effect 8: star/asterisk: alpha */
226 /* effect 9: whohead 1 alpha */
236 /* effect 10: whohead-brite alpha */
243 /* {13.95, 0.00}}; */
245 /* effect 11: whohead-psy alpha */
253 /* effect 12: whohead-silhouette pos-z, alpha */
260 {16.78, 0.1, 0.00} };
262 /* effect 1: wall tunnel */
264 init_effect(e, 6, 2, -0.2, (float *) e1d);
266 /* effect 2: tardisl */
268 init_effect(e, 8, 3, 1.0, (float *) e2d);
270 /* effect 3: cylinder tunnel */
272 init_effect(e, 5, 2, 0.889 , (float *) e3d);
274 /* effect 4: fog color */
276 init_effect(e, 9, 5, 1.0, (float *) e4d);
277 /* effect 5: logo distance, alpha*/
279 init_effect(e, 7, 3, 1.0, (float *) e5d);
280 /* effect 6: diamond tunnel, alpha*/
282 init_effect(e, 3, 2, 0.24 , (float *) e6d);
284 /* effect 7: cap wall tunnel*/
286 init_effect(e, 3, 2, 1.0, (float *) e7d);
288 /* effect 8: asterisk */
290 init_effect(e, 5, 2, 1.0, (float *) e8d);
292 /* effect 9, 10, 11, 12: whoheads */
294 init_effect(e, 5, 2, 1.0, (float *) e9d);
295 if (effectnum == 10 )
296 init_effect(e, 5, 2, 1.0, (float *) e10d);
297 if (effectnum == 11 )
298 init_effect(e, 5, 2, 1.0, (float *) e11d);
299 if (effectnum == 12 )
300 init_effect(e, 6, 3, 1.0, (float *) e12d);
304 /* set fog parameters, controlled by effect */
305 static void update_fog(float color, float density, float start, float end)
309 col[0] = col[1] = col[2] = color;
312 glFogi(GL_FOG_MODE, GL_LINEAR);
313 glFogfv(GL_FOG_COLOR, col);
314 glFogf(GL_FOG_DENSITY, density);
315 glFogf(GL_FOG_START, start);
316 glFogf(GL_FOG_END, end);
319 /* set effect's floating point data values by linearally interpolating
320 between two knots whose times bound the current time: eff_time */
322 static void update_knots(effect_t *e, float eff_time)
325 float timedelta, lowknot, highknot, *curknot, *nextknot;
327 for ( i = 0 ; i < e->numknots ; i++)
328 if (e->knots[i * e->knotwidth] <= eff_time) {
329 if ( i < e->numknots - 1)
330 nextknot = e->knots + (i + 1) * e->knotwidth;
332 /*repeat last knot to carry knot data forward*/
333 nextknot = e->knots + (i) * e->knotwidth;
334 curknot = e->knots + i * e->knotwidth;
335 if (*nextknot - *curknot <= 0.0) timedelta = 1.0;
337 timedelta = (eff_time-*curknot)/(*nextknot-*curknot);
338 if (timedelta > 1.0) timedelta = 1.0;
339 for (j = 1 ; j < e->knotwidth ; j++) {
340 highknot = (float) *(nextknot + j);
341 lowknot = (float) *(curknot + j);
342 e->state[j - 1 ] = lowknot+(highknot-lowknot)*timedelta;
349 /* Window management, etc
352 reshape_tunnel (ModeInfo *mi, int width, int height)
354 GLfloat h = (GLfloat) height / (GLfloat) width;
357 if (width > height * 5) { /* tiny window: show middle */
358 height = width * 9/16;
360 h = height / (GLfloat) width;
363 glViewport (0, y, (GLint) width, (GLint) height);
365 glMatrixMode(GL_PROJECTION);
367 gluPerspective (90.0, 1/h, 0.2, 50.0);
369 glMatrixMode(GL_MODELVIEW);
371 gluLookAt( 0.0, 0.0, 0.3,
375 glClear(GL_COLOR_BUFFER_BIT);
382 tunnel_handle_event (ModeInfo *mi, XEvent *event)
384 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
386 if (gltrackball_event_handler (event, tc->trackball,
387 MI_WIDTH (mi), MI_HEIGHT (mi),
394 static void setTexParams(void)
396 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
397 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
398 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
399 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
400 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
403 static void update_animation(tunnel_configuration *tc) {
405 /* time based, of course*/
406 /* shift texture based on elapsed time since previous call*/
409 int elapsed_usecs, elapsed_secs, i;
410 float computed_timeshift;
412 /* get new animation time */
413 gettimeofday(&tv, &tz);
414 elapsed_secs = tv.tv_sec - tc->time_oldsec;
415 elapsed_usecs = tv.tv_usec - tc->time_oldusec;
416 /* store current time */
417 tc->time_oldsec = tv.tv_sec ;
418 tc->time_oldusec = tv.tv_usec;
419 /* elaped time. computed timeshift is tenths of a second */
420 computed_timeshift = (float) (elapsed_secs * 1000000. + elapsed_usecs)/
423 /* calibrate effect time to lie between start and end times */
424 /* loop if time exceeds end time */
426 tc->effect_time -= computed_timeshift / 10.0 * dilate;
428 tc->effect_time += computed_timeshift / 10.0 * dilate;
429 if ( tc->effect_time >= tc->end_time)
430 tc->effect_time = tc->start_time;
431 if ( tc->effect_time < tc->start_time)
432 tc->effect_time = tc->end_time;;
434 /* move texture shifters in effect's direction, e.g. tardis
435 tunnel moves backward, effect 1's direction */
437 tc->texshift[0] -= tc->effects[1].direction * computed_timeshift/ 10.0;
438 tc->texshift[1] -= tc->effects[3].direction * computed_timeshift/ 10.0;
439 tc->texshift[2] -= tc->effects[6].direction * computed_timeshift/ 10.0;
442 tc->texshift[0] += tc->effects[1].direction * computed_timeshift/ 10.0;
443 tc->texshift[1] += tc->effects[3].direction * computed_timeshift/ 10.0;
444 tc->texshift[2] += tc->effects[6].direction * computed_timeshift/ 10.0;
447 /* loop texture shifters if necessary */
448 for ( i = 0 ; i < tc->num_texshifts; i++) {
449 if (tc->texshift[i] > 1.0)
450 tc->texshift[i] -= (int) tc->texshift[i];
451 if (tc->texshift[i]< -1.0)
452 tc->texshift[i] -= (int) tc->texshift[i];
455 /* update effect data with current time. Uses linear interpolation */
456 for ( i = 1 ; i <= tc->num_effects ; i++)
457 update_knots(&tc->effects[i], tc->effect_time);
459 } /*update_animation*/
461 /* draw a textured(tex) quad at a certain depth (z), and certain alpha (alpha),
462 with aspect ratio (aspect), and blending mode (blend_mode) of either adding
463 or subtracting. if alpha is zero or less, nothing happens */
464 static void draw_sign(ModeInfo *mi, tunnel_configuration *tc, float z, float alpha, float aspect,
465 GLuint tex, int blend_mode)
470 mi->polygon_count ++;
471 /* glEnable(GL_BLEND); */
472 glBlendColor(0.0, 0.0, 0.0, alpha);
473 /*glBlendColor(0.0, 0.0, 0.0, 0.0); */
474 if (blend_mode == 1) {
475 glBlendFunc(GL_CONSTANT_ALPHA,
477 glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
478 } else if (blend_mode == 2) {
479 glBlendFunc(GL_CONSTANT_ALPHA,
481 glBlendEquation(GL_FUNC_ADD);
483 glBlendFunc(GL_CONSTANT_ALPHA,
484 GL_ONE_MINUS_CONSTANT_ALPHA);
485 glBlendEquation(GL_FUNC_ADD);
486 } /* blend mode switch */
488 #ifdef HAVE_GLBINDTEXTURE
490 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[tex]);
493 glTexCoord2f(1.0, 0.0);
494 glVertex3f(-1.0 , -1.0 * aspect , z);
495 glTexCoord2f(1.0, 1.0);
496 glVertex3f(-1.0 , 1.0 * aspect , z);
497 glTexCoord2f(0.0, 1.0);
498 glVertex3f(1.0 , 1.0 * aspect , z);
499 glTexCoord2f(0.0, 0.0);
500 glVertex3f(1.0 , -1.0 * aspect , z);
502 if (blend_mode != 0) {
503 glBlendFunc(GL_CONSTANT_ALPHA,
504 GL_ONE_MINUS_CONSTANT_ALPHA);
505 glBlendEquation(GL_FUNC_ADD);
507 /* glDisable(GL_BLEND); */
510 #endif /* !HAVE_JWZGLES */
514 /* draw a time tunnel. used for both cylinder and diamond tunnels.
515 uses texture shifter (indexed by shiftnum) to simulate motion.
516 tunnel does not move, and is acutally a display list. if alpha = 0, skip */
517 static void draw_cyl(ModeInfo *mi, tunnel_configuration *tc, float alpha, int texnum, int listnum, int shiftnum)
521 if (listnum == tc->diamondlist)
522 mi->polygon_count += 4;
523 if (listnum == tc->cyllist)
524 mi->polygon_count += 30;
525 glMatrixMode(GL_TEXTURE);
527 glTranslatef(tc->texshift[shiftnum], 0.0, 0.0);
528 glMatrixMode(GL_MODELVIEW);
529 /* glEnable(GL_BLEND); */
530 glBlendColor(0.0, 0.0, 0.0, alpha);
531 glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
533 #ifdef HAVE_GLBINDTEXTURE
535 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[texnum]);
539 glMatrixMode(GL_TEXTURE);
541 glMatrixMode(GL_MODELVIEW);
542 /* glDisable(GL_BLEND); */
544 #endif /* HAVE_JWZGLES */
548 /* make tardis type tunnel. Starts as walls and then
549 grows to outline of tardis. percent is how complete
550 tardis outline is. cap is to draw cap for nice fog effects */
552 static void make_wall_tunnel(ModeInfo *mi, tunnel_configuration *tc, float percent, float cap)
554 /* tardis is about 2x1, so wrap tex around, starting at the base*/
562 that's br=bottom right, etc. ttr is top-top-right */
564 float half_floor= 0.08333333333333333,
565 full_wall = 0.33333333333333333;
571 depth=0.3, zdepth=15.0;
572 /* zdepth is how far back tunnel goes */
573 /* depth is tex coord scale. low number = fast texture shifting */
575 float textop, texbot;
582 tr1 = r1 + half_floor;
584 tl1 = tl0 + half_floor;
588 glMatrixMode(GL_TEXTURE);
590 glRotatef(90.0, 0.0, 0.0, 1.0);
591 glTranslatef(tc->texshift[0], 0.0, 0.0);
592 glMatrixMode(GL_MODELVIEW);
594 #ifdef HAVE_GLBINDTEXTURE
596 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[0]);
598 glColor3f(1.0, 1.0, 0.0);
599 if (cap > 0.0 && percent > 0.0 && drawlogo && do_fog) {
600 mi->polygon_count += 6;
601 glBegin(GL_TRIANGLE_FAN);
602 glVertex3f(0.0, 0.0, zdepth);
603 glVertex3f(-1.0, -2.0, zdepth);
604 glVertex3f(1.0, -2.0, zdepth);
605 glVertex3f(1.0, 2.0, zdepth);
606 glVertex3f(0.2, 2.0, zdepth);
607 glVertex3f(0.2, 2.2, zdepth);
608 glVertex3f(-0.2, 2.2, zdepth);
609 glVertex3f(-0.2, 2.0, zdepth);
610 glVertex3f(-1.0, 2.0, zdepth);
611 glVertex3f(-1.0, -2.0, zdepth);
614 if (percent > ( full_wall * 2.0)) {
617 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
618 if (height > 1.0) height = 1.0;
622 mi->polygon_count += 2;
623 if ( height > 0.90) {
624 mi->polygon_count += 2;
627 textop = tr0 + half_floor * height;
628 glTexCoord2f(0.0, texbot);
629 glVertex3f(0.2, 2.2, 0.0);
631 glTexCoord2f(0.0, textop);
632 glVertex3f(2.0 - height * 2.0, 2.2, 0.0);
634 glTexCoord2f(depth, textop);
635 glVertex3f(2.0 - height * 2.0, 2.2, zdepth);
637 glTexCoord2f(depth, texbot);
638 glVertex3f(0.2, 2.2, zdepth);
641 texbot = tl1 - half_floor * height;
643 glTexCoord2f(0.0, texbot);
644 glVertex3f(-2.0 + height * 2.0, 2.2, 0.0);
646 glTexCoord2f(0.0, textop);
647 glVertex3f(-0.2, 2.2, 0.0);
649 glTexCoord2f(depth, textop);
650 glVertex3f(-0.2, 2.2, zdepth);
652 glTexCoord2f(depth, texbot);
653 glVertex3f(-2.0 + height * 2.0, 2.2, zdepth);
655 if (height > 0.90) height = 0.90;
659 textop = tr0 + half_floor * height;
660 glTexCoord2f(0.0, texbot);
661 glVertex3f(0.2, 2.0, 0.0);
663 glTexCoord2f(0.0, textop);
664 glVertex3f(0.2, 0.4 + height * 2.0, 0.0);
666 glTexCoord2f(depth, textop);
667 glVertex3f(0.2, 0.4 + height * 2.0, zdepth);
669 glTexCoord2f(depth, texbot);
670 glVertex3f(0.2, 2.0, zdepth);
673 texbot = tl1 - half_floor * height;
675 glTexCoord2f(0.0, texbot);
676 /*glVertex3f(-.2, 2.0 + (0.9 - height) * 2.0, 0.0); */
677 glVertex3f(-.2, 0.4 + height * 2.0, 0.0);
679 glTexCoord2f(0.0, textop);
680 glVertex3f(-.2, 2.0, 0.0);
682 glTexCoord2f(depth, textop);
683 glVertex3f(-.2, 2.0, zdepth);
685 glTexCoord2f(depth, texbot);
686 glVertex3f(-.2, 0.4 + height * 2.0, zdepth);
689 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
690 if (height > 0.8) height = 0.8;
693 mi->polygon_count += 2;
696 textop = tr0 + half_floor * height;
697 glTexCoord2f(0.0, texbot);
698 glVertex3f(1.0, 2.0, 0.0);
700 glTexCoord2f(0.0, textop);
701 glVertex3f(1.0 - height, 2.0, 0.0);
703 glTexCoord2f(depth, textop);
704 glVertex3f(1.0 - height, 2.0, zdepth);
706 glTexCoord2f(depth, texbot);
707 glVertex3f(1.0, 2.0, zdepth);
710 texbot = tl1 - half_floor * height;
712 glTexCoord2f(0.0, texbot);
713 glVertex3f(-1.0 + height, 2.0, 0.0);
715 glTexCoord2f(0.0, textop);
716 glVertex3f(-1.0, 2.0, 0.0);
718 glTexCoord2f(depth, textop);
719 glVertex3f(-1.0, 2.0, zdepth);
721 glTexCoord2f(depth, texbot);
722 glVertex3f(-1.0 + height, 2.0, zdepth);
724 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
726 if (height > 1.0) height = 1.0;
729 mi->polygon_count += 2;
732 textop = tr0 + half_floor * height;
733 glTexCoord2f(0.0, texbot);
734 glVertex3f(1.0, -2.0, 0.0);
736 glTexCoord2f(0.0, textop);
737 glVertex3f(1.0 - height, -2.0, 0.0);
739 glTexCoord2f(depth, textop);
740 glVertex3f(1.0 - height, -2.0, zdepth);
742 glTexCoord2f(depth, texbot);
743 glVertex3f(1.0, -2.0, zdepth);
746 texbot = tl1 - half_floor * height;
748 glTexCoord2f(0.0, texbot);
749 glVertex3f(-1.0 + height, -2.0, 0.0);
751 glTexCoord2f(0.0, textop);
752 glVertex3f(-1.0, -2.0, 0.0);
754 glTexCoord2f(depth, textop);
755 glVertex3f(-1.0, -2.0, zdepth);
757 glTexCoord2f(depth, texbot);
758 glVertex3f(-1.0 + height, -2.0, zdepth);
765 mi->polygon_count += 2;
767 height = percent / ( full_wall * 2.0);
768 if (height > 1.0) height = 1.0;
769 textop = (l0 + l1) / 2.0 - full_wall * 0.5 * height;
770 texbot = (l0 + l1) / 2.0 + full_wall * 0.5 * height;
772 glTexCoord2f(0.0, textop);
773 glVertex3f(-1.0, height * 2, 0.0);
775 glTexCoord2f(0.0, texbot);
776 glVertex3f(-1.0, -height * 2, 0.0);
778 glTexCoord2f(depth, texbot);
779 glVertex3f(-1.0, -height * 2, zdepth);
781 glTexCoord2f(depth, textop);
782 glVertex3f(-1.0, height * 2, zdepth);
784 textop = (r0 + r1) / 2.0 - full_wall * 0.5 * height;
785 texbot = (r0 + r1) / 2.0 + full_wall * 0.5 * height;
787 glTexCoord2f(0.0, texbot);
788 glVertex3f(1.0, height * 2, 0.0);
790 glTexCoord2f(0.0, textop);
791 glVertex3f(1.0, -height * 2, 0.0);
793 glTexCoord2f(depth, textop);
794 glVertex3f(1.0, -height * 2, zdepth);
796 glTexCoord2f(depth, texbot);
797 glVertex3f(1.0, height * 2, zdepth);
802 glMatrixMode(GL_TEXTURE);
804 glMatrixMode(GL_MODELVIEW);
805 } /* make_wall_tunnel */
807 /* wraps an int to between min and max.
808 Kind of like the remainder when devided by (max - min).
809 Used to create torus mapping on square array */
810 static int wrapVal(int val, int min, int max)
816 ret = min + (val - max ) % (max - min);
818 ret = max - (min - val) % (max - min);
822 /*=================== Load Texture =========================================*/
823 /* ripped from atunnel.c, Copyright (c) E. Lassauge, 2003-2004. */
824 /* modified like so by Sean Brennan:
825 take texture object for glbind
828 blur color / alpha channel [3x3 box filter, done [blur] times
829 anegative : create b/w image from zero alpha. zero alpha gets bw_color,
830 nonzero alpha gets 1.0 - bwcolor, then alpha flipped to 1-alpha.
832 Inputs: xpm structure, or filename of xmp image. if filename == NULL, use structure.
833 Outputs: texture bound to texutre Id texbind.
837 static float mylog2(float x) { return ( log(x) / log(2));}
839 static void LoadTexture(ModeInfo * mi, const unsigned char *fn, unsigned long size, const char *filename, GLuint texbind, int blur, float bw_color, Bool anegative, Bool onealpha)
841 /* looping and temporary array index variables */
842 int ix, iy, bx, by, indx, indy, boxsize, cchan, tmpidx, dtaidx;
844 float boxdiv, tmpfa, blursum ;
845 unsigned char *tmpbuf, tmpa;
849 XImage *teximage; /* Texture data */
854 boxdiv = 1.0 / ( boxsize * 2.0 + 1.0) / ( boxsize * 2.0 + 1.0);
858 teximage = file_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
861 teximage = image_data_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
863 if (teximage == NULL) {
864 fprintf(stderr, "%s: error reading the texture.\n", progname);
865 glDeleteTextures(1, &texbind);
870 /* check if image is 2^kumquat, where kumquat is an integer between 1 and 10. Recale to
871 nearest power of 2. */
872 tmpfa = mylog2((float) teximage->width);
873 bx = 2 << (int) (tmpfa -1);
874 if (bx != teximage->width) {
876 if ((tmpfa - (int) tmpfa) > 0.5849)
879 tmpfa = mylog2((float) teximage->height);
880 by = 2 << (int) (tmpfa - 1);
881 if (by != teximage->height) {
883 if ((tmpfa - (int) tmpfa) > 0.5849)
889 tmpbuf = calloc(bx * by * 4, sizeof(unsigned char));
890 if (gluScaleImage(GL_RGBA, teximage->width, teximage->height, GL_UNSIGNED_BYTE, teximage->data,
891 bx, by, GL_UNSIGNED_BYTE, tmpbuf))
892 check_gl_error("scale image");
894 free(teximage->data);
895 teximage->data = (char *) tmpbuf;
896 teximage->width = bx;
897 teximage->height= by;
898 #endif /* !HAVE_JWZGLES */
900 /* end rescale code */
903 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
905 if (!teximage->data[ ix * 4 + 3]) {
906 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
907 tmpa = (unsigned char) (bw_color * 0xff);
910 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
912 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff -
913 teximage->data[ ix * 4 + 3];
914 tmpa = (unsigned char) ((1.0 - bw_color) * 0xff);
916 /* make texture uniform b/w color */
917 teximage->data[ ix * 4 + 0] =
918 (unsigned char) ( tmpa);
919 teximage->data[ ix * 4 + 1] =
920 (unsigned char) ( tmpa);
921 teximage->data[ ix * 4 + 2] =
922 (unsigned char) ( tmpa);
928 if (! anegative ) /* anegative alread b/w's the whole image */
929 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
930 if (!teximage->data[ ix * 4 + 3])
932 teximage->data[ ix * 4 + 0] =
933 (unsigned char) ( 255.0 * bw_color);
934 teximage->data[ ix * 4 + 1] =
935 (unsigned char) ( 255.0 * bw_color);
936 teximage->data[ ix * 4 + 2] =
937 (unsigned char) ( 255.0 * bw_color);
940 tmpbuf = calloc(teximage->height * teximage->width * 4, sizeof(unsigned char) ) ;
942 /* zero out tmp alpha buffer */
943 for (iy = 0 ; iy <teximage->height * teximage->width * 4 ; iy++)
945 for (cchan = 0; cchan < 4 ; cchan++) {
946 for (iy = 0 ; iy < teximage->height ; iy++) {
947 for (ix = 0 ; ix < teximage->width ; ix++) {
948 dtaidx = (teximage->width * iy + ix) * 4;
949 tmpa = teximage->data[dtaidx + cchan];
950 tmpfa = (float) tmpa * boxdiv;
952 for (by = -boxsize ; by <= boxsize; by++) {
953 for (bx = -boxsize ; bx <= boxsize; bx++) {
954 indx = wrapVal(ix + bx, 0, teximage->width);
955 indy = wrapVal(iy + by, 0, teximage->height);
956 tmpidx = (teximage->width * indy + indx) * 4;
958 tmpbuf[tmpidx + cchan] += (unsigned char) blursum;
964 /* copy back buffer */
965 for (ix = 0 ; ix < teximage->height * teximage->width * 4; ix++)
966 teximage->data[ix] = tmpbuf[ix];
968 free(tmpbuf); /*tidy*/
975 #ifdef HAVE_GLBINDTEXTURE
976 glBindTexture(GL_TEXTURE_2D, texbind);
977 clear_gl_error(); /* WTF? sometimes "invalid op" from glBindTexture! */
979 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
980 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height,
981 0, GL_RGBA, GL_UNSIGNED_BYTE, teximage->data);
982 check_gl_error("texture");
984 XDestroyImage(teximage);
987 /* creates cylinder for time tunnel. sides, zmin, zmax, rad(ius) obvious.
988 stretch scales texture coords; makes tunnel go slower the larger it is.
989 not drawn, but put into display list. */
990 static void makecyl(int sides, float zmin, float zmax, float rad, float stretch)
997 glBegin(GL_TRIANGLE_FAN);
998 glTexCoord2f(1.0, 0.0);
999 glVertex3f(0.0 , 0.0 , zmax);
1000 for (i = 0 ; i <= sides; i++) {
1001 theta = 2.0 * M_PI * ((float) i / (float) sides);
1002 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1004 glVertex3f(cos(0.0) * rad, sin(0.0) * rad, zmax);
1008 glBegin(GL_QUAD_STRIP);
1009 for (i = 0 ; i <= sides; i++)
1012 theta = 2.0 * M_PI * ((float) i / (float) sides);
1013 glTexCoord2f(0.0, 1.0 * (float) i / (float) sides);
1014 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1015 glTexCoord2f(stretch, 1.0 * (float) i / (float) sides);
1016 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1019 glTexCoord2f(0.0, 1.0);
1020 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1021 glTexCoord2f(stretch, 1.0);
1022 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1029 init_tunnel (ModeInfo *mi)
1033 tunnel_configuration *tc;
1035 wire = MI_IS_WIREFRAME(mi);
1037 # ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
1041 MI_INIT (mi, tconf);
1043 tc = &tconf[MI_SCREEN(mi)];
1045 tc->glx_context = init_GL(mi);
1047 tc->cyllist = glGenLists(1);
1048 tc->diamondlist = glGenLists(1);
1049 tc->num_effects = 12;
1050 tc->num_texshifts = 3;
1051 tc->effect_time = 0.0;
1052 tc->effect_maxsecs = 30.00;
1053 /* check bounds on cmd line opts */
1054 if (start > tc->effect_maxsecs) start = tc->effect_maxsecs;
1055 if (end > tc->effect_maxsecs) end = tc->effect_maxsecs;
1056 if (start < tc->effect_time) start = tc->effect_time;
1057 if (end < tc->effect_time) end = tc->effect_time;
1059 /* set loop times, in seconds */
1060 tc->start_time = start;
1063 /* reset animation knots, effect 0 not defined. */
1064 tc->effects = malloc(sizeof(effect_t) * ( tc->num_effects + 1));
1065 for ( i = 1; i <= tc->num_effects ; i++)
1066 init_effects(&tc->effects[i], i);
1069 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1075 /* the following textures are loaded, and possible overridden:
1076 tunnel 1, tunnel 2, tunnel 3, marquee, tardis, head */
1077 glGenTextures(MAX_TEXTURE, tc->texture_binds);
1079 /*LoadTexture(*mi, *data, size, *filename, texbind, bluralpha, bw_color, anegative, onealpha)*/
1080 if (strcasecmp (do_tun1, "(none)")) /* tunnel 1 */
1081 LoadTexture(mi, NULL, 0, do_tun1, tc->texture_binds[0], 0,0.0, False, False);
1083 LoadTexture(mi, timetunnel0_png, sizeof(timetunnel0_png), NULL, tc->texture_binds[0], 0, 0.0, False, False);
1084 if (strcasecmp (do_tun2, "(none)")) /* tunnel 2 */
1085 LoadTexture(mi, NULL, 0, do_tun2, tc->texture_binds[2], 0,0.0, False, False);
1087 LoadTexture(mi, timetunnel1_png, sizeof(timetunnel1_png), NULL, tc->texture_binds[2], 0, 0.0, False, False);
1088 if (strcasecmp (do_tun3, "(none)")) /* tunnel 3 */
1089 LoadTexture(mi, NULL, 0, do_tun3, tc->texture_binds[5], 0,0.0, False, False);
1091 LoadTexture(mi, timetunnel2_png, sizeof(timetunnel2_png), NULL, tc->texture_binds[5], 0, 0.0, False, False);
1092 LoadTexture(mi, tunnelstar_png, sizeof(tunnelstar_png), NULL, tc->texture_binds[4], 0, 0.0, False, False);
1093 if (strcasecmp (do_tx1, "(none)")) /* marquee */
1094 LoadTexture(mi, NULL, 0, do_tx1, tc->texture_binds[3], 0,0.0, False, False);
1095 #ifndef HAVE_JWZGLES /* logo_180_png is 180px which is not a power of 2! */
1097 LoadTexture(mi, logo_180_png, sizeof(logo_180_png), NULL, tc->texture_binds[3], 0,0.0, False, False);
1099 if (strcasecmp (do_tx2, "(none)")) /* tardis */
1100 LoadTexture(mi, NULL, 0, do_tx2, tc->texture_binds[1], 0, 0.0 ,False, False);
1101 #ifndef HAVE_JWZGLES /* logo_180_png is 180px which is not a power of 2! */
1103 LoadTexture(mi, logo_180_png, sizeof(logo_180_png), NULL, tc->texture_binds[1], 0,0.0, False, False);
1105 if (strcasecmp (do_tx3, "(none)")) { /* head */
1106 LoadTexture(mi, NULL, 0, do_tx3, tc->texture_binds[6], 0, 0.0 ,False, False);
1108 LoadTexture(mi, NULL, 0, do_tx3, tc->texture_binds[9], 2,1.0, True, True);
1109 #ifndef HAVE_JWZGLES /* logo_180_png is 180px which is not a power of 2! */
1111 LoadTexture(mi, logo_180_png, sizeof(logo_180_png), NULL, tc->texture_binds[6], 0,0.0, False, False);
1113 LoadTexture(mi, logo_180_png, sizeof(logo_180_png), NULL, tc->texture_binds[9], 2,1.0, True, True);
1116 glEnable(GL_TEXTURE_2D);
1117 check_gl_error("tex");
1120 reshape_tunnel (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1122 glDisable(GL_DEPTH_TEST); /* who needs it? ;-) */
1129 glEnable(GL_ALPHA_TEST);
1130 glAlphaFunc(GL_GREATER, 0.5);
1133 tc->trackball = gltrackball_init (True);
1136 tc->texshift = calloc(tc->num_texshifts, sizeof(GLfloat));
1137 for ( i = 0 ; i < tc->num_texshifts; i++)
1138 tc->texshift[i] = 0.0;
1140 glNewList(tc->cyllist, GL_COMPILE);
1141 makecyl(30, -0.1, CYL_LEN, 1., 10. / 40.0 * CYL_LEN);
1142 /*makecyl(30, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN); */
1145 glNewList(tc->diamondlist, GL_COMPILE);
1146 makecyl(4, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN);
1152 draw_tunnel (ModeInfo *mi)
1154 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
1155 Display *dpy = MI_DISPLAY(mi);
1156 Window window = MI_WINDOW(mi);
1159 if (!tc->glx_context)
1162 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tc->glx_context));
1164 glShadeModel(GL_SMOOTH);
1166 glEnable(GL_NORMALIZE);
1167 /* glEnable(GL_CULL_FACE); */
1169 glClear(GL_COLOR_BUFFER_BIT );
1171 update_animation(tc);
1176 glRotatef(180., 0., 1., 0.);
1177 gltrackball_rotate (tc->trackball);
1178 glRotatef(180., 0., 1., 0.);
1182 mi->polygon_count = 0;
1184 update_fog(tc->effects[4].state[0], /*color*/
1185 tc->effects[4].state[1], /*density*/
1186 tc->effects[4].state[2], /*start*/
1187 tc->effects[4].state[3]); /*end*/
1189 /* --- begin composite image assembly --- */
1191 /* head mask and draw diamond tunnel */
1194 draw_cyl(mi, tc, tc->effects[6].state[0], 5, tc->diamondlist, 2);
1196 draw_sign(mi, tc,tc->effects[12].state[0], tc->effects[12].state[1], 1.0 / 1.33, 9, 1);
1197 glDisable(GL_BLEND);
1198 /* then tardis tunnel */
1199 make_wall_tunnel(mi, tc, tc->effects[1].state[0], tc->effects[7].state[0]);
1201 /* then cylinder tunnel */
1203 draw_cyl(mi, tc, tc->effects[3].state[0], 2, tc->cyllist, 1);
1205 /*void draw_sign(mi, tc,z,alpha,aspect,tex,blendmode)*/
1208 draw_sign(mi, tc, tc->effects[2].state[0], tc->effects[2].state[1], 2.0, 1, 0);
1211 draw_sign(mi, tc, tc->effects[5].state[0], tc->effects[5].state[1], 1.0, 3, 0);
1214 draw_sign(mi, tc,1.0, tc->effects[10].state[0], 1.0 / 1.33, 6, 2);
1215 /*who head psychadelic REMOVED*/
1216 /* draw_sign(mi, tc,1.0, tc->effects[11].state[0], 1.0 / 1.33, 8, 0); */
1219 /* draw_sign(mi, tc, tc->effects[8].state[0]tc->effects[8].state[0], 1.0 , 1.0, 4, 1); */
1220 draw_sign(mi, tc, tc->effects[8].state[0], tc->effects[8].state[0], 1.0, 4, 1);
1224 draw_sign(mi, tc,1.0, tc->effects[9].state[0], 1.0 / 1.33, 6, 0);
1226 /* --- end composite image assembly --- */
1231 if (mi->fps_p) do_fps (mi);
1234 check_gl_error("drawing done, calling swap buffers");
1235 glXSwapBuffers(dpy, window);
1238 XSCREENSAVER_MODULE_2 ("TimeTunnel", timetunnel, tunnel)