2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: life.c /main/3 1995/11/02 16:07:44 rswiston $ */
25 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
26 * (c) Copyright 1993, 1994 International Business Machines Corp. *
27 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
28 * (c) Copyright 1993, 1994 Novell, Inc. *
31 * life.c - Conway's game of Life for dtscreen, the X Window System lockscreen.
33 * Copyright (c) 1991 by Patrick J. Naughton.
35 * See dtscreen.c for copying information.
38 * 24-May-91: Added wraparound code from johnson@bugs.comm.mot.com.
39 * Made old cells stay blue.
40 * Made batchcount control the number of generations till restart.
41 * 29-Jul-90: support for multiple screens.
42 * 07-Feb-90: remove bogus semi-colon after #include line.
43 * 15-Dec-89: Fix for proper skipping of {White,Black}Pixel() in colors.
44 * 08-Oct-89: Moved seconds() to an extern.
45 * 20-Sep-89: Written (life algorithm courtesy of Jim Graham, flar@sun.com).
49 #include "lifeicon.bit"
52 static XImage logo = {
53 0, 0, /* width, height */
54 0, XYBitmap, 0, /* xoffset, format, data */
55 LSBFirst, 8, /* byte-order, bitmap-unit */
56 LSBFirst, 8, 1 /* bitmap-bit-order, bitmap-pad, depth */
58 #define min(a, b) ((a)<(b)?(a):(b))
75 unsigned char buffer[(MAXROWS + 2) * (MAXCOLS + 2) + 2];
76 unsigned char tempbuf[MAXCOLS * 2];
77 unsigned char lastbuf[MAXCOLS];
78 unsigned char agebuf[(MAXROWS + 2) * (MAXCOLS + 2)];
81 static int icon_width, icon_height;
83 /* Buffer stores the data for each cell. Each cell is stored as
84 * 8 bits representing the presence of a critter in each of it's
85 * surrounding 8 cells. There is an empty row and column around
86 * the whole array to allow stores without bounds checking as well
87 * as an extra row at the end for the fetches into tempbuf.
89 * Tempbuf stores the data for the next two rows so that we know
90 * the state of those critter before he was modified by the fate
91 * of the critters that have already been processed.
93 * Agebuf stores the age of each critter.
105 /* Fates is a lookup table for the fate of a critter. The 256
106 * entries represent the 256 possible combinations of the 8
107 * neighbor cells. Each entry is one of BIRTH (create a cell
108 * or leave one alive), SAME (leave the cell alive or dead),
109 * or DEATH (kill anything in the cell).
114 static unsigned char fates[256];
115 static int initialized = 0;
117 const int patterns[][128] = {
119 -3, -3, -2, -3, -1, -3,
120 -3, -2, -2, -2, -1, -2,
121 -3, -1, -2, -1, -1, -1,
128 1, 1, 2, 1, 3, 1, 4, 1, 5, 1,
146 -7, -3, -6, -3, -2, -3, -1, -3, 0, -3, 1, -3, 5, -3, 6, -3,
147 -7, -2, -5, -2, -3, -2, 2, -2, 4, -2, 6, -2,
148 -5, -1, -3, -1, -2, -1, 2, -1, 4, -1,
149 -7, 0, -5, 0, -3, 0, 2, 0, 4, 0, 6, 0,
150 -7, 1, -6, 1, -2, 1, -1, 1, 0, 1, 1, 1, 5, 1, 6, 1,
156 -6, -6, -5, -6, 6, -6, 7, -6,
157 -6, -5, -5, -5, 6, -5, 7, -5,
159 -7, 6, -5, 6, 6, 6, 8, 6,
160 -7, 7, -5, 7, 6, 7, 8, 7,
161 -7, 8, -6, 8, 7, 8, 8, 8,
168 -7, -5, -3, -5, -2, -5,
186 -8, -7, -7, -7, -5, -7,
187 -8, -6, -7, -6, -4, -6, -1, -6,
197 -4, -5, -3, -5, -2, -5, -1, -5,
198 -5, -4, -3, -4, 0, -4, 2, -4, 3, -4,
199 -5, -3, -1, -3, 0, -3, 2, -3, 3, -3,
200 -8, -2, -7, -2, -5, -2, -2, -2, 0, -2,
201 -8, -1, -7, -1, -5, -1, 0, -1,
202 -4, 0, -3, 0, -2, 0, -1, 0,
208 -1, -1, 0, -1, 1, -1,
214 -3, -1, -2, -1, -1, -1, 1, -1, 2, -1, 3, -1,
215 -3, 0, -2, 0, 1, 0, 2, 0,
216 -3, 1, -2, 1, -1, 1, 1, 1, 2, 1, 3, 1,
220 -3, -1, -2, -1, -1, -1, 1, -1, 2, -1, 3, -1,
221 -3, 0, -2, 0, 2, 0, 3, 0,
222 -3, 1, -2, 1, -1, 1, 1, 1, 2, 1, 3, 1,
226 -15, 0, -14, 0, -13, 0, -12, 0, -11, 0,
227 -10, 0, -9, 0, -8, 0, -7, 0, -6, 0,
228 -5, 0, -4, 0, -3, 0, -2, 0, -1, 0,
229 4, 0, 3, 0, 2, 0, 1, 0, 0, 0,
230 9, 0, 8, 0, 7, 0, 6, 0, 5, 0,
231 14, 0, 13, 0, 12, 0, 11, 0, 10, 0,
235 -7, -2, -6, -2, -5, -2, -4, -2, -3, -2,
236 -2, -2, -1, -2, 0, -2, 1, -2, 2, -2,
237 -5, -1, -4, -1, -3, -1, -2, -1, -1, -1,
238 0, -1, 1, -1, 2, -1, 3, -1, 4, -1,
239 -3, 0, -2, 0, -1, 0, 0, 0, 1, 0,
240 2, 0, 3, 0, 4, 0, 5, 0, 6, 0,
241 -10, 1, -9, 1, -8, 1, -7, 1, -6, 1,
242 -5, 1, -4, 1, -3, 1, -2, 1, -1, 1,
243 -10, 2, -9, 2, -8, 2, -7, 2, -6, 2,
244 -5, 2, -4, 2, -3, 2, -2, 2, -1, 2,
266 -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 4, 0, 3, 0, 2, 0, 1, 0, 0, 0,
307 -4, -4, -3, -4, -2, -4, -1, -4, 0, -4, 1, -4, 2, -4, 3, -4, 4, -4,
308 -4, -3, 0, -3, 4, -3,
309 -4, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, 4, -2,
310 -4, -1, -2, -1, 2, -1, 4, -1,
311 -4, 0, -2, 0, -1, 0, 0, 0, 1, 0, 2, 0, 4, 0,
312 -4, 1, -2, 1, 2, 1, 4, 1,
313 -4, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2, 4, 2,
315 -4, 4, -3, 4, -2, 4, -1, 4, 0, 4, 1, 4, 2, 4, 3, 4, 4, 4,
320 #define NPATS (sizeof patterns / sizeof patterns[0])
324 drawcell(perwindow *pwin, int row, int col)
328 lp = (lifestruct *)pwin->data;
329 XSetForeground(dsp, pwin->gc, WhitePixelOfScreen(pwin->perscreen->screen));
330 if (!mono && pwin->perscreen->npixels > 2) {
331 unsigned char *loc = lp->buffer + ((row + 1) * (lp->ncols + 2)) + col + 1;
332 unsigned char *ageptr = lp->agebuf + (loc - lp->buffer);
333 unsigned char age = *ageptr;
335 /* if we aren't up to blue yet, then keep aging the cell. */
336 if (age < (unsigned char) (pwin->perscreen->npixels * 0.7))
339 XSetForeground(dsp, pwin->gc, pwin->perscreen->pixels[age]);
343 XFillRectangle(dsp, pwin->w, pwin->gc,
344 lp->xb + lp->xs * col, lp->yb + lp->ys * row, lp->xs, lp->ys);
346 XPutImage(dsp, pwin->w, pwin->gc, &logo,
347 0, 0, lp->xb + lp->xs * col, lp->yb + lp->ys * row,
348 icon_width, icon_height);
353 erasecell(perwindow *pwin, int row, int col)
355 lifestruct *lp = (lifestruct *)pwin->data;
356 XSetForeground(dsp, pwin->gc, BlackPixelOfScreen(pwin->perscreen->screen));
357 XFillRectangle(dsp, pwin->w, pwin->gc,
358 lp->xb + lp->xs * col, lp->yb + lp->ys * row, lp->xs, lp->ys);
363 spawn(perwindow *pwin, unsigned char *loc)
365 lifestruct *lp = (lifestruct *)pwin->data;
366 unsigned char *ulloc, *ucloc, *urloc, *clloc, *crloc, *llloc, *lcloc, *lrloc,
368 int off, row, col, lastrow;
370 lastrow = (lp->nrows) * (lp->ncols + 2);
371 off = loc - lp->buffer;
372 col = off % (lp->ncols + 2);
373 row = (off - col) / (lp->ncols + 2);
374 ulloc = loc - lp->ncols - 3;
375 ucloc = loc - lp->ncols - 2;
376 urloc = loc - lp->ncols - 1;
380 llloc = loc + lp->ncols + 1;
381 lcloc = loc + lp->ncols + 2;
382 lrloc = loc + lp->ncols + 3;
388 if (row == lp->nrows) {
398 if (col == lp->ncols) {
413 *(lp->agebuf + (loc - lp->buffer)) = 0;
418 life_kill(perwindow *pwin, unsigned char *loc)
420 lifestruct *lp = (lifestruct *)pwin->data;
422 unsigned char *ulloc, *ucloc, *urloc, *clloc, *crloc, *llloc, *lcloc,
424 int off, row, col, lastrow;
426 lastrow = (lp->nrows) * (lp->ncols + 2);
427 off = loc - lp->buffer;
428 row = off / (lp->ncols + 2);
429 col = off % (lp->ncols + 2);
430 row = (off - col) / (lp->ncols + 2);
431 ulloc = loc - lp->ncols - 3;
432 ucloc = loc - lp->ncols - 2;
433 urloc = loc - lp->ncols - 1;
437 llloc = loc + lp->ncols + 1;
438 lcloc = loc + lp->ncols + 2;
439 lrloc = loc + lp->ncols + 3;
445 if (row == lp->nrows) {
455 if (col == lp->ncols) {
473 setcell(perwindow *pwin, int row, int col)
475 lifestruct *lp = (lifestruct *)pwin->data;
478 loc = lp->buffer + ((row + 1) * (lp->ncols + 2)) + col + 1;
480 drawcell(pwin, row, col);
487 int i, bits, neighbors;
489 for (i = 0; i < 256; i++) {
491 for (bits = i; bits; bits &= (bits - 1))
495 else if (neighbors == 2)
504 initlife(perwindow *pwin)
508 XWindowAttributes xgwa;
511 if (pwin->data) free(pwin->data);
512 pwin->data = (void *)malloc(sizeof(lifestruct));
513 memset(pwin->data, '\0', sizeof(lifestruct));
514 lp = (lifestruct *)pwin->data;
516 lp->shooterTime = seconds();
517 icon_width = lifeicon_width;
518 icon_height = lifeicon_height;
523 logo.data = (char *) lifeicon_bits;
524 logo.width = icon_width;
525 logo.height = icon_height;
526 logo.bytes_per_line = (icon_width + 7) / 8;
528 XGetWindowAttributes(dsp, pwin->w, &xgwa);
529 lp->width = xgwa.width;
530 lp->height = xgwa.height;
531 lp->pixelmode = (lp->width < 4 * icon_width);
536 lp->ncols = min(lp->width / icon_width, MAXCOLS);
537 lp->nrows = min(lp->height / icon_height, MAXROWS);
539 /* For the dtstyle preview screen, the rows and columns can
540 * be less than 32 regardless of the pixelmode calculation.
541 * This can cause the row/column calculations below to go
542 * negative, which causes very bad things to happen. Until we
543 * get an official fix, this will keep life from core dumping.
545 if ((lp->ncols < 32) || (lp->nrows < 32)) {
550 lp->xs = lp->width / lp->ncols;
551 lp->ys = lp->height / lp->nrows;
552 lp->xb = (lp->width - lp->xs * lp->ncols) / 2;
553 lp->yb = (lp->height - lp->ys * lp->nrows) / 2;
555 XSetForeground(dsp, pwin->gc, BlackPixelOfScreen(pwin->perscreen->screen));
556 XFillRectangle(dsp, pwin->w, pwin->gc, 0, 0, lp->width, lp->height);
558 memset(lp->buffer, '\0', sizeof(lp->buffer));
559 patptr = (int *)&patterns[random() % NPATS][0];
560 while ((col = *patptr++) != 99) {
562 col += lp->ncols / 2;
563 row += lp->nrows / 2;
564 if ((row >= 0) && (row < lp->nrows) && (col >= 0) && (col < lp->ncols))
565 setcell(pwin, row, col);
571 drawlife(perwindow *pwin)
573 unsigned char *loc, *temploc, *lastloc;
576 lifestruct *lp = (lifestruct *)pwin->data;
578 loc = lp->buffer + lp->ncols + 2 + 1;
579 temploc = lp->tempbuf;
580 /* copy the first 2 rows to the tempbuf */
581 memcpy(temploc, loc, lp->ncols);
582 memcpy(temploc + lp->ncols, loc + lp->ncols + 2, lp->ncols);
584 lastloc = lp->lastbuf;
585 /* copy the last row to another buffer for wraparound */
586 memcpy(lastloc, loc + ((lp->nrows - 1) * (lp->ncols + 2)), lp->ncols);
588 for (row = 0; row < lp->nrows; ++row) {
589 for (col = 0; col < lp->ncols; ++col) {
590 fate = fates[*temploc];
591 *temploc = (row == (lp->nrows - 3)) ?
593 *(loc + (lp->ncols + 2) * 2);
596 if (!(*(loc + 1) & RT)) {
601 if (*(loc + 1) & RT) {
602 drawcell(pwin, row, col);
606 if (*(loc + 1) & RT) {
607 life_kill(pwin, loc);
608 erasecell(pwin, row, col);
616 if (temploc >= lp->tempbuf + lp->ncols * 2)
617 temploc = lp->tempbuf;
620 if (++lp->generation > batchcount)
624 * generate a randomized shooter aimed roughly toward the center of the
625 * screen after timeout.
628 if (seconds() - lp->shooterTime > TIMEOUT) {
629 int hsp = random() % (lp->ncols - 5) + 3;
630 int vsp = random() % (lp->nrows - 5) + 3;
633 if (vsp > lp->nrows / 2)
635 if (hsp > lp->ncols / 2)
637 setcell(pwin, vsp + 0 * voff, hsp + 2 * hoff);
638 setcell(pwin, vsp + 1 * voff, hsp + 2 * hoff);
639 setcell(pwin, vsp + 2 * voff, hsp + 2 * hoff);
640 setcell(pwin, vsp + 2 * voff, hsp + 1 * hoff);
641 setcell(pwin, vsp + 1 * voff, hsp + 0 * hoff);
642 lp->shooterTime = seconds();