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/halo.c | 440 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 hacks/halo.c (limited to 'hacks/halo.c') diff --git a/hacks/halo.c b/hacks/halo.c new file mode 100644 index 0000000..42b6a55 --- /dev/null +++ b/hacks/halo.c @@ -0,0 +1,440 @@ +/* xscreensaver, Copyright (c) 1993-2013 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. + */ + +/* I wanted to lay down new circles with TV:ALU-ADD instead of TV:ALU-XOR, + but X doesn't support arithmetic combinations of pixmaps!! What losers. + I suppose I could crank out the 2's compliment math by hand, but that's + a real drag... + + This would probably look good with shapes other than circles as well. + + */ + +#include "screenhack.h" +#include + +struct circle { + int x, y, radius; + int increment; + int dx, dy; +}; + +static enum color_mode { + seuss_mode, ramp_mode, random_mode +} cmode; + + +struct state { + Display *dpy; + Window window; + + struct circle *circles; + int count, global_count; + Pixmap pixmap, buffer; + int width, height, global_inc; + int delay, delay2; + unsigned long fg_pixel, bg_pixel; + GC draw_gc, erase_gc, copy_gc, merge_gc; + Bool anim_p; + Colormap cmap; + + int ncolors; + XColor *colors; + int fg_index; + int bg_index; + + int iterations; + Bool done_once; + Bool done_once_no_really; + int clear_tick; + struct timeval then; +}; + +#define min(x,y) ((x)<(y)?(x):(y)) +#define max(x,y) ((x)>(y)?(x):(y)) + +static void +init_circles_1 (struct state *st) +{ + int i; + st->count = (st->global_count ? st->global_count + : (3 + (random () % max (1, (min (st->width, st->height) / 50))) + + (random () % max (1, (min (st->width, st->height) / 50))))); + st->circles = (struct circle *) malloc (st->count * sizeof (struct circle)); + for (i = 0; i < st->count; i++) + { + st->circles [i].x = 10 + random () % (st->width - 20); + st->circles [i].y = 10 + random () % (st->height - 20); + if (st->global_inc) + st->circles [i].increment = st->global_inc; + else + { /* prefer smaller increments to larger ones */ + int j = 8; + int inc = ((random()%j) + (random()%j) + (random()%j)) - ((j*3)/2); + if (inc < 0) inc = -inc + 3; + st->circles [i].increment = inc + 3; + } + st->circles [i].radius = random () % st->circles [i].increment; + st->circles [i].dx = ((random () % 3) - 1) * (1 + random () % 5); + st->circles [i].dy = ((random () % 3) - 1) * (1 + random () % 5); + } +} + +static void * +halo_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + XWindowAttributes xgwa; + char *mode_str = 0; + st->dpy = dpy; + st->window = window; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->cmap = xgwa.colormap; + st->global_count = get_integer_resource (st->dpy, "count", "Integer"); + if (st->global_count < 0) st->global_count = 0; + st->global_inc = get_integer_resource (st->dpy, "increment", "Integer"); + if (st->global_inc < 0) st->global_inc = 0; + st->anim_p = get_boolean_resource (st->dpy, "animate", "Boolean"); + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer") * 1000000; + mode_str = get_string_resource (st->dpy, "colorMode", "ColorMode"); + if (! mode_str) cmode = random_mode; + else if (!strcmp (mode_str, "seuss")) cmode = seuss_mode; + else if (!strcmp (mode_str, "ramp")) cmode = ramp_mode; + else if (!strcmp (mode_str, "random")) cmode = random_mode; + else { + fprintf (stderr, + "%s: colorMode must be seuss, ramp, or random, not \"%s\"\n", + progname, mode_str); + exit (1); + } + + if (mono_p) cmode = seuss_mode; + if (cmode == random_mode) + cmode = ((random()&3) == 1) ? ramp_mode : seuss_mode; + + if (cmode == ramp_mode) + st->anim_p = False; /* This combo doesn't work right... */ + + st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); + if (st->ncolors < 2) st->ncolors = 2; + if (st->ncolors <= 2) mono_p = True; + + if (mono_p) + st->colors = 0; + else + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + + + if (mono_p) + ; + else if (random() % (cmode == seuss_mode ? 2 : 10)) + make_uniform_colormap (xgwa.screen, xgwa.visual, st->cmap, + st->colors, &st->ncolors, + True, 0, True); + else + make_smooth_colormap (xgwa.screen, xgwa.visual, st->cmap, + st->colors, &st->ncolors, + True, 0, True); + + if (st->ncolors <= 2) mono_p = True; + if (mono_p) cmode = seuss_mode; + + if (mono_p) + { + st->fg_pixel = get_pixel_resource (st->dpy, st->cmap, "foreground", "Foreground"); + st->bg_pixel = get_pixel_resource (st->dpy, st->cmap, "background", "Background"); + } + else + { + st->fg_index = 0; + st->bg_index = st->ncolors / 4; + if (st->fg_index == st->bg_index) st->bg_index++; + st->fg_pixel = st->colors[st->fg_index].pixel; + st->bg_pixel = st->colors[st->bg_index].pixel; + } + + st->width = max (50, xgwa.width); + st->height = max (50, xgwa.height); + +#ifdef DEBUG + st->width/=2; st->height/=2; +#endif + + st->pixmap = XCreatePixmap (st->dpy, st->window, st->width, st->height, 1); + if (cmode == seuss_mode) + st->buffer = XCreatePixmap (st->dpy, st->window, st->width, st->height, 1); + else + st->buffer = 0; + + gcv.foreground = 1; + gcv.background = 0; + st->draw_gc = XCreateGC (st->dpy, st->pixmap, GCForeground | GCBackground, &gcv); + gcv.foreground = 0; + st->erase_gc = XCreateGC (st->dpy, st->pixmap, GCForeground, &gcv); + gcv.foreground = st->fg_pixel; + gcv.background = st->bg_pixel; + st->copy_gc = XCreateGC (st->dpy, st->window, GCForeground | GCBackground, &gcv); + +#ifdef HAVE_JWXYZ + jwxyz_XSetAntiAliasing (dpy, st->draw_gc, False); + jwxyz_XSetAntiAliasing (dpy, st->erase_gc, False); + jwxyz_XSetAntiAliasing (dpy, st->copy_gc, False); +#endif + + if (cmode == seuss_mode) + { + gcv.foreground = 1; + gcv.background = 0; + gcv.function = GXxor; + st->merge_gc = XCreateGC (st->dpy, st->pixmap, + GCForeground | GCBackground | GCFunction, &gcv); + } + else + { + gcv.foreground = st->fg_pixel; + gcv.background = st->bg_pixel; + gcv.function = GXcopy; + st->merge_gc = XCreateGC (st->dpy, st->window, + GCForeground | GCBackground | GCFunction, &gcv); + } + + init_circles_1 (st); + XClearWindow (st->dpy, st->window); + if (st->buffer) XFillRectangle (st->dpy, st->buffer, st->erase_gc, 0, 0, st->width, st->height); + return st; +} + +static unsigned long +halo_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int i; + Bool done = False; + Bool inhibit_sleep = False; + int this_delay = st->delay; + + XFillRectangle (st->dpy, st->pixmap, st->erase_gc, 0, 0, st->width, st->height); + for (i = 0; i < st->count; i++) + { + int radius = st->circles [i].radius; + int inc = st->circles [i].increment; + + if (! (st->iterations & 1)) /* never stop on an odd number of iterations */ + ; + else if (radius == 0) /* eschew inf */ + ; + else if (radius < 0) /* stop when the circles are points */ + done = True; + else /* stop when the circles fill the st->window */ + { + /* Probably there's a simpler way to ask the musical question, + "is this square completely enclosed by this circle," but I've + forgotten too much trig to know it... (That's not really the + right question anyway, but the right question is too hard.) */ + double x1 = ((double) (-st->circles [i].x)) / ((double) radius); + double y1 = ((double) (-st->circles [i].y)) / ((double) radius); + double x2 = ((double) (st->width - st->circles [i].x)) / ((double) radius); + double y2 = ((double) (st->height - st->circles [i].y)) / ((double) radius); + x1 *= x1; x2 *= x2; y1 *= y1; y2 *= y2; + if ((x1 + y1) < 1 && (x2 + y2) < 1 && (x1 + y2) < 1 && (x2 + y1) < 1) + done = True; + } + + if (radius > 0 && + (cmode == seuss_mode || /* drawing all circles, or */ + st->circles [0].increment < 0)) /* on the way back in */ + { + XFillArc (st->dpy, + (cmode == seuss_mode ? st->pixmap : st->window), + (cmode == seuss_mode ? st->draw_gc : st->merge_gc), + st->circles [i].x - radius, st->circles [i].y - radius, + radius * 2, radius * 2, 0, 360*64); + } + st->circles [i].radius += inc; + } + + if (st->anim_p && !st->done_once) + inhibit_sleep = !done; + + if (done) + { + if (st->anim_p) + { + st->done_once = True; + for (i = 0; i < st->count; i++) + { + st->circles [i].x += st->circles [i].dx; + st->circles [i].y += st->circles [i].dy; + st->circles [i].radius %= st->circles [i].increment; + if (st->circles [i].x < 0 || st->circles [i].x >= st->width) + { + st->circles [i].dx = -st->circles [i].dx; + st->circles [i].x += (2 * st->circles [i].dx); + } + if (st->circles [i].y < 0 || st->circles [i].y >= st->height) + { + st->circles [i].dy = -st->circles [i].dy; + st->circles [i].y += (2 * st->circles [i].dy); + } + } + } + else if (st->circles [0].increment < 0) + { + /* We've zoomed out and the screen is blank -- re-pick the + center points, and shift the st->colors. + */ + free (st->circles); + init_circles_1 (st); + if (! mono_p) + { + st->fg_index = (st->fg_index + 1) % st->ncolors; + st->bg_index = (st->fg_index + (st->ncolors/2)) % st->ncolors; + XSetForeground (st->dpy, st->copy_gc, st->colors [st->fg_index].pixel); + XSetBackground (st->dpy, st->copy_gc, st->colors [st->bg_index].pixel); + } + } + /* Sometimes go out from the inside instead of the outside */ + else if (st->clear_tick == 0 && ((random () % 3) == 0)) + { + st->iterations = 0; /* ick */ + for (i = 0; i < st->count; i++) + st->circles [i].radius %= st->circles [i].increment; + + st->clear_tick = ((random() % 8) + 4) | 1; /* must be odd */ + } + else + { + for (i = 0; i < st->count; i++) + { + st->circles [i].increment = -st->circles [i].increment; + st->circles [i].radius += (2 * st->circles [i].increment); + } + } + } + + if (st->buffer) + XCopyPlane (st->dpy, st->pixmap, st->buffer, st->merge_gc, 0, 0, st->width, st->height, 0, 0, 1); + else if (cmode != seuss_mode) + { + + if (!mono_p) + { + st->fg_index++; + st->bg_index++; + if (st->fg_index >= st->ncolors) st->fg_index = 0; + if (st->bg_index >= st->ncolors) st->bg_index = 0; + XSetForeground (st->dpy, st->merge_gc, st->colors [st->fg_index].pixel); + } + + if (st->circles [0].increment >= 0) + inhibit_sleep = True; + else if (done && cmode == seuss_mode) + XFillRectangle (st->dpy, st->window, st->merge_gc, 0, 0, st->width, st->height); + } + else + XCopyPlane (st->dpy, st->pixmap, st->window, st->merge_gc, 0, 0, st->width, st->height, 0, 0, 1); + + /* st->buffer is only used in seuss-mode or anim-mode */ + if (st->buffer && (st->anim_p + ? (done || (!st->done_once && (st->iterations & 1))) + : (st->iterations & 1))) + { + XCopyPlane (st->dpy, st->buffer, st->window, st->copy_gc, 0, 0, st->width, st->height, 0, 0, 1); + if (st->anim_p && done) + XFillRectangle (st->dpy, st->buffer, st->erase_gc, 0, 0, st->width, st->height); + } + +#ifdef DEBUG + XCopyPlane (st->dpy, st->pixmap, st->window, st->copy_gc, 0,0,st->width,st->height,st->width,st->height, 1); + if (st->buffer) + XCopyPlane (st->dpy, st->buffer, st->window, st->copy_gc, 0,0,st->width,st->height,0,st->height, 1); +#endif + + if (done) + st->iterations = 0; + else + st->iterations++; + + if (st->delay && !inhibit_sleep) + { + int d = st->delay; + + if (cmode == seuss_mode && st->anim_p) + this_delay = d/100; + else + this_delay = d; + + if (done) + st->done_once_no_really = True; + } + + if (done && st->clear_tick > 0) + { + st->clear_tick--; + if (!st->clear_tick) + { + XClearWindow (st->dpy, st->window); + if (st->buffer) XFillRectangle (st->dpy, st->buffer, st->erase_gc, 0,0,st->width,st->height); + } + } + + if (inhibit_sleep) this_delay = 0; + + return this_delay; +} + + + +static const char *halo_defaults [] = { + ".background: black", + ".foreground: white", + "*colorMode: random", + "*colors: 100", + "*count: 0", + "*delay: 100000", + "*delay2: 20", + "*increment: 0", + "*animate: False", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec halo_options [] = { + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-animate", ".animate", XrmoptionNoArg, "True" }, + { "-mode", ".colorMode", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +static void +halo_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +halo_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +halo_free (Display *dpy, Window window, void *closure) +{ +} + +XSCREENSAVER_MODULE ("Halo", halo) -- cgit v1.2.3-55-g7522