1 /* Eruption, 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 - "eruption.c"
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)
19 #include "screenhack.h"
20 #include <X11/Xutil.h>
24 char *progclass = "Eruption";
39 XrmOptionDescRec 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 },
50 /* Slightly whacked, for better explosions
55 static int sin_cache[PI_2000];
56 static int cos_cache[PI_2000];
58 /*particle structure*/
61 short xpos, ypos, xdir, ydir;
62 unsigned char colorindex;
66 static PARTICLE *particles;
67 static unsigned short iWinWidth, iWinHeight;
68 static unsigned char **fire;
69 static unsigned short nParticleCount;
70 static unsigned char xdelta, ydelta, decay;
71 static signed char gravity;
72 static signed short heat;
76 { /*needs to be run once. Could easily be */
77 int i; /*reimplemented to run and cache at compile-time,*/
79 for (i=0; i<PI_2000; i++)
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);
91 void init_particle(PARTICLE* particle, signed short iColorCount, unsigned short xcenter, unsigned short ycenter)
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;
102 static void Execute( Display *pDisplay,
104 GC *pGC, XImage *pImage,
105 signed short iColorCount, unsigned long *aiColorVals )
110 /* move and draw particles into fire array */
112 for (i = 0; i < nParticleCount; i++)
114 if (!particles[i].dead)
116 particles[i].xpos += particles[i].xdir;
117 particles[i].ypos += particles[i].ydir;
119 /* is particle dead? */
121 if (particles[i].colorindex == 0)
123 particles[i].dead = 1;
127 if (particles[i].xpos < 1)
129 particles[i].xpos = 1;
130 particles[i].xdir = -particles[i].xdir - 4;
131 particles[i].colorindex = iColorCount;
133 else if (particles[i].xpos >= iWinWidth - 2)
135 particles[i].xpos = iWinWidth - 2;
136 particles[i].xdir = -particles[i].xdir + 4;
137 particles[i].colorindex = iColorCount;
140 if (particles[i].ypos < 1)
142 particles[i].ypos = 1;
143 particles[i].ydir = -particles[i].ydir;
144 particles[i].colorindex = iColorCount;
146 else if (particles[i].ypos >= iWinHeight - 3)
148 particles[i].ypos = iWinHeight- 3;
149 particles[i].ydir = (-particles[i].ydir >> 2) - (random() % 2);
150 particles[i].colorindex = iColorCount;
153 /* gravity kicks in */
154 particles[i].ydir += gravity;
156 /* particle cools off */
157 particles[i].colorindex--;
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;
168 /* create fire effect */
169 for (i = 0; i < iWinHeight; i++)
171 for (j = 0; j < iWinWidth; j++)
173 if (j + 1 >= iWinWidth)
176 temp = fire[i][j + 1];
179 temp += fire[i][j - 1];
183 temp += fire[i - 1][j];
185 temp += fire[i - 1][j - 1];
186 if (j + 1 < iWinWidth)
187 temp += fire[i - 1][j + 1];
190 if (i + 1 < iWinHeight)
192 temp += fire[i + 1][j];
193 if (j + 1 < iWinWidth)
194 temp += fire[i + 1][j + 1];
196 temp += fire[i + 1][j - 1];
212 memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
214 /* draw fire array to screen */
215 for (i = 0; i < iWinHeight; ++i)
217 for (j = 0; j < iWinWidth; ++j)
220 XPutPixel( pImage, j, i, aiColorVals[ fire[i][j] ] );
223 XPutImage( pDisplay, MainWindow, *pGC, pImage,
224 0,0,0,0, iWinWidth, iWinHeight );
225 XSync( pDisplay, False );
228 static unsigned long * SetPalette(Display *pDisplay, Window Win, signed short *piColorCount )
230 XWindowAttributes XWinAttribs;
231 XColor Color, *aColors;
232 unsigned long *aiColorVals;
235 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
237 *piColorCount = get_integer_resource( "ncolors", "Integer" );
238 if( *piColorCount < 16 ) *piColorCount = 16;
239 if( *piColorCount > 255 ) *piColorCount = 256;
241 aColors = calloc( *piColorCount, sizeof(XColor) );
242 aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
244 Color.red = Color.green = Color.blue = 65535 / *piColorCount;
246 /* create fire palette */
247 for( iColor=0; iColor < *piColorCount; iColor++ )
249 if (iColor < *piColorCount >> 3)
252 aColors[iColor].red = 0;
253 aColors[iColor].green = 0;
254 aColors[iColor].blue = Color.blue * (iColor << 1);
256 else if (iColor < *piColorCount >> 2)
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);
264 else if (iColor < (*piColorCount >> 2) + (*piColorCount >> 3))
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;
272 else if (iColor < *piColorCount >> 1)
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;
283 aColors[iColor].red = aColors[iColor].green = aColors[iColor].blue = 65535;
286 if( !XAllocColor( pDisplay, XWinAttribs.colormap, &aColors[ iColor ] ) )
288 /* start all over with less colors */
289 XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColor, 0 );
293 aColors = calloc( *piColorCount, sizeof(XColor) );
294 aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
298 aiColorVals[ iColor ] = aColors[ iColor ].pixel;
301 if (heat < *piColorCount)
302 *piColorCount = heat;
306 XSetWindowBackground( pDisplay, Win, aiColorVals[ 0 ] );
312 static void Initialize( Display *pDisplay, Window Win, GC *pGC, XImage **ppImage )
315 XWindowAttributes XWinAttribs;
316 int iBitsPerPixel, i;
318 /* Create the Image for drawing */
319 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
321 /* Find the preferred bits-per-pixel. (jwz) */
324 XPixmapFormatValues *pfv = XListPixmapFormats( pDisplay, &pfvc );
325 for( i=0; i<pfvc; i++ )
326 if( pfv[ i ].depth == XWinAttribs.depth )
328 iBitsPerPixel = pfv[ i ].bits_per_pixel;
336 *pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
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);
342 iWinWidth = XWinAttribs.width;
343 iWinHeight = XWinAttribs.height;
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));
350 /*create particles */
351 particles = malloc (nParticleCount * sizeof(PARTICLE));
354 void screenhack(Display *pDisplay, Window Win )
356 XWindowAttributes XWinAttribs;
358 signed short iColorCount = 0;
359 unsigned long *aiColorVals = NULL;
360 unsigned short sum = 0;
361 XImage *pImage = NULL;
363 time_t nTime = time( NULL );
364 unsigned short iFrame = 0;
366 int delay, cycles, i;
368 nParticleCount = get_integer_resource( "particles", "Integer" );
369 if (nParticleCount < 100)
370 nParticleCount = 100;
371 if (nParticleCount > 2000)
372 nParticleCount = 2000;
374 decay = get_integer_resource( "cooloff", "Integer" );
380 gravity = get_integer_resource( "gravity", "Integer" );
386 heat = get_integer_resource( "heat", "Integer" );
393 printf( "%s: Allocated %d particles\n", progclass, nParticleCount );
396 Initialize( pDisplay, Win, &gc, &pImage );
399 while (sum < (iWinHeight >> 1) - SPREAD)
406 while (sum < (iWinWidth >> 3))
412 delay = get_integer_resource( "delay", "Integer" );
413 cycles = get_integer_resource( "cycles", "Integer" );
418 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
419 XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColorCount, 0 );
421 aiColorVals = SetPalette( pDisplay, Win, &iColorCount );
422 XClearWindow( pDisplay, Win );
423 memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
427 screenhack_handle_events( pDisplay );
431 /* compute random center */
432 unsigned short xcenter, ycenter;
433 xcenter = random() % iWinWidth;
434 ycenter = random() % iWinHeight;
436 for (i = 0; i < nParticleCount; i++)
437 init_particle(particles + i, iColorCount - 1, xcenter, ycenter);
441 Execute( pDisplay, Win, &gc, pImage, iColorCount - 1, aiColorVals );
443 if( delay && !(i % 4) )
448 if( nTime - time( NULL ) )
450 printf( "%s: %d FPS\n", progclass, iFrame );
451 nTime = time( NULL );
457 free( pImage->data );
458 XDestroyImage( pImage );
460 for (i = 0; i < iWinHeight; ++i)
466 /* End of Module - "eruption.c" */