From d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 16 Oct 2018 10:08:48 +0200 Subject: Original 5.40 --- hacks/pedal.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 hacks/pedal.c (limited to 'hacks/pedal.c') diff --git a/hacks/pedal.c b/hacks/pedal.c new file mode 100644 index 0000000..87820be --- /dev/null +++ b/hacks/pedal.c @@ -0,0 +1,335 @@ +/* + * pedal + * + * Based on a program for some old PDP-11 Graphics Display Processors + * at CMU. + * + * X version by + * + * Dale Moore + * 24-Jun-1994 + * + * Copyright (c) 1994, by Carnegie Mellon University. Permission to use, + * copy, modify, distribute, and sell this software and its documentation + * for any purpose is hereby granted without fee, provided fnord 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 fnord this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + */ + +#include +#include +#include "screenhack.h" +#include "erase.h" + +/* If MAXLINES is too big, we might not be able to get it + * to the X server in the 2byte length field. Must be less + * than 16k + */ +#define MAXLINES (16 * 1024) +#define MAXPOINTS MAXLINES + +/* + * If the pedal has only this many lines, it must be ugly and we dont + * want to see it. + */ +#define MINLINES 7 + + +struct state { + Display *dpy; + Window window; + + XPoint *points; + + int sizex, sizey; + int delay; + int maxlines; + GC gc; + XColor foreground, background; + Colormap cmap; + + eraser_state *eraser; + int erase_p; +}; + + +/* + * Routine (Macro actually) + * mysin + * Description: + * Assume that degrees is .. oh 360... meaning that + * there are 360 degress in a circle. Then this function + * would return the sin of the angle in degrees. But lets + * say that they are really big degrees, with 4 big degrees + * the same as one regular degree. Then this routine + * would be called mysin(t, 90) and would return sin(t degrees * 4) + */ +#define mysin(t, degrees) sin(t * 2 * M_PI / (degrees)) +#define mycos(t, degrees) cos(t * 2 * M_PI / (degrees)) + +/* + * Macro: + * rand_range + * Description: + * Return a random number between a inclusive and b exclusive. + * rand (3, 6) returns 3 or 4 or 5, but not 6. + */ +#define rand_range(a, b) (a + random() % (b - a)) + + +static int +gcd(int m, int n) /* Greatest Common Divisor (also Greates common factor). */ +{ + int r; + + for (;;) { + r = m % n; + if (r == 0) return (n); + m = n; + n = r; + } +} + +static int numlines (int a, int b, int d) +/* + * Description: + * + * Given parameters a and b, how many lines will we have to draw? + * + * Algorithm: + * + * This algorithm assumes that r = sin (theta * a), where we + * evaluate theta on multiples of b. + * + * LCM (i, j) = i * j / GCD (i, j); + * + * So, at LCM (b, 360) we start over again. But since we + * got to LCM (b, 360) by steps of b, the number of lines is + * LCM (b, 360) / b. + * + * If a is odd, then at 180 we cross over and start the + * negative. Someone should write up an elegant way of proving + * this. Why? Because I'm not convinced of it myself. + * + */ +{ +#define odd(x) (x & 1) +#define even(x) (!odd(x)) + if ( odd(a) && odd(b) && even(d)) d /= 2; + return (d / gcd (d, b)); +#undef odd +} + +static int +compute_pedal(struct state *st, XPoint *points, int maxpoints) +/* + * Description: + * + * Basically, it's combination spirograph and string art. + * Instead of doing lines, we just use a complex polygon, + * and use an even/odd rule for filling in between. + * + * The spirograph, in mathematical terms is a polar + * plot of the form r = sin (theta * c); + * The string art of this is that we evaluate that + * function only on certain multiples of theta. That is + * we let theta advance in some random increment. And then + * we draw a straight line between those two adjacent points. + * + * Eventually, the lines will start repeating themselves + * if we've evaluated theta on some rational portion of the + * whole. + * + * The number of lines generated is limited to the + * ratio of the increment we put on theta to the whole. + * If we say that there are 360 degrees in a circle, then we + * will never have more than 360 lines. + * + * Return: + * + * The number of points. + * + */ +{ + int a, b, d; /* These describe a unique pedal */ + + double r; + int theta = 0; + XPoint *pp = st->points; + int count; + int numpoints; + + /* Just to make sure that this division is not done inside the loop */ + int h_width = st->sizex / 2, h_height = st->sizey / 2 ; + + for (;;) { + d = rand_range (MINLINES, st->maxlines); + + a = rand_range (1, d); + b = rand_range (1, d); + numpoints = numlines(a, b, d); + if (numpoints > MINLINES) break; + } + + /* it might be nice to try to move as much sin and cos computing + * (or at least the argument computing) out of the loop. + */ + for (count = numpoints; count-- ; ) + { + r = mysin (theta * a, d); + + /* Convert from polar to cartesian coordinates */ + /* We could round the results, but coercing seems just fine */ + pp->x = mysin (theta, d) * r * h_width + h_width; + pp->y = mycos (theta, d) * r * h_height + h_height; + + /* Advance index into array */ + pp++; + + /* Advance theta */ + theta += b; + theta %= d; + } + + return(numpoints); +} + +static void * +pedal_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + XWindowAttributes xgwa; + + st->dpy = dpy; + st->window = window; + + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + if (st->delay < 0) st->delay = 0; + + st->maxlines = get_integer_resource (st->dpy, "maxlines", "Integer"); + if (st->maxlines < MINLINES) st->maxlines = MINLINES; + else if (st->maxlines > MAXLINES) st->maxlines = MAXLINES; + + st->points = (XPoint *)malloc(sizeof(XPoint) * st->maxlines); + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->sizex = xgwa.width; + st->sizey = xgwa.height; + + st->cmap = xgwa.colormap; + + gcv.function = GXcopy; + gcv.foreground = get_pixel_resource (st->dpy, st->cmap, "foreground", "Foreground"); + gcv.background = get_pixel_resource (st->dpy, st->cmap, "background", "Background"); + st->gc = XCreateGC (st->dpy, st->window, GCForeground | GCBackground |GCFunction, &gcv); + + return st; +} + +/* + * Since the XFillPolygon doesn't require that the last + * point == first point, the number of points is the same + * as the number of lines. We just let XFillPolygon supply + * the line from the last point to the first point. + * + */ +static unsigned long +pedal_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int numpoints; + int erase_delay = 10000; + int long_delay = 1000000 * st->delay; + + if (st->erase_p || st->eraser) { + st->eraser = erase_window (dpy, window, st->eraser); + st->erase_p = 0; + return (st->eraser ? erase_delay : 1000000); + } + + numpoints = compute_pedal(st, st->points, st->maxlines); + + /* Pick a new foreground color (added by jwz) */ + if (! mono_p) + { + XColor color; + hsv_to_rgb (random()%360, 1.0, 1.0, + &color.red, &color.green, &color.blue); + if (XAllocColor (st->dpy, st->cmap, &color)) + { + XSetForeground (st->dpy, st->gc, color.pixel); + XFreeColors (st->dpy, st->cmap, &st->foreground.pixel, 1, 0); + st->foreground.red = color.red; + st->foreground.green = color.green; + st->foreground.blue = color.blue; + st->foreground.pixel = color.pixel; + } + } + + XFillPolygon (st->dpy, st->window, st->gc, st->points, numpoints, + Complex, CoordModeOrigin); + + st->erase_p = 1; + return long_delay; +} + +static void +pedal_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->sizex = w; + st->sizey = h; +} + +static Bool +pedal_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + if (screenhack_event_helper (dpy, window, event)) + { + st->erase_p = 1; + return True; + } + return False; +} + +static void +pedal_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + + + +/* + * If we are trying to save the screen, the background + * should be dark. + */ +static const char *pedal_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 5", + "*maxlines: 1000", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec pedal_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-maxlines", ".maxlines", XrmoptionSepArg, 0 }, + { "-foreground", ".foreground", XrmoptionSepArg, 0 }, + { "-background", ".background", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Pedal", pedal) -- cgit v1.2.3-55-g7522