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