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 if (st->particles[i].xpos < 1) st->particles[i].xpos = 1;
120 st->particles[i].xdir = -st->particles[i].xdir + 4;
121 st->particles[i].colorindex = st->iColorCount;
124 if (st->particles[i].ypos < 1)
126 st->particles[i].ypos = 1;
127 st->particles[i].ydir = -st->particles[i].ydir;
128 st->particles[i].colorindex = st->iColorCount;
130 else if (st->particles[i].ypos >= st->iWinHeight - 3)
132 st->particles[i].ypos = st->iWinHeight- 3;
133 if (st->particles[i].ypos < 1) st->particles[i].ypos = 1;
134 st->particles[i].ydir = (-st->particles[i].ydir >> 2) - (random() % 2);
135 st->particles[i].colorindex = st->iColorCount;
139 /* st->gravity kicks in */
140 st->particles[i].ydir += st->gravity;
142 /* particle cools off */
143 st->particles[i].colorindex--;
146 if (st->iWinHeight <= 2 || st->iWinWidth <= 2) continue;
147 st->fire[st->particles[i].ypos][st->particles[i].xpos] = st->particles[i].colorindex;
148 st->fire[st->particles[i].ypos][st->particles[i].xpos - 1] = st->particles[i].colorindex;
149 st->fire[st->particles[i].ypos + 1][st->particles[i].xpos] = st->particles[i].colorindex;
150 st->fire[st->particles[i].ypos - 1][st->particles[i].xpos] = st->particles[i].colorindex;
151 st->fire[st->particles[i].ypos][st->particles[i].xpos + 1] = st->particles[i].colorindex;
155 /* create st->fire effect */
156 for (i = 0; i < st->iWinHeight; i++)
158 for (j = 0; j < st->iWinWidth; j++)
160 if (j + 1 >= st->iWinWidth)
163 temp = st->fire[i][j + 1];
166 temp += st->fire[i][j - 1];
170 temp += st->fire[i - 1][j];
172 temp += st->fire[i - 1][j - 1];
173 if (j + 1 < st->iWinWidth)
174 temp += st->fire[i - 1][j + 1];
177 if (i + 1 < st->iWinHeight)
179 temp += st->fire[i + 1][j];
180 if (j + 1 < st->iWinWidth)
181 temp += st->fire[i + 1][j + 1];
183 temp += st->fire[i + 1][j - 1];
188 if (temp > st->decay)
195 st->fire[i][j] = temp;
199 memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height );
201 /* draw st->fire array to screen */
202 for (i = 0; i < st->iWinHeight; ++i)
204 for (j = 0; j < st->iWinWidth; ++j)
206 if (st->fire[i][j] > 0)
207 XPutPixel( st->pImage, j, i, st->aiColorVals[ st->fire[i][j] ] );
210 XPutImage( st->dpy, st->window, st->gc, st->pImage,
211 0,0,0,0, st->iWinWidth, st->iWinHeight );
214 static unsigned long * SetPalette(struct state *st)
216 XWindowAttributes XWinAttribs;
217 XColor Color, *aColors;
220 XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
222 st->iColorCount = get_integer_resource(st->dpy, "ncolors", "Integer" );
223 if( st->iColorCount < 16 ) st->iColorCount = 16;
224 if( st->iColorCount > 255 ) st->iColorCount = 256;
226 aColors = calloc( st->iColorCount, sizeof(XColor) );
227 st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) );
229 Color.red = Color.green = Color.blue = 65535 / st->iColorCount;
231 /* create st->fire palette */
232 for( iColor=0; iColor < st->iColorCount; iColor++ )
234 if (iColor < st->iColorCount >> 3)
237 aColors[iColor].red = 0;
238 aColors[iColor].green = 0;
239 aColors[iColor].blue = Color.blue * (iColor << 1);
241 else if (iColor < st->iColorCount >> 2)
244 signed short temp = (iColor - (st->iColorCount >> 3));
245 aColors[iColor].red = Color.red * (temp << 3);
246 aColors[iColor].green = 0;
247 aColors[iColor].blue = 16383 - Color.blue * (temp << 1);
249 else if (iColor < (st->iColorCount >> 2) + (st->iColorCount >> 3))
252 signed short temp = (iColor - (st->iColorCount >> 2)) << 3;
253 aColors[iColor].red = 65535;
254 aColors[iColor].green = Color.green * temp;
255 aColors[iColor].blue = 0;
257 else if (iColor < st->iColorCount >> 1)
259 /* yellow to white */
260 signed int temp = (iColor - ((st->iColorCount >> 2) + (st->iColorCount >> 3))) << 3;
261 aColors[iColor].red = 65535;
262 aColors[iColor].green = 65535;
263 aColors[iColor].blue = Color.blue * temp;
268 aColors[iColor].red = aColors[iColor].green = aColors[iColor].blue = 65535;
271 if( !XAllocColor( st->dpy, XWinAttribs.colormap, &aColors[ iColor ] ) )
273 /* start all over with less colors */
274 XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, iColor, 0 );
276 free( st->aiColorVals );
278 aColors = calloc( st->iColorCount, sizeof(XColor) );
279 st->aiColorVals = calloc( st->iColorCount, sizeof(unsigned long) );
283 st->aiColorVals[ iColor ] = aColors[ iColor ].pixel;
286 if (st->heat < st->iColorCount)
287 st->iColorCount = st->heat;
291 XSetWindowBackground( st->dpy, st->window, st->aiColorVals[ 0 ] );
293 return st->aiColorVals;
297 static void Initialize( struct state *st )
300 XWindowAttributes XWinAttribs;
301 int /*iBitsPerPixel,*/ i;
303 /* Create the Image for drawing */
304 XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
306 /* Find the preferred bits-per-pixel. (jwz) */
309 XPixmapFormatValues *pfv = XListPixmapFormats( st->dpy, &pfvc );
310 for( i=0; i<pfvc; i++ )
311 if( pfv[ i ].depth == XWinAttribs.depth )
313 /*iBitsPerPixel = pfv[ i ].bits_per_pixel;*/
321 st->gc = XCreateGC( st->dpy, st->window, 0, &gcValues );
323 st->pImage = XCreateImage( st->dpy, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
324 XWinAttribs.width, XWinAttribs.height, BitmapPad( st->dpy ), 0 );
325 (st->pImage)->data = calloc((st->pImage)->bytes_per_line, (st->pImage)->height);
327 st->iWinWidth = XWinAttribs.width;
328 st->iWinHeight = XWinAttribs.height;
330 /* create st->fire array */
331 st->fire = calloc( st->iWinHeight, sizeof(unsigned char*));
332 for (i = 0; i < st->iWinHeight; ++i)
333 st->fire[i] = calloc( st->iWinWidth, sizeof(unsigned char));
335 /*create st->particles */
336 st->particles = malloc (st->nParticleCount * sizeof(PARTICLE));
340 eruption_init (Display *dpy, Window window)
342 struct state *st = (struct state *) calloc (1, sizeof(*st));
343 XWindowAttributes XWinAttribs;
344 unsigned short sum = 0;
346 time_t nTime = time( NULL );
347 unsigned short iFrame = 0;
353 st->nParticleCount = get_integer_resource(st->dpy, "particles", "Integer" );
354 if (st->nParticleCount < 100)
355 st->nParticleCount = 100;
356 if (st->nParticleCount > 2000)
357 st->nParticleCount = 2000;
359 st->decay = get_integer_resource(st->dpy, "cooloff", "Integer" );
365 st->gravity = get_integer_resource(st->dpy, "gravity", "Integer" );
366 if (st->gravity < -5)
371 st->heat = get_integer_resource(st->dpy, "heat", "Integer" );
378 printf( "%s: Allocated %d st->particles\n", progclass, st->nParticleCount );
384 while (sum < (st->iWinHeight >> 1) - SPREAD)
391 while (sum < (st->iWinWidth >> 3))
397 st->delay = get_integer_resource(st->dpy, "delay", "Integer" );
398 st->cycles = get_integer_resource(st->dpy, "cycles", "Integer" );
402 XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
403 XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, st->iColorCount, 0 );
404 free( st->aiColorVals );
405 st->aiColorVals = SetPalette( st );
406 XClearWindow( st->dpy, st->window );
407 memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height );
416 eruption_draw (Display *dpy, Window window, void *closure)
418 struct state *st = (struct state *) closure;
420 if( st->draw_i < 0 || st->draw_i++ >= st->cycles )
422 /* compute random center */
423 unsigned short xcenter, ycenter;
424 xcenter = random() % st->iWinWidth;
425 ycenter = random() % st->iWinHeight;
427 for (st->draw_i = 0; st->draw_i < st->nParticleCount; st->draw_i++)
428 init_particle(st, st->particles + st->draw_i, xcenter, ycenter);
436 if( nTime - time( NULL ) )
438 printf( "%s: %d FPS\n", progclass, iFrame );
439 nTime = time( NULL );
449 eruption_reshape (Display *dpy, Window window, void *closure,
450 unsigned int w, unsigned int h)
452 struct state *st = (struct state *) closure;
453 XWindowAttributes XWinAttribs;
456 for (i = 0; i < st->iWinHeight; ++i)
463 st->fire = calloc( st->iWinHeight, sizeof(unsigned char*));
464 for (i = 0; i < st->iWinHeight; ++i)
465 st->fire[i] = calloc( st->iWinWidth, sizeof(unsigned char));
467 XDestroyImage( st->pImage );
468 XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
469 st->pImage = XCreateImage( st->dpy, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
470 XWinAttribs.width, XWinAttribs.height, BitmapPad( st->dpy ), 0 );
471 (st->pImage)->data = calloc((st->pImage)->bytes_per_line, (st->pImage)->height);
477 eruption_event (Display *dpy, Window window, void *closure, XEvent *event)
483 eruption_free (Display *dpy, Window window, void *closure)
486 struct state *st = (struct state *) closure;
487 XDestroyImage( st->pImage );
488 free( st->aiColorVals );
489 for (i = 0; i < st->iWinHeight; ++i)
492 free( st->particles );
497 static const char *eruption_defaults [] = {
498 ".background: black",
499 ".foreground: white",
511 static XrmOptionDescRec eruption_options [] = {
512 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
513 { "-delay", ".delay", XrmoptionSepArg, 0 },
514 { "-cycles", ".cycles", XrmoptionSepArg, 0 },
515 { "-particles", ".particles", XrmoptionSepArg, 0 },
516 { "-cooloff", ".cooloff", XrmoptionSepArg, 0 },
517 { "-gravity", ".gravity", XrmoptionSepArg, 0 },
518 { "-heat", ".heat", XrmoptionSepArg, 0 },
523 XSCREENSAVER_MODULE ("Eruption", eruption)
525 /* End of Module - "eruption.c" */