diff options
author | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
---|---|---|
committer | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
commit | d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch) | |
tree | cbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /hacks/xspirograph.c | |
download | xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip |
Original 5.40
Diffstat (limited to 'hacks/xspirograph.c')
-rw-r--r-- | hacks/xspirograph.c | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/hacks/xspirograph.c b/hacks/xspirograph.c new file mode 100644 index 0000000..e6504ff --- /dev/null +++ b/hacks/xspirograph.c @@ -0,0 +1,333 @@ +/* The Spiral Generator, Copyright (c) 2000 + * by Rohit Singh <rohit_singh@hotmail.com> + * + * Contains code from / To be used with: + * xscreensaver, Copyright (c) 1992, 1995, 1996, 1997 + * 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 notices appear in all copies and that both that + * copyright notices 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. + * + * Modified (Dec 2001) by Matthew Strait <straitm@mathcs.carleton.edu> + * Added -subdelay and -alwaysfinish + * Prevented redrawing over existing lines + */ + +#include <math.h> +#include "screenhack.h" +#include "erase.h" + +struct state { + Display *dpy; + Window window; + XWindowAttributes xgwa; + + GC draw_gc; + int long_delay; + int sub_sleep_time; + int num_layers; + unsigned int default_fg_pixel; + Bool always_finish_p; + XColor color; + int got_color; + + int theta; + float firstx, firsty; + int x1, y1, x2, y2; + + int counter; + int distance; + int radius1, radius2; + double divisor; + + enum curstate { NEW_LAYER, DRAW, ERASE1, ERASE2 } drawstate; + eraser_state *eraser; +}; + + +static void +init_tsg (struct state *st) +{ + XGCValues gcv; + Colormap cmap; + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + cmap = st->xgwa.colormap; + gcv.foreground = st->default_fg_pixel = + get_pixel_resource (st->dpy, cmap, "foreground", "Foreground"); + st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + gcv.foreground = get_pixel_resource (st->dpy, cmap, "background", "Background"); +} + + +static Bool +go (struct state *st, int radius1, int radius2, int d) +{ + int width, height; + int xmid, ymid; + float tmpx, tmpy; + int delta; + + width = st->xgwa.width; + height = st->xgwa.height; + delta = 1; + xmid = width / 2; + ymid = height / 2; + + if (st->theta == 1) { + st->x1 = xmid + radius1 - radius2 + d; + st->y1 = ymid; + } + +/* for (theta = 1; / * theta < ( 360 * 100 ) * /; theta++) */ + /* see below about alwaysfinish */ + { + tmpx = xmid + (( radius1 /* * * * * */ + - radius2 ) /* This algo simulates */ + * cos(( st->theta /* the rotation of a */ + * M_PI ) /* circular disk inside */ + / 180 )) /* a hollow circular */ + + ( d /* rim. A point on the */ + * cos(((( radius1 /* disk dist d from the */ + * st->theta ) /* centre, traces the */ + - delta ) /* path given by this */ + / radius2 ) /* equation. */ + * M_PI /* A deviation (error) */ + / 180 ) /* of delta needs to be */ + ); /* given, which greatly */ + /* adds to the beauty */ + tmpy = ymid + ( /* of the figure. */ + ( radius1 - radius2 /* */ + ) * sin /* Imperfection adds to */ + ( /* beauty, symbolically */ + ( st->theta * M_PI /* ... */ + ) / 180 /* Algo deduced by */ + ) /* Rohit Singh, Jan'00 */ + ) + /* based on a toy he */ + ( d * sin /* used to play with */ + ( /* when he was a kid. */ + ( /* * * * * */ + ( + ( radius1 * st->theta + ) - delta + ) / radius2 + ) * M_PI / 180 + ) + ); + + /*makes integers from the calculated values to do the drawing*/ + st->x2 = tmpx; + st->y2 = tmpy; + + /*stores the first values for later reference*/ + if(st->theta == 1) + { + st->firstx = tmpx; + st->firsty = tmpy; + } + + if (st->theta != 1) + XDrawLine (st->dpy, st->window, st->draw_gc, + st->x1, st->y1, st->x2, st->y2); + + st->x1 = st->x2; + st->y1 = st->y2; + + /* compares the exact values calculated to the first + exact values calculated */ + /* this will break when nothing new is being drawn */ + if(tmpx == st->firstx && tmpy == st->firsty && st->theta != 1) { + st->firstx = st->firsty = 0; + st->theta = 1; + return True; + } + + /* this will break after 36000 iterations if + the -alwaysfinish option is not specified */ + if(!st->always_finish_p && st->theta > ( 360 * 100 ) ) { + st->firstx = st->firsty = 0; + st->theta = 1; + return True; + } + } + + st->theta++; + + return False; +} + + +#define min(a,b) ((a)<(b)?(a):(b)) + + +static void +pick_new (struct state *st) +{ + int radius = min (st->xgwa.width, st->xgwa.height) / 2; + st->divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1)); + st->radius1 = radius; + st->radius2 = radius / st->divisor + 5; + st->distance = 100 + (random() % 200); + st->theta = 1; +} + + +static void * +xspirograph_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = window; + st->long_delay = get_integer_resource(st->dpy, "delay", "Integer"); + st->sub_sleep_time = get_integer_resource(st->dpy, "subdelay", "Integer"); + st->num_layers = get_integer_resource(st->dpy, "layers", "Integer"); + st->always_finish_p = get_boolean_resource (st->dpy, "alwaysfinish", "Boolean"); + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + + init_tsg (st); + st->theta = 1; + st->drawstate = NEW_LAYER; + + return st; +} + + +static void +new_colors (struct state *st) +{ + if (mono_p) + XSetForeground (st->dpy, st->draw_gc, st->default_fg_pixel); + else + { + hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5, + &st->color.red, &st->color.green, &st->color.blue); + if ((st->got_color = XAllocColor (st->dpy, st->xgwa.colormap, + &st->color))) + XSetForeground (st->dpy, st->draw_gc, st->color.pixel); + else + XSetForeground (st->dpy, st->draw_gc, st->default_fg_pixel); + } +} + + + +static unsigned long +xspirograph_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + Bool free_color = False; + Bool flip_p = (st->counter & 1); + int i; + + switch (st->drawstate) { + case ERASE1: + /* 5 sec delay before starting the erase */ + st->drawstate = ERASE2; + /* shouldn't this use the configured long_delay value??? */ + return (st->long_delay == 0 ? 0 : 5000000); + + case ERASE2: + /* erase, delaying 1/50th sec between frames */ + st->eraser = erase_window(st->dpy, st->window, st->eraser); + if (st->eraser) + /* shouldn't this be a configured pause??? */ + return 20000; + st->drawstate = NEW_LAYER; + /* just finished erasing -- leave screen black for 1 sec */ + return (st->long_delay == 0 ? 0 : 1000000); + + case DRAW: + /* most common case put in front */ + for (i = 0; i < 1000; i++) { + if (go(st, st->radius1, (flip_p ? st->radius2 : -st->radius2), + st->distance)) { + st->drawstate = NEW_LAYER; + break; + } + } + /* Next draw is delayed sleep_time (initialized value)*/ + return st->sub_sleep_time; + + case NEW_LAYER: + /* Increment counter */ + st->counter++; + if (st->counter > (2 * st->num_layers)) { + /* reset to zero, free, and erase next time through */ + st->counter = 0; + if (free_color) + XFreeColors (st->dpy, st->xgwa.colormap, &st->color.pixel, 1, 0); + st->drawstate = ERASE1; + } else { + /* first, third, fifth, ... time through */ + if (!flip_p) + pick_new (st); + + new_colors (st); + st->drawstate = DRAW; + } + /* No delay to the next draw */ + return 0; + + default: + /* OOPS!! */ + fprintf(stderr, "%s: invalid state\n", progname); + exit(1); + } + + return st->sub_sleep_time; + /* notreached */ +} + + +static void +xspirograph_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); +} + +static Bool +xspirograph_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +xspirograph_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *xspirograph_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 5", + "*subdelay: 20000", + "*layers: 2", + "*alwaysfinish: false", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec xspirograph_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-subdelay", ".subdelay", XrmoptionSepArg, 0 }, + { "-layers", ".layers", XrmoptionSepArg, 0 }, + { "-alwaysfinish", ".alwaysfinish", XrmoptionNoArg, "true"}, + { "-noalwaysfinish", ".alwaysfinish", XrmoptionNoArg, "false"}, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("XSpirograph", xspirograph) |