source: trunk/third/xscreensaver/hacks/metaballs.c @ 20148

Revision 20148, 10.7 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* MetaBalls, Copyright (c) 2002-2003 W.P. van Paassen <peter@paassen.tmfweb.nl>
2 *
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
9 * implied warranty.
10 *
11 * Module - "metaballs.c"
12 *
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)
16 */
17
18#include <math.h>
19#include "screenhack.h"
20#include <X11/Xutil.h>
21
22/*#define VERBOSE*/
23
24char *progclass = "Metaballs";
25
26char *defaults [] = {
27  ".background: black",
28  ".foreground: white",
29  "*color:    random",
30  "*count:    10",
31  "*cycles:   1000",
32  "*ncolors:  256",
33  "*delay:    5000",
34  "*radius:   100",
35  "*delta:   3",
36  0
37};
38
39XrmOptionDescRec 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 },
47  { 0, 0, 0, 0 }
48};
49
50static unsigned short iWinWidth, iWinHeight;
51static char *sColor;
52
53/*blob structure*/
54typedef struct
55{
56  short xpos,ypos;
57} BLOB;
58
59static unsigned int nBlobCount;
60static unsigned char radius;
61static unsigned char delta;
62static unsigned char dradius;
63static unsigned short sradius;
64static unsigned char **blob;
65static BLOB *blobs;
66static unsigned char **blub;
67
68static void init_blob(BLOB *blob)
69{
70  blob->xpos =  (iWinWidth>> 1) - radius;
71  blob->ypos =  (iWinHeight >> 1) - radius;
72}
73
74static void Execute( Display *pDisplay,
75                     Window MainWindow,
76                     GC *pGC, XImage *pImage,
77                     signed short iColorCount, unsigned long *aiColorVals )
78{
79        unsigned int i, j, k;
80
81        /* clear blub array */
82        for (i = 0; i < iWinHeight; ++i)
83          memset(blub[i], 0, iWinWidth * sizeof(unsigned char));
84
85        /* move blobs */
86        for (i = 0; i < nBlobCount; i++)
87        {
88          blobs[i].xpos += -delta + (int)((delta + .5f) * frand(2.0));
89          blobs[i].ypos += -delta + (int)((delta + .5f) * frand(2.0));
90        }
91
92        /* draw blobs to blub array */
93        for (k = 0; k < nBlobCount; ++k)
94          {
95            if (blobs[k].ypos > -dradius && blobs[k].xpos > -dradius && blobs[k].ypos < iWinHeight && blobs[k].xpos < iWinWidth)
96              {
97                for (i = 0; i < dradius; ++i)
98                  {
99                    if (blobs[k].ypos + i >= 0 && blobs[k].ypos + i < iWinHeight)
100                      {
101                        for (j = 0; j < dradius; ++j)
102                          {
103                            if (blobs[k].xpos + j >= 0 && blobs[k].xpos + j < iWinWidth)
104                              {
105                                if (blub[blobs[k].ypos + i][blobs[k].xpos + j] < iColorCount)
106                                  {
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;
109                                    else
110                                      blub[blobs[k].ypos + i][blobs[k].xpos + j] += blob[i][j];     
111                                  }
112                              }
113                          }
114                      }
115                  }
116              }
117            else
118              init_blob(blobs + k);
119          }
120
121        memset( pImage->data, 0, pImage->bytes_per_line * pImage->height);
122
123        /* draw blub array to screen */
124        for (i = 0; i < iWinHeight; ++i)
125          {
126            for (j = 0; j < iWinWidth; ++j)
127              {
128                if (aiColorVals[blub[i][j]] > 0)
129                  XPutPixel( pImage, j, i, aiColorVals[blub[i][j]] );
130              }
131          }
132
133        XPutImage( pDisplay, MainWindow, *pGC, pImage,
134                   0, 0, 0, 0, iWinWidth, iWinHeight );
135        XSync( pDisplay, False );
136}
137
138static unsigned long * SetPalette(Display *pDisplay, Window Win, char *sColor, signed short *piColorCount )
139{
140        XWindowAttributes XWinAttribs;
141        XColor Color, *aColors;
142        unsigned long *aiColorVals;
143        signed short iColor;
144        float nHalfColors;
145       
146        XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
147       
148        Color.red =   random() % 0xFFFF;
149        Color.green = random() % 0xFFFF;
150        Color.blue =  random() % 0xFFFF;
151
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 );
154
155#ifdef VERBOSE
156        printf( "%s: Base color (RGB): <%d, %d, %d>\n", progclass, Color.red, Color.green, Color.blue );
157#endif  /*  VERBOSE */
158
159        *piColorCount = get_integer_resource( "ncolors", "Integer" );
160        if( *piColorCount <   2 )       *piColorCount = 2;
161        if( *piColorCount > 255 )       *piColorCount = 255;
162
163        aColors    = calloc( *piColorCount, sizeof(XColor) );
164        aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
165       
166        for( iColor=0; iColor<*piColorCount; iColor++ )
167        {
168                nHalfColors = *piColorCount / 2.0F;
169                /* Black -> Base Color */
170                if( iColor < (*piColorCount/2) )
171                {
172                        aColors[ iColor ].red   = ( Color.red   / nHalfColors ) * iColor;
173                        aColors[ iColor ].green = ( Color.green / nHalfColors ) * iColor;
174                        aColors[ iColor ].blue  = ( Color.blue  / nHalfColors ) * iColor;
175                }
176                /* Base Color -> White */
177                else
178                {
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;
182                }
183
184                if( !XAllocColor( pDisplay, XWinAttribs.colormap, &aColors[ iColor ] ) )
185                {
186                        /* start all over with less colors */   
187                        XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColor, 0 );
188                        free( aColors );
189                        free( aiColorVals );
190                        (*piColorCount)--;
191
192                        if (*piColorCount < 6)
193                          {
194                            fprintf (stderr, "%s: insufficient colors!\n",
195                                     progname);
196                            exit (1);
197                          }
198
199                        aColors     = calloc( *piColorCount, sizeof(XColor) );
200                        aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
201                        iColor = -1;
202                }
203                else
204                        aiColorVals[ iColor ] = aColors[ iColor ].pixel;
205        }
206
207        free( aColors );
208
209        XSetWindowBackground( pDisplay, Win, aiColorVals[ 0 ] );
210
211        return aiColorVals;
212}
213
214
215static void Initialize( Display *pDisplay, Window Win, GC *pGC, XImage **ppImage )
216{
217        XGCValues gcValues;
218        XWindowAttributes XWinAttribs;
219        int iBitsPerPixel, i, j;
220        unsigned int distance_squared;
221        float fraction;
222
223        /* Create the Image for drawing */
224        XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
225
226        /* Find the preferred bits-per-pixel. (jwz) */
227        {
228                int pfvc = 0;
229                XPixmapFormatValues *pfv = XListPixmapFormats( pDisplay, &pfvc );
230                for( i=0; i<pfvc; i++ )
231                        if( pfv[ i ].depth == XWinAttribs.depth )
232                        {
233                                iBitsPerPixel = pfv[ i ].bits_per_pixel;
234                                break;
235                        }
236                if( pfv )
237                        XFree (pfv);
238        }
239
240        /*  Create the GC. */
241        *pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
242
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);
246
247        iWinWidth = XWinAttribs.width;
248        iWinHeight = XWinAttribs.height;
249
250        /*  Get the base color. */
251        sColor = get_string_resource( "color", "Color" );
252
253        /*  Get the delta. */
254        delta = get_integer_resource( "delta", "Integer" );
255        if (delta < 1)
256          delta = 1;
257        else if (delta > 20)
258          delta = 20;
259       
260        /*  Get the radius. */
261        radius = get_integer_resource( "radius", "Integer" );
262        if (radius < 2)
263          radius = 2;
264        if (radius > 100)
265          radius = 100;
266       
267        radius = (radius / 100.0) * (iWinHeight >> 3);
268        if (radius >= 128) /* should use UCHAR_MAX? */
269          radius = 127; /* dradius should fit in u_char */
270
271        dradius = radius * 2;
272        sradius = radius * radius;
273
274        /* create blob */
275        blob = malloc ( dradius * sizeof(unsigned char*));
276        for (i = 0; i < dradius; ++i)
277          blob[i] = malloc( dradius * sizeof(unsigned char));
278
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));
283
284        /* create blob */
285        for (i = -radius; i < radius; ++i)
286          {
287            for (j = -radius; j < radius; ++j)
288              {
289                distance_squared = i * i + j * j;
290                if (distance_squared <= sradius)
291                  {
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;
295                  }
296                else
297                  {
298                    blob[i + radius][j + radius] = 0;
299                  }
300              }   
301          }
302       
303        for (i = 0; i < nBlobCount; i++)
304          {
305            init_blob(blobs + i);
306          }
307}
308
309void screenhack(Display *pDisplay, Window Win )
310{
311        GC gc;
312        signed short iColorCount = 0;
313        unsigned long *aiColorVals = NULL;
314        XImage *pImage = NULL;
315#ifdef VERBOSE
316        time_t nTime = time( NULL );
317        unsigned short iFrame = 0;
318#endif  /*  VERBOSE */
319        int delay, cycles, i;
320
321        nBlobCount = get_integer_resource( "count", "Integer" );
322        if( nBlobCount > 255 ) nBlobCount = 255;
323        if( nBlobCount <  2 ) nBlobCount = 2;
324
325        if( ( blobs = calloc( nBlobCount, sizeof(BLOB) ) ) == NULL )
326        {
327                fprintf( stderr, "%s: Could not allocate %d Blobs\n", progclass, nBlobCount );
328                return;
329        }
330#ifdef VERBOSE
331        printf( "%s: Allocated %d Blobs\n", progclass, nBlobCount );
332#endif  /*  VERBOSE */
333
334        Initialize( pDisplay, Win, &gc, &pImage );
335
336        delay = get_integer_resource( "delay", "Integer" );
337        cycles = get_integer_resource( "cycles", "Integer" );
338        i = cycles;
339
340        while( 1 )
341        {
342                screenhack_handle_events( pDisplay );
343
344                if( i++ >= cycles )
345                {
346                        XWindowAttributes XWinAttribs;
347                        XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
348
349                        memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
350                        XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColorCount, 0 );
351                        free( aiColorVals );
352                        aiColorVals = SetPalette( pDisplay, Win, sColor, &iColorCount );
353                        XClearWindow( pDisplay, Win );
354                        for (i = 0; i < nBlobCount; i++)
355                          {
356                            init_blob(blobs + i);
357                          }
358                        i = 0;
359                }
360
361                Execute( pDisplay, Win, &gc, pImage, iColorCount - 1, aiColorVals );
362
363                if( delay && !(i % 4) )
364                        usleep(delay);
365
366#ifdef VERBOSE
367                iFrame++;
368                if( nTime - time( NULL ) )
369                {
370                        printf( "%s: %d FPS\n", progclass, iFrame );
371                        nTime = time( NULL );
372                        iFrame = 0;
373                }
374#endif  /*  VERBOSE */
375        }
376
377        free( pImage->data );
378        XDestroyImage( pImage );
379        free( aiColorVals );
380        free( blobs );
381        for (i = 0; i < iWinHeight; ++i)
382          free( blub[i] );
383        free( blub );
384        for (i = 0; i < dradius; ++i)
385          free( blob[i] );
386        free( blob );
387}
388
389
390/* End of Module - "metaballs.c" */
391
Note: See TracBrowser for help on using the repository browser.