instant: partially revert commit bc96e6f1ff6c72d4d2cafb6a4088ffa32cd3019f. remove...
[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 #define TWOPI 6.2831853
54
55 /* Define this >1 to get small rectangles instead of points */
56 #ifndef STARSIZE
57 #define STARSIZE 2
58 #endif
59
60 #define SILENT 0
61 #define REDGLARE 1
62 #define BURSTINGINAIR 2
63
64 #define CLOUD 0
65 #define DOUBLECLOUD 1
66 /* Clearly other types and other fascinating visual effects could be added...*/
67
68 /* P_xxx parameters represent the reciprocal of the probability... */
69 #define P_IGNITE 5000           /* ...of ignition per cycle */
70 #define P_DOUBLECLOUD 10        /* ...of an ignition being double */
71 #define P_MULTI 75              /* ...of an ignition being several @ once */
72 #define P_FUSILLADE 250         /* ...of an ignition starting a fusillade */
73
74 #define ROCKETW 2               /* Dimensions of rocket */
75 #define ROCKETH 4
76 #define XVELFACTOR 0.0025       /* Max horizontal velocity / screen width */
77 #define MINYVELFACTOR 0.016     /* Min vertical velocity / screen height */
78 #define MAXYVELFACTOR 0.018
79 #define GRAVFACTOR 0.0002       /* delta v / screen height */
80 #define MINFUSE 50              /* range of fuse lengths for rocket */
81 #define MAXFUSE 100
82
83 #define FUSILFACTOR 10          /* Generate fusillade by reducing P_IGNITE */
84 #define FUSILLEN 100            /* Length of fusillade, in ignitions */
85
86 #define SVELFACTOR 0.1          /* Max star velocity / yvel */
87 #define BOUYANCY 0.2            /* Reduction in grav deceleration for stars */
88 #define MAXSTARS 75             /* Number of stars issued from a shell */
89 #define MINSTARS 50
90 #define MINSFUSE 50             /* Range of fuse lengths for stars */
91 #define MAXSFUSE 100
92
93 #define INTRAND(min,max) (random()%((max+1)-(min))+(min))
94 #define FLOATRAND(min,max) ((min)+(random()/MAXRAND)*((max)-(min)))
95
96 static void ignite();
97 static void animate();
98 static void shootup();
99 static void burst();
100
101 typedef struct {
102     int         state;
103     int         shelltype;
104     int         color1, color2;
105     int         fuse;
106     float       xvel, yvel;
107     float       x, y;
108     int         nstars;
109 #if STARSIZE > 1
110     XRectangle  Xpoints[MAXSTARS];
111     XRectangle  Xpoints2[MAXSTARS];
112 #else
113     XPoint      Xpoints[MAXSTARS];
114     XPoint      Xpoints2[MAXSTARS];
115 #endif
116     float       sx[MAXSTARS], sy[MAXSTARS];     /* Distance from notional
117                                                  * center  */
118     float       sxvel[MAXSTARS], syvel[MAXSTARS];       /* Relative to notional
119                                                          * center */
120 }           rocket;
121
122 typedef struct {
123     Screen     *scr;
124     Colormap    cmap;
125     int         p_ignite;
126     unsigned long bgpixel;
127     unsigned long fgpixel;
128     unsigned long rockpixel;
129     GC          bgGC;
130     int         nflying;
131     int         fusilcount;
132     int         width, lmargin, rmargin, height;
133     float       minvelx, maxvelx;
134     float       minvely, maxvely;
135     float       maxsvel;
136     float       rockdecel, stardecel;
137     rocket     *rockq;
138 }           pyrostruct;
139
140 static int  orig_p_ignite;
141 static int  just_started = True;/* Greet the user right away */
142
143 void
144 initpyro(pwin)
145     perwindow *pwin;
146 {
147     pyrostruct *pp;
148     rocket     *rp;
149     XWindowAttributes xwa;
150     XGCValues   xgcv;
151     int         rockn, starn, bsize;
152
153     if (pwin->data) free(pwin->data);
154     pwin->data = (pyrostruct *)malloc(sizeof(pyrostruct));
155     memset(pwin->data, '\0', sizeof(pyrostruct));
156     pp = (pyrostruct *)pwin->data;
157     XGetWindowAttributes(dsp, pwin->w, &xwa);
158
159     orig_p_ignite = P_IGNITE / batchcount;
160     if (orig_p_ignite <= 0)
161         orig_p_ignite = 1;
162     pp->p_ignite = orig_p_ignite;
163
164     pp->rockq = (rocket *) malloc(batchcount * sizeof(rocket));
165
166     pp->nflying = pp->fusilcount = 0;
167
168     bsize = (xwa.height <= 64) ? 1 : STARSIZE;
169     for (rockn = 0, rp = pp->rockq; rockn < batchcount; rockn++, rp++) {
170         rp->state = SILENT;
171 #if STARSIZE > 1
172         for (starn = 0; starn < MAXSTARS; starn++) {
173             rp->Xpoints[starn].width = rp->Xpoints[starn].height =
174                 rp->Xpoints2[starn].width = rp->Xpoints2[starn].height = bsize;
175         }
176 #endif
177     }
178
179     pp->width = xwa.width;
180     pp->lmargin = xwa.width / 16;
181     pp->rmargin = xwa.width - pp->lmargin;
182     pp->height = xwa.height;
183     pp->scr = pwin->perscreen->screen;
184     pp->cmap = DefaultColormapOfScreen(pp->scr);
185
186     pp->fgpixel = WhitePixelOfScreen(pp->scr);
187     pp->bgpixel = BlackPixelOfScreen(pp->scr);
188     if (!mono && pwin->perscreen->npixels > 3)
189         pp->rockpixel = pwin->perscreen->pixels[3];/* Just the right shade of
190                                                  * orange */
191     else
192         pp->rockpixel = pp->fgpixel;
193
194     xgcv.foreground = pp->bgpixel;
195     pp->bgGC = XCreateGC(dsp, pwin->w, GCForeground, &xgcv);
196     
197 /* Geometry-dependent physical data: */
198     pp->maxvelx = (float) (xwa.width) * XVELFACTOR;
199     pp->minvelx = -pp->maxvelx;
200     pp->minvely = -(float) (xwa.height) * MINYVELFACTOR;
201     pp->maxvely = -(float) (xwa.height) * MAXYVELFACTOR;
202     pp->maxsvel = pp->minvely * SVELFACTOR;
203     pp->rockdecel = (float) (pp->height) * GRAVFACTOR;
204     pp->stardecel = pp->rockdecel * BOUYANCY;
205
206     XFillRectangle(dsp, pwin->w, pp->bgGC, 0, 0, xwa.width, xwa.height);
207 }
208
209 /*ARGSUSED*/
210 void
211 drawpyro(pwin)
212     perwindow *pwin;
213 {
214     pyrostruct *pp;
215     rocket     *rp;
216     int         rockn;
217
218     pp = (pyrostruct *)pwin->data;
219     if (just_started || (random() % pp->p_ignite == 0)) {
220         just_started = False;
221         if (random() % P_FUSILLADE == 0) {
222             pp->p_ignite = orig_p_ignite / FUSILFACTOR;
223             pp->fusilcount = INTRAND(FUSILLEN * 9 / 10, FUSILLEN * 11 / 10);
224         }
225         ignite(pwin, pp);
226         if (pp->fusilcount > 0) {
227             if (--pp->fusilcount == 0)
228                 pp->p_ignite = orig_p_ignite;
229         }
230     }
231     for (rockn = pp->nflying, rp = pp->rockq; rockn > 0; rp++) {
232         if (rp->state != SILENT) {
233             animate(pwin, pp, rp);
234             rockn--;
235         }
236     }
237 }
238
239 static void
240 ignite(pwin, pp)
241     perwindow *pwin;
242     pyrostruct *pp;
243 {
244     rocket     *rp;
245     int         multi, shelltype, nstars, fuse, npix, pix, color1, color2;
246     float       xvel, yvel, x;
247
248     x = random() % pp->width;
249     xvel = FLOATRAND(-pp->maxvelx, pp->maxvelx);
250 /* All this to stop too many rockets going offscreen: */
251     if (x < pp->lmargin && xvel < 0.0 || x > pp->rmargin && xvel > 0.0)
252         xvel = -xvel;
253     yvel = FLOATRAND(pp->minvely, pp->maxvely);
254     fuse = INTRAND(MINFUSE, MAXFUSE);
255     nstars = INTRAND(MINSTARS, MAXSTARS);
256     if (!mono && (npix = pwin->perscreen->npixels) > 2) {
257         color1 = pwin->perscreen->pixels[pix = random() % npix];
258         color2 = pwin->perscreen->pixels[(pix + (npix / 2)) % npix];
259     } else {
260         color1 = color2 = WhitePixelOfScreen(pwin->perscreen->screen);
261     }
262
263     multi = 1;
264     if (random() % P_DOUBLECLOUD == 0)
265         shelltype = DOUBLECLOUD;
266     else {
267         shelltype = CLOUD;
268         if (random() % P_MULTI == 0)
269             multi = INTRAND(5, 15);
270     }
271
272     rp = pp->rockq;
273     while (multi--) {
274         if (pp->nflying >= batchcount)
275             return;
276         while (rp->state != SILENT)
277             rp++;
278         pp->nflying++;
279         rp->shelltype = shelltype;
280         rp->state = REDGLARE;
281         rp->color1 = color1;
282         rp->color2 = color2;
283         rp->xvel = xvel;
284         rp->yvel = FLOATRAND(yvel * 0.97, yvel * 1.03);
285         rp->fuse = INTRAND((fuse * 90) / 100, (fuse * 110) / 100);
286         rp->x = x + FLOATRAND(multi * 7.6, multi * 8.4);
287         rp->y = pp->height - 1;
288         rp->nstars = nstars;
289     }
290 }
291
292 static void
293 animate(pwin, pp, rp)
294     perwindow *pwin;
295     pyrostruct *pp;
296     rocket     *rp;
297 {
298     int         starn;
299     float       r, theta;
300
301     if (rp->state == REDGLARE) {
302         shootup(pwin, pp, rp);
303
304 /* Handle setup for explosion */
305         if (rp->state == BURSTINGINAIR) {
306             for (starn = 0; starn < rp->nstars; starn++) {
307                 rp->sx[starn] = rp->sy[starn] = 0.0;
308                 rp->Xpoints[starn].x = (int) rp->x;
309                 rp->Xpoints[starn].y = (int) rp->y;
310                 if (rp->shelltype == DOUBLECLOUD) {
311                     rp->Xpoints2[starn].x = (int) rp->x;
312                     rp->Xpoints2[starn].y = (int) rp->y;
313                 }
314 /* This isn't accurate solid geometry, but it looks OK. */
315
316                 r = FLOATRAND(0.0, pp->maxsvel);
317                 theta = FLOATRAND(0.0, TWOPI);
318                 rp->sxvel[starn] = r * cos(theta);
319                 rp->syvel[starn] = r * sin(theta);
320             }
321             rp->fuse = INTRAND(MINSFUSE, MAXSFUSE);
322         }
323     }
324     if (rp->state == BURSTINGINAIR) {
325         burst(pwin, pp, rp);
326     }
327 }
328
329 static void
330 shootup(pwin, pp, rp)
331     perwindow *pwin;
332     pyrostruct *pp;
333     rocket     *rp;
334 {
335     XFillRectangle(dsp, pwin->w, pp->bgGC, (int) (rp->x), (int) (rp->y),
336                    ROCKETW, ROCKETH + 3);
337
338     if (rp->fuse-- <= 0) {
339         rp->state = BURSTINGINAIR;
340         return;
341     }
342     rp->x += rp->xvel;
343     rp->y += rp->yvel;
344     rp->yvel += pp->rockdecel;
345     XSetForeground(dsp, pwin->gc, pp->rockpixel);
346     XFillRectangle(dsp, pwin->w, pwin->gc, (int) (rp->x), (int) (rp->y),
347                    ROCKETW, ROCKETH + random() % 4);
348 }
349
350 static void
351 burst(pwin, pp, rp)
352     perwindow *pwin;
353     pyrostruct *pp;
354     rocket     *rp;
355 {
356     register int starn;
357     register int nstars, stype;
358     register float rx, ry, sd;  /* Help compiler optimize :-) */
359     register float sx, sy;
360
361     nstars = rp->nstars;
362     stype = rp->shelltype;
363
364 #if STARSIZE > 1
365     XFillRectangles(dsp, pwin->w, pp->bgGC, rp->Xpoints, nstars);
366     if (stype == DOUBLECLOUD)
367         XFillRectangles(dsp, pwin->w, pp->bgGC, rp->Xpoints2, nstars);
368 #else
369     XDrawPoints(dsp, pwin->w, pp->bgGC, rp->Xpoints, nstars, CoordModeOrigin);
370     if (stype == DOUBLECLOUD)
371         XDrawPoints(dsp, pwin->w, pp->bgGC, rp->Xpoints2, nstars, CoordModeOrigin);
372 #endif
373
374     if (rp->fuse-- <= 0) {
375         rp->state = SILENT;
376         pp->nflying--;
377         return;
378     }
379 /* Stagger the stars' decay */
380     if (rp->fuse <= 7) {
381         if ((rp->nstars = nstars = nstars * 90 / 100) == 0)
382             return;
383     }
384     rx = rp->x;
385     ry = rp->y;
386     sd = pp->stardecel;
387     for (starn = 0; starn < nstars; starn++) {
388         sx = rp->sx[starn] += rp->sxvel[starn];
389         sy = rp->sy[starn] += rp->syvel[starn];
390         rp->syvel[starn] += sd;
391         rp->Xpoints[starn].x = (int) (rx + sx);
392         rp->Xpoints[starn].y = (int) (ry + sy);
393         if (stype == DOUBLECLOUD) {
394             rp->Xpoints2[starn].x = (int) (rx + 1.7 * sx);
395             rp->Xpoints2[starn].y = (int) (ry + 1.7 * sy);
396         }
397     }
398     rp->x = rx + rp->xvel;
399     rp->y = ry + rp->yvel;
400     rp->yvel += sd;
401
402     XSetForeground(dsp, pwin->gc, rp->color1);
403 #if STARSIZE > 1
404     XFillRectangles(dsp, pwin->w, pwin->gc, rp->Xpoints, nstars);
405     if (stype == DOUBLECLOUD) {
406         XSetForeground(dsp, pwin->gc, rp->color2);
407         XFillRectangles(dsp, pwin->w, pwin->gc, rp->Xpoints2, nstars);
408     }
409 #else
410     XDrawPoints(dsp, pwin->w, pwin->gc, rp->Xpoints, nstars, CoordModeOrigin);
411     if (stype == DOUBLECLOUD) {
412         XSetForeground(dsp, pwin->gc, rp->color2);
413         XDrawPoints(dsp, pwin->w, pwin->gc, rp->Xpoints2, nstars,
414                     CoordModeOrigin);
415     }
416 #endif
417 }