xenocara/app/xlockmore/modes/coral.c
2006-11-26 11:07:42 +00:00

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 */