From http://www.jwz.org/xscreensaver/xscreensaver-5.22.tar.gz
[xscreensaver] / hacks / cloudlife.c
index 368eb9d55ff5b5d0b8c28b6db4b7aa9e4f7aee91..4e848ef56619183dfac07b399e05ff390c49a643 100644 (file)
@@ -10,6 +10,8 @@
  * Cloudlife only draws one pixel of each cell per tick, whether the cell is
  * alive or dead.  So gliders look like little comets.
 
+ * 20 May 2003 -- now includes color cycling and a man page.
+
  * Based on several examples from the hacks directory of: 
  
  * xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski <jwz@jwz.org>
@@ -24,8 +26,6 @@
  */
 
 #include "screenhack.h"
-#include <stdio.h>
-#include <sys/time.h>
 
 #ifndef MAX_WIDTH
 #include <limits.h>
 #define inline                 /* */
 #endif
 
-typedef struct {
+struct field {
     unsigned int height;
     unsigned int width;
     unsigned int max_age;
     unsigned int cell_size;
     unsigned char *cells;
     unsigned char *new_cells;
-} field;
+};
+
+struct state {
+  Display *dpy;
+  Window window;
+
+#ifdef TIME_ME
+  time_t start_time;
+#endif
+
+  unsigned int cycles;
+  unsigned int colorindex;  /* which color in the colormap are we on */
+  unsigned int colortimer;  /* when this reaches 0, cycle to next color */
+
+  int cycle_delay;
+  int cycle_colors;
+  int ncolors;
+  int density;
+
+  GC fgc, bgc;
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  XColor *colors;
+
+  struct field *field;
+
+  XPoint fg_points[MAX_WIDTH];
+  XPoint bg_points[MAX_WIDTH];
+};
+
 
 static void 
 *xrealloc(void *p, size_t size)
@@ -63,57 +92,60 @@ static void
     return ret;
 }
 
-field 
-*init_field(void)
+static struct field *
+init_field(struct state *st)
 {
-    field *f = xrealloc(NULL, sizeof(field));
+    struct field *f = xrealloc(NULL, sizeof(struct field));
     f->height = 0;
     f->width = 0;
-    f->cell_size = get_integer_resource("cellSize", "Integer");
-    f->max_age = get_integer_resource("maxAge", "Integer");
+    f->cell_size = get_integer_resource(st->dpy, "cellSize", "Integer");
+    f->max_age = get_integer_resource(st->dpy, "maxAge", "Integer");
+
+    if (f->max_age > 255) {
+      fprintf (stderr, "%s: max-age must be < 256 (not %d)\n", progname,
+               f->max_age);
+      exit (1);
+    }
+
     f->cells = NULL;
     f->new_cells = NULL;
     return f;
 }
 
-void 
-resize_field(field * f, unsigned int w, unsigned int h)
+static void 
+resize_field(struct field * f, unsigned int w, unsigned int h)
 {
+    int s = w * h * sizeof(unsigned char);
     f->width = w;
     f->height = h;
 
-    f->cells = xrealloc(f->cells,
-                       w * sizeof(unsigned char) * 
-                        h * sizeof(unsigned char));
-    f->new_cells =
-       xrealloc(f->new_cells,
-                w * sizeof(unsigned char) * h * sizeof(unsigned char));
+    f->cells = xrealloc(f->cells, s);
+    f->new_cells = xrealloc(f->new_cells, s);
+    memset(f->cells, 0, s);
+    memset(f->new_cells, 0, s);
 }
 
-inline unsigned char 
-*cell_at(field * f, unsigned int x, unsigned int y)
+static inline unsigned char 
+*cell_at(struct field * f, unsigned int x, unsigned int y)
 {
     return (f->cells + x * sizeof(unsigned char) + 
                        y * f->width * sizeof(unsigned char));
 }
 
