2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: pyro.c /main/3 1995/11/02 16:07:59 rswiston $ */
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. *
33 * pyro.c - Fireworks for dtscreen, the X Window System lockscreen.
35 * Copyright (c) 1991 by Patrick J. Naughton.
37 * See dtscreen.c for copying information.
40 * 16-Mar-91: Written. (received from David Brooks, brooks@osf.org).
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.
55 #define TWOPI 6.2831853
57 /* Define this >1 to get small rectangles instead of points */
64 #define BURSTINGINAIR 2
68 /* Clearly other types and other fascinating visual effects could be added...*/
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 */
76 #define ROCKETW 2 /* Dimensions of rocket */
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 */
85 #define FUSILFACTOR 10 /* Generate fusillade by reducing P_IGNITE */
86 #define FUSILLEN 100 /* Length of fusillade, in ignitions */
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 */
92 #define MINSFUSE 50 /* Range of fuse lengths for stars */
95 #define INTRAND(min,max) (random()%((max+1)-(min))+(min))
96 #define FLOATRAND(min,max) ((min)+(random()/MAXRAND)*((max)-(min)))
99 static void animate();
100 static void shootup();
112 XRectangle Xpoints[MAXSTARS];
113 XRectangle Xpoints2[MAXSTARS];
115 XPoint Xpoints[MAXSTARS];
116 XPoint Xpoints2[MAXSTARS];
118 float sx[MAXSTARS], sy[MAXSTARS]; /* Distance from notional
120 float sxvel[MAXSTARS], syvel[MAXSTARS]; /* Relative to notional
128 unsigned long bgpixel;
129 unsigned long fgpixel;
130 unsigned long rockpixel;
134 int width, lmargin, rmargin, height;
135 float minvelx, maxvelx;
136 float minvely, maxvely;
138 float rockdecel, stardecel;
142 static int orig_p_ignite;
143 static int just_started = True;/* Greet the user right away */
146 initpyro(perwindow *pwin)
150 XWindowAttributes xwa;
152 int rockn, starn, bsize;
154 if (pwin->data) free(pwin->data);
155 pwin->data = (pyrostruct *)malloc(sizeof(pyrostruct));
156 memset(pwin->data, '\0', sizeof(pyrostruct));
157 pp = (pyrostruct *)pwin->data;
158 XGetWindowAttributes(dsp, pwin->w, &xwa);
160 orig_p_ignite = P_IGNITE / batchcount;
161 if (orig_p_ignite <= 0)
163 pp->p_ignite = orig_p_ignite;
165 pp->rockq = (rocket *) malloc(batchcount * sizeof(rocket));
167 pp->nflying = pp->fusilcount = 0;
169 bsize = (xwa.height <= 64) ? 1 : STARSIZE;
170 for (rockn = 0, rp = pp->rockq; rockn < batchcount; rockn++, rp++) {
173 for (starn = 0; starn < MAXSTARS; starn++) {
174 rp->Xpoints[starn].width = rp->Xpoints[starn].height =
175 rp->Xpoints2[starn].width = rp->Xpoints2[starn].height = bsize;
180 pp->width = xwa.width;
181 pp->lmargin = xwa.width / 16;
182 pp->rmargin = xwa.width - pp->lmargin;
183 pp->height = xwa.height;
184 pp->scr = pwin->perscreen->screen;
185 pp->cmap = DefaultColormapOfScreen(pp->scr);
187 pp->fgpixel = WhitePixelOfScreen(pp->scr);
188 pp->bgpixel = BlackPixelOfScreen(pp->scr);
189 if (!mono && pwin->perscreen->npixels > 3)
190 pp->rockpixel = pwin->perscreen->pixels[3];/* Just the right shade of
193 pp->rockpixel = pp->fgpixel;
195 xgcv.foreground = pp->bgpixel;
196 pp->bgGC = XCreateGC(dsp, pwin->w, GCForeground, &xgcv);
198 /* Geometry-dependent physical data: */
199 pp->maxvelx = (float) (xwa.width) * XVELFACTOR;
200 pp->minvelx = -pp->maxvelx;
201 pp->minvely = -(float) (xwa.height) * MINYVELFACTOR;
202 pp->maxvely = -(float) (xwa.height) * MAXYVELFACTOR;
203 pp->maxsvel = pp->minvely * SVELFACTOR;
204 pp->rockdecel = (float) (pp->height) * GRAVFACTOR;
205 pp->stardecel = pp->rockdecel * BOUYANCY;
207 XFillRectangle(dsp, pwin->w, pp->bgGC, 0, 0, xwa.width, xwa.height);
212 drawpyro(perwindow *pwin)
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);
226 if (pp->fusilcount > 0) {
227 if (--pp->fusilcount == 0)
228 pp->p_ignite = orig_p_ignite;
231 for (rockn = pp->nflying, rp = pp->rockq; rockn > 0; rp++) {
232 if (rp->state != SILENT) {
233 animate(pwin, pp, rp);
240 ignite(perwindow *pwin, pyrostruct *pp)
243 int multi, shelltype, nstars, fuse, npix, pix, color1, color2;
246 x = random() % pp->width;
247 xvel = FLOATRAND(-pp->maxvelx, pp->maxvelx);
248 /* All this to stop too many rockets going offscreen: */
249 if ((x < pp->lmargin && xvel < 0.0) || (x > pp->rmargin && xvel > 0.0))
251 yvel = FLOATRAND(pp->minvely, pp->maxvely);
252 fuse = INTRAND(MINFUSE, MAXFUSE);
253 nstars = INTRAND(MINSTARS, MAXSTARS);
254 if (!mono && (npix = pwin->perscreen->npixels) > 2) {
255 color1 = pwin->perscreen->pixels[pix = random() % npix];
256 color2 = pwin->perscreen->pixels[(pix + (npix / 2)) % npix];
258 color1 = color2 = WhitePixelOfScreen(pwin->perscreen->screen);
262 if (random() % P_DOUBLECLOUD == 0)
263 shelltype = DOUBLECLOUD;
266 if (random() % P_MULTI == 0)
267 multi = INTRAND(5, 15);
272 if (pp->nflying >= batchcount)
274 while (rp->state != SILENT)
277 rp->shelltype = shelltype;
278 rp->state = REDGLARE;
282 rp->yvel = FLOATRAND(yvel * 0.97, yvel * 1.03);
283 rp->fuse = INTRAND((fuse * 90) / 100, (fuse * 110) / 100);
284 rp->x = x + FLOATRAND(multi * 7.6, multi * 8.4);
285 rp->y = pp->height - 1;
291 animate(perwindow *pwin, pyrostruct *pp, rocket *rp)
296 if (rp->state == REDGLARE) {
297 shootup(pwin, pp, rp);
299 /* Handle setup for explosion */
300 if (rp->state == BURSTINGINAIR) {
301 for (starn = 0; starn < rp->nstars; starn++) {
302 rp->sx[starn] = rp->sy[starn] = 0.0;
303 rp->Xpoints[starn].x = (int) rp->x;
304 rp->Xpoints[starn].y = (int) rp->y;
305 if (rp->shelltype == DOUBLECLOUD) {
306 rp->Xpoints2[starn].x = (int) rp->x;
307 rp->Xpoints2[starn].y = (int) rp->y;
309 /* This isn't accurate solid geometry, but it looks OK. */
311 r = FLOATRAND(0.0, pp->maxsvel);
312 theta = FLOATRAND(0.0, TWOPI);
313 rp->sxvel[starn] = r * cos(theta);
314 rp->syvel[starn] = r * sin(theta);
316 rp->fuse = INTRAND(MINSFUSE, MAXSFUSE);
319 if (rp->state == BURSTINGINAIR) {
325 shootup(perwindow *pwin, pyrostruct *pp, rocket *rp)
327 XFillRectangle(dsp, pwin->w, pp->bgGC, (int) (rp->x), (int) (rp->y),
328 ROCKETW, ROCKETH + 3);
330 if (rp->fuse-- <= 0) {
331 rp->state = BURSTINGINAIR;
336 rp->yvel += pp->rockdecel;
337 XSetForeground(dsp, pwin->gc, pp->rockpixel);
338 XFillRectangle(dsp, pwin->w, pwin->gc, (int) (rp->x), (int) (rp->y),
339 ROCKETW, ROCKETH + random() % 4);
343 burst(perwindow *pwin, pyrostruct *pp, rocket *rp)
347 float rx, ry, sd; /* Help compiler optimize :-) */
351 stype = rp->shelltype;
354 XFillRectangles(dsp, pwin->w, pp->bgGC, rp->Xpoints, nstars);
355 if (stype == DOUBLECLOUD)
356 XFillRectangles(dsp, pwin->w, pp->bgGC, rp->Xpoints2, nstars);
358 XDrawPoints(dsp, pwin->w, pp->bgGC, rp->Xpoints, nstars, CoordModeOrigin);
359 if (stype == DOUBLECLOUD)
360 XDrawPoints(dsp, pwin->w, pp->bgGC, rp->Xpoints2, nstars, CoordModeOrigin);
363 if (rp->fuse-- <= 0) {
368 /* Stagger the stars' decay */
370 if ((rp->nstars = nstars = nstars * 90 / 100) == 0)
376 for (starn = 0; starn < nstars; starn++) {
377 sx = rp->sx[starn] += rp->sxvel[starn];
378 sy = rp->sy[starn] += rp->syvel[starn];
379 rp->syvel[starn] += sd;
380 rp->Xpoints[starn].x = (int) (rx + sx);
381 rp->Xpoints[starn].y = (int) (ry + sy);
382 if (stype == DOUBLECLOUD) {
383 rp->Xpoints2[starn].x = (int) (rx + 1.7 * sx);
384 rp->Xpoints2[starn].y = (int) (ry + 1.7 * sy);
387 rp->x = rx + rp->xvel;
388 rp->y = ry + rp->yvel;
391 XSetForeground(dsp, pwin->gc, rp->color1);
393 XFillRectangles(dsp, pwin->w, pwin->gc, rp->Xpoints, nstars);
394 if (stype == DOUBLECLOUD) {
395 XSetForeground(dsp, pwin->gc, rp->color2);
396 XFillRectangles(dsp, pwin->w, pwin->gc, rp->Xpoints2, nstars);
399 XDrawPoints(dsp, pwin->w, pwin->gc, rp->Xpoints, nstars, CoordModeOrigin);
400 if (stype == DOUBLECLOUD) {
401 XSetForeground(dsp, pwin->gc, rp->color2);
402 XDrawPoints(dsp, pwin->w, pwin->gc, rp->Xpoints2, nstars,