#include <math.h>
#include "screenhack.h"
-#include <X11/Xutil.h>
/*#define VERBOSE*/
-char *progclass = "Metaballs";
-
-char *defaults [] = {
- ".background: black",
- ".foreground: white",
- "*color: random",
- "*count: 10",
- "*cycles: 1000",
- "*ncolors: 256",
- "*delay: 5000",
- "*radius: 100",
- "*delta: 3",
- 0
-};
-
-XrmOptionDescRec options [] = {
- { "-color", ".color", XrmoptionSepArg, 0 },
- { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
- { "-count", ".count", XrmoptionSepArg, 0 },
- { "-delay", ".delay", XrmoptionSepArg, 0 },
- { "-cycles", ".cycles", XrmoptionSepArg, 0 },
- { "-radius", ".radius", XrmoptionSepArg, 0 },
- { "-delta", ".delta", XrmoptionSepArg, 0 },
- { 0, 0, 0, 0 }
-};
-
-static unsigned short iWinWidth, iWinHeight;
-static char *sColor;
-
/*blob structure*/
typedef struct
{
short xpos,ypos;
} BLOB;
-static unsigned int nBlobCount;
-static unsigned char radius;
-static unsigned char delta;
-static unsigned char dradius;
-static unsigned short sradius;
-static unsigned char **blob;
-static BLOB *blobs;
-static unsigned char **blub;
+struct state {
+ Display *dpy;
+ Window window;
+
+ unsigned short iWinWidth, iWinHeight;
+ char *sColor;
+
+ unsigned int nBlobCount;
+ unsigned char radius;
+ unsigned char delta;
+ unsigned char dradius;
+ unsigned short sradius;
+ unsigned char **blob;
+ BLOB *blobs;
+ unsigned char **blub;
+
+ int delay, cycles;
+ signed short iColorCount;
+ unsigned long *aiColorVals;
+ XImage *pImage;
+ GC gc;
+ int draw_i;
+};
+
-static void init_blob(BLOB *blob)
+#undef BELLRAND
+#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
+
+static void init_blob(struct state *st, BLOB *blob)
{
- blob->xpos = (iWinWidth>> 1) - radius;
- blob->ypos = (iWinHeight >> 1) - radius;
+ blob->xpos = st->iWinWidth/4 + BELLRAND(st->iWinWidth/2) - st->radius;
+ blob->ypos = st->iWinHeight/4 + BELLRAND(st->iWinHeight/2) - st->radius;
}
-static void Execute( Display *pDisplay,
- Window MainWindow,
- GC *pGC, XImage *pImage,
- signed short iColorCount, unsigned long *aiColorVals )
+static void Execute( struct state *st )
{
unsigned int i, j, k;
- /* clear blub array */
- for (i = 0; i < iWinHeight; ++i)
- memset(blub[i], 0, iWinWidth * sizeof(unsigned char));
+ /* clear st->blub array */
+ for (i = 0; i < st->iWinHeight; ++i)
+ memset(st->blub[i], 0, st->iWinWidth * sizeof(unsigned char));
- /* move blobs */
- for (i = 0; i < nBlobCount; i++)
+ /* move st->blobs */
+ for (i = 0; i < st->nBlobCount; i++)
{
- blobs[i].xpos += -delta + (int)((delta + .5f) * frand(2.0));
- blobs[i].ypos += -delta + (int)((delta + .5f) * frand(2.0));
+ st->blobs[i].xpos += -st->delta + (int)((st->delta + .5f) * frand(2.0));
+ st->blobs[i].ypos += -st->delta + (int)((st->delta + .5f) * frand(2.0));
}
- /* draw blobs to blub array */
- for (k = 0; k < nBlobCount; ++k)
+ /* draw st->blobs to st->blub array */
+ for (k = 0; k < st->nBlobCount; ++k)
{
- if (blobs[k].ypos > -dradius && blobs[k].xpos > -dradius && blobs[k].ypos < iWinHeight && blobs[k].xpos < iWinWidth)
+ if (st->blobs[k].ypos > -st->dradius && st->blobs[k].xpos > -st->dradius && st->blobs[k].ypos < st->iWinHeight && st->blobs[k].xpos < st->iWinWidth)
{
- for (i = 0; i < dradius; ++i)
+ for (i = 0; i < st->dradius; ++i)
{
- if (blobs[k].ypos + i >= 0 && blobs[k].ypos + i < iWinHeight)
+ if (st->blobs[k].ypos + i >= 0 && st->blobs[k].ypos + i < st->iWinHeight)
{
- for (j = 0; j < dradius; ++j)
+ for (j = 0; j < st->dradius; ++j)
{
- if (blobs[k].xpos + j >= 0 && blobs[k].xpos + j < iWinWidth)
+ if (st->blobs[k].xpos + j >= 0 && st->blobs[k].xpos + j < st->iWinWidth)
{
- if (blub[blobs[k].ypos + i][blobs[k].xpos + j] < iColorCount)
+ if (st->blub[st->blobs[k].ypos + i][st->blobs[k].xpos + j] < st->iColorCount-1)
{
- if (blub[blobs[k].ypos + i][blobs[k].xpos + j] + blob[i][j] > iColorCount)
- blub[blobs[k].ypos + i][blobs[k].xpos + j] = iColorCount;
+ if (st->blub[st->blobs[k].ypos + i][st->blobs[k].xpos + j] + st->blob[i][j] > st->iColorCount-1)
+ st->blub[st->blobs[k].ypos + i][st->blobs[k].xpos + j] = st->iColorCount-1;
else
- blub[blobs[k].ypos + i][blobs[k].xpos + j] += blob[i][j];
+ st->blub[st->blobs[k].ypos + i][st->blobs[k].xpos + j] += st->blob[i][j];
}
}
}
}
}
else
- init_blob(blobs + k);
+ init_blob(st, st->blobs + k);
}
- memset( pImage->data, 0, pImage->bytes_per_line * pImage->height);
+ memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height);
- /* draw blub array to screen */
- for (i = 0; i < iWinHeight; ++i)
+ /* draw st->blub array to screen */
+ for (i = 0; i < st->iWinHeight; ++i)
{
- for (j = 0; j < iWinWidth; ++j)
+ for (j = 0; j < st->iWinWidth; ++j)
{
- if (aiColorVals[blub[i][j]] > 0)
- XPutPixel( pImage, j, i, aiColorVals[blub[i][j]] );
+ if (st->aiColorVals[st->blub[i][j]] > 0)
+ XPutPixel( st->pImage, j, i, st->aiColorVals[st->blub[i][j]] );
}
}
- XPutImage( pDisplay, MainWindow, *pGC, pImage,
- 0, 0, 0, 0, iWinWidth, iWinHeight );
- XSync( pDisplay, False );
+ XPutImage( st->dpy, st->window, st->gc, st->pImage,
+ 0, 0, 0, 0, st->iWinWidth, st->iWinHeight );
}
-static unsigned long * SetPalette(Display *pDisplay, Window Win, char *sColor, signed short *piColorCount )
+static unsigned long * SetPalette(struct state *st )
{
XWindowAttributes XWinAttribs;
XColor Color, *aColors;
- unsigned long *aiColorVals;
signed short iColor;
float nHalfColors;
- XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
+ XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
Color.red = random() % 0xFFFF;
Color.green = random() % 0xFFFF;
Color.blue = random() % 0xFFFF;
- if( strcasecmp( sColor, "random" ) && !XParseColor( pDisplay, XWinAttribs.colormap, sColor, &Color ) )
- fprintf( stderr, "%s: color %s not found in database. Choosing to random...\n", progname, sColor );
+ if( strcasecmp( st->sColor, "random" ) && !XParseColor( st->dpy, XWinAttribs.colormap, st->sColor, &Color ) )
+ fprintf( stderr, "%s: color %s not found in database. Choosing to random...\n", progname, st->sColor );
#ifdef VERBOSE
- printf( "%s: Base color (RGB): <%d, %d, %d>\n", progclass, Color.red, Color.green, Color.blue );
+ printf( "%s: Base color (RGB): <%d, %d, %d>\n", progname, Color.red, Color.green, Color.blue );
#endif /* VERBOSE */
- *piColorCount = get_integer_resource( "ncolors", "Integer" );
- if( *piColorCount < 2 ) *piColorCount = 2;
- if( *piColorCount > 255 ) *piColorCount = 255;
+ st->iColorCount = get_integer_resource(st->dpy, "ncolors", "Integer" );
+ if( st->iColorCount < 2 ) st->iColorCount = 2;
+ if( st->iColorCount > 255 ) st->iColorCount = 255;
- aColors = calloc( *piColorCount, sizeof(XColor) );
- aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
+ aColors = calloc( st->iColorCount, sizeof(XColor) );
+ st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) );
- for( iColor=0; iColor<*piColorCount; iColor++ )
+ for( iColor=0; iColor < st->iColorCount; iColor++ )
{
- nHalfColors = *piColorCount / 2.0F;
+ nHalfColors = st->iColorCount / 2.0F;
/* Black -> Base Color */
- if( iColor < (*piColorCount/2) )
+ if( iColor < (st->iColorCount/2) )
{
aColors[ iColor ].red = ( Color.red / nHalfColors ) * iColor;
aColors[ iColor ].green = ( Color.green / nHalfColors ) * iColor;
aColors[ iColor ].blue = ( ( ( 0xFFFF - Color.blue ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.blue;
}
- if( !XAllocColor( pDisplay, XWinAttribs.colormap, &aColors[ iColor ] ) )
+ if( !XAllocColor( st->dpy, XWinAttribs.colormap, &aColors[ iColor ] ) )
{
/* start all over with less colors */
- XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColor, 0 );
+ XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, iColor, 0 );
free( aColors );
- free( aiColorVals );
- (*piColorCount)--;
+ free( st->aiColorVals );
+ (st->iColorCount)--;
- if (*piColorCount < 6)
+ if (st->iColorCount < 6)
{
fprintf (stderr, "%s: insufficient colors!\n",
progname);
exit (1);
}
- aColors = calloc( *piColorCount, sizeof(XColor) );
- aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
+ aColors = calloc( st->iColorCount, sizeof(XColor) );
+ st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) );
iColor = -1;
}
else
- aiColorVals[ iColor ] = aColors[ iColor ].pixel;
+ st->aiColorVals[ iColor ] = aColors[ iColor ].pixel;
}
free( aColors );
- XSetWindowBackground( pDisplay, Win, aiColorVals[ 0 ] );
+ XSetWindowBackground( st->dpy, st->window, st->aiColorVals[ 0 ] );
- return aiColorVals;
+ return st->aiColorVals;
}
-static void Initialize( Display *pDisplay, Window Win, GC *pGC, XImage **ppImage )
+static void Initialize( struct state *st )
{
XGCValues gcValues;
XWindowAttributes XWinAttribs;
float fraction;
/* Create the Image for drawing */
- XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
+ XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
/* Find the preferred bits-per-pixel. (jwz) */
{
int pfvc = 0;
- XPixmapFormatValues *pfv = XListPixmapFormats( pDisplay, &pfvc );
+ XPixmapFormatValues *pfv = XListPixmapFormats( st->dpy, &pfvc );
for( i=0; i<pfvc; i++ )
if( pfv[ i ].depth == XWinAttribs.depth )
{
}
/* Create the GC. */
- *pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
+ st->gc = XCreateGC( st->dpy, st->window, 0, &gcValues );
- *ppImage = XCreateImage( pDisplay, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
- XWinAttribs.width, XWinAttribs.height, BitmapPad( pDisplay ), 0 );
- (*ppImage)->data = calloc((*ppImage)->bytes_per_line, (*ppImage)->height);
+ st->pImage = XCreateImage( st->dpy, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
+ XWinAttribs.width, XWinAttribs.height, BitmapPad( st->dpy ), 0 );
+ (st->pImage)->data = calloc((st->pImage)->bytes_per_line, (st->pImage)->height);
- iWinWidth = XWinAttribs.width;
- iWinHeight = XWinAttribs.height;
+ st->iWinWidth = XWinAttribs.width;
+ st->iWinHeight = XWinAttribs.height;
/* Get the base color. */
- sColor = get_string_resource( "color", "Color" );
-
- /* Get the delta. */
- delta = get_integer_resource( "delta", "Integer" );
- if (delta < 1)
- delta = 1;
- else if (delta > 20)
- delta = 20;
+ st->sColor = get_string_resource(st->dpy, "color", "Color" );
+
+ /* Get the st->delta. */
+ st->delta = get_integer_resource(st->dpy, "delta", "Integer" );
+ if (st->delta < 1)
+ st->delta = 1;
+ else if (st->delta > 20)
+ st->delta = 20;
- /* Get the radius. */
- radius = get_integer_resource( "radius", "Integer" );
- if (radius < 2)
- radius = 2;
- if (radius > 100)
- radius = 100;
+ /* Get the st->radius. */
+ st->radius = get_integer_resource(st->dpy, "radius", "Integer" );
+ if (st->radius < 2)
+ st->radius = 2;
+ if (st->radius > 100)
+ st->radius = 100;
- radius = (radius / 100.0) * (iWinHeight >> 3);
- if (radius >= 128) /* should use UCHAR_MAX? */
- radius = 127; /* dradius should fit in u_char */
+ st->radius = (st->radius / 100.0) * (st->iWinHeight >> 3);
+ if (st->radius >= 128) /* should use UCHAR_MAX? */
+ st->radius = 127; /* st->dradius should fit in u_char */
- dradius = radius * 2;
- sradius = radius * radius;
+ st->dradius = st->radius * 2;
+ st->sradius = st->radius * st->radius;
- /* create blob */
- blob = malloc ( dradius * sizeof(unsigned char*));
- for (i = 0; i < dradius; ++i)
- blob[i] = malloc( dradius * sizeof(unsigned char));
+ /* create st->blob */
+ st->blob = malloc ( st->dradius * sizeof(unsigned char*));
+ for (i = 0; i < st->dradius; ++i)
+ st->blob[i] = malloc( st->dradius * sizeof(unsigned char));
- /* create blub array */
- blub = malloc( iWinHeight * sizeof(unsigned char*));
- for (i = 0; i < iWinHeight; ++i)
- blub[i] = malloc( iWinWidth * sizeof(unsigned char));
+ /* create st->blub array */
+ st->blub = malloc( st->iWinHeight * sizeof(unsigned char*));
+ for (i = 0; i < st->iWinHeight; ++i)
+ st->blub[i] = malloc( st->iWinWidth * sizeof(unsigned char));
- /* create blob */
- for (i = -radius; i < radius; ++i)
+ /* create st->blob */
+ for (i = -st->radius; i < st->radius; ++i)
{
- for (j = -radius; j < radius; ++j)
+ for (j = -st->radius; j < st->radius; ++j)
{
distance_squared = i * i + j * j;
- if (distance_squared <= sradius)
+ if (distance_squared <= st->sradius)
{
/* compute density */
- fraction = (float)distance_squared / (float)sradius;
- blob[i + radius][j + radius] = pow((1.0 - (fraction * fraction)),4.0) * 255.0;
+ fraction = (float)distance_squared / (float)st->sradius;
+ st->blob[i + st->radius][j + st->radius] = pow((1.0 - (fraction * fraction)),4.0) * 255.0;
}
else
{
- blob[i + radius][j + radius] = 0;
+ st->blob[i + st->radius][j + st->radius] = 0;
}
}
}
- for (i = 0; i < nBlobCount; i++)
+ for (i = 0; i < st->nBlobCount; i++)
{
- init_blob(blobs + i);
+ init_blob(st, st->blobs + i);
}
}
-void screenhack(Display *pDisplay, Window Win )
+static void *
+metaballs_init (Display *dpy, Window window)
{
- GC gc;
- signed short iColorCount = 0;
- unsigned long *aiColorVals = NULL;
- XImage *pImage = NULL;
+ struct state *st = (struct state *) calloc (1, sizeof(*st));
#ifdef VERBOSE
- time_t nTime = time( NULL );
- unsigned short iFrame = 0;
+ time_t nTime = time( NULL );
+ unsigned short iFrame = 0;
#endif /* VERBOSE */
- int delay, cycles, i;
- nBlobCount = get_integer_resource( "count", "Integer" );
- if( nBlobCount > 255 ) nBlobCount = 255;
- if( nBlobCount < 2 ) nBlobCount = 2;
+ st->dpy = dpy;
+ st->window = window;
- if( ( blobs = calloc( nBlobCount, sizeof(BLOB) ) ) == NULL )
- {
- fprintf( stderr, "%s: Could not allocate %d Blobs\n", progclass, nBlobCount );
- return;
- }
+ st->nBlobCount = get_integer_resource(st->dpy, "count", "Integer" );
+ if( st->nBlobCount > 255 ) st->nBlobCount = 255;
+ if( st->nBlobCount < 2 ) st->nBlobCount = 2;
+
+ if( ( st->blobs = calloc( st->nBlobCount, sizeof(BLOB) ) ) == NULL )
+ {
+ fprintf( stderr, "%s: Could not allocate %d Blobs\n", progname, st->nBlobCount );
+ abort();
+ }
#ifdef VERBOSE
- printf( "%s: Allocated %d Blobs\n", progclass, nBlobCount );
+ printf( "%s: Allocated %d Blobs\n", progname, st->nBlobCount );
#endif /* VERBOSE */
- Initialize( pDisplay, Win, &gc, &pImage );
+ Initialize( st );
- delay = get_integer_resource( "delay", "Integer" );
- cycles = get_integer_resource( "cycles", "Integer" );
- i = cycles;
+ st->delay = get_integer_resource(st->dpy, "delay", "Integer" );
+ st->cycles = get_integer_resource(st->dpy, "cycles", "Integer" );
- while( 1 )
- {
- screenhack_handle_events( pDisplay );
+ st->draw_i = -1;
+ return st;
+}
- if( i++ >= cycles )
- {
- XWindowAttributes XWinAttribs;
- XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
-
- memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
- XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColorCount, 0 );
- free( aiColorVals );
- aiColorVals = SetPalette( pDisplay, Win, sColor, &iColorCount );
- XClearWindow( pDisplay, Win );
- for (i = 0; i < nBlobCount; i++)
- {
- init_blob(blobs + i);
- }
- i = 0;
- }
- Execute( pDisplay, Win, &gc, pImage, iColorCount - 1, aiColorVals );
- if( delay && !(i % 4) )
- usleep(delay);
+static unsigned long
+metaballs_draw (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+
+ if( st->draw_i < 0 || st->draw_i++ >= st->cycles )
+ {
+ int i;
+ XWindowAttributes XWinAttribs;
+ XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
+
+ memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height );
+ XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, st->iColorCount, 0 );
+ free( st->aiColorVals );
+ st->aiColorVals = SetPalette( st );
+ XClearWindow( st->dpy, st->window );
+ for (i = 0; i < st->nBlobCount; i++)
+ {
+ init_blob(st, st->blobs + i);
+ }
+ st->draw_i = 0;
+ }
+
+ Execute( st );
#ifdef VERBOSE
- iFrame++;
- if( nTime - time( NULL ) )
- {
- printf( "%s: %d FPS\n", progclass, iFrame );
- nTime = time( NULL );
- iFrame = 0;
- }
+ iFrame++;
+ if( nTime - time( NULL ) )
+ {
+ printf( "%s: %d FPS\n", progname, iFrame );
+ nTime = time( NULL );
+ iFrame = 0;
+ }
#endif /* VERBOSE */
- }
- free( pImage->data );
- XDestroyImage( pImage );
- free( aiColorVals );
- free( blobs );
- for (i = 0; i < iWinHeight; ++i)
- free( blub[i] );
- free( blub );
- for (i = 0; i < dradius; ++i)
- free( blob[i] );
- free( blob );
+ return st->delay;
+}
+
+
+static void
+metaballs_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+}
+
+static Bool
+metaballs_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ return False;
}
+static void
+metaballs_free (Display *dpy, Window window, void *closure)
+{
+#if 0
+ struct state *st = (struct state *) closure;
+ free( st->pImage->data );
+ XDestroyImage( st->pImage );
+ free( st->aiColorVals );
+ free( st->blobs );
+ for (i = 0; i < st->iWinHeight; ++i)
+ free( st->blub[i] );
+ free( st->blub );
+ for (i = 0; i < st->dradius; ++i)
+ free( st->blob[i] );
+ free( st->blob );
+#endif
+}
+
+
+static const char *metaballs_defaults [] = {
+ ".background: black",
+ ".foreground: white",
+ "*color: random",
+ "*count: 10",
+ "*cycles: 1000",
+ "*ncolors: 256",
+ "*delay: 10000",
+ "*radius: 100",
+ "*delta: 3",
+ 0
+};
+
+static XrmOptionDescRec metaballs_options [] = {
+ { "-color", ".color", XrmoptionSepArg, 0 },
+ { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
+ { "-count", ".count", XrmoptionSepArg, 0 },
+ { "-delay", ".delay", XrmoptionSepArg, 0 },
+ { "-cycles", ".cycles", XrmoptionSepArg, 0 },
+ { "-radius", ".radius", XrmoptionSepArg, 0 },
+ { "-delta", ".delta", XrmoptionSepArg, 0 },
+ { 0, 0, 0, 0 }
+};
+
+
+XSCREENSAVER_MODULE ("MetaBalls", metaballs)
/* End of Module - "metaballs.c" */