1 /* critical -- Self-organizing-criticality display hack for XScreenSaver
2 * Copyright (C) 1998, 1999 Martin Pool <mbp@humbug.org.au>
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation. No representations are made
9 * about the suitability of this software for any purpose. It is
10 * provided "as is" without express or implied warranty.
12 * See `critical.man' for more information.
15 * 13 Nov 1998: Initial version, Martin Pool <mbp@humbug.org.au>
18 #include "screenhack.h"
24 char *progclass = "Critical";
28 int width, height; /* in cells */
29 unsigned short *cells;
33 CriticalModel * model_allocate (int w, int h);
34 void model_initialize (CriticalModel *model);
35 static void model_step (CriticalModel *model, int *top_x, int *top_y);
38 /* Options this module understands. */
39 XrmOptionDescRec options[] = {
40 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
41 { "-delay", ".delay", XrmoptionSepArg, 0 },
42 { "-colorscheme", ".colorscheme", XrmoptionSepArg, 0 },
43 { "-restart", ".restart", XrmoptionSepArg, 0 },
44 { "-cellsize", ".cellsize", XrmoptionSepArg, 0 },
45 { "-batchcount", ".batchcount", XrmoptionSepArg, 0 },
46 { 0, 0, 0, 0 } /* end */
50 /* Default xrm resources. */
53 "*colorscheme: smooth",
63 /* Allocate an return a new simulation model datastructure.
67 model_allocate (int model_w, int model_h)
71 model = malloc (sizeof (CriticalModel));
75 model->width = model_w;
76 model->height = model_h;
78 model->cells = malloc (sizeof (int) * model_w * model_h);
87 /* Initialize the data model underlying the hack.
89 For the self-organizing criticality hack, this consists of a 2d
90 array full of random integers.
92 I've considered storing the data as (say) a binary tree within a 2d
93 array, to make finding the highest value faster at the expense of
94 storage space: searching the whole array on each iteration seems a
95 little inefficient. However, the screensaver doesn't seem to take
96 up many cycles as it is: presumably the search is pretty quick
97 compared to the sleeps. The current version uses less than 1% of
98 the CPU time of an AMD K6-233. Many machines running X11 at this
99 point in time seem to be memory-limited, not CPU-limited.
101 The root of all evil, and all that.
106 model_initialize (CriticalModel *model)
110 for (i = model->width * model->height; i >= 0; i--)
112 model->cells[i] = (unsigned short) random ();
117 /* Move one step forward in the criticality simulation.
119 This function locates and returns in (TOP_X, TOP_Y) the location of
120 the highest-valued cell in the model. It also replaces that cell
121 and it's eight nearest neighbours with new random values.
122 Neighbours that fall off the edge of the model are simply
125 model_step (CriticalModel *model, int *top_x, int *top_y)
129 unsigned short top_value;
131 /* Find the top cell */
134 for (y = 0; y < model->height; y++)
135 for (x = 0; x < model->width; x++)
137 if (model->cells[i] >= top_value)
139 top_value = model->cells[i];
146 /* Replace it and its neighbours with new random values */
147 for (dy = -1; dy <= 1; dy++)
150 if (y < 0 || y >= model->height)
153 for (dx = -1; dx <= 1; dx++)
156 if (x < 0 || x >= model->width)
159 model->cells[y * model->width + x] = (unsigned short) random();
165 /* Construct and return in COLORS and N_COLORS a new set of colors,
166 depending on the resource settings. */
168 setup_colormap (Display *dpy, XWindowAttributes *wattr,
173 char const * color_scheme;
175 /* Make a colormap */
176 *n_colors = get_integer_resource ("ncolors", "Integer");
180 *colors = (XColor *) calloc (sizeof(XColor), *n_colors);
183 fprintf (stderr, "%s:%d: can't allocate memory for colors\n",
189 color_scheme = get_string_resource ("colorscheme", "ColorScheme");
191 if (!strcmp (color_scheme, "random"))
193 make_random_colormap (dpy, wattr->visual,
196 True, True, &writable, True);
198 else if (!strcmp (color_scheme, "smooth"))
200 make_smooth_colormap (dpy, wattr->visual,
203 True, &writable, True);
207 make_uniform_colormap (dpy, wattr->visual,
209 *colors, n_colors, True,
216 /* Display a self-organizing criticality screen hack. The program
217 runs indefinately on the root window. */
219 screenhack (Display *dpy, Window window)
223 XWindowAttributes wattr;
226 int model_w, model_h;
227 CriticalModel *model;
228 int lines_per_color = 10;
235 /* Number of screens that should be drawn before reinitializing the
236 model, and count of the number of screens done so far. */
237 int n_restart, i_restart;
239 /* Find window attributes */
240 XGetWindowAttributes (dpy, window, &wattr);
242 /* Construct the initial model state. */
243 cell_size = get_integer_resource ("cellsize", "Integer");
246 if (cell_size >= 100)
249 batchcount = get_integer_resource ("batchcount", "Integer");
253 model_w = wattr.width / cell_size;
254 model_h = wattr.height / cell_size;
256 model = model_allocate (model_w, model_h);
259 fprintf (stderr, "critical: error preparing the model\n");
263 /* make a black gc for the background */
264 gcv.foreground = get_pixel_resource ("background", "Background",
265 dpy, wattr.colormap);
266 bgc = XCreateGC (dpy, window, GCForeground, &gcv);
268 fgc = XCreateGC (dpy, window, 0, &gcv);
270 x2 = rand() % model_w;
271 y2 = rand() % model_h;
273 delay_usecs = get_integer_resource ("delay", "Integer");
274 n_restart = get_integer_resource ("restart", "Integer");
276 /* xscreensaver will kill or stop us when the user does something
277 * that deserves attention. */
285 setup_colormap (dpy, &wattr, &colors, &n_colors);
286 model_initialize (model);
289 for (i_batch = batchcount; i_batch; i_batch--)
292 if ((i_batch % lines_per_color) == 0)
294 i_color = (i_color + 1) % n_colors;
295 gcv.foreground = colors[i_color].pixel;
296 XChangeGC (dpy, fgc, GCForeground, &gcv);
303 model_step (model, &x2, &y2);
305 XDrawLine (dpy, window, fgc,
306 x1 * cell_size + cell_size/2,
307 y1 * cell_size + cell_size/2,
308 x2 * cell_size + cell_size/2,
309 y2 * cell_size + cell_size/2);
312 screenhack_handle_events (dpy);
315 usleep (delay_usecs);
318 i_restart = (i_restart + 1) % n_restart;
319 erase_full_window (dpy, window);
327 * compile-command "make critical && ./critical"