1 /*
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>
5
6 From Kerala, INDIA
7 Website: http://www.ronybc.com
8
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
15 implied warranty.
16
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.
21
22 Additional coding:
23 ---------------------------------------------------------------------------------
24 Support for different display color modes: put_image()
25 Jean-Pierre Demailly <Jean-Pierre.Demailly@ujf-grenoble.fr>
26
27 Fixed array access problems by beating on it with a large hammer.
28 Nicholas Miell <nmiell@gmail.com>
29
30 Help 'free'ing up of memory with needed 'XSync's.
31 Renuka S <renuka@ronybc.com>
32 Rugmini R Chandran <rugmini@ronybc.com>
33 \
34 */
35
36 #include "screenhack.h"
37
38 #ifdef __SSE2__
39 # include <emmintrin.h>
40 #endif
41
42 #define FWXVERSION "2.2"
43
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 */
54
55 typedef struct
56 {
57 unsigned int burn;
58 float x, y;
59 float xv, yv;
60 } firepix;
61
62 typedef struct
63 {
64 unsigned int cx, cy;
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;
70 unsigned int h;
71 double s, v;
72 unsigned char r, g, b;
73 firepix *fpix;
74 } fireshell;
75
76 struct state
77 {
78 unsigned int fps_on;
79 unsigned int flash_on;
80 unsigned int shoot;
81 unsigned int verbose;
82 unsigned int width;
83 unsigned int height;
84 unsigned int fullscreen;
85 unsigned int max_shell_life;
86 unsigned int delay;
87 float flash_fade;
88 float *light_map;
89 unsigned char *palaka1;
90 unsigned char *palaka2;
91 void *mem1;
92 void *mem2;
93 fireshell *fireshell_array;
94
95 Display *dpy;
96 Window window;
97 XImage *xim;
98 GC gc;
99 XColor *colors;
100 int depth;
101 int bigendian;
102 int ncolors;
103 Bool button_down_p;
104 int deferred;
105
106 };
107
108 /*
109 will return zero.. divide with care.
110 */
rnd(unsigned int x)111 static unsigned int rnd(unsigned int x)
112 {
113 return(random() % x);
114 }
115
fs_roll_rgb(fireshell * fs)116 static void fs_roll_rgb(fireshell *fs)
117 {
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);
123 }
124
mix_colors(fireshell * fs)125 static void mix_colors(fireshell *fs)
126 {
127 float flash;
128 fs->h = rnd(360);
129 fs->s = frand(0.4) + 0.6;
130 fs->v = 1.0;
131 fs_roll_rgb(fs);
132
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;
137 }
138
render_light_map(struct state * st,fireshell * fs)139 static void render_light_map(struct state *st, fireshell *fs)
140 {
141 signed int x, y, v = 0;
142 for (y = 0, v = fs->seq_number; y < st->height; y += 2)
143 {
144 for (x = 0; x < st->width; x += 2, v += SHELLCOUNT)
145 {
146 double f;
147 f = sqrt((fs->cx - x) * (fs->cx - x) + (fs->cy - y) * (fs->cy - y)) + 4.0;
148 f = FLASH_ZOOM / f;
149 f += pow(f,0.1) * frand(0.0001); /* dither */
150 st->light_map[v] = f;
151 }
152 }
153 }
154
recycle(struct state * st,fireshell * fs,unsigned int x,unsigned int y)155 static void recycle(struct state *st, fireshell *fs, unsigned int x, unsigned int y)
156 {
157 unsigned int n, pixlife;
158 firepix *fp = fs->fpix;
159 fs->mortar_fired = st->shoot;
160 fs->explode_y = y;
161 fs->cx = x;
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++)
173 {
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);
177 fp->x = x;
178 fp->y = y;
179 fp++;
180 }
181 mix_colors(fs);
182 render_light_map(st, fs);
183 }
184
recycle_oldest(struct state * st,unsigned int x,unsigned int y)185 static void recycle_oldest(struct state *st, unsigned int x, unsigned int y)
186 {
187 unsigned int n;
188 fireshell *fs, *oldest;
189 fs = oldest = st->fireshell_array;
190 for (n = 0; n < SHELLCOUNT; n++)
191 {
192 if(fs[n].life < oldest->life) oldest = &fs[n];
193 }
194 recycle(st, oldest, x, y);
195 }
196
rotate_hue(fireshell * fs,int dh)197 static void rotate_hue(fireshell *fs, int dh)
198 {
199 fs->h = fs->h + dh;
200 fs->s = fs->s - 0.001;
201 fs_roll_rgb(fs);
202 }
203
wave_value(fireshell * fs)204 static void wave_value(fireshell *fs)
205 {
206 fs->vshift_phase = fs->vshift_phase + 0.008;
207 fs->v = fabs(sin(fs->vshift_phase));
208 fs_roll_rgb(fs);
209 }
210
explode(struct state * st,fireshell * fs)211 static int explode(struct state *st, fireshell *fs)
212 {
213 float air_drag;
214 unsigned int n;
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)
222 {
223 if (--fs->cy == fs->explode_y)
224 {
225 fs->mortar_fired = 0;
226 mix_colors(fs);
227 render_light_map(st, fs);
228 }
229 else
230 {
231 fs->flash_r =
232 fs->flash_g =
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);
238 return(1);
239 }
240 }
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;
249 r = fs->r;
250 g = fs->g;
251 b = fs->b;
252 for (n = 0; n < PIXCOUNT; n++, fp++)
253 {
254 if (!fp->burn) continue;
255 --fp->burn;
256 if (fs->flies)
257 {
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;
260 }
261 else
262 {
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;
265 }
266 if (fp->y > h)
267 {
268 if (rnd(5) == 3)
269 {
270 fp->yv *= -0.24;
271 fp->y = h;
272 }
273 /* touch muddy ground :) */
274 else fp->burn = 0;
275 }
276 if (fp->x < w && fp->x > 0 && fp->y < h && fp->y > 0)
277 {
278 prgba = palaka + ((int)fp->y * w + (int)fp->x) * 4;
279 prgba[0] = b;
280 prgba[1] = g;
281 prgba[2] = r;
282 }
283 }
284 return(--fs->life);
285 }
286
287 #ifdef __SSE2__
288
289 /* SSE2 optimized versions of glow_blur() and chromo_2x2_light() */
290
glow_blur(struct state * st)291 static void glow_blur(struct state *st)
292 {
293 unsigned int n, nn;
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;
299
300 xmm0 = _mm_setzero_si128();
301 nn = st->width * st->height * 4;
302 for (n = 0; n < nn; n+=16)
303 {
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);
307
308 xmm1 = _mm_load_si128((const __m128i*)&ps[n]);
309 xmm2 = xmm1;
310 xmm1 = _mm_unpacklo_epi8(xmm1,xmm0);
311 xmm2 = _mm_unpackhi_epi8(xmm2,xmm0);
312 xmm3 = _mm_loadu_si128((const __m128i*)&ps[n+4]);
313 xmm4 = xmm3;
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]);
321 xmm4 = xmm3;
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);
326
327 xmm3 = _mm_load_si128((const __m128i*)&pa[n]);
328 xmm4 = xmm3;
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]);
334 xmm4 = xmm3;
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]);
340 xmm4 = xmm3;
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);
345
346 xmm3 = _mm_load_si128((const __m128i*)&pb[n]);
347 xmm4 = xmm3;
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]);
353 xmm4 = xmm3;
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]);
359 xmm4 = xmm3;
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);
364
365 xmm3 = xmm1;
366 xmm4 = xmm2;
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);
373
374 _mm_storeu_si128((__m128i*)&ps[n+4], xmm1);
375 _mm_storeu_si128((__m128i*)&pd[n+4], xmm3);
376 }
377 }
378
chromo_2x2_light(struct state * st)379 static void chromo_2x2_light(struct state *st)
380 {
381 __m128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6;
382 __m128i xmi4, xmi5, xmi6, xmi7;
383
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;
388
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);
393
394 for (y = st->height/2; y; y--, mem += nl)
395 {
396 for (x = st->width/4; x; x--, v += 8, mem += 16)
397 {
398 xmm4 = _mm_set1_ps(st->light_map[v+0]);
399 xmm5 = xmm0;
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);
410
411 xmm4 = _mm_set1_ps(st->light_map[v+4]);
412 xmm6 = xmm0;
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);
423
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);
428
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);
438
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);
448 }
449 }
450 }
451
452 #else
453
glow_blur(struct state * st)454 static void glow_blur(struct state *st)
455 {
456 unsigned int n, q;
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);
461 /*
462 unsigned int rgba = 0;
463 for (n = st->width*st->height*4; n; n--, pm++, pa++, pb++, po++)
464 {
465 if(++rgba > 3)
466 {
467 rgba = 0;
468 continue;
469 }
470 q = pm[0] + pm[4] * 8 + pm[8] +
471 pa[0] + pa[4] + pa[8] +
472 pb[0] + pb[4] + pb[8];
473 pm[4] = q >> 4;
474 po[4] = q > 2047 ? 255 : q >> 3;
475 }
476 --- using unrolled version ------------
477 */
478 for (n = st->width*st->height*4; n; n-=4)
479 {
480 q = pm[0] + pm[4] * 8 + pm[8] +
481 pa[0] + pa[4] + pa[8] +
482 pb[0] + pb[4] + pb[8];
483 pm[4] = q >> 4;
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];
488 pm[5] = q >> 4;
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];
493 pm[6] = q >> 4;
494 po[6] = q > 2047 ? 255 : q >> 3;
495
496 pm+=4, pa+=4, pb+=4, po+=4;
497 }
498 }
499
addbs(unsigned char c,unsigned int i)500 static inline unsigned char addbs(unsigned char c, unsigned int i)
501 {
502 i += c;
503 return(i > 255 ? 255 : i);
504 }
505
chromo_2x2_light(struct state * st)506 static void chromo_2x2_light(struct state *st)
507 {
508 unsigned int n, x, y, v = 0;
509 unsigned int nl = st->width * 4;
510 unsigned char *mem = st->palaka2;
511 float r, g, b;
512 float rgb[SHELLCOUNT*4];
513 fireshell *fs = st->fireshell_array;
514
515 for (n = 0, x = 0; n < SHELLCOUNT; n++, x += 4, fs++)
516 {
517 rgb[x ] = fs->flash_r;
518 rgb[x+1] = fs->flash_g;
519 rgb[x+2] = fs->flash_b;
520 }
521
522 for (y = st->height/2; y; y--)
523 {
524 for (x = st->width/2; x; x--, v += 4)
525 {
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];
532
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);
539
540 mem += nl;
541
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);
548
549 mem -= nl - 8;
550 }
551 mem += nl;
552 }
553 }
554
555 #endif
556
resize(struct state * st)557 static void resize(struct state *st)
558 {
559 unsigned int n;
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;
567 if (st->verbose)
568 {
569 printf("resolution: %d x %d \n",st->width,st->height);
570 }
571 XSync(st->dpy, 0);
572 if (st->xim)
573 {
574 /* if (st->xim->data == (char *)st->palaka2) */
575 st->xim->data = NULL;
576 XDestroyImage(st->xim);
577 XSync(st->dpy, 0);
578 free(st->mem2);
579 free(st->mem1);
580 st->xim = 0;
581 }
582 st->xim = XCreateImage(st->dpy, xwa.visual, xwa.depth, ZPixmap, 0, 0,
583 st->width, st->height, 8, 0);
584 if (!st->xim) return;
585
586 #ifdef __SSE2___ABANDONED /* causes __ERROR_use_memset_not_bzero_in_xscreensaver__ */
587 st->mem1 = _mm_malloc(((st->height + 2) * st->width + 8)*4, 16);
588 bzero(st->mem1, ((st->height + 2) * st->width + 8)*4);
589 st->mem2 = _mm_malloc(((st->height + 2) * st->width + 8)*4, 16);
590 bzero(st->mem2, ((st->height + 2) * st->width + 8)*4);
591 #else
592 st->mem1 = calloc((st->height + 2) * st->width + 8, 4);
593 st->mem2 = calloc((st->height + 2) * st->width + 8, 4);
594 #endif
595 st->palaka1 = (unsigned char *) st->mem1 + (st->width * 4 + 16);
596 st->palaka2 = (unsigned char *) st->mem2 + (st->width * 4 + 16);
597
598 if (xwa.depth >= 24)
599 {
600 st->xim->data = (char *)st->palaka2;
601 }
602 else
603 {
604 st->xim->data = calloc(st->height, st->xim->bytes_per_line);
605 }
606
607 if (st->light_map) free(st->light_map);
608 st->light_map = calloc((st->width * st->height * SHELLCOUNT)/4, sizeof(float));
609 for (n = 0; n < SHELLCOUNT; n++, fs++)
610 {
611 render_light_map(st, fs);
612 }
613 }
614
put_image(struct state * st)615 static void put_image(struct state *st)
616 {
617 int x,y,i,j;
618 unsigned char r, g, b;
619 if (!st->xim) return;
620 i = 0;
621 j = 0;
622 if (st->depth==16)
623 {
624 if(st->bigendian)
625 for (y=0; y<st->xim->height; y++)
626 for (x=0; x<st->xim->width; x++)
627 {
628 r = st->palaka2[j++];
629 g = st->palaka2[j++];
630 b = st->palaka2[j++];
631 j++;
632 st->xim->data[i++] = (g&224)>>5 | (r&248);
633 st->xim->data[i++] = (b&248)>>3 | (g&28)<<3;
634 }
635 else
636 for (y=0; y<st->xim->height; y++)
637 for (x=0; x<st->xim->width; x++)
638 {
639 r = st->palaka2[j++];
640 g = st->palaka2[j++];
641 b = st->palaka2[j++];
642 j++;
643 st->xim->data[i++] = (b&248)>>3 | (g&28)<<3;
644 st->xim->data[i++] = (g&224)>>5 | (r&248);
645 }
646 }
647 if (st->depth==15)
648 {
649 if(st->bigendian)
650 for (y=0; y<st->xim->height; y++)
651 for (x=0; x<st->xim->width; x++)
652 {
653 r = st->palaka2[j++];
654 g = st->palaka2[j++];
655 b = st->palaka2[j++];
656 j++;
657 st->xim->data[i++] = (g&192)>>6 | (r&248)>>1;
658 st->xim->data[i++] = (b&248)>>3 | (g&56)<<2;
659 }
660 else
661 for (y=0; y<st->xim->height; y++)
662 for (x=0; x<st->xim->width; x++)
663 {
664 r = st->palaka2[j++];
665 g = st->palaka2[j++];
666 b = st->palaka2[j++];
667 j++;
668 st->xim->data[i++] = (b&248)>>3 | (g&56)<<2;
669 st->xim->data[i++] = (g&192)>>6 | (r&248)>>1;
670 }
671 }
672 if (st->depth==8)
673 {
674 for (y=0; y<st->xim->height; y++)
675 for (x=0; x<st->xim->width; x++)
676 {
677 r = st->palaka2[j++];
678 g = st->palaka2[j++];
679 b = st->palaka2[j++];
680 j++;
681 st->xim->data[i++] = (((7*g)/256)*36)+(((6*r)/256)*6)+((6*b)/256);
682 }
683 }
684 XPutImage(st->dpy,st->window,st->gc,st->xim,0,0,0,0,st->xim->width,st->xim->height);
685 }
686
687 static void *
fireworkx_init(Display * dpy,Window win)688 fireworkx_init (Display *dpy, Window win)
689 {
690 struct state *st = (struct state *) calloc (1, sizeof(*st));
691 unsigned int n;
692 Visual *vi;
693 Colormap cmap;
694 Bool writable;
695 XWindowAttributes xwa;
696 XGCValues gcv;
697 firepix *fp;
698 fireshell *fs;
699
700 st->dpy = dpy;
701 st->window = win;
702 st->xim = NULL;
703 st->flash_on = 1;
704 st->shoot = 0;
705 st->width = 0;
706 st->height = 0;
707 st->max_shell_life = SHELL_LIFE_DEFAULT;
708 st->flash_fade = 0.995;
709 st->light_map = NULL;
710 st->palaka1 = NULL;
711 st->palaka2 = NULL;
712
713 st->flash_on = get_boolean_resource(st->dpy, "flash" , "Boolean");
714 st->shoot = get_boolean_resource(st->dpy, "shoot" , "Boolean");
715 st->verbose = get_boolean_resource(st->dpy, "verbose" , "Boolean");
716 st->max_shell_life = get_integer_resource(st->dpy, "maxlife" , "Integer");
717 /* transition from xscreensaver <= 5.20 */
718 if (st->max_shell_life > 100) st->max_shell_life = 100;
719
720 st->delay = get_integer_resource(st->dpy, "delay" , "Integer");
721
722 st->max_shell_life = pow(10.0,(st->max_shell_life/50.0)+2.7);
723 if(st->max_shell_life < 1000) st->flash_fade = 0.998;
724
725 if(st->verbose)
726 {
727 printf("Fireworkx %s - Pyrotechnics explosions simulation \n", FWXVERSION);
728 printf("Copyright (GPL) 1999-2013 Rony B Chandran <ronybc@gmail.com> \n\n");
729 printf("url: http://www.ronybc.com \n\n");
730 printf("Life = %u\n", st->max_shell_life);
731 #ifdef __SSE2__
732 printf("Using SSE2 optimization.\n");
733 #endif
734 }
735
736 XGetWindowAttributes(st->dpy,win,&xwa);
737 st->depth = xwa.depth;
738 vi = xwa.visual;
739 cmap = xwa.colormap;
740 st->bigendian = (ImageByteOrder(st->dpy) == MSBFirst);
741
742 if(st->depth==8)
743 {
744 st->colors = (XColor *) calloc(sizeof(XColor),st->ncolors+1);
745 writable = False;
746 make_smooth_colormap(xwa.screen, vi, cmap,
747 st->colors, &st->ncolors,
748 False, &writable, True);
749 }
750 st->gc = XCreateGC(st->dpy, win, 0, &gcv);
751
752 fs = calloc(SHELLCOUNT, sizeof(fireshell));
753 fp = calloc(PIXCOUNT * SHELLCOUNT, sizeof(firepix));
754 st->fireshell_array = fs;
755
756 XGetWindowAttributes (st->dpy, st->window, &xwa);
757 st->depth = xwa.depth;
758
759 resize(st); /* initialize palakas */
760
761 for (n = 0; n < SHELLCOUNT; n++, fs++)
762 {
763 fs->seq_number = n;
764 fs->fpix = fp;
765 recycle (st, fs, rnd(st->width), rnd(st->height));
766 fp += PIXCOUNT;
767 }
768
769 return st;
770 }
771
772 static unsigned long
fireworkx_draw(Display * dpy,Window win,void * closure)773 fireworkx_draw (Display *dpy, Window win, void *closure)
774 {
775 struct state *st = (struct state *) closure;
776 fireshell *fs;
777 unsigned int n, q;
778 for (q = FTWEAK; q; q--)
779 {
780 fs = st->fireshell_array;
781 for (n = 0; n < SHELLCOUNT; n++, fs++)
782 {
783 if (!explode(st, fs))
784 {
785 if (st->button_down_p)
786 st->deferred++;
787 else
788 recycle(st, fs, rnd(st->width), rnd(st->height));
789 }
790 }
791 }
792
793 while (!st->button_down_p && st->deferred) {
794 st->deferred--;
795 recycle_oldest(st, rnd(st->width), rnd(st->height));
796 }
797
798 glow_blur(st);
799
800 if (st->flash_on)
801 {
802 chromo_2x2_light(st);
803 }
804
805 put_image(st);
806 return st->delay;
807 }
808
809 static void
fireworkx_reshape(Display * dpy,Window window,void * closure,unsigned int w,unsigned int h)810 fireworkx_reshape (Display *dpy, Window window, void *closure,
811 unsigned int w, unsigned int h)
812 {
813 struct state *st = (struct state *) closure;
814 st->width = w;
815 st->height = h;
816 resize(st);
817 }
818
819 static Bool
fireworkx_event(Display * dpy,Window window,void * closure,XEvent * event)820 fireworkx_event (Display *dpy, Window window, void *closure, XEvent *event)
821 {
822 struct state *st = (struct state *) closure;
823 if (event->type == ButtonPress)
824 {
825 recycle_oldest(st, event->xbutton.x, event->xbutton.y);
826 st->button_down_p = True;
827 return True;
828 }
829 else if (event->type == ButtonRelease)
830 {
831 st->button_down_p = False;
832 return True;
833 }
834
835 return False;
836 }
837
838 static void
fireworkx_free(Display * dpy,Window window,void * closure)839 fireworkx_free (Display *dpy, Window window, void *closure)
840 {
841 struct state *st = (struct state *) closure;
842 free(st->mem2);
843 free(st->mem1);
844 free(st->fireshell_array->fpix);
845 free(st->fireshell_array);
846 if (st->xim) {
847 st->xim->data = NULL;
848 XDestroyImage (st->xim);
849 }
850 if (st->light_map) free(st->light_map);
851 if (st->colors) free (st->colors);
852 XFreeGC (dpy, st->gc);
853 free(st);
854 }
855
856 static const char *fireworkx_defaults [] =
857 {
858 ".background: black",
859 ".foreground: white",
860 "*delay: 10000", /* never default to zero! */
861 "*maxlife: 32",
862 "*flash: True",
863 "*shoot: False",
864 "*verbose: False",
865 ".lowrez: true", /* Too slow on Retina screens otherwise */
866 0
867 };
868
869 static XrmOptionDescRec fireworkx_options [] =
870 {
871 { "-delay", ".delay", XrmoptionSepArg, 0 },
872 { "-maxlife", ".maxlife", XrmoptionSepArg, 0 },
873 { "-no-flash", ".flash", XrmoptionNoArg, "False" },
874 { "-shoot", ".shoot", XrmoptionNoArg, "True" },
875 { "-verbose", ".verbose", XrmoptionNoArg, "True" },
876 { 0, 0, 0, 0 }
877 };
878
879 XSCREENSAVER_MODULE ("Fireworkx", fireworkx)
880