1 /* timetunnel. Based on dangerball.c, hack by Sean Brennan <zettix@yahoo.com>*/
2 /* dangerball, Copyright (c) 2001-2014 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"
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 "xpm-ximage.h"
93 #include "images/logo-180.xpm"
94 #include "images/tunnelstar.xpm"
95 #include "images/timetunnel0.xpm"
96 #include "images/timetunnel1.xpm"
97 #include "images/timetunnel2.xpm"
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;
356 glViewport (0, 0, (GLint) width, (GLint) height);
358 glMatrixMode(GL_PROJECTION);
360 gluPerspective (90.0, 1/h, 0.2, 50.0);
362 glMatrixMode(GL_MODELVIEW);
364 gluLookAt( 0.0, 0.0, 0.3,
368 glClear(GL_COLOR_BUFFER_BIT);
375 tunnel_handle_event (ModeInfo *mi, XEvent *event)
377 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
379 if (gltrackball_event_handler (event, tc->trackball,
380 MI_WIDTH (mi), MI_HEIGHT (mi),
387 static void setTexParams(void)
389 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
390 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
391 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
392 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
393 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
396 static void update_animation(tunnel_configuration *tc) {
398 /* time based, of course*/
399 /* shift texture based on elapsed time since previous call*/
402 int elapsed_usecs, elapsed_secs, i;
403 float computed_timeshift;
405 /* get new animation time */
406 gettimeofday(&tv, &tz);
407 elapsed_secs = tv.tv_sec - tc->time_oldsec;
408 elapsed_usecs = tv.tv_usec - tc->time_oldusec;
409 /* store current time */
410 tc->time_oldsec = tv.tv_sec ;
411 tc->time_oldusec = tv.tv_usec;
412 /* elaped time. computed timeshift is tenths of a second */
413 computed_timeshift = (float) (elapsed_secs * 1000000. + elapsed_usecs)/
416 /* calibrate effect time to lie between start and end times */
417 /* loop if time exceeds end time */
419 tc->effect_time -= computed_timeshift / 10.0 * dilate;
421 tc->effect_time += computed_timeshift / 10.0 * dilate;
422 if ( tc->effect_time >= tc->end_time)
423 tc->effect_time = tc->start_time;
424 if ( tc->effect_time < tc->start_time)
425 tc->effect_time = tc->end_time;;
427 /* move texture shifters in effect's direction, e.g. tardis
428 tunnel moves backward, effect 1's direction */
430 tc->texshift[0] -= tc->effects[1].direction * computed_timeshift/ 10.0;
431 tc->texshift[1] -= tc->effects[3].direction * computed_timeshift/ 10.0;
432 tc->texshift[2] -= tc->effects[6].direction * computed_timeshift/ 10.0;
435 tc->texshift[0] += tc->effects[1].direction * computed_timeshift/ 10.0;
436 tc->texshift[1] += tc->effects[3].direction * computed_timeshift/ 10.0;
437 tc->texshift[2] += tc->effects[6].direction * computed_timeshift/ 10.0;
440 /* loop texture shifters if necessary */
441 for ( i = 0 ; i < tc->num_texshifts; i++) {
442 if (tc->texshift[i] > 1.0)
443 tc->texshift[i] -= (int) tc->texshift[i];
444 if (tc->texshift[i]< -1.0)
445 tc->texshift[i] -= (int) tc->texshift[i];
448 /* update effect data with current time. Uses linear interpolation */
449 for ( i = 1 ; i <= tc->num_effects ; i++)
450 update_knots(&tc->effects[i], tc->effect_time);
452 } /*update_animation*/
454 /* draw a textured(tex) quad at a certain depth (z), and certain alpha (alpha),
455 with aspect ratio (aspect), and blending mode (blend_mode) of either adding
456 or subtracting. if alpha is zero or less, nothing happens */
457 static void draw_sign(ModeInfo *mi, tunnel_configuration *tc, float z, float alpha, float aspect,
458 GLuint tex, int blend_mode)
463 mi->polygon_count ++;
464 /* glEnable(GL_BLEND); */
465 glBlendColor(0.0, 0.0, 0.0, alpha);
466 /*glBlendColor(0.0, 0.0, 0.0, 0.0); */
467 if (blend_mode == 1) {
468 glBlendFunc(GL_CONSTANT_ALPHA,
470 glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
471 } else if (blend_mode == 2) {
472 glBlendFunc(GL_CONSTANT_ALPHA,
474 glBlendEquation(GL_FUNC_ADD);
476 glBlendFunc(GL_CONSTANT_ALPHA,
477 GL_ONE_MINUS_CONSTANT_ALPHA);
478 glBlendEquation(GL_FUNC_ADD);
479 } /* blend mode switch */
481 #ifdef HAVE_GLBINDTEXTURE
483 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[tex]);
486 glTexCoord2f(1.0, 0.0);
487 glVertex3f(-1.0 , -1.0 * aspect , z);
488 glTexCoord2f(1.0, 1.0);
489 glVertex3f(-1.0 , 1.0 * aspect , z);
490 glTexCoord2f(0.0, 1.0);
491 glVertex3f(1.0 , 1.0 * aspect , z);
492 glTexCoord2f(0.0, 0.0);
493 glVertex3f(1.0 , -1.0 * aspect , z);
495 if (blend_mode != 0) {
496 glBlendFunc(GL_CONSTANT_ALPHA,
497 GL_ONE_MINUS_CONSTANT_ALPHA);
498 glBlendEquation(GL_FUNC_ADD);
500 /* glDisable(GL_BLEND); */
503 #endif /* !HAVE_JWZGLES */
507 /* draw a time tunnel. used for both cylinder and diamond tunnels.
508 uses texture shifter (indexed by shiftnum) to simulate motion.
509 tunnel does not move, and is acutally a display list. if alpha = 0, skip */
510 static void draw_cyl(ModeInfo *mi, tunnel_configuration *tc, float alpha, int texnum, int listnum, int shiftnum)
514 if (listnum == tc->diamondlist)
515 mi->polygon_count += 4;
516 if (listnum == tc->cyllist)
517 mi->polygon_count += 30;
518 glMatrixMode(GL_TEXTURE);
520 glTranslatef(tc->texshift[shiftnum], 0.0, 0.0);
521 glMatrixMode(GL_MODELVIEW);
522 /* glEnable(GL_BLEND); */
523 glBlendColor(0.0, 0.0, 0.0, alpha);
524 glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
526 #ifdef HAVE_GLBINDTEXTURE
528 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[texnum]);
532 glMatrixMode(GL_TEXTURE);
534 glMatrixMode(GL_MODELVIEW);
535 /* glDisable(GL_BLEND); */
537 #endif /* HAVE_JWZGLES */
541 /* make tardis type tunnel. Starts as walls and then
542 grows to outline of tardis. percent is how complete
543 tardis outline is. cap is to draw cap for nice fog effects */
545 static void make_wall_tunnel(ModeInfo *mi, tunnel_configuration *tc, float percent, float cap)
547 /* tardis is about 2x1, so wrap tex around, starting at the base*/
555 that's br=bottom right, etc. ttr is top-top-right */
557 float half_floor= 0.08333333333333333,
558 full_wall = 0.33333333333333333;
564 depth=0.3, zdepth=15.0;
565 /* zdepth is how far back tunnel goes */
566 /* depth is tex coord scale. low number = fast texture shifting */
568 float textop, texbot;
575 tr1 = r1 + half_floor;
577 tl1 = tl0 + half_floor;
581 glMatrixMode(GL_TEXTURE);
583 glRotatef(90.0, 0.0, 0.0, 1.0);
584 glTranslatef(tc->texshift[0], 0.0, 0.0);
585 glMatrixMode(GL_MODELVIEW);
587 #ifdef HAVE_GLBINDTEXTURE
589 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[0]);
591 glColor3f(1.0, 1.0, 0.0);
592 if (cap > 0.0 && percent > 0.0 && drawlogo && do_fog) {
593 mi->polygon_count += 6;
594 glBegin(GL_TRIANGLE_FAN);
595 glVertex3f(0.0, 0.0, zdepth);
596 glVertex3f(-1.0, -2.0, zdepth);
597 glVertex3f(1.0, -2.0, zdepth);
598 glVertex3f(1.0, 2.0, zdepth);
599 glVertex3f(0.2, 2.0, zdepth);
600 glVertex3f(0.2, 2.2, zdepth);
601 glVertex3f(-0.2, 2.2, zdepth);
602 glVertex3f(-0.2, 2.0, zdepth);
603 glVertex3f(-1.0, 2.0, zdepth);
604 glVertex3f(-1.0, -2.0, zdepth);
607 if (percent > ( full_wall * 2.0)) {
610 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
611 if (height > 1.0) height = 1.0;
615 mi->polygon_count += 2;
616 if ( height > 0.90) {
617 mi->polygon_count += 2;
620 textop = tr0 + half_floor * height;
621 glTexCoord2f(0.0, texbot);
622 glVertex3f(0.2, 2.2, 0.0);
624 glTexCoord2f(0.0, textop);
625 glVertex3f(2.0 - height * 2.0, 2.2, 0.0);
627 glTexCoord2f(depth, textop);
628 glVertex3f(2.0 - height * 2.0, 2.2, zdepth);
630 glTexCoord2f(depth, texbot);
631 glVertex3f(0.2, 2.2, zdepth);
634 texbot = tl1 - half_floor * height;
636 glTexCoord2f(0.0, texbot);
637 glVertex3f(-2.0 + height * 2.0, 2.2, 0.0);
639 glTexCoord2f(0.0, textop);
640 glVertex3f(-0.2, 2.2, 0.0);
642 glTexCoord2f(depth, textop);
643 glVertex3f(-0.2, 2.2, zdepth);
645 glTexCoord2f(depth, texbot);
646 glVertex3f(-2.0 + height * 2.0, 2.2, zdepth);
648 if (height > 0.90) height = 0.90;
652 textop = tr0 + half_floor * height;
653 glTexCoord2f(0.0, texbot);
654 glVertex3f(0.2, 2.0, 0.0);
656 glTexCoord2f(0.0, textop);
657 glVertex3f(0.2, 0.4 + height * 2.0, 0.0);
659 glTexCoord2f(depth, textop);
660 glVertex3f(0.2, 0.4 + height * 2.0, zdepth);
662 glTexCoord2f(depth, texbot);
663 glVertex3f(0.2, 2.0, zdepth);
666 texbot = tl1 - half_floor * height;
668 glTexCoord2f(0.0, texbot);
669 /*glVertex3f(-.2, 2.0 + (0.9 - height) * 2.0, 0.0); */
670 glVertex3f(-.2, 0.4 + height * 2.0, 0.0);
672 glTexCoord2f(0.0, textop);
673 glVertex3f(-.2, 2.0, 0.0);
675 glTexCoord2f(depth, textop);
676 glVertex3f(-.2, 2.0, zdepth);
678 glTexCoord2f(depth, texbot);
679 glVertex3f(-.2, 0.4 + height * 2.0, zdepth);
682 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
683 if (height > 0.8) height = 0.8;
686 mi->polygon_count += 2;
689 textop = tr0 + half_floor * height;
690 glTexCoord2f(0.0, texbot);
691 glVertex3f(1.0, 2.0, 0.0);
693 glTexCoord2f(0.0, textop);
694 glVertex3f(1.0 - height, 2.0, 0.0);
696 glTexCoord2f(depth, textop);
697 glVertex3f(1.0 - height, 2.0, zdepth);
699 glTexCoord2f(depth, texbot);
700 glVertex3f(1.0, 2.0, zdepth);
703 texbot = tl1 - half_floor * height;
705 glTexCoord2f(0.0, texbot);
706 glVertex3f(-1.0 + height, 2.0, 0.0);
708 glTexCoord2f(0.0, textop);
709 glVertex3f(-1.0, 2.0, 0.0);
711 glTexCoord2f(depth, textop);
712 glVertex3f(-1.0, 2.0, zdepth);
714 glTexCoord2f(depth, texbot);
715 glVertex3f(-1.0 + height, 2.0, zdepth);
717 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
719 if (height > 1.0) height = 1.0;
722 mi->polygon_count += 2;
725 textop = tr0 + half_floor * height;
726 glTexCoord2f(0.0, texbot);
727 glVertex3f(1.0, -2.0, 0.0);
729 glTexCoord2f(0.0, textop);
730 glVertex3f(1.0 - height, -2.0, 0.0);
732 glTexCoord2f(depth, textop);
733 glVertex3f(1.0 - height, -2.0, zdepth);
735 glTexCoord2f(depth, texbot);
736 glVertex3f(1.0, -2.0, zdepth);
739 texbot = tl1 - half_floor * height;
741 glTexCoord2f(0.0, texbot);
742 glVertex3f(-1.0 + height, -2.0, 0.0);
744 glTexCoord2f(0.0, textop);
745 glVertex3f(-1.0, -2.0, 0.0);
747 glTexCoord2f(depth, textop);
748 glVertex3f(-1.0, -2.0, zdepth);
750 glTexCoord2f(depth, texbot);
751 glVertex3f(-1.0 + height, -2.0, zdepth);
758 mi->polygon_count += 2;
760 height = percent / ( full_wall * 2.0);
761 if (height > 1.0) height = 1.0;
762 textop = (l0 + l1) / 2.0 - full_wall * 0.5 * height;
763 texbot = (l0 + l1) / 2.0 + full_wall * 0.5 * height;
765 glTexCoord2f(0.0, textop);
766 glVertex3f(-1.0, height * 2, 0.0);
768 glTexCoord2f(0.0, texbot);
769 glVertex3f(-1.0, -height * 2, 0.0);
771 glTexCoord2f(depth, texbot);
772 glVertex3f(-1.0, -height * 2, zdepth);
774 glTexCoord2f(depth, textop);
775 glVertex3f(-1.0, height * 2, zdepth);
777 textop = (r0 + r1) / 2.0 - full_wall * 0.5 * height;
778 texbot = (r0 + r1) / 2.0 + full_wall * 0.5 * height;
780 glTexCoord2f(0.0, texbot);
781 glVertex3f(1.0, height * 2, 0.0);
783 glTexCoord2f(0.0, textop);
784 glVertex3f(1.0, -height * 2, 0.0);
786 glTexCoord2f(depth, textop);
787 glVertex3f(1.0, -height * 2, zdepth);
789 glTexCoord2f(depth, texbot);
790 glVertex3f(1.0, height * 2, zdepth);
795 glMatrixMode(GL_TEXTURE);
797 glMatrixMode(GL_MODELVIEW);
798 } /* make_wall_tunnel */
800 /* wraps an int to between min and max.
801 Kind of like the remainder when devided by (max - min).
802 Used to create torus mapping on square array */
803 static int wrapVal(int val, int min, int max)
809 ret = min + (val - max ) % (max - min);
811 ret = max - (min - val) % (max - min);
815 /*=================== Load Texture =========================================*/
816 /* ripped from atunnel.c, Copyright (c) E. Lassauge, 2003-2004. */
817 /* modified like so by Sean Brennan:
818 take texture object for glbind
821 blur color / alpha channel [3x3 box filter, done [blur] times
822 anegative : create b/w image from zero alpha. zero alpha gets bw_color,
823 nonzero alpha gets 1.0 - bwcolor, then alpha flipped to 1-alpha.
825 Inputs: xpm structure, or filename of xmp image. if filename == NULL, use structure.
826 Outputs: texture bound to texutre Id texbind.
830 static float mylog2(float x) { return ( log(x) / log(2));}
832 static void LoadTexture(ModeInfo * mi, char **fn, const char *filename, GLuint texbind, int blur, float bw_color, Bool anegative, Bool onealpha)
834 /* looping and temporary array index variables */
835 int ix, iy, bx, by, indx, indy, boxsize, cchan, tmpidx, dtaidx;
837 float boxdiv, tmpfa, blursum ;
838 unsigned char *tmpbuf, tmpa;
842 XImage *teximage; /* Texture data */
847 boxdiv = 1.0 / ( boxsize * 2.0 + 1.0) / ( boxsize * 2.0 + 1.0);
851 teximage = xpm_file_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
852 MI_COLORMAP(mi), filename);
854 teximage = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
855 MI_COLORMAP(mi), fn);
856 if (teximage == NULL) {
857 fprintf(stderr, "%s: error reading the texture.\n", progname);
858 glDeleteTextures(1, &texbind);
863 /* check if image is 2^kumquat, where kumquat is an integer between 1 and 10. Recale to
864 nearest power of 2. */
865 tmpfa = mylog2((float) teximage->width);
866 bx = 2 << (int) (tmpfa -1);
867 if (bx != teximage->width) {
869 if ((tmpfa - (int) tmpfa) > 0.5849)
872 tmpfa = mylog2((float) teximage->height);
873 by = 2 << (int) (tmpfa - 1);
874 if (by != teximage->height) {
876 if ((tmpfa - (int) tmpfa) > 0.5849)
882 tmpbuf = calloc(bx * by * 4, sizeof(unsigned char));
883 if (gluScaleImage(GL_RGBA, teximage->width, teximage->height, GL_UNSIGNED_BYTE, teximage->data,
884 bx, by, GL_UNSIGNED_BYTE, tmpbuf))
885 check_gl_error("scale image");
887 free(teximage->data);
888 teximage->data = (char *) tmpbuf;
889 teximage->width = bx;
890 teximage->height= by;
891 #endif /* !HAVE_JWZGLES */
893 /* end rescale code */
896 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
898 if (!teximage->data[ ix * 4 + 3]) {
899 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
900 tmpa = (unsigned char) (bw_color * 0xff);
903 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
905 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff -
906 teximage->data[ ix * 4 + 3];
907 tmpa = (unsigned char) ((1.0 - bw_color) * 0xff);
909 /* make texture uniform b/w color */
910 teximage->data[ ix * 4 + 0] =
911 (unsigned char) ( tmpa);
912 teximage->data[ ix * 4 + 1] =
913 (unsigned char) ( tmpa);
914 teximage->data[ ix * 4 + 2] =
915 (unsigned char) ( tmpa);
921 if (! anegative ) /* anegative alread b/w's the whole image */
922 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
923 if (!teximage->data[ ix * 4 + 3])
925 teximage->data[ ix * 4 + 0] =
926 (unsigned char) ( 255.0 * bw_color);
927 teximage->data[ ix * 4 + 1] =
928 (unsigned char) ( 255.0 * bw_color);
929 teximage->data[ ix * 4 + 2] =
930 (unsigned char) ( 255.0 * bw_color);
933 tmpbuf = calloc(teximage->height * teximage->width * 4, sizeof(unsigned char) ) ;
935 /* zero out tmp alpha buffer */
936 for (iy = 0 ; iy <teximage->height * teximage->width * 4 ; iy++)
938 for (cchan = 0; cchan < 4 ; cchan++) {
939 for (iy = 0 ; iy < teximage->height ; iy++) {
940 for (ix = 0 ; ix < teximage->width ; ix++) {
941 dtaidx = (teximage->width * iy + ix) * 4;
942 tmpa = teximage->data[dtaidx + cchan];
943 tmpfa = (float) tmpa * boxdiv;
945 for (by = -boxsize ; by <= boxsize; by++) {
946 for (bx = -boxsize ; bx <= boxsize; bx++) {
947 indx = wrapVal(ix + bx, 0, teximage->width);
948 indy = wrapVal(iy + by, 0, teximage->height);
949 tmpidx = (teximage->width * indy + indx) * 4;
951 tmpbuf[tmpidx + cchan] += (unsigned char) blursum;
957 /* copy back buffer */
958 for (ix = 0 ; ix < teximage->height * teximage->width * 4; ix++)
959 teximage->data[ix] = tmpbuf[ix];
961 free(tmpbuf); /*tidy*/
968 #ifdef HAVE_GLBINDTEXTURE
969 glBindTexture(GL_TEXTURE_2D, texbind);
970 clear_gl_error(); /* WTF? sometimes "invalid op" from glBindTexture! */
972 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
973 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height,
974 0, GL_RGBA, GL_UNSIGNED_BYTE, teximage->data);
975 check_gl_error("texture");
977 XDestroyImage(teximage);
980 /* creates cylinder for time tunnel. sides, zmin, zmax, rad(ius) obvious.
981 stretch scales texture coords; makes tunnel go slower the larger it is.
982 not drawn, but put into display list. */
983 static void makecyl(int sides, float zmin, float zmax, float rad, float stretch)
990 glBegin(GL_TRIANGLE_FAN);
991 glTexCoord2f(1.0, 0.0);
992 glVertex3f(0.0 , 0.0 , zmax);
993 for (i = 0 ; i <= sides; i++) {
994 theta = 2.0 * M_PI * ((float) i / (float) sides);
995 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
997 glVertex3f(cos(0.0) * rad, sin(0.0) * rad, zmax);
1001 glBegin(GL_QUAD_STRIP);
1002 for (i = 0 ; i <= sides; i++)
1005 theta = 2.0 * M_PI * ((float) i / (float) sides);
1006 glTexCoord2f(0.0, 1.0 * (float) i / (float) sides);
1007 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1008 glTexCoord2f(stretch, 1.0 * (float) i / (float) sides);
1009 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1012 glTexCoord2f(0.0, 1.0);
1013 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1014 glTexCoord2f(stretch, 1.0);
1015 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1022 init_tunnel (ModeInfo *mi)
1026 tunnel_configuration *tc;
1028 wire = MI_IS_WIREFRAME(mi);
1030 # ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
1034 MI_INIT (mi, tconf, NULL);
1036 tc = &tconf[MI_SCREEN(mi)];
1038 tc->glx_context = init_GL(mi);
1040 tc->cyllist = glGenLists(1);
1041 tc->diamondlist = glGenLists(1);
1042 tc->num_effects = 12;
1043 tc->num_texshifts = 3;
1044 tc->effect_time = 0.0;
1045 tc->effect_maxsecs = 30.00;
1046 /* check bounds on cmd line opts */
1047 if (start > tc->effect_maxsecs) start = tc->effect_maxsecs;
1048 if (end > tc->effect_maxsecs) end = tc->effect_maxsecs;
1049 if (start < tc->effect_time) start = tc->effect_time;
1050 if (end < tc->effect_time) end = tc->effect_time;
1052 /* set loop times, in seconds */
1053 tc->start_time = start;
1056 /* reset animation knots, effect 0 not defined. */
1057 tc->effects = malloc(sizeof(effect_t) * ( tc->num_effects + 1));
1058 for ( i = 1; i <= tc->num_effects ; i++)
1059 init_effects(&tc->effects[i], i);
1062 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1068 /* the following textures are loaded, and possible overridden:
1069 tunnel 1, tunnel 2, tunnel 3, marquee, tardis, head */
1070 glGenTextures(MAX_TEXTURE, tc->texture_binds);
1072 /*LoadTexture(*mi, **fn, *filename, texbind, bluralpha, bw_color, anegative, onealpha)*/
1073 if (strcasecmp (do_tun1, "(none)")) /* tunnel 1 */
1074 LoadTexture(mi, NULL, do_tun1, tc->texture_binds[0], 0,0.0, False, False);
1076 LoadTexture(mi, timetunnel0_xpm, NULL, tc->texture_binds[0], 0, 0.0, False, False);
1077 if (strcasecmp (do_tun2, "(none)")) /* tunnel 2 */
1078 LoadTexture(mi, NULL, do_tun2, tc->texture_binds[2], 0,0.0, False, False);
1080 LoadTexture(mi, timetunnel1_xpm, NULL, tc->texture_binds[2], 0, 0.0, False, False);
1081 if (strcasecmp (do_tun3, "(none)")) /* tunnel 3 */
1082 LoadTexture(mi, NULL, do_tun3, tc->texture_binds[5], 0,0.0, False, False);
1084 LoadTexture(mi, timetunnel2_xpm, NULL, tc->texture_binds[5], 0, 0.0, False, False);
1085 LoadTexture(mi, tunnelstar_xpm, NULL, tc->texture_binds[4], 0, 0.0, False, False);
1086 if (strcasecmp (do_tx1, "(none)")) /* marquee */
1087 LoadTexture(mi, NULL, do_tx1, tc->texture_binds[3], 0,0.0, False, False);
1088 #ifndef HAVE_JWZGLES /* logo_180_xpm is 180px which is not a power of 2! */
1090 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[3], 0,0.0, False, False);
1092 if (strcasecmp (do_tx2, "(none)")) /* tardis */
1093 LoadTexture(mi, NULL, do_tx2, tc->texture_binds[1], 0, 0.0 ,False, False);
1094 #ifndef HAVE_JWZGLES /* logo_180_xpm is 180px which is not a power of 2! */
1096 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[1], 0,0.0, False, False);
1098 if (strcasecmp (do_tx3, "(none)")) { /* head */
1099 LoadTexture(mi, NULL, do_tx3, tc->texture_binds[6], 0, 0.0 ,False, False);
1101 LoadTexture(mi, NULL, do_tx3, tc->texture_binds[9], 2,1.0, True, True);
1102 #ifndef HAVE_JWZGLES /* logo_180_xpm is 180px which is not a power of 2! */
1104 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[6], 0,0.0, False, False);
1106 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[9], 2,1.0, True, True);
1109 glEnable(GL_TEXTURE_2D);
1110 check_gl_error("tex");
1113 reshape_tunnel (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1115 glDisable(GL_DEPTH_TEST); /* who needs it? ;-) */
1122 glEnable(GL_ALPHA_TEST);
1123 glAlphaFunc(GL_GREATER, 0.5);
1126 tc->trackball = gltrackball_init (True);
1129 tc->texshift = calloc(tc->num_texshifts, sizeof(GLfloat));
1130 for ( i = 0 ; i < tc->num_texshifts; i++)
1131 tc->texshift[i] = 0.0;
1133 glNewList(tc->cyllist, GL_COMPILE);
1134 makecyl(30, -0.1, CYL_LEN, 1., 10. / 40.0 * CYL_LEN);
1135 /*makecyl(30, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN); */
1138 glNewList(tc->diamondlist, GL_COMPILE);
1139 makecyl(4, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN);
1145 draw_tunnel (ModeInfo *mi)
1147 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
1148 Display *dpy = MI_DISPLAY(mi);
1149 Window window = MI_WINDOW(mi);
1152 if (!tc->glx_context)
1155 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tc->glx_context));
1157 glShadeModel(GL_SMOOTH);
1159 glEnable(GL_NORMALIZE);
1160 /* glEnable(GL_CULL_FACE); */
1162 glClear(GL_COLOR_BUFFER_BIT );
1164 update_animation(tc);
1169 glRotatef(180., 0., 1., 0.);
1170 gltrackball_rotate (tc->trackball);
1171 glRotatef(180., 0., 1., 0.);
1175 mi->polygon_count = 0;
1177 update_fog(tc->effects[4].state[0], /*color*/
1178 tc->effects[4].state[1], /*density*/
1179 tc->effects[4].state[2], /*start*/
1180 tc->effects[4].state[3]); /*end*/
1182 /* --- begin composite image assembly --- */
1184 /* head mask and draw diamond tunnel */
1187 draw_cyl(mi, tc, tc->effects[6].state[0], 5, tc->diamondlist, 2);
1189 draw_sign(mi, tc,tc->effects[12].state[0], tc->effects[12].state[1], 1.0 / 1.33, 9, 1);
1190 glDisable(GL_BLEND);
1191 /* then tardis tunnel */
1192 make_wall_tunnel(mi, tc, tc->effects[1].state[0], tc->effects[7].state[0]);
1194 /* then cylinder tunnel */
1196 draw_cyl(mi, tc, tc->effects[3].state[0], 2, tc->cyllist, 1);
1198 /*void draw_sign(mi, tc,z,alpha,aspect,tex,blendmode)*/
1201 draw_sign(mi, tc, tc->effects[2].state[0], tc->effects[2].state[1], 2.0, 1, 0);
1204 draw_sign(mi, tc, tc->effects[5].state[0], tc->effects[5].state[1], 1.0, 3, 0);
1207 draw_sign(mi, tc,1.0, tc->effects[10].state[0], 1.0 / 1.33, 6, 2);
1208 /*who head psychadelic REMOVED*/
1209 /* draw_sign(mi, tc,1.0, tc->effects[11].state[0], 1.0 / 1.33, 8, 0); */
1212 /* draw_sign(mi, tc, tc->effects[8].state[0]tc->effects[8].state[0], 1.0 , 1.0, 4, 1); */
1213 draw_sign(mi, tc, tc->effects[8].state[0], tc->effects[8].state[0], 1.0, 4, 1);
1217 draw_sign(mi, tc,1.0, tc->effects[9].state[0], 1.0 / 1.33, 6, 0);
1219 /* --- end composite image assembly --- */
1224 if (mi->fps_p) do_fps (mi);
1227 check_gl_error("drawing done, calling swap buffers");
1228 glXSwapBuffers(dpy, window);
1231 XSCREENSAVER_MODULE_2 ("TimeTunnel", timetunnel, tunnel)