From ae69a754244c4e475c8d2591772ca8e005071d83 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 18 Feb 2019 11:55:41 +0100 Subject: Update to 5.42 --- hacks/glx/unknownpleasures.c | 698 +++++++++++++++++++++++++++---------------- 1 file changed, 446 insertions(+), 252 deletions(-) (limited to 'hacks/glx/unknownpleasures.c') diff --git a/hacks/glx/unknownpleasures.c b/hacks/glx/unknownpleasures.c index 9802566..a52819f 100644 --- a/hacks/glx/unknownpleasures.c +++ b/hacks/glx/unknownpleasures.c @@ -1,4 +1,4 @@ -/* unknownpleasures, Copyright (c) 2013-2014 Jamie Zawinski +/* unknownpleasures, Copyright (c) 2013-2018 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -8,40 +8,48 @@ * software for any purpose. It is provided "as is" without express or * implied warranty. * - * Translated from Mathematica code by Archery: - * http://intothecontinuum.tumblr.com/post/27443100682/in-july-1967-astronomers-at-the-cavendish + * A very particular waterfall chart. * * Interestingly, the original image is copyright-free: * http://adamcap.com/2011/05/19/history-of-joy-division-unknown-pleasures-album-art/ + * https://blogs.scientificamerican.com/sa-visual/pop-culture-pulsar-origin-story-of-joy-division-s-unknown-pleasures-album-cover-video/ * https://en.wikipedia.org/wiki/Unknown_Pleasures * - * TODO: - * - * - Performance is not great. Spending half our time in compute_line() - * and half our time in glEnd(). It's a vast number of cos/pow calls, - * and a vast number of polygons. I'm not sure how much could be cached. + * "Eighty successive periods of the first pulsar observed, CP1919 + * (Cambridge pulsar at 19 hours 19 minutes right ascension), are stacked + * on top of one another using the average period of 1.33730 seconds in + * this computer-generated illustration produced at the Arecibo Radio + * Observatory in Puerto Rico. Athough the leading edges of the radio + * pulses occur within a few thousandths of a second of the predicted + * times, the shape of the pulses is quite irregular. Some of this + * irregularity in radio reception is caused by the effects of + * transmission through the interstellar medium. The average pulse width + * is less than 50 thousandths of a second." * - * - There's too low periodicity vertically on the screen. + * TODO: * - * - There's too low periodicity in time. + * - Load images and feed them line by line into the plotter, so it scrolls. * - * - Could take advantage of time periodicity for caching: just save every - * poly for an N second loop. That would be a huge amount of RAM though. + * - Same but use the image as a mask against the random graph data. * - * - At low resolutions, GL_POLYGON_OFFSET_FILL seems to work poorly - * and the lines get blocky. + * - Take a function generator program as a command line argument: + * read lines of N float values from it, interpolate to full width. */ +#define DEF_ORTHO "True" +#define DEF_SPEED "1.0" +#define DEF_RESOLUTION "100" +#define DEF_AMPLITUDE "0.13" +#define DEF_NOISE "1.0" +#define DEF_ASPECT "1.9" +#define DEF_BUZZ "False" #define DEFAULTS "*delay: 30000 \n" \ "*count: 80 \n" \ - "*resolution: 100 \n" \ - "*ortho: True \n" \ "*showFPS: False \n" \ "*wireframe: False \n" \ "*geometry: =800x800" "\n" \ -# define free_unk 0 # define release_unk 0 #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) @@ -53,7 +61,15 @@ #ifdef USE_GL /* whole file */ -#define DEF_SPEED "1.0" +#undef DEBUG + +Bool ortho_arg; +GLfloat speed_arg; +int resolution_arg; +GLfloat amplitude_arg; +GLfloat noise_arg; +GLfloat aspect_arg; +Bool buzz_arg; typedef struct { @@ -61,38 +77,91 @@ typedef struct { trackball_state *trackball; Bool button_down_p; Bool orthop; - GLfloat resolution; - int count; - GLfloat t; + double speed, tick; + int resolution; /* X points */ + int count; /* Y lines */ + GLfloat amplitude; /* Z height */ + int frames; /* Number of renders of each line, for buzzing */ + GLfloat noise; /* Number of peaks in each line */ + GLfloat aspect; /* Shape of the plot */ + GLuint base; /* Display list for back */ + GLuint *lines; /* Display lists for each edge * face * frame */ + GLfloat *heights; /* Animated elevation / alpha of each line */ + GLfloat fg[4], bg[4]; /* Colors */ } unk_configuration; static unk_configuration *bps = NULL; -static GLfloat speed; - static XrmOptionDescRec opts[] = { { "-speed", ".speed", XrmoptionSepArg, 0 }, { "-resolution", ".resolution", XrmoptionSepArg, 0 }, + { "-amplitude", ".amplitude", XrmoptionSepArg, 0 }, + { "-noise", ".noise", XrmoptionSepArg, 0 }, + { "-aspect", ".aspect", XrmoptionSepArg, 0 }, { "-ortho", ".ortho", XrmoptionNoArg, "True" }, { "-no-ortho", ".ortho", XrmoptionNoArg, "False" }, + { "-buzz", ".buzz", XrmoptionNoArg, "True" }, + { "-no-buzz", ".buzz", XrmoptionNoArg, "False" }, }; static argtype vars[] = { - {&speed, "speed", "Speed", DEF_SPEED, t_Float}, + {&ortho_arg, "ortho", "Ortho", DEF_ORTHO, t_Bool}, + {&speed_arg, "speed", "Speed", DEF_SPEED, t_Float}, + {&resolution_arg, "resolution", "Resolution", DEF_RESOLUTION, t_Int}, + {&litude_arg, "amplitude", "Amplitude", DEF_AMPLITUDE, t_Float}, + {&noise_arg, "noise", "Noise", DEF_NOISE, t_Float}, + {&aspect_arg, "aspect", "Aspect", DEF_ASPECT, t_Float}, + {&buzz_arg, "buzz", "Buzz", DEF_BUZZ, t_Bool}, }; ENTRYPOINT ModeSpecOpt unk_opts = {countof(opts), opts, countof(vars), vars, NULL}; -/* Window management, etc +/* Returns the current time in seconds as a double. */ +static double +double_time (void) +{ + struct timeval now; +# ifdef GETTIMEOFDAY_TWO_ARGS + struct timezone tzp; + gettimeofday(&now, &tzp); +# else + gettimeofday(&now); +# endif + + return (now.tv_sec + ((double) now.tv_usec * 0.000001)); +} + + +static void +parse_color (ModeInfo *mi, char *res, char *class, GLfloat *a) +{ + XColor c; + char *s = get_string_resource(mi->dpy, res, class); + if (! XParseColor (MI_DISPLAY(mi), MI_COLORMAP(mi), s, &c)) + { + fprintf (stderr, "%s: can't parse %s color %s", progname, res, s); + exit (1); + } + if (s) free (s); + a[0] = c.red / 65536.0; + a[1] = c.green / 65536.0; + a[2] = c.blue / 65536.0; + a[3] = 1.0; +} + + ENTRYPOINT void reshape_unk (ModeInfo *mi, int width, int height) { unk_configuration *bp = &bps[MI_SCREEN(mi)]; + int wire = MI_IS_WIREFRAME(mi); GLfloat h = (GLfloat) height / (GLfloat) width; int y = 0; + int i; + int new_count; if (width > height * 5) { /* tiny window: show middle */ height = width*1.5; @@ -104,13 +173,15 @@ reshape_unk (ModeInfo *mi, int width, int height) if (bp->orthop) { + int magic = 700; + int range = 30; /* Must be small or glPolygonOffset doesn't work. */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluPerspective (1.0, 1/h, 690, 710); + gluPerspective (1.0, 1/h, magic-range/2, magic+range/2); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - gluLookAt( 0, 0, 700, + gluLookAt( 0, 0, magic, 0, 0, 0, 0, 1, 0); if (width < height) @@ -121,7 +192,7 @@ reshape_unk (ModeInfo *mi, int width, int height) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluPerspective (30.0, 1/h, 20.0, 40.0); + gluPerspective (30.0, 1/h, 1.0, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -132,10 +203,72 @@ reshape_unk (ModeInfo *mi, int width, int height) glScalef (1/h, 1/h, 1); } + new_count = MI_COUNT(mi); + +# if 0 + /* Lower the resolution to get a decent frame rate on iPhone 4s */ + if (mi->xgwa.width <= 640 || mi->xgwa.height <= 640) + new_count /= 3; +# endif + + /* Lower it even further for iPhone 3 */ + if (mi->xgwa.width <= 480 || mi->xgwa.height <= 480) + new_count /= 2; + + if (wire) new_count /= 2; + + if (new_count < 1) new_count = 1; + + if (bp->count != new_count || !bp->lines) + { + if (bp->lines) + { + for (i = 0; i < bp->count * bp->frames * 2; i++) + glDeleteLists (bp->lines[i], 1); + free (bp->lines); + free (bp->heights); + } + + bp->count = new_count; + bp->lines = (GLuint *) + malloc (bp->count * bp->frames * 2 * sizeof(*bp->lines)); + for (i = 0; i < bp->count * bp->frames * 2; i++) + bp->lines[i] = glGenLists (1); + bp->heights = (GLfloat *) calloc (bp->count, sizeof(*bp->heights)); + } + + { + GLfloat lw = 1; + GLfloat s = 1; + + if (MI_WIDTH(mi) > 2560) lw = 4; /* Retina displays */ +# ifdef HAVE_COCOA + else if (MI_WIDTH(mi) > 1280) lw = 3; /* WTF */ +# endif + else if (MI_WIDTH(mi) > 1920) lw = 3; + else if (mi->xgwa.width > 640 && mi->xgwa.height > 640) lw = 2; + +# ifdef HAVE_MOBILE + lw = 4; + s = 1.4; +# else + /* Make the image fill the screen a little more fully */ + if (mi->xgwa.width <= 640 || mi->xgwa.height <= 640) + s = 1.2; +# endif + + glScalef (s, s, s); + glLineWidth (lw); + } + glClear(GL_COLOR_BUFFER_BIT); } +# ifdef DEBUG +static GLfloat poly1 = 0, poly2 = 0; +# endif + ENTRYPOINT Bool unk_handle_event (ModeInfo *mi, XEvent *event) { @@ -161,6 +294,26 @@ unk_handle_event (ModeInfo *mi, XEvent *event) gltrackball_mousewheel (bp->trackball, b, speed, !!event->xbutton.state); return True; } + +# ifdef DEBUG + else if (event->type == KeyPress) + { + KeySym keysym; + char c = 0; + GLfloat i = 0.1; + XLookupString (&event->xkey, &c, 1, &keysym, 0); + switch (keysym) { + case XK_Up: poly1 += i; break; + case XK_Down: poly1 -= i; break; + case XK_Left: poly2 += i; break; + case XK_Right: poly2 -= i; break; + default: break; + } + fprintf (stderr,"%.2f %.2f\n", poly1, poly2); + return True; + } +# endif /* DEBUG */ + else if (gltrackball_event_handler (event, bp->trackball, MI_WIDTH (mi), MI_HEIGHT (mi), &bp->button_down_p)) @@ -176,11 +329,117 @@ unk_handle_event (ModeInfo *mi, XEvent *event) } +/* Like cos but constrained to [-pi, +pi] */ +static GLfloat +cos1 (GLfloat th) +{ + if (th < -M_PI) th = -M_PI; + if (th > M_PI) th = M_PI; + return cos (th); +} + + +/* Returns an array of floats for one new row, range [0, 1.0] */ +static double * +generate_signal (ModeInfo *mi) +{ + unk_configuration *bp = &bps[MI_SCREEN(mi)]; + double *points = (double *) calloc (sizeof(*points), bp->resolution); + double *p; + int i, j; + int nspikes = (6 + frand(15)) * bp->noise; + double step = 1.0 / bp->resolution; + double r, max; + + for (j = 0; j < nspikes; j++) + { + double off = frand (0.8) - 0.4; + double amp = (0.1 + frand (0.9)) * nspikes; + double freq = (7 + frand (11)) * bp->noise; + for (i = 0, r = -0.5, p = points; + i < bp->resolution; + i++, r += step, p++) + *p += amp/2 + amp/2 * cos1 ((r + off) * M_PI * 2 * freq); + } + + /* Avoid clipping */ + max = nspikes; + if (max <= 0) max = 1; + for (i = 0, p = points; i < bp->resolution; i++, p++) + if (max < *p) max = *p; + + /* Multiply by baseline clipping curve, add static. */ + for (i = 0, r = -0.5, p = points; i < bp->resolution; i++, r += step, p++) + *p = ((*p / max) + * (0.5 + 0.5 * cos1 (r * r * M_PI * 14) * (1 - frand(0.2)))); + + return points; +} + + +static void +tick_unk (ModeInfo *mi) +{ + unk_configuration *bp = &bps[MI_SCREEN(mi)]; + int wire = MI_IS_WIREFRAME(mi); + double *points = generate_signal (mi); + int linesp, frame; + + /* Roll forward by one line (2 dlists per frame) */ + GLuint *cur = (GLuint *) malloc (bp->frames * 2 * sizeof(*cur)); + memcpy (cur, bp->lines, bp->frames * 2 * sizeof(*cur)); + memmove (bp->lines, bp->lines + 2 * bp->frames, + sizeof(*bp->lines) * (bp->count-1) * bp->frames * 2); + memcpy (bp->lines + (bp->count-1) * bp->frames * 2, cur, + bp->frames * 2 * sizeof(*cur)); + + memmove (bp->heights, bp->heights + 1, + sizeof(*bp->heights) * (bp->count-1)); + bp->heights[bp->count-1] = 0; + + /* Regenerate the pair at the bottom. */ + + for (frame = 0; frame < bp->frames; frame++) + { + mi->polygon_count = 0; + for (linesp = 0; linesp <= 1; linesp++) + { + int i; + + glNewList (cur[frame * 2 + !linesp], GL_COMPILE); + glBegin (linesp + ? GL_LINE_STRIP + : wire ? GL_LINES : GL_QUAD_STRIP); + for (i = 0; i < bp->resolution; i++) + { + GLfloat x = i / (GLfloat) bp->resolution; + GLfloat z = (points[i] + frand (0.05)) * bp->amplitude; + if (z < 0) z = 0; + if (z > bp->amplitude) z = bp->amplitude; + glVertex3f (x, 0, z); + if (! linesp) + glVertex3f (x, 0, 0); + mi->polygon_count++; + } + glEnd (); + glEndList (); + } + } + + mi->polygon_count *= bp->count; + mi->polygon_count += 5; /* base */ + + free (cur); + free (points); +} + ENTRYPOINT void init_unk (ModeInfo *mi) { unk_configuration *bp; + int wire = MI_IS_WIREFRAME(mi); + int i; MI_INIT (mi, bps); @@ -188,109 +447,110 @@ init_unk (ModeInfo *mi) bp->glx_context = init_GL(mi); - bp->orthop = get_boolean_resource (MI_DISPLAY (mi), "ortho", "Ortho"); - bp->resolution = get_float_resource (MI_DISPLAY (mi), - "resolution", "Resolution"); + bp->orthop = ortho_arg; + bp->resolution = resolution_arg; + bp->amplitude = amplitude_arg; + bp->noise = noise_arg; + bp->aspect = aspect_arg; + bp->speed = speed_arg; + bp->frames = buzz_arg ? 15 : 1; if (bp->resolution < 1) bp->resolution = 1; if (bp->resolution > 300) bp->resolution = 300; + if (bp->amplitude < 0.01) bp->amplitude = 0.01; + if (bp->amplitude > 1) bp->amplitude = 1; + if (bp->noise < 0.01) bp->noise = 0.01; + if (bp->speed <= 0.001) bp->speed = 0.001; - reshape_unk (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); + parse_color (mi, "foreground", "Foreground", bp->fg); + parse_color (mi, "background", "Background", bp->bg); - bp->count = MI_COUNT(mi); - if (bp->count < 1) bp->count = 1; + reshape_unk (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); bp->trackball = gltrackball_init (False); if (MI_COUNT(mi) < 1) MI_COUNT(mi) = 1; + /* bp->count is set in reshape */ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - - + bp->base = glGenLists (1); + glNewList (bp->base, GL_COMPILE); + { + GLfloat h1 = 0.01; + GLfloat h2 = 0.02; + GLfloat h3 = (h1 + h2) / 2; + GLfloat s = 0.505; + glBegin (wire ? GL_LINE_LOOP : GL_QUADS); + glVertex3f (-s, -s, -h1); + glVertex3f ( s, -s, -h1); + glVertex3f ( s, s, -h1); + glVertex3f (-s, s, -h1); + glEnd(); + glBegin (wire ? GL_LINE_LOOP : GL_QUADS); + glVertex3f (-s, -s, 0); + glVertex3f (-s, -s, -h2); + glVertex3f ( s, -s, -h2); + glVertex3f ( s, -s, 0); + glEnd(); + glBegin (wire ? GL_LINE_LOOP : GL_QUADS); + glVertex3f (-s, -s, 0); + glVertex3f (-s, -s, -h2); + glVertex3f (-s, s, -h2); + glVertex3f (-s, s, 0); + glEnd(); + glBegin (wire ? GL_LINE_LOOP : GL_QUADS); + glVertex3f ( s, -s, 0); + glVertex3f ( s, -s, -h2); + glVertex3f ( s, s, -h2); + glVertex3f ( s, s, 0); + glEnd(); + glBegin (wire ? GL_LINE_LOOP : GL_QUADS); + glVertex3f (-s, s, 0); + glVertex3f (-s, s, -h2); + glVertex3f ( s, s, -h2); + glVertex3f ( s, s, 0); + glEnd(); -static double -R (double f) -{ - /* A simple, fast, deterministic PRNG. - ya_rand_init() is too slow for this, and the stream of numbers here - doesn't have to be high quality. - */ -#if 1 - int seed0 = 1613287; + glColor3fv (bp->fg); + glBegin (GL_LINE_LOOP); + s -= 0.01; + glVertex3f (-s, -s, -h3); + glVertex3f ( s, -s, -h3); + glVertex3f ( s, s, -h3); + glVertex3f (-s, s, -h3); + glEnd(); + } + glEndList (); -# else - /* Kluge to let me pick a good seed factor by trial and error... */ - static int seed0 = 0; - static int count = 0; - if (count++ > 150000000) seed0 = 0, count=0; - if (! seed0) + if (! wire) { - seed0 = (random() & 0xFFFFF); - fprintf(stderr, "seed0 = %8x %d\n", seed0, seed0); + glEnable (GL_LINE_SMOOTH); + glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable (GL_BLEND); } -# endif - long seed = seed0 * f; - seed = 48271 * (seed % 44488) - 3399 * (seed / 44488); - f = (double) seed / 0x7FFFFFFF; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - return f; + for (i = 0; i < bp->count; i++) + tick_unk (mi); } -static void -compute_line (ModeInfo *mi, - int xmin, int xmax, GLfloat xinc, - GLfloat res_scale, - int y, - GLfloat *points) +static double +ease_fn (double r) { - unk_configuration *bp = &bps[MI_SCREEN(mi)]; - - GLfloat fx; - int lastx = -999999; - - /* Compute the points on the line */ - - for (fx = xmin; fx < xmax; fx += xinc) - { - int x = fx; - int n; - GLfloat hsum = 0, vsum = 0; - - if (x == lastx) continue; - lastx = x; - - for (n = 1; n <= 30; n++) - { - /* This sum affects crinkliness of the lines */ - hsum += (10 * - sin (2 * M_PI - * R (4 * y) - + bp->t - + R (2 * n * y) - * 2 * M_PI) - * exp (-pow ((.3 * (x / res_scale) + 30 - - 1 * 100 * R (2 * n * y)), - 2) - / 20.0)); - } - - for (n = 1; n <= 4; n++) - { - /* This sum affects amplitude of the peaks */ - vsum += (3 * (1 + R (3 * n * y)) - * fabs (sin (bp->t + R (n * y) - * 2 * M_PI)) - * exp (-pow (((x / res_scale) - 1 * 100 * R (n * y)), - 2) - / 20.0)); - } + return cos ((r/2 + 1) * M_PI) + 1; /* Smooth curve up, end at slope 1. */ +} - /* Scale of this affects amplitude of the flat parts */ - points[x - xmin] = (0.2 * sin (2 * M_PI * R (6 * y) + hsum) + vsum); - } +static double +ease_ratio (double r) +{ + double ease = 0.5; + if (r <= 0) return 0; + else if (r >= 1) return 1; + else if (r <= ease) return ease * ease_fn (r / ease); + else if (r > 1-ease) return 1 - ease * ease_fn ((1 - r) / ease); + else return r; } @@ -298,32 +558,25 @@ ENTRYPOINT void draw_unk (ModeInfo *mi) { unk_configuration *bp = &bps[MI_SCREEN(mi)]; + int wire = MI_IS_WIREFRAME(mi); Display *dpy = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); - int wire = MI_IS_WIREFRAME(mi); - GLfloat aspect = 1.5; + GLfloat step = 1.0 / bp->count; + double speed = (0.6 / bp->speed) * (80.0 / bp->count); + double now = double_time(); + double ratio = (now - bp->tick) / speed; + int frame; + int i; - GLfloat res_scale = 4; - int xmin = -50 * res_scale; - int xmax = 150 * res_scale; - GLfloat xinc = 100.0 / (bp->resolution / res_scale); - int ymin = 1; - int ytop = MI_COUNT(mi); - int yinc = 1; - int y; - GLfloat *points; - - if (xinc < 0.25) xinc = 0.25; + ratio = (ratio < 0 ? 0 : ratio > 1 ? 1 : ratio); if (!bp->glx_context) return; - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context)); + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - mi->polygon_count = 0; - glShadeModel (GL_FLAT); glEnable (GL_DEPTH_TEST); glDisable (GL_CULL_FACE); @@ -333,152 +586,93 @@ draw_unk (ModeInfo *mi) glRotatef(current_device_rotation(), 0, 0, 1); gltrackball_rotate (bp->trackball); - glScalef (10, 10, 10); glRotatef (-45, 1, 0, 0); - glTranslatef (-0.5, -0.5, 0); - if (bp->orthop) - glTranslatef (0, 0.05, 0); + + i = bp->orthop ? 15 : 17; + glScalef (i / bp->aspect, i, i / bp->aspect); + + glDisable (GL_POLYGON_OFFSET_FILL); + if (wire) + glColor3f (0.5 * bp->fg[0], 0.5 * bp->fg[1], 0.5 * bp->fg[2]); else - glTranslatef (0, 0.15, 0); + glColor4fv (bp->bg); + glCallList (bp->base); - points = (GLfloat *) malloc (sizeof(*points) * (xmax - xmin)); + /* So the masking quads don't interfere with the lines. + These numbers are empirical black magic. */ + glEnable (GL_POLYGON_OFFSET_FILL); - if (!bp->button_down_p) - { - double s = 6.3 / 19 / 3; -# if 1 - bp->t -= s * speed; - if (bp->t <= 0) - bp->t = s * 18 * 3; +# ifdef DEBUG + glPolygonOffset (poly1, poly2); # else - bp->t += s; + glPolygonOffset (0.5, 0.5); # endif - } - glLineWidth (2); + glTranslatef (-0.5, 0.55 + step*ratio, 0); - /* Lower the resolution to get a decent frame rate on iPhone 4s */ - if (mi->xgwa.width <= 640 || mi->xgwa.height <= 640) + frame = random() % bp->frames; + for (i = 0; i < bp->count; i++) { - ytop *= 0.6; - xinc *= 3; + int j = i * bp->frames * 2 + frame * 2; + GLfloat s = ease_ratio (bp->heights[i]); + GLfloat s2 = ease_ratio (bp->heights[i] * 1.5); + + glPushMatrix(); + glScalef (1, 1, s); + glColor4f (bp->fg[0], bp->fg[1], bp->fg[2], s2); + glCallList (bp->lines[j]); /* curve */ + s = 1; + if (wire) + glColor4f (0.5 * bp->fg[0], 0.5 * bp->fg[1], 0.5 * bp->fg[2], s); + else + glColor4f (bp->bg[0], bp->bg[1], bp->bg[2], s); + glCallList (bp->lines[j+1]); /* shield */ + glPopMatrix(); + glTranslatef (0, -step, 0); } -# ifdef HAVE_MOBILE - /* Lower it even further for iPhone 3 */ - if (mi->xgwa.width <= 480 || mi->xgwa.height <= 480) - { - ytop *= 0.8; - xinc *= 1.2; - } - - /* Performance just sucks on iPad 3, even with a very high xinc. WTF? */ -/* - if (mi->xgwa.width >= 2048 || mi->xgwa.height >= 2048) - xinc *= 2; -*/ - -# endif /* HAVE_MOBILE */ - - - /* Make the image fill the screen a little more fully */ - if (mi->xgwa.width <= 640 || mi->xgwa.height <= 640) - { - glScalef (1.2, 1.2, 1.2); - glTranslatef (-0.08, 0, 0); - } - - if (mi->xgwa.width <= 480 || mi->xgwa.height <= 480) - glLineWidth (1); - - - if (wire) - xinc *= 1.3; + glPopMatrix (); - /* Draw back mask */ - { - GLfloat s = 0.99; - glDisable (GL_POLYGON_OFFSET_FILL); - glColor3f (0, 0, 0); - glPushMatrix(); - glTranslatef (0, (1-aspect)/2, -0.005); - glScalef (1, aspect, 1); - glTranslatef (0.5, 0.5, 0); - glScalef (s, s, 1); - glBegin (GL_QUADS); - glVertex3f (-0.5, -0.5, 0); - glVertex3f ( 0.5, -0.5, 0); - glVertex3f ( 0.5, 0.5, 0); - glVertex3f (-0.5, 0.5, 0); - glEnd(); - glPopMatrix(); - } + if (mi->fps_p) do_fps (mi); + glFinish(); - if (! wire) + if (!bp->button_down_p) { - glEnable (GL_LINE_SMOOTH); - glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_BLEND); - - /* So the masking quads don't interfere with the lines */ - glEnable (GL_POLYGON_OFFSET_FILL); - glPolygonOffset (1.0, 1.0); - } + /* Set height/fade based on distance from either edge. */ + GLfloat dist = bp->count * 0.05; + int i; + for (i = 0; i < bp->count; i++) + { + GLfloat i2 = i - ratio; + GLfloat h = ((i2 < bp->count/2 ? i2 : (bp->count - 1 - i2)) + / dist); + bp->heights[i] = (h > 1 ? 1 : h < 0 ? 0 : h); + } - for (y = ymin; y <= ytop; y += yinc) - { - /* Compute all the verts on the line */ - compute_line (mi, xmin, xmax, xinc, res_scale, y, points); - - /* Draw the line segments; then draw the black shielding quads. */ - { - GLfloat yy = y / (GLfloat) ytop; - int linesp; - - yy = (yy * aspect) - ((aspect - 1) / 2); - - for (linesp = 0; linesp <= 1; linesp++) - { - GLfloat fx; - int lastx = -999999; - - GLfloat c = (linesp || wire ? 1 : 0); - glColor3f (c, c, c); - - glBegin (linesp - ? GL_LINE_STRIP - : wire ? GL_LINES : GL_QUAD_STRIP); - lastx = -999999; - for (fx = xmin; fx < xmax; fx += xinc) - { - int x = fx; - GLfloat xx = (x - xmin) / (GLfloat) (xmax - xmin); - GLfloat zz = points [x - xmin]; - - if (x == lastx) continue; - lastx = x; - - zz /= 80; - glVertex3f (xx, yy, zz); - if (! linesp) - glVertex3f (xx, yy, 0); - mi->polygon_count++; - } - glEnd (); - } - } + if (bp->tick + speed <= now) /* Add a new row. */ + { + tick_unk (mi); + bp->tick = now; + } } - free (points); + glXSwapBuffers(dpy, window); +} - glPopMatrix (); - if (mi->fps_p) do_fps (mi); - glFinish(); - - glXSwapBuffers(dpy, window); +ENTRYPOINT void +free_unk (ModeInfo *mi) +{ + unk_configuration *bp = &bps[MI_SCREEN(mi)]; + int i; + if (!bp->glx_context) return; + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); + if (bp->trackball) gltrackball_free (bp->trackball); + for (i = 0; i < bp->count * bp->frames * 2; i++) + glDeleteLists (bp->lines[i], 1); + free (bp->lines); + free (bp->heights); } XSCREENSAVER_MODULE_2 ("UnknownPleasures", unknownpleasures, unk) -- cgit v1.2.3-55-g7522