344 lines
8.1 KiB
C
344 lines
8.1 KiB
C
/* -*- 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" <roeber@netscape.com>
|
|
*
|
|
* 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 <bagleyd@tux.org>)
|
|
* 15-Jul-1997: xscreensaver version Frederick G.M. Roeber
|
|
* <roeber@netscape.com>
|
|
*/
|
|
|
|
/*-
|
|
* original copyright
|
|
* Copyright (c) 1997 by "Frederick G.M. Roeber" <roeber@netscape.com>
|
|
*
|
|
* 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 */
|