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"
23 /* Slightly whacked, for better explosions
28 /*particle structure*/
31 short xpos, ypos, xdir, ydir;
32 unsigned char colorindex;
40 int sin_cache[PI_2000];
41 int cos_cache[PI_2000];
44 unsigned short iWinWidth, iWinHeight;
46 unsigned short nParticleCount;
47 unsigned char xdelta, ydelta, decay;
53 signed short iColorCount;
54 unsigned long *aiColorVals;
61 cache(struct state *st) /* jwz */
62 { /*needs to be run once. Could easily be */
63 int i; /*reimplemented to run and cache at compile-time,*/
65 for (i=0; i<PI_2000; i++)
67 dA=sin(((double) (random() % (PI_2000/2)))/1000.0);
68 /*Emulation of spherical distribution*/
69 dA+=asin(frand(1.0))/M_PI_2*0.1;
70 /*Approximating the integration of the binominal, for
71 well-distributed randomness*/
72 st->cos_cache[i]=-abs((int) (cos(((double)i)/1000.0)*dA*st->ydelta));
73 st->sin_cache[i]=(int) (sin(((double)i)/1000.0)*dA*st->xdelta);
77 static void init_particle(struct state *st, PARTICLE* particle, unsigned short xcenter, unsigned short ycenter)
79 int v = random() % PI_2000;
80 particle->xpos = xcenter - SPREAD + (random() % (SPREAD * 2));
81 particle->ypos = ycenter - SPREAD + (random() % (SPREAD * 2));;
82 particle->xdir = st->sin_cache[v];
83 particle->ydir = st->cos_cache[v];
84 particle->colorindex = st->iColorCount-1;
88 static void Execute( struct state *st )
93 /* move and draw particles into st->fire array */
95 for (i = 0; i < st->nParticleCount; i++)
97 if (!st->particles[i].dead)
99 st->particles[i].xpos += st->particles[i].xdir;
100 st->particles[i].ypos += st->particles[i].ydir;
102 /* is particle dead? */
104 if (st->particles[i].colorindex == 0)
106 st->particles[i].dead = 1;
110 if (st->particles[i].xpos < 1)
112 st->particles[i].xpos = 1;
113 st->particles[i].xdir = -st->particles[i].xdir - 4;
114 st->particles[i].colorindex = st->iColorCount;
116 else if (st->particles[i].xpos >= st->iWinWidth - 2)
118 st->particles[i].xpos = st->iWinWidth - 2;
119 st->particles[i].xdir = -st->particles[i].xdir + 4;
120 st->particles[i].colorindex = st->iColorCount;
123 if (st->particles[i].ypos < 1)
125 st->particles[i].ypos = 1;
126 st->particles[i].ydir = -st->particles[i].ydir;
127 st->particles[i].colorindex = st->iColorCount;
129 else if (st->particles[i].ypos >= st->iWinHeight - 3)
131 st->particles[i].ypos = st->iWinHeight- 3;
132 st->particles[i].ydir = (-st->particles[i].ydir >> 2) - (random() % 2);
133 st->particles[i].colorindex = st->iColorCount;
136 /* st->gravity kicks in */
137 st->particles[i].ydir += st->gravity;
139 /* particle cools off */
140 st->particles[i].colorindex--;
143 st->fire[st->particles[i].ypos][st->particles[i].xpos] = st->particles[i].colorindex;
144 st->fire[st->particles[i].ypos][st->particles[i].xpos - 1] = st->particles[i].colorindex;
145 st->fire[st->particles[i].ypos + 1][st->particles[i].xpos] = st->particles[i].colorindex;
146 st->fire[st->particles[i].ypos - 1][st->particles[i].xpos] = st->particles[i].colorindex;
147 st->fire[st->particles[i].ypos][st->particles[i].xpos + 1] = st->particles[i].colorindex;
151 /* create st->fire effect */
152 for (i = 0; i < st->iWinHeight; i++)
154 for (j = 0; j < st->iWinWidth; j++)
156 if (j + 1 >= st->iWinWidth)
159 temp = st->fire[i][j + 1];
162 temp += st->fire[i][j - 1];
166 temp += st->fire[i - 1][j];
168 temp += st->fire[i - 1][j - 1];
169 if (j + 1 < st->iWinWidth)
170 temp += st->fire[i - 1][j + 1];
173 if (i + 1 < st->iWinHeight)
175 temp += st->fire[i + 1][j];
176 if (j + 1 < st->iWinWidth)
177 temp += st->fire[i + 1][j + 1];
179 temp += st->fire[i + 1][j - 1];
184 if (temp > st->decay)
191 st->fire[i][j] = temp;
195 memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height );
197 /* draw st->fire array to screen */
198 for (i = 0; i < st->iWinHeight; ++i)
200 for (j = 0; j < st->iWinWidth; ++j)
202 if (st->fire[i][j] > 0)
203 XPutPixel( st->pImage, j, i, st->aiColorVals[ st->fire[i][j] ] );
206 XPutImage( st->dpy, st->window, st->gc, st->pImage,
207 0,0,0,0, st->iWinWidth, st->iWinHeight );
210 static unsigned long * SetPalette(struct state *st)
212 XWindowAttributes XWinAttribs;
213 XColor Color, *aColors;
216 XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
218 st->iColorCount = get_integer_resource(st->dpy, "ncolors", "Integer" );
219 if( st->iColorCount < 16 ) st->iColorCount = 16;
220 if( st->iColorCount > 255 ) st->iColorCount = 256;
222 aColors = calloc( st->iColorCount, sizeof(XColor) );
223 st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) );
225 Color.red = Color.green = Color.blue = 65535 / st->iColorCount;
227 /* create st->fire palette */
228 for( iColor=0; iColor < st->iColorCount; iColor++ )
230 if (iColor < st->iColorCount >> 3)
233 aColors[iColor].red = 0;
234 aColors[iColor].green = 0;
235 aColors[iColor].blue = Color.blue * (iColor << 1);
237 else if (iColor < st->iColorCount >> 2)
240 signed short temp = (iColor - (st->iColorCount >> 3));
241 aColors[iColor].red = Color.red * (temp << 3);
242 aColors[iColor].green = 0;
243 aColors[iColor].blue = 16383 - Color.blue * (temp << 1);
245 else if (iColor < (st->iColorCount >> 2) + (st->iColorCount >> 3))
248 signed short temp = (iColor - (st->iColorCount >> 2)) << 3;
249 aColors[iColor].red = 65535;
250 aColors[iColor].green = Color.green * temp;
251 aColors[iColor].blue = 0;
253 else if (iColor < st->iColorCount >> 1)
255 /* yellow to white */
256 signed int temp = (iColor - ((st->iColorCount >> 2) + (st->iColorCount >> 3))) << 3;
257 aColors[iColor].red = 65535;
258 aColors[iColor].green = 65535;
259 aColors[iColor].blue = Color.blue * temp;
264 aColors[iColor].red = aColors[iColor].green = aColors[iColor].blue = 65535;
267 if( !XAllocColor( st->dpy, XWinAttribs.colormap, &aColors[ iColor ] ) )
269 /* start all over with less colors */
270 XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, iColor, 0 );
272 free( st->aiColorVals );
274 aColors = calloc( st->iColorCount, sizeof(XColor) );
275 st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) );
279 st->aiColorVals[ iColor ] = aColors[ iColor ].pixel;
282 if (st->heat < st->iColorCount)
283 st->iColorCount = st->heat;
287 XSetWindowBackground( st->dpy, st->window, st->aiColorVals[ 0 ] );
289 return st->aiColorVals;
293 static void Initialize( struct state *st )
296 XWindowAttributes XWinAttribs;
297 int iBitsPerPixel, i;
299 /* Create the Image for drawing */
300 XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
302 /* Find the preferred bits-per-pixel. (jwz) */
305 XPixmapFormatValues *pfv = XListPixmapFormats( st->dpy, &pfvc );
306 for( i=0; i<pfvc; i++ )
307 if( pfv[ i ].depth == XWinAttribs.depth )
309 iBitsPerPixel = pfv[ i ].bits_per_pixel;
317 st->gc = XCreateGC( st->dpy, st->window, 0, &gcValues );
319 st->pImage = XCreateImage( st->dpy, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
320 XWinAttribs.width, XWinAttribs.height, BitmapPad( st->dpy ), 0 );
321 (st->pImage)->data = calloc((st->pImage)->bytes_per_line, (st->pImage)->height);
323 st->iWinWidth = XWinAttribs.width;
324 st->iWinHeight = XWinAttribs.height;
326 /* create st->fire array */
327 st->fire = calloc( st->iWinHeight, sizeof(unsigned char*));
328 for (i = 0; i < st->iWinHeight; ++i)
329 st->fire[i] = calloc( st->iWinWidth, sizeof(unsigned char));
331 /*create st->particles */
332 st->particles = malloc (st->nParticleCount * sizeof(PARTICLE));
336 eruption_init (Display *dpy, Window window)
338 struct state *st = (struct state *) calloc (1, sizeof(*st));
339 XWindowAttributes XWinAttribs;
340 unsigned short sum = 0;
342 time_t nTime = time( NULL );
343 unsigned short iFrame = 0;
350 st->nParticleCount = get_integer_resource(st->dpy, "particles", "Integer" );
351 if (st->nParticleCount < 100)
352 st->nParticleCount = 100;
353 if (st->nParticleCount > 2000)
354 st->nParticleCount = 2000;
356 st->decay = get_integer_resource(st->dpy, "cooloff", "Integer" );
362 st->gravity = get_integer_resource(st->dpy, "gravity", "Integer" );
363 if (st->gravity < -5)
368 st->heat = get_integer_resource(st->dpy, "heat", "Integer" );
375 printf( "%s: Allocated %d st->particles\n", progclass, st->nParticleCount );
381 while (sum < (st->iWinHeight >> 1) - SPREAD)
388 while (sum < (st->iWinWidth >> 3))
394 st->delay = get_integer_resource(st->dpy, "delay", "Integer" );
395 st->cycles = get_integer_resource(st->dpy, "cycles", "Integer" );
400 XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
401 XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, st->iColorCount, 0 );
402 free( st->aiColorVals );
403 st->aiColorVals = SetPalette( st );
404 XClearWindow( st->dpy, st->window );
405 memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height );
414 eruption_draw (Display *dpy, Window window, void *closure)
416 struct state *st = (struct state *) closure;
418 if( st->draw_i < 0 || st->draw_i++ >= st->cycles )
420 /* compute random center */
421 unsigned short xcenter, ycenter;
422 xcenter = random() % st->iWinWidth;
423 ycenter = random() % st->iWinHeight;
425 for (st->draw_i = 0; st->draw_i < st->nParticleCount; st->draw_i++)
426 init_particle(st, st->particles + st->draw_i, xcenter, ycenter);
434 if( nTime - time( NULL ) )
436 printf( "%s: %d FPS\n", progclass, iFrame );
437 nTime = time( NULL );
447 eruption_reshape (Display *dpy, Window window, void *closure,
448 unsigned int w, unsigned int h)
453 eruption_event (Display *dpy, Window window, void *closure, XEvent *event)
459 eruption_free (Display *dpy, Window window, void *closure)
462 struct state *st = (struct state *) closure;
463 free( st->pImage->data );
464 XDestroyImage( st->pImage );
465 free( st->aiColorVals );
466 for (i = 0; i < st->iWinHeight; ++i)
469 free( st->particles );
474 static const char *eruption_defaults [] = {
475 ".background: black",
476 ".foreground: white",
487 static XrmOptionDescRec eruption_options [] = {
488 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
489 { "-delay", ".delay", XrmoptionSepArg, 0 },
490 { "-cycles", ".cycles", XrmoptionSepArg, 0 },
491 { "-particles", ".particles", XrmoptionSepArg, 0 },
492 { "-cooloff", ".cooloff", XrmoptionSepArg, 0 },
493 { "-gravity", ".gravity", XrmoptionSepArg, 0 },
494 { "-heat", ".heat", XrmoptionSepArg, 0 },
499 XSCREENSAVER_MODULE ("Eruption", eruption)
501 /* End of Module - "eruption.c" */