/* anemone, Copyright (c) 2001 Gabriel Finch
*
* 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.
*/
/*------------------------------------------------------------------------
|
| FILE anemone.c
| MODULE OF xscreensaver
|
| DESCRIPTION Anemone.
|
| WRITTEN BY Gabriel Finch
|
|
|
| MODIFICATIONS june 2001 started
|
+----------------------------------------------------------------------*/
#include <math.h>
#include "screenhack.h"
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
#include "xdbe.h"
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
/*-----------------------------------------------------------------------+
| PRIVATE DATA |
+-----------------------------------------------------------------------*/
#define TWO_PI (2.0 * M_PI)
#define RND(x) (random() % (x))
#define MAXPEND 2000
#define MAXPTS 200
#define TRUE 1
#define FALSE 0
typedef struct {
double x,y,z;
int sx,sy,sz;
} vPend;
typedef struct {
long col;
int numpt;
int growth;
unsigned short rate;
} appDef;
struct state {
Display *dpy;
Pixmap b, ba, bb;
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
XdbeBackBuffer backb;
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
int arms; /* number of arms */
int finpoints; /* final number of points in each array. */
long delay; /* usecs to wait between updates. */
int scrWidth, scrHeight;
GC gcDraw, gcClear;
Bool dbuf;
int width;
vPend *vPendage; /* 3D representation of appendages */
appDef *appD; /* defaults */
vPend *vCurr, *vNext;
appDef *aCurr;
double turn, turndelta;
int mx, my; /* max screen coordinates. */
int withdraw;
XGCValues gcv;
Colormap cmap;
XColor *colors;
int ncolors;
};
/*-----------------------------------------------------------------------+
| PUBLIC DATA |
+-----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------+
| PRIVATE FUNCTIONS |
+-----------------------------------------------------------------------*/
static void *
xmalloc(size_t size)
{
void *ret;
if ((ret = malloc(size)) == NULL) {
fprintf(stderr, "anemone: out of memory\n");
exit(1);
}
return ret;
}
static void
initAppendages(struct state *st)
{
int i;
/*int marginx, marginy; */
/*double scalex, scaley;*/
double x,y,z,dist;
st->mx = st->scrWidth - 1;
st->my = st->scrHeight - 1;
/* each appendage will have: colour,
number of points, and a grow or shrink indicator */
/* added: growth rate 1-10 (smaller==faster growth) */
/* each appendage needs virtual coords (x,y,z) with y and z combining to
give the screen y */
st->vPendage = (vPend *) xmalloc((st->finpoints + 1) * sizeof(vPend) * st->arms);
st->appD = (appDef *) xmalloc(sizeof(appDef) * st->arms);
for (i = 0; i < st->arms; i++) {
st->aCurr = st->appD + i;
st->vCurr = st->vPendage + (st->finpoints + 1) * i;
st->vNext = st->vCurr + 1;
st->aCurr->col = st->colors[random() % st->ncolors].pixel;
st->aCurr->numpt = 1;
st->aCurr->growth = st->finpoints / 2 + RND(st->finpoints / 2);
st->aCurr->rate = RND(11) * RND(11);
do {
x = (1 - RND(1001) / 500);
y = (1 - RND(1001) / 500);
z = (1 - RND(1001) / 500);
dist = x * x + y * y + z * z;
} while (dist >= 1.);
st->vCurr->x = x * 200;
st->vCurr->y = st->my / 2 + y * 200;
st->vCurr->z = 0 + z * 200;
/* start the arm going outwards */
st->vCurr->sx = st->vCurr->x / 5;
st->vCurr->sy = (st->vCurr->y - st->my / 2) / 5;
st->vCurr->sz = (st->vCurr->z) / 5;
st->vNext->x = st->vCurr->x + st->vCurr->sx;
st->vNext->y = st->vCurr->y + st->vCurr->sy;
st->vNext->z = st->vCurr->z + st->vCurr->sz;
}
}
static void *
anemone_init (Display *disp, Window window)
{
struct state *st = (struct state *) calloc (1, sizeof(*st));
XWindowAttributes wa;
st->dpy = disp;
st->turn = 0.;
st->width = get_integer_resource(st->dpy, "width", "Integer");
st->arms = get_integer_resource(st->dpy, "arms", "Integer");
st->finpoints = get_integer_resource(st->dpy, "finpoints", "Integer");
st->delay = get_integer_resource(st->dpy, "delay", "Integer");
st->withdraw = get_integer_resource(st->dpy, "withdraw", "Integer");
st->turndelta = get_float_resource(st->dpy, "turnspeed", "float") / 100000;
st->dbuf = TRUE;
# ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */
st->dbuf = False;
# endif
st->b = st->ba = st->bb = 0; /* double-buffer to reduce flicker */
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
st->b = st->backb = xdbe_get_backbuffer (st->dpy, window, XdbeUndefined);
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
XGetWindowAttributes(st->dpy, window, &wa);
st->scrWidth = wa.width;
st->scrHeight = wa.height;
st->cmap = wa.colormap;
st->ncolors = get_integer_resource (st->dpy, "colors", "Colors");
st->ncolors += 3;
st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1));
make_smooth_colormap (wa.screen, wa.visual, st->cmap,
st->colors, &st->ncolors,
True, 0, True);
st->gcDraw = XCreateGC(st->dpy, window, 0, &st->gcv);
st->gcv.foreground = get_pixel_resource(st->dpy, st->cmap,
"background", "Background");
st->gcClear = XCreateGC(st->dpy, window, GCForeground, &st->gcv);
if (st->dbuf) {
if (!st->b)
{
st->ba = XCreatePixmap (st->dpy, window, st->scrWidth, st->scrHeight, wa.depth);
st->bb = XCreatePixmap (st->dpy, window, st->scrWidth, st->scrHeight, wa.depth);
st->b = st->ba;
}
}
else
{
st->b = window;
}
if (st->ba) XFillRectangle (st->dpy, st->ba, st->gcClear, 0, 0, st->scrWidth, st->scrHeight);
if (st->bb) XFillRectangle (st->dpy, st->bb, st->gcClear, 0, 0, st->scrWidth, st->scrHeight);
XClearWindow(st->dpy, window);
XSetLineAttributes(st->dpy, st->gcDraw, st->width, LineSolid, CapRound, JoinBevel);
initAppendages(st);
return st;
}
static void
createPoints(struct state *st)
{
int i;
int withdrawall = RND(st->withdraw);
for (i = 0; i< st->arms; i++) {
st->aCurr = st->appD + i;
if (!withdrawall) {
st->aCurr->growth = -st->finpoints;
st->turndelta = -st->turndelta;
}
else if (withdrawall<11) st->aCurr->growth = -st->aCurr->numpt;
else if (RND(100)<st->aCurr->rate) {
if (st->aCurr->growth>0) {
if (!(--st->aCurr->growth)) st->aCurr->growth = -RND(st->finpoints) - 1;
st->vCurr = st->vPendage + (st->finpoints + 1) * i + st->aCurr->numpt - 1;
if (st->aCurr->numpt<st->finpoints - 1) {
/* add a piece */
st->vNext = st->vCurr + 1;
st->aCurr->numpt++;
st->vNext->sx = st->vCurr->sx + RND(3) - 1;
st->vNext->sy = st->vCurr->sy + RND(3) - 1;
st->vNext->sz = st->vCurr->sz + RND(3) - 1;
st->vCurr = st->vNext + 1;
st->vCurr->x = st->vNext->x + st->vNext->sx;
st->vCurr->y = st->vNext->y + st->vNext->sy;
st->vCurr->z = st->vNext->z + st->vNext->sz;
}
}
}
}
}
static void
drawImage(struct state *st, Drawable curr_window, double sint, double cost)
{
int q,numpt,mx2 = st->mx / 2;
double cx,cy,cz,nx = 0,ny = 0,nz = 0;
if ((numpt = st->aCurr->numpt)==1) return;
XSetForeground(st->dpy, st->gcDraw, st->aCurr->col);
st->vNext = st->vCurr + 1;
cx = st->vCurr->x;
cy = st->vCurr->y;
cz = st->vCurr->z;
for (q = 0; q < numpt - 1; q++) {
nx = st->vNext->x + 2 - RND(5);
ny = st->vNext->y + 2 - RND(5);
nz = st->vNext->z + 2 - RND(5);
XDrawLine(st->dpy, curr_window, st->gcDraw,
mx2 + cx * cost - cz * sint, cy,
mx2 + nx * cost - nz * sint, ny);
st->vCurr++;
st->vNext++;
cx = nx;
cy = ny;
cz = nz;
}
XSetLineAttributes(st->dpy, st->gcDraw, st->width * 3,
LineSolid, CapRound, JoinBevel);
XDrawLine(st->dpy, curr_window, st->gcDraw,
st->mx / 2 + cx * cost - cz * sint, cy,
st->mx / 2 + nx * cost - nz * sint, ny);
XSetLineAttributes(st->dpy, st->gcDraw, st->width,
LineSolid, CapRound, JoinBevel);
}
static void
animateAnemone(struct state *st, Drawable curr_window)
{
int i;
double sint = sin(st->turn),cost = cos(st->turn);
st->aCurr = st->appD;
for (i = 0; i< st->arms; i++) {
st->vCurr = st->vPendage + (st->finpoints + 1) * i;
if (RND(25)<st->aCurr->rate) {
if (st->aCurr->growth<0) {
st->aCurr->numpt -= st->aCurr->numpt>1;
if (!(++st->aCurr->growth)) st->aCurr->growth = RND(st->finpoints - st->aCurr->numpt) + 1;
}
}
drawImage(st, curr_window, sint, cost);
st->turn += st->turndelta;
st->aCurr++;
}
createPoints(st);
if (st->turn >= TWO_PI) st->turn -= TWO_PI;
}
static unsigned long
anemone_draw (Display *dpy, Window window, void *closure)
{
struct state *st = (struct state *) closure;
XFillRectangle (st->dpy, st->b, st->gcClear, 0, 0, st->scrWidth, st->scrHeight);
animateAnemone(st, st->b);
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
if (st->backb)
{
XdbeSwapInfo info[1];
info[0].swap_window = window;
info[0].swap_action = XdbeUndefined;
XdbeSwapBuffers (st->dpy, info, 1);
}
else
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
if (st->dbuf)
{
XCopyArea (st->dpy, st->b, window, st->gcClear, 0, 0,
st->scrWidth, st->scrHeight, 0, 0);
st->b = (st->b == st->ba ? st->bb : st->ba);
}
return st->delay;
}
static void
anemone_reshape (Display *dpy, Window window, void *closure,
unsigned int w, unsigned int h)
{
struct state *st = (struct state *) closure;
st->scrWidth = w;
st->scrHeight = h;
#if 0
if (st->dbuf) {
XWindowAttributes wa;
XGetWindowAttributes(dpy, window, &wa);
if (st->ba) XFreePixmap (dpy, st->ba);
if (st->bb) XFreePixmap (dpy, st->bb);
st->ba = XCreatePixmap (dpy, window, st->scrWidth, st->scrHeight, wa.depth);
st->bb = XCreatePixmap (dpy, window, st->scrWidth, st->scrHeight, wa.depth);
st->b = st->ba;
}
#endif
}
static Bool
anemone_event (Display *dpy, Window window, void *closure, XEvent *event)
{
return False;
}
static void
anemone_free (Display *dpy, Window window, void *closure)
{
struct state *st = (struct state *) closure;
if (st->vPendage) free (st->vPendage);
if (st->appD) free (st->appD);
free (st);
}
static const char *anemone_defaults [] = {
".background: black",
"*arms: 128",
"*width: 2",
"*finpoints: 64",
"*delay: 40000",
"*withdraw: 1200",
"*turnspeed: 50",
"*colors: 20",
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
"*useDBE: True",
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
#ifdef HAVE_MOBILE
"*ignoreRotation: True",
#endif
0
};
static XrmOptionDescRec anemone_options [] = {
{ "-arms", ".arms", XrmoptionSepArg, 0 },
{ "-finpoints", ".finpoints", XrmoptionSepArg, 0 },
{ "-delay", ".delay", XrmoptionSepArg, 0 },
{ "-width", ".width", XrmoptionSepArg, 0 },
{ "-withdraw", ".withdraw", XrmoptionSepArg, 0 },
{ "-turnspeed", ".turnspeed", XrmoptionSepArg, 0 },
{ "-colors", ".colors", XrmoptionSepArg, 0 },
{ 0, 0, 0, 0 }
};
XSCREENSAVER_MODULE ("Anemone", anemone)