X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fhelix.c;h=3b6f0f8c22b4e70b47049e1ffb57f688bc480176;hb=4ade52359b6eba3621566dac79793a33aa4c915f;hp=84c4fd8ca42340e49b3cc9f7e29f60ba7eae01cc;hpb=ccbc9f87eb59497b23bd0424ee1ed20ad7c7db54;p=xscreensaver diff --git a/hacks/helix.c b/hacks/helix.c index 84c4fd8c..3b6f0f8c 100644 --- a/hacks/helix.c +++ b/hacks/helix.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992, 1995 Jamie Zawinski +/* xscreensaver, Copyright (c) 1992-2008 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 @@ -9,42 +9,78 @@ * implied warranty. */ +/* Algorithm from a Mac program by Chris Tate, written in 1988 or so. */ + +/* 18-Sep-97: Johannes Keukelaar (johannes@nada.kth.se): Improved screen + * eraser. + * 10-May-97: merged ellipse code by Dan Stromberg + * as found in xlockmore 4.03a10. + * 1992: jwz created. + */ + +/* 25 April 2002: Matthew Strait added +-subdelay option so the drawing process can be watched */ + #include #include "screenhack.h" +#include "erase.h" -static double sins [360]; -static double coss [360]; +enum draw_state { HELIX, DRAW_HELIX, TRIG, DRAW_TRIG, LINGER, ERASE }; -static GC draw_gc, erase_gc; -static unsigned int default_fg_pixel; +struct state { + enum draw_state dstate; + double sins [360]; + double coss [360]; -static void -init_helix (dpy, window) - Display *dpy; - Window window; + GC draw_gc; + unsigned int default_fg_pixel; + int sleep_time; + int subdelay; + eraser_state *eraser; + + int width, height; + Colormap cmap; + + int x1, y1, x2, y2, angle, i; + + int radius1, radius2, d_angle, factor1, factor2, factor3, factor4; + int d_angle_offset; + int offset, dir, density; +}; + +static void * +helix_init (Display *dpy, Window window) { + struct state *st = (struct state *) calloc (1, sizeof(*st)); int i; XGCValues gcv; XWindowAttributes xgwa; - Colormap cmap; + + st->sleep_time = get_integer_resource(dpy, "delay", "Integer"); + st->subdelay = get_integer_resource(dpy, "subdelay", "Integer"); + XGetWindowAttributes (dpy, window, &xgwa); - cmap = xgwa.colormap; - gcv.foreground = default_fg_pixel = - get_pixel_resource ("foreground", "Foreground", dpy, cmap); - draw_gc = XCreateGC (dpy, window, GCForeground, &gcv); - gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap); - erase_gc = XCreateGC (dpy, window, GCForeground, &gcv); + st->width = xgwa.width; + st->height = xgwa.height; + st->cmap = xgwa.colormap; + gcv.foreground = st->default_fg_pixel = + get_pixel_resource (dpy, st->cmap, "foreground", "Foreground"); + st->draw_gc = XCreateGC (dpy, window, GCForeground, &gcv); + gcv.foreground = get_pixel_resource (dpy, st->cmap, "background", "Background"); for (i = 0; i < 360; i++) { - sins [i] = sin ((((double) i) / 180.0) * M_PI); - coss [i] = cos ((((double) i) / 180.0) * M_PI); + st->sins [i] = sin ((((double) i) / 180.0) * M_PI); + st->coss [i] = cos ((((double) i) / 180.0) * M_PI); } + + st->dstate = (random() & 1) ? HELIX : TRIG; + + return st; } static int -gcd (a, b) - int a, b; +gcd (int a, int b) { while (b > 0) { @@ -57,152 +93,264 @@ gcd (a, b) } static void -helix (dpy, window, - radius1, radius2, d_angle, - factor1, factor2, factor3, factor4) - Display *dpy; - Window window; - int radius1, radius2, d_angle; - int factor1, factor2, factor3, factor4; +helix (Display *dpy, Window window, struct state *st) { - XWindowAttributes xgwa; - int width, height; - int xmid, ymid; - int x1, y1, x2, y2, angle, limit; - int i; + int xmid = st->width / 2; + int ymid = st->height / 2; + int limit = 1 + (360 / gcd (360, st->d_angle)); - XClearWindow (dpy, window); - XGetWindowAttributes (dpy, window, &xgwa); - width = xgwa.width; - height = xgwa.height; - - xmid = width / 2; - ymid = height / 2; - x1 = xmid; - y1 = ymid + radius2; - x2 = xmid; - y2 = ymid + radius1; - angle = 0; - limit = 1 + (360 / gcd (360, d_angle)); + if (st->i == 0) + { + st->x1 = xmid; + st->y1 = ymid + st->radius2; + st->x2 = xmid; + st->y2 = ymid + st->radius1; + st->angle = 0; + } - for (i = 0; i < limit; i++) +/* for (st->i = 0; st->i < limit; st->i++)*/ { int tmp; -#define pmod(x,y) (tmp = (x % y), (tmp >= 0 ? tmp : tmp + y)) - x1 = xmid + (((double) radius1) * sins [pmod ((angle * factor1), 360)]); - y1 = ymid + (((double) radius2) * coss [pmod ((angle * factor2), 360)]); - XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2); - x2 = xmid + (((double) radius2) * sins [pmod ((angle * factor3), 360)]); - y2 = ymid + (((double) radius1) * coss [pmod ((angle * factor4), 360)]); - XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2); - angle += d_angle; - XFlush (dpy); +#define pmod(x,y) (tmp=((x) % (y)), (tmp >= 0 ? tmp : (tmp + (y)))) + + st->x1 = xmid + (((double) st->radius1) * st->sins [pmod ((st->angle * st->factor1), 360)]); + st->y1 = ymid + (((double) st->radius2) * st->coss [pmod ((st->angle * st->factor2), 360)]); + XDrawLine (dpy, window, st->draw_gc, st->x1, st->y1, st->x2, st->y2); + st->x2 = xmid + (((double) st->radius2) * st->sins [pmod ((st->angle * st->factor3), 360)]); + st->y2 = ymid + (((double) st->radius1) * st->coss [pmod ((st->angle * st->factor4), 360)]); + XDrawLine (dpy, window, st->draw_gc, st->x1, st->y1, st->x2, st->y2); + st->angle += st->d_angle; } + st->i++; + + if (st->i >= limit) + st->dstate = LINGER; } +static void +trig (Display *dpy, Window window, struct state *st) +{ + int xmid = st->width / 2; + int ymid = st->height / 2; + +/* while (st->d_angle >= -360 && st->d_angle <= 360)*/ + { + int tmp; + int angle = st->d_angle + st->d_angle_offset; + st->x1 = (st->sins [pmod(angle * st->factor1, 360)] * xmid) + xmid; + st->y1 = (st->coss [pmod(angle * st->factor1, 360)] * ymid) + ymid; + st->x2 = (st->sins [pmod(angle * st->factor2 + st->offset, 360)] * xmid) + xmid; + st->y2 = (st->coss [pmod(angle * st->factor2 + st->offset, 360)] * ymid) + ymid; + XDrawLine(dpy, window, st->draw_gc, st->x1, st->y1, st->x2, st->y2); + tmp = (int) 360 / (2 * st->density * st->factor1 * st->factor2); + if (tmp == 0) /* Do not want it getting stuck... */ + tmp = 1; /* Would not need if floating point */ + st->d_angle += st->dir * tmp; + } + + if (st->d_angle < -360 || st->d_angle > 360) + st->dstate = LINGER; +} + + #define min(a,b) ((a)<(b)?(a):(b)) static void -random_helix (dpy, window) - Display *dpy; - Window window; +random_helix (Display *dpy, Window window, struct state *st, + XColor *color, Bool *got_color) { - Colormap cmap; - int width, height; - int radius, radius1, radius2, d_angle, factor1, factor2, factor3, factor4; + int radius; double divisor; - XColor color; - int i, got_color = 0; - XWindowAttributes xgwa; - XGetWindowAttributes (dpy, window, &xgwa); - width = xgwa.width; - height = xgwa.height; - cmap = xgwa.colormap; - radius = min (width, height) / 2; + radius = min (st->width, st->height) / 2; - d_angle = 0; - factor1 = 2; - factor2 = 2; - factor3 = 2; - factor4 = 2; + st->i = 0; + st->d_angle = 0; + st->factor1 = 2; + st->factor2 = 2; + st->factor3 = 2; + st->factor4 = 2; divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1)); if ((random () & 1) == 0) { - radius1 = radius; - radius2 = radius / divisor; + st->radius1 = radius; + st->radius2 = radius / divisor; } else { - radius2 = radius; - radius1 = radius / divisor; + st->radius2 = radius; + st->radius1 = radius / divisor; } - while (gcd (360, d_angle) >= 2) - d_angle = random () % 360; + while (gcd (360, st->d_angle) >= 2) + st->d_angle = random () % 360; #define random_factor() \ (((random() % 7) ? ((random() & 1) + 1) : 3) \ * (((random() & 1) * 2) - 1)) - while (gcd (gcd (gcd (factor1, factor2), factor3), factor4) != 1) + while (gcd (gcd (gcd (st->factor1, st->factor2), st->factor3), st->factor4) != 1) { - factor1 = random_factor (); - factor2 = random_factor (); - factor3 = random_factor (); - factor4 = random_factor (); + st->factor1 = random_factor (); + st->factor2 = random_factor (); + st->factor3 = random_factor (); + st->factor4 = random_factor (); } if (mono_p) - XSetForeground (dpy, draw_gc, default_fg_pixel); + XSetForeground (dpy, st->draw_gc, st->default_fg_pixel); else { hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5, - &color.red, &color.green, &color.blue); - if ((got_color = XAllocColor (dpy, cmap, &color))) - XSetForeground (dpy, draw_gc, color.pixel); + &color->red, &color->green, &color->blue); + if ((*got_color = XAllocColor (dpy, st->cmap, color))) + XSetForeground (dpy, st->draw_gc, color->pixel); else - XSetForeground (dpy, draw_gc, default_fg_pixel); + XSetForeground (dpy, st->draw_gc, st->default_fg_pixel); } - helix (dpy, window, radius1, radius2, d_angle, - factor1, factor2, factor3, factor4); - XSync (dpy, True); - sleep (5); + XClearWindow (dpy, window); +} + +static void +random_trig (Display *dpy, Window window, struct state *st, + XColor *color, Bool *got_color) +{ + st->d_angle = 0; + st->factor1 = (random() % 8) + 1; + do { + st->factor2 = (random() % 8) + 1; + } while (st->factor1 == st->factor2); + + st->dir = (random() & 1) ? 1 : -1; + st->d_angle_offset = random() % 360; + st->offset = ((random() % ((360 / 4) - 1)) + 1) / 4; + st->density = 1 << ((random() % 4) + 4); /* Higher density, higher angles */ - for (i = 0; i < height; i++) + if (mono_p) + XSetForeground (dpy, st->draw_gc, st->default_fg_pixel); + else { - int y = (random () % height); - XDrawLine (dpy, window, erase_gc, 0, y, width, y); - XFlush (dpy); - if ((i % 50) == 0) - usleep (10000); + hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5, + &color->red, &color->green, &color->blue); + if ((*got_color = XAllocColor (dpy, st->cmap, color))) + XSetForeground (dpy, st->draw_gc, color->pixel); + else + XSetForeground (dpy, st->draw_gc, st->default_fg_pixel); } + XClearWindow (dpy, window); - if (got_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0); - XSync (dpy, True); - sleep (1); } - -char *progclass = "Helix"; -char *defaults [] = { - "Helix.background: black", /* to placate SGI */ - 0 -}; +/* random_helix_or_trig */ +static unsigned long +helix_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + Bool free_color = False; + XColor color; + int delay = st->subdelay; + int erase_delay = 10000; + int ii; + + if (st->eraser) { + st->eraser = erase_window (dpy, window, st->eraser); + if (st->eraser) + delay = erase_delay; + goto END; + } + + switch (st->dstate) + { + case LINGER: + delay = st->sleep_time * 1000000; + st->dstate = ERASE; + break; + + case ERASE: + st->eraser = erase_window (dpy, window, st->eraser); + delay = erase_delay; + if (free_color) XFreeColors (dpy, st->cmap, &color.pixel, 1, 0); + st->dstate = (random() & 1) ? HELIX : TRIG; + break; + + case DRAW_HELIX: + for (ii = 0; ii < 10; ii++) { + helix (dpy, window, st); + if (st->dstate != DRAW_HELIX) + break; + } + break; + + case DRAW_TRIG: + for (ii = 0; ii < 5; ii++) { + trig (dpy, window, st); + if (st->dstate != DRAW_TRIG) + break; + } + break; -XrmOptionDescRec options [] = { { 0, } }; -int options_size = 0; + case HELIX: + random_helix (dpy, window, st, &color, &free_color); + st->dstate = DRAW_HELIX; + break; -void -screenhack (dpy, window) - Display *dpy; - Window window; + case TRIG: + random_trig(dpy, window, st, &color, &free_color); + st->dstate = DRAW_TRIG; + break; + + default: + abort(); + } + + END: + return delay; +} + +static void +helix_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) { - init_helix (dpy, window); - while (1) - random_helix (dpy, window); + struct state *st = (struct state *) closure; + st->width = w; + st->height = h; } + +static Bool +helix_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +helix_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + + +static const char *helix_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*delay: 5", + "*subdelay: 20000", +#ifdef USE_IPHONE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec helix_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-subdelay", ".subdelay", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 }, +}; + +XSCREENSAVER_MODULE ("Helix", helix)