1
/* MetaBalls, Copyright (c) 2002-2003 W.P. van Paassen <peter@paassen.tmfweb.nl>
3
* Permission to use, copy, modify, distribute, and sell this software and its
4
* documentation for any purpose is hereby granted without fee, provided that
5
* the above copyright notice appear in all copies and that both that
6
* copyright notice and this permission notice appear in supporting
7
* documentation. No representations are made about the suitability of this
8
* software for any purpose. It is provided "as is" without express or
11
* Module - "metaballs.c"
13
* [01/24/03] - W.P. van Paassen: Additional features
14
* [12/29/02] - W.P. van Paassen: Port to X for use with XScreenSaver, the shadebob hack by Shane Smit was used as a template
15
* [12/26/02] - W.P. van Paassen: Creation for the Demo Effects Collection (http://demo-effects.sourceforge.net)
19
#include "screenhack.h"
20
#include <X11/Xutil.h>
24
char *progclass = "Metaballs";
39
XrmOptionDescRec options [] = {
40
{ "-color", ".color", XrmoptionSepArg, 0 },
41
{ "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
42
{ "-count", ".count", XrmoptionSepArg, 0 },
43
{ "-delay", ".delay", XrmoptionSepArg, 0 },
44
{ "-cycles", ".cycles", XrmoptionSepArg, 0 },
45
{ "-radius", ".radius", XrmoptionSepArg, 0 },
46
{ "-delta", ".delta", XrmoptionSepArg, 0 },
50
static unsigned short iWinWidth, iWinHeight;
59
static unsigned int nBlobCount;
60
static unsigned char radius;
61
static unsigned char delta;
62
static unsigned char dradius;
63
static unsigned short sradius;
64
static unsigned char **blob;
66
static unsigned char **blub;
69
#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
71
static void init_blob(BLOB *blob)
73
blob->xpos = iWinWidth/4 + BELLRAND(iWinWidth/2) - radius;
74
blob->ypos = iWinHeight/4 + BELLRAND(iWinHeight/2) - radius;
77
static void Execute( Display *pDisplay,
79
GC *pGC, XImage *pImage,
80
signed short iColorCount, unsigned long *aiColorVals )
84
/* clear blub array */
85
for (i = 0; i < iWinHeight; ++i)
86
memset(blub[i], 0, iWinWidth * sizeof(unsigned char));
89
for (i = 0; i < nBlobCount; i++)
91
blobs[i].xpos += -delta + (int)((delta + .5f) * frand(2.0));
92
blobs[i].ypos += -delta + (int)((delta + .5f) * frand(2.0));
95
/* draw blobs to blub array */
96
for (k = 0; k < nBlobCount; ++k)
98
if (blobs[k].ypos > -dradius && blobs[k].xpos > -dradius && blobs[k].ypos < iWinHeight && blobs[k].xpos < iWinWidth)
100
for (i = 0; i < dradius; ++i)
102
if (blobs[k].ypos + i >= 0 && blobs[k].ypos + i < iWinHeight)
104
for (j = 0; j < dradius; ++j)
106
if (blobs[k].xpos + j >= 0 && blobs[k].xpos + j < iWinWidth)
108
if (blub[blobs[k].ypos + i][blobs[k].xpos + j] < iColorCount)
110
if (blub[blobs[k].ypos + i][blobs[k].xpos + j] + blob[i][j] > iColorCount)
111
blub[blobs[k].ypos + i][blobs[k].xpos + j] = iColorCount;
113
blub[blobs[k].ypos + i][blobs[k].xpos + j] += blob[i][j];
121
init_blob(blobs + k);
124
memset( pImage->data, 0, pImage->bytes_per_line * pImage->height);
126
/* draw blub array to screen */
127
for (i = 0; i < iWinHeight; ++i)
129
for (j = 0; j < iWinWidth; ++j)
131
if (aiColorVals[blub[i][j]] > 0)
132
XPutPixel( pImage, j, i, aiColorVals[blub[i][j]] );
136
XPutImage( pDisplay, MainWindow, *pGC, pImage,
137
0, 0, 0, 0, iWinWidth, iWinHeight );
138
XSync( pDisplay, False );
141
static unsigned long * SetPalette(Display *pDisplay, Window Win, char *sColor, signed short *piColorCount )
143
XWindowAttributes XWinAttribs;
144
XColor Color, *aColors;
145
unsigned long *aiColorVals;
149
XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
151
Color.red = random() % 0xFFFF;
152
Color.green = random() % 0xFFFF;
153
Color.blue = random() % 0xFFFF;
155
if( strcasecmp( sColor, "random" ) && !XParseColor( pDisplay, XWinAttribs.colormap, sColor, &Color ) )
156
fprintf( stderr, "%s: color %s not found in database. Choosing to random...\n", progname, sColor );
159
printf( "%s: Base color (RGB): <%d, %d, %d>\n", progclass, Color.red, Color.green, Color.blue );
162
*piColorCount = get_integer_resource( "ncolors", "Integer" );
163
if( *piColorCount < 2 ) *piColorCount = 2;
164
if( *piColorCount > 255 ) *piColorCount = 255;
166
aColors = calloc( *piColorCount, sizeof(XColor) );
167
aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
169
for( iColor=0; iColor<*piColorCount; iColor++ )
171
nHalfColors = *piColorCount / 2.0F;
172
/* Black -> Base Color */
173
if( iColor < (*piColorCount/2) )
175
aColors[ iColor ].red = ( Color.red / nHalfColors ) * iColor;
176
aColors[ iColor ].green = ( Color.green / nHalfColors ) * iColor;
177
aColors[ iColor ].blue = ( Color.blue / nHalfColors ) * iColor;
179
/* Base Color -> White */
182
aColors[ iColor ].red = ( ( ( 0xFFFF - Color.red ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.red;
183
aColors[ iColor ].green = ( ( ( 0xFFFF - Color.green ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.green;
184
aColors[ iColor ].blue = ( ( ( 0xFFFF - Color.blue ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.blue;
187
if( !XAllocColor( pDisplay, XWinAttribs.colormap, &aColors[ iColor ] ) )
189
/* start all over with less colors */
190
XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColor, 0 );
195
if (*piColorCount < 6)
197
fprintf (stderr, "%s: insufficient colors!\n",
202
aColors = calloc( *piColorCount, sizeof(XColor) );
203
aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
207
aiColorVals[ iColor ] = aColors[ iColor ].pixel;
212
XSetWindowBackground( pDisplay, Win, aiColorVals[ 0 ] );
218
static void Initialize( Display *pDisplay, Window Win, GC *pGC, XImage **ppImage )
221
XWindowAttributes XWinAttribs;
222
int iBitsPerPixel, i, j;
223
unsigned int distance_squared;
226
/* Create the Image for drawing */
227
XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
229
/* Find the preferred bits-per-pixel. (jwz) */
232
XPixmapFormatValues *pfv = XListPixmapFormats( pDisplay, &pfvc );
233
for( i=0; i<pfvc; i++ )
234
if( pfv[ i ].depth == XWinAttribs.depth )
236
iBitsPerPixel = pfv[ i ].bits_per_pixel;
244
*pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
246
*ppImage = XCreateImage( pDisplay, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
247
XWinAttribs.width, XWinAttribs.height, BitmapPad( pDisplay ), 0 );
248
(*ppImage)->data = calloc((*ppImage)->bytes_per_line, (*ppImage)->height);
250
iWinWidth = XWinAttribs.width;
251
iWinHeight = XWinAttribs.height;
253
/* Get the base color. */
254
sColor = get_string_resource( "color", "Color" );
257
delta = get_integer_resource( "delta", "Integer" );
263
/* Get the radius. */
264
radius = get_integer_resource( "radius", "Integer" );
270
radius = (radius / 100.0) * (iWinHeight >> 3);
271
if (radius >= 128) /* should use UCHAR_MAX? */
272
radius = 127; /* dradius should fit in u_char */
274
dradius = radius * 2;
275
sradius = radius * radius;
278
blob = malloc ( dradius * sizeof(unsigned char*));
279
for (i = 0; i < dradius; ++i)
280
blob[i] = malloc( dradius * sizeof(unsigned char));
282
/* create blub array */
283
blub = malloc( iWinHeight * sizeof(unsigned char*));
284
for (i = 0; i < iWinHeight; ++i)
285
blub[i] = malloc( iWinWidth * sizeof(unsigned char));
288
for (i = -radius; i < radius; ++i)
290
for (j = -radius; j < radius; ++j)
292
distance_squared = i * i + j * j;
293
if (distance_squared <= sradius)
295
/* compute density */
296
fraction = (float)distance_squared / (float)sradius;
297
blob[i + radius][j + radius] = pow((1.0 - (fraction * fraction)),4.0) * 255.0;
301
blob[i + radius][j + radius] = 0;
306
for (i = 0; i < nBlobCount; i++)
308
init_blob(blobs + i);
312
void screenhack(Display *pDisplay, Window Win )
315
signed short iColorCount = 0;
316
unsigned long *aiColorVals = NULL;
317
XImage *pImage = NULL;
319
time_t nTime = time( NULL );
320
unsigned short iFrame = 0;
322
int delay, cycles, i;
324
nBlobCount = get_integer_resource( "count", "Integer" );
325
if( nBlobCount > 255 ) nBlobCount = 255;
326
if( nBlobCount < 2 ) nBlobCount = 2;
328
if( ( blobs = calloc( nBlobCount, sizeof(BLOB) ) ) == NULL )
330
fprintf( stderr, "%s: Could not allocate %d Blobs\n", progclass, nBlobCount );
334
printf( "%s: Allocated %d Blobs\n", progclass, nBlobCount );
337
Initialize( pDisplay, Win, &gc, &pImage );
339
delay = get_integer_resource( "delay", "Integer" );
340
cycles = get_integer_resource( "cycles", "Integer" );
345
screenhack_handle_events( pDisplay );
349
XWindowAttributes XWinAttribs;
350
XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
352
memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
353
XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColorCount, 0 );
355
aiColorVals = SetPalette( pDisplay, Win, sColor, &iColorCount );
356
XClearWindow( pDisplay, Win );
357
for (i = 0; i < nBlobCount; i++)
359
init_blob(blobs + i);
364
Execute( pDisplay, Win, &gc, pImage, iColorCount - 1, aiColorVals );
366
if( delay && !(i % 4) )
371
if( nTime - time( NULL ) )
373
printf( "%s: %d FPS\n", progclass, iFrame );
374
nTime = time( NULL );
380
free( pImage->data );
381
XDestroyImage( pImage );
384
for (i = 0; i < iWinHeight; ++i)
387
for (i = 0; i < dradius; ++i)
393
/* End of Module - "metaballs.c" */