X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fcritical.c;h=1e8f3a1ab19731ca7283f51a35402ef7647581a7;hp=3f8f2763ab85dc812ca6fc16dd49fcc068fcd8e8;hb=0316d74da7982288abddd34e7a62698eb7f79965;hpb=06e9a7886a77cad92f9ddbc169d6d199a4d8b76d diff --git a/hacks/critical.c b/hacks/critical.c index 3f8f2763..1e8f3a1a 100644 --- a/hacks/critical.c +++ b/hacks/critical.c @@ -1,5 +1,5 @@ /* critical -- Self-organizing-criticality display hack for XScreenSaver - * Copyright (C) 1998, 1999 Martin Pool + * Copyright (C) 1998, 1999, 2000 Martin Pool * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without @@ -13,13 +13,18 @@ * * Revision history: * 13 Nov 1998: Initial version, Martin Pool - */ + * 08 Feb 2000: Change to keeping and erasing a trail, + * + * It would be nice to draw curvy shapes rather than just straight + * lines, but X11 doesn't have spline primitives (?) so we'd have to + * do all the work ourselves */ #include "screenhack.h" #include "erase.h" #include #include +#include char *progclass = "Critical"; @@ -29,11 +34,14 @@ typedef struct { unsigned short *cells; } CriticalModel; +typedef struct { + int trail; /* length of trail */ + int cell_size; +} CriticalSettings; + CriticalModel * model_allocate (int w, int h); void model_initialize (CriticalModel *model); -static void model_step (CriticalModel *model, int *top_x, int *top_y); - /* Options this module understands. */ XrmOptionDescRec options[] = { @@ -43,6 +51,7 @@ XrmOptionDescRec options[] = { { "-restart", ".restart", XrmoptionSepArg, 0 }, { "-cellsize", ".cellsize", XrmoptionSepArg, 0 }, { "-batchcount", ".batchcount", XrmoptionSepArg, 0 }, + { "-trail", ".trail", XrmoptionSepArg, 0 }, { 0, 0, 0, 0 } /* end */ }; @@ -54,12 +63,24 @@ char *defaults[] = { "*delay: 10000", "*ncolors: 64", "*restart: 8", - "*cellsize: 9", "*batchcount: 1500", + "*trail: 50", 0 /* end */ }; +int +clip (int low, int val, int high) +{ + if (val < low) + return low; + else if (val > high) + return high; + else + return val; +} + + /* Allocate an return a new simulation model datastructure. */ @@ -122,11 +143,12 @@ model_initialize (CriticalModel *model) Neighbours that fall off the edge of the model are simply ignored. */ static void -model_step (CriticalModel *model, int *top_x, int *top_y) +model_step (CriticalModel *model, XPoint *ptop) { int x, y, i; int dx, dy; - unsigned short top_value; + unsigned short top_value = 0; + int top_x = 0, top_y = 0; /* Find the top cell */ top_value = 0; @@ -137,8 +159,8 @@ model_step (CriticalModel *model, int *top_x, int *top_y) if (model->cells[i] >= top_value) { top_value = model->cells[i]; - *top_x = x; - *top_y = y; + top_x = x; + top_y = y; } i++; } @@ -146,19 +168,22 @@ model_step (CriticalModel *model, int *top_x, int *top_y) /* Replace it and its neighbours with new random values */ for (dy = -1; dy <= 1; dy++) { - int y = *top_y + dy; + int y = top_y + dy; if (y < 0 || y >= model->height) continue; for (dx = -1; dx <= 1; dx++) { - int x = *top_x + dx; + int x = top_x + dx; if (x < 0 || x >= model->width) continue; model->cells[y * model->width + x] = (unsigned short) random(); } } + + ptop->x = top_x; + ptop->y = top_y; } @@ -212,25 +237,47 @@ setup_colormap (Display *dpy, XWindowAttributes *wattr, } +/* Draw one step of the hack. Positions are cell coordinates. */ +static void +draw_step (CriticalSettings *settings, + Display *dpy, Window window, GC gc, + int pos, XPoint *history) +{ + int cell_size = settings->cell_size; + int half = cell_size/2; + int old_pos = (pos + settings->trail - 1) % settings->trail; + + pos = pos % settings->trail; + + XDrawLine (dpy, window, gc, + history[pos].x * cell_size + half, + history[pos].y * cell_size + half, + history[old_pos].x * cell_size + half, + history[old_pos].y * cell_size + half); +} + + /* Display a self-organizing criticality screen hack. The program runs indefinately on the root window. */ void screenhack (Display *dpy, Window window) { - GC fgc, bgc; - XGCValues gcv; - XWindowAttributes wattr; int n_colors; XColor *colors; int model_w, model_h; CriticalModel *model; int lines_per_color = 10; int i_color = 0; - int x1, y1, x2, y2; long delay_usecs; - int cell_size; int batchcount; + XPoint *history; /* in cell coords */ + int pos = 0; + int wrapped = 0; + GC fgc, bgc; + XGCValues gcv; + XWindowAttributes wattr; + CriticalSettings settings; /* Number of screens that should be drawn before reinitializing the model, and count of the number of screens done so far. */ @@ -239,20 +286,30 @@ screenhack (Display *dpy, Window window) /* Find window attributes */ XGetWindowAttributes (dpy, window, &wattr); - /* Construct the initial model state. */ - cell_size = get_integer_resource ("cellsize", "Integer"); - if (cell_size < 1) - cell_size = 1; - if (cell_size >= 100) - cell_size = 99; - batchcount = get_integer_resource ("batchcount", "Integer"); if (batchcount < 5) batchcount = 5; + + /* For the moment the model size is just fixed -- making it vary + with the screen size just makes the hack boring on large + screens. */ + model_w = 80; + settings.cell_size = wattr.width / model_w; + model_h = wattr.height / settings.cell_size; + + /* Construct the initial model state. */ + + settings.trail = clip(2, get_integer_resource ("trail", "Integer"), 1000); - model_w = wattr.width / cell_size; - model_h = wattr.height / cell_size; - + history = malloc (sizeof history[0] * settings.trail); + if (!history) + { + fprintf (stderr, "critical: " + "couldn't allocate trail history of %d cells\n", + settings.trail); + return; + } + model = model_allocate (model_w, model_h); if (!model) { @@ -267,9 +324,6 @@ screenhack (Display *dpy, Window window) fgc = XCreateGC (dpy, window, 0, &gcv); - x2 = random() % model_w; - y2 = random() % model_h; - delay_usecs = get_integer_resource ("delay", "Integer"); n_restart = get_integer_resource ("restart", "Integer"); @@ -280,10 +334,15 @@ screenhack (Display *dpy, Window window) while (1) { int i_batch; - if (!i_restart) + if (i_restart == 0) { + /* Time to start a new simulation, this one has probably got + to be a bit boring. */ setup_colormap (dpy, &wattr, &colors, &n_colors); + erase_full_window (dpy, window); model_initialize (model); + pos = 1; + wrapped = 0; } for (i_batch = batchcount; i_batch; i_batch--) @@ -296,27 +355,33 @@ screenhack (Display *dpy, Window window) XChangeGC (dpy, fgc, GCForeground, &gcv); } - /* draw a line */ - x1 = x2; - y1 = y2; + assert(pos >= 0 && pos < settings.trail); + model_step (model, &history[pos]); - model_step (model, &x2, &y2); + draw_step (&settings, dpy, window, fgc, pos, history); - XDrawLine (dpy, window, fgc, - x1 * cell_size + cell_size/2, - y1 * cell_size + cell_size/2, - x2 * cell_size + cell_size/2, - y2 * cell_size + cell_size/2); + /* we use the history as a ring buffer, but don't start erasing until + we've wrapped around once. */ + if (++pos >= settings.trail) + { + pos -= settings.trail; + wrapped = 1; + } - XSync (dpy, False); - screenhack_handle_events (dpy); + if (wrapped) + { + draw_step (&settings, dpy, window, bgc, pos+1, history); + } - if (delay_usecs) - usleep (delay_usecs); - } + XSync (dpy, False); + screenhack_handle_events (dpy); + + if (delay_usecs) + usleep (delay_usecs); + } + i_restart = (i_restart + 1) % n_restart; - erase_full_window (dpy, window); } }