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 * [01-2003] - W.P. van Paassen: Port to X for use with XScreenSaver, the shadebob hack by Shane Smit was used as a template
14 * [04-2002] - W.P. van Paassen: Creation for the Demo Effects Collection (http://demo-effects.sourceforge.net)
18 #include "screenhack.h"
19 #include <X11/Xutil.h>
23 char *progclass = "Eruption";
38 XrmOptionDescRec options [] = {
39 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
40 { "-delay", ".delay", XrmoptionSepArg, 0 },
41 { "-cycles", ".cycles", XrmoptionSepArg, 0 },
42 { "-particles", ".particles", XrmoptionSepArg, 0 },
43 { "-cooloff", ".cooloff", XrmoptionSepArg, 0 },
44 { "-gravity", ".gravity", XrmoptionSepArg, 0 },
45 { "-heat", ".heat", XrmoptionSepArg, 0 },
49 /*particle structure*/
52 short xpos, ypos, xdir, ydir;
53 unsigned char colorindex;
57 static PARTICLE *particles;
58 static unsigned short iWinWidth, iWinHeight;
59 static unsigned char **fire;
60 static unsigned short nParticleCount;
61 static unsigned char xdelta, ydelta, decay;
62 static signed char gravity;
63 static signed short heat;
65 void init_particle(PARTICLE* particle, signed short iColorCount)
67 /* randomly init particles, generate them in the center of the screen */
68 particle->xpos = (iWinWidth >> 1) - 15 + (int)(14.0 * frand(2.0));
69 particle->ypos = (iWinHeight >> 1) - 15 + (int)(16.0 * frand(2.0));
70 particle->xdir = -xdelta + (int)(xdelta * frand(2.0));
71 particle->ydir = -ydelta + (int)((ydelta / 2) * frand(2.0));
72 particle->colorindex = iColorCount;
76 static void Execute( Display *pDisplay,
78 GC *pGC, XImage *pImage,
79 signed short iColorCount, unsigned long *aiColorVals )
84 /* move and draw particles into fire array */
86 for (i = 0; i < nParticleCount; i++)
88 if (!particles[i].dead)
90 particles[i].xpos += particles[i].xdir;
91 particles[i].ypos += particles[i].ydir;
93 /* is particle dead? */
95 if (particles[i].colorindex == 0)
97 particles[i].dead = 1;
101 if (particles[i].xpos < 2)
103 particles[i].xpos = 2;
104 particles[i].xdir = -particles[i].xdir - 4;
105 particles[i].colorindex = iColorCount;
107 else if (particles[i].xpos > iWinWidth - 3)
109 particles[i].xpos = iWinWidth - 3;
110 particles[i].xdir = -particles[i].xdir + 4;
111 particles[i].colorindex = iColorCount;
114 if (particles[i].ypos < 2)
116 particles[i].ypos = 2;
117 particles[i].ydir = -particles[i].ydir;
118 particles[i].colorindex = iColorCount;
120 else if (particles[i].ypos > iWinHeight - 3)
122 particles[i].ypos = iWinHeight - 3;
123 particles[i].ydir = (-particles[i].ydir >> 2) - (random() % 4);
124 particles[i].colorindex = iColorCount;
127 /* gravity kicks in */
128 particles[i].ydir += gravity;
130 /* particle cools off */
131 particles[i].colorindex--;
134 fire[particles[i].ypos][particles[i].xpos] = particles[i].colorindex;
135 fire[particles[i].ypos][particles[i].xpos - 1] = particles[i].colorindex;
136 fire[particles[i].ypos + 1][particles[i].xpos] = particles[i].colorindex;
137 fire[particles[i].ypos - 1][particles[i].xpos] = particles[i].colorindex;
138 fire[particles[i].ypos][particles[i].xpos + 1] = particles[i].colorindex;
142 /* create fire effect */
143 for (i = 0; i < iWinHeight; i++)
145 for (j = 0; j < iWinWidth; j++)
147 if (j + 1 >= iWinWidth)
150 temp = fire[i][j + 1];
153 temp += fire[i][j - 1];
157 temp += fire[i - 1][j];
159 temp += fire[i - 1][j - 1];
160 if (j + 1 < iWinWidth)
161 temp += fire[i - 1][j + 1];
164 if (i + 1 < iWinHeight)
166 temp += fire[i + 1][j];
167 if (j + 1 < iWinWidth)
168 temp += fire[i + 1][j + 1];
170 temp += fire[i + 1][j - 1];
186 memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
188 /* draw fire array to screen */
189 for (i = 0; i < iWinHeight; ++i)
191 for (j = 0; j < iWinWidth; ++j)
194 XPutPixel( pImage, j, i, aiColorVals[ fire[i][j] ] );
197 XPutImage( pDisplay, MainWindow, *pGC, pImage,
198 0,0,0,0, iWinWidth, iWinHeight );
199 XSync( pDisplay, False );
202 static unsigned long * SetPalette(Display *pDisplay, Window Win, signed short *piColorCount )
204 XWindowAttributes XWinAttribs;
205 XColor Color, *aColors;
206 unsigned long *aiColorVals;
209 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
211 *piColorCount = get_integer_resource( "ncolors", "Integer" );
212 if( *piColorCount < 16 ) *piColorCount = 16;
213 if( *piColorCount > 255 ) *piColorCount = 256;
215 aColors = calloc( *piColorCount, sizeof(XColor) );
216 aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
218 Color.red = Color.green = Color.blue = 65535 / *piColorCount;
220 /* create fire palette */
221 for( iColor=0; iColor < *piColorCount; iColor++ )
223 if (iColor < *piColorCount >> 3)
226 aColors[iColor].red = 0;
227 aColors[iColor].green = 0;
228 aColors[iColor].blue = Color.blue * (iColor << 1);
230 else if (iColor < *piColorCount >> 2)
233 signed short temp = (iColor - (*piColorCount >> 3));
234 aColors[iColor].red = Color.red * (temp << 3);
235 aColors[iColor].green = 0;
236 aColors[iColor].blue = 16383 - Color.blue * (temp << 1);
238 else if (iColor < (*piColorCount >> 2) + (*piColorCount >> 3))
241 signed short temp = (iColor - (*piColorCount >> 2)) << 3;
242 aColors[iColor].red = 65535;
243 aColors[iColor].green = Color.green * temp;
244 aColors[iColor].blue = 0;
246 else if (iColor < *piColorCount >> 1)
248 /* yellow to white */
249 signed int temp = (iColor - ((*piColorCount >> 2) + (*piColorCount >> 3))) << 3;
250 aColors[iColor].red = 65535;
251 aColors[iColor].green = 65535;
252 aColors[iColor].blue = Color.blue * temp;
257 aColors[iColor].red = aColors[iColor].green = aColors[iColor].blue = 65535;
260 if( !XAllocColor( pDisplay, XWinAttribs.colormap, &aColors[ iColor ] ) )
262 /* start all over with less colors */
263 XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColor, 0 );
268 if (*piColorCount < 6)
270 fprintf (stderr, "%s: insufficient colors!\n", progname);
274 aColors = calloc( *piColorCount, sizeof(XColor) );
275 aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
279 aiColorVals[ iColor ] = aColors[ iColor ].pixel;
282 if (heat < *piColorCount)
283 *piColorCount = heat;
287 XSetWindowBackground( pDisplay, Win, aiColorVals[ 0 ] );
293 static void Initialize( Display *pDisplay, Window Win, GC *pGC, XImage **ppImage )
296 XWindowAttributes XWinAttribs;
297 int iBitsPerPixel, i;
299 /* Create the Image for drawing */
300 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
302 /* Find the preferred bits-per-pixel. (jwz) */
305 XPixmapFormatValues *pfv = XListPixmapFormats( pDisplay, &pfvc );
306 for( i=0; i<pfvc; i++ )
307 if( pfv[ i ].depth == XWinAttribs.depth )
309 iBitsPerPixel = pfv[ i ].bits_per_pixel;
317 *pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
319 *ppImage = XCreateImage( pDisplay, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
320 XWinAttribs.width, XWinAttribs.height, BitmapPad( pDisplay ), 0 );
321 (*ppImage)->data = calloc((*ppImage)->bytes_per_line, (*ppImage)->height);
323 iWinWidth = XWinAttribs.width;
324 iWinHeight = XWinAttribs.height;
326 /* create fire array */
327 fire = malloc( iWinHeight * sizeof(unsigned char*));
328 for (i = 0; i < iWinHeight; ++i)
329 fire[i] = malloc( iWinWidth * sizeof(unsigned char));
331 /*create particles */
332 particles = malloc (nParticleCount * sizeof(PARTICLE));
335 void screenhack(Display *pDisplay, Window Win )
337 XWindowAttributes XWinAttribs;
339 signed short iColorCount = 0;
340 unsigned long *aiColorVals = NULL;
341 unsigned short sum = 0;
342 XImage *pImage = NULL;
344 time_t nTime = time( NULL );
345 unsigned short iFrame = 0;
347 int delay, cycles, i;
349 nParticleCount = get_integer_resource( "particles", "Integer" );
350 if (nParticleCount < 100)
351 nParticleCount = 100;
352 if (nParticleCount > 2000)
353 nParticleCount = 2000;
355 decay = get_integer_resource( "cooloff", "Integer" );
361 gravity = get_integer_resource( "gravity", "Integer" );
367 heat = get_integer_resource( "heat", "Integer" );
374 printf( "%s: Allocated %d particles\n", progclass, nParticleCount );
377 Initialize( pDisplay, Win, &gc, &pImage );
380 while (sum < (iWinHeight >> 1) - 15)
387 while (sum < (iWinWidth >> 3))
393 delay = get_integer_resource( "delay", "Integer" );
394 cycles = get_integer_resource( "cycles", "Integer" );
397 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
398 XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColorCount, 0 );
400 aiColorVals = SetPalette( pDisplay, Win, &iColorCount );
401 XClearWindow( pDisplay, Win );
405 screenhack_handle_events( pDisplay );
409 for (i = 0; i < nParticleCount; i++)
410 init_particle(particles + i, iColorCount - 1);
414 Execute( pDisplay, Win, &gc, pImage, iColorCount - 1, aiColorVals );
416 if( delay && !(i % 4) )
421 if( nTime - time( NULL ) )
423 printf( "%s: %d FPS\n", progclass, iFrame );
424 nTime = time( NULL );
430 free( pImage->data );
431 XDestroyImage( pImage );
433 for (i = 0; i < iWinHeight; ++i)
439 /* End of Module - "eruption.c" */