source: trunk/third/xscreensaver/hacks/cloudlife.c @ 20148

Revision 20148, 9.0 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* cloudlife by Don Marti <dmarti@zgp.org>
2 *
3 * Based on Conway's Life, but with one rule change to make it a better
4 * screensaver: cells have a max age.
5 *
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.
9 *
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.
12
13 * 20 May 2003 -- now includes color cycling and a man page.
14
15 * Based on several examples from the hacks directory of:
16 
17 * xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski <jwz@jwz.org>
18 *
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
25 * implied warranty.
26 */
27
28#include "screenhack.h"
29#include <stdio.h>
30#include <sys/time.h>
31
32#ifndef MAX_WIDTH
33#include <limits.h>
34#define MAX_WIDTH SHRT_MAX
35#endif
36
37#ifdef TIME_ME
38#include <time.h>
39#endif
40
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)
44#undef inline
45#define inline                  /* */
46#endif
47
48struct field {
49    unsigned int height;
50    unsigned int width;
51    unsigned int max_age;
52    unsigned int cell_size;
53    unsigned char *cells;
54    unsigned char *new_cells;
55};
56
57static void
58*xrealloc(void *p, size_t size)
59{
60    void *ret;
61    if ((ret = realloc(p, size)) == NULL) {
62        fprintf(stderr, "%s: out of memory\n", progname);
63        exit(1);
64    }
65    return ret;
66}
67
68struct field
69*init_field(void)
70{
71    struct field *f = xrealloc(NULL, sizeof(struct field));
72    f->height = 0;
73    f->width = 0;
74    f->cell_size = get_integer_resource("cellSize", "Integer");
75    f->max_age = get_integer_resource("maxAge", "Integer");
76    f->cells = NULL;
77    f->new_cells = NULL;
78    return f;
79}
80
81void
82resize_field(struct field * f, unsigned int w, unsigned int h)
83{
84    f->width = w;
85    f->height = h;
86
87    f->cells = xrealloc(f->cells,
88                        w * sizeof(unsigned char) *
89                        h * sizeof(unsigned char));
90    f->new_cells =
91        xrealloc(f->new_cells,
92                 w * sizeof(unsigned char) * h * sizeof(unsigned char));
93}
94
95inline unsigned char
96*cell_at(struct field * f, unsigned int x, unsigned int y)
97{
98    return (f->cells + x * sizeof(unsigned char) +
99                       y * f->width * sizeof(unsigned char));
100}
101
102inline unsigned char
103*new_cell_at(struct field * f, unsigned int x, unsigned int y)
104{
105    return (f->new_cells + x * sizeof(unsigned char) +
106                           y * f->width * sizeof(unsigned char));
107}
108
109static void
110draw_field(Display * dpy,
111           Window window, GC fgc, GC bgc, struct field * f)
112{
113    unsigned int x, y;
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;
120
121    /* columns 0 and width-1 are off screen and not drawn. */
122    for (y = 1; y < f->height - 1; y++) {
123        fg_count = 0;
124        bg_count = 0;
125
126        /* rows 0 and height-1 are off screen and not drawn. */
127        for (x = 1; x < f->width - 1; x++) {
128            rx = random();
129            ry = rx >> f->cell_size;
130            rx &= mask;
131            ry &= mask;
132
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;
136                fg_count++;
137            } else {
138                bg_points[bg_count].x = (short) x *size - rx - 1;
139                bg_points[bg_count].y = (short) y *size - ry - 1;
140                bg_count++;
141            }
142        }
143        XDrawPoints(dpy, window, fgc, fg_points, fg_count,
144                    CoordModeOrigin);
145        XDrawPoints(dpy, window, bgc, bg_points, bg_count,
146                    CoordModeOrigin);
147    }
148}
149
150inline unsigned int
151cell_value(unsigned char c, unsigned int age)
152{
153    if (!c) {
154        return 0;
155    } else if (c > age) {
156        return (3);
157    } else {
158        return (1);
159    }
160}
161
162inline unsigned int
163is_alive(struct field * f, unsigned int x, unsigned int y)
164{
165    unsigned int count;
166    unsigned int i, j;
167    unsigned char *p;
168
169    count = 0;
170
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);
175            }
176        }
177    }
178
179    p = cell_at(f, x, y);
180    if (*p) {
181        if (count == 2 || count == 3) {
182            return ((*p) + 1);
183        } else {
184            return (0);
185        }
186    } else {
187        if (count == 3) {
188            return (1);
189        } else {
190            return (0);
191        }
192    }
193}
194
195unsigned int
196do_tick(struct field * f)
197{
198    unsigned int x, y;
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);
203        }
204    }
205    memcpy(f->cells, f->new_cells, f->width * sizeof(unsigned char) *
206           f->height * sizeof(unsigned char));
207    return count;
208}
209
210
211unsigned int
212random_cell(unsigned int p)
213{
214    int r = random() & 0xff;
215
216    if (r < p) {
217        return (1);
218    } else {
219        return (0);
220    }
221}
222
223void
224populate_field(struct field * f, unsigned int p)
225{
226    unsigned int x, y;
227
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);
231        }
232    }
233}
234
235void
236populate_edges(struct field * f, unsigned int p)
237{
238    unsigned int i;
239
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);
243    }
244
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);
248    }
249}
250
251
252char *progclass = "Cloudlife";
253
254char *defaults[] = {
255    ".background:       black",
256    ".foreground:       blue",
257    "*cycleDelay:       25000",
258    "*cycleColors:      2",
259    "*ncolors:          64",
260    "*maxAge:           64",
261    "*initialDensity:   30",
262    "*cellSize:         3",
263    0
264};
265
266XrmOptionDescRec 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},
275    {0, 0, 0, 0}
276};
277
278void screenhack(Display * dpy, Window window)
279{
280    struct field *f = init_field();
281
282#ifdef TIME_ME
283    time_t start_time = time(NULL);
284#endif
285
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 */
289
290    int cycle_delay;
291    int cycle_colors;
292    int ncolors;
293    int density;
294
295    GC fgc, bgc;
296    XGCValues gcv;
297    XWindowAttributes xgwa;
298    XColor *colors = NULL;
299    Bool tmp = True;
300
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")
305                  % 100 * 256)/100;
306
307    XGetWindowAttributes(dpy, window, &xgwa);
308
309    if (cycle_colors) {
310        colors = (XColor *) xrealloc(colors, sizeof(XColor) * (ncolors+1));
311        make_smooth_colormap (dpy, xgwa.visual, xgwa.colormap, colors, &ncolors,
312                              True, &tmp, True);
313    }
314
315    gcv.foreground = get_pixel_resource("foreground", "Foreground",
316                                        dpy, xgwa.colormap);
317    fgc = XCreateGC(dpy, window, GCForeground, &gcv);
318
319    gcv.foreground = get_pixel_resource("background", "Background",
320                                        dpy, xgwa.colormap);
321    bgc = XCreateGC(dpy, window, GCForeground, &gcv);
322
323    while (1) {
324
325        if (cycle_colors) {
326            if (colortimer == 0) {
327               colortimer = cycle_colors;
328               if( colorindex == 0 )
329                   colorindex = ncolors;
330               colorindex--;
331               XSetForeground(dpy, fgc, colors[colorindex].pixel);
332            }
333            colortimer--;
334        }
335
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) {
339
340            resize_field(f, xgwa.width / (1 << f->cell_size) + 2,
341                         xgwa.height / (1 << f->cell_size) + 2);
342            populate_field(f, density);
343        }
344
345        screenhack_handle_events(dpy);
346
347        draw_field(dpy, window, fgc, bgc, f);
348
349        if (do_tick(f) < (f->height + f->width) / 4) {
350            populate_field(f, density);
351        }
352
353        if (cycles % (f->max_age /2) == 0) {
354            populate_edges(f, density);
355            do_tick(f);
356            populate_edges(f, 0);
357        }
358
359        XSync(dpy, False);
360 
361        cycles++;
362
363        if (cycle_delay)
364            usleep(cycle_delay);
365
366#ifdef TIME_ME
367        if (cycles % f->max_age == 0) {
368            printf("%g s.\n",
369                   ((time(NULL) - start_time) * 1000.0) / cycles);
370        }
371#endif
372    }
373}
Note: See TracBrowser for help on using the repository browser.