+++ /dev/null
-/*
- * pedal
- *
- * Based on a program for some old PDP-11 Graphics Display Processors
- * at CMU.
- *
- * X version by
- *
- * Dale Moore <Dale.Moore@cs.cmu.edu>
- * 24-Jun-1994
- *
- * Copyright \(co 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 <math.h>
-#include <stdlib.h>
-#include "screenhack.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
-XPoint *points;
-
-/*
- * If the pedal has only this many lines, it must be ugly and we dont
- * want to see it.
- */
-#define MINLINES 7
-
-static int sizex, sizey;
-static int delay;
-static int fadedelay;
-static int maxlines;
-static GC gc;
-static XColor foreground, background;
-static Colormap cmap;
-
-static Bool fade_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 (m, n)
- 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 (a, b, d)
- 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(points, maxpoints)
-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 = points;
- int count;
- int numpoints;
-
- /* Just to make sure that this division is not done inside the loop */
- int h_width = sizex / 2, h_height = sizey / 2 ;
-
- for (;;) {
- d = rand_range (MINLINES, 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
-init_pedal (dpy, window)
- Display *dpy;
- Window window;
-{
- XGCValues gcv;
- XWindowAttributes xgwa;
-
- fade_p = !mono_p;
-
- delay = get_integer_resource ("delay", "Integer");
- if (delay < 0) delay = 0;
-
- fadedelay = get_integer_resource ("fadedelay", "Integer");
- if (fadedelay < 0) fadedelay = 0;
-
- maxlines = get_integer_resource ("maxlines", "Integer");
- if (maxlines < MINLINES) maxlines = MINLINES;
- else if (maxlines > MAXLINES) maxlines = MAXLINES;
-
- points = (XPoint *)malloc(sizeof(XPoint) * maxlines);
-
- XGetWindowAttributes (dpy, window, &xgwa);
- sizex = xgwa.width;
- sizey = xgwa.height;
-
- if ((xgwa.visual->class != GrayScale) && (xgwa.visual->class != PseudoColor))
- fade_p = False;
-
- cmap = xgwa.colormap;
-
- gcv.function = GXcopy;
- gcv.subwindow_mode = IncludeInferiors;
- gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
- gcv.background = get_pixel_resource ("background", "Background", dpy, cmap);
- gc = XCreateGC (
- dpy,
- window,
- GCForeground | GCBackground |GCFunction | GCSubwindowMode ,
- &gcv);
-
- if (fade_p)
- {
- int status;
- foreground.pixel = gcv.foreground;
- XQueryColor (dpy, cmap, &foreground);
-
- status = XAllocColorCells (
- dpy,
- cmap,
- 0,
- NULL,
- 0,
- &foreground.pixel,
- 1);
- if (status)
- {
- XStoreColor ( dpy, cmap, &foreground);
- XSetForeground (dpy, gc, foreground.pixel);
-
- background.pixel = gcv.background;
- XQueryColor (dpy, cmap, &background);
- }
- else
- {
- /* If we cant allocate a color cell, then just forget the
- * whole fade business.
- */
- fade_p = False;
- }
- }
-}
-
-static void
-fade_foreground (dpy, cmap, from, to, steps)
- Display *dpy;
- Colormap cmap;
- XColor from;
- XColor to;
- int steps;
-/*
- * This routine assumes that we have a writeable colormap.
- * That means that the default colormap is not full, and that
- * the visual class is PseudoColor or GrayScale.
- */
-{
- int i;
- XColor inbetween;
- int udelay = fadedelay / (steps + 1);
-
- inbetween = foreground;
- for (i = 0; i <= steps; i++ )
- {
- inbetween.red = from.red + (to.red - from.red) * i / steps ;
- inbetween.green = from.green + (to.green - from.green) * i / steps ;
- inbetween.blue = from.blue + (to.blue - from.blue) * i / steps ;
- XStoreColor (dpy, cmap, &inbetween);
- /* If we don't sync, these can bunch up */
- XSync(dpy, 0);
- usleep(udelay);
- }
-}
-
-static void
-pedal (dpy, window)
- Display *dpy;
- Window window;
-/*
- * 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.
- *
- */
-{
- int numpoints;
-
- numpoints = compute_pedal(points, maxlines);
-
- /* Fade out, make foreground the same as background */
- if (fade_p)
- fade_foreground (dpy, cmap, foreground, background, 32);
-
- /* Clear the window of previous garbage */
- XClearWindow (dpy, window);
-
- XFillPolygon (
- dpy,
- window,
- gc,
- points,
- numpoints,
- Complex,
- CoordModeOrigin);
-
- /* 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);
- XSync(dpy, 0);
- if (fade_p)
- {
- foreground.red = color.red;
- foreground.green = color.green;
- foreground.blue = color.blue;
- XStoreColor (dpy, cmap, &foreground);
- }
- else if (XAllocColor (dpy, cmap, &color))
- {
- XSetForeground (dpy, gc, color.pixel);
- XFreeColors (dpy, cmap, &foreground.pixel, 1, 0);
- foreground.red = color.red;
- foreground.green = color.green;
- foreground.blue = color.blue;
- foreground.pixel = color.pixel;
- }
- XSync(dpy, 0);
- }
-
- /* Fade in by bringing the foreground back from background */
- if (fade_p)
- fade_foreground (dpy, cmap, background, foreground, 32);
-}
-
-\f
-char *progclass = "Pedal";
-
-/*
- * If we are trying to save the screen, the background
- * should be dark.
- */
-char *defaults [] = {
- "Pedal.background: black", /* to placate SGI */
- "Pedal.foreground: white",
- "*delay: 5",
- "*fadedelay: 200000",
- "*maxlines: 1000",
- 0
-};
-
-XrmOptionDescRec options [] = {
- { "-delay", ".delay", XrmoptionSepArg, 0 },
- { "-fadedelay", ".fadedelay", XrmoptionSepArg, 0 },
- { "-maxlines", ".maxlines", XrmoptionSepArg, 0 },
- { "-foreground", ".foreground", XrmoptionSepArg, 0 },
- { "-background", ".background", XrmoptionSepArg, 0 },
-};
-
-int options_size = (sizeof (options) / sizeof (options[0]));
-
-void
-screenhack (dpy, window)
- Display *dpy;
- Window window;
-{
- init_pedal (dpy, window);
- for (;;) {
- pedal (dpy, window);
- XSync(dpy, 0);
- if (delay) sleep (delay);
- }
-}