dtscreen: Resolve (all) 11 warnigns caused by -Wall
[oweals/cde.git] / cde / programs / dtscreen / pyro.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: pyro.c /main/3 1995/11/02 16:07:59 rswiston $ */
24 /*
25  */
26 /*                                                                      *
27  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
28  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
29  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
30  * (c) Copyright 1993, 1994 Novell, Inc.                                *
31  */
32 /*-
33  * pyro.c - Fireworks for dtscreen, the X Window System lockscreen.
34  *
35  * Copyright (c) 1991 by Patrick J. Naughton.
36  *
37  * See dtscreen.c for copying information.
38  *
39  * Revision History:
40  * 16-Mar-91: Written. (received from David Brooks, brooks@osf.org).
41  */
42
43 /* The physics of the rockets is a little bogus, but it looks OK.  Each is
44  * given an initial velocity impetus.  They decelerate slightly (gravity
45  * overcomes the rocket's impulse) and explode as the rocket's main fuse
46  * gives out (we could add a ballistic stage, maybe).  The individual
47  * stars fan out from the rocket, and they decelerate less quickly.
48  * That's called bouyancy, but really it's again a visual preference.
49  */
50
51 #include "dtscreen.h"
52 #include <math.h>
53 #include <stdlib.h>
54
55 #define TWOPI 6.2831853
56
57 /* Define this >1 to get small rectangles instead of points */
58 #ifndef STARSIZE
59 #define STARSIZE 2
60 #endif
61
62 #define SILENT 0
63 #define REDGLARE 1
64 #define BURSTINGINAIR 2
65
66 #define CLOUD 0
67 #define DOUBLECLOUD 1
68 /* Clearly other types and other fascinating visual effects could be added...*/
69
70 /* P_xxx parameters represent the reciprocal of the probability... */
71 #define P_IGNITE 5000           /* ...of ignition per cycle */
72 #define P_DOUBLECLOUD 10        /* ...of an ignition being double */
73 #define P_MULTI 75              /* ...of an ignition being several @ once */
74 #define P_FUSILLADE 250         /* ...of an ignition starting a fusillade */
75
76 #define ROCKETW 2               /* Dimensions of rocket */
77 #define ROCKETH 4
78 #define XVELFACTOR 0.0025       /* Max horizontal velocity / screen width */
79 #define MINYVELFACTOR 0.016     /* Min vertical velocity / screen height */
80 #define MAXYVELFACTOR 0.018
81 #define GRAVFACTOR 0.0002       /* delta v / screen height */
82 #define MINFUSE 50              /* range of fuse lengths for rocket */
83 #define MAXFUSE 100
84
85 #define FUSILFACTOR 10          /* Generate fusillade by reducing P_IGNITE */
86 #define FUSILLEN 100            /* Length of fusillade, in ignitions */
87
88 #define SVELFACTOR 0.1          /* Max star velocity / yvel */
89 #define BOUYANCY 0.2            /* Reduction in grav deceleration for stars */
90 #define MAXSTARS 75             /* Number of stars issued from a shell */
91 #define MINSTARS 50
92 #define MINSFUSE 50             /* Range of fuse lengths for stars */
93 #define MAXSFUSE 100
94
95 #define INTRAND(min,max) (random()%((max+1)-(min))+(min))
96 #define FLOATRAND(min,max) ((min)+(random()/MAXRAND)*((max)-(min)))
97
98 static void ignite();
99 static void animate();
100 static void shootup();
101 static void burst();
102
103 typedef struct {
104     int         state;
105     int         shelltype;
106     int         color1, color2;
107     int         fuse;
108     float       xvel, yvel;
109     float       x, y;
110     int         nstars;
111 #if STARSIZE > 1
112     XRectangle  Xpoints[MAXSTARS];
113     XRectangle  Xpoints2[MAXSTARS];
114 #else
115     XPoint      Xpoints[MAXSTARS];
116     XPoint      Xpoints2[MAXSTARS];
117 #endif
118     float       sx[MAXSTARS], sy[MAXSTARS];     /* Distance from notional
119                                                  * center  */
120     float       sxvel[MAXSTARS], syvel[MAXSTARS];       /* Relative to notional
121                                                          * center */
122 }           rocket;
123
124 typedef struct {
125     Screen     *scr;
126     Colormap    cmap;
127     int         p_ignite;
128     unsigned long bgpixel;
129     unsigned long fgpixel;
130     unsigned long rockpixel;
131     GC          bgGC;
132     int         nflying;
133     int         fusilcount;
134     int         width, lmargin, rmargin, height;
135     float       minvelx, maxvelx;
136     float       minvely, maxvely;
137     float       maxsvel;
138     float       rockdecel, stardecel;
139     rocket     *rockq;
140 }           pyrostruct;
141
142 static int  orig_p_ignite;
143 static int  just_started = True;/* Greet the user right away */
144
145 void
146 initpyro(pwin)
147     perwindow *pwin;
148 {
149     pyrostruct *pp;
150     rocket     *rp;
151     XWindowAttributes xwa;
152     XGCValues   xgcv;
153     int         rockn, starn, bsize;
154
155     if (pwin->data) free(pwin->data);
156     pwin->data = (pyrostruct *)malloc(sizeof(pyrostruct));
157     memset(pwin->data, '\0', sizeof(pyrostruct));
158     pp = (pyrostruct *)pwin->data;
159     XGetWindowAttributes(dsp, pwin->w, &xwa);
160
161     orig_p_ignite = P_IGNITE / batchcount;
162     if (orig_p_ignite <= 0)
163         orig_p_ignite = 1;
164     pp->p_ignite = orig_p_ignite;
165
166     pp->rockq = (rocket *) malloc(batchcount * sizeof(rocket));
167
168     pp->nflying = pp->fusilcount = 0;
169
170     bsize = (xwa.height <= 64) ? 1 : STARSIZE;
171     for (rockn = 0, rp = pp->rockq; rockn < batchcount; rockn++, rp++) {
172         rp->state = SILENT;
173 #if STARSIZE > 1
174         for (starn = 0; starn < MAXSTARS; starn++) {
175             rp->Xpoints[starn].width = rp->Xpoints[starn].height =
176                 rp->Xpoints2[starn].width = rp->Xpoints2[starn].height = bsize;
177         }
178 #endif
179     }
180
181     pp->width = xwa.width;
182     pp->lmargin = xwa.width / 16;
183     pp->rmargin = xwa.width - pp->lmargin;
184     pp->height = xwa.height;
185     pp->scr = pwin->perscreen->screen;
186     pp->cmap = DefaultColormapOfScreen(pp->scr);
187
188     pp->fgpixel = WhitePixelOfScreen(pp->scr);
189     pp->bgpixel = BlackPixelOfScreen(pp->scr);
190     if (!mono && pwin->perscreen->npixels > 3)
191         pp->rockpixel = pwin->perscreen->pixels[3];/* Just the right shade of
192                                                  * orange */
193     else
194         pp->rockpixel = pp->fgpixel;
195
196     xgcv.foreground = pp->bgpixel;
197     pp->bgGC = XCreateGC(dsp, pwin->w, GCForeground, &xgcv);
198     
199 /* Geometry-dependent physical data: */
200     pp->maxvelx = (float) (xwa.width) * XVELFACTOR;
201     pp->minvelx = -pp->maxvelx;
202     pp->minvely = -(float) (xwa.height) * MINYVELFACTOR;
203     pp->maxvely = -(float) (xwa.height) * MAXYVELFACTOR;
204     pp->maxsvel = pp->minvely * SVELFACTOR;
205     pp->rockdecel = (float) (pp->height) * GRAVFACTOR;
206     pp->stardecel = pp->rockdecel * BOUYANCY;
207
208     XFillRectangle(dsp, pwin->w, pp->bgGC, 0, 0, xwa.width, xwa.height);
209 }
210
211 /*ARGSUSED*/
212 void
213 drawpyro(pwin)
214     perwindow *pwin;
215 {
216     pyrostruct *pp;
217     rocket     *rp;
218     int         rockn;
219
220     pp = (pyrostruct *)pwin->data;
221     if (just_started || (random() % pp->p_ignite == 0)) {
222         just_started = False;
223         if (random() % P_FUSILLADE == 0) {
224             pp->p_ignite = orig_p_ignite / FUSILFACTOR;
225             pp->fusilcount = INTRAND(FUSILLEN * 9 / 10, FUSILLEN * 11 / 10);
226         }
227         ignite(pwin, pp);
228         if (pp->fusilcount > 0) {
229             if (--pp->fusilcount == 0)
230                 pp->p_ignite = orig_p_ignite;
231         }
232     }
233     for (rockn = pp->nflying, rp = pp->rockq; rockn > 0; rp++) {
234         if (rp->state != SILENT) {
235             animate(pwin, pp, rp);
236             rockn--;
237         }
238     }
239 }
240
241 static void
242 ignite(pwin, pp)
243     perwindow *pwin;
244     pyrostruct *pp;
245 {
246     rocket     *rp;
247     int         multi, shelltype, nstars, fuse, npix, pix, color1, color2;
248     float       xvel, yvel, x;
249
250     x = random() % pp->width;
251     xvel = FLOATRAND(-pp->maxvelx, pp->maxvelx);
252 /* All this to stop too many rockets going offscreen: */
253     if ((x < pp->lmargin && xvel < 0.0) || (x > pp->rmargin && xvel > 0.0))
254         xvel = -xvel;
255     yvel = FLOATRAND(pp->minvely, pp->maxvely);
256     fuse = INTRAND(MINFUSE, MAXFUSE);
257     nstars = INTRAND(MINSTARS, MAXSTARS);
258     if (!mono && (npix = pwin->perscreen->npixels) > 2) {
259         color1 = pwin->perscreen->pixels[pix = random() % npix];
260         color2 = pwin->perscreen->pixels[(pix + (npix / 2)) % npix];
261     } else {
262         color1 = color2 = WhitePixelOfScreen(pwin->perscreen->screen);
263     }
264
265     multi = 1;
266     if (random() % P_DOUBLECLOUD == 0)
267         shelltype = DOUBLECLOUD;
268     else {
269         shelltype = CLOUD;
270         if (random() % P_MULTI == 0)
271             multi = INTRAND(5, 15);
272     }
273
274     rp = pp->rockq;
275     while (multi--) {
276         if (pp->nflying >= batchcount)
277             return;
278         while (rp->state != SILENT)
279             rp++;
280         pp->nflying++;
281         rp->shelltype = shelltype;
282         rp->state = REDGLARE;
283         rp->color1 = color1;
284         rp->color2 = color2;
285         rp->xvel = xvel;
286         rp->yvel = FLOATRAND(yvel * 0.97, yvel * 1.03);
287         rp->fuse = INTRAND((fuse * 90) / 100, (fuse * 110) / 100);
288         rp->x = x + FLOATRAND(multi * 7.6, multi * 8.4);
289         rp->y = pp->height - 1;
290         rp->nstars = nstars;
291     }
292 }
293
294 static void
295 animate(pwin, pp, rp)
296     perwindow *pwin;
297     pyrostruct *pp;
298     rocket     *rp;
299 {
300     int         starn;
301     float       r, theta;
302
303     if (rp->state == REDGLARE) {
304         shootup(pwin, pp, rp);
305
306 /* Handle setup for explosion */
307         if (rp->state == BURSTINGINAIR) {
308             for (starn = 0; starn < rp->nstars; starn++) {
309                 rp->sx[starn] = rp->sy[starn] = 0.0;
310                 rp->Xpoints[starn].x = (int) rp->x;
311                 rp->Xpoints[starn].y = (int) rp->y;
312                 if (rp->shelltype == DOUBLECLOUD) {
313                     rp->Xpoints2[starn].x = (int) rp->x;
314                     rp->Xpoints2[starn].y = (int) rp->y;
315                 }
316 /* This isn't accurate solid geometry, but it looks OK. */
317
318                 r = FLOATRAND(0.0, pp->maxsvel);
319                 theta = FLOATRAND(0.0, TWOPI);
320                 rp->sxvel[starn] = r * cos(theta);
321                 rp->syvel[starn] = r * sin(theta);
322             }
323             rp->fuse = INTRAND(MINSFUSE, MAXSFUSE);
324         }
325     }
326     if (rp->state == BURSTINGINAIR) {
327         burst(pwin, pp, rp);
328     }
329 }
330
331 static void
332 shootup(pwin, pp, rp)
333     perwindow *pwin;
334     pyrostruct *pp;
335     rocket     *rp;
336 {
337     XFillRectangle(dsp, pwin->w, pp->bgGC, (int) (rp->x), (int) (rp->y),
338                    ROCKETW, ROCKETH + 3);
339
340     if (rp->fuse-- <= 0) {
341         rp->state = BURSTINGINAIR;
342         return;
343     }
344     rp->x += rp->xvel;
345     rp->y += rp->yvel;
346     rp->yvel += pp->rockdecel;
347     XSetForeground(dsp, pwin->gc, pp->rockpixel);
348     XFillRectangle(dsp, pwin->w, pwin->gc, (int) (rp->x), (int) (rp->y),
349                    ROCKETW, ROCKETH + random() % 4);
350 }
351
352 static void
353 burst(pwin, pp, rp)
354     perwindow *pwin;
355     pyrostruct *pp;
356     rocket     *rp;
357 {
358     register int starn;
359     register int nstars, stype;
360     register float rx, ry, sd;  /* Help compiler optimize :-) */
361     register float sx, sy;
362
363     nstars = rp->nstars;
364     stype = rp->shelltype;
365
366 #if STARSIZE > 1
367     XFillRectangles(dsp, pwin->w, pp->bgGC, rp->Xpoints, nstars);
368     if (stype == DOUBLECLOUD)
369         XFillRectangles(dsp, pwin->w, pp->bgGC, rp->Xpoints2, nstars);
370 #else
371     XDrawPoints(dsp, pwin->w, pp->bgGC, rp->Xpoints, nstars, CoordModeOrigin);
372     if (stype == DOUBLECLOUD)
373         XDrawPoints(dsp, pwin->w, pp->bgGC, rp->Xpoints2, nstars, CoordModeOrigin);
374 #endif
375
376     if (rp->fuse-- <= 0) {
377         rp->state = SILENT;
378         pp->nflying--;
379         return;
380     }
381 /* Stagger the stars' decay */
382     if (rp->fuse <= 7) {
383         if ((rp->nstars = nstars = nstars * 90 / 100) == 0)
384             return;
385     }
386     rx = rp->x;
387     ry = rp->y;
388     sd = pp->stardecel;
389     for (starn = 0; starn < nstars; starn++) {
390         sx = rp->sx[starn] += rp->sxvel[starn];
391         sy = rp->sy[starn] += rp->syvel[starn];
392         rp->syvel[starn] += sd;
393         rp->Xpoints[starn].x = (int) (rx + sx);
394         rp->Xpoints[starn].y = (int) (ry + sy);
395         if (stype == DOUBLECLOUD) {
396             rp->Xpoints2[starn].x = (int) (rx + 1.7 * sx);
397             rp->Xpoints2[starn].y = (int) (ry + 1.7 * sy);
398         }
399     }
400     rp->x = rx + rp->xvel;
401     rp->y = ry + rp->yvel;
402     rp->yvel += sd;
403
404     XSetForeground(dsp, pwin->gc, rp->color1);
405 #if STARSIZE > 1
406     XFillRectangles(dsp, pwin->w, pwin->gc, rp->Xpoints, nstars);
407     if (stype == DOUBLECLOUD) {
408         XSetForeground(dsp, pwin->gc, rp->color2);
409         XFillRectangles(dsp, pwin->w, pwin->gc, rp->Xpoints2, nstars);
410     }
411 #else
412     XDrawPoints(dsp, pwin->w, pwin->gc, rp->Xpoints, nstars, CoordModeOrigin);
413     if (stype == DOUBLECLOUD) {
414         XSetForeground(dsp, pwin->gc, rp->color2);
415         XDrawPoints(dsp, pwin->w, pwin->gc, rp->Xpoints2, nstars,
416                     CoordModeOrigin);
417     }
418 #endif
419 }