2 * Fireworkx 1.6 - pyrotechnics simulation program (XScreensaver version)
3 * Copyright (c) 1999-2007 Rony B Chandran <ronybc@asia.com>
7 * url: http://www.ronybc.8k.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 * Additional programming:
18 * ------------------------
19 * Support for different dpy color modes:
20 * Jean-Pierre Demailly <Jean-Pierre.Demailly@ujf-grenoble.fr>
22 * Fixed array access problems by beating on it with a large hammer.
23 * Nicholas Miell <nmiell@gmail.com>
25 * Freed 'free'ing up of memory by adding the forgotten 'XSync's
26 * Renuka S <renuka@local.net>
31 #include "screenhack.h"
33 #define FWXVERSION "1.6"
35 #define SHELLCOUNT 3 /* 3 ; see light() before changing this value */
36 #define PIXCOUNT 500 /* 500 */
37 #define POWER 5 /* 5 */
38 #define FTWEAK 12 /* 12 */
41 void mmx_blur(char *a, int b, int c, int d);
42 void mmx_glow(char *a, int b, int c, int d, char *e);
45 #define rnd(x) ((x) ? (int)(random() % (x)) : 0)
62 firepix *fpix; }fireshell;
68 fireshell *fshell, *ffshell;
83 unsigned char *palaka1;
84 unsigned char *palaka2;
90 static int explode(struct state *st, fireshell *fs)
92 float air,adg = 0.001; /* gravity */
94 unsigned int h = st->height;
95 unsigned int w = st->width;
97 unsigned char *palaka = st->palaka1;
98 firepix *fp = fs->fpix;
100 if(--fs->cy == fs->shy){
102 fs->flash = rnd(30000)+25000;
103 fs->flash = fs->flash*fs->flash; }
105 fs->flash = 200000+(fs->cy - fs->shy)*(fs->cy - fs->shy)*8;
106 prgb=(unsigned int *)(palaka + (fs->cy * w + fs->cx + rnd(5)-2)*4);
107 *prgb=(rnd(8)+8)*0x000f0f10;
109 if(fs->cshift) --fs->cshift;
110 if((fs->cshift+1)%50==0) fs->color = ~fs->color;
113 fs->flash *= st->flash_fade;
114 for(n=PIXCOUNT;n;n--){
115 if(fp->burn){ --fp->burn;
117 fp->x += fp->xv = fp->xv * air + (float)(rnd(200)-100)/2000;
118 fp->y += fp->yv = fp->yv * air + (float)(rnd(200)-100)/2000+ adg;}
120 fp->x += fp->xv = fp->xv * air + (float)(rnd(200)-100)/20000;
121 fp->y += fp->yv = fp->yv * air + (float)(rnd(200)-100)/40000+ adg; }
123 if(rnd(5)==3) {fp->yv *= -0.24; fp->y = h;}
124 else fp->burn=0;} /* touch muddy ground :) */
125 if(fp->x < w && fp->x > 0 && fp->y < h && fp->y > 0){
126 prgb = (unsigned int *)(palaka + ((int)fp->y * w + (int)fp->x)*4);
129 } return(--fs->life); }
131 static void recycle(struct state *st, fireshell *fs,int x,int y)
133 unsigned int n,pixlife;
134 firepix *fp = fs->fpix;
138 fs->cy = st->shoot ? st->height : y ;
139 fs->color = (rnd(155)+100) <<16 |
142 fs->life = rnd(st->rndlife)+st->minlife;
143 fs->air = 1-(float)(rnd(200))/10000;
144 fs->flash = rnd(30000)+25000; /* million jouls... */
145 fs->flash = fs->flash*fs->flash;
146 fs->cshift = !rnd(5) ? 120:0;
147 fs->special = !rnd(10) ? 1:0;
149 printf("recycle(): color = %x air = %f life = %d \n",fs->color,fs->air,fs->life);
150 pixlife = rnd(fs->life)+fs->life/10+1; /* ! */
151 for(n=0;n<PIXCOUNT;n++){
152 fp->burn = rnd(pixlife)+32;
153 fp->xv = POWER*(float)(rnd(20000)-10000)/10000;
154 fp->yv = sqrt(POWER*POWER - fp->xv * fp->xv) *
155 (float)(rnd(20000)-10000)/10000;
160 static void glow(struct state *st)
163 unsigned int w = st->width;
164 unsigned int h = st->height;
165 unsigned char *pa, *pb, *pm, *po;
166 if (!st->xim) return;
170 {pm[n]=0; po[n]=0;} /* clean first line */
174 for(n=4;n<w*h*4-4;n++){
175 q = pm[n-4] + (pm[n]*8) + pm[n+4] +
176 pa[n-4] + pa[n] + pa[n+4] +
177 pb[n-4] + pb[n] + pb[n+4];
181 po[n] = q>255 ? 255 : q;}
184 {pm[n]=0; po[n]=0;}} /* clean last line */
186 static void blur(struct state *st)
189 unsigned int w = st->width;
190 unsigned int h = st->height;
191 unsigned char *pa, *pb, *pm;
193 pm += w*4; h-=2; /* line 0&h */
196 for(n=4;n<w*h*4-4;n++){
197 q = pm[n-4] + (pm[n]*8) + pm[n+4] +
198 pa[n-4] + pa[n] + pa[n+4] +
199 pb[n-4] + pb[n] + pb[n+4];
202 pm += n-4; /* last line */
203 for(n=0;n<w*4+4;n++) pm[n]=0;
204 pm = st->palaka1; /* first line */
205 for(n=0;n<w*4+4;n++) pm[n]=pm[n+w*4]; }
207 static void light_2x2(struct state *st, fireshell *fss)
209 unsigned int l,t,x,y;
213 unsigned char *dim = st->palaka2;
214 unsigned char *sim = st->palaka1;
217 if(st->glow_on) sim=dim;
222 /* Note: The follwing loop is unrolled for speed.
223 check this before changing the value of SHELLCOUNT
225 for(n=SHELLCOUNT;n;n--,f++){
226 s += f->flash/(1+(f->cx - x)*(f->cx - x)+(f->cy - y)*(f->cy - y));} */
228 s = f->flash/(1+(f->cx - x)*(f->cx - x)+(f->cy - y)*(f->cy - y));
230 s += f->flash/(1+(f->cx - x)*(f->cx - x)+(f->cy - y)*(f->cy - y));
232 s += f->flash/(1+(f->cx - x)*(f->cx - x)+(f->cy - y)*(f->cy - y));
237 dim[0] = (t > 255 ? 255 : t);
239 dim[1] = (t > 255 ? 255 : t);
241 dim[2] = (t > 255 ? 255 : t);
244 dim[4] = (t > 255 ? 255 : t);
246 dim[5] = (t > 255 ? 255 : t);
248 dim[6] = (t > 255 ? 255 : t);
251 dim[nl+0] = (t > 255 ? 255 : t);
253 dim[nl+1] = (t > 255 ? 255 : t);
255 dim[nl+2] = (t > 255 ? 255 : t);
258 dim[nl+4] = (t > 255 ? 255 : t);
260 dim[nl+5] = (t > 255 ? 255 : t);
262 dim[nl+6] = (t > 255 ? 255 : t);
264 sim += 8; dim += 8; } sim += nl; dim += nl;}}
266 static void resize(struct state *st)
268 XWindowAttributes xwa;
269 XGetWindowAttributes (st->dpy, st->window, &xwa);
270 xwa.width -= xwa.width % 2;
271 xwa.height -= xwa.height % 2;
272 if(xwa.height != st->height || xwa.width != st->width) {
273 st->width = xwa.width;
274 st->height = xwa.height;
276 printf("sky size: %dx%d ------------------------------\n",st->width,st->height);
278 if (st->xim->data==(char *)st->palaka2) st->xim->data=NULL;
279 XDestroyImage(st->xim);
280 if (st->palaka2!=st->palaka1) free(st->palaka2 - 8);
281 free(st->palaka1 - 8);
285 st->xim = XCreateImage(st->dpy, xwa.visual, xwa.depth, ZPixmap, 0, 0,
286 st->width, st->height, 8, 0);
287 if (!st->xim) return;
288 st->palaka1 = (unsigned char *) calloc(st->xim->height+1,st->xim->width*4) + 8;
289 if(st->flash_on|st->glow_on)
290 st->palaka2 = (unsigned char *) calloc(st->xim->height+1,st->xim->width*4) + 8;
292 st->palaka2 = st->palaka1;
294 st->xim->data = (char *)st->palaka2;
296 st->xim->data = calloc(st->xim->height,st->xim->bytes_per_line); }}
298 static void put_image(struct state *st)
301 unsigned char r, g, b;
302 if (!st->xim) return;
307 for (y=0;y<st->xim->height; y++)
308 for (x=0;x<st->xim->width; x++) {
309 r = st->palaka2[j++];
310 g = st->palaka2[j++];
311 b = st->palaka2[j++];
313 st->xim->data[i++] = (g&224)>>5 | (r&248);
314 st->xim->data[i++] = (b&248)>>3 | (g&28)<<3;
317 for (y=0;y<st->xim->height; y++)
318 for (x=0;x<st->xim->width; x++) {
319 r = st->palaka2[j++];
320 g = st->palaka2[j++];
321 b = st->palaka2[j++];
323 st->xim->data[i++] = (b&248)>>3 | (g&28)<<3;
324 st->xim->data[i++] = (g&224)>>5 | (r&248);
329 for (y=0;y<st->xim->height; y++)
330 for (x=0;x<st->xim->width; x++) {
331 r = st->palaka2[j++];
332 g = st->palaka2[j++];
333 b = st->palaka2[j++];
335 st->xim->data[i++] = (g&192)>>6 | (r&248)>>1;
336 st->xim->data[i++] = (b&248)>>3 | (g&56)<<2;
339 for (y=0;y<st->xim->height; y++)
340 for (x=0;x<st->xim->width; x++) {
341 r = st->palaka2[j++];
342 g = st->palaka2[j++];
343 b = st->palaka2[j++];
345 st->xim->data[i++] = (b&248)>>3 | (g&56)<<2;
346 st->xim->data[i++] = (g&192)>>6 | (r&248)>>1;
350 for (y=0;y<st->xim->height; y++)
351 for (x=0;x<st->xim->width; x++) {
352 r = st->palaka2[j++];
353 g = st->palaka2[j++];
354 b = st->palaka2[j++];
356 st->xim->data[i++] = (((7*g)/256)*36)+(((6*r)/256)*6)+((6*b)/256);
359 XPutImage(st->dpy,st->window,st->gc,st->xim,0,0,0,0,st->xim->width,st->xim->height); }
363 fireworkx_init (Display *dpy, Window win)
365 struct state *st = (struct state *) calloc (1, sizeof(*st));
370 XWindowAttributes xwa;
372 firepix *fpix, *ffpix;
377 st->glow_on = get_boolean_resource(st->dpy, "glow" , "Boolean");
378 st->flash_on = get_boolean_resource(st->dpy, "flash" , "Boolean");
379 st->shoot = get_boolean_resource(st->dpy, "shoot" , "Boolean");
380 st->verbose = get_boolean_resource(st->dpy, "verbose" , "Boolean");
381 st->rndlife = get_integer_resource(st->dpy, "maxlife" , "Integer");
382 st->delay = get_integer_resource(st->dpy, "delay" , "Integer");
383 st->minlife = st->rndlife/4;
385 if(st->rndlife < 1000) st->flash_fade=0.96;
386 if(st->rndlife < 500) st->flash_fade=0.94;
388 printf("Fireworkx %s - pyrotechnics simulation program \n", FWXVERSION);
389 printf("Copyright (c) 1999-2007 Rony B Chandran <ronybc@asia.com> \n\n");
390 printf("url: http://www.ronybc.8k.com \n\n");}
392 XGetWindowAttributes(st->dpy,win,&xwa);
393 st->depth = xwa.depth;
396 st->bigendian = (ImageByteOrder(st->dpy) == MSBFirst);
400 printf("Pseudocolor color: use '-no-flash' for better results.\n");}
401 st->colors = (XColor *) calloc(sizeof(XColor),st->ncolors+1);
403 make_smooth_colormap(st->dpy, vi, cmap, st->colors, &st->ncolors,
404 False, &writable, True);
406 st->gc = XCreateGC(st->dpy, win, 0, &gcv);
408 resize(st); /* initialize palakas */
410 ffpix = malloc(sizeof(firepix) * PIXCOUNT * SHELLCOUNT);
411 st->ffshell = malloc(sizeof(fireshell) * SHELLCOUNT);
412 st->fshell = st->ffshell;
414 for (n=0;n<SHELLCOUNT;n++){
415 st->fshell->fpix = fpix;
416 recycle (st, st->fshell,rnd(st->width),rnd(st->height));
425 fireworkx_draw (Display *dpy, Window win, void *closure)
427 struct state *st = (struct state *) closure;
430 st->fshell=st->ffshell;
431 for(n=SHELLCOUNT;n;n--){
432 if (!explode(st, st->fshell)){
433 recycle(st, st->fshell,rnd(st->width),rnd(st->height)); }
436 if(st->glow_on) mmx_glow(st->palaka1,st->width,st->height,8,st->palaka2);
438 if(st->glow_on) glow(st);
440 if(st->flash_on) light_2x2(st, st->ffshell);
443 if(!st->glow_on) mmx_blur(st->palaka1,st->width,st->height,8);
445 if(!st->glow_on) blur(st);
453 fireworkx_reshape (Display *dpy, Window window, void *closure,
454 unsigned int w, unsigned int h)
456 struct state *st = (struct state *) closure;
461 fireworkx_event (Display *dpy, Window window, void *closure, XEvent *event)
463 struct state *st = (struct state *) closure;
464 if (event->type == ButtonPress) {
465 recycle(st, st->ffshell, event->xbutton.x, event->xbutton.y);
472 fireworkx_free (Display *dpy, Window window, void *closure)
477 static const char *fireworkx_defaults [] = {
478 ".background: black",
479 ".foreground: white",
480 "*delay: 20000", /* never default to zero! */
489 static XrmOptionDescRec fireworkx_options [] = {
490 { "-delay", ".delay", XrmoptionSepArg, 0 },
491 { "-maxlife", ".maxlife", XrmoptionSepArg, 0 },
492 { "-no-flash", ".flash", XrmoptionNoArg, "False" },
493 { "-no-glow", ".glow", XrmoptionNoArg, "False" },
494 { "-shoot", ".shoot", XrmoptionNoArg, "True" },
495 { "-verbose", ".verbose", XrmoptionNoArg, "True" },
499 XSCREENSAVER_MODULE ("Fireworkx", fireworkx)