-inline unsigned char 
-*new_cell_at(field * f, unsigned int x, unsigned int y)
+static inline unsigned char 
+*new_cell_at(struct field * f, unsigned int x, unsigned int y)
 {
     return (f->new_cells + x * sizeof(unsigned char) + 
                            y * f->width * sizeof(unsigned char));
 }
 
 static void
-draw_field(Display * dpy,
-          Window window, Colormap cmap, GC fgc, GC bgc, field * f)
+draw_field(struct state *st, struct field * f)
 {
     unsigned int x, y;
     unsigned int rx, ry = 0;   /* random amount to offset the dot */
     unsigned int size = 1 << f->cell_size;
     unsigned int mask = size - 1;
-    static XPoint fg_points[MAX_WIDTH];
-    static XPoint bg_points[MAX_WIDTH];
     unsigned int fg_count, bg_count;
 
     /* columns 0 and width-1 are off screen and not drawn. */
@@ -129,23 +161,23 @@ draw_field(Display * dpy,
            ry &= mask;
 
            if (*cell_at(f, x, y)) {
-               fg_points[fg_count].x = (short) x *size - rx - 1;
-               fg_points[fg_count].y = (short) y *size - ry - 1;
+               st->fg_points[fg_count].x = (short) x *size - rx - 1;
+               st->fg_points[fg_count].y = (short) y *size - ry - 1;
                fg_count++;
            } else {
-               bg_points[bg_count].x = (short) x *size - rx - 1;
-               bg_points[bg_count].y = (short) y *size - ry - 1;
+               st->bg_points[bg_count].x = (short) x *size - rx - 1;
+               st->bg_points[bg_count].y = (short) y *size - ry - 1;
                bg_count++;
            }
        }
-       XDrawPoints(dpy, window, fgc, fg_points, fg_count,
+       XDrawPoints(st->dpy, st->window, st->fgc, st->fg_points, fg_count,
                    CoordModeOrigin);
-       XDrawPoints(dpy, window, bgc, bg_points, bg_count,
+       XDrawPoints(st->dpy, st->window, st->bgc, st->bg_points, bg_count,
                    CoordModeOrigin);
     }
 }
 
-inline unsigned int 
+static inline unsigned int 
 cell_value(unsigned char c, unsigned int age)
 {
     if (!c) {
@@ -157,8 +189,8 @@ cell_value(unsigned char c, unsigned int age)
     }
 }
 
-inline unsigned int 
-is_alive(field * f, unsigned int x, unsigned int y)
+static inline unsigned int 
+is_alive(struct field * f, unsigned int x, unsigned int y)
 {
     unsigned int count;
     unsigned int i, j;
@@ -190,8 +222,8 @@ is_alive(field * f, unsigned int x, unsigned int y)
     }
 }
 
-unsigned int 
-do_tick(field * f)
+static unsigned int 
+do_tick(struct field * f)
 {
     unsigned int x, y;
     unsigned int count = 0;
@@ -200,13 +232,13 @@ do_tick(field * f)
            count += *new_cell_at(f, x, y) = is_alive(f, x, y);
        }
     }
-    memcpy(f->cells, f->new_cells, f->width * sizeof(unsigned char) *
-          f->height * sizeof(unsigned char));
+    memcpy(f->cells, f->new_cells, f->width * f->height *
+           sizeof(unsigned char));
     return count;
 }
 
 
-unsigned int 
+static unsigned int 
 random_cell(unsigned int p)
 {
     int r = random() & 0xff;
@@ -218,8 +250,8 @@ random_cell(unsigned int p)
     }
 }
 
-void 
-populate_field(field * f, unsigned int p)
+static void 
+populate_field(struct field * f, unsigned int p)
 {
     unsigned int x, y;
 
@@ -230,8 +262,8 @@ populate_field(field * f, unsigned int p)
     }
 }
 
-void 
-populate_edges(field * f, unsigned int p)
+static void 
+populate_edges(struct field * f, unsigned int p)
 {
     unsigned int i;
 
@@ -246,93 +278,143 @@ populate_edges(field * f, unsigned int p)
     }
 }
 
-\f
-char *progclass = "Cloudlife";
-
-char *defaults[] = {
-    ".background:      black",
-    ".foreground:      blue",
-    "*cycleDelay:      25000",
-    "*maxAge:          64",
-    "*initialDensity:  160",
-    "*cellSize:                3",
-    0
-};
-
-XrmOptionDescRec options[] = {
-    {"-background", ".background", XrmoptionSepArg, 0},
-    {"-foreground", ".foreground", XrmoptionSepArg, 0},
-    {"-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0},
-    {"-cell-size", ".cellSize", XrmoptionSepArg, 0},
-    {"-initial-density", ".initialDensity", XrmoptionSepArg, 0},
-    {"-max-age", ".maxAge", XrmoptionSepArg, 0},
-    {0, 0, 0, 0}
-};
-
-void screenhack(Display * dpy, Window window)
+static void *
+cloudlife_init (Display *dpy, Window window)
 {
-    field *f = init_field();
+  struct state *st = (struct state *) calloc (1, sizeof(*st));
+    Bool tmp = True;
+
+    st->dpy = dpy;
+    st->window = window;
+    st->field = init_field(st);
 
 #ifdef TIME_ME
-    time_t start_time = time(NULL);
+    st->start_time = time(NULL);
 #endif
 
-    unsigned int cycles = 0;
-
-    GC fgc, bgc;
-    XGCValues gcv;
-    XWindowAttributes xgwa;
+    st->cycle_delay = get_integer_resource(st->dpy, "cycleDelay", "Integer");
+    st->cycle_colors = get_integer_resource(st->dpy, "cycleColors", "Integer");
+    st->ncolors = get_integer_resource(st->dpy, "ncolors", "Integer");
+    st->density = (get_integer_resource(st->dpy, "initialDensity", "Integer") 
+                  % 100 * 256)/100;
 
-    unsigned int cycle_delay = (unsigned int)
-       get_integer_resource("cycleDelay", "Integer");
-    unsigned int density = (unsigned int)
-       get_integer_resource("initialDensity", "Integer") & 0xff;
-    XGetWindowAttributes(dpy, window, &xgwa);
+    XGetWindowAttributes(st->dpy, st->window, &st->xgwa);
 
-    gcv.foreground = get_pixel_resource("foreground", "Foreground",
-                                       dpy, xgwa.colormap);
-    fgc = XCreateGC(dpy, window, GCForeground, &gcv);
+    if (st->cycle_colors) {
+        st->colors = (XColor *) xrealloc(st->colors, sizeof(XColor) * (st->ncolors+1));
+        make_smooth_colormap (st->xgwa.screen, st->xgwa.visual,
+                              st->xgwa.colormap, st->colors, &st->ncolors,
+                              True, &tmp, True);
+    }
 
-    gcv.foreground = get_pixel_resource("background", "Background",
-                                       dpy, xgwa.colormap);
-    bgc = XCreateGC(dpy, window, GCForeground, &gcv);
+    st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap,
+                                        "foreground", "Foreground");
+    st->fgc = XCreateGC(st->dpy, st->window, GCForeground, &st->gcv);
 
-    while (1) {
-       XGetWindowAttributes(dpy, window, &xgwa);
-       if (f->height != xgwa.height / (1 << f->cell_size) + 2 ||
-           f->width != xgwa.width / (1 << f->cell_size) + 2) {
+    st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap,
+                                        "background", "Background");
+    st->bgc = XCreateGC(st->dpy, st->window, GCForeground, &st->gcv);
 
-           resize_field(f, xgwa.width / (1 << f->cell_size) + 2,
-                        xgwa.height / (1 << f->cell_size) + 2);
-           populate_field(f, density);
-       }
+    return st;
+}
 
-       screenhack_handle_events(dpy);
+static unsigned long
+cloudlife_draw (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+
+  if (st->cycle_colors) {
+    if (st->colortimer == 0) {
+      st->colortimer = st->cycle_colors;
+      if( st->colorindex == 0 ) 
+        st->colorindex = st->ncolors;
+      st->colorindex--;
+      XSetForeground(st->dpy, st->fgc, st->colors[st->colorindex].pixel);
+    }
+    st->colortimer--;
+  } 
 
-       draw_field(dpy, window, xgwa.colormap, fgc, bgc, f);
+  XGetWindowAttributes(st->dpy, st->window, &st->xgwa);
+  if (st->field->height != st->xgwa.height / (1 << st->field->cell_size) + 2 ||
+      st->field->width != st->xgwa.width / (1 << st->field->cell_size) + 2) {
 
-       if (do_tick(f) < (f->height + f->width) / 4) {
-           populate_field(f, density);
-       }
+    resize_field(st->field, st->xgwa.width / (1 << st->field->cell_size) + 2,
+                 st->xgwa.height / (1 << st->field->cell_size) + 2);
+    populate_field(st->field, st->density);
+  }
 
-       if (cycles % (f->max_age /2) == 0) {
-           populate_edges(f, density);
-           do_tick(f);
-           populate_edges(f, 0);
-       }
+  draw_field(st, st->field);
 
-       XSync(dpy, False);
+  if (do_tick(st->field) < (st->field->height + st->field->width) / 4) {
+    populate_field(st->field, st->density);
+  }
 
-       cycles++;
+  if (st->cycles % (st->field->max_age /2) == 0) {
+    populate_edges(st->field, st->density);
+    do_tick(st->field);
+    populate_edges(st->field, 0);
+  }
 
-       if (cycle_delay)
-           usleep(cycle_delay);
+  st->cycles++;
 
 #ifdef TIME_ME
-       if (cycles % f->max_age == 0) {
-           printf("%g s.\n",
-                  ((time(NULL) - start_time) * 1000.0) / cycles);
-       }
+  if (st->cycles % st->field->max_age == 0) {
+    printf("%g s.\n",
+           ((time(NULL) - st->start_time) * 1000.0) / st->cycles);
+  }
 #endif
-    }
+
+  return (st->cycle_delay);
 }
+
+
+static void
+cloudlife_reshape (Display *dpy, Window window, void *closure, 
+                 unsigned int w, unsigned int h)
+{
+}
+
+static Bool
+cloudlife_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+  return False;
+}
+
+static void
+cloudlife_free (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  free (st);
+}
+
+
+static const char *cloudlife_defaults[] = {
+    ".background:      black",
+    ".foreground:      blue",
+    "*fpsSolid:        true",
+    "*cycleDelay:      25000",
+    "*cycleColors:      2",
+    "*ncolors:          64",
+    "*maxAge:          64",
+    "*initialDensity:  30",
+    "*cellSize:                3",
+#ifdef USE_IPHONE
+    "*ignoreRotation:   True",
+#endif
+    0
+};
+
+static XrmOptionDescRec cloudlife_options[] = {
+    {"-background", ".background", XrmoptionSepArg, 0},
+    {"-foreground", ".foreground", XrmoptionSepArg, 0},
+    {"-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0},
+    {"-cycle-colors", ".cycleColors", XrmoptionSepArg, 0},
+    {"-ncolors", ".ncolors", XrmoptionSepArg, 0},
+    {"-cell-size", ".cellSize", XrmoptionSepArg, 0},
+    {"-initial-density", ".initialDensity", XrmoptionSepArg, 0},
+    {"-max-age", ".maxAge", XrmoptionSepArg, 0},
+    {0, 0, 0, 0}
+};
+
+
+XSCREENSAVER_MODULE ("CloudLife", cloudlife)