X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fcloudlife.c;h=4b65f9e3fa3250543f60d47c95cdac3ab2fcb858;hb=aa75c7476aeaa84cf3abc192b376a8b03c325213;hp=368eb9d55ff5b5d0b8c28b6db4b7aa9e4f7aee91;hpb=6cee540bdbb571485cd5e519f89f389faebd0495;p=xscreensaver diff --git a/hacks/cloudlife.c b/hacks/cloudlife.c index 368eb9d5..4b65f9e3 100644 --- a/hacks/cloudlife.c +++ b/hacks/cloudlife.c @@ -10,6 +10,8 @@ * Cloudlife only draws one pixel of each cell per tick, whether the cell is * alive or dead. So gliders look like little comets. + * 20 May 2003 -- now includes color cycling and a man page. + * Based on several examples from the hacks directory of: * xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski @@ -24,8 +26,6 @@ */ #include "screenhack.h" -#include -#include #ifndef MAX_WIDTH #include @@ -43,14 +43,43 @@ #define inline /* */ #endif -typedef struct { +struct field { unsigned int height; unsigned int width; unsigned int max_age; unsigned int cell_size; unsigned char *cells; unsigned char *new_cells; -} field; +}; + +struct state { + Display *dpy; + Window window; + +#ifdef TIME_ME + time_t start_time; +#endif + + unsigned int cycles; + unsigned int colorindex; /* which color in the colormap are we on */ + unsigned int colortimer; /* when this reaches 0, cycle to next color */ + + int cycle_delay; + int cycle_colors; + int ncolors; + int density; + + GC fgc, bgc; + XGCValues gcv; + XWindowAttributes xgwa; + XColor *colors; + + struct field *field; + + XPoint fg_points[MAX_WIDTH]; + XPoint bg_points[MAX_WIDTH]; +}; + static void *xrealloc(void *p, size_t size) @@ -63,57 +92,60 @@ static void return ret; } -field -*init_field(void) +static struct field * +init_field(struct state *st) { - field *f = xrealloc(NULL, sizeof(field)); + struct field *f = xrealloc(NULL, sizeof(struct field)); f->height = 0; f->width = 0; - f->cell_size = get_integer_resource("cellSize", "Integer"); - f->max_age = get_integer_resource("maxAge", "Integer"); + f->cell_size = get_integer_resource(st->dpy, "cellSize", "Integer"); + f->max_age = get_integer_resource(st->dpy, "maxAge", "Integer"); + + if (f->max_age > 255) { + fprintf (stderr, "%s: max-age must be < 256 (not %d)\n", progname, + f->max_age); + exit (1); + } + f->cells = NULL; f->new_cells = NULL; return f; } -void -resize_field(field * f, unsigned int w, unsigned int h) +static void +resize_field(struct field * f, unsigned int w, unsigned int h) { + int s = w * h * sizeof(unsigned char); f->width = w; f->height = h; - f->cells = xrealloc(f->cells, - w * sizeof(unsigned char) * - h * sizeof(unsigned char)); - f->new_cells = - xrealloc(f->new_cells, - w * sizeof(unsigned char) * h * sizeof(unsigned char)); + f->cells = xrealloc(f->cells, s); + f->new_cells = xrealloc(f->new_cells, s); + memset(f->cells, 0, s); + memset(f->new_cells, 0, s); } -inline unsigned char -*cell_at(field * f, unsigned int x, unsigned int y) +static inline unsigned char +*cell_at(struct field * f, unsigned int x, unsigned int y) { return (f->cells + x * sizeof(unsigned char) + y * f->width * sizeof(unsigned char)); } -inline unsigned char -*new_cell_at(field * f, unsigned int x, unsigned int y) +static inline unsigned char +*new_cell_at(struct field * f, unsigned int x, unsigned int y) { return (f->new_cells + x * sizeof(unsigned char) + y * f->width * sizeof(unsigned char)); } static void -draw_field(Display * dpy, - Window window, Colormap cmap, GC fgc, GC bgc, field * f) +draw_field(struct state *st, struct field * f) { unsigned int x, y; unsigned int rx, ry = 0; /* random amount to offset the dot */ unsigned int size = 1 << f->cell_size; unsigned int mask = size - 1; - static XPoint fg_points[MAX_WIDTH]; - static XPoint bg_points[MAX_WIDTH]; unsigned int fg_count, bg_count; /* columns 0 and width-1 are off screen and not drawn. */ @@ -129,23 +161,23 @@ draw_field(Display * dpy, ry &= mask; if (*cell_at(f, x, y)) { - fg_points[fg_count].x = (short) x *size - rx - 1; - fg_points[fg_count].y = (short) y *size - ry - 1; + st->fg_points[fg_count].x = (short) x *size - rx - 1; + st->fg_points[fg_count].y = (short) y *size - ry - 1; fg_count++; } else { - bg_points[bg_count].x = (short) x *size - rx - 1; - bg_points[bg_count].y = (short) y *size - ry - 1; + st->bg_points[bg_count].x = (short) x *size - rx - 1; + st->bg_points[bg_count].y = (short) y *size - ry - 1; bg_count++; } } - XDrawPoints(dpy, window, fgc, fg_points, fg_count, + XDrawPoints(st->dpy, st->window, st->fgc, st->fg_points, fg_count, CoordModeOrigin); - XDrawPoints(dpy, window, bgc, bg_points, bg_count, + XDrawPoints(st->dpy, st->window, st->bgc, st->bg_points, bg_count, CoordModeOrigin); } } -inline unsigned int +static inline unsigned int cell_value(unsigned char c, unsigned int age) { if (!c) { @@ -157,8 +189,8 @@ cell_value(unsigned char c, unsigned int age) } } -inline unsigned int -is_alive(field * f, unsigned int x, unsigned int y) +static inline unsigned int +is_alive(struct field * f, unsigned int x, unsigned int y) { unsigned int count; unsigned int i, j; @@ -190,8 +222,8 @@ is_alive(field * f, unsigned int x, unsigned int y) } } -unsigned int -do_tick(field * f) +static unsigned int +do_tick(struct field * f) { unsigned int x, y; unsigned int count = 0; @@ -200,13 +232,13 @@ do_tick(field * f) count += *new_cell_at(f, x, y) = is_alive(f, x, y); } } - memcpy(f->cells, f->new_cells, f->width * sizeof(unsigned char) * - f->height * sizeof(unsigned char)); + memcpy(f->cells, f->new_cells, f->width * f->height * + sizeof(unsigned char)); return count; } -unsigned int +static unsigned int random_cell(unsigned int p) { int r = random() & 0xff; @@ -218,8 +250,8 @@ random_cell(unsigned int p) } } -void -populate_field(field * f, unsigned int p) +static void +populate_field(struct field * f, unsigned int p) { unsigned int x, y; @@ -230,8 +262,8 @@ populate_field(field * f, unsigned int p) } } -void -populate_edges(field * f, unsigned int p) +static void +populate_edges(struct field * f, unsigned int p) { unsigned int i; @@ -246,93 +278,151 @@ populate_edges(field * f, unsigned int p) } } - -char *progclass = "Cloudlife"; - -char *defaults[] = { - ".background: black", - ".foreground: blue", - "*cycleDelay: 25000", - "*maxAge: 64", - "*initialDensity: 160", - "*cellSize: 3", - 0 -}; - -XrmOptionDescRec options[] = { - {"-background", ".background", XrmoptionSepArg, 0}, - {"-foreground", ".foreground", XrmoptionSepArg, 0}, - {"-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0}, - {"-cell-size", ".cellSize", XrmoptionSepArg, 0}, - {"-initial-density", ".initialDensity", XrmoptionSepArg, 0}, - {"-max-age", ".maxAge", XrmoptionSepArg, 0}, - {0, 0, 0, 0} -}; - -void screenhack(Display * dpy, Window window) +static void * +cloudlife_init (Display *dpy, Window window) { - field *f = init_field(); + struct state *st = (struct state *) calloc (1, sizeof(*st)); + Bool tmp = True; + + st->dpy = dpy; + st->window = window; + st->field = init_field(st); #ifdef TIME_ME - time_t start_time = time(NULL); + st->start_time = time(NULL); #endif - unsigned int cycles = 0; - - GC fgc, bgc; - XGCValues gcv; - XWindowAttributes xgwa; + st->cycle_delay = get_integer_resource(st->dpy, "cycleDelay", "Integer"); + st->cycle_colors = get_integer_resource(st->dpy, "cycleColors", "Integer"); + st->ncolors = get_integer_resource(st->dpy, "ncolors", "Integer"); + st->density = (get_integer_resource(st->dpy, "initialDensity", "Integer") + % 100 * 256)/100; - unsigned int cycle_delay = (unsigned int) - get_integer_resource("cycleDelay", "Integer"); - unsigned int density = (unsigned int) - get_integer_resource("initialDensity", "Integer") & 0xff; - XGetWindowAttributes(dpy, window, &xgwa); + XGetWindowAttributes(st->dpy, st->window, &st->xgwa); - gcv.foreground = get_pixel_resource("foreground", "Foreground", - dpy, xgwa.colormap); - fgc = XCreateGC(dpy, window, GCForeground, &gcv); + if (st->cycle_colors) { + st->colors = (XColor *) xrealloc(st->colors, sizeof(XColor) * (st->ncolors+1)); + make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, + st->xgwa.colormap, st->colors, &st->ncolors, + True, &tmp, True); + } - gcv.foreground = get_pixel_resource("background", "Background", - dpy, xgwa.colormap); - bgc = XCreateGC(dpy, window, GCForeground, &gcv); + st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + st->fgc = XCreateGC(st->dpy, st->window, GCForeground, &st->gcv); - while (1) { - XGetWindowAttributes(dpy, window, &xgwa); - if (f->height != xgwa.height / (1 << f->cell_size) + 2 || - f->width != xgwa.width / (1 << f->cell_size) + 2) { + st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, + "background", "Background"); + st->bgc = XCreateGC(st->dpy, st->window, GCForeground, &st->gcv); - resize_field(f, xgwa.width / (1 << f->cell_size) + 2, - xgwa.height / (1 << f->cell_size) + 2); - populate_field(f, density); - } + return st; +} - screenhack_handle_events(dpy); +static unsigned long +cloudlife_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if (st->cycle_colors) { + if (st->colortimer == 0) { + st->colortimer = st->cycle_colors; + if( st->colorindex == 0 ) + st->colorindex = st->ncolors; + st->colorindex--; + XSetForeground(st->dpy, st->fgc, st->colors[st->colorindex].pixel); + } + st->colortimer--; + } - draw_field(dpy, window, xgwa.colormap, fgc, bgc, f); + XGetWindowAttributes(st->dpy, st->window, &st->xgwa); + if (st->field->height != st->xgwa.height / (1 << st->field->cell_size) + 2 || + st->field->width != st->xgwa.width / (1 << st->field->cell_size) + 2) { - if (do_tick(f) < (f->height + f->width) / 4) { - populate_field(f, density); - } + resize_field(st->field, st->xgwa.width / (1 << st->field->cell_size) + 2, + st->xgwa.height / (1 << st->field->cell_size) + 2); + populate_field(st->field, st->density); + } - if (cycles % (f->max_age /2) == 0) { - populate_edges(f, density); - do_tick(f); - populate_edges(f, 0); - } + draw_field(st, st->field); - XSync(dpy, False); + if (do_tick(st->field) < (st->field->height + st->field->width) / 4) { + populate_field(st->field, st->density); + } - cycles++; + if (st->cycles % (st->field->max_age /2) == 0) { + populate_edges(st->field, st->density); + do_tick(st->field); + populate_edges(st->field, 0); + } - if (cycle_delay) - usleep(cycle_delay); + st->cycles++; #ifdef TIME_ME - if (cycles % f->max_age == 0) { - printf("%g s.\n", - ((time(NULL) - start_time) * 1000.0) / cycles); - } + if (st->cycles % st->field->max_age == 0) { + printf("%g s.\n", + ((time(NULL) - st->start_time) * 1000.0) / st->cycles); + } #endif + + return (st->cycle_delay); +} + + +static void +cloudlife_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +cloudlife_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + if (screenhack_event_helper (dpy, window, event)) + { + XClearWindow (dpy, window); + st->cycles = 0; + st->field = init_field(st); + return True; } + return False; } + +static void +cloudlife_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *cloudlife_defaults[] = { + ".background: black", + ".foreground: blue", + "*fpsSolid: true", + "*cycleDelay: 25000", + "*cycleColors: 2", + "*ncolors: 64", + "*maxAge: 64", + "*initialDensity: 30", + "*cellSize: 3", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec cloudlife_options[] = { + {"-background", ".background", XrmoptionSepArg, 0}, + {"-foreground", ".foreground", XrmoptionSepArg, 0}, + {"-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0}, + {"-cycle-colors", ".cycleColors", XrmoptionSepArg, 0}, + {"-ncolors", ".ncolors", XrmoptionSepArg, 0}, + {"-cell-size", ".cellSize", XrmoptionSepArg, 0}, + {"-initial-density", ".initialDensity", XrmoptionSepArg, 0}, + {"-max-age", ".maxAge", XrmoptionSepArg, 0}, + {0, 0, 0, 0} +}; + + +XSCREENSAVER_MODULE ("CloudLife", cloudlife)