1 | /* petri, simulate mold in a petri dish. v2.7 |
---|
2 | * by Dan Bornstein, danfuzz@milk.com |
---|
3 | * with help from Jamie Zawinski, jwz@jwz.org |
---|
4 | * Copyright (c) 1992-1999 Dan Bornstein. |
---|
5 | * |
---|
6 | * Permission to use, copy, modify, distribute, and sell this software and its |
---|
7 | * documentation for any purpose is hereby granted without fee, provided that |
---|
8 | * the above copyright notice appear in all copies and that both that |
---|
9 | * copyright notice and this permission notice appear in supporting |
---|
10 | * documentation. No representations are made about the suitability of this |
---|
11 | * software for any purpose. It is provided "as is" without express or |
---|
12 | * implied warranty. |
---|
13 | * |
---|
14 | * |
---|
15 | * Brief description of options/resources: |
---|
16 | * |
---|
17 | * delay: the delay in microseconds between iterations |
---|
18 | * size: the size of a cell in pixels |
---|
19 | * count: the number of different kinds of mold (minimum: 2) |
---|
20 | * diaglim: the age limit for diagonal growth as a multiplier of orthogonal |
---|
21 | * growth (minimum: 1, maximum 2). 1 means square growth, 1.414 |
---|
22 | * (i.e., sqrt(2)) means approximately circular growth, 2 means diamond |
---|
23 | * growth. |
---|
24 | * anychan: the chance (fraction, between 0 and 1) that at each iteration, |
---|
25 | * any new cell will be born |
---|
26 | * minorchan: the chance (fraction, between 0 and 1) that, given that new |
---|
27 | * cells will be added, that only two will be added (a minor cell birth |
---|
28 | * event) |
---|
29 | * instantdeathchan: the chance (fraction, between 0 and 1) that, given |
---|
30 | * that death and destruction will happen, that instead of using plague |
---|
31 | * cells, death will be instantaneous |
---|
32 | * minlifespan: the minimum lifespan of a colony (before black death ensues) |
---|
33 | * maxlifespan: the maximum lifespan of a colony (before black death ensues) |
---|
34 | * minlifespeed: the minimum speed for living cells as a fraction of the |
---|
35 | * maximum possible speed (fraction, between 0 and 1) |
---|
36 | * maxlifespeed: the maximum speed for living cells as a fraction of the |
---|
37 | * maximum possible speed (fraction, between 0 and 1) |
---|
38 | * mindeathspeed: the minimum speed for black death cells as a fraction of the |
---|
39 | * maximum possible speed (fraction, between 0 and 1) |
---|
40 | * maxdeathspeed: the maximum speed for black death cells as a fraction of the |
---|
41 | * maximum possible speed (fraction, between 0 and 1) |
---|
42 | * originalcolors: if true, count must be 8 or less and the colors are a |
---|
43 | * fixed set of primary and secondary colors (the artist's original choices) |
---|
44 | * |
---|
45 | * Interesting settings: |
---|
46 | * |
---|
47 | * petri -originalcolors -size 8 |
---|
48 | * petri -size 2 |
---|
49 | * petri -size 8 -diaglim 1.8 |
---|
50 | * petri -diaglim 1.1 |
---|
51 | * |
---|
52 | * petri -count 4 -anychan 0.01 -minorchan 1 \ |
---|
53 | * -minlifespan 2000 -maxlifespan 5000 |
---|
54 | * |
---|
55 | * petri -count 3 -anychan 1 -minlifespan 100000 \ |
---|
56 | * -instantdeathchan 0 |
---|
57 | * |
---|
58 | * petri -minlifespeed 0.02 -maxlifespeed 0.03 -minlifespan 1 \ |
---|
59 | * -maxlifespan 1 -instantdeathchan 0 -minorchan 0 \ |
---|
60 | * -anychan 0.3 -delay 4000 |
---|
61 | */ |
---|
62 | |
---|
63 | #include <math.h> |
---|
64 | #include "screenhack.h" |
---|
65 | #include "spline.h" |
---|
66 | |
---|
67 | #define FLOAT float |
---|
68 | #define RAND_FLOAT (((FLOAT) (random() & 0xffff)) / ((FLOAT) 0x10000)) |
---|
69 | |
---|
70 | typedef struct cell_s |
---|
71 | { |
---|
72 | unsigned char col; /* 0 */ |
---|
73 | unsigned char isnext; /* 1 */ |
---|
74 | unsigned char nextcol; /* 2 */ |
---|
75 | /* 3 */ |
---|
76 | struct cell_s *next; /* 4 */ |
---|
77 | struct cell_s *prev; /* 8 - */ |
---|
78 | FLOAT speed; /* 12 */ |
---|
79 | FLOAT growth; /* 16 20 - */ |
---|
80 | FLOAT nextspeed; /* 20 28 */ |
---|
81 | /* 24 36 - */ |
---|
82 | } cell; |
---|
83 | |
---|
84 | static int arr_width; |
---|
85 | static int arr_height; |
---|
86 | static int count; |
---|
87 | |
---|
88 | static cell *arr; |
---|
89 | static cell *head; |
---|
90 | static cell *tail; |
---|
91 | static int blastcount; |
---|
92 | |
---|
93 | static Display *display; |
---|
94 | static Window window; |
---|
95 | static GC *coloredGCs; |
---|
96 | |
---|
97 | static int windowWidth; |
---|
98 | static int windowHeight; |
---|
99 | static int xOffset; |
---|
100 | static int yOffset; |
---|
101 | static int xSize; |
---|
102 | static int ySize; |
---|
103 | |
---|
104 | static FLOAT orthlim = 1.0; |
---|
105 | static FLOAT diaglim; |
---|
106 | static FLOAT anychan; |
---|
107 | static FLOAT minorchan; |
---|
108 | static FLOAT instantdeathchan; |
---|
109 | static int minlifespan; |
---|
110 | static int maxlifespan; |
---|
111 | static FLOAT minlifespeed; |
---|
112 | static FLOAT maxlifespeed; |
---|
113 | static FLOAT mindeathspeed; |
---|
114 | static FLOAT maxdeathspeed; |
---|
115 | static Bool originalcolors; |
---|
116 | |
---|
117 | #define cell_x(c) (((c) - arr) % arr_width) |
---|
118 | #define cell_y(c) (((c) - arr) / arr_width) |
---|
119 | |
---|
120 | |
---|
121 | static int random_life_value (void) |
---|
122 | { |
---|
123 | return (int) ((RAND_FLOAT * (maxlifespan - minlifespan)) + minlifespan); |
---|
124 | } |
---|
125 | |
---|
126 | static void setup_random_colormap (XWindowAttributes *xgwa) |
---|
127 | { |
---|
128 | XGCValues gcv; |
---|
129 | int lose = 0; |
---|
130 | int ncolors = count - 1; |
---|
131 | int n; |
---|
132 | XColor *colors = (XColor *) calloc (sizeof(*colors), count*2); |
---|
133 | |
---|
134 | colors[0].pixel = get_pixel_resource ("background", "Background", |
---|
135 | display, xgwa->colormap); |
---|
136 | |
---|
137 | make_random_colormap (display, xgwa->visual, xgwa->colormap, |
---|
138 | colors+1, &ncolors, True, True, 0, True); |
---|
139 | if (ncolors < 1) |
---|
140 | { |
---|
141 | fprintf (stderr, "%s: couldn't allocate any colors\n", progname); |
---|
142 | exit (-1); |
---|
143 | } |
---|
144 | |
---|
145 | ncolors++; |
---|
146 | count = ncolors; |
---|
147 | |
---|
148 | memcpy (colors + count, colors, count * sizeof(*colors)); |
---|
149 | colors[count].pixel = get_pixel_resource ("foreground", "Foreground", |
---|
150 | display, xgwa->colormap); |
---|
151 | |
---|
152 | for (n = 1; n < count; n++) |
---|
153 | { |
---|
154 | int m = n + count; |
---|
155 | colors[n].red = colors[m].red / 2; |
---|
156 | colors[n].green = colors[m].green / 2; |
---|
157 | colors[n].blue = colors[m].blue / 2; |
---|
158 | |
---|
159 | if (!XAllocColor (display, xgwa->colormap, &colors[n])) |
---|
160 | { |
---|
161 | lose++; |
---|
162 | colors[n] = colors[m]; |
---|
163 | } |
---|
164 | } |
---|
165 | |
---|
166 | if (lose) |
---|
167 | { |
---|
168 | fprintf (stderr, |
---|
169 | "%s: unable to allocate %d half-intensity colors.\n", |
---|
170 | progname, lose); |
---|
171 | } |
---|
172 | |
---|
173 | for (n = 0; n < count*2; n++) |
---|
174 | { |
---|
175 | gcv.foreground = colors[n].pixel; |
---|
176 | coloredGCs[n] = XCreateGC (display, window, GCForeground, &gcv); |
---|
177 | } |
---|
178 | |
---|
179 | free (colors); |
---|
180 | } |
---|
181 | |
---|
182 | static void setup_original_colormap (XWindowAttributes *xgwa) |
---|
183 | { |
---|
184 | XGCValues gcv; |
---|
185 | int lose = 0; |
---|
186 | int n; |
---|
187 | XColor *colors = (XColor *) calloc (sizeof(*colors), count*2); |
---|
188 | |
---|
189 | colors[0].pixel = get_pixel_resource ("background", "Background", |
---|
190 | display, xgwa->colormap); |
---|
191 | |
---|
192 | colors[count].pixel = get_pixel_resource ("foreground", "Foreground", |
---|
193 | display, xgwa->colormap); |
---|
194 | |
---|
195 | for (n = 1; n < count; n++) |
---|
196 | { |
---|
197 | int m = n + count; |
---|
198 | colors[n].red = ((n & 0x01) != 0) * 0x8000; |
---|
199 | colors[n].green = ((n & 0x02) != 0) * 0x8000; |
---|
200 | colors[n].blue = ((n & 0x04) != 0) * 0x8000; |
---|
201 | |
---|
202 | if (!XAllocColor (display, xgwa->colormap, &colors[n])) |
---|
203 | { |
---|
204 | lose++; |
---|
205 | colors[n] = colors[0]; |
---|
206 | } |
---|
207 | |
---|
208 | colors[m].red = colors[n].red + 0x4000; |
---|
209 | colors[m].green = colors[n].green + 0x4000; |
---|
210 | colors[m].blue = colors[n].blue + 0x4000; |
---|
211 | |
---|
212 | if (!XAllocColor (display, xgwa->colormap, &colors[m])) |
---|
213 | { |
---|
214 | lose++; |
---|
215 | colors[m] = colors[count]; |
---|
216 | } |
---|
217 | } |
---|
218 | |
---|
219 | if (lose) |
---|
220 | { |
---|
221 | fprintf (stderr, |
---|
222 | "%s: unable to allocate %d colors.\n", |
---|
223 | progname, lose); |
---|
224 | } |
---|
225 | |
---|
226 | for (n = 0; n < count*2; n++) |
---|
227 | { |
---|
228 | gcv.foreground = colors[n].pixel; |
---|
229 | coloredGCs[n] = XCreateGC (display, window, GCForeground, &gcv); |
---|
230 | } |
---|
231 | |
---|
232 | free (colors); |
---|
233 | } |
---|
234 | |
---|
235 | static void setup_display (void) |
---|
236 | { |
---|
237 | XWindowAttributes xgwa; |
---|
238 | Colormap cmap; |
---|
239 | |
---|
240 | int cell_size = get_integer_resource ("size", "Integer"); |
---|
241 | int osize, alloc_size, oalloc; |
---|
242 | int mem_throttle = 0; |
---|
243 | char *s; |
---|
244 | |
---|
245 | if (cell_size < 1) cell_size = 1; |
---|
246 | |
---|
247 | osize = cell_size; |
---|
248 | |
---|
249 | s = get_string_resource ("memThrottle", "MemThrottle"); |
---|
250 | if (s) |
---|
251 | { |
---|
252 | int n; |
---|
253 | char c; |
---|
254 | if (1 == sscanf (s, " %d M %c", &n, &c) || |
---|
255 | 1 == sscanf (s, " %d m %c", &n, &c)) |
---|
256 | mem_throttle = n * (1 << 20); |
---|
257 | else if (1 == sscanf (s, " %d K %c", &n, &c) || |
---|
258 | 1 == sscanf (s, " %d k %c", &n, &c)) |
---|
259 | mem_throttle = n * (1 << 10); |
---|
260 | else if (1 == sscanf (s, " %d %c", &n, &c)) |
---|
261 | mem_throttle = n; |
---|
262 | else |
---|
263 | { |
---|
264 | fprintf (stderr, "%s: invalid memThrottle \"%s\" (try \"10M\")\n", |
---|
265 | progname, s); |
---|
266 | exit (1); |
---|
267 | } |
---|
268 | |
---|
269 | free (s); |
---|
270 | } |
---|
271 | |
---|
272 | XGetWindowAttributes (display, window, &xgwa); |
---|
273 | |
---|
274 | originalcolors = get_boolean_resource ("originalcolors", "Boolean"); |
---|
275 | |
---|
276 | count = get_integer_resource ("count", "Integer"); |
---|
277 | if (count < 2) count = 2; |
---|
278 | |
---|
279 | /* number of colors can't be greater than the half depth of the screen. */ |
---|
280 | if (count > (1L << (xgwa.depth-1))) |
---|
281 | count = (1L << (xgwa.depth-1)); |
---|
282 | |
---|
283 | /* Actually, since cell->col is of type char, this has to be small. */ |
---|
284 | if (count >= (1L << ((sizeof(arr[0].col) * 8) - 1))) |
---|
285 | count = (1L << ((sizeof(arr[0].col) * 8) - 1)); |
---|
286 | |
---|
287 | |
---|
288 | if (originalcolors && (count > 8)) |
---|
289 | { |
---|
290 | count = 8; |
---|
291 | } |
---|
292 | |
---|
293 | coloredGCs = (GC *) calloc (sizeof(GC), count * 2); |
---|
294 | |
---|
295 | diaglim = get_float_resource ("diaglim", "Float"); |
---|
296 | if (diaglim < 1.0) |
---|
297 | { |
---|
298 | diaglim = 1.0; |
---|
299 | } |
---|
300 | else if (diaglim > 2.0) |
---|
301 | { |
---|
302 | diaglim = 2.0; |
---|
303 | } |
---|
304 | diaglim *= orthlim; |
---|
305 | |
---|
306 | anychan = get_float_resource ("anychan", "Float"); |
---|
307 | if (anychan < 0.0) |
---|
308 | { |
---|
309 | anychan = 0.0; |
---|
310 | } |
---|
311 | else if (anychan > 1.0) |
---|
312 | { |
---|
313 | anychan = 1.0; |
---|
314 | } |
---|
315 | |
---|
316 | minorchan = get_float_resource ("minorchan","Float"); |
---|
317 | if (minorchan < 0.0) |
---|
318 | { |
---|
319 | minorchan = 0.0; |
---|
320 | } |
---|
321 | else if (minorchan > 1.0) |
---|
322 | { |
---|
323 | minorchan = 1.0; |
---|
324 | } |
---|
325 | |
---|
326 | instantdeathchan = get_float_resource ("instantdeathchan","Float"); |
---|
327 | if (instantdeathchan < 0.0) |
---|
328 | { |
---|
329 | instantdeathchan = 0.0; |
---|
330 | } |
---|
331 | else if (instantdeathchan > 1.0) |
---|
332 | { |
---|
333 | instantdeathchan = 1.0; |
---|
334 | } |
---|
335 | |
---|
336 | minlifespan = get_integer_resource ("minlifespan", "Integer"); |
---|
337 | if (minlifespan < 1) |
---|
338 | { |
---|
339 | minlifespan = 1; |
---|
340 | } |
---|
341 | |
---|
342 | maxlifespan = get_integer_resource ("maxlifespan", "Integer"); |
---|
343 | if (maxlifespan < minlifespan) |
---|
344 | { |
---|
345 | maxlifespan = minlifespan; |
---|
346 | } |
---|
347 | |
---|
348 | minlifespeed = get_float_resource ("minlifespeed", "Float"); |
---|
349 | if (minlifespeed < 0.0) |
---|
350 | { |
---|
351 | minlifespeed = 0.0; |
---|
352 | } |
---|
353 | else if (minlifespeed > 1.0) |
---|
354 | { |
---|
355 | minlifespeed = 1.0; |
---|
356 | } |
---|
357 | |
---|
358 | maxlifespeed = get_float_resource ("maxlifespeed", "Float"); |
---|
359 | if (maxlifespeed < minlifespeed) |
---|
360 | { |
---|
361 | maxlifespeed = minlifespeed; |
---|
362 | } |
---|
363 | else if (maxlifespeed > 1.0) |
---|
364 | { |
---|
365 | maxlifespeed = 1.0; |
---|
366 | } |
---|
367 | |
---|
368 | mindeathspeed = get_float_resource ("mindeathspeed", "Float"); |
---|
369 | if (mindeathspeed < 0.0) |
---|
370 | { |
---|
371 | mindeathspeed = 0.0; |
---|
372 | } |
---|
373 | else if (mindeathspeed > 1.0) |
---|
374 | { |
---|
375 | mindeathspeed = 1.0; |
---|
376 | } |
---|
377 | |
---|
378 | maxdeathspeed = get_float_resource ("maxdeathspeed", "Float"); |
---|
379 | if (maxdeathspeed < mindeathspeed) |
---|
380 | { |
---|
381 | maxdeathspeed = mindeathspeed; |
---|
382 | } |
---|
383 | else if (maxdeathspeed > 1.0) |
---|
384 | { |
---|
385 | maxdeathspeed = 1.0; |
---|
386 | } |
---|
387 | |
---|
388 | minlifespeed *= diaglim; |
---|
389 | maxlifespeed *= diaglim; |
---|
390 | mindeathspeed *= diaglim; |
---|
391 | maxdeathspeed *= diaglim; |
---|
392 | |
---|
393 | cmap = xgwa.colormap; |
---|
394 | |
---|
395 | windowWidth = xgwa.width; |
---|
396 | windowHeight = xgwa.height; |
---|
397 | |
---|
398 | arr_width = windowWidth / cell_size; |
---|
399 | arr_height = windowHeight / cell_size; |
---|
400 | |
---|
401 | alloc_size = sizeof(cell) * arr_width * arr_height; |
---|
402 | oalloc = alloc_size; |
---|
403 | |
---|
404 | if (mem_throttle > 0) |
---|
405 | while (cell_size < windowWidth/10 && |
---|
406 | cell_size < windowHeight/10 && |
---|
407 | alloc_size > mem_throttle) |
---|
408 | { |
---|
409 | cell_size++; |
---|
410 | arr_width = windowWidth / cell_size; |
---|
411 | arr_height = windowHeight / cell_size; |
---|
412 | alloc_size = sizeof(cell) * arr_width * arr_height; |
---|
413 | } |
---|
414 | |
---|
415 | if (osize != cell_size) |
---|
416 | { |
---|
417 | static int warned = 0; |
---|
418 | if (!warned) |
---|
419 | { |
---|
420 | fprintf (stderr, |
---|
421 | "%s: throttling cell size from %d to %d because of %dM limit.\n", |
---|
422 | progname, osize, cell_size, mem_throttle / (1 << 20)); |
---|
423 | fprintf (stderr, "%s: %dx%dx%d = %.1fM, %dx%dx%d = %.1fM.\n", |
---|
424 | progname, |
---|
425 | windowWidth, windowHeight, osize, |
---|
426 | ((float) oalloc) / (1 << 20), |
---|
427 | windowWidth, windowHeight, cell_size, |
---|
428 | ((float) alloc_size) / (1 << 20)); |
---|
429 | warned = 1; |
---|
430 | } |
---|
431 | } |
---|
432 | |
---|
433 | xSize = windowWidth / arr_width; |
---|
434 | ySize = windowHeight / arr_height; |
---|
435 | if (xSize > ySize) |
---|
436 | { |
---|
437 | xSize = ySize; |
---|
438 | } |
---|
439 | else |
---|
440 | { |
---|
441 | ySize = xSize; |
---|
442 | } |
---|
443 | |
---|
444 | xOffset = (windowWidth - (arr_width * xSize)) / 2; |
---|
445 | yOffset = (windowHeight - (arr_height * ySize)) / 2; |
---|
446 | |
---|
447 | if (originalcolors) |
---|
448 | { |
---|
449 | setup_original_colormap (&xgwa); |
---|
450 | } |
---|
451 | else |
---|
452 | { |
---|
453 | setup_random_colormap (&xgwa); |
---|
454 | } |
---|
455 | } |
---|
456 | |
---|
457 | static void drawblock (int x, int y, unsigned char c) |
---|
458 | { |
---|
459 | if (xSize == 1 && ySize == 1) |
---|
460 | XDrawPoint (display, window, coloredGCs[c], x + xOffset, y + yOffset); |
---|
461 | else |
---|
462 | XFillRectangle (display, window, coloredGCs[c], |
---|
463 | x * xSize + xOffset, y * ySize + yOffset, |
---|
464 | xSize, ySize); |
---|
465 | } |
---|
466 | |
---|
467 | static void setup_arr (void) |
---|
468 | { |
---|
469 | int x, y; |
---|
470 | |
---|
471 | if (arr != NULL) |
---|
472 | { |
---|
473 | free (arr); |
---|
474 | } |
---|
475 | |
---|
476 | XFillRectangle (display, window, coloredGCs[0], 0, 0, |
---|
477 | windowWidth, windowHeight); |
---|
478 | |
---|
479 | arr = (cell *) calloc (sizeof(cell), arr_width * arr_height); |
---|
480 | if (!arr) |
---|
481 | { |
---|
482 | fprintf (stderr, "%s: out of memory allocating %dx%d grid\n", |
---|
483 | progname, arr_width, arr_height); |
---|
484 | exit (1); |
---|
485 | } |
---|
486 | |
---|
487 | for (y = 0; y < arr_height; y++) |
---|
488 | { |
---|
489 | int row = y * arr_width; |
---|
490 | for (x = 0; x < arr_width; x++) |
---|
491 | { |
---|
492 | arr[row+x].speed = 0.0; |
---|
493 | arr[row+x].growth = 0.0; |
---|
494 | arr[row+x].col = 0; |
---|
495 | arr[row+x].isnext = 0; |
---|
496 | arr[row+x].next = 0; |
---|
497 | arr[row+x].prev = 0; |
---|
498 | } |
---|
499 | } |
---|
500 | |
---|
501 | if (head == NULL) |
---|
502 | { |
---|
503 | head = (cell *) malloc (sizeof (cell)); |
---|
504 | } |
---|
505 | |
---|
506 | if (tail == NULL) |
---|
507 | { |
---|
508 | tail = (cell *) malloc (sizeof (cell)); |
---|
509 | } |
---|
510 | |
---|
511 | head->next = tail; |
---|
512 | head->prev = head; |
---|
513 | tail->next = tail; |
---|
514 | tail->prev = head; |
---|
515 | |
---|
516 | blastcount = random_life_value (); |
---|
517 | } |
---|
518 | |
---|
519 | static void newcell (cell *c, unsigned char col, FLOAT sp) |
---|
520 | { |
---|
521 | if (! c) return; |
---|
522 | |
---|
523 | if (c->col == col) return; |
---|
524 | |
---|
525 | c->nextcol = col; |
---|
526 | c->nextspeed = sp; |
---|
527 | c->isnext = 1; |
---|
528 | |
---|
529 | if (c->prev == 0) { |
---|
530 | c->next = head->next; |
---|
531 | c->prev = head; |
---|
532 | head->next = c; |
---|
533 | c->next->prev = c; |
---|
534 | } |
---|
535 | } |
---|
536 | |
---|
537 | static void killcell (cell *c) |
---|
538 | { |
---|
539 | c->prev->next = c->next; |
---|
540 | c->next->prev = c->prev; |
---|
541 | c->prev = 0; |
---|
542 | c->speed = 0.0; |
---|
543 | drawblock (cell_x(c), cell_y(c), c->col); |
---|
544 | } |
---|
545 | |
---|
546 | |
---|
547 | static void randblip (int doit) |
---|
548 | { |
---|
549 | int n; |
---|
550 | int b = 0; |
---|
551 | if (!doit |
---|
552 | && (blastcount-- >= 0) |
---|
553 | && (RAND_FLOAT > anychan)) |
---|
554 | { |
---|
555 | return; |
---|
556 | } |
---|
557 | |
---|
558 | if (blastcount < 0) |
---|
559 | { |
---|
560 | b = 1; |
---|
561 | n = 2; |
---|
562 | blastcount = random_life_value (); |
---|
563 | if (RAND_FLOAT < instantdeathchan) |
---|
564 | { |
---|
565 | /* clear everything every so often to keep from getting into a |
---|
566 | * rut */ |
---|
567 | setup_arr (); |
---|
568 | b = 0; |
---|
569 | } |
---|
570 | } |
---|
571 | else if (RAND_FLOAT <= minorchan) |
---|
572 | { |
---|
573 | n = 2; |
---|
574 | } |
---|
575 | else |
---|
576 | { |
---|
577 | n = random () % 3 + 3; |
---|
578 | } |
---|
579 | |
---|
580 | while (n--) |
---|
581 | { |
---|
582 | int x = random () % arr_width; |
---|
583 | int y = random () % arr_height; |
---|
584 | int c; |
---|
585 | FLOAT s; |
---|
586 | if (b) |
---|
587 | { |
---|
588 | c = 0; |
---|
589 | s = RAND_FLOAT * (maxdeathspeed - mindeathspeed) + mindeathspeed; |
---|
590 | } |
---|
591 | else |
---|
592 | { |
---|
593 | c = (random () % (count-1)) + 1; |
---|
594 | s = RAND_FLOAT * (maxlifespeed - minlifespeed) + minlifespeed; |
---|
595 | } |
---|
596 | newcell (&arr[y * arr_width + x], c, s); |
---|
597 | } |
---|
598 | } |
---|
599 | |
---|
600 | static void update (void) |
---|
601 | { |
---|
602 | cell *a; |
---|
603 | |
---|
604 | for (a = head->next; a != tail; a = a->next) |
---|
605 | { |
---|
606 | static XPoint all_coords[] = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1}, |
---|
607 | {-1, 0}, { 1, 0}, {0, -1}, {0, 1}, |
---|
608 | {99, 99}}; |
---|
609 | |
---|
610 | XPoint *coords = 0; |
---|
611 | |
---|
612 | if (a->speed == 0) continue; |
---|
613 | a->growth += a->speed; |
---|
614 | |
---|
615 | if (a->growth >= diaglim) |
---|
616 | { |
---|
617 | coords = all_coords; |
---|
618 | } |
---|
619 | else if (a->growth >= orthlim) |
---|
620 | { |
---|
621 | coords = &all_coords[4]; |
---|
622 | } |
---|
623 | else |
---|
624 | { |
---|
625 | continue; |
---|
626 | } |
---|
627 | |
---|
628 | while (coords->x != 99) |
---|
629 | { |
---|
630 | int x = cell_x(a) + coords->x; |
---|
631 | int y = cell_y(a) + coords->y; |
---|
632 | coords++; |
---|
633 | |
---|
634 | if (x < 0) x = arr_width - 1; |
---|
635 | else if (x >= arr_width) x = 0; |
---|
636 | |
---|
637 | if (y < 0) y = arr_height - 1; |
---|
638 | else if (y >= arr_height) y = 0; |
---|
639 | |
---|
640 | newcell (&arr[y * arr_width + x], a->col, a->speed); |
---|
641 | } |
---|
642 | |
---|
643 | if (a->growth >= diaglim) |
---|
644 | killcell (a); |
---|
645 | } |
---|
646 | |
---|
647 | randblip ((head->next) == tail); |
---|
648 | |
---|
649 | for (a = head->next; a != tail; a = a->next) |
---|
650 | { |
---|
651 | if (a->isnext) |
---|
652 | { |
---|
653 | a->isnext = 0; |
---|
654 | a->speed = a->nextspeed; |
---|
655 | a->growth = 0.0; |
---|
656 | a->col = a->nextcol; |
---|
657 | drawblock (cell_x(a), cell_y(a), a->col + count); |
---|
658 | } |
---|
659 | } |
---|
660 | } |
---|
661 | |
---|
662 | |
---|
663 | char *progclass = "Petri"; |
---|
664 | |
---|
665 | char *defaults [] = { |
---|
666 | ".background: black", |
---|
667 | ".foreground: white", |
---|
668 | "*delay: 10000", |
---|
669 | "*count: 8", |
---|
670 | "*size: 4", |
---|
671 | "*diaglim: 1.414", |
---|
672 | "*anychan: 0.0015", |
---|
673 | "*minorchan: 0.5", |
---|
674 | "*instantdeathchan: 0.2", |
---|
675 | "*minlifespan: 500", |
---|
676 | "*maxlifespan: 1500", |
---|
677 | "*minlifespeed: 0.04", |
---|
678 | "*maxlifespeed: 0.13", |
---|
679 | "*mindeathspeed: 0.42", |
---|
680 | "*maxdeathspeed: 0.46", |
---|
681 | "*originalcolors: false", |
---|
682 | "*memThrottle: 22M", /* don't malloc more than this much. |
---|
683 | Scale the pixels up if necessary. */ |
---|
684 | 0 |
---|
685 | }; |
---|
686 | |
---|
687 | XrmOptionDescRec options [] = { |
---|
688 | { "-delay", ".delay", XrmoptionSepArg, 0 }, |
---|
689 | { "-size", ".size", XrmoptionSepArg, 0 }, |
---|
690 | { "-count", ".count", XrmoptionSepArg, 0 }, |
---|
691 | { "-diaglim", ".diaglim", XrmoptionSepArg, 0 }, |
---|
692 | { "-anychan", ".anychan", XrmoptionSepArg, 0 }, |
---|
693 | { "-minorchan", ".minorchan", XrmoptionSepArg, 0 }, |
---|
694 | { "-instantdeathchan", ".instantdeathchan", XrmoptionSepArg, 0 }, |
---|
695 | { "-minlifespan", ".minlifespan", XrmoptionSepArg, 0 }, |
---|
696 | { "-maxlifespan", ".maxlifespan", XrmoptionSepArg, 0 }, |
---|
697 | { "-minlifespeed", ".minlifespeed", XrmoptionSepArg, 0 }, |
---|
698 | { "-maxlifespeed", ".maxlifespeed", XrmoptionSepArg, 0 }, |
---|
699 | { "-mindeathspeed", ".mindeathspeed", XrmoptionSepArg, 0 }, |
---|
700 | { "-maxdeathspeed", ".maxdeathspeed", XrmoptionSepArg, 0 }, |
---|
701 | { "-originalcolors", ".originalcolors", XrmoptionNoArg, "true" }, |
---|
702 | { "-mem-throttle", ".memThrottle", XrmoptionSepArg, 0 }, |
---|
703 | { 0, 0, 0, 0 } |
---|
704 | }; |
---|
705 | |
---|
706 | void screenhack (Display *dpy, Window win) |
---|
707 | { |
---|
708 | int delay = get_integer_resource ("delay", "Delay"); |
---|
709 | display = dpy; |
---|
710 | window = win; |
---|
711 | setup_display (); |
---|
712 | |
---|
713 | setup_arr (); |
---|
714 | |
---|
715 | randblip (1); |
---|
716 | |
---|
717 | for (;;) |
---|
718 | { |
---|
719 | update (); |
---|
720 | XSync (dpy, False); |
---|
721 | screenhack_handle_events (dpy); |
---|
722 | usleep (delay); |
---|
723 | } |
---|
724 | } |
---|