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 * Based on several examples from the hacks directory of:
15 * xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski <jwz@jwz.org>
17 * Permission to use, copy, modify, distribute, and sell this software and its
18 * documentation for any purpose is hereby granted without fee, provided that
19 * the above copyright notice appear in all copies and that both that
20 * copyright notice and this permission notice appear in supporting
21 * documentation. No representations are made about the suitability of this
22 * software for any purpose. It is provided "as is" without express or
26 #include "screenhack.h"
32 #define MAX_WIDTH SHRT_MAX
39 /* this program goes faster if some functions are inline. The following is
40 * borrowed from ifs.c */
41 #if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus)
50 unsigned int cell_size;
52 unsigned char *new_cells;
56 *xrealloc(void *p, size_t size)
59 if ((ret = realloc(p, size)) == NULL) {
60 fprintf(stderr, "%s: out of memory\n", progname);
69 field *f = xrealloc(NULL, sizeof(field));
72 f->cell_size = get_integer_resource("cellSize", "Integer");
73 f->max_age = get_integer_resource("maxAge", "Integer");
80 resize_field(field * f, unsigned int w, unsigned int h)
85 f->cells = xrealloc(f->cells,
86 w * sizeof(unsigned char) *
87 h * sizeof(unsigned char));
89 xrealloc(f->new_cells,
90 w * sizeof(unsigned char) * h * sizeof(unsigned char));
94 *cell_at(field * f, unsigned int x, unsigned int y)
96 return (f->cells + x * sizeof(unsigned char) +
97 y * f->width * sizeof(unsigned char));
101 *new_cell_at(field * f, unsigned int x, unsigned int y)
103 return (f->new_cells + x * sizeof(unsigned char) +
104 y * f->width * sizeof(unsigned char));
108 draw_field(Display * dpy,
109 Window window, Colormap cmap, GC fgc, GC bgc, field * f)
112 unsigned int rx, ry = 0; /* random amount to offset the dot */
113 unsigned int size = 1 << f->cell_size;
114 unsigned int mask = size - 1;
115 static XPoint fg_points[MAX_WIDTH];
116 static XPoint bg_points[MAX_WIDTH];
117 unsigned int fg_count, bg_count;
119 /* columns 0 and width-1 are off screen and not drawn. */
120 for (y = 1; y < f->height - 1; y++) {
124 /* rows 0 and height-1 are off screen and not drawn. */
125 for (x = 1; x < f->width - 1; x++) {
127 ry = rx >> f->cell_size;
131 if (*cell_at(f, x, y)) {
132 fg_points[fg_count].x = (short) x *size - rx - 1;
133 fg_points[fg_count].y = (short) y *size - ry - 1;
136 bg_points[bg_count].x = (short) x *size - rx - 1;
137 bg_points[bg_count].y = (short) y *size - ry - 1;
141 XDrawPoints(dpy, window, fgc, fg_points, fg_count,
143 XDrawPoints(dpy, window, bgc, bg_points, bg_count,
149 cell_value(unsigned char c, unsigned int age)
153 } else if (c > age) {
161 is_alive(field * f, unsigned int x, unsigned int y)
169 for (i = x - 1; i <= x + 1; i++) {
170 for (j = y - 1; j <= y + 1; j++) {
171 if (y != j || x != i) {
172 count += cell_value(*cell_at(f, i, j), f->max_age);
177 p = cell_at(f, x, y);
179 if (count == 2 || count == 3) {
197 unsigned int count = 0;
198 for (x = 1; x < f->width - 1; x++) {
199 for (y = 1; y < f->height - 1; y++) {
200 count += *new_cell_at(f, x, y) = is_alive(f, x, y);
203 memcpy(f->cells, f->new_cells, f->width * sizeof(unsigned char) *
204 f->height * sizeof(unsigned char));
210 random_cell(unsigned int p)
212 int r = random() & 0xff;
222 populate_field(field * f, unsigned int p)
226 for (x = 0; x < f->width; x++) {
227 for (y = 0; y < f->height; y++) {
228 *cell_at(f, x, y) = random_cell(p);
234 populate_edges(field * f, unsigned int p)
238 for (i = f->width; i--;) {
239 *cell_at(f, i, 0) = random_cell(p);
240 *cell_at(f, i, f->height - 1) = random_cell(p);
243 for (i = f->height; i--;) {
244 *cell_at(f, f->width - 1, i) = random_cell(p);
245 *cell_at(f, 0, i) = random_cell(p);
250 char *progclass = "Cloudlife";
253 ".background: black",
255 "*cycleDelay: 25000",
257 "*initialDensity: 160",
262 XrmOptionDescRec options[] = {
263 {"-background", ".background", XrmoptionSepArg, 0},
264 {"-foreground", ".foreground", XrmoptionSepArg, 0},
265 {"-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0},
266 {"-cell-size", ".cellSize", XrmoptionSepArg, 0},
267 {"-initial-density", ".initialDensity", XrmoptionSepArg, 0},
268 {"-max-age", ".maxAge", XrmoptionSepArg, 0},
272 void screenhack(Display * dpy, Window window)
274 field *f = init_field();
277 time_t start_time = time(NULL);
280 unsigned int cycles = 0;
284 XWindowAttributes xgwa;
286 unsigned int cycle_delay = (unsigned int)
287 get_integer_resource("cycleDelay", "Integer");
288 unsigned int density = (unsigned int)
289 get_integer_resource("initialDensity", "Integer") & 0xff;
290 XGetWindowAttributes(dpy, window, &xgwa);
292 gcv.foreground = get_pixel_resource("foreground", "Foreground",
294 fgc = XCreateGC(dpy, window, GCForeground, &gcv);
296 gcv.foreground = get_pixel_resource("background", "Background",
298 bgc = XCreateGC(dpy, window, GCForeground, &gcv);
301 XGetWindowAttributes(dpy, window, &xgwa);
302 if (f->height != xgwa.height / (1 << f->cell_size) + 2 ||
303 f->width != xgwa.width / (1 << f->cell_size) + 2) {
305 resize_field(f, xgwa.width / (1 << f->cell_size) + 2,
306 xgwa.height / (1 << f->cell_size) + 2);
307 populate_field(f, density);
310 screenhack_handle_events(dpy);
312 draw_field(dpy, window, xgwa.colormap, fgc, bgc, f);
314 if (do_tick(f) < (f->height + f->width) / 4) {
315 populate_field(f, density);
318 if (cycles % (f->max_age /2) == 0) {
319 populate_edges(f, density);
321 populate_edges(f, 0);
332 if (cycles % f->max_age == 0) {
334 ((time(NULL) - start_time) * 1000.0) / cycles);