summaryrefslogtreecommitdiffstats
path: root/hacks/glx/unknownpleasures.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/glx/unknownpleasures.c')
-rw-r--r--hacks/glx/unknownpleasures.c698
1 files changed, 446 insertions, 252 deletions
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 <jwz@jwz.org>
+/* unknownpleasures, Copyright (c) 2013-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
@@ -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},
+ {&amplitude_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)