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 char 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;
68 static void init_blob(BLOB *blob)
70 blob->xpos = (iWinWidth>> 1) - radius;
71 blob->ypos = (iWinHeight >> 1) - radius;
74 static void Execute( Display *pDisplay,
76 GC *pGC, XImage *pImage,
77 signed short iColorCount, unsigned long *aiColorVals )
81 /* clear blub array */
82 for (i = 0; i < iWinHeight; ++i)
83 memset(blub[i], 0, iWinWidth * sizeof(unsigned char));
86 for (i = 0; i < nBlobCount; i++)
88 blobs[i].xpos += -delta + (int)((delta + .5f) * frand(2.0));
89 blobs[i].ypos += -delta + (int)((delta + .5f) * frand(2.0));
92 /* draw blobs to blub array */
93 for (k = 0; k < nBlobCount; ++k)
95 if (blobs[k].ypos > -dradius && blobs[k].xpos > -dradius && blobs[k].ypos < iWinHeight && blobs[k].xpos < iWinWidth)
97 for (i = 0; i < dradius; ++i)
99 if (blobs[k].ypos + i >= 0 && blobs[k].ypos + i < iWinHeight)
101 for (j = 0; j < dradius; ++j)
103 if (blobs[k].xpos + j >= 0 && blobs[k].xpos + j < iWinWidth)
105 if (blub[blobs[k].ypos + i][blobs[k].xpos + j] < iColorCount)
107 if (blub[blobs[k].ypos + i][blobs[k].xpos + j] + blob[i][j] > iColorCount)
108 blub[blobs[k].ypos + i][blobs[k].xpos + j] = iColorCount;
110 blub[blobs[k].ypos + i][blobs[k].xpos + j] += blob[i][j];
118 init_blob(blobs + k);
121 memset( pImage->data, 0, pImage->bytes_per_line * pImage->height);
123 /* draw blub array to screen */
124 for (i = 0; i < iWinHeight; ++i)
126 for (j = 0; j < iWinWidth; ++j)
128 if (aiColorVals[blub[i][j]] > 0)
129 XPutPixel( pImage, j, i, aiColorVals[blub[i][j]] );
133 XPutImage( pDisplay, MainWindow, *pGC, pImage,
134 0, 0, 0, 0, iWinWidth, iWinHeight );
135 XSync( pDisplay, False );
138 static unsigned long * SetPalette(Display *pDisplay, Window Win, char *sColor, signed short *piColorCount )
140 XWindowAttributes XWinAttribs;
141 XColor Color, *aColors;
142 unsigned long *aiColorVals;
146 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
148 Color.red = random() % 0xFFFF;
149 Color.green = random() % 0xFFFF;
150 Color.blue = random() % 0xFFFF;
152 if( strcasecmp( sColor, "random" ) && !XParseColor( pDisplay, XWinAttribs.colormap, sColor, &Color ) )
153 fprintf( stderr, "%s: color %s not found in database. Choosing to random...\n", progname, sColor );
156 printf( "%s: Base color (RGB): <%d, %d, %d>\n", progclass, Color.red, Color.green, Color.blue );
159 *piColorCount = get_integer_resource( "ncolors", "Integer" );
160 if( *piColorCount < 2 ) *piColorCount = 2;
161 if( *piColorCount > 255 ) *piColorCount = 255;
163 aColors = calloc( *piColorCount, sizeof(XColor) );
164 aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
166 for( iColor=0; iColor<*piColorCount; iColor++ )
168 nHalfColors = *piColorCount / 2.0F;
169 /* Black -> Base Color */
170 if( iColor < (*piColorCount/2) )
172 aColors[ iColor ].red = ( Color.red / nHalfColors ) * iColor;
173 aColors[ iColor ].green = ( Color.green / nHalfColors ) * iColor;
174 aColors[ iColor ].blue = ( Color.blue / nHalfColors ) * iColor;
176 /* Base Color -> White */
179 aColors[ iColor ].red = ( ( ( 0xFFFF - Color.red ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.red;
180 aColors[ iColor ].green = ( ( ( 0xFFFF - Color.green ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.green;
181 aColors[ iColor ].blue = ( ( ( 0xFFFF - Color.blue ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.blue;
184 if( !XAllocColor( pDisplay, XWinAttribs.colormap, &aColors[ iColor ] ) )
186 /* start all over with less colors */
187 XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColor, 0 );
192 if (*piColorCount < 6)
194 fprintf (stderr, "%s: insufficient colors!\n",
199 aColors = calloc( *piColorCount, sizeof(XColor) );
200 aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
204 aiColorVals[ iColor ] = aColors[ iColor ].pixel;
209 XSetWindowBackground( pDisplay, Win, aiColorVals[ 0 ] );
215 static void Initialize( Display *pDisplay, Window Win, GC *pGC, XImage **ppImage )
218 XWindowAttributes XWinAttribs;
219 int iBitsPerPixel, i, j;
220 unsigned int distance_squared;
223 /* Create the Image for drawing */
224 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
226 /* Find the preferred bits-per-pixel. (jwz) */
229 XPixmapFormatValues *pfv = XListPixmapFormats( pDisplay, &pfvc );
230 for( i=0; i<pfvc; i++ )
231 if( pfv[ i ].depth == XWinAttribs.depth )
233 iBitsPerPixel = pfv[ i ].bits_per_pixel;
241 *pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
243 *ppImage = XCreateImage( pDisplay, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
244 XWinAttribs.width, XWinAttribs.height, BitmapPad( pDisplay ), 0 );
245 (*ppImage)->data = calloc((*ppImage)->bytes_per_line, (*ppImage)->height);
247 iWinWidth = XWinAttribs.width;
248 iWinHeight = XWinAttribs.height;
250 /* Get the base color. */
251 sColor = get_string_resource( "color", "Color" );
254 delta = get_integer_resource( "delta", "Integer" );
260 /* Get the radius. */
261 radius = get_integer_resource( "radius", "Integer" );
267 radius = (radius / 100.0) * (iWinHeight >> 3);
268 if (radius >= 128) /* should use UCHAR_MAX? */
269 radius = 127; /* dradius should fit in u_char */
271 dradius = radius * 2;
272 sradius = radius * radius;
275 blob = malloc ( dradius * sizeof(unsigned char*));
276 for (i = 0; i < dradius; ++i)
277 blob[i] = malloc( dradius * sizeof(unsigned char));
279 /* create blub array */
280 blub = malloc( iWinHeight * sizeof(unsigned char*));
281 for (i = 0; i < iWinHeight; ++i)
282 blub[i] = malloc( iWinWidth * sizeof(unsigned char));
285 for (i = -radius; i < radius; ++i)
287 for (j = -radius; j < radius; ++j)
289 distance_squared = i * i + j * j;
290 if (distance_squared <= sradius)
292 /* compute density */
293 fraction = (float)distance_squared / (float)sradius;
294 blob[i + radius][j + radius] = pow((1.0 - (fraction * fraction)),4.0) * 255.0;
298 blob[i + radius][j + radius] = 0;
303 for (i = 0; i < nBlobCount; i++)
305 init_blob(blobs + i);
309 void screenhack(Display *pDisplay, Window Win )
312 signed short iColorCount = 0;
313 unsigned long *aiColorVals = NULL;
314 XImage *pImage = NULL;
316 time_t nTime = time( NULL );
317 unsigned short iFrame = 0;
319 int delay, cycles, i;
321 nBlobCount = get_integer_resource( "count", "Integer" );
322 if( nBlobCount > 255 ) nBlobCount = 255;
323 if( nBlobCount < 2 ) nBlobCount = 2;
325 if( ( blobs = calloc( nBlobCount, sizeof(BLOB) ) ) == NULL )
327 fprintf( stderr, "%s: Could not allocate %d Blobs\n", progclass, nBlobCount );
331 printf( "%s: Allocated %d Blobs\n", progclass, nBlobCount );
334 Initialize( pDisplay, Win, &gc, &pImage );
336 delay = get_integer_resource( "delay", "Integer" );
337 cycles = get_integer_resource( "cycles", "Integer" );
342 screenhack_handle_events( pDisplay );
346 XWindowAttributes XWinAttribs;
347 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
349 memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
350 XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColorCount, 0 );
352 aiColorVals = SetPalette( pDisplay, Win, sColor, &iColorCount );
353 XClearWindow( pDisplay, Win );
354 for (i = 0; i < nBlobCount; i++)
356 init_blob(blobs + i);
361 Execute( pDisplay, Win, &gc, pImage, iColorCount - 1, aiColorVals );
363 if( delay && !(i % 4) )
368 if( nTime - time( NULL ) )
370 printf( "%s: %d FPS\n", progclass, iFrame );
371 nTime = time( NULL );
377 free( pImage->data );
378 XDestroyImage( pImage );
381 for (i = 0; i < iWinHeight; ++i)
384 for (i = 0; i < dradius; ++i)
390 /* End of Module - "metaballs.c" */