/* -*- Mode: C; tab-width: 4 -*- */ /* coral --- a coral reef */ #if !defined( lint ) && !defined( SABER ) static const char sccsid[] = "@(#)coral.c 5.00 2000/11/01 xlockmore"; #endif /* * Copyright (c) 1997 by "Frederick G.M. Roeber" * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * * Revision History: * 01-Nov-2000: Allocation checks * 29-Oct-1997: xlock version (David Bagley ) * 15-Jul-1997: xscreensaver version Frederick G.M. Roeber * */ /*- * original copyright * Copyright (c) 1997 by "Frederick G.M. Roeber" * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. */ #ifdef STANDALONE #define MODE_coral #define PROGCLASS "Coral" #define HACK_INIT init_coral #define HACK_DRAW draw_coral #define coral_opts xlockmore_opts #define DEFAULTS "*delay: 60000 \n" \ "*batchcount: -3 \n" \ "*size: 35 \n" \ "*ncolors: 200 \n" #include "xlockmore.h" /* in xscreensaver distribution */ #else /* STANDALONE */ #include "xlock.h" /* in xlockmore distribution */ #endif /* STANDALONE */ #ifdef MODE_coral ModeSpecOpt coral_opts = {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; #ifdef USE_MODULES ModStruct coral_description = {"coral", "init_coral", "draw_coral", "release_coral", "init_coral", "init_coral", (char *) NULL, &coral_opts, 60000, -3, 1, 35, 64, 0.6, "", "Shows a coral reef", 0, NULL}; #endif #define MINSIZE 1 #define MINSEEDS 1 #define MAXSIZE 99 #define MAXPOINTS 200 #define COLORTHRESH 512 typedef struct { unsigned int default_fg_pixel; XPoint *walkers; XPoint *pointbuf; unsigned int *reef; int nwalkers; int width, widthb; int height; int colorindex; int density; int seeds; } coralstruct; static coralstruct *reefs = (coralstruct *) NULL; #define getdot(x,y) (cp->reef[(y*cp->widthb)+(x>>5)] & (1<<(x & 31))) /* Avoid array bounds reads and writes */ #define setdot(x,y) (cp->reef[((y*cp->widthb)+(x>>5) >= 0 ? (y*cp->widthb)+(x>>5) : 0)] |= (1<<(x & 31))) /*- * returns 2 bits of randomness (conserving calls to LRAND()). * This speeds things up a little, but not a lot (5-10% or so.) */ static int rand_2(void) { static int i = 0; static int r = 0; if (i) { i--; } else { i = 15; r = (int) LRAND(); } { register int j = (r & 3); r = r >> 2; return j; } } static void free_coral(coralstruct *cp) { if (cp->reef != NULL) { free(cp->reef); cp->reef = (unsigned int *) NULL; } if (cp->walkers != NULL) { free(cp->walkers); cp->walkers = (XPoint *) NULL; } if (cp->pointbuf != NULL) { free(cp->pointbuf); cp->pointbuf = (XPoint *) NULL; } } void init_coral(ModeInfo * mi) { Display *display = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); GC gc = MI_GC(mi); coralstruct *cp; int size = MI_SIZE(mi); int i; if (reefs == NULL) { if ((reefs = (coralstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (coralstruct))) == NULL) return; } cp = &reefs[MI_SCREEN(mi)]; cp->width = MAX(MI_WIDTH(mi), 4); cp->height = MAX(MI_HEIGHT(mi), 4); cp->widthb = ((cp->width + 31) >> 5); if (cp->reef != NULL) free(cp->reef); if ((cp->reef = (unsigned int *) calloc((cp->widthb + 1) * cp->height, sizeof (unsigned int))) == NULL) { free_coral(cp); return; } if (size < -MINSIZE) cp->density = NRAND(MIN(MAXSIZE, -size) - MINSIZE + 1) + MINSIZE; else if (size < MINSIZE) cp->density = MINSIZE; else cp->density = MIN(MAXSIZE, size); cp->nwalkers = MAX((cp->width * cp->height * cp->density) / 100, 1); if (cp->walkers != NULL) free(cp->walkers); if ((cp->walkers = (XPoint *) calloc(cp->nwalkers, sizeof (XPoint))) == NULL) { free_coral(cp); return; } cp->seeds = MI_COUNT(mi); if (cp->seeds < -MINSEEDS) cp->seeds = NRAND(-cp->seeds - MINSEEDS + 1) + MINSEEDS; else if (cp->seeds < MINSEEDS) cp->seeds = MINSEEDS; MI_CLEARWINDOW(mi); if (MI_NPIXELS(mi) > 2) { cp->colorindex = NRAND(MI_NPIXELS(mi) * COLORTHRESH); XSetForeground(display, gc, MI_PIXEL(mi, cp->colorindex / COLORTHRESH)); } else XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); for (i = 0; i < cp->seeds; i++) { int x, y; do { x = NRAND(cp->width); y = NRAND(cp->height); } while (getdot(x, y)); setdot((x - 1), (y - 1)); setdot(x, (y - 1)); setdot((x + 1), (y - 1)); setdot((x - 1), y); setdot(x, y); setdot((x + 1), y); setdot((x - 1), (y + 1)); setdot(x, (y + 1)); setdot((x + 1), (y + 1)); XDrawPoint(display, window, gc, x, y); } for (i = 0; i < cp->nwalkers; i++) { cp->walkers[i].x = NRAND(cp->width - 2) + 1; cp->walkers[i].y = NRAND(cp->height - 2) + 1; } if (cp->pointbuf) { free(cp->pointbuf); } if ((cp->pointbuf = (XPoint *) calloc((MAXPOINTS + 2), sizeof (XPoint))) == NULL) { free_coral(cp); return; } } void draw_coral(ModeInfo * mi) { Display *display = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); GC gc = MI_GC(mi); int npoints = 0; int i; coralstruct *cp; if (reefs == NULL) return; cp = &reefs[MI_SCREEN(mi)]; if (cp->reef == NULL) return; MI_IS_DRAWN(mi) = True; for (i = 0; i < cp->nwalkers; i++) { int x = cp->walkers[i].x; int y = cp->walkers[i].y; if (getdot(x, y)) { /* XDrawPoint(display, window, gc, x, y); */ cp->pointbuf[npoints].x = x; cp->pointbuf[npoints].y = y; npoints++; /* Mark the surrounding area as "sticky" */ setdot((x - 1), (y - 1)); setdot(x, (y - 1)); setdot((x + 1), (y - 1)); setdot((x - 1), y); setdot((x + 1), y); setdot((x - 1), (y + 1)); setdot(x, (y + 1)); setdot((x + 1), (y + 1)); cp->nwalkers--; cp->walkers[i].x = cp->walkers[cp->nwalkers].x; cp->walkers[i].y = cp->walkers[cp->nwalkers].y; if (0 == cp->nwalkers || npoints >= MAXPOINTS) { XDrawPoints(display, window, gc, cp->pointbuf, npoints, CoordModeOrigin); npoints = 0; } if (MI_NPIXELS(mi) > 2) { XSetForeground(display, gc, MI_PIXEL(mi, cp->colorindex / COLORTHRESH)); if (++cp->colorindex >= MI_NPIXELS(mi) * COLORTHRESH) cp->colorindex = 0; } else XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); if (0 == cp->nwalkers) { if (cp->pointbuf) free(cp->pointbuf); cp->pointbuf = 0; init_coral(mi); return; } } else { /* move it a notch */ switch (rand_2()) { case 0: if (1 == x) continue; cp->walkers[i].x--; break; case 1: if (cp->width - 2 == x) continue; cp->walkers[i].x++; break; case 2: if (1 == y) continue; cp->walkers[i].y--; break; default: /* case 3: */ if (cp->height - 2 == y) continue; cp->walkers[i].y++; break; } } } if (npoints > 0) { XDrawPoints(display, window, gc, cp->pointbuf, npoints, CoordModeOrigin); } } void release_coral(ModeInfo * mi) { if (reefs != NULL) { int screen; for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) free_coral(&reefs[screen]); free(reefs); reefs = (coralstruct *) NULL; } } #endif /* MODE_coral */