diff options
Diffstat (limited to 'hacks/glx/timetunnel.c')
-rw-r--r-- | hacks/glx/timetunnel.c | 1240 |
1 files changed, 1240 insertions, 0 deletions
diff --git a/hacks/glx/timetunnel.c b/hacks/glx/timetunnel.c new file mode 100644 index 0000000..723d04d --- /dev/null +++ b/hacks/glx/timetunnel.c @@ -0,0 +1,1240 @@ +/* timetunnel. Based on dangerball.c, hack by Sean Brennan <zettix@yahoo.com>*/ +/* dangerball, Copyright (c) 2001-2018 Jamie Zawinski <jwz@jwz.org> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#define GL_GLEXT_PROTOTYPES 1 + +#include <math.h> /* for log2 */ + +#define DEFAULTS "*delay: 30000 \n" \ + "*count: 30 \n" \ + "*showFPS: False \n" \ + "*timeStart: 0.0 \n" \ + "*timeEnd: 27.79 \n" \ + "*wireframe: False \n" \ + + + +# define free_tunnel 0 +# define release_tunnel 0 +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + +#include "xlockmore.h" +#include "colors.h" +#include "rotator.h" +#include "gltrackball.h" + +#define DEF_START "0.00" +#define DEF_DILATE "1.00" +#define DEF_END "27.79" +#define DEF_LOCKLOGO "False" +#define DEF_DRAWLOGO "True" +#define DEF_REVERSE "False" +#define DEF_FOG "True" +#define DEF_TEXTURE "True" +#define MAX_TEXTURE 10 +#define CYL_LEN 14.0 +#define DIAMOND_LEN 10.0 + +static float start, end, dilate; +static Bool do_texture, drawlogo, wire, reverse, do_fog; +static const char *do_tx1, *do_tx2, *do_tx3, *do_tun1, *do_tun2, *do_tun3; + +static XrmOptionDescRec opts[] = { + {"-texture" , ".texture", XrmoptionNoArg, "true" }, + {"+texture" , ".texture", XrmoptionNoArg, "false" }, + {"-start" , ".start", XrmoptionSepArg, 0 }, + {"-end" , ".end", XrmoptionSepArg, 0 }, + {"-dilate" , ".dilate", XrmoptionSepArg, 0 }, + {"+logo" , ".drawlogo", XrmoptionNoArg, "false" }, + {"-reverse" , ".reverse", XrmoptionNoArg, "true" }, + {"+fog" , ".fog", XrmoptionNoArg, "false" }, + {"-marquee" , ".marquee", XrmoptionSepArg, 0}, + /* {"+marquee" , ".marquee", XrmoptionNoArg, "(none)"}, */ + {"-tardis" , ".tardis", XrmoptionSepArg, 0}, + /* {"+tardis" , ".tardis", XrmoptionNoArg, "(none)"}, */ + {"-head" , ".head", XrmoptionSepArg, 0}, + /* {"+head" , ".head", XrmoptionNoArg, "(none)"}, */ + {"-tun1" , ".tun1", XrmoptionSepArg, 0}, + /* {"+tun1" , ".tun1", XrmoptionNoArg, "(none)"}, */ + {"-tun2" , ".tun2", XrmoptionSepArg, 0}, + /* {"+tun2" , ".tun2", XrmoptionNoArg, "(none)"}, */ + {"-tun3" , ".tun3", XrmoptionSepArg, 0}, + /* {"+tun3" , ".tun3", XrmoptionNoArg, "(none)"}, */ +}; + +static argtype vars[] = { + {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool}, + {&start, "start", "Start", DEF_START, t_Float}, + {&end, "end", "End", DEF_END , t_Float}, + {&dilate, "dilate", "Dilate", DEF_DILATE , t_Float}, + {&drawlogo, "drawlogo", "DrawLogo", DEF_DRAWLOGO , t_Bool}, + {&reverse, "reverse", "Reverse", DEF_REVERSE , t_Bool}, + {&do_fog, "fog", "Fog", DEF_FOG , t_Bool}, + {&do_tx1, "marquee", "Marquee", "(none)", t_String}, + {&do_tx2, "tardis", "Tardis", "(none)", t_String}, + {&do_tx3, "head", "Head", "(none)", t_String}, + {&do_tun1, "tun1", "Tunnel 1", "(none)", t_String}, + {&do_tun2, "tun2", "Tunnel 2", "(none)", t_String}, + {&do_tun3, "tun3", "Tunnel 3", "(none)", t_String}, +}; + +ENTRYPOINT ModeSpecOpt tunnel_opts = {countof(opts), opts, countof(vars), vars, NULL}; +#include "ximage-loader.h" +#include "images/gen/logo-180_png.h" +#include "images/gen/tunnelstar_png.h" +#include "images/gen/timetunnel0_png.h" +#include "images/gen/timetunnel1_png.h" +#include "images/gen/timetunnel2_png.h" + + +#ifdef USE_GL /* whole file */ + +/* ANIMATION CONTROLS */ +/* an effect is a collection of floating point variables that vary with time. +A knot is a timestamp with an array of floats. State is the current values of the floats. +State is set by linearly interpolating between knots */ +typedef struct { + float *knots, *state; + int numknots, knotwidth; + float direction; +} effect_t; + +typedef struct { + GLXContext *glx_context; + rotator *rot; + trackball_state *trackball; + Bool button_down_p; + + int time_oldusec, time_oldsec; + + int num_texshifts; /* animates tunnels. Not an effect. */ + GLfloat pos, *texshift; + + GLuint texture_binds[MAX_TEXTURE], cyllist, diamondlist; + + float effect_time, effect_maxsecs; /* global time controls */ + float start_time, end_time; + + int num_effects; + effect_t *effects; /* array of all effects */ + +} tunnel_configuration; + +static tunnel_configuration *tconf = NULL; + +/* allocate memory and populate effect with knot data */ +static void init_effect(effect_t *e, int numk, int kwidth, + float dir, float *data ) +{ + int i, j; + + e->numknots = numk; + e->knotwidth = kwidth; + e->direction = dir; + e->knots = calloc(numk * kwidth, sizeof(float)); + e->state = calloc(numk, sizeof(float)); + for ( i = 0 ; i < e->numknots ; i++) + for ( j = 0 ; j < e->knotwidth; j++) + e->knots[i * kwidth + j] = data[i * kwidth + j]; +} + +/* static knot data. each effect is listed and knot data is hard coded. + Knots are linerally interpolated to yield float values, depending on + knot width. knot format is [time, data, data, data...]. + Data can be alpha, zvalue, etc. */ +static void init_effects(effect_t *e, int effectnum) +{ + /* effect 1: wall tunnel. percent closed */ + float e1d[6][2] = + {{0.0, 0.055}, + {2.77, 0.055}, + {3.07,1.0}, + {8.08, 1.0}, + {8.08, 0.0}, + {10.0, 0.0}}; + /* effect 2: tardis. distance and alpha */ + float e2d[8][3] = + { {0.0, 0.0 , 0.0}, + {3.44, 0.0 , 0.0}, + {3.36, 5.4 , 0.0}, + {4.24, 3.66, 1.0}, + {6.51, 2.4, 0.94}, + {8.08, 0.75 , 0.0}, + {8.08, 0.0 , 0.0}, + {10.0, 0.0, 0.0}}; + /* effect 3: cylinder. alpha */ + float e3d[5][2] = + {{0.0, 0.0}, + {6.41, 0.00}, + {8.08, 1.0}, + {14.81, 1.0}, + {15.65, 0.0}}; + + /* effect 4: fog. color, density, start, end */ + float e4d[9][5] = + {{0.0 , 1.0, 0.45, 3.0, 15.0}, + {6.40, 1.0, 0.45, 3.0, 14.0}, + {8.08, 1.0, 0.95, 1.0, 14.0}, + {15.17, 1.0, 0.95, 1.0, 6.0}, + {15.51, 1.0, 0.95, 3.0, 8.0}, + {23.35, 1.0, 0.95, 3.0, 8.0}, + {24.02, 0.0, 0.95, 2.3, 5.0}, + {26.02, 0.0, 0.95, 2.3, 5.0}, + {27.72, 0.0, 1.00, 0.3, 0.9} + }; + + /* effect 5: logo. dist, alpha */ + float e5d[7][3] = + {{0.0, 0.0, 0.0}, + {16.52, 0.00, 0.0}, + {16.52, 0.80, 0.01}, + {17.18, 1.15, 1.0}, + {22.36, 5.3, 1.0}, + {22.69, 5.7, 0.0}, + {22.69, 0.0, 0.0} + }; + /* effect 6: diamond tunnel. alpha */ + float e6d[3][2] = + {{0.0, 0.00}, + {15.17, 0.00}, + {15.51,1.0}}; + + /* effect 7: tardis cap draw . positive draws cap*/ + float e7d[3][2] = + {{0.0, -1.00}, + {4.24, -1.00}, + {4.24, 1.00}}; + + /* effect 8: star/asterisk: alpha */ + float e8d[5][2] = + {{0.0, .00}, + {10.77, .00}, + {11.48, 1.00}, + {15.35, 1.00}, + {16.12, 0.00}}; + + /* effect 9: whohead 1 alpha */ + float e9d[5][2] = + {{0.0, .00}, + {13.35, .00}, + {14.48, 1.00}, + {15.17, 1.00}, + {15.97, 0.00}}; + /* {14.87, 1.00}, + {15.17, 0.00}}; */ + + /* effect 10: whohead-brite alpha */ + float e10d[5][2] = + {{0.0, .00}, + {11.34, .00}, + {12.34, .20}, + {13.35, 0.60}, + {14.48, 0.00}}; + /* {13.95, 0.00}}; */ + + /* effect 11: whohead-psy alpha */ + float e11d[5][2] = + {{0.0, .00}, + {14.87, .00}, + {15.17, 1.00}, + {15.91, 0.00}, + {16.12, 0.00}}; + + /* effect 12: whohead-silhouette pos-z, alpha */ + float e12d[6][3] = + {{0.0, 1.0, .00}, + {15.07, 1.0, 0.00}, + {15.07, 1.0, 1.00}, + {16.01, 1.0, 1.00}, + {16.78, 0.5, 1.00}, + {16.78, 0.1, 0.00} }; + + /* effect 1: wall tunnel */ + if (effectnum == 1) + init_effect(e, 6, 2, -0.2, (float *) e1d); + + /* effect 2: tardisl */ + if (effectnum == 2) + init_effect(e, 8, 3, 1.0, (float *) e2d); + + /* effect 3: cylinder tunnel */ + if (effectnum == 3) + init_effect(e, 5, 2, 0.889 , (float *) e3d); + + /* effect 4: fog color */ + if (effectnum == 4) + init_effect(e, 9, 5, 1.0, (float *) e4d); + /* effect 5: logo distance, alpha*/ + if (effectnum == 5) + init_effect(e, 7, 3, 1.0, (float *) e5d); + /* effect 6: diamond tunnel, alpha*/ + if (effectnum == 6) + init_effect(e, 3, 2, 0.24 , (float *) e6d); + + /* effect 7: cap wall tunnel*/ + if (effectnum == 7) + init_effect(e, 3, 2, 1.0, (float *) e7d); + + /* effect 8: asterisk */ + if (effectnum == 8) + init_effect(e, 5, 2, 1.0, (float *) e8d); + + /* effect 9, 10, 11, 12: whoheads */ + if (effectnum == 9 ) + init_effect(e, 5, 2, 1.0, (float *) e9d); + if (effectnum == 10 ) + init_effect(e, 5, 2, 1.0, (float *) e10d); + if (effectnum == 11 ) + init_effect(e, 5, 2, 1.0, (float *) e11d); + if (effectnum == 12 ) + init_effect(e, 6, 3, 1.0, (float *) e12d); +} + + +/* set fog parameters, controlled by effect */ +static void update_fog(float color, float density, float start, float end) +{ + GLfloat col[4]; + + col[0] = col[1] = col[2] = color; + col[3] = 1.0; + + glFogi(GL_FOG_MODE, GL_LINEAR); + glFogfv(GL_FOG_COLOR, col); + glFogf(GL_FOG_DENSITY, density); + glFogf(GL_FOG_START, start); + glFogf(GL_FOG_END, end); +} + +/* set effect's floating point data values by linearally interpolating +between two knots whose times bound the current time: eff_time */ + +static void update_knots(effect_t *e, float eff_time) +{ + int i, j; + float timedelta, lowknot, highknot, *curknot, *nextknot; + + for ( i = 0 ; i < e->numknots ; i++) + if (e->knots[i * e->knotwidth] <= eff_time) { + if ( i < e->numknots - 1) + nextknot = e->knots + (i + 1) * e->knotwidth; + else + /*repeat last knot to carry knot data forward*/ + nextknot = e->knots + (i) * e->knotwidth; + curknot = e->knots + i * e->knotwidth; + if (*nextknot - *curknot <= 0.0) timedelta = 1.0; + else + timedelta = (eff_time-*curknot)/(*nextknot-*curknot); + if (timedelta > 1.0) timedelta = 1.0; + for (j = 1 ; j < e->knotwidth ; j++) { + highknot = (float) *(nextknot + j); + lowknot = (float) *(curknot + j); + e->state[j - 1 ] = lowknot+(highknot-lowknot)*timedelta; + } + } + +} + + +/* Window management, etc + */ +ENTRYPOINT void +reshape_tunnel (ModeInfo *mi, int width, int height) +{ + GLfloat h = (GLfloat) height / (GLfloat) width; + int y = 0; + + if (width > height * 5) { /* tiny window: show middle */ + height = width * 9/16; + y = -height/2; + h = height / (GLfloat) width; + } + + glViewport (0, y, (GLint) width, (GLint) height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective (90.0, 1/h, 0.2, 50.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt( 0.0, 0.0, 0.3, + 0.0, 0.0, 1.0, + 0.0, 1.0, 0.0); + + glClear(GL_COLOR_BUFFER_BIT); +} + + + + +ENTRYPOINT Bool +tunnel_handle_event (ModeInfo *mi, XEvent *event) +{ + tunnel_configuration *tc = &tconf[MI_SCREEN(mi)]; + + if (gltrackball_event_handler (event, tc->trackball, + MI_WIDTH (mi), MI_HEIGHT (mi), + &tc->button_down_p)) + return True; + + return False; +} + +static void setTexParams(void) +{ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +} + +static void update_animation(tunnel_configuration *tc) { + + /* time based, of course*/ + /* shift texture based on elapsed time since previous call*/ + struct timeval tv; + struct timezone tz; + int elapsed_usecs, elapsed_secs, i; + float computed_timeshift; + + /* get new animation time */ + gettimeofday(&tv, &tz); + elapsed_secs = tv.tv_sec - tc->time_oldsec; + elapsed_usecs = tv.tv_usec - tc->time_oldusec; + /* store current time */ + tc->time_oldsec = tv.tv_sec ; + tc->time_oldusec = tv.tv_usec; + /* elaped time. computed timeshift is tenths of a second */ + computed_timeshift = (float) (elapsed_secs * 1000000. + elapsed_usecs)/ + 100000.0; + + /* calibrate effect time to lie between start and end times */ + /* loop if time exceeds end time */ + if (reverse) + tc->effect_time -= computed_timeshift / 10.0 * dilate; + else + tc->effect_time += computed_timeshift / 10.0 * dilate; + if ( tc->effect_time >= tc->end_time) + tc->effect_time = tc->start_time; + if ( tc->effect_time < tc->start_time) + tc->effect_time = tc->end_time;; + + /* move texture shifters in effect's direction, e.g. tardis + tunnel moves backward, effect 1's direction */ + if (reverse) { + tc->texshift[0] -= tc->effects[1].direction * computed_timeshift/ 10.0; + tc->texshift[1] -= tc->effects[3].direction * computed_timeshift/ 10.0; + tc->texshift[2] -= tc->effects[6].direction * computed_timeshift/ 10.0; + + } else { + tc->texshift[0] += tc->effects[1].direction * computed_timeshift/ 10.0; + tc->texshift[1] += tc->effects[3].direction * computed_timeshift/ 10.0; + tc->texshift[2] += tc->effects[6].direction * computed_timeshift/ 10.0; + } + + /* loop texture shifters if necessary */ + for ( i = 0 ; i < tc->num_texshifts; i++) { + if (tc->texshift[i] > 1.0) + tc->texshift[i] -= (int) tc->texshift[i]; + if (tc->texshift[i]< -1.0) + tc->texshift[i] -= (int) tc->texshift[i]; + } + + /* update effect data with current time. Uses linear interpolation */ + for ( i = 1 ; i <= tc->num_effects ; i++) + update_knots(&tc->effects[i], tc->effect_time); + +} /*update_animation*/ + +/* draw a textured(tex) quad at a certain depth (z), and certain alpha (alpha), +with aspect ratio (aspect), and blending mode (blend_mode) of either adding +or subtracting. if alpha is zero or less, nothing happens */ +static void draw_sign(ModeInfo *mi, tunnel_configuration *tc, float z, float alpha, float aspect, + GLuint tex, int blend_mode) +{ + +#ifndef HAVE_JWZGLES + if (alpha > 0.0) { + mi->polygon_count ++; + /* glEnable(GL_BLEND); */ + glBlendColor(0.0, 0.0, 0.0, alpha); + /*glBlendColor(0.0, 0.0, 0.0, 0.0); */ + if (blend_mode == 1) { + glBlendFunc(GL_CONSTANT_ALPHA, + GL_ONE); + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + } else if (blend_mode == 2) { + glBlendFunc(GL_CONSTANT_ALPHA, + GL_ONE); + glBlendEquation(GL_FUNC_ADD); + } else { + glBlendFunc(GL_CONSTANT_ALPHA, + GL_ONE_MINUS_CONSTANT_ALPHA); + glBlendEquation(GL_FUNC_ADD); + } /* blend mode switch */ + +#ifdef HAVE_GLBINDTEXTURE + if (do_texture) + glBindTexture(GL_TEXTURE_2D, tc->texture_binds[tex]); +#endif + glBegin(GL_QUADS); + glTexCoord2f(1.0, 0.0); + glVertex3f(-1.0 , -1.0 * aspect , z); + glTexCoord2f(1.0, 1.0); + glVertex3f(-1.0 , 1.0 * aspect , z); + glTexCoord2f(0.0, 1.0); + glVertex3f(1.0 , 1.0 * aspect , z); + glTexCoord2f(0.0, 0.0); + glVertex3f(1.0 , -1.0 * aspect , z); + glEnd(); + if (blend_mode != 0) { + glBlendFunc(GL_CONSTANT_ALPHA, + GL_ONE_MINUS_CONSTANT_ALPHA); + glBlendEquation(GL_FUNC_ADD); + } + /* glDisable(GL_BLEND); */ + + } +#endif /* !HAVE_JWZGLES */ +} /* draw sign */ + + +/* draw a time tunnel. used for both cylinder and diamond tunnels. + uses texture shifter (indexed by shiftnum) to simulate motion. + tunnel does not move, and is acutally a display list. if alpha = 0, skip */ +static void draw_cyl(ModeInfo *mi, tunnel_configuration *tc, float alpha, int texnum, int listnum, int shiftnum) +{ +#ifndef HAVE_JWZGLES + if (alpha > 0.0) { + if (listnum == tc->diamondlist) + mi->polygon_count += 4; + if (listnum == tc->cyllist) + mi->polygon_count += 30; + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glTranslatef(tc->texshift[shiftnum], 0.0, 0.0); + glMatrixMode(GL_MODELVIEW); + /* glEnable(GL_BLEND); */ + glBlendColor(0.0, 0.0, 0.0, alpha); + glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA); + +#ifdef HAVE_GLBINDTEXTURE + if (do_texture) + glBindTexture(GL_TEXTURE_2D, tc->texture_binds[texnum]); +#endif + glCallList(listnum); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + /* glDisable(GL_BLEND); */ + } +#endif /* HAVE_JWZGLES */ +} + + +/* make tardis type tunnel. Starts as walls and then +grows to outline of tardis. percent is how complete +tardis outline is. cap is to draw cap for nice fog effects */ + +static void make_wall_tunnel(ModeInfo *mi, tunnel_configuration *tc, float percent, float cap) +{ + /* tardis is about 2x1, so wrap tex around, starting at the base*/ + /* tex coords are: + + _tl__tr_ + | | +l| |r + | | + -bl__br_ + that's br=bottom right, etc. ttr is top-top-right */ + + float half_floor= 0.08333333333333333, + full_wall = 0.33333333333333333; + float br1, + r0 , r1 , + tr0, tr1, + tl0, tl1, + l0 , l1 , + depth=0.3, zdepth=15.0; + /* zdepth is how far back tunnel goes */ + /* depth is tex coord scale. low number = fast texture shifting */ + + float textop, texbot; + float height; + + br1 = half_floor; + r0 = br1 ; + r1 = r0 + full_wall; + tr0 = r1; + tr1 = r1 + half_floor; + tl0 = tr1; + tl1 = tl0 + half_floor; + l0 = tr1; + l1 = l0 + full_wall; + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glRotatef(90.0, 0.0, 0.0, 1.0); + glTranslatef(tc->texshift[0], 0.0, 0.0); + glMatrixMode(GL_MODELVIEW); + +#ifdef HAVE_GLBINDTEXTURE + if (do_texture) + glBindTexture(GL_TEXTURE_2D, tc->texture_binds[0]); +#endif + glColor3f(1.0, 1.0, 0.0); + if (cap > 0.0 && percent > 0.0 && drawlogo && do_fog) { + mi->polygon_count += 6; + glBegin(GL_TRIANGLE_FAN); + glVertex3f(0.0, 0.0, zdepth); + glVertex3f(-1.0, -2.0, zdepth); + glVertex3f(1.0, -2.0, zdepth); + glVertex3f(1.0, 2.0, zdepth); + glVertex3f(0.2, 2.0, zdepth); + glVertex3f(0.2, 2.2, zdepth); + glVertex3f(-0.2, 2.2, zdepth); + glVertex3f(-0.2, 2.0, zdepth); + glVertex3f(-1.0, 2.0, zdepth); + glVertex3f(-1.0, -2.0, zdepth); + glEnd(); + } + if (percent > ( full_wall * 2.0)) { + glBegin(GL_QUADS); + + height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0); + if (height > 1.0) height = 1.0; + + + if ( height > 0.8) { + mi->polygon_count += 2; + if ( height > 0.90) { + mi->polygon_count += 2; + /* TTTR */ + texbot = tr0; + textop = tr0 + half_floor * height; + glTexCoord2f(0.0, texbot); + glVertex3f(0.2, 2.2, 0.0); + + glTexCoord2f(0.0, textop); + glVertex3f(2.0 - height * 2.0, 2.2, 0.0); + + glTexCoord2f(depth, textop); + glVertex3f(2.0 - height * 2.0, 2.2, zdepth); + + glTexCoord2f(depth, texbot); + glVertex3f(0.2, 2.2, zdepth); + + /* TTTL */ + texbot = tl1 - half_floor * height; + textop = tl1; + glTexCoord2f(0.0, texbot); + glVertex3f(-2.0 + height * 2.0, 2.2, 0.0); + + glTexCoord2f(0.0, textop); + glVertex3f(-0.2, 2.2, 0.0); + + glTexCoord2f(depth, textop); + glVertex3f(-0.2, 2.2, zdepth); + + glTexCoord2f(depth, texbot); + glVertex3f(-2.0 + height * 2.0, 2.2, zdepth); + } + if (height > 0.90) height = 0.90; + + /* TTR */ + texbot = tr0; + textop = tr0 + half_floor * height; + glTexCoord2f(0.0, texbot); + glVertex3f(0.2, 2.0, 0.0); + + glTexCoord2f(0.0, textop); + glVertex3f(0.2, 0.4 + height * 2.0, 0.0); + + glTexCoord2f(depth, textop); + glVertex3f(0.2, 0.4 + height * 2.0, zdepth); + + glTexCoord2f(depth, texbot); + glVertex3f(0.2, 2.0, zdepth); + + /* TTL */ + texbot = tl1 - half_floor * height; + textop = tl1; + glTexCoord2f(0.0, texbot); + /*glVertex3f(-.2, 2.0 + (0.9 - height) * 2.0, 0.0); */ + glVertex3f(-.2, 0.4 + height * 2.0, 0.0); + + glTexCoord2f(0.0, textop); + glVertex3f(-.2, 2.0, 0.0); + + glTexCoord2f(depth, textop); + glVertex3f(-.2, 2.0, zdepth); + + glTexCoord2f(depth, texbot); + glVertex3f(-.2, 0.4 + height * 2.0, zdepth); + } + + height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0); + if (height > 0.8) height = 0.8; + + + mi->polygon_count += 2; + /* TR */ + texbot = tr0; + textop = tr0 + half_floor * height; + glTexCoord2f(0.0, texbot); + glVertex3f(1.0, 2.0, 0.0); + + glTexCoord2f(0.0, textop); + glVertex3f(1.0 - height, 2.0, 0.0); + + glTexCoord2f(depth, textop); + glVertex3f(1.0 - height, 2.0, zdepth); + + glTexCoord2f(depth, texbot); + glVertex3f(1.0, 2.0, zdepth); + + /* TL */ + texbot = tl1 - half_floor * height; + textop = tl1; + glTexCoord2f(0.0, texbot); + glVertex3f(-1.0 + height, 2.0, 0.0); + + glTexCoord2f(0.0, textop); + glVertex3f(-1.0, 2.0, 0.0); + + glTexCoord2f(depth, textop); + glVertex3f(-1.0, 2.0, zdepth); + + glTexCoord2f(depth, texbot); + glVertex3f(-1.0 + height, 2.0, zdepth); + + height = (percent - full_wall * 2.0) /( 1.0 - full_wall * 2.0); + + if (height > 1.0) height = 1.0; + + + mi->polygon_count += 2; + /* BR */ + texbot = tr0; + textop = tr0 + half_floor * height; + glTexCoord2f(0.0, texbot); + glVertex3f(1.0, -2.0, 0.0); + + glTexCoord2f(0.0, textop); + glVertex3f(1.0 - height, -2.0, 0.0); + + glTexCoord2f(depth, textop); + glVertex3f(1.0 - height, -2.0, zdepth); + + glTexCoord2f(depth, texbot); + glVertex3f(1.0, -2.0, zdepth); + + /* BL */ + texbot = tl1 - half_floor * height; + textop = tl1; + glTexCoord2f(0.0, texbot); + glVertex3f(-1.0 + height, -2.0, 0.0); + + glTexCoord2f(0.0, textop); + glVertex3f(-1.0, -2.0, 0.0); + + glTexCoord2f(depth, textop); + glVertex3f(-1.0, -2.0, zdepth); + + glTexCoord2f(depth, texbot); + glVertex3f(-1.0 + height, -2.0, zdepth); + + + glEnd(); + } + + if (percent > 0.0) { + mi->polygon_count += 2; + glBegin(GL_QUADS); + height = percent / ( full_wall * 2.0); + if (height > 1.0) height = 1.0; + textop = (l0 + l1) / 2.0 - full_wall * 0.5 * height; + texbot = (l0 + l1) / 2.0 + full_wall * 0.5 * height; + + glTexCoord2f(0.0, textop); + glVertex3f(-1.0, height * 2, 0.0); + + glTexCoord2f(0.0, texbot); + glVertex3f(-1.0, -height * 2, 0.0); + + glTexCoord2f(depth, texbot); + glVertex3f(-1.0, -height * 2, zdepth); + + glTexCoord2f(depth, textop); + glVertex3f(-1.0, height * 2, zdepth); + + textop = (r0 + r1) / 2.0 - full_wall * 0.5 * height; + texbot = (r0 + r1) / 2.0 + full_wall * 0.5 * height; + + glTexCoord2f(0.0, texbot); + glVertex3f(1.0, height * 2, 0.0); + + glTexCoord2f(0.0, textop); + glVertex3f(1.0, -height * 2, 0.0); + + glTexCoord2f(depth, textop); + glVertex3f(1.0, -height * 2, zdepth); + + glTexCoord2f(depth, texbot); + glVertex3f(1.0, height * 2, zdepth); + glEnd(); + } + + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); +} /* make_wall_tunnel */ + +/* wraps an int to between min and max. + Kind of like the remainder when devided by (max - min). + Used to create torus mapping on square array */ +static int wrapVal(int val, int min, int max) +{ + int ret; + + ret = val; + if (val >= max) + ret = min + (val - max ) % (max - min); + if (val < min) + ret = max - (min - val) % (max - min); + return(ret); +} + +/*=================== Load Texture =========================================*/ +/* ripped from atunnel.c, Copyright (c) E. Lassauge, 2003-2004. */ +/* modified like so by Sean Brennan: + take texture object for glbind + removed xlock stuff + Added filters: + blur color / alpha channel [3x3 box filter, done [blur] times + anegative : create b/w image from zero alpha. zero alpha gets bw_color, + nonzero alpha gets 1.0 - bwcolor, then alpha flipped to 1-alpha. + + Inputs: xpm structure, or filename of xmp image. if filename == NULL, use structure. + Outputs: texture bound to texutre Id texbind. + +*/ + +static float mylog2(float x) { return ( log(x) / log(2));} + +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) +{ + /* looping and temporary array index variables */ + int ix, iy, bx, by, indx, indy, boxsize, cchan, tmpidx, dtaidx; + + float boxdiv, tmpfa, blursum ; + unsigned char *tmpbuf, tmpa; + Bool rescale; + + + XImage *teximage; /* Texture data */ + + rescale = False; + + boxsize = 2; + boxdiv = 1.0 / ( boxsize * 2.0 + 1.0) / ( boxsize * 2.0 + 1.0); + + + if (filename) + teximage = file_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi), + filename); + else + teximage = image_data_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi), + fn, size); + if (teximage == NULL) { + fprintf(stderr, "%s: error reading the texture.\n", progname); + glDeleteTextures(1, &texbind); + do_texture = False; + exit(0); + } + + /* check if image is 2^kumquat, where kumquat is an integer between 1 and 10. Recale to + nearest power of 2. */ + tmpfa = mylog2((float) teximage->width); + bx = 2 << (int) (tmpfa -1); + if (bx != teximage->width) { + rescale = True; + if ((tmpfa - (int) tmpfa) > 0.5849) + bx = bx * 2; + } + tmpfa = mylog2((float) teximage->height); + by = 2 << (int) (tmpfa - 1); + if (by != teximage->height) { + rescale = True; + if ((tmpfa - (int) tmpfa) > 0.5849) + by = by * 2; + } + + if (rescale) { +#ifndef HAVE_JWZGLES + tmpbuf = calloc(bx * by * 4, sizeof(unsigned char)); + if (gluScaleImage(GL_RGBA, teximage->width, teximage->height, GL_UNSIGNED_BYTE, teximage->data, + bx, by, GL_UNSIGNED_BYTE, tmpbuf)) + check_gl_error("scale image"); + + free(teximage->data); + teximage->data = (char *) tmpbuf; + teximage->width = bx; + teximage->height= by; +#endif /* !HAVE_JWZGLES */ + } + /* end rescale code */ + + if (anegative ) { + for (ix = 0 ; ix < teximage->height * teximage->width; ix++) + { + if (!teximage->data[ ix * 4 + 3]) { + teximage->data[ ix * 4 + 3] = (unsigned char) 0xff; + tmpa = (unsigned char) (bw_color * 0xff); + } else { + if (onealpha) + teximage->data[ ix * 4 + 3] = (unsigned char) 0xff; + else + teximage->data[ ix * 4 + 3] = (unsigned char) 0xff - + teximage->data[ ix * 4 + 3]; + tmpa = (unsigned char) ((1.0 - bw_color) * 0xff); + } + /* make texture uniform b/w color */ + teximage->data[ ix * 4 + 0] = + (unsigned char) ( tmpa); + teximage->data[ ix * 4 + 1] = + (unsigned char) ( tmpa); + teximage->data[ ix * 4 + 2] = + (unsigned char) ( tmpa); + /* negate alpha */ + } + } + + if (blur > 0) { + if (! anegative ) /* anegative alread b/w's the whole image */ + for (ix = 0 ; ix < teximage->height * teximage->width; ix++) + if (!teximage->data[ ix * 4 + 3]) + { + teximage->data[ ix * 4 + 0] = + (unsigned char) ( 255.0 * bw_color); + teximage->data[ ix * 4 + 1] = + (unsigned char) ( 255.0 * bw_color); + teximage->data[ ix * 4 + 2] = + (unsigned char) ( 255.0 * bw_color); + } + ; + tmpbuf = calloc(teximage->height * teximage->width * 4, sizeof(unsigned char) ) ; + while (blur--) { + /* zero out tmp alpha buffer */ + for (iy = 0 ; iy <teximage->height * teximage->width * 4 ; iy++) + tmpbuf[iy] = 0; + for (cchan = 0; cchan < 4 ; cchan++) { + for (iy = 0 ; iy < teximage->height ; iy++) { + for (ix = 0 ; ix < teximage->width ; ix++) { + dtaidx = (teximage->width * iy + ix) * 4; + tmpa = teximage->data[dtaidx + cchan]; + tmpfa = (float) tmpa * boxdiv; + /* box filter */ + for (by = -boxsize ; by <= boxsize; by++) { + for (bx = -boxsize ; bx <= boxsize; bx++) { + indx = wrapVal(ix + bx, 0, teximage->width); + indy = wrapVal(iy + by, 0, teximage->height); + tmpidx = (teximage->width * indy + indx) * 4; + blursum = tmpfa; + tmpbuf[tmpidx + cchan] += (unsigned char) blursum; + } /* for bx */ + } /* for by */ + } /* for ix */ + } /* for iy */ + } /* for cchan */ + /* copy back buffer */ + for (ix = 0 ; ix < teximage->height * teximage->width * 4; ix++) + teximage->data[ix] = tmpbuf[ix]; + } /*while blur */ + free(tmpbuf); /*tidy*/ + } /* if blur */ + + + + + clear_gl_error(); +#ifdef HAVE_GLBINDTEXTURE + glBindTexture(GL_TEXTURE_2D, texbind); + clear_gl_error(); /* WTF? sometimes "invalid op" from glBindTexture! */ +#endif + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, teximage->width, teximage->height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, teximage->data); + check_gl_error("texture"); + setTexParams(); + XDestroyImage(teximage); +} + +/* creates cylinder for time tunnel. sides, zmin, zmax, rad(ius) obvious. + stretch scales texture coords; makes tunnel go slower the larger it is. + not drawn, but put into display list. */ +static void makecyl(int sides, float zmin, float zmax, float rad, float stretch) +{ + int i; + float theta; + + /* cap */ + if (do_fog) { + glBegin(GL_TRIANGLE_FAN); + glTexCoord2f(1.0, 0.0); + glVertex3f(0.0 , 0.0 , zmax); + for (i = 0 ; i <= sides; i++) { + theta = 2.0 * M_PI * ((float) i / (float) sides); + glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax); + } + glVertex3f(cos(0.0) * rad, sin(0.0) * rad, zmax); + glEnd(); + } + + glBegin(GL_QUAD_STRIP); + for (i = 0 ; i <= sides; i++) + { + if ( i != sides) { + theta = 2.0 * M_PI * ((float) i / (float) sides); + glTexCoord2f(0.0, 1.0 * (float) i / (float) sides); + glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin); + glTexCoord2f(stretch, 1.0 * (float) i / (float) sides); + glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax); + } else { + theta = 0.0; + glTexCoord2f(0.0, 1.0); + glVertex3f(cos(theta) * rad, sin(theta) * rad, zmin); + glTexCoord2f(stretch, 1.0); + glVertex3f(cos(theta) * rad, sin(theta) * rad, zmax); + } + } + glEnd(); +} + +ENTRYPOINT void +init_tunnel (ModeInfo *mi) +{ + int i; + + tunnel_configuration *tc; + + wire = MI_IS_WIREFRAME(mi); + +# ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */ + wire = 0; +# endif + + MI_INIT (mi, tconf); + + tc = &tconf[MI_SCREEN(mi)]; + + tc->glx_context = init_GL(mi); + + tc->cyllist = glGenLists(1); + tc->diamondlist = glGenLists(1); + tc->num_effects = 12; + tc->num_texshifts = 3; + tc->effect_time = 0.0; + tc->effect_maxsecs = 30.00; + /* check bounds on cmd line opts */ + if (start > tc->effect_maxsecs) start = tc->effect_maxsecs; + if (end > tc->effect_maxsecs) end = tc->effect_maxsecs; + if (start < tc->effect_time) start = tc->effect_time; + if (end < tc->effect_time) end = tc->effect_time; + + /* set loop times, in seconds */ + tc->start_time = start; + tc->end_time = end; + + /* reset animation knots, effect 0 not defined. */ + tc->effects = malloc(sizeof(effect_t) * ( tc->num_effects + 1)); + for ( i = 1; i <= tc->num_effects ; i++) + init_effects(&tc->effects[i], i); + + if (wire) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + do_texture = False; + } + + if (do_texture) + { + /* the following textures are loaded, and possible overridden: + tunnel 1, tunnel 2, tunnel 3, marquee, tardis, head */ + glGenTextures(MAX_TEXTURE, tc->texture_binds); + + /*LoadTexture(*mi, *data, size, *filename, texbind, bluralpha, bw_color, anegative, onealpha)*/ + if (strcasecmp (do_tun1, "(none)")) /* tunnel 1 */ + LoadTexture(mi, NULL, 0, do_tun1, tc->texture_binds[0], 0,0.0, False, False); + else + LoadTexture(mi, timetunnel0_png, sizeof(timetunnel0_png), NULL, tc->texture_binds[0], 0, 0.0, False, False); + if (strcasecmp (do_tun2, "(none)")) /* tunnel 2 */ + LoadTexture(mi, NULL, 0, do_tun2, tc->texture_binds[2], 0,0.0, False, False); + else + LoadTexture(mi, timetunnel1_png, sizeof(timetunnel1_png), NULL, tc->texture_binds[2], 0, 0.0, False, False); + if (strcasecmp (do_tun3, "(none)")) /* tunnel 3 */ + LoadTexture(mi, NULL, 0, do_tun3, tc->texture_binds[5], 0,0.0, False, False); + else + LoadTexture(mi, timetunnel2_png, sizeof(timetunnel2_png), NULL, tc->texture_binds[5], 0, 0.0, False, False); + LoadTexture(mi, tunnelstar_png, sizeof(tunnelstar_png), NULL, tc->texture_binds[4], 0, 0.0, False, False); + if (strcasecmp (do_tx1, "(none)")) /* marquee */ + LoadTexture(mi, NULL, 0, do_tx1, tc->texture_binds[3], 0,0.0, False, False); +#ifndef HAVE_JWZGLES /* logo_180_png is 180px which is not a power of 2! */ + else + LoadTexture(mi, logo_180_png, sizeof(logo_180_png), NULL, tc->texture_binds[3], 0,0.0, False, False); +#endif + if (strcasecmp (do_tx2, "(none)")) /* tardis */ + LoadTexture(mi, NULL, 0, do_tx2, tc->texture_binds[1], 0, 0.0 ,False, False); +#ifndef HAVE_JWZGLES /* logo_180_png is 180px which is not a power of 2! */ + else + LoadTexture(mi, logo_180_png, sizeof(logo_180_png), NULL, tc->texture_binds[1], 0,0.0, False, False); +#endif + if (strcasecmp (do_tx3, "(none)")) { /* head */ + LoadTexture(mi, NULL, 0, do_tx3, tc->texture_binds[6], 0, 0.0 ,False, False); + /* negative */ + LoadTexture(mi, NULL, 0, do_tx3, tc->texture_binds[9], 2,1.0, True, True); +#ifndef HAVE_JWZGLES /* logo_180_png is 180px which is not a power of 2! */ + } else { + LoadTexture(mi, logo_180_png, sizeof(logo_180_png), NULL, tc->texture_binds[6], 0,0.0, False, False); + /* negative */ + LoadTexture(mi, logo_180_png, sizeof(logo_180_png), NULL, tc->texture_binds[9], 2,1.0, True, True); +#endif + } + glEnable(GL_TEXTURE_2D); + check_gl_error("tex"); + } + + reshape_tunnel (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); + + glDisable(GL_DEPTH_TEST); /* who needs it? ;-) */ + + if (do_fog) + glEnable(GL_FOG); + + if (!wire) + { + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.5); + } + + tc->trackball = gltrackball_init (True); + + + tc->texshift = calloc(tc->num_texshifts, sizeof(GLfloat)); + for ( i = 0 ; i < tc->num_texshifts; i++) + tc->texshift[i] = 0.0; + + glNewList(tc->cyllist, GL_COMPILE); + makecyl(30, -0.1, CYL_LEN, 1., 10. / 40.0 * CYL_LEN); + /*makecyl(30, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN); */ + glEndList(); + + glNewList(tc->diamondlist, GL_COMPILE); + makecyl(4, -0.5, DIAMOND_LEN, 1., 4. / 40 * DIAMOND_LEN); + glEndList(); +} + + +ENTRYPOINT void +draw_tunnel (ModeInfo *mi) +{ + tunnel_configuration *tc = &tconf[MI_SCREEN(mi)]; + Display *dpy = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + + + if (!tc->glx_context) + return; + + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tc->glx_context)); + + glShadeModel(GL_SMOOTH); + + glEnable(GL_NORMALIZE); + /* glEnable(GL_CULL_FACE); */ + + glClear(GL_COLOR_BUFFER_BIT ); + + update_animation(tc); + + + glPushMatrix (); + + glRotatef(180., 0., 1., 0.); + gltrackball_rotate (tc->trackball); + glRotatef(180., 0., 1., 0.); + + + + mi->polygon_count = 0; + + update_fog(tc->effects[4].state[0], /*color*/ + tc->effects[4].state[1], /*density*/ + tc->effects[4].state[2], /*start*/ + tc->effects[4].state[3]); /*end*/ + + /* --- begin composite image assembly --- */ + + /* head mask and draw diamond tunnel */ + + glEnable(GL_BLEND); + draw_cyl(mi, tc, tc->effects[6].state[0], 5, tc->diamondlist, 2); + if (drawlogo) + draw_sign(mi, tc,tc->effects[12].state[0], tc->effects[12].state[1], 1.0 / 1.33, 9, 1); + glDisable(GL_BLEND); + /* then tardis tunnel */ + make_wall_tunnel(mi, tc, tc->effects[1].state[0], tc->effects[7].state[0]); + + /* then cylinder tunnel */ + glEnable(GL_BLEND); + draw_cyl(mi, tc, tc->effects[3].state[0], 2, tc->cyllist, 1); + + /*void draw_sign(mi, tc,z,alpha,aspect,tex,blendmode)*/ + /* tardis */ + if (drawlogo) + draw_sign(mi, tc, tc->effects[2].state[0], tc->effects[2].state[1], 2.0, 1, 0); + /* marquee */ + if (drawlogo) + draw_sign(mi, tc, tc->effects[5].state[0], tc->effects[5].state[1], 1.0, 3, 0); + /*who head brite*/ + if (drawlogo) + draw_sign(mi, tc,1.0, tc->effects[10].state[0], 1.0 / 1.33, 6, 2); + /*who head psychadelic REMOVED*/ + /* draw_sign(mi, tc,1.0, tc->effects[11].state[0], 1.0 / 1.33, 8, 0); */ + + /* star */ + /* draw_sign(mi, tc, tc->effects[8].state[0]tc->effects[8].state[0], 1.0 , 1.0, 4, 1); */ + draw_sign(mi, tc, tc->effects[8].state[0], tc->effects[8].state[0], 1.0, 4, 1); + + /* normal head */ + if (drawlogo) + draw_sign(mi, tc,1.0, tc->effects[9].state[0], 1.0 / 1.33, 6, 0); + + /* --- end composite image assembly --- */ + + + glPopMatrix (); + + if (mi->fps_p) do_fps (mi); + glFinish(); + + check_gl_error("drawing done, calling swap buffers"); + glXSwapBuffers(dpy, window); +} + +XSCREENSAVER_MODULE_2 ("TimeTunnel", timetunnel, tunnel) + +#endif /* USE_GL */ |