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;
109 will return zero.. divide with care.
111 static unsigned int rnd(unsigned int x)
113 return(random() % x);
116 static void fs_roll_rgb(fireshell *fs)
118 unsigned short r, g, b;
119 hsv_to_rgb (fs->h, fs->s, fs->v, &r, &g, &b);
120 fs->r = (unsigned char) (r >> 8);
121 fs->g = (unsigned char) (g >> 8);
122 fs->b = (unsigned char) (b >> 8);
125 static void mix_colors(fireshell *fs)
129 fs->s = frand(0.4) + 0.6;
133 flash = rnd(444) + 111; /* Mega Jouls ! */
134 fs->flash_r = fs->r * flash;
135 fs->flash_g = fs->g * flash;
136 fs->flash_b = fs->b * flash;
139 static void render_light_map(struct state *st, fireshell *fs)
141 signed int x, y, v = 0;
142 for (y = 0, v = fs->seq_number; y < st->height; y += 2)
144 for (x = 0; x < st->width; x += 2, v += SHELLCOUNT)
147 f = sqrt((fs->cx - x) * (fs->cx - x) + (fs->cy - y) * (fs->cy - y)) + 4.0;
149 f += pow(f,0.1) * frand(0.0001); /* dither */
150 st->light_map[v] = f;
155 static void recycle(struct state *st, fireshell *fs, unsigned int x, unsigned int y)
157 unsigned int n, pixlife;
158 firepix *fp = fs->fpix;
159 fs->mortar_fired = st->shoot;
162 fs->cy = st->shoot ? st->height : y ;
163 fs->life = rnd(st->max_shell_life) + (st->max_shell_life/SHELL_LIFE_RATIO);
164 fs->life += !rnd(25) ? st->max_shell_life * 5 : 0;
165 fs->air_drag = 1.0 - (float)(rnd(200)) / (10000.0 + fs->life);
166 fs->bicolor = !rnd(5) ? 120 : 0;
167 fs->flies = !rnd(10) ? 1 : 0; /* flies' motion */
168 fs->hshift = !rnd(5) ? 1 : 0; /* hue shifting */
169 fs->vshift = !rnd(10) ? 1 : 0; /* value shifting */
170 fs->vshift_phase = M_PI/2.0;
171 pixlife = rnd(fs->life) + fs->life / 10 + 1; /* ! */
172 for (n = 0; n < PIXCOUNT; n++)
174 fp->burn = rnd(pixlife) + 32;
175 fp->xv = frand(2.0) * POWDER - POWDER;
176 fp->yv = sqrt(POWDER * POWDER - fp->xv * fp->xv) * (frand(2.0) - 1.0);
182 render_light_map(st, fs);
185 static void recycle_oldest(struct state *st, unsigned int x, unsigned int y)
188 fireshell *fs, *oldest;
189 fs = oldest = st->fireshell_array;
190 for (n = 0; n < SHELLCOUNT; n++)
192 if(fs[n].life < oldest->life) oldest = &fs[n];
194 recycle(st, oldest, x, y);
197 static void rotate_hue(fireshell *fs, int dh)
200 fs->s = fs->s - 0.001;
204 static void wave_value(fireshell *fs)
206 fs->vshift_phase = fs->vshift_phase + 0.008;
207 fs->v = fabs(sin(fs->vshift_phase));
211 static int explode(struct state *st, fireshell *fs)
215 unsigned int h = st->height;
216 unsigned int w = st->width;
217 unsigned char r, g, b;
218 unsigned char *prgba;
219 unsigned char *palaka = st->palaka1;
220 firepix *fp = fs->fpix;
221 if (fs->mortar_fired)
223 if (--fs->cy == fs->explode_y)
225 fs->mortar_fired = 0;
227 render_light_map(st, fs);
233 fs->flash_b = 50 + (fs->cy - fs->explode_y) * 10;
234 prgba = palaka + (fs->cy * w + fs->cx + rnd(5) - 2) * 4;
235 prgba[0] = (rnd(32) + 128);
236 prgba[1] = (rnd(32) + 128);
237 prgba[2] = (rnd(32) + 128);
241 if ((fs->bicolor + 1) % 50 == 0) rotate_hue(fs, 180);
242 if (fs->bicolor) --fs->bicolor;
243 if (fs->hshift) rotate_hue(fs, rnd(8));
244 if (fs->vshift) wave_value(fs);
245 if (fs->flash_r > 1.0) fs->flash_r *= st->flash_fade;
246 if (fs->flash_g > 1.0) fs->flash_g *= st->flash_fade;
247 if (fs->flash_b > 1.0) fs->flash_b *= st->flash_fade;
248 air_drag = fs->air_drag;
252 for (n = 0; n < PIXCOUNT; n++, fp++)
254 if (!fp->burn) continue;
258 fp->x += fp->xv = fp->xv * air_drag + frand(0.1) - 0.05;
259 fp->y += fp->yv = fp->yv * air_drag + frand(0.1) - 0.05 + G_ACCELERATION;
263 fp->x += fp->xv = fp->xv * air_drag + frand(0.01) - 0.005;
264 fp->y += fp->yv = fp->yv * air_drag + frand(0.005) - 0.0025 + G_ACCELERATION;
273 /* touch muddy ground :) */
276 if (fp->x < w && fp->x > 0 && fp->y < h && fp->y > 0)
278 prgba = palaka + ((int)fp->y * w + (int)fp->x) * 4;
289 /* SSE2 optimized versions of glow_blur() and chromo_2x2_light() */
291 static void glow_blur(struct state *st)
294 unsigned char *ps = st->palaka1;
295 unsigned char *pd = st->palaka2;
296 unsigned char *pa = st->palaka1 - (st->width * 4);
297 unsigned char *pb = st->palaka1 + (st->width * 4);
298 __m128i xmm0, xmm1, xmm2, xmm3, xmm4;
300 xmm0 = _mm_setzero_si128();
301 nn = st->width * st->height * 4;
302 for (n = 0; n < nn; n+=16)
304 _mm_prefetch((const void *)&ps[n+16],_MM_HINT_T0);
305 _mm_prefetch((const void *)&pa[n+16],_MM_HINT_T0);
306 _mm_prefetch((const void *)&pb[n+16],_MM_HINT_T0);
308 xmm1 = _mm_load_si128((const __m128i*)&ps[n]);
310 xmm1 = _mm_unpacklo_epi8(xmm1,xmm0);
311 xmm2 = _mm_unpackhi_epi8(xmm2,xmm0);
312 xmm3 = _mm_loadu_si128((const __m128i*)&ps[n+4]);
314 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
315 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
316 xmm3 = _mm_slli_epi16(xmm3,3);
317 xmm4 = _mm_slli_epi16(xmm4,3);
318 xmm1 = _mm_add_epi16(xmm1,xmm3);
319 xmm2 = _mm_add_epi16(xmm2,xmm4);
320 xmm3 = _mm_loadu_si128((const __m128i*)&ps[n+8]);
322 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
323 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
324 xmm1 = _mm_add_epi16(xmm1,xmm3);
325 xmm2 = _mm_add_epi16(xmm2,xmm4);
327 xmm3 = _mm_load_si128((const __m128i*)&pa[n]);
329 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
330 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
331 xmm1 = _mm_add_epi16(xmm1,xmm3);
332 xmm2 = _mm_add_epi16(xmm2,xmm4);
333 xmm3 = _mm_loadu_si128((const __m128i*)&pa[n+4]);
335 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
336 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
337 xmm1 = _mm_add_epi16(xmm1,xmm3);
338 xmm2 = _mm_add_epi16(xmm2,xmm4);
339 xmm3 = _mm_loadu_si128((const __m128i*)&pa[n+8]);
341 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
342 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
343 xmm1 = _mm_add_epi16(xmm1,xmm3);
344 xmm2 = _mm_add_epi16(xmm2,xmm4);
346 xmm3 = _mm_load_si128((const __m128i*)&pb[n]);
348 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
349 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
350 xmm1 = _mm_add_epi16(xmm1,xmm3);
351 xmm2 = _mm_add_epi16(xmm2,xmm4);
352 xmm3 = _mm_loadu_si128((const __m128i*)&pb[n+4]);
354 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
355 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
356 xmm1 = _mm_add_epi16(xmm1,xmm3);
357 xmm2 = _mm_add_epi16(xmm2,xmm4);
358 xmm3 = _mm_loadu_si128((const __m128i*)&pb[n+8]);
360 xmm3 = _mm_unpacklo_epi8(xmm3,xmm0);
361 xmm4 = _mm_unpackhi_epi8(xmm4,xmm0);
362 xmm1 = _mm_add_epi16(xmm1,xmm3);
363 xmm2 = _mm_add_epi16(xmm2,xmm4);
367 xmm1 = _mm_srli_epi16(xmm1,4);
368 xmm2 = _mm_srli_epi16(xmm2,4);
369 xmm3 = _mm_srli_epi16(xmm3,3);
370 xmm4 = _mm_srli_epi16(xmm4,3);
371 xmm1 = _mm_packus_epi16(xmm1,xmm2);
372 xmm3 = _mm_packus_epi16(xmm3,xmm4);
374 _mm_storeu_si128((__m128i*)&ps[n+4], xmm1);
375 _mm_storeu_si128((__m128i*)&pd[n+4], xmm3);
379 static void chromo_2x2_light(struct state *st)
381 __m128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6;
382 __m128i xmi4, xmi5, xmi6, xmi7;
384 unsigned int x, y, v = 0;
385 unsigned int nl = st->width * 4;
386 unsigned char *mem = st->palaka2;
387 fireshell *fs = st->fireshell_array;
389 xmm0 = _mm_setr_ps(fs[0].flash_b, fs[0].flash_g, fs[0].flash_r, 0.0);
390 xmm1 = _mm_setr_ps(fs[1].flash_b, fs[1].flash_g, fs[1].flash_r, 0.0);
391 xmm2 = _mm_setr_ps(fs[2].flash_b, fs[2].flash_g, fs[2].flash_r, 0.0);
392 xmm3 = _mm_setr_ps(fs[3].flash_b, fs[3].flash_g, fs[3].flash_r, 0.0);
394 for (y = st->height/2; y; y--, mem += nl)
396 for (x = st->width/4; x; x--, v += 8, mem += 16)
398 xmm4 = _mm_set1_ps(st->light_map[v+0]);
400 xmm5 = _mm_mul_ps(xmm5,xmm4);
401 xmm4 = _mm_set1_ps(st->light_map[v+1]);
402 xmm4 = _mm_mul_ps(xmm4,xmm1);
403 xmm5 = _mm_add_ps(xmm5,xmm4);
404 xmm4 = _mm_set1_ps(st->light_map[v+2]);
405 xmm4 = _mm_mul_ps(xmm4,xmm2);
406 xmm5 = _mm_add_ps(xmm5,xmm4);
407 xmm4 = _mm_set1_ps(st->light_map[v+3]);
408 xmm4 = _mm_mul_ps(xmm4,xmm3);
409 xmm5 = _mm_add_ps(xmm5,xmm4);
411 xmm4 = _mm_set1_ps(st->light_map[v+4]);
413 xmm6 = _mm_mul_ps(xmm6,xmm4);
414 xmm4 = _mm_set1_ps(st->light_map[v+5]);
415 xmm4 = _mm_mul_ps(xmm4,xmm1);
416 xmm6 = _mm_add_ps(xmm6,xmm4);
417 xmm4 = _mm_set1_ps(st->light_map[v+6]);
418 xmm4 = _mm_mul_ps(xmm4,xmm2);
419 xmm6 = _mm_add_ps(xmm6,xmm4);
420 xmm4 = _mm_set1_ps(st->light_map[v+7]);
421 xmm4 = _mm_mul_ps(xmm4,xmm3);
422 xmm6 = _mm_add_ps(xmm6,xmm4);
424 xmi6 = _mm_cvtps_epi32(xmm5);
425 xmi7 = _mm_cvtps_epi32(xmm6);
426 xmi6 = _mm_packs_epi32(xmi6,xmi6);
427 xmi7 = _mm_packs_epi32(xmi7,xmi7);
429 xmi4 = _mm_load_si128((const __m128i*) mem);
430 xmi5 = _mm_unpacklo_epi8(xmi5,xmi4);
431 xmi5 = _mm_srli_epi16(xmi5,8);
432 xmi4 = _mm_unpackhi_epi8(xmi4,xmi4);
433 xmi4 = _mm_srli_epi16(xmi4,8);
434 xmi5 = _mm_add_epi16(xmi5,xmi6);
435 xmi4 = _mm_add_epi16(xmi4,xmi7);
436 xmi5 = _mm_packus_epi16(xmi5,xmi4);
437 _mm_store_si128((__m128i*) mem, xmi5);
439 xmi4 = _mm_load_si128((const __m128i*) &mem[nl]);
440 xmi5 = _mm_unpacklo_epi8(xmi5,xmi4);
441 xmi5 = _mm_srli_epi16(xmi5,8);
442 xmi4 = _mm_unpackhi_epi8(xmi4,xmi4);
443 xmi4 = _mm_srli_epi16(xmi4,8);
444 xmi5 = _mm_add_epi16(xmi5,xmi6);
445 xmi4 = _mm_add_epi16(xmi4,xmi7);
446 xmi5 = _mm_packus_epi16(xmi5,xmi4);
447 _mm_store_si128((__m128i*) &mem[nl], xmi5);
454 static void glow_blur(struct state *st)
457 unsigned char *pm = st->palaka1;
458 unsigned char *po = st->palaka2;
459 unsigned char *pa = pm - (st->width * 4);
460 unsigned char *pb = pm + (st->width * 4);
462 unsigned int rgba = 0;
463 for (n = st->width*st->height*4; n; n--, pm++, pa++, pb++, po++)
470 q = pm[0] + pm[4] * 8 + pm[8] +
471 pa[0] + pa[4] + pa[8] +
472 pb[0] + pb[4] + pb[8];
474 po[4] = q > 2047 ? 255 : q >> 3;
476 --- using unrolled version ------------
478 for (n = st->width*st->height*4; n; n-=4)
480 q = pm[0] + pm[4] * 8 + pm[8] +
481 pa[0] + pa[4] + pa[8] +
482 pb[0] + pb[4] + pb[8];
484 po[4] = q > 2047 ? 255 : q >> 3;
485 q = pm[1] + pm[5] * 8 + pm[9] +
486 pa[1] + pa[5] + pa[9] +
487 pb[1] + pb[5] + pb[9];
489 po[5] = q > 2047 ? 255 : q >> 3;
490 q = pm[2] + pm[6] * 8 + pm[10] +
491 pa[2] + pa[6] + pa[10] +
492 pb[2] + pb[6] + pb[10];
494 po[6] = q > 2047 ? 255 : q >> 3;
496 pm+=4, pa+=4, pb+=4, po+=4;
500 static inline unsigned char addbs(unsigned char c, unsigned int i)
503 return(i > 255 ? 255 : i);
506 static void chromo_2x2_light(struct state *st)
508 unsigned int n, x, y, v = 0;
509 unsigned int nl = st->width * 4;
510 unsigned char *mem = st->palaka2;
512 float rgb[SHELLCOUNT*4];
513 fireshell *fs = st->fireshell_array;
515 for (n = 0, x = 0; n < SHELLCOUNT; n++, x += 4, fs++)
517 rgb[x ] = fs->flash_r;
518 rgb[x+1] = fs->flash_g;
519 rgb[x+2] = fs->flash_b;
522 for (y = st->height/2; y; y--)
524 for (x = st->width/2; x; x--, v += 4)
526 r = rgb[0] * st->light_map[v] + rgb[4] * st->light_map[v+1]
527 + rgb[ 8] * st->light_map[v+2] + rgb[12] * st->light_map[v+3];
528 g = rgb[1] * st->light_map[v] + rgb[5] * st->light_map[v+1]
529 + rgb[ 9] * st->light_map[v+2] + rgb[13] * st->light_map[v+3];
530 b = rgb[2] * st->light_map[v] + rgb[6] * st->light_map[v+1]
531 + rgb[10] * st->light_map[v+2] + rgb[14] * st->light_map[v+3];
533 mem[0] = addbs(mem[0], b);
534 mem[1] = addbs(mem[1], g);
535 mem[2] = addbs(mem[2], r);
536 mem[4] = addbs(mem[4], b);
537 mem[5] = addbs(mem[5], g);
538 mem[6] = addbs(mem[6], r);
542 mem[0] = addbs(mem[0], b);
543 mem[1] = addbs(mem[1], g);
544 mem[2] = addbs(mem[2], r);
545 mem[4] = addbs(mem[4], b);
546 mem[5] = addbs(mem[5], g);
547 mem[6] = addbs(mem[6], r);
557 static void resize(struct state *st)
560 fireshell *fs = st->fireshell_array;
561 XWindowAttributes xwa;
562 XGetWindowAttributes (st->dpy, st->window, &xwa);
563 xwa.width -= xwa.width % 4;
564 xwa.height -= xwa.height % 2;
565 st->width = xwa.width;
566 st->height = xwa.height;
569 printf("resolution: %d x %d \n",st->width,st->height);
574 if (st->xim->data == (char *)st->palaka2) st->xim->data = NULL;
575 XDestroyImage(st->xim);
580 st->xim = XCreateImage(st->dpy, xwa.visual, xwa.depth, ZPixmap, 0, 0,
581 st->width, st->height, 8, 0);
582 if (!st->xim) return;
584 #ifdef __SSE2___ABANDONED /* causes __ERROR_use_memset_not_bzero_in_xscreensaver__ */
585 st->mem1 = _mm_malloc(((st->height + 2) * st->width + 8)*4, 16);
586 bzero(st->mem1, ((st->height + 2) * st->width + 8)*4);
587 st->mem2 = _mm_malloc(((st->height + 2) * st->width + 8)*4, 16);
588 bzero(st->mem2, ((st->height + 2) * st->width + 8)*4);
590 st->mem1 = calloc((st->height + 2) * st->width + 8, 4);
591 st->mem2 = calloc((st->height + 2) * st->width + 8, 4);
593 st->palaka1 = (unsigned char *) st->mem1 + (st->width * 4 + 16);
594 st->palaka2 = (unsigned char *) st->mem2 + (st->width * 4 + 16);
598 st->xim->data = (char *)st->palaka2;
602 st->xim->data = calloc(st->height, st->xim->bytes_per_line);
605 if (st->light_map) free(st->light_map);
606 st->light_map = calloc((st->width * st->height * SHELLCOUNT)/4, sizeof(float));
607 for (n = 0; n < SHELLCOUNT; n++, fs++)
609 render_light_map(st, fs);
613 static void put_image(struct state *st)
616 unsigned char r, g, b;
617 if (!st->xim) return;
623 for (y=0; y<st->xim->height; y++)
624 for (x=0; x<st->xim->width; x++)
626 r = st->palaka2[j++];
627 g = st->palaka2[j++];
628 b = st->palaka2[j++];
630 st->xim->data[i++] = (g&224)>>5 | (r&248);
631 st->xim->data[i++] = (b&248)>>3 | (g&28)<<3;
634 for (y=0; y<st->xim->height; y++)
635 for (x=0; x<st->xim->width; x++)
637 r = st->palaka2[j++];
638 g = st->palaka2[j++];
639 b = st->palaka2[j++];
641 st->xim->data[i++] = (b&248)>>3 | (g&28)<<3;
642 st->xim->data[i++] = (g&224)>>5 | (r&248);
648 for (y=0; y<st->xim->height; y++)
649 for (x=0; x<st->xim->width; x++)
651 r = st->palaka2[j++];
652 g = st->palaka2[j++];
653 b = st->palaka2[j++];
655 st->xim->data[i++] = (g&192)>>6 | (r&248)>>1;
656 st->xim->data[i++] = (b&248)>>3 | (g&56)<<2;
659 for (y=0; y<st->xim->height; y++)
660 for (x=0; x<st->xim->width; x++)
662 r = st->palaka2[j++];
663 g = st->palaka2[j++];
664 b = st->palaka2[j++];
666 st->xim->data[i++] = (b&248)>>3 | (g&56)<<2;
667 st->xim->data[i++] = (g&192)>>6 | (r&248)>>1;
672 for (y=0; y<st->xim->height; y++)
673 for (x=0; x<st->xim->width; x++)
675 r = st->palaka2[j++];
676 g = st->palaka2[j++];
677 b = st->palaka2[j++];
679 st->xim->data[i++] = (((7*g)/256)*36)+(((6*r)/256)*6)+((6*b)/256);
682 XPutImage(st->dpy,st->window,st->gc,st->xim,0,0,0,0,st->xim->width,st->xim->height);
686 fireworkx_init (Display *dpy, Window win)
688 struct state *st = (struct state *) calloc (1, sizeof(*st));
693 XWindowAttributes xwa;
705 st->max_shell_life = SHELL_LIFE_DEFAULT;
706 st->flash_fade = 0.995;
707 st->light_map = NULL;
711 st->flash_on = get_boolean_resource(st->dpy, "flash" , "Boolean");
712 st->shoot = get_boolean_resource(st->dpy, "shoot" , "Boolean");
713 st->verbose = get_boolean_resource(st->dpy, "verbose" , "Boolean");
714 st->max_shell_life = get_integer_resource(st->dpy, "maxlife" , "Integer");
715 /* transition from xscreensaver <= 5.20 */
716 if (st->max_shell_life > 100) st->max_shell_life = 100;
718 st->delay = get_integer_resource(st->dpy, "delay" , "Integer");
720 st->max_shell_life = pow(10.0,(st->max_shell_life/50.0)+2.7);
721 if(st->max_shell_life < 1000) st->flash_fade = 0.998;
725 printf("Fireworkx %s - Pyrotechnics explosions simulation \n", FWXVERSION);
726 printf("Copyright (GPL) 1999-2013 Rony B Chandran <ronybc@gmail.com> \n\n");
727 printf("url: http://www.ronybc.com \n\n");
728 printf("Life = %u\n", st->max_shell_life);
730 printf("Using SSE2 optimization.\n");
734 XGetWindowAttributes(st->dpy,win,&xwa);
735 st->depth = xwa.depth;
738 st->bigendian = (ImageByteOrder(st->dpy) == MSBFirst);
742 st->colors = (XColor *) calloc(sizeof(XColor),st->ncolors+1);
744 make_smooth_colormap(xwa.screen, vi, cmap,
745 st->colors, &st->ncolors,
746 False, &writable, True);
748 st->gc = XCreateGC(st->dpy, win, 0, &gcv);
750 fs = calloc(SHELLCOUNT, sizeof(fireshell));
751 fp = calloc(PIXCOUNT * SHELLCOUNT, sizeof(firepix));
752 st->fireshell_array = fs;
754 XGetWindowAttributes (st->dpy, st->window, &xwa);
755 st->depth = xwa.depth;
757 resize(st); /* initialize palakas */
759 for (n = 0; n < SHELLCOUNT; n++, fs++)
763 recycle (st, fs, rnd(st->width), rnd(st->height));
771 fireworkx_draw (Display *dpy, Window win, void *closure)
773 struct state *st = (struct state *) closure;
776 for (q = FTWEAK; q; q--)
778 fs = st->fireshell_array;
779 for (n = 0; n < SHELLCOUNT; n++, fs++)
781 if (!explode(st, fs))
783 if (st->button_down_p)
786 recycle(st, fs, rnd(st->width), rnd(st->height));
791 while (!st->button_down_p && st->deferred) {
793 recycle_oldest(st, rnd(st->width), rnd(st->height));
800 chromo_2x2_light(st);
808 fireworkx_reshape (Display *dpy, Window window, void *closure,
809 unsigned int w, unsigned int h)
811 struct state *st = (struct state *) closure;
818 fireworkx_event (Display *dpy, Window window, void *closure, XEvent *event)
820 struct state *st = (struct state *) closure;
821 if (event->type == ButtonPress)
823 recycle_oldest(st, event->xbutton.x, event->xbutton.y);
824 st->button_down_p = True;
827 else if (event->type == ButtonRelease)
829 st->button_down_p = False;
837 fireworkx_free (Display *dpy, Window window, void *closure)
839 struct state *st = (struct state *) closure;
842 free(st->fireshell_array->fpix);
843 free(st->fireshell_array);
846 static const char *fireworkx_defaults [] =
848 ".background: black",
849 ".foreground: white",
850 "*delay: 10000", /* never default to zero! */
858 static XrmOptionDescRec fireworkx_options [] =
860 { "-delay", ".delay", XrmoptionSepArg, 0 },
861 { "-maxlife", ".maxlife", XrmoptionSepArg, 0 },
862 { "-no-flash", ".flash", XrmoptionNoArg, "False" },
863 { "-shoot", ".shoot", XrmoptionNoArg, "True" },
864 { "-verbose", ".verbose", XrmoptionNoArg, "True" },
868 XSCREENSAVER_MODULE ("Fireworkx", fireworkx)