/* 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 * 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 this * software for any purpose. It is provided "as is" without express or * 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" enum draw_state { HELIX, DRAW_HELIX, TRIG, DRAW_TRIG, LINGER, ERASE }; struct state { enum draw_state dstate; double sins [360]; double coss [360]; 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; st->sleep_time = get_integer_resource(dpy, "delay", "Integer"); st->subdelay = get_integer_resource(dpy, "subdelay", "Integer"); XGetWindowAttributes (dpy, window, &xgwa); 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++) { 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 (int a, int b) { while (b > 0) { int tmp; tmp = a % b; a = b; b = tmp; } return (a < 0 ? -a : a); } static void helix (Display *dpy, Window window, struct state *st) { int xmid = st->width / 2; int ymid = st->height / 2; int limit = 1 + (360 / gcd (360, st->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 (st->i = 0; st->i < limit; st->i++)*/ { int tmp; #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 (Display *dpy, Window window, struct state *st, XColor *color, Bool *got_color) { int radius; double divisor; radius = min (st->width, st->height) / 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) { st->radius1 = radius; st->radius2 = radius / divisor; } else { st->radius2 = radius; st->radius1 = radius / divisor; } 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 (st->factor1, st->factor2), st->factor3), st->factor4) != 1) { st->factor1 = random_factor (); st->factor2 = random_factor (); st->factor3 = random_factor (); st->factor4 = random_factor (); } if (mono_p) 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, st->cmap, color))) XSetForeground (dpy, st->draw_gc, color->pixel); else XSetForeground (dpy, st->draw_gc, st->default_fg_pixel); } 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 */ if (mono_p) 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, st->cmap, color))) XSetForeground (dpy, st->draw_gc, color->pixel); else XSetForeground (dpy, st->draw_gc, st->default_fg_pixel); } XClearWindow (dpy, window); } /* 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; case HELIX: random_helix (dpy, window, st, &color, &free_color); st->dstate = DRAW_HELIX; break; 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) { 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; XFreeGC (dpy, st->draw_gc); free (st); } static const char *helix_defaults [] = { ".background: black", ".foreground: white", "*fpsSolid: true", "*delay: 5", "*subdelay: 20000", #ifdef HAVE_MOBILE "*ignoreRotation: True", #endif 0 }; static XrmOptionDescRec helix_options [] = { { "-delay", ".delay", XrmoptionSepArg, 0 }, { "-subdelay", ".subdelay", XrmoptionSepArg, 0 }, { 0, 0, 0, 0 }, }; XSCREENSAVER_MODULE ("Helix", helix)