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

Revision 20148, 12.3 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/* Eruption, 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 - "eruption.c"
12 *
13 * [02-2003] - W.P. van Paassen: Improvements, added some code of jwz from the pyro hack for a spherical distribution of the particles
14 * [01-2003] - W.P. van Paassen: Port to X for use with XScreenSaver, the shadebob hack by Shane Smit was used as a template
15 * [04-2002] - 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 = "Eruption";
25
26char *defaults [] = {
27  ".background: black",
28  ".foreground: white",
29  "*cycles:   80",
30  "*ncolors:  256",
31  "*delay:    5000",
32  "*particles: 300",
33  "*cooloff: 2",
34  "*gravity: 1",
35  "*heat: 256",
36  0
37};
38
39XrmOptionDescRec options [] = {
40  { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
41  { "-delay",   ".delay",   XrmoptionSepArg, 0 },
42  { "-cycles",  ".cycles",  XrmoptionSepArg, 0 },
43  { "-particles",  ".particles",  XrmoptionSepArg, 0 },
44  { "-cooloff",  ".cooloff",  XrmoptionSepArg, 0 },
45  { "-gravity",  ".gravity",  XrmoptionSepArg, 0 },
46  { "-heat",  ".heat",  XrmoptionSepArg, 0 },
47  { 0, 0, 0, 0 }
48};
49
50/* Slightly whacked, for better explosions
51 */
52#define PI_2000 6284
53#define SPREAD 15
54
55static int sin_cache[PI_2000];
56static int cos_cache[PI_2000];
57
58/*particle structure*/
59typedef struct
60{
61  short xpos, ypos, xdir, ydir;
62  unsigned char colorindex;
63  unsigned char dead;
64} PARTICLE;
65
66static PARTICLE *particles;
67static unsigned short iWinWidth, iWinHeight;
68static unsigned char **fire;
69static unsigned short nParticleCount;
70static unsigned char xdelta, ydelta, decay;
71static signed char gravity;
72static signed short heat;
73
74static void
75cache(void) /* jwz */
76{               /*needs to be run once. Could easily be */
77  int i;        /*reimplemented to run and cache at compile-time,*/
78  double dA;   
79  for (i=0; i<PI_2000; i++)
80    {
81      dA=sin(((double) (random() % (PI_2000/2)))/1000.0);
82      /*Emulation of spherical distribution*/
83      dA+=asin(frand(1.0))/M_PI_2*0.1;
84      /*Approximating the integration of the binominal, for
85        well-distributed randomness*/
86      cos_cache[i]=-abs((int) (cos(((double)i)/1000.0)*dA*ydelta));
87      sin_cache[i]=(int) (sin(((double)i)/1000.0)*dA*xdelta);
88    }
89}
90
91void init_particle(PARTICLE* particle, signed short iColorCount, unsigned short xcenter, unsigned short ycenter)
92{
93  int v = random() % PI_2000;
94  particle->xpos = xcenter - SPREAD + (random() % (SPREAD * 2));
95  particle->ypos = ycenter - SPREAD + (random() % (SPREAD * 2));;
96  particle->xdir = sin_cache[v];
97  particle->ydir = cos_cache[v];
98  particle->colorindex = iColorCount;
99  particle->dead = 0;
100}
101
102static void Execute( Display *pDisplay,
103                     Window MainWindow,
104                     GC *pGC, XImage *pImage,
105                     signed short iColorCount, unsigned long *aiColorVals )
106{
107  int i, j;
108  unsigned int temp;
109
110  /* move and draw particles into fire array */
111 
112  for (i = 0; i < nParticleCount; i++)
113    {
114      if (!particles[i].dead)
115        {
116          particles[i].xpos += particles[i].xdir;
117          particles[i].ypos += particles[i].ydir;
118         
119          /* is particle dead? */
120         
121          if (particles[i].colorindex == 0)
122            {
123              particles[i].dead = 1;
124              continue;
125            }
126         
127          if (particles[i].xpos < 1)
128            {
129              particles[i].xpos = 1;
130              particles[i].xdir = -particles[i].xdir - 4;
131              particles[i].colorindex = iColorCount;
132            }
133          else if (particles[i].xpos >= iWinWidth - 2)
134            {
135              particles[i].xpos = iWinWidth - 2;
136              particles[i].xdir = -particles[i].xdir + 4;
137              particles[i].colorindex = iColorCount;
138            }
139         
140          if (particles[i].ypos < 1)
141            {
142              particles[i].ypos = 1;
143              particles[i].ydir = -particles[i].ydir;
144              particles[i].colorindex = iColorCount;
145            }
146          else if (particles[i].ypos >= iWinHeight - 3)
147            {
148              particles[i].ypos = iWinHeight- 3;
149              particles[i].ydir = (-particles[i].ydir >> 2) - (random() % 2);
150              particles[i].colorindex = iColorCount;
151            }
152         
153          /* gravity kicks in */
154          particles[i].ydir += gravity;
155         
156          /* particle cools off */
157          particles[i].colorindex--;
158         
159          /* draw particle */
160          fire[particles[i].ypos][particles[i].xpos] = particles[i].colorindex;
161          fire[particles[i].ypos][particles[i].xpos - 1] = particles[i].colorindex;
162          fire[particles[i].ypos + 1][particles[i].xpos] = particles[i].colorindex;
163          fire[particles[i].ypos - 1][particles[i].xpos] = particles[i].colorindex;
164          fire[particles[i].ypos][particles[i].xpos + 1] = particles[i].colorindex;
165        }
166    }
167 
168  /* create fire effect */
169  for (i = 0; i < iWinHeight; i++)
170    {
171      for (j = 0; j < iWinWidth; j++)
172        {
173          if (j + 1 >= iWinWidth)
174            temp = 0;
175          else
176            temp = fire[i][j + 1];
177
178          if (j - 1 >= 0) 
179            temp += fire[i][j - 1];
180
181          if (i - 1 >= 0)
182            {
183              temp += fire[i - 1][j];
184              if (j - 1 >= 0)
185                temp += fire[i - 1][j - 1];
186              if (j + 1 < iWinWidth)
187                temp += fire[i - 1][j + 1];
188            }
189         
190          if (i + 1 < iWinHeight)
191            {
192              temp += fire[i + 1][j];
193              if (j + 1 < iWinWidth)
194                temp += fire[i + 1][j + 1];
195              if (j - 1 >= 0)
196                temp += fire[i + 1][j - 1];
197            }
198         
199          temp >>= 3;
200         
201          if (temp > decay)
202            {
203              temp -= decay;
204            }
205          else
206            temp = 0;
207         
208          fire[i][j] = temp;
209        }
210    }
211 
212  memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
213 
214  /* draw fire array to screen */
215  for (i = 0; i < iWinHeight; ++i)
216    {
217      for (j = 0; j < iWinWidth; ++j)
218        {
219          if (fire[i][j] > 0)
220            XPutPixel( pImage, j, i, aiColorVals[ fire[i][j] ] );
221        }
222    }
223  XPutImage( pDisplay, MainWindow, *pGC, pImage,
224             0,0,0,0, iWinWidth, iWinHeight );
225  XSync( pDisplay, False );
226}
227
228static unsigned long * SetPalette(Display *pDisplay, Window Win, signed short *piColorCount )
229{
230        XWindowAttributes XWinAttribs;
231        XColor Color, *aColors;
232        unsigned long *aiColorVals;
233        signed short iColor;
234
235        XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
236       
237        *piColorCount = get_integer_resource( "ncolors", "Integer" );
238        if( *piColorCount < 16 )        *piColorCount = 16;
239        if( *piColorCount > 255 )       *piColorCount = 256;
240
241        aColors    = calloc( *piColorCount, sizeof(XColor) );
242        aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
243       
244        Color.red = Color.green = Color.blue = 65535 / *piColorCount;
245
246        /* create fire palette */
247        for( iColor=0; iColor < *piColorCount; iColor++ )
248        {
249          if (iColor < *piColorCount >> 3)
250            {
251              /* black to blue */
252              aColors[iColor].red = 0;
253              aColors[iColor].green = 0;
254              aColors[iColor].blue = Color.blue * (iColor << 1);
255            }
256          else if (iColor < *piColorCount >> 2)
257            {
258              /* blue to red */
259              signed short temp = (iColor - (*piColorCount >> 3));
260              aColors[iColor].red = Color.red * (temp << 3);
261              aColors[iColor].green = 0;
262              aColors[iColor].blue = 16383 - Color.blue * (temp << 1);
263            }
264          else if (iColor < (*piColorCount >> 2) + (*piColorCount >> 3))
265            {
266              /* red to yellow */
267              signed short temp = (iColor - (*piColorCount >> 2)) << 3;
268              aColors[iColor].red = 65535;
269              aColors[iColor].green = Color.green * temp;
270              aColors[iColor].blue = 0;
271            }
272          else if (iColor < *piColorCount >> 1)
273            {
274              /* yellow to white */
275              signed int temp = (iColor - ((*piColorCount >> 2) + (*piColorCount >> 3))) << 3;
276              aColors[iColor].red = 65535;
277              aColors[iColor].green = 65535;
278              aColors[iColor].blue = Color.blue * temp;
279            }
280          else
281            {
282              /* white */
283              aColors[iColor].red = aColors[iColor].green = aColors[iColor].blue = 65535;
284            }
285
286          if( !XAllocColor( pDisplay, XWinAttribs.colormap, &aColors[ iColor ] ) )
287            {
288              /* start all over with less colors */     
289              XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColor, 0 );
290              free( aColors );
291              free( aiColorVals );
292              (*piColorCount)--;
293              aColors     = calloc( *piColorCount, sizeof(XColor) );
294              aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
295              iColor = -1;
296            }
297          else
298            aiColorVals[ iColor ] = aColors[ iColor ].pixel;
299        }
300
301        if (heat < *piColorCount)
302          *piColorCount = heat;
303       
304        free( aColors );
305
306        XSetWindowBackground( pDisplay, Win, aiColorVals[ 0 ] );
307
308        return aiColorVals;
309}
310
311
312static void Initialize( Display *pDisplay, Window Win, GC *pGC, XImage **ppImage )
313{
314        XGCValues gcValues;
315        XWindowAttributes XWinAttribs;
316        int iBitsPerPixel, i;
317
318        /* Create the Image for drawing */
319        XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
320
321        /* Find the preferred bits-per-pixel. (jwz) */
322        {
323                int pfvc = 0;
324                XPixmapFormatValues *pfv = XListPixmapFormats( pDisplay, &pfvc );
325                for( i=0; i<pfvc; i++ )
326                        if( pfv[ i ].depth == XWinAttribs.depth )
327                        {
328                                iBitsPerPixel = pfv[ i ].bits_per_pixel;
329                                break;
330                        }
331                if( pfv )
332                        XFree (pfv);
333        }
334
335        /*  Create the GC. */
336        *pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
337
338        *ppImage = XCreateImage( pDisplay, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
339                                                          XWinAttribs.width, XWinAttribs.height, BitmapPad( pDisplay ), 0 );
340        (*ppImage)->data = calloc((*ppImage)->bytes_per_line, (*ppImage)->height);
341
342        iWinWidth = XWinAttribs.width;
343        iWinHeight = XWinAttribs.height;
344
345        /* create fire array */
346        fire = calloc( iWinHeight, sizeof(unsigned char*));
347        for (i = 0; i < iWinHeight; ++i)
348          fire[i] = calloc( iWinWidth, sizeof(unsigned char));
349
350        /*create particles */
351        particles = malloc (nParticleCount * sizeof(PARTICLE));
352}
353
354void screenhack(Display *pDisplay, Window Win )
355{
356        XWindowAttributes XWinAttribs;
357        GC gc;
358        signed short iColorCount = 0;
359        unsigned long *aiColorVals = NULL;
360        unsigned short sum = 0;
361        XImage *pImage = NULL;
362#ifdef VERBOSE
363        time_t nTime = time( NULL );
364        unsigned short iFrame = 0;
365#endif  /*  VERBOSE */
366        int delay, cycles, i;
367
368        nParticleCount = get_integer_resource( "particles", "Integer" );
369        if (nParticleCount < 100)
370          nParticleCount = 100;
371        if (nParticleCount > 2000)
372          nParticleCount = 2000;
373
374        decay = get_integer_resource( "cooloff", "Integer" );
375        if (decay <= 0)
376          decay = 0;
377        if (decay > 10)
378          decay = 10;
379
380        gravity = get_integer_resource( "gravity", "Integer" );
381        if (gravity < -5)
382          gravity = -5;
383        if (gravity > 5)
384          gravity = 5;
385
386        heat = get_integer_resource( "heat", "Integer" );
387        if (heat < 64)
388          heat = 64;
389        if (heat > 256)
390          heat = 256;
391
392#ifdef VERBOSE
393        printf( "%s: Allocated %d particles\n", progclass, nParticleCount );
394#endif  /*  VERBOSE */
395
396        Initialize( pDisplay, Win, &gc, &pImage );
397
398        ydelta = 0;
399        while (sum < (iWinHeight >> 1) - SPREAD)
400          {
401            ydelta++;
402            sum += ydelta;
403          }
404
405        sum = 0;
406        while (sum < (iWinWidth >> 3))
407          {
408            xdelta++;
409            sum += xdelta;
410          }
411
412        delay = get_integer_resource( "delay", "Integer" );
413        cycles = get_integer_resource( "cycles", "Integer" );
414        i = cycles;
415
416        cache();
417       
418        XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
419        XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColorCount, 0 );
420        free( aiColorVals );
421        aiColorVals = SetPalette( pDisplay, Win, &iColorCount );
422        XClearWindow( pDisplay, Win );
423        memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
424
425        while( 1 )
426          {
427            screenhack_handle_events( pDisplay );
428           
429            if( i++ >= cycles )
430              {
431                /* compute random center */
432                unsigned short xcenter, ycenter;
433                xcenter = random() % iWinWidth;
434                ycenter = random() % iWinHeight;
435               
436                for (i = 0; i < nParticleCount; i++)
437                  init_particle(particles + i, iColorCount - 1, xcenter, ycenter);
438                i = 0;
439              }
440           
441            Execute( pDisplay, Win, &gc, pImage, iColorCount - 1, aiColorVals );
442           
443            if( delay && !(i % 4) )
444              usleep(delay);
445           
446#ifdef VERBOSE
447            iFrame++;
448            if( nTime - time( NULL ) )
449              {
450                printf( "%s: %d FPS\n", progclass, iFrame );
451                nTime = time( NULL );
452                iFrame = 0;
453              }
454#endif  /*  VERBOSE */
455          }
456       
457        free( pImage->data );
458        XDestroyImage( pImage );
459        free( aiColorVals );
460        for (i = 0; i < iWinHeight; ++i)
461          free( fire[i] );
462        free( fire );
463        free( particles );
464}
465
466/* End of Module - "eruption.c" */
467
Note: See TracBrowser for help on using the repository browser.