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

554 lines
14 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* anemone --- */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)anemone.c 5.22 2006/03/04 xlockmore";
#endif
/* anemon, 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
| March 2006 adaption for xlockmore
|
+----------------------------------------------------------------------*/
#ifdef STANDALONE
#define MODE_anemone
#define PROGCLASS "Anemone"
#define HACK_INIT init_anemone
#define HACK_DRAW draw_anemone
#define anemone_opts xlockmore_opts
#define DEFAULTS "*delay: 100000 \n" \
"*size: 4 \n" \
"*ncolors: 8 \n" \
"*fullrandom: True \n" \
"*verbose: False \n" \
".background: black \n" \
"*arms: 256 \n" \
"*width: 2 \n" \
"*finpoints: 64 \n" \
"*delay: 40000 \n" \
"*withdraw: 2400 \n" \
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
"*useDBE: True \n" \
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
"*turnspeed: 100 \n"
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#endif /* STANDALONE */
#ifdef MODE_anemone
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
#include "xdbe.h"
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
/*-----------------------------------------------------------------------+
| PRIVATE DATA |
+-----------------------------------------------------------------------*/
#define TWO_PI (2.0 * M_PI)
#define MAXPEND 2000
#define MAXPTS 200
#define DEF_ARMS "256"
#define DEF_FINPOINTS "64"
#define DEF_WIDTH "2"
#define DEF_WITHDRAW "2400"
#define DEF_TURNSPEED "5"
static int st_arms;
static int st_finpoints;
static int st_width;
static int st_withdraw;
static int st_turnspeed;
typedef struct {
double x,y,z;
int sx,sy,sz;
} vPend;
typedef unsigned short bool;
typedef struct {
long col;
int numpt;
int growth;
unsigned short rate;
} appDef;
typedef struct {
Display *dpy;
Window window;
Pixmap b,ba,bb;
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
static XdbeBackBuffer backb;
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
int
arms, /* number of arms */
finpoints; /* final number of points in each array. */
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;
} anemonestruct;
static anemonestruct *anemones = (anemonestruct *) NULL;
/*-----------------------------------------------------------------------+
| PUBLIC DATA |
+-----------------------------------------------------------------------*/
static XrmOptionDescRec opts[] =
{
{(char *) "-arms", (char *) ".anemone.arms", XrmoptionSepArg, (caddr_t) NULL},
{(char *) "-finpoints", (char *) ".anemone.finpoints", XrmoptionSepArg, (caddr_t) NULL},
{(char *) "-width", (char *) ".anemone.width", XrmoptionSepArg, (caddr_t) NULL},
{(char *) "-withdraw", (char *) ".anemone.withdraw", XrmoptionSepArg, (caddr_t) NULL},
{(char *) "-turnspeed", (char *) ".anemone.turnspeed", XrmoptionSepArg, (caddr_t) NULL}
};
static argtype vars[] =
{
{(void *) &st_arms, (char *) "arms",
(char *) "Arms", (char *) DEF_ARMS , t_Int},
{(void *) &st_finpoints, (char *) "finpoints",
(char *) "Finpoints", (char *) DEF_FINPOINTS , t_Int},
{(void *) &st_width, (char *) "width",
(char *) "Width", (char *) DEF_WIDTH , t_Int},
{(void *) &st_withdraw, (char *) "withdraw",
(char *) "Withdt=raw", (char *) DEF_WITHDRAW , t_Int},
{(void *) &st_turnspeed, (char *) "turnspeed",
(char *) "Turnspeed", (char *) DEF_TURNSPEED , t_Int}
};
static OptionStruct desc[] =
{
{(char *) "-arms num", (char *) "Number of arms"},
{(char *) "-width num", (char *) "Width of arms"},
{(char *) "-finpoints num", (char *) "final number of points in each array"},
{(char *) "-withdraw num", (char *) "withdraw frequency"},
{(char *) "-turnspeed num", (char *) "turning speed"}
};
ModeSpecOpt anemone_opts =
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
#ifdef USE_MODULES
ModStruct anemone_description =
{"anemone", "init_anemone", "draw_anemone", "release_anemone",
"refresh_anemone", "init_anemone", (char *) NULL, &anemone_opts,
50000, 1, 1, 1, 64, 1.0, "",
"Shows wiggling tentacles", 0, NULL};
#endif
/*-----------------------------------------------------------------------+
| PRIVATE FUNCTIONS |
+-----------------------------------------------------------------------*/
static void
free_anemone(Display *display, anemonestruct *sp)
{
if ( sp->vPendage )
{
free( sp->vPendage );
sp->vPendage = (vPend*) NULL;
}
if ( sp->appD )
{
free( sp->appD );
sp->appD = (appDef*) NULL;
}
if ( sp->gcDraw != None )
{
XFreeGC(display, sp->gcDraw );
sp->gcDraw = None;
}
if ( sp->gcClear != None )
{
XFreeGC(display, sp->gcClear );
sp->gcClear = None;
}
if (sp->ba != None)
{
XFreePixmap(display, sp->ba);
sp->ba = None;
}
if (sp->bb != None)
{
XFreePixmap(display, sp->bb);
sp->ba = None;
}
}
static void *
xmalloc(size_t size)
{
void *ret;
if ((ret = malloc(size)) == NULL) {
fprintf(stderr, "anemone: out of memory\n");
}
return ret;
}
static void
initAppendages(anemonestruct *sp)
{
int i;
/*int marginx, marginy; */
/*double scalex, scaley;*/
double x,y,z,dist;
sp->mx = sp->scrWidth - 1;
sp->my = sp->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 */
sp->vPendage = (vPend *) xmalloc((sp->finpoints + 1) * sizeof(vPend) * sp->arms);
sp->appD = (appDef *) xmalloc(sizeof(appDef) * sp->arms);
for (i = 0; i < sp->arms; i++) {
sp->aCurr = sp->appD + i;
sp->vCurr = sp->vPendage + (sp->finpoints + 1) * i;
sp->vNext = sp->vCurr + 1;
sp->aCurr->col = (long)NRAND(256)*NRAND(256)+32768;
sp->aCurr->numpt = 1;
sp->aCurr->growth=sp->finpoints/2+NRAND(sp->finpoints/2);
sp->aCurr->rate=NRAND(11)*NRAND(11);
dist=1.;
do {
x=(1-NRAND(1001)/500);
y=(1-NRAND(1001)/500);
z=(1-NRAND(1001)/500);
dist=x*x+y*y+z*z;
} while (dist>=1.);
sp->vCurr->x=x*200;
sp->vCurr->y=sp->my/2+y*200;
sp->vCurr->z=0+z*200;
/* start the arm going outwards */
sp->vCurr->sx=(int) (sp->vCurr->x/5);
sp->vCurr->sy=(int) ((sp->vCurr->y-sp->my/2)/5);
sp->vCurr->sz=(int) (sp->vCurr->z/5);
sp->vNext->x=sp->vCurr->x+sp->vCurr->sx;
sp->vNext->y=sp->vCurr->y+sp->vCurr->sy;
sp->vNext->z=sp->vCurr->z+sp->vCurr->sz;
}
}
static void
initAnemone( ModeInfo * mi , anemonestruct *sp )
{
XWindowAttributes wa;
sp->turn = 0.;
if ( st_width < 0 )
sp->width = NRAND( -st_width ) + 1;
else
sp->width = st_width;
if ( st_arms < 0 )
sp->arms = NRAND( -st_arms ) + 1;
else
sp->arms = st_arms;
if ( st_finpoints < 0 )
sp->finpoints = NRAND( -st_finpoints ) + 1;
else
sp->finpoints = st_finpoints;
if ( st_withdraw < 0 )
sp->withdraw = NRAND( -st_withdraw );
else
sp->withdraw = st_withdraw;
if ( st_turnspeed < 0 )
sp->turndelta = NRAND( -st_turnspeed ) / 10000.;
else
sp->turndelta =st_turnspeed / 10000.0;
sp->dbuf=True;
sp->b=sp->ba=sp->bb=0; /* double-buffer to reduce flicker */
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
sp->b = backb = xdbe_get_backbuffer (sp->dpy, sp->window, XdbeUndefined);
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
XGetWindowAttributes(sp->dpy, sp->window, &wa);
sp->scrWidth = wa.width;
sp->scrHeight = wa.height;
sp->cmap = wa.colormap;
sp->gcDraw = XCreateGC(sp->dpy, sp->window, GCForeground, &sp->gcv);
sp->gcv.foreground = MI_BLACK_PIXEL(mi);
sp->gcClear = XCreateGC(sp->dpy, sp->window, GCForeground, &sp->gcv);
if (sp->dbuf) {
if (!sp->b)
{
sp->ba = XCreatePixmap (sp->dpy, sp->window, sp->scrWidth, sp->scrHeight, wa.depth);
sp->bb = XCreatePixmap (sp->dpy, sp->window, sp->scrWidth, sp->scrHeight, wa.depth);
sp->b = sp->ba;
}
}
else
{
sp->b= sp->window;
}
if (sp->ba) XFillRectangle (sp->dpy, sp->ba, sp->gcClear, 0, 0, sp->scrWidth, sp->scrHeight);
if (sp->bb) XFillRectangle (sp->dpy, sp->bb, sp->gcClear, 0, 0, sp->scrWidth, sp->scrHeight);
XClearWindow(sp->dpy, sp->window);
XSetLineAttributes(sp->dpy, sp->gcDraw, sp->width, LineSolid, CapRound, JoinBevel);
initAppendages( sp );
}
static void
createPoints(anemonestruct *sp)
{
int i;
int withdrawall=NRAND(sp->withdraw);
for (i = 0; i< sp->arms; i++) {
sp->aCurr = sp->appD + i;
if (!withdrawall) {
sp->aCurr->growth=-sp->finpoints;
sp->turndelta=-sp->turndelta;
}
else if (withdrawall<11) sp->aCurr->growth=-sp->aCurr->numpt;
else if (NRAND(100)<sp->aCurr->rate) {
if (sp->aCurr->growth>0) {
if (!(--sp->aCurr->growth)) sp->aCurr->growth=-NRAND(sp->finpoints)-1;
sp->vCurr = sp->vPendage + (sp->finpoints + 1) * i + sp->aCurr->numpt-1;
if (sp->aCurr->numpt<sp->finpoints - 1) {
/* add a piece */
sp->vNext=sp->vCurr + 1;
sp->aCurr->numpt++;
sp->vNext->sx=sp->vCurr->sx+NRAND(3)-1;
sp->vNext->sy=sp->vCurr->sy+NRAND(3)-1;
sp->vNext->sz=sp->vCurr->sz+NRAND(3)-1;
sp->vCurr=sp->vNext+1;
sp->vCurr->x=sp->vNext->x+sp->vNext->sx;
sp->vCurr->y=sp->vNext->y+sp->vNext->sy;
sp->vCurr->z=sp->vNext->z+sp->vNext->sz;
}
}
}
}
}
static void
drawImage(Drawable curr_window, double sint, double cost , anemonestruct *sp)
{
int q,numpt,mx2=sp->mx/2;
double cx,cy,cz,nx=0,ny=0,nz=0;
if ((numpt=sp->aCurr->numpt)==1) return;
XSetForeground(sp->dpy, sp->gcDraw, sp->aCurr->col);
sp->vNext=sp->vCurr+1;
cx=sp->vCurr->x;
cy=sp->vCurr->y;
cz=sp->vCurr->z;
for (q = 0; q < numpt-1; q++) {
nx=sp->vNext->x+2-NRAND(5);
ny=sp->vNext->y+2-NRAND(5);
nz=sp->vNext->z+2-NRAND(5);
XDrawLine(sp->dpy, curr_window, sp->gcDraw,
(int) (mx2+cx*cost-cz*sint), (int) cy,
(int) (mx2+nx*cost-nz*sint), (int) ny);
sp->vCurr++;
sp->vNext++;
cx=nx;
cy=ny;
cz=nz;
}
XSetLineAttributes(sp->dpy, sp->gcDraw, sp->width*3, LineSolid, CapRound, JoinBevel);
XDrawLine(sp->dpy, curr_window, sp->gcDraw,
(int) (sp->mx/2+cx*cost-cz*sint), (int) cy,
(int) (sp->mx/2+nx*cost-nz*sint), (int) ny);
XSetLineAttributes(sp->dpy, sp->gcDraw, sp->width, LineSolid, CapRound, JoinBevel);
}
static void
animateAnemone(Drawable curr_window , anemonestruct *sp )
{
int i;
double sint=sin(sp->turn),cost=cos(sp->turn);
sp->aCurr = sp->appD;
for (i = 0; i< sp->arms; i++) {
sp->vCurr=sp->vPendage + (sp->finpoints + 1) * i;
if (NRAND(25)<sp->aCurr->rate) {
if (sp->aCurr->growth<0) {
sp->aCurr->numpt-=sp->aCurr->numpt>1;
if (!(++sp->aCurr->growth)) sp->aCurr->growth=NRAND(sp->finpoints-sp->aCurr->numpt)+1;
}
}
drawImage(curr_window, sint, cost , sp );
sp->turn+=sp->turndelta;
sp->aCurr++;
}
createPoints(sp);
if (sp->turn>=TWO_PI) sp->turn-=TWO_PI;
}
/*-----------------------------------------------------------------------+
| PUBLIC FUNCTIONS |
+-----------------------------------------------------------------------*/
void
init_anemone(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
anemonestruct *sp;
/* initialize */
if (anemones == NULL) {
if ((anemones = (anemonestruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (anemonestruct))) == NULL)
return;
}
sp = &anemones[MI_SCREEN(mi)];
free_anemone(display, sp);
sp->dpy= MI_DISPLAY(mi);
sp->window=MI_WINDOW(mi);
initAnemone( mi , sp );
XFillRectangle (sp->dpy, sp->b, sp->gcClear, 0, 0, sp->scrWidth, sp->scrHeight);
animateAnemone( sp->b , sp );
}
void draw_anemone (ModeInfo * mi)
{
anemonestruct *sp = &anemones[MI_SCREEN(mi)];
if (anemones == NULL)
return;
MI_IS_DRAWN(mi) = True;
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
if (backb)
{
XdbeSwapInfo info[1];
info[0].swap_window = sp->window;
info[0].swap_action = XdbeUndefined;
XdbeSwapBuffers (sp->dpy, info, 1);
}
else
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
if (sp->dbuf)
{
XCopyArea (sp->dpy, sp->b, sp->window, sp->gcClear, 0, 0,
sp->scrWidth, sp->scrHeight, 0, 0);
sp->b = (sp->b == sp->ba ? sp->bb : sp->ba);
}
XFillRectangle (sp->dpy, sp->b, sp->gcClear, 0, 0, sp->scrWidth, sp->scrHeight);
animateAnemone( sp->b , sp );
}
void
release_anemone(ModeInfo * mi)
{
if (anemones != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_anemone(MI_DISPLAY(mi), &anemones[screen]);
free(anemones);
anemones = (anemonestruct *) NULL;
}
}
void
refresh_anemone(ModeInfo * mi)
{
if (anemones == NULL)
return;
}
#endif /* MODE_anemone */