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"
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 (event->xany.type == ButtonPress &&
380 event->xbutton.button == Button1)
382 tc->button_down_p = True;
383 gltrackball_start (tc->trackball,
384 event->xbutton.x, event->xbutton.y,
385 MI_WIDTH (mi), MI_HEIGHT (mi));
388 else if (event->xany.type == ButtonRelease &&
389 event->xbutton.button == Button1)
391 tc->button_down_p = False;
394 else if (event->xany.type == ButtonPress &&
395 (event->xbutton.button == Button4 ||
396 event->xbutton.button == Button5))
398 gltrackball_mousewheel (tc->trackball, event->xbutton.button, 10,
399 !!event->xbutton.state);
402 else if (event->xany.type == MotionNotify &&
405 gltrackball_track (tc->trackball,
406 event->xmotion.x, event->xmotion.y,
407 MI_WIDTH (mi), MI_HEIGHT (mi));
414 static void setTexParams(void)
416 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
417 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
418 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
419 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
420 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
423 static void update_animation(tunnel_configuration *tc) {
425 /* time based, of course*/
426 /* shift texture based on elapsed time since previous call*/
429 int elapsed_usecs, elapsed_secs, i;
430 float computed_timeshift;
432 /* get new animation time */
433 gettimeofday(&tv, &tz);
434 elapsed_secs = tv.tv_sec - tc->time_oldsec;
435 elapsed_usecs = tv.tv_usec - tc->time_oldusec;
436 /* store current time */
437 tc->time_oldsec = tv.tv_sec ;
438 tc->time_oldusec = tv.tv_usec;
439 /* elaped time. computed timeshift is tenths of a second */
440 computed_timeshift = (float) (elapsed_secs * 1000000. + elapsed_usecs)/
443 /* calibrate effect time to lie between start and end times */
444 /* loop if time exceeds end time */
446 tc->effect_time -= computed_timeshift / 10.0 * dilate;
448 tc->effect_time += computed_timeshift / 10.0 * dilate;
449 if ( tc->effect_time >= tc->end_time)
450 tc->effect_time = tc->start_time;
451 if ( tc->effect_time < tc->start_time)
452 tc->effect_time = tc->end_time;;
454 /* move texture shifters in effect's direction, e.g. tardis
455 tunnel moves backward, effect 1's direction */
457 tc->texshift[0] -= tc->effects[1].direction * computed_timeshift/ 10.0;
458 tc->texshift[1] -= tc->effects[3].direction * computed_timeshift/ 10.0;
459 tc->texshift[2] -= tc->effects[6].direction * computed_timeshift/ 10.0;
462 tc->texshift[0] += tc->effects[1].direction * computed_timeshift/ 10.0;
463 tc->texshift[1] += tc->effects[3].direction * computed_timeshift/ 10.0;
464 tc->texshift[2] += tc->effects[6].direction * computed_timeshift/ 10.0;
467 /* loop texture shifters if necessary */
468 for ( i = 0 ; i < tc->num_texshifts; i++) {
469 if (tc->texshift[i] > 1.0)
470 tc->texshift[i] -= (int) tc->texshift[i];
471 if (tc->texshift[i]< -1.0)
472 tc->texshift[i] -= (int) tc->texshift[i];
475 /* update effect data with current time. Uses linear interpolation */
476 for ( i = 1 ; i <= tc->num_effects ; i++)
477 update_knots(&tc->effects[i], tc->effect_time);
479 } /*update_animation*/
481 /* draw a textured(tex) quad at a certain depth (z), and certain alpha (alpha),
482 with aspect ratio (aspect), and blending mode (blend_mode) of either adding
483 or subtracting. if alpha is zero or less, nothing happens */
484 static void draw_sign(ModeInfo *mi, tunnel_configuration *tc, float z, float alpha, float aspect,
485 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); */
530 #endif /* !HAVE_JWZGLES */
534 /* draw a time tunnel. used for both cylinder and diamond tunnels.
535 uses texture shifter (indexed by shiftnum) to simulate motion.
536 tunnel does not move, and is acutally a display list. if alpha = 0, skip */
537 static void draw_cyl(ModeInfo *mi, tunnel_configuration *tc, float alpha, int texnum, int listnum, int shiftnum)
541 if (listnum == tc->diamondlist)
542 mi->polygon_count += 4;
543 if (listnum == tc->cyllist)
544 mi->polygon_count += 30;
545 glMatrixMode(GL_TEXTURE);
547 glTranslatef(tc->texshift[shiftnum], 0.0, 0.0);
548 glMatrixMode(GL_MODELVIEW);
549 /* glEnable(GL_BLEND); */
550 glBlendColor(0.0, 0.0, 0.0, alpha);
551 glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
553 #ifdef HAVE_GLBINDTEXTURE
555 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[texnum]);
559 glMatrixMode(GL_TEXTURE);
561 glMatrixMode(GL_MODELVIEW);
562 /* glDisable(GL_BLEND); */
564 #endif /* HAVE_JWZGLES */
568 /* make tardis type tunnel. Starts as walls and then
569 grows to outline of tardis. percent is how complete
570 tardis outline is. cap is to draw cap for nice fog effects */
572 static void make_wall_tunnel(ModeInfo *mi, tunnel_configuration *tc, float percent, float cap)
574 /* tardis is about 2x1, so wrap tex around, starting at the base*/
582 that's br=bottom right, etc. ttr is top-top-right */
584 float half_floor= 0.08333333333333333,
585 full_wall = 0.33333333333333333;
591 depth=0.3, zdepth=15.0;
592 /* zdepth is how far back tunnel goes */
593 /* depth is tex coord scale. low number = fast texture shifting */
595 float textop, texbot;
602 tr1 = r1 + half_floor;
604 tl1 = tl0 + half_floor;
608 glMatrixMode(GL_TEXTURE);
610 glRotatef(90.0, 0.0, 0.0, 1.0);
611 glTranslatef(tc->texshift[0], 0.0, 0.0);
612 glMatrixMode(GL_MODELVIEW);
614 #ifdef HAVE_GLBINDTEXTURE
616 glBindTexture(GL_TEXTURE_2D, tc->texture_binds[0]);
618 glColor3f(1.0, 1.0, 0.0);
619 if (cap > 0.0 && percent > 0.0 && drawlogo && do_fog) {
620 mi->polygon_count += 6;
621 glBegin(GL_TRIANGLE_FAN);
622 glVertex3f(0.0, 0.0, zdepth);
623 glVertex3f(-1.0, -2.0, zdepth);
624 glVertex3f(1.0, -2.0, zdepth);
625 glVertex3f(1.0, 2.0, zdepth);
626 glVertex3f(0.2, 2.0, zdepth);
627 glVertex3f(0.2, 2.2, zdepth);
628 glVertex3f(-0.2, 2.2, zdepth);
629 glVertex3f(-0.2, 2.0, zdepth);
630 glVertex3f(-1.0, 2.0, zdepth);
631 glVertex3f(-1.0, -2.0, zdepth);
634 if (percent > ( full_wall * 2.0)) {
637 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
638 if (height > 1.0) height = 1.0;
642 mi->polygon_count += 2;
643 if ( height > 0.90) {
644 mi->polygon_count += 2;
647 textop = tr0 + half_floor * height;
648 glTexCoord2f(0.0, texbot);
649 glVertex3f(0.2, 2.2, 0.0);
651 glTexCoord2f(0.0, textop);
652 glVertex3f(2.0 - height * 2.0, 2.2, 0.0);
654 glTexCoord2f(depth, textop);
655 glVertex3f(2.0 - height * 2.0, 2.2, zdepth);
657 glTexCoord2f(depth, texbot);
658 glVertex3f(0.2, 2.2, zdepth);
661 texbot = tl1 - half_floor * height;
663 glTexCoord2f(0.0, texbot);
664 glVertex3f(-2.0 + height * 2.0, 2.2, 0.0);
666 glTexCoord2f(0.0, textop);
667 glVertex3f(-0.2, 2.2, 0.0);
669 glTexCoord2f(depth, textop);
670 glVertex3f(-0.2, 2.2, zdepth);
672 glTexCoord2f(depth, texbot);
673 glVertex3f(-2.0 + height * 2.0, 2.2, zdepth);
675 if (height > 0.90) height = 0.90;
679 textop = tr0 + half_floor * height;
680 glTexCoord2f(0.0, texbot);
681 glVertex3f(0.2, 2.0, 0.0);
683 glTexCoord2f(0.0, textop);
684 glVertex3f(0.2, 0.4 + height * 2.0, 0.0);
686 glTexCoord2f(depth, textop);
687 glVertex3f(0.2, 0.4 + height * 2.0, zdepth);
689 glTexCoord2f(depth, texbot);
690 glVertex3f(0.2, 2.0, zdepth);
693 texbot = tl1 - half_floor * height;
695 glTexCoord2f(0.0, texbot);
696 /*glVertex3f(-.2, 2.0 + (0.9 - height) * 2.0, 0.0); */
697 glVertex3f(-.2, 0.4 + height * 2.0, 0.0);
699 glTexCoord2f(0.0, textop);
700 glVertex3f(-.2, 2.0, 0.0);
702 glTexCoord2f(depth, textop);
703 glVertex3f(-.2, 2.0, zdepth);
705 glTexCoord2f(depth, texbot);
706 glVertex3f(-.2, 0.4 + height * 2.0, zdepth);
709 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
710 if (height > 0.8) height = 0.8;
713 mi->polygon_count += 2;
716 textop = tr0 + half_floor * height;
717 glTexCoord2f(0.0, texbot);
718 glVertex3f(1.0, 2.0, 0.0);
720 glTexCoord2f(0.0, textop);
721 glVertex3f(1.0 - height, 2.0, 0.0);
723 glTexCoord2f(depth, textop);
724 glVertex3f(1.0 - height, 2.0, zdepth);
726 glTexCoord2f(depth, texbot);
727 glVertex3f(1.0, 2.0, zdepth);
730 texbot = tl1 - half_floor * height;
732 glTexCoord2f(0.0, texbot);
733 glVertex3f(-1.0 + height, 2.0, 0.0);
735 glTexCoord2f(0.0, textop);
736 glVertex3f(-1.0, 2.0, 0.0);
738 glTexCoord2f(depth, textop);
739 glVertex3f(-1.0, 2.0, zdepth);
741 glTexCoord2f(depth, texbot);
742 glVertex3f(-1.0 + height, 2.0, zdepth);
744 height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0);
746 if (height > 1.0) height = 1.0;
749 mi->polygon_count += 2;
752 textop = tr0 + half_floor * height;
753 glTexCoord2f(0.0, texbot);
754 glVertex3f(1.0, -2.0, 0.0);
756 glTexCoord2f(0.0, textop);
757 glVertex3f(1.0 - height, -2.0, 0.0);
759 glTexCoord2f(depth, textop);
760 glVertex3f(1.0 - height, -2.0, zdepth);
762 glTexCoord2f(depth, texbot);
763 glVertex3f(1.0, -2.0, zdepth);
766 texbot = tl1 - half_floor * height;
768 glTexCoord2f(0.0, texbot);
769 glVertex3f(-1.0 + height, -2.0, 0.0);
771 glTexCoord2f(0.0, textop);
772 glVertex3f(-1.0, -2.0, 0.0);
774 glTexCoord2f(depth, textop);
775 glVertex3f(-1.0, -2.0, zdepth);
777 glTexCoord2f(depth, texbot);
778 glVertex3f(-1.0 + height, -2.0, zdepth);
785 mi->polygon_count += 2;
787 height = percent / ( full_wall * 2.0);
788 if (height > 1.0) height = 1.0;
789 textop = (l0 + l1) / 2.0 - full_wall * 0.5 * height;
790 texbot = (l0 + l1) / 2.0 + full_wall * 0.5 * height;
792 glTexCoord2f(0.0, textop);
793 glVertex3f(-1.0, height * 2, 0.0);
795 glTexCoord2f(0.0, texbot);
796 glVertex3f(-1.0, -height * 2, 0.0);
798 glTexCoord2f(depth, texbot);
799 glVertex3f(-1.0, -height * 2, zdepth);
801 glTexCoord2f(depth, textop);
802 glVertex3f(-1.0, height * 2, zdepth);
804 textop = (r0 + r1) / 2.0 - full_wall * 0.5 * height;
805 texbot = (r0 + r1) / 2.0 + full_wall * 0.5 * height;
807 glTexCoord2f(0.0, texbot);
808 glVertex3f(1.0, height * 2, 0.0);
810 glTexCoord2f(0.0, textop);
811 glVertex3f(1.0, -height * 2, 0.0);
813 glTexCoord2f(depth, textop);
814 glVertex3f(1.0, -height * 2, zdepth);
816 glTexCoord2f(depth, texbot);
817 glVertex3f(1.0, height * 2, zdepth);
822 glMatrixMode(GL_TEXTURE);
824 glMatrixMode(GL_MODELVIEW);
825 } /* make_wall_tunnel */
827 /* wraps an int to between min and max.
828 Kind of like the remainder when devided by (max - min).
829 Used to create torus mapping on square array */
830 static int wrapVal(int val, int min, int max)
836 ret = min + (val - max ) % (max - min);
838 ret = max - (min - val) % (max - min);
842 /*=================== Load Texture =========================================*/
843 /* ripped from atunnel.c, Copyright (c) E. Lassauge, 2003-2004. */
844 /* modified like so by Sean Brennan:
845 take texture object for glbind
848 blur color / alpha channel [3x3 box filter, done [blur] times
849 anegative : create b/w image from zero alpha. zero alpha gets bw_color,
850 nonzero alpha gets 1.0 - bwcolor, then alpha flipped to 1-alpha.
852 Inputs: xpm structure, or filename of xmp image. if filename == NULL, use structure.
853 Outputs: texture bound to texutre Id texbind.
857 static float mylog2(float x) { return ( log(x) / log(2));}
859 static void LoadTexture(ModeInfo * mi, char **fn, const char *filename, GLuint texbind, int blur, float bw_color, Bool anegative, Bool onealpha)
861 /* looping and temporary array index variables */
862 int ix, iy, bx, by, indx, indy, boxsize, cchan, tmpidx, dtaidx;
864 float boxdiv, tmpfa, blursum ;
865 unsigned char *tmpbuf, tmpa;
869 XImage *teximage; /* Texture data */
874 boxdiv = 1.0 / ( boxsize * 2.0 + 1.0) / ( boxsize * 2.0 + 1.0);
878 teximage = xpm_file_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
879 MI_COLORMAP(mi), filename);
881 teximage = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
882 MI_COLORMAP(mi), fn);
883 if (teximage == NULL) {
884 fprintf(stderr, "%s: error reading the texture.\n", progname);
885 glDeleteTextures(1, &texbind);
890 /* check if image is 2^kumquat, where kumquat is an integer between 1 and 10. Recale to
891 nearest power of 2. */
892 tmpfa = mylog2((float) teximage->width);
893 bx = 2 << (int) (tmpfa -1);
894 if (bx != teximage->width) {
896 if ((tmpfa - (int) tmpfa) > 0.5849)
899 tmpfa = mylog2((float) teximage->height);
900 by = 2 << (int) (tmpfa - 1);
901 if (by != teximage->height) {
903 if ((tmpfa - (int) tmpfa) > 0.5849)
909 tmpbuf = calloc(bx * by * 4, sizeof(unsigned char));
910 if (gluScaleImage(GL_RGBA, teximage->width, teximage->height, GL_UNSIGNED_BYTE, teximage->data,
911 bx, by, GL_UNSIGNED_BYTE, tmpbuf))
912 check_gl_error("scale image");
914 free(teximage->data);
915 teximage->data = (char *) tmpbuf;
916 teximage->width = bx;
917 teximage->height= by;
919 /* end rescale code */
920 #endif /* !HAVE_JWZGLES */
923 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
925 if (!teximage->data[ ix * 4 + 3]) {
926 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
927 tmpa = (unsigned char) (bw_color * 0xff);
930 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff;
932 teximage->data[ ix * 4 + 3] = (unsigned char) 0xff -
933 teximage->data[ ix * 4 + 3];
934 tmpa = (unsigned char) ((1.0 - bw_color) * 0xff);
936 /* make texture uniform b/w color */
937 teximage->data[ ix * 4 + 0] =
938 (unsigned char) ( tmpa);
939 teximage->data[ ix * 4 + 1] =
940 (unsigned char) ( tmpa);
941 teximage->data[ ix * 4 + 2] =
942 (unsigned char) ( tmpa);
948 if (! anegative ) /* anegative alread b/w's the whole image */
949 for (ix = 0 ; ix < teximage->height * teximage->width; ix++)
950 if (!teximage->data[ ix * 4 + 3])
952 teximage->data[ ix * 4 + 0] =
953 (unsigned char) ( 255.0 * bw_color);
954 teximage->data[ ix * 4 + 1] =
955 (unsigned char) ( 255.0 * bw_color);
956 teximage->data[ ix * 4 + 2] =
957 (unsigned char) ( 255.0 * bw_color);
960 tmpbuf = calloc(teximage->height * teximage->width * 4, sizeof(unsigned char) ) ;
962 /* zero out tmp alpha buffer */
963 for (iy = 0 ; iy <teximage->height * teximage->width * 4 ; iy++)
965 for (cchan = 0; cchan < 4 ; cchan++) {
966 for (iy = 0 ; iy < teximage->height ; iy++) {
967 for (ix = 0 ; ix < teximage->width ; ix++) {
968 dtaidx = (teximage->width * iy + ix) * 4;
969 tmpa = teximage->data[dtaidx + cchan];
970 tmpfa = (float) tmpa * boxdiv;
972 for (by = -boxsize ; by <= boxsize; by++) {
973 for (bx = -boxsize ; bx <= boxsize; bx++) {
974 indx = wrapVal(ix + bx, 0, teximage->width);
975 indy = wrapVal(iy + by, 0, teximage->height);
976 tmpidx = (teximage->width * indy + indx) * 4;
978 tmpbuf[tmpidx + cchan] += (unsigned char) blursum;
984 /* copy back buffer */
985 for (ix = 0 ; ix < teximage->height * teximage->width * 4; ix++)
986 teximage->data[ix] = tmpbuf[ix];
988 free(tmpbuf); /*tidy*/
995 #ifdef HAVE_GLBINDTEXTURE
996 glBindTexture(GL_TEXTURE_2D, texbind);
997 clear_gl_error(); /* WTF? sometimes "invalid op" from glBindTexture! */
999 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1000 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height,
1001 0, GL_RGBA, GL_UNSIGNED_BYTE, teximage->data);
1002 check_gl_error("texture");
1004 XDestroyImage(teximage);
1007 /* creates cylinder for time tunnel. sides, zmin, zmax, rad(ius) obvious.
1008 stretch scales texture coords; makes tunnel go slower the larger it is.
1009 not drawn, but put into display list. */
1010 static void makecyl(int sides, float zmin, float zmax, float rad, float stretch)
1017 glBegin(GL_TRIANGLE_FAN);
1018 glTexCoord2f(1.0, 0.0);
1019 glVertex3f(0.0 , 0.0 , zmax);
1020 for (i = 0 ; i <= sides; i++) {
1021 theta = 2.0 * M_PI * ((float) i / (float) sides);
1022 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1024 glVertex3f(cos(0.0) * rad, sin(0.0) * rad, zmax);
1028 glBegin(GL_QUAD_STRIP);
1029 for (i = 0 ; i <= sides; i++)
1032 theta = 2.0 * M_PI * ((float) i / (float) sides);
1033 glTexCoord2f(0.0, 1.0 * (float) i / (float) sides);
1034 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1035 glTexCoord2f(stretch, 1.0 * (float) i / (float) sides);
1036 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1039 glTexCoord2f(0.0, 1.0);
1040 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin);
1041 glTexCoord2f(stretch, 1.0);
1042 glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax);
1049 init_tunnel (ModeInfo *mi)
1053 tunnel_configuration *tc;
1055 wire = MI_IS_WIREFRAME(mi);
1058 tconf = (tunnel_configuration *)
1059 calloc (MI_NUM_SCREENS(mi), sizeof (tunnel_configuration));
1061 fprintf(stderr, "%s: out of memory\n", progname);
1066 tc = &tconf[MI_SCREEN(mi)];
1068 tc->glx_context = init_GL(mi);
1070 tc->cyllist = glGenLists(1);
1071 tc->diamondlist = glGenLists(1);
1072 tc->num_effects = 12;
1073 tc->num_texshifts = 3;
1074 tc->effect_time = 0.0;
1075 tc->effect_maxsecs = 30.00;
1076 /* check bounds on cmd line opts */
1077 if (start > tc->effect_maxsecs) start = tc->effect_maxsecs;
1078 if (end > tc->effect_maxsecs) end = tc->effect_maxsecs;
1079 if (start < tc->effect_time) start = tc->effect_time;
1080 if (end < tc->effect_time) end = tc->effect_time;
1082 /* set loop times, in seconds */
1083 tc->start_time = start;
1086 /* reset animation knots, effect 0 not defined. */
1087 tc->effects = malloc(sizeof(effect_t) * ( tc->num_effects + 1));
1088 for ( i = 1; i <= tc->num_effects ; i++)
1089 init_effects(&tc->effects[i], i);
1092 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1098 /* the following textures are loaded, and possible overridden:
1099 tunnel 1, tunnel 2, tunnel 3, marquee, tardis, head */
1100 glGenTextures(MAX_TEXTURE, tc->texture_binds);
1102 /*LoadTexture(*mi, **fn, *filename, texbind, bluralpha, bw_color, anegative, onealpha)*/
1103 if (strcasecmp (do_tun1, "(none)")) /* tunnel 1 */
1104 LoadTexture(mi, NULL, do_tun1, tc->texture_binds[0], 0,0.0, False, False);
1106 LoadTexture(mi, timetunnel0_xpm, NULL, tc->texture_binds[0], 0, 0.0, False, False);
1107 if (strcasecmp (do_tun2, "(none)")) /* tunnel 2 */
1108 LoadTexture(mi, NULL, do_tun2, tc->texture_binds[2], 0,0.0, False, False);
1110 LoadTexture(mi, timetunnel1_xpm, NULL, tc->texture_binds[2], 0, 0.0, False, False);
1111 if (strcasecmp (do_tun3, "(none)")) /* tunnel 3 */
1112 LoadTexture(mi, NULL, do_tun3, tc->texture_binds[5], 0,0.0, False, False);
1114 LoadTexture(mi, timetunnel2_xpm, NULL, tc->texture_binds[5], 0, 0.0, False, False);
1115 LoadTexture(mi, tunnelstar_xpm, NULL, tc->texture_binds[4], 0, 0.0, False, False);
1116 if (strcasecmp (do_tx1, "(none)")) /* marquee */
1117 LoadTexture(mi, NULL, do_tx1, tc->texture_binds[3], 0,0.0, False, False);
1118 #ifndef HAVE_JWZGLES /* logo_180_xpm is 180px which is not a power of 2! */
1120 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[3], 0,0.0, False, False);
1122 if (strcasecmp (do_tx2, "(none)")) /* tardis */
1123 LoadTexture(mi, NULL, do_tx2, tc->texture_binds[1], 0, 0.0 ,False, False);
1124 #ifndef HAVE_JWZGLES /* logo_180_xpm is 180px which is not a power of 2! */
1126 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[1], 0,0.0, False, False);
1128 if (strcasecmp (do_tx3, "(none)")) { /* head */
1129 LoadTexture(mi, NULL, do_tx3, tc->texture_binds[6], 0, 0.0 ,False, False);
1131 LoadTexture(mi, NULL, do_tx3, tc->texture_binds[9], 2,1.0, True, True);
1132 #ifndef HAVE_JWZGLES /* logo_180_xpm is 180px which is not a power of 2! */
1134 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[6], 0,0.0, False, False);
1136 LoadTexture(mi, (char **) logo_180_xpm, NULL, tc->texture_binds[9], 2,1.0, True, True);
1139 glEnable(GL_TEXTURE_2D);
1140 check_gl_error("tex");
1143 reshape_tunnel (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1145 glDisable(GL_DEPTH_TEST); /* who needs it? ;-) */
1152 glEnable(GL_ALPHA_TEST);
1153 glAlphaFunc(GL_GREATER, 0.5);
1156 tc->trackball = gltrackball_init ();
1159 tc->texshift = calloc(tc->num_texshifts, sizeof(GLfloat));
1160 for ( i = 0 ; i < tc->num_texshifts; i++)
1161 tc->texshift[i] = 0.0;
1163 glNewList(tc->cyllist, GL_COMPILE);
1164 makecyl(30, -0.1, CYL_LEN, 1., 10. / 40.0 * CYL_LEN);
1165 /*makecyl(30, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN); */
1168 glNewList(tc->diamondlist, GL_COMPILE);
1169 makecyl(4, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN);
1175 draw_tunnel (ModeInfo *mi)
1177 tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
1178 Display *dpy = MI_DISPLAY(mi);
1179 Window window = MI_WINDOW(mi);
1182 if (!tc->glx_context)
1185 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tc->glx_context));
1187 glShadeModel(GL_SMOOTH);
1189 glEnable(GL_NORMALIZE);
1190 /* glEnable(GL_CULL_FACE); */
1192 glClear(GL_COLOR_BUFFER_BIT );
1194 update_animation(tc);
1199 glRotatef(180., 0., 1., 0.);
1200 gltrackball_rotate (tc->trackball);
1201 glRotatef(180., 0., 1., 0.);
1205 mi->polygon_count = 0;
1207 update_fog(tc->effects[4].state[0], /*color*/
1208 tc->effects[4].state[1], /*density*/
1209 tc->effects[4].state[2], /*start*/
1210 tc->effects[4].state[3]); /*end*/
1212 /* --- begin composite image assembly --- */
1214 /* head mask and draw diamond tunnel */
1217 draw_cyl(mi, tc, tc->effects[6].state[0], 5, tc->diamondlist, 2);
1219 draw_sign(mi, tc,tc->effects[12].state[0], tc->effects[12].state[1], 1.0 / 1.33, 9, 1);
1220 glDisable(GL_BLEND);
1221 /* then tardis tunnel */
1222 make_wall_tunnel(mi, tc, tc->effects[1].state[0], tc->effects[7].state[0]);
1224 /* then cylinder tunnel */
1226 draw_cyl(mi, tc, tc->effects[3].state[0], 2, tc->cyllist, 1);
1228 /*void draw_sign(mi, tc,z,alpha,aspect,tex,blendmode)*/
1231 draw_sign(mi, tc, tc->effects[2].state[0], tc->effects[2].state[1], 2.0, 1, 0);
1234 draw_sign(mi, tc, tc->effects[5].state[0], tc->effects[5].state[1], 1.0, 3, 0);
1237 draw_sign(mi, tc,1.0, tc->effects[10].state[0], 1.0 / 1.33, 6, 2);
1238 /*who head psychadelic REMOVED*/
1239 /* draw_sign(mi, tc,1.0, tc->effects[11].state[0], 1.0 / 1.33, 8, 0); */
1242 /* draw_sign(mi, tc, tc->effects[8].state[0]tc->effects[8].state[0], 1.0 , 1.0, 4, 1); */
1243 draw_sign(mi, tc, tc->effects[8].state[0], tc->effects[8].state[0], 1.0, 4, 1);
1247 draw_sign(mi, tc,1.0, tc->effects[9].state[0], 1.0 / 1.33, 6, 0);
1249 /* --- end composite image assembly --- */
1254 if (mi->fps_p) do_fps (mi);
1257 check_gl_error("drawing done, calling swap buffers");
1258 glXSwapBuffers(dpy, window);
1261 XSCREENSAVER_MODULE_2 ("TimeTunnel", timetunnel, tunnel)