1 /* cloudlife by Don Marti <dmarti@zgp.org>
3 * Based on Conway's Life, but with one rule change to make it a better
4 * screensaver: cells have a max age.
6 * When a cell exceeds the max age, it counts as 3 for populating the next
7 * generation. This makes long-lived formations explode instead of just
8 * sitting there burning a hole in your screen.
10 * Cloudlife only draws one pixel of each cell per tick, whether the cell is
11 * alive or dead. So gliders look like little comets.
13 * 20 May 2003 -- now includes color cycling and a man page.
15 * Based on several examples from the hacks directory of:
17 * xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski <jwz@jwz.org>
19 * Permission to use, copy, modify, distribute, and sell this software and its
20 * documentation for any purpose is hereby granted without fee, provided that
21 * the above copyright notice appear in all copies and that both that
22 * copyright notice and this permission notice appear in supporting
23 * documentation. No representations are made about the suitability of this
24 * software for any purpose. It is provided "as is" without express or
28 #include "screenhack.h"
34 #define MAX_WIDTH SHRT_MAX
41 /* this program goes faster if some functions are inline. The following is
42 * borrowed from ifs.c */
43 #if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus)
52 unsigned int cell_size;
54 unsigned char *new_cells;
58 *xrealloc(void *p, size_t size)
61 if ((ret = realloc(p, size)) == NULL) {
62 fprintf(stderr, "%s: out of memory\n", progname);
71 struct field *f = xrealloc(NULL, sizeof(struct field));
74 f->cell_size = get_integer_resource("cellSize", "Integer");
75 f->max_age = get_integer_resource("maxAge", "Integer");
82 resize_field(struct field * f, unsigned int w, unsigned int h)
87 f->cells = xrealloc(f->cells,
88 w * sizeof(unsigned char) *
89 h * sizeof(unsigned char));
91 xrealloc(f->new_cells,
92 w * sizeof(unsigned char) * h * sizeof(unsigned char));
96 *cell_at(struct field * f, unsigned int x, unsigned int y)
98 return (f->cells + x * sizeof(unsigned char) +
99 y * f->width * sizeof(unsigned char));
103 *new_cell_at(struct field * f, unsigned int x, unsigned int y)
105 return (f->new_cells + x * sizeof(unsigned char) +
106 y * f->width * sizeof(unsigned char));
110 draw_field(Display * dpy,
111 Window window, GC fgc, GC bgc, struct field * f)
114 unsigned int rx, ry = 0; /* random amount to offset the dot */
115 unsigned int size = 1 << f->cell_size;
116 unsigned int mask = size - 1;
117 static XPoint fg_points[MAX_WIDTH];
118 static XPoint bg_points[MAX_WIDTH];
119 unsigned int fg_count, bg_count;
121 /* columns 0 and width-1 are off screen and not drawn. */
122 for (y = 1; y < f->height - 1; y++) {
126 /* rows 0 and height-1 are off screen and not drawn. */
127 for (x = 1; x < f->width - 1; x++) {
129 ry = rx >> f->cell_size;
133 if (*cell_at(f, x, y)) {
134 fg_points[fg_count].x = (short) x *size - rx - 1;
135 fg_points[fg_count].y = (short) y *size - ry - 1;
138 bg_points[bg_count].x = (short) x *size - rx - 1;
139 bg_points[bg_count].y = (short) y *size - ry - 1;
143 XDrawPoints(dpy, window, fgc, fg_points, fg_count,
145 XDrawPoints(dpy, window, bgc, bg_points, bg_count,
151 cell_value(unsigned char c, unsigned int age)
155 } else if (c > age) {
163 is_alive(struct field * f, unsigned int x, unsigned int y)
171 for (i = x - 1; i <= x + 1; i++) {
172 for (j = y - 1; j <= y + 1; j++) {
173 if (y != j || x != i) {
174 count += cell_value(*cell_at(f, i, j), f->max_age);
179 p = cell_at(f, x, y);
181 if (count == 2 || count == 3) {
196 do_tick(struct field * f)
199 unsigned int count = 0;
200 for (x = 1; x < f->width - 1; x++) {
201 for (y = 1; y < f->height - 1; y++) {
202 count += *new_cell_at(f, x, y) = is_alive(f, x, y);
205 memcpy(f->cells, f->new_cells, f->width * sizeof(unsigned char) *
206 f->height * sizeof(unsigned char));
212 random_cell(unsigned int p)
214 int r = random() & 0xff;
224 populate_field(struct field * f, unsigned int p)
228 for (x = 0; x < f->width; x++) {
229 for (y = 0; y < f->height; y++) {
230 *cell_at(f, x, y) = random_cell(p);
236 populate_edges(struct field * f, unsigned int p)
240 for (i = f->width; i--;) {
241 *cell_at(f, i, 0) = random_cell(p);
242 *cell_at(f, i, f->height - 1) = random_cell(p);
245 for (i = f->height; i--;) {
246 *cell_at(f, f->width - 1, i) = random_cell(p);
247 *cell_at(f, 0, i) = random_cell(p);
252 char *progclass = "Cloudlife";
255 ".background: black",
257 "*cycleDelay: 25000",
261 "*initialDensity: 30",
266 XrmOptionDescRec options[] = {
267 {"-background", ".background", XrmoptionSepArg, 0},
268 {"-foreground", ".foreground", XrmoptionSepArg, 0},
269 {"-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0},
270 {"-cycle-colors", ".cycleColors", XrmoptionSepArg, 0},
271 {"-ncolors", ".ncolors", XrmoptionSepArg, 0},
272 {"-cell-size", ".cellSize", XrmoptionSepArg, 0},
273 {"-initial-density", ".initialDensity", XrmoptionSepArg, 0},
274 {"-max-age", ".maxAge", XrmoptionSepArg, 0},
278 void screenhack(Display * dpy, Window window)
280 struct field *f = init_field();
283 time_t start_time = time(NULL);
286 unsigned int cycles = 0;
287 unsigned int colorindex = 0; /* which color in the colormap are we on */
288 unsigned int colortimer = 0; /* when this reaches 0, cycle to next color */
297 XWindowAttributes xgwa;
298 XColor *colors = NULL;
301 cycle_delay = get_integer_resource("cycleDelay", "Integer");
302 cycle_colors = get_integer_resource("cycleColors", "Integer");
303 ncolors = get_integer_resource("ncolors", "Integer");
304 density = (get_integer_resource("initialDensity", "Integer")
307 XGetWindowAttributes(dpy, window, &xgwa);
310 colors = (XColor *) xrealloc(colors, sizeof(XColor) * (ncolors+1));
311 make_smooth_colormap (dpy, xgwa.visual, xgwa.colormap, colors, &ncolors,
315 gcv.foreground = get_pixel_resource("foreground", "Foreground",
317 fgc = XCreateGC(dpy, window, GCForeground, &gcv);
319 gcv.foreground = get_pixel_resource("background", "Background",
321 bgc = XCreateGC(dpy, window, GCForeground, &gcv);
326 if (colortimer == 0) {
327 colortimer = cycle_colors;
328 if( colorindex == 0 )
329 colorindex = ncolors;
331 XSetForeground(dpy, fgc, colors[colorindex].pixel);
336 XGetWindowAttributes(dpy, window, &xgwa);
337 if (f->height != xgwa.height / (1 << f->cell_size) + 2 ||
338 f->width != xgwa.width / (1 << f->cell_size) + 2) {
340 resize_field(f, xgwa.width / (1 << f->cell_size) + 2,
341 xgwa.height / (1 << f->cell_size) + 2);
342 populate_field(f, density);
345 screenhack_handle_events(dpy);
347 draw_field(dpy, window, fgc, bgc, f);
349 if (do_tick(f) < (f->height + f->width) / 4) {
350 populate_field(f, density);
353 if (cycles % (f->max_age /2) == 0) {
354 populate_edges(f, density);
356 populate_edges(f, 0);
367 if (cycles % f->max_age == 0) {
369 ((time(NULL) - start_time) * 1000.0) / cycles);