2 Fireworkx 2.2 - Pyrotechnic explosions simulation,
3 an eyecandy, live animating colorful fireworks super-blasts..!
4 Copyright (GPL) 1999-2013 Rony B Chandran <ronybc@gmail.com>
7 Website: http://www.ronybc.com
9 Permission to use, copy, modify, distribute, and sell this software and its
10 documentation for any purpose is hereby granted without fee, provided that
11 the above copyright notice appear in all copies and that both that
12 copyright notice and this permission notice appear in supporting
13 documentation. No representations are made about the suitability of this
14 software for any purpose. It is provided "as is" without express or
17 2004-OCT: ronybc: Landed on Xscreensaver..!
18 2012-DEC: ronybc: Almost rewrite of the last version (>4 years old)
19 with SSE2 optimization, colored light flashes,
20 HSV color and many visual and speed improvements.
23 ---------------------------------------------------------------------------------
24 Support for different display color modes: put_image()
25 Jean-Pierre Demailly <Jean-Pierre.Demailly@ujf-grenoble.fr>
27 Fixed array access problems by beating on it with a large hammer.
28 Nicholas Miell <nmiell@gmail.com>
30 Help 'free'ing up of memory with needed 'XSync's.
31 Renuka S <renuka@ronybc.com>
32 Rugmini R Chandran <rugmini@ronybc.com>
36 #include "screenhack.h"
39 # include <emmintrin.h>
42 #define FWXVERSION "2.2"
44 #define WIDTH 1024 /* 888 */
45 #define HEIGHT 632 /* 548 */
46 #define SHELLCOUNT 4 /* FIXED NUMBER; for SSE optimization */
47 #define PIXCOUNT 500 /* 500 */
48 #define SHELL_LIFE_DEFAULT 32 /* 32 */
49 #define SHELL_LIFE_RATIO 6 /* 6 */
50 #define POWDER 5.0 /* 5.0 */
51 #define FTWEAK 12 /* 12 */
52 #define FLASH_ZOOM 0.8 /* 1.0 */
53 #define G_ACCELERATION 0.001 /* GRAVITY */
65 unsigned int seq_number, life;
66 unsigned int bicolor, flies, hshift, vshift;
67 unsigned int mortar_fired, explode_y;
68 float air_drag, vshift_phase;
69 float flash_r, flash_g, flash_b;
72 unsigned char r, g, b;
79 unsigned int flash_on;
84 unsigned int fullscreen;
85 unsigned int max_shell_life;
89 unsigned char *palaka1;
90 unsigned char *palaka2;
93 fireshell *fireshell_array;
106 will return zero.. divide with care.
108 static unsigned int rnd(unsigned int x)
110 return(random() % x);
113 static void fs_roll_rgb(fireshell *fs)
115 unsigned short r, g, b;
116 hsv_to_rgb (fs->h, fs->s, fs->v, &r, &g, &b);
117 fs->r = (unsigned char) (r >> 8);
118 fs->g = (unsigned char) (g >> 8);
119 fs->b = (unsigned char) (b >> 8);
122 static void mix_colors(fireshell *fs)
126 fs->s = frand(0.4) + 0.6;
130 flash = rnd(444) + 111; /* Mega Jouls ! */
131 fs->flash_r = fs->r * flash;
132 fs->flash_g = fs->g * flash;
133 fs->flash_b = fs->b * flash;
136 static void render_light_map(struct state *st, fireshell *fs)
138 signed int x, y, v = 0;
139 for (y = 0, v = fs->seq_number; y < st->height; y += 2)
141 for (x = 0; x < st->width; x += 2, v += SHELLCOUNT)
144 f = sqrtf((fs->cx - x) * (fs->cx - x) + (fs->cy - y) * (fs->cy - y)) + 4.0;
146 f += pow(f,0.1) * frand(0.0001); /* dither */
147 st->light_map[v] = f;
152 static void recycle(struct state *st, fireshell *fs, unsigned int x, unsigned int y)
154 unsigned int n, pixlife;
155 firepix *fp = fs->fpix;
156 fs->mortar_fired = st->shoot;
159 fs->cy = st->shoot ? st->height : y ;
160 fs->life = rnd(st->max_shell_life) + (st->max_shell_life/SHELL_LIFE_RATIO);
161 fs->life += !rnd(25) ? st->max_shell_life * 5 : 0;
162 fs->air_drag = 1.0 - (float)(rnd(200)) / (10000.0 + fs->life);
163 fs->bicolor = !rnd(5) ? 120 : 0;
164 fs->flies = !rnd(10) ? 1 : 0; /* flies' motion */
165 fs->hshift = !rnd(5) ? 1 : 0; /* hue shifting */
166 fs->vshift = !rnd(10) ? 1 : 0; /* value shifting */
167 fs->vshift_phase = M_PI/2.0;
168 pixlife = rnd(fs->life) + fs->life / 10 + 1; /* ! */
169 for (n = 0; n < PIXCOUNT; n++)
171 fp->burn = rnd(pixlife) + 32;
172 fp->xv = frand(2.0) * POWDER - POWDER;
173 fp->yv = sqrt(POWDER * POWDER - fp->xv * fp->xv) * (frand(2.0) - 1.0);
179 render_light_map(st, fs);
182 static void recycle_oldest(struct state *st, unsigned int x, unsigned int y)
185 fireshell *fs, *oldest;
186 fs = oldest = st->fireshell_array;
187 for (n = 0; n < SHELLCOUNT; n++)
189 if(fs[n].life < oldest->life) oldest = &fs[n];
191 recycle(st, oldest, x, y);
194 static void rotate_hue(fireshell *fs, int dh)
197 fs->s = fs->s - 0.001;
201 static void wave_value(fireshell *fs)
203 fs->vshift_phase = fs->vshift_phase + 0.008;
204 fs->v = fabs(sin(fs->vshift_phase));
208 static int explode(struct state *st, fireshell *fs)
212 unsigned int h = st->height;
213 unsigned int w = st->width;
214 unsigned char r, g, b;
215 unsigned char *prgba;
216 unsigned char *palaka = st->palaka1;
217 firepix *fp = fs->fpix;
218 if (fs->mortar_fired)
220 if (--fs->cy == fs->explode_y)
222 fs->mortar_fired = 0;
224 render_light_map(st, fs);
230 fs->flash_b = 50 + (fs->cy - fs->explode_y) * 10;
231 prgba = palaka + (fs->cy * w + fs->cx + rnd(5) - 2) * 4;
232 prgba[0] = (rnd(32) + 128);
233 prgba[1] = (rnd(32) + 128);
234 prgba[2] = (rnd(32) + 128);
238 if ((fs->bicolor + 1) % 50 == 0) rotate_hue(fs, 180);
239 if (fs->bicolor) --fs->bicolor;
240 if (fs->hshift) rotate_hue(fs, rnd(8));
241 if (fs->vshift) wave_value(fs);
242 if (fs->flash_r > 1.0) fs->flash_r *= st->flash_fade;
243 if (fs->flash_g > 1.0) fs->flash_g *= st->flash_fade;
244 if (fs->flash_b > 1.0) fs->flash_b *= st->flash_fade;
245 air_drag = fs->air_drag;
249 for (n = 0; n < PIXCOUNT; n++, fp++)
251 if (!fp->burn) continue;
255 fp->x += fp->xv = fp->xv * air_drag + frand(0.1) - 0.05;
256 fp->y += fp->yv = fp->yv * air_drag + frand(0.1) - 0.05 + G_ACCELERATION;
260 fp->x += fp->xv = fp->xv * air_drag + frand(0.01) - 0.005;
261 fp->y += fp->yv = fp->yv * air_drag + frand(0.005) - 0.0025 + G_ACCELERATION;
270 /* touch muddy ground :) */
273 if (fp->x < w && fp->x > 0 && fp->y < h && fp->y > 0)
275 prgba = palaka + ((int)fp->y * w + (int)fp->x) * 4;
286 /* SSE2 optimized versions of glow_blur() and chromo_2x2_light() */
288 static void glow_blur(struct state *st)
291 unsigned char *ps = st->palaka1;
292 unsigned char *pd = st->palaka2;
293 unsigned char *pa = st->palaka1 - (st->width * 4);
294 unsigned char *pb = st->palaka1 + (st->width * 4);
295 __m128i xmm0, xmm1, xmm2, xmm3, xmm4;
297 xmm0 = _mm_setzero_si128();
298 nn = st->width * st->height * 4;
299 for (n = 0; n < nn; n+=16)
301 _mm_prefetch((const void *)&ps[n+16],_MM_HINT_T0);
302 _mm_prefetch((const void *)&pa[n+16],_MM_HINT_T0);
303 _mm_prefetch((const void *)&pb[n+16],_MM_HINT_T0);
305 xmm1 = _mm_load_si128((const __m128i*)&ps[n]);
307 xmm1 = _mm_unpacklo_epi8(xmm1,xmm0);
308 xmm2 = _mm_unpackhi_epi8(xmm2,xmm0);
309 xmm3 = _mm_loadu_si128((const __m128i*)&ps[n+4]);
311 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
312 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
313 xmm3 = _mm_slli_epi16(xmm3,3);
314 xmm4 = _mm_slli_epi16(xmm4,3);
315 xmm1 = _mm_add_epi16(xmm1,xmm3);
316 xmm2 = _mm_add_epi16(xmm2,xmm4);
317 xmm3 = _mm_loadu_si128((const __m128i*)&ps[n+8]);
319 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
320 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
321 xmm1 = _mm_add_epi16(xmm1,xmm3);
322 xmm2 = _mm_add_epi16(xmm2,xmm4);
324 xmm3 = _mm_load_si128((const __m128i*)&pa[n]);
326 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
327 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
328 xmm1 = _mm_add_epi16(xmm1,xmm3);
329 xmm2 = _mm_add_epi16(xmm2,xmm4);
330 xmm3 = _mm_loadu_si128((const __m128i*)&pa[n+4]);
332 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
333 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
334 xmm1 = _mm_add_epi16(xmm1,xmm3);
335 xmm2 = _mm_add_epi16(xmm2,xmm4);
336 xmm3 = _mm_loadu_si128((const __m128i*)&pa[n+8]);
338 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
339 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
340 xmm1 = _mm_add_epi16(xmm1,xmm3);
341 xmm2 = _mm_add_epi16(xmm2,xmm4);
343 xmm3 = _mm_load_si128((const __m128i*)&pb[n]);
345 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
346 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
347 xmm1 = _mm_add_epi16(xmm1,xmm3);
348 xmm2 = _mm_add_epi16(xmm2,xmm4);
349 xmm3 = _mm_loadu_si128((const __m128i*)&pb[n+4]);
351 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
352 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
353 xmm1 = _mm_add_epi16(xmm1,xmm3);
354 xmm2 = _mm_add_epi16(xmm2,xmm4);
355 xmm3 = _mm_loadu_si128((const __m128i*)&pb[n+8]);
357 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
358 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
359 xmm1 = _mm_add_epi16(xmm1,xmm3);
360 xmm2 = _mm_add_epi16(xmm2,xmm4);
364 xmm1 = _mm_srli_epi16(xmm1,4);
365 xmm2 = _mm_srli_epi16(xmm2,4);
366 xmm3 = _mm_srli_epi16(xmm3,3);
367 xmm4 = _mm_srli_epi16(xmm4,3);
368 xmm1 = _mm_packus_epi16(xmm1,xmm2);
369 xmm3 = _mm_packus_epi16(xmm3,xmm4);
371 _mm_storeu_si128((__m128i*)&ps[n+4], xmm1);
372 _mm_storeu_si128((__m128i*)&pd[n+4], xmm3);
376 static void chromo_2x2_light(struct state *st)
378 __m128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6;
379 __m128i xmi4, xmi5, xmi6, xmi7;
381 unsigned int x, y, v = 0;
382 unsigned int nl = st->width * 4;
383 unsigned char *mem = st->palaka2;
384 fireshell *fs = st->fireshell_array;
386 xmm0 = _mm_setr_ps(fs[0].flash_b, fs[0].flash_g, fs[0].flash_r, 0.0);
387 xmm1 = _mm_setr_ps(fs[1].flash_b, fs[1].flash_g, fs[1].flash_r, 0.0);
388 xmm2 = _mm_setr_ps(fs[2].flash_b, fs[2].flash_g, fs[2].flash_r, 0.0);
389 xmm3 = _mm_setr_ps(fs[3].flash_b, fs[3].flash_g, fs[3].flash_r, 0.0);
391 for (y = st->height/2; y; y--, mem += nl)
393 for (x = st->width/4; x; x--, v += 8, mem += 16)
395 xmm4 = _mm_set1_ps(st->light_map[v+0]);
397 xmm5 = _mm_mul_ps(xmm5,xmm4);
398 xmm4 = _mm_set1_ps(st->light_map[v+1]);
399 xmm4 = _mm_mul_ps(xmm4,xmm1);
400 xmm5 = _mm_add_ps(xmm5,xmm4);
401 xmm4 = _mm_set1_ps(st->light_map[v+2]);
402 xmm4 = _mm_mul_ps(xmm4,xmm2);
403 xmm5 = _mm_add_ps(xmm5,xmm4);
404 xmm4 = _mm_set1_ps(st->light_map[v+3]);
405 xmm4 = _mm_mul_ps(xmm4,xmm3);
406 xmm5 = _mm_add_ps(xmm5,xmm4);
408 xmm4 = _mm_set1_ps(st->light_map[v+4]);
410 xmm6 = _mm_mul_ps(xmm6,xmm4);
411 xmm4 = _mm_set1_ps(st->light_map[v+5]);
412 xmm4 = _mm_mul_ps(xmm4,xmm1);
413 xmm6 = _mm_add_ps(xmm6,xmm4);
414 xmm4 = _mm_set1_ps(st->light_map[v+6]);
415 xmm4 = _mm_mul_ps(xmm4,xmm2);
416 xmm6 = _mm_add_ps(xmm6,xmm4);
417 xmm4 = _mm_set1_ps(st->light_map[v+7]);
418 xmm4 = _mm_mul_ps(xmm4,xmm3);
419 xmm6 = _mm_add_ps(xmm6,xmm4);
421 xmi6 = _mm_cvtps_epi32(xmm5);
422 xmi7 = _mm_cvtps_epi32(xmm6);
423 xmi6 = _mm_packs_epi32(xmi6,xmi6);
424 xmi7 = _mm_packs_epi32(xmi7,xmi7);
426 xmi4 = _mm_load_si128((const __m128i*) mem);
427 xmi5 = _mm_unpacklo_epi8(xmi5,xmi4);
428 xmi5 = _mm_srli_epi16(xmi5,8);
429 xmi4 = _mm_unpackhi_epi8(xmi4,xmi4);
430 xmi4 = _mm_srli_epi16(xmi4,8);
431 xmi5 = _mm_add_epi16(xmi5,xmi6);
432 xmi4 = _mm_add_epi16(xmi4,xmi7);
433 xmi5 = _mm_packus_epi16(xmi5,xmi4);
434 _mm_store_si128((__m128i*) mem, xmi5);
436 xmi4 = _mm_load_si128((const __m128i*) &mem[nl]);
437 xmi5 = _mm_unpacklo_epi8(xmi5,xmi4);
438 xmi5 = _mm_srli_epi16(xmi5,8);
439 xmi4 = _mm_unpackhi_epi8(xmi4,xmi4);
440 xmi4 = _mm_srli_epi16(xmi4,8);
441 xmi5 = _mm_add_epi16(xmi5,xmi6);
442 xmi4 = _mm_add_epi16(xmi4,xmi7);
443 xmi5 = _mm_packus_epi16(xmi5,xmi4);
444 _mm_store_si128((__m128i*) &mem[nl], xmi5);
451 static void glow_blur(struct state *st)
454 unsigned char *pm = st->palaka1;
455 unsigned char *po = st->palaka2;
456 unsigned char *pa = pm - (st->width * 4);
457 unsigned char *pb = pm + (st->width * 4);
459 unsigned int rgba = 0;
460 for (n = st->width*st->height*4; n; n--, pm++, pa++, pb++, po++)
467 q = pm[0] + pm[4] * 8 + pm[8] +
468 pa[0] + pa[4] + pa[8] +
469 pb[0] + pb[4] + pb[8];
471 po[4] = q > 2047 ? 255 : q >> 3;
473 --- using unrolled version ------------
475 for (n = st->width*st->height*4; n; n-=4)
477 q = pm[0] + pm[4] * 8 + pm[8] +
478 pa[0] + pa[4] + pa[8] +
479 pb[0] + pb[4] + pb[8];
481 po[4] = q > 2047 ? 255 : q >> 3;
482 q = pm[1] + pm[5] * 8 + pm[9] +
483 pa[1] + pa[5] + pa[9] +
484 pb[1] + pb[5] + pb[9];
486 po[5] = q > 2047 ? 255 : q >> 3;
487 q = pm[2] + pm[6] * 8 + pm[10] +
488 pa[2] + pa[6] + pa[10] +
489 pb[2] + pb[6] + pb[10];
491 po[6] = q > 2047 ? 255 : q >> 3;
493 pm+=4, pa+=4, pb+=4, po+=4;
497 static inline unsigned char addbs(unsigned char c, unsigned int i)
500 return(i > 255 ? 255 : i);
503 static void chromo_2x2_light(struct state *st)
505 unsigned int n, x, y, v = 0;
506 unsigned int nl = st->width * 4;
507 unsigned char *mem = st->palaka2;
509 float rgb[SHELLCOUNT*4];
510 fireshell *fs = st->fireshell_array;
512 for (n = 0, x = 0; n < SHELLCOUNT; n++, x += 4, fs++)
514 rgb[x ] = fs->flash_r;
515 rgb[x+1] = fs->flash_g;
516 rgb[x+2] = fs->flash_b;
519 for (y = st->height/2; y; y--)
521 for (x = st->width/2; x; x--, v += 4)
523 r = rgb[0] * st->light_map[v] + rgb[4] * st->light_map[v+1]
524 + rgb[ 8] * st->light_map[v+2] + rgb[12] * st->light_map[v+3];
525 g = rgb[1] * st->light_map[v] + rgb[5] * st->light_map[v+1]
526 + rgb[ 9] * st->light_map[v+2] + rgb[13] * st->light_map[v+3];
527 b = rgb[2] * st->light_map[v] + rgb[6] * st->light_map[v+1]
528 + rgb[10] * st->light_map[v+2] + rgb[14] * st->light_map[v+3];
530 mem[0] = addbs(mem[0], b);
531 mem[1] = addbs(mem[1], g);
532 mem[2] = addbs(mem[2], r);
533 mem[4] = addbs(mem[4], b);
534 mem[5] = addbs(mem[5], g);
535 mem[6] = addbs(mem[6], r);
539 mem[0] = addbs(mem[0], b);
540 mem[1] = addbs(mem[1], g);
541 mem[2] = addbs(mem[2], r);
542 mem[4] = addbs(mem[4], b);
543 mem[5] = addbs(mem[5], g);
544 mem[6] = addbs(mem[6], r);
554 static void resize(struct state *st)
557 fireshell *fs = st->fireshell_array;
558 XWindowAttributes xwa;
559 XGetWindowAttributes (st->dpy, st->window, &xwa);
560 xwa.width -= xwa.width % 4;
561 xwa.height -= xwa.height % 2;
562 st->width = xwa.width;
563 st->height = xwa.height;
566 printf("resolution: %d x %d \n",st->width,st->height);
571 if (st->xim->data == (char *)st->palaka2) st->xim->data = NULL;
572 XDestroyImage(st->xim);
577 st->xim = XCreateImage(st->dpy, xwa.visual, xwa.depth, ZPixmap, 0, 0,
578 st->width, st->height, 8, 0);
579 if (!st->xim) return;
581 #ifdef __SSE2___ABANDONED /* causes __ERROR_use_memset_not_bzero_in_xscreensaver__ */
582 st->mem1 = _mm_malloc(((st->height + 2) * st->width + 8)*4, 16);
583 bzero(st->mem1, ((st->height + 2) * st->width + 8)*4);
584 st->mem2 = _mm_malloc(((st->height + 2) * st->width + 8)*4, 16);
585 bzero(st->mem2, ((st->height + 2) * st->width + 8)*4);
587 st->mem1 = calloc((st->height + 2) * st->width + 8, 4);
588 st->mem2 = calloc((st->height + 2) * st->width + 8, 4);
590 st->palaka1 = (unsigned char *) st->mem1 + (st->width * 4 + 16);
591 st->palaka2 = (unsigned char *) st->mem2 + (st->width * 4 + 16);
595 st->xim->data = (char *)st->palaka2;
599 st->xim->data = calloc(st->height, st->xim->bytes_per_line);
602 if (st->light_map) free(st->light_map);
603 st->light_map = calloc((st->width * st->height * SHELLCOUNT)/4, sizeof(float));
604 for (n = 0; n < SHELLCOUNT; n++, fs++)
606 render_light_map(st, fs);
610 static void put_image(struct state *st)
613 unsigned char r, g, b;
614 if (!st->xim) return;
620 for (y=0; y<st->xim->height; y++)
621 for (x=0; x<st->xim->width; x++)
623 r = st->palaka2[j++];
624 g = st->palaka2[j++];
625 b = st->palaka2[j++];
627 st->xim->data[i++] = (g&224)>>5 | (r&248);
628 st->xim->data[i++] = (b&248)>>3 | (g&28)<<3;
631 for (y=0; y<st->xim->height; y++)
632 for (x=0; x<st->xim->width; x++)
634 r = st->palaka2[j++];
635 g = st->palaka2[j++];
636 b = st->palaka2[j++];
638 st->xim->data[i++] = (b&248)>>3 | (g&28)<<3;
639 st->xim->data[i++] = (g&224)>>5 | (r&248);
645 for (y=0; y<st->xim->height; y++)
646 for (x=0; x<st->xim->width; x++)
648 r = st->palaka2[j++];
649 g = st->palaka2[j++];
650 b = st->palaka2[j++];
652 st->xim->data[i++] = (g&192)>>6 | (r&248)>>1;
653 st->xim->data[i++] = (b&248)>>3 | (g&56)<<2;
656 for (y=0; y<st->xim->height; y++)
657 for (x=0; x<st->xim->width; x++)
659 r = st->palaka2[j++];
660 g = st->palaka2[j++];
661 b = st->palaka2[j++];
663 st->xim->data[i++] = (b&248)>>3 | (g&56)<<2;
664 st->xim->data[i++] = (g&192)>>6 | (r&248)>>1;
669 for (y=0; y<st->xim->height; y++)
670 for (x=0; x<st->xim->width; x++)
672 r = st->palaka2[j++];
673 g = st->palaka2[j++];
674 b = st->palaka2[j++];
676 st->xim->data[i++] = (((7*g)/256)*36)+(((6*r)/256)*6)+((6*b)/256);
679 XPutImage(st->dpy,st->window,st->gc,st->xim,0,0,0,0,st->xim->width,st->xim->height);
683 fireworkx_init (Display *dpy, Window win)
685 struct state *st = (struct state *) calloc (1, sizeof(*st));
690 XWindowAttributes xwa;
702 st->max_shell_life = SHELL_LIFE_DEFAULT;
703 st->flash_fade = 0.995;
704 st->light_map = NULL;
708 st->flash_on = get_boolean_resource(st->dpy, "flash" , "Boolean");
709 st->shoot = get_boolean_resource(st->dpy, "shoot" , "Boolean");
710 st->verbose = get_boolean_resource(st->dpy, "verbose" , "Boolean");
711 st->max_shell_life = get_integer_resource(st->dpy, "maxlife" , "Integer");
712 /* transition from xscreensaver <= 5.20 */
713 if (st->max_shell_life > 100) st->max_shell_life = 100;
715 st->delay = get_integer_resource(st->dpy, "delay" , "Integer");
717 st->max_shell_life = pow(10.0,(st->max_shell_life/50.0)+2.7);
718 if(st->max_shell_life < 1000) st->flash_fade = 0.998;
722 printf("Fireworkx %s - Pyrotechnics explosions simulation \n", FWXVERSION);
723 printf("Copyright (GPL) 1999-2013 Rony B Chandran <ronybc@gmail.com> \n\n");
724 printf("url: http://www.ronybc.com \n\n");
725 printf("Life = %u\n", st->max_shell_life);
727 printf("Using SSE2 optimization.\n");
731 XGetWindowAttributes(st->dpy,win,&xwa);
732 st->depth = xwa.depth;
735 st->bigendian = (ImageByteOrder(st->dpy) == MSBFirst);
739 st->colors = (XColor *) calloc(sizeof(XColor),st->ncolors+1);
741 make_smooth_colormap(xwa.screen, vi, cmap,
742 st->colors, &st->ncolors,
743 False, &writable, True);
745 st->gc = XCreateGC(st->dpy, win, 0, &gcv);
747 fs = calloc(SHELLCOUNT, sizeof(fireshell));
748 fp = calloc(PIXCOUNT * SHELLCOUNT, sizeof(firepix));
749 st->fireshell_array = fs;
751 XGetWindowAttributes (st->dpy, st->window, &xwa);
752 st->depth = xwa.depth;
754 resize(st); /* initialize palakas */
756 for (n = 0; n < SHELLCOUNT; n++, fs++)
760 recycle (st, fs, rnd(st->width), rnd(st->height));
768 fireworkx_draw (Display *dpy, Window win, void *closure)
770 struct state *st = (struct state *) closure;
773 for (q = FTWEAK; q; q--)
775 fs = st->fireshell_array;
776 for (n = 0; n < SHELLCOUNT; n++, fs++)
778 if (!explode(st, fs))
780 recycle(st, fs, rnd(st->width), rnd(st->height));
789 chromo_2x2_light(st);
797 fireworkx_reshape (Display *dpy, Window window, void *closure,
798 unsigned int w, unsigned int h)
800 struct state *st = (struct state *) closure;
807 fireworkx_event (Display *dpy, Window window, void *closure, XEvent *event)
809 struct state *st = (struct state *) closure;
810 if (event->type == ButtonPress)
812 recycle_oldest(st, event->xbutton.x, event->xbutton.y);
819 fireworkx_free (Display *dpy, Window window, void *closure)
821 struct state *st = (struct state *) closure;
824 free(st->fireshell_array->fpix);
825 free(st->fireshell_array);
828 static const char *fireworkx_defaults [] =
830 ".background: black",
831 ".foreground: white",
832 "*delay: 10000", /* never default to zero! */
840 static XrmOptionDescRec fireworkx_options [] =
842 { "-delay", ".delay", XrmoptionSepArg, 0 },
843 { "-maxlife", ".maxlife", XrmoptionSepArg, 0 },
844 { "-no-flash", ".flash", XrmoptionNoArg, "False" },
845 { "-shoot", ".shoot", XrmoptionNoArg, "True" },
846 { "-verbose", ".verbose", XrmoptionNoArg, "True" },
850 XSCREENSAVER_MODULE ("Fireworkx", fireworkx)