pyro.c 12 KB

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