2 * Copyright (c) 1988-91 by Patrick J. Naughton.
4 * Permission to use, copy, modify, and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted,
6 * provided that the above copyright notice appear in all copies and that
7 * both that copyright notice and this permission notice appear in
8 * supporting documentation.
10 * This file is provided AS IS with no warranties of any kind. The author
11 * shall have no liability with respect to the infringement of copyrights,
12 * trade secrets or any patents by this file or any part thereof. In no
13 * event will the author be liable for any lost revenue or profits or
14 * other special, indirect and consequential damages.
18 * Copyright (c) 1991, 2015, Oracle and/or its affiliates. All rights reserved.
20 * Permission is hereby granted, free of charge, to any person obtaining a
21 * copy of this software and associated documentation files (the "Software"),
22 * to deal in the Software without restriction, including without limitation
23 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
24 * and/or sell copies of the Software, and to permit persons to whom the
25 * Software is furnished to do so, subject to the following conditions:
27 * The above copyright notice and this permission notice (including the next
28 * paragraph) shall be included in all copies or substantial portions of the
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
34 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
36 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
37 * DEALINGS IN THE SOFTWARE.
40 * pyro.c - Fireworks for xlock, the X Window System lockscreen.
42 * Copyright (c) 1991 by Patrick J. Naughton.
44 * See xlock.c for copying information.
47 * 16-Mar-91: Written. (received from David Brooks, brooks@osf.org).
50 /* The physics of the rockets is a little bogus, but it looks OK. Each is
51 * given an initial velocity impetus. They decelerate slightly (gravity
52 * overcomes the rocket's impulse) and explode as the rocket's main fuse
53 * gives out (we could add a ballistic stage, maybe). The individual
54 * stars fan out from the rocket, and they decelerate less quickly.
55 * That's called bouyancy, but really it's again a visual preference.
60 #define TWOPI 6.2831853
62 /* Define this >1 to get small rectangles instead of points */
69 #define BURSTINGINAIR 2
73 /* Clearly other types and other fascinating visual effects could be added...*/
75 /* P_xxx parameters represent the reciprocal of the probability... */
76 #define P_IGNITE 5000 /* ...of ignition per cycle */
77 #define P_DOUBLECLOUD 10 /* ...of an ignition being double */
78 #define P_MULTI 75 /* ...of an ignition being several @ once */
79 #define P_FUSILLADE 250 /* ...of an ignition starting a fusillade */
81 #define ROCKETW 2 /* Dimensions of rocket */
83 #define XVELFACTOR 0.0025 /* Max horizontal velocity / screen width */
84 #define MINYVELFACTOR 0.016 /* Min vertical velocity / screen height */
85 #define MAXYVELFACTOR 0.018
86 #define GRAVFACTOR 0.0002 /* delta v / screen height */
87 #define MINFUSE 50 /* range of fuse lengths for rocket */
90 #define FUSILFACTOR 10 /* Generate fusillade by reducing P_IGNITE */
91 #define FUSILLEN 100 /* Length of fusillade, in ignitions */
93 #define SVELFACTOR 0.1 /* Max star velocity / yvel */
94 #define BOUYANCY 0.2 /* Reduction in grav deceleration for stars */
95 #define MAXSTARS 75 /* Number of stars issued from a shell */
97 #define MINSFUSE 50 /* Range of fuse lengths for stars */
100 #define INTRAND(min,max) ((int) (random()%((max+1)-(min))+(min)))
101 #define FLOATRAND(min,max) ((min)+(random()/MAXRAND)*((max)-(min)))
106 unsigned long color1
, color2
;
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 pyrostruct pyros
[MAXSCREENS
];
143 static int orig_p_ignite
;
144 static int just_started
= True
;/* Greet the user right away */
146 static void ignite(pyrostruct
*pp
);
147 static void animate(Window win
, pyrostruct
*pp
, rocket
*rp
);
148 static void shootup(Window win
, pyrostruct
*pp
, rocket
*rp
);
149 static void burst(Window win
, pyrostruct
*pp
, rocket
*rp
);
154 pyrostruct
*pp
= &pyros
[screen
];
156 XWindowAttributes xwa
;
164 XGetWindowAttributes(dsp
, win
, &xwa
);
166 if ((batchcount
< 1) || (batchcount
> 1024))
169 orig_p_ignite
= P_IGNITE
/ batchcount
;
170 if (orig_p_ignite
<= 0)
172 pp
->p_ignite
= orig_p_ignite
;
174 if (pp
->rockq
== NULL
) {
175 pp
->rockq
= calloc(batchcount
, sizeof(rocket
));
176 if (pp
->rockq
== NULL
)
177 error("allocation failed, unable to launch rockets\n");
179 pp
->nflying
= pp
->fusilcount
= 0;
182 bsize
= (short) ((xwa
.height
<= 64) ? 1 : STARSIZE
);
184 for (rockn
= 0, rp
= pp
->rockq
; rockn
< batchcount
; rockn
++, rp
++) {
187 for (starn
= 0; starn
< MAXSTARS
; starn
++) {
188 rp
->Xpoints
[starn
].width
= rp
->Xpoints
[starn
].height
=
189 rp
->Xpoints2
[starn
].width
= rp
->Xpoints2
[starn
].height
= bsize
;
194 pp
->width
= xwa
.width
;
195 pp
->lmargin
= xwa
.width
/ 16;
196 pp
->rmargin
= xwa
.width
- pp
->lmargin
;
197 pp
->height
= xwa
.height
;
198 pp
->scr
= ScreenOfDisplay(dsp
, screen
);
199 pp
->cmap
= xwa
.colormap
;
201 pp
->fgpixel
= sswhite
[screen
].pixel
;
202 pp
->bgpixel
= ssblack
[screen
].pixel
;
203 if (!mono
&& Scr
[screen
].npixels
> 3)
204 pp
->rockpixel
= Scr
[screen
].pixels
[3]; /* Just the right shade of
207 pp
->rockpixel
= pp
->fgpixel
;
210 xgcv
.foreground
= pp
->bgpixel
;
211 pp
->bgGC
= XCreateGC(dsp
, win
, GCForeground
, &xgcv
);
213 /* Geometry-dependent physical data: */
214 pp
->maxvelx
= (float) (xwa
.width
) * XVELFACTOR
;
215 pp
->minvelx
= -pp
->maxvelx
;
216 pp
->minvely
= -(float) (xwa
.height
) * MINYVELFACTOR
;
217 pp
->maxvely
= -(float) (xwa
.height
) * MAXYVELFACTOR
;
218 pp
->maxsvel
= pp
->minvely
* SVELFACTOR
;
219 pp
->rockdecel
= (float) (pp
->height
) * GRAVFACTOR
;
220 pp
->stardecel
= pp
->rockdecel
* BOUYANCY
;
222 XFillRectangle(dsp
, win
, pp
->bgGC
, 0, 0, xwa
.width
, xwa
.height
);
228 pyrostruct
*pp
= &pyros
[screen
];
232 if (pp
->p_ignite
== 0)
234 if (just_started
|| (random() % pp
->p_ignite
== 0)) {
235 just_started
= False
;
236 if (random() % P_FUSILLADE
== 0) {
237 pp
->p_ignite
= orig_p_ignite
/ FUSILFACTOR
;
238 pp
->fusilcount
= INTRAND(FUSILLEN
* 9 / 10, FUSILLEN
* 11 / 10);
241 if (pp
->fusilcount
> 0) {
242 if (--pp
->fusilcount
== 0)
243 pp
->p_ignite
= orig_p_ignite
;
246 for (rockn
= pp
->nflying
, rp
= pp
->rockq
; rockn
> 0; rp
++) {
247 if (rp
->state
!= SILENT
) {
248 animate(win
, pp
, rp
);
255 ignite(pyrostruct
*pp
)
258 int multi
, shelltype
, nstars
, fuse
, npix
, pix
;
259 unsigned long color1
, color2
;
262 x
= random() % pp
->width
;
263 xvel
= FLOATRAND(-pp
->maxvelx
, pp
->maxvelx
);
264 /* All this to stop too many rockets going offscreen: */
265 if (x
< pp
->lmargin
&& xvel
< 0.0 || x
> pp
->rmargin
&& xvel
> 0.0)
267 yvel
= FLOATRAND(pp
->minvely
, pp
->maxvely
);
268 fuse
= INTRAND(MINFUSE
, MAXFUSE
);
269 nstars
= INTRAND(MINSTARS
, MAXSTARS
);
270 if (!mono
&& (npix
= Scr
[screen
].npixels
) > 2) {
271 color1
= Scr
[screen
].pixels
[pix
= (int) random() % npix
];
272 color2
= Scr
[screen
].pixels
[(pix
+ (npix
/ 2)) % npix
];
274 color1
= color2
= sswhite
[screen
].pixel
;
278 if (random() % P_DOUBLECLOUD
== 0)
279 shelltype
= DOUBLECLOUD
;
282 if (random() % P_MULTI
== 0)
283 multi
= INTRAND(5, 15);
288 if (pp
->nflying
>= batchcount
)
290 while (rp
->state
!= SILENT
)
293 rp
->shelltype
= shelltype
;
294 rp
->state
= REDGLARE
;
298 rp
->yvel
= FLOATRAND(yvel
* 0.97, yvel
* 1.03);
299 rp
->fuse
= INTRAND((fuse
* 90) / 100, (fuse
* 110) / 100);
300 rp
->x
= x
+ FLOATRAND(multi
* 7.6, multi
* 8.4);
301 rp
->y
= pp
->height
- 1;
316 if (rp
->state
== REDGLARE
) {
317 shootup(win
, pp
, rp
);
319 /* Handle setup for explosion */
320 if (rp
->state
== BURSTINGINAIR
) {
321 for (starn
= 0; starn
< rp
->nstars
; starn
++) {
322 rp
->sx
[starn
] = rp
->sy
[starn
] = 0.0;
323 rp
->Xpoints
[starn
].x
= (short) rp
->x
;
324 rp
->Xpoints
[starn
].y
= (short) rp
->y
;
325 if (rp
->shelltype
== DOUBLECLOUD
) {
326 rp
->Xpoints2
[starn
].x
= (short) rp
->x
;
327 rp
->Xpoints2
[starn
].y
= (short) rp
->y
;
329 /* This isn't accurate solid geometry, but it looks OK. */
331 r
= FLOATRAND(0.0, pp
->maxsvel
);
332 theta
= FLOATRAND(0.0, TWOPI
);
333 rp
->sxvel
[starn
] = r
* cos(theta
);
334 rp
->syvel
[starn
] = r
* sin(theta
);
336 rp
->fuse
= INTRAND(MINSFUSE
, MAXSFUSE
);
339 if (rp
->state
== BURSTINGINAIR
) {
351 XFillRectangle(dsp
, win
, pp
->bgGC
, (int) (rp
->x
), (int) (rp
->y
),
352 ROCKETW
, ROCKETH
+ 3);
354 if (rp
->fuse
-- <= 0) {
355 rp
->state
= BURSTINGINAIR
;
360 rp
->yvel
+= pp
->rockdecel
;
361 XSetForeground(dsp
, Scr
[screen
].gc
, pp
->rockpixel
);
362 XFillRectangle(dsp
, win
, Scr
[screen
].gc
, (int) (rp
->x
), (int) (rp
->y
),
363 ROCKETW
, (int) (ROCKETH
+ random() % 4));
374 register int nstars
, stype
;
375 register float rx
, ry
, sd
; /* Help compiler optimize :-) */
376 register float sx
, sy
;
379 stype
= rp
->shelltype
;
382 XFillRectangles(dsp
, win
, pp
->bgGC
, rp
->Xpoints
, nstars
);
383 if (stype
== DOUBLECLOUD
)
384 XFillRectangles(dsp
, win
, pp
->bgGC
, rp
->Xpoints2
, nstars
);
386 XDrawPoints(dsp
, win
, pp
->bgGC
, rp
->Xpoints
, nstars
, CoordModeOrigin
);
387 if (stype
== DOUBLECLOUD
)
388 XDrawPoints(dsp
, win
, pp
->bgGC
, rp
->Xpoints2
, nstars
, CoordModeOrigin
);
391 if (rp
->fuse
-- <= 0) {
396 /* Stagger the stars' decay */
398 if ((rp
->nstars
= nstars
= nstars
* 90 / 100) == 0)
404 for (starn
= 0; starn
< nstars
; starn
++) {
405 sx
= rp
->sx
[starn
] += rp
->sxvel
[starn
];
406 sy
= rp
->sy
[starn
] += rp
->syvel
[starn
];
407 rp
->syvel
[starn
] += sd
;
408 rp
->Xpoints
[starn
].x
= (short) (rx
+ sx
);
409 rp
->Xpoints
[starn
].y
= (short) (ry
+ sy
);
410 if (stype
== DOUBLECLOUD
) {
411 rp
->Xpoints2
[starn
].x
= (short) (rx
+ 1.7 * sx
);
412 rp
->Xpoints2
[starn
].y
= (short) (ry
+ 1.7 * sy
);
415 rp
->x
= rx
+ rp
->xvel
;
416 rp
->y
= ry
+ rp
->yvel
;
419 XSetForeground(dsp
, Scr
[screen
].gc
, rp
->color1
);
421 XFillRectangles(dsp
, win
, Scr
[screen
].gc
, rp
->Xpoints
, nstars
);
422 if (stype
== DOUBLECLOUD
) {
423 XSetForeground(dsp
, Scr
[screen
].gc
, rp
->color2
);
424 XFillRectangles(dsp
, win
, Scr
[screen
].gc
, rp
->Xpoints2
, nstars
);
427 XDrawPoints(dsp
, win
, Scr
[screen
].gc
, rp
->Xpoints
, nstars
, CoordModeOrigin
);
428 if (stype
== DOUBLECLOUD
) {
429 XSetForeground(dsp
, Scr
[screen
].gc
, rp
->color2
);
430 XDrawPoints(dsp
, win
, Scr
[screen
].gc
, rp
->Xpoints2
, nstars
,