1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* bounce --- bouncing footballs */
3
4 #if 0
5 static const char sccsid[] = "@(#)bounce.c 5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10 * Copyright (c) 1988 by Sun Microsystems
11 *
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
17 *
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
23 *
24 * Revision History:
25 * 01-Nov-2000: Allocation checks
26 * 10-May-1997: Compatible with xscreensaver
27 * 01-Apr-1997: Curtis Larsen <larsen@rtp3.med.utah.edu>
28 * The modification is only for the inroot option. It causes
29 * the balls to see children of the root window and bounce
30 * off of the sides of them. New windows are only recognized
31 * after every init_bounce, because fvwm did not like xlock
32 * setting SubstructureNotifyMask on root. I did not fix the
33 * initial placement of balls yet, so they can start out
34 * underneath windows.
35 * 18-Sep-1995: tinkered with it to look like bat.c .
36 * 15-Jul-1994: cleaned up in time for the final match.
37 * 04-Apr-1994: spinning multiple ball version
38 * (I got a lot of help from with the physics of ball to ball
39 * collision looking at the source of xpool from Ismail ARIT
40 * <iarit@tara.mines.colorado.edu>
41 * 22-Mar-1994: got rid of flashing problem by only erasing parts of the
42 * image that will not be covered up by the next image.
43 * 02-Sep-1993: xlock version David Bagley <bagleyd AT verizon.net>
44 * 1986: Sun Microsystems
45 */
46
47 /*-
48 * original copyright
49 * **************************************************************************
50 * Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA.
51 *
52 * All Rights Reserved
53 *
54 * Permission to use, copy, modify, and distribute this software and its
55 * documentation for any purpose and without fee is hereby granted, provided
56 * that the above copyright notice appear in all copies and that both that
57 * copyright notice and this permission notice appear in supporting
58 * documentation, and that the names of Sun or MIT not be used in advertising
59 * or publicity pertaining to distribution of the software without specific
60 * prior written permission. Sun and M.I.T. make no representations about the
61 * suitability of this software for any purpose. It is provided "as is"
62 * without any express or implied warranty.
63 *
64 * SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
66 * IN NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
67 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
68 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
69 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
70 * SOFTWARE.
71 * ***************************************************************************
72 */
73
74 /*-
75 * Open for improvement:
76 * include different balls (size and mass)
77 * how about be real crazy and put in an American/Australian football?
78 * should only have 1 bitmap for ball, the others should be generated
79 * as 90 degree rotations.
80 * multiscreen interaction
81 */
82
83 #ifdef STANDALONE
84 # define MODE_bounce
85 # define DEFAULTS "*delay: 5000 \n" \
86 "*count: -10 \n" \
87 "*size: 0 \n" \
88 "*ncolors: 200 \n" \
89
90 # define free_bounce 0
91 # define reshape_bounce 0
92 # define bounce_handle_event 0
93 #include "xlockmore.h" /* in xscreensaver distribution */
94 #else /* STANDALONE */
95 # include "xlock.h" /* in xlockmore distribution */
96 # include "color.h"
97 # include "iostuff.h"
98 #endif /* STANDALONE */
99
100 #ifdef MODE_bounce
101
102 ENTRYPOINT ModeSpecOpt bounce_opts =
103 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
104
105 #ifdef USE_MODULES
106 const ModStruct bounce_description =
107 {"bounce", "init_bounce", "draw_bounce", "release_bounce",
108 "refresh_bounce", "init_bounce", (char *) NULL, &bounce_opts,
109 5000, -10, 1, 0, 64, 1.0, "",
110 "Shows bouncing footballs", 0, NULL};
111
112 #endif
113
114 #include "bitmaps/bounce-0.xbm"
115 #include "bitmaps/bounce-1.xbm"
116 #include "bitmaps/bounce-2.xbm"
117 #include "bitmaps/bounce-3.xbm"
118 #include "bitmaps/bounce-mask.xbm"
119
120 #define BALLBITS(n,w,h)\
121 if ((bp->pixmaps[bp->init_orients]=\
122 XCreateBitmapFromData(display,window,(char *)n,w,h))==None){\
123 free_bounce_screen(display,bp); return False;} else {bp->init_orients++;}
124
125 #ifndef STANDALONE
126 /* aliases for vars defined in the bitmap file */
127 #define BOUNCE_WIDTH image_width
128 #define BOUNCE_HEIGHT image_height
129 #define BOUNCE_BITS image_bits
130
131 #include "bounce.xbm"
132
133 #ifdef HAVE_XPM
134 #define BOUNCE_NAME image_name
135 #include "bounce.xpm"
136 #define DEFAULT_XPM 1
137 #endif
138 #endif
139
140 #define MAX_STRENGTH 24
141 #define FRICTION 24
142 #define PENETRATION 0.3
143 #define SLIPAGE 4
144 #define TIME 32
145 #define MINBALLS 1
146 #define MINSIZE 1
147 #define MINGRIDSIZE 5
148
149 #define ORIENTS 4
150 #define ORIENTCYCLE 16
151 #define CCW 1
152 #define CW (ORIENTS-1)
153 #define DIR(x) (((x)>=0)?CCW:CW)
154 #define SIGN(x) (((x)>=0)?1:-1)
155
156 typedef struct {
157 int x, y;
158 int width, height;
159 } ballwindow;
160
161 typedef struct {
162 int x, y, xlast, ylast, orientlast;
163 int spincount, spindelay, spindir, orient;
164 int vx, vy, vang;
165 unsigned long color;
166 } ballstruct;
167
168 typedef struct {
169 int width, height;
170 int nballs;
171 int xs, ys, avgsize;
172 int restartnum;
173 int pixelmode;
174 ballstruct *balls;
175 int graphics_format;
176 GC backGC;
177 XImage *logo;
178 unsigned long black;
179 Colormap cmap;
180 GC stippledGC;
181 Pixmap pixmaps[ORIENTS + 1];
182 int init_orients;
183 int nwindow;
184 ballwindow *windows;
185 } bouncestruct;
186
187 static bouncestruct *bounces = (bouncestruct *) NULL;
188
189 static void
checkCollision(bouncestruct * bp,int aball)190 checkCollision(bouncestruct * bp, int aball)
191 {
192 int i, amount, spin, d, size;
193 double x, y;
194
195 for (i = 0; i < bp->nballs; i++) {
196 if (i != aball) {
197 x = (double) (bp->balls[i].x - bp->balls[aball].x);
198 y = (double) (bp->balls[i].y - bp->balls[aball].y);
199 d = (int) sqrt(x * x + y * y);
200 size = bp->avgsize;
201 if (d > 0 && d < size) {
202 amount = size - d;
203 if (amount > PENETRATION * size)
204 amount = (int) (PENETRATION * size);
205 bp->balls[i].vx += (int) ((double) amount * x / d);
206 bp->balls[i].vy += (int) ((double) amount * y / d);
207 bp->balls[i].vx -= bp->balls[i].vx / FRICTION;
208 bp->balls[i].vy -= bp->balls[i].vy / FRICTION;
209 bp->balls[aball].vx -= (int) ((double) amount * x / d);
210 bp->balls[aball].vy -= (int) ((double) amount * y / d);
211 bp->balls[aball].vx -= bp->balls[aball].vx / FRICTION;
212 bp->balls[aball].vy -= bp->balls[aball].vy / FRICTION;
213 spin = (bp->balls[i].vang - bp->balls[aball].vang) /
214 (2 * size * SLIPAGE);
215 bp->balls[i].vang -= spin;
216 bp->balls[aball].vang += spin;
217 bp->balls[i].spindir = DIR(bp->balls[i].vang);
218 bp->balls[aball].spindir = DIR(bp->balls[aball].vang);
219 if (!bp->balls[i].vang) {
220 bp->balls[i].spindelay = 1;
221 bp->balls[i].spindir = 0;
222 } else
223 bp->balls[i].spindelay = (int) ((double) M_PI *
224 bp->avgsize / (ABS(bp->balls[i].vang))) + 1;
225 if (!bp->balls[aball].vang) {
226 bp->balls[aball].spindelay = 1;
227 bp->balls[aball].spindir = 0;
228 } else
229 bp->balls[aball].spindelay = (int) ((double) M_PI *
230 bp->avgsize / (ABS(bp->balls[aball].vang))) + 1;
231 return;
232 }
233 }
234 }
235 }
236
237 static void
drawball(ModeInfo * mi,ballstruct * ball)238 drawball(ModeInfo * mi, ballstruct * ball)
239 {
240 Display *display = MI_DISPLAY(mi);
241 Window window = MI_WINDOW(mi);
242 bouncestruct *bp = &bounces[MI_SCREEN(mi)];
243
244 if (ball->xlast != -1) {
245 if (bp->logo && !bp->pixelmode) {
246 XSetForeground(display, bp->backGC, bp->black);
247 #ifdef FLASH
248 XFillRectangle(display, window, bp->backGC,
249 ball->xlast, ball->ylast, bp->xs, bp->ys);
250 #else
251 ERASE_IMAGE(display, window, bp->backGC,
252 ball->x, ball->y, ball->xlast, ball->ylast,
253 bp->xs, bp->ys);
254 #endif
255 } else {
256 XSetForeground(display, bp->stippledGC, MI_BLACK_PIXEL(mi));
257 XSetStipple(display, bp->stippledGC,
258 bp->pixmaps[(bp->pixelmode) ? 0 : ORIENTS]);
259 XSetFillStyle(display, bp->stippledGC, FillStippled);
260 XSetTSOrigin(display, bp->stippledGC,
261 ball->xlast, ball->ylast);
262 XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
263 #ifdef FLASH
264 XFillRectangle(display, window, MI_GC(mi),
265 ball->xlast, ball->ylast, bp->xs, bp->ys);
266 #else
267 ERASE_IMAGE(display, window, MI_GC(mi),
268 ball->x, ball->y, ball->xlast, ball->ylast,
269 bp->xs, bp->ys);
270 #endif
271 }
272 }
273 if (bp->logo && !bp->pixelmode) {
274 XSetForeground(display, bp->backGC, ball->color);
275 if (bp->logo)
276 (void) XPutImage(display, window, bp->backGC, bp->logo,
277 0, 0, ball->x, ball->y, bp->xs, bp->ys);
278 } else {
279 XSetTSOrigin(display, bp->stippledGC, ball->x, ball->y);
280 XSetForeground(display, bp->stippledGC, ball->color);
281 XSetStipple(display, bp->stippledGC,
282 bp->pixmaps[(bp->pixelmode) ? 0 : ball->orient]);
283 #ifdef FLASH
284 XSetFillStyle(display, bp->stippledGC, FillStippled);
285 #else
286 XSetFillStyle(display, bp->stippledGC, FillOpaqueStippled);
287 #endif
288 XFillRectangle(display, window, bp->stippledGC,
289 ball->x, ball->y, bp->xs, bp->ys);
290 }
291 XFlush(display);
292 }
293
294 static void
spinball(ballstruct * ball,int dir,int * vel,int avgsize)295 spinball(ballstruct * ball, int dir, int *vel, int avgsize)
296 {
297 *vel -= (int) ((*vel + SIGN(*vel * dir) *
298 ball->spindelay * ORIENTCYCLE / (M_PI * avgsize)) / SLIPAGE);
299 if (*vel) {
300 ball->spindir = DIR(*vel * dir);
301 ball->vang = *vel * ORIENTCYCLE;
302 ball->spindelay = (int) ((double) M_PI * avgsize / (ABS(ball->vang))) + 1;
303 } else
304 ball->spindir = 0;
305 }
306
307 #define BETWEEN(x, xmin, xmax) (((x) >= (xmin)) && ((x) <= (xmax)))
308 static void
hit_left_wall(ModeInfo * mi,ballstruct * ball,int ytop,int height,int x,int side)309 hit_left_wall(ModeInfo * mi, ballstruct * ball,
310 int ytop, int height, int x, int side)
311 {
312 bouncestruct *bp = &bounces[MI_SCREEN(mi)];
313
314 if ((ball->x <= x) && ((ball->xlast >= x) || side) &&
315 BETWEEN(ball->y, ytop - bp->ys, ytop + height)) {
316 /* Bounce off the wall to the left of the ball */
317
318 ball->x = 2 * x - ball->x;
319 ball->vx = (ball->vx - (ball->vx * FRICTION)) / FRICTION;
320 spinball(ball, -1, &ball->vy, bp->avgsize);
321 }
322 }
323
324 static void
hit_right_wall(ModeInfo * mi,ballstruct * ball,int ytop,int height,int x,int side)325 hit_right_wall(ModeInfo * mi, ballstruct * ball,
326 int ytop, int height, int x, int side)
327 {
328 bouncestruct *bp = &bounces[MI_SCREEN(mi)];
329
330 x -= bp->xs; /* account for ball width */
331
332 if ((ball->x >= x) && ((ball->xlast <= x) || side) &&
333 BETWEEN(ball->y, ytop - bp->ys, ytop + height)) {
334 /* Bounce off the wall to the right of the ball */
335
336 ball->x = 2 * x - ball->x;
337 ball->vx = (ball->vx - (ball->vx * FRICTION)) / FRICTION;
338 spinball(ball, 1, &ball->vy, bp->avgsize);
339 }
340 }
341
342 static void
hit_top_wall(bouncestruct * bp,ballstruct * ball,int xleft,int width,int y,int side)343 hit_top_wall(bouncestruct * bp, ballstruct * ball, int xleft, int width, int y, int side)
344 {
345 if ((ball->y <= y) && ((ball->ylast >= y) || side) &&
346 BETWEEN(ball->x, xleft - bp->xs, xleft + width)) {
347 /* Bounce off the wall to the top of the ball */
348 ball->y = 2 * y - ball->y;
349 /* HACK to make it look better for iconified mode */
350 if (y == 0) {
351 ball->vy = 0;
352 } else {
353 ball->vy = (ball->vy - (FRICTION * ball->vy)) / FRICTION;
354 }
355 spinball(ball, 1, &ball->vx, bp->avgsize);
356 }
357 }
358
359
360 static void
hit_bottom_wall(bouncestruct * bp,ballstruct * ball,int xleft,int width,int y,int side)361 hit_bottom_wall(bouncestruct * bp, ballstruct * ball, int xleft, int width, int y, int side)
362 {
363 y -= bp->ys; /* account for ball height */
364
365 if ((ball->y >= y) && ((ball->ylast <= y) || side) &&
366 BETWEEN(ball->x, xleft - bp->xs, xleft + width)) {
367 /* Bounce off the wall to the bottom of the ball */
368 ball->y = y;
369 ball->vy = (ball->vy - (FRICTION * ball->vy)) / FRICTION;
370 spinball(ball, -1, &ball->vx, bp->avgsize);
371 }
372 }
373
374 static void
moveball(ModeInfo * mi,ballstruct * ball)375 moveball(ModeInfo * mi, ballstruct * ball)
376 {
377 bouncestruct *bp = &bounces[MI_SCREEN(mi)];
378 int i;
379 ballwindow *win;
380
381 ball->xlast = ball->x;
382 ball->ylast = ball->y;
383 ball->orientlast = ball->orient;
384 ball->x += ball->vx;
385
386 for (i = 0; i < bp->nwindow; i++) {
387 win = &bp->windows[i];
388
389 hit_left_wall(mi, ball, win->y, win->height, win->x + win->width, 0);
390 hit_right_wall(mi, ball, win->y, win->height, win->x, 0);
391 }
392 hit_right_wall(mi, ball, 0, bp->height, bp->width, 1);
393 hit_left_wall(mi, ball, 0, bp->height, 0, 1);
394
395 ball->vy++;
396 ball->y += ball->vy;
397
398 for (i = 0; i < bp->nwindow; i++) {
399 win = &bp->windows[i];
400
401 hit_top_wall(bp, ball, win->x, win->width, win->y + win->height, 0);
402 hit_bottom_wall(bp, ball, win->x, win->width, win->y, 0);
403 }
404 hit_top_wall(bp, ball, 0, bp->width, 0, 1);
405 hit_bottom_wall(bp, ball, 0, bp->width, bp->height, 1);
406
407 if (ball->spindir) {
408 ball->spincount--;
409 if (!ball->spincount) {
410 ball->orient = (ball->spindir + ball->orient) % ORIENTS;
411 ball->spincount = ball->spindelay;
412 }
413 }
414 }
415
416 static int
collide(bouncestruct * bp,int aball)417 collide(bouncestruct * bp, int aball)
418 {
419 int i, d, x, y;
420
421 for (i = 0; i < aball; i++) {
422 x = (bp->balls[i].x - bp->balls[aball].x);
423 y = (bp->balls[i].y - bp->balls[aball].y);
424 d = (int) sqrt((double) (x * x + y * y));
425 if (d < bp->avgsize)
426 return i;
427 }
428 return i;
429 }
430
431 static void
bounce_windows(ModeInfo * mi,bouncestruct * bp)432 bounce_windows(ModeInfo * mi, bouncestruct * bp)
433 {
434 Window root, parent, *children;
435 unsigned int nchildren;
436 int i;
437 int n;
438
439 if (!MI_IS_INROOT(mi)) {
440 bp->nwindow = 0;
441 return;
442 }
443 if (XQueryTree(MI_DISPLAY(mi), MI_WINDOW(mi),
444 &root, &parent, &children, &nchildren) == 0) { /* failure */
445 bp->nwindow = 0;
446 return;
447 }
448 bp->nwindow = nchildren;
449 if (bp->windows != NULL)
450 free(bp->windows);
451 if ((bp->windows = (ballwindow *) malloc(bp->nwindow *
452 sizeof (ballwindow))) == NULL) {
453 XFree((caddr_t) children);
454 bp->nwindow = 0;
455 return;
456 }
457 for (n = 0, i = 0; i < bp->nwindow; i++) {
458 XWindowAttributes att;
459
460 /*-
461 May give
462 X Error of failed request: BadWindow (invalid Window parameter)
463 Major opcode of failed request: 3 (X_GetWindowAttributes)
464 */
465 if (XGetWindowAttributes(MI_DISPLAY(mi), children[i], &att) == 0) { /* failure */
466 XFree((caddr_t) children);
467 bp->nwindow = 0;
468 free(bp->windows);
469 bp->windows = (ballwindow *) NULL;
470 return;
471 }
472 if ((att.x < 0) || (att.x > bp->width) ||
473 (att.y < 0) || (att.y > bp->height) ||
474 #if defined(__cplusplus) || defined(c_plusplus)
475 (att.c_class != InputOutput) ||
476 #else
477 (att.class != InputOutput) ||
478 #endif
479 (att.map_state != IsViewable)) {
480 continue;
481 }
482 bp->windows[n].x = att.x;
483 bp->windows[n].y = att.y;
484 bp->windows[n].width = att.width;
485 bp->windows[n].height = att.height;
486 n++;
487 }
488 bp->nwindow = n;
489 XFree((caddr_t) children);
490 return;
491 }
492
493 static void
free_stuff(Display * display,bouncestruct * bp)494 free_stuff(Display * display, bouncestruct * bp)
495 {
496 int bits;
497
498 for (bits = 0; bits < bp->init_orients; bits++) {
499 if (bp->pixmaps[bits] != None) {
500 XFreePixmap(display, bp->pixmaps[bits]);
501 bp->pixmaps[bits] = None;
502 }
503 }
504 bp->init_orients = 0;
505 if (bp->cmap != None) {
506 XFreeColormap(display, bp->cmap);
507 if (bp->backGC != None) {
508 XFreeGC(display, bp->backGC);
509 bp->backGC = None;
510 }
511 bp->cmap = None;
512 } else
513 bp->backGC = None;
514 #ifndef STANDALONE
515 /* this used to work there I think */
516 if (bp->logo != None) {
517 destroyImage(&bp->logo, &bp->graphics_format);
518 bp->logo = None;
519 }
520 #endif
521 }
522
523 static void
free_bounce_screen(Display * display,bouncestruct * bp)524 free_bounce_screen(Display *display, bouncestruct *bp)
525 {
526 if (bp == NULL) {
527 return;
528 }
529 if (bp->balls != NULL) {
530 free(bp->balls);
531 bp->balls = (ballstruct *) NULL;
532 }
533 free_stuff(display, bp);
534 if (bp->stippledGC != None) {
535 XFreeGC(display, bp->stippledGC);
536 bp->stippledGC = None;
537 }
538 if (bp->windows != NULL) {
539 free(bp->windows);
540 bp->windows = (ballwindow *) NULL;
541 }
542 bp = NULL;
543 }
544
545 static Bool
init_stuff(ModeInfo * mi)546 init_stuff(ModeInfo * mi)
547 {
548 Display *display = MI_DISPLAY(mi);
549 Window window = MI_WINDOW(mi);
550 bouncestruct *bp = &bounces[MI_SCREEN(mi)];
551 XGCValues gcv;
552
553 #ifndef STANDALONE
554 /* this used to work there I think */
555 if (MI_BITMAP(mi) && strlen(MI_BITMAP(mi))) {
556 if (bp->logo == None) {
557 getImage(mi, &bp->logo, BOUNCE_WIDTH, BOUNCE_HEIGHT, BOUNCE_BITS,
558 #ifdef HAVE_XPM
559 DEFAULT_XPM, BOUNCE_NAME,
560 #endif
561 &bp->graphics_format, &bp->cmap, &bp->black);
562 if (bp->logo == None) {
563 free_bounce_screen(display, bp);
564 return False;
565 }
566 }
567 } else
568 #endif
569 {
570 BALLBITS(bounce0_bits, bounce0_width, bounce0_height);
571 BALLBITS(bounce1_bits, bounce1_width, bounce1_height);
572 BALLBITS(bounce2_bits, bounce2_width, bounce2_height);
573 BALLBITS(bounce3_bits, bounce3_width, bounce3_height);
574 BALLBITS(bouncemask_bits, bouncemask_width, bouncemask_height);
575 }
576 if (bp->cmap != None) {
577 #ifndef STANDALONE
578 setColormap(display, window, bp->cmap, MI_IS_INWINDOW(mi));
579 #endif
580 if (bp->backGC == None) {
581 gcv.background = bp->black;
582 if ((bp->backGC = XCreateGC(display, window,
583 GCBackground, &gcv)) == None) {
584 free_bounce_screen(display, bp);
585 return False;
586 }
587 }
588 } else {
589 bp->black = MI_BLACK_PIXEL(mi);
590 bp->backGC = MI_GC(mi);
591 }
592 return True;
593 }
594
595 ENTRYPOINT void
init_bounce(ModeInfo * mi)596 init_bounce(ModeInfo * mi)
597 {
598 Display *display = MI_DISPLAY(mi);
599 Window window = MI_WINDOW(mi);
600 int size = MI_SIZE(mi);
601 bouncestruct *bp;
602 int i, tryagain = 0;
603 XGCValues gcv;
604
605 MI_INIT(mi, bounces);
606 bp = &bounces[MI_SCREEN(mi)];
607
608 free_stuff(display, bp);
609 bp->width = MI_WIDTH(mi);
610 bp->height = MI_HEIGHT(mi);
611 if (bp->width < 2)
612 bp->width = 2;
613 if (bp->height < 2)
614 bp->height = 2;
615 bp->restartnum = TIME;
616 bounce_windows(mi, bp);
617 bp->nballs = MI_COUNT(mi);
618 if (bp->nballs < -MINBALLS) {
619 /* if bp->nballs is random ... the size can change */
620 if (bp->balls != NULL) {
621 free(bp->balls);
622 bp->balls = (ballstruct *) NULL;
623 }
624 bp->nballs = NRAND(-bp->nballs - MINBALLS + 1) + MINBALLS;
625 } else if (bp->nballs < MINBALLS)
626 bp->nballs = MINBALLS;
627 if (bp->balls == NULL) {
628 if ((bp->balls = (ballstruct *) malloc(bp->nballs *
629 sizeof (ballstruct))) == NULL) {
630 free_bounce_screen(display, bp);
631 return;
632 }
633 }
634 if (!init_stuff(mi))
635 return;
636 if (bp->stippledGC == None) {
637 gcv.foreground = MI_BLACK_PIXEL(mi);
638 gcv.background = MI_BLACK_PIXEL(mi);
639 if ((bp->stippledGC = XCreateGC(display, window,
640 GCForeground | GCBackground, &gcv)) == None) {
641 free_bounce_screen(display, bp);
642 return;
643 }
644 }
645 if (size == 0 ||
646 MINGRIDSIZE * size > bp->width || MINGRIDSIZE * size > bp->height) {
647 if (bp->logo) {
648 bp->xs = bp->logo->width;
649 bp->ys = bp->logo->height;
650 } else {
651 bp->xs = bounce0_width;
652 bp->ys = bounce0_height;
653 }
654 if (bp->width > MINGRIDSIZE * bp->xs &&
655 bp->height > MINGRIDSIZE * bp->ys) {
656 bp->pixelmode = False;
657 } else {
658 bp->pixelmode = True;
659 bp->ys = MAX(MINSIZE, MIN(bp->width, bp->height) / MINGRIDSIZE);
660 bp->xs = bp->ys;
661 free_stuff(display, bp);
662 }
663 } else {
664 bp->pixelmode = True;
665 if (size < -MINSIZE)
666 bp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(bp->width, bp->height) /
667 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
668 else if (size < MINSIZE)
669 bp->ys = MINSIZE;
670 else
671 bp->ys = MIN(size, MAX(MINSIZE, MIN(bp->width, bp->height) /
672 MINGRIDSIZE));
673 bp->xs = bp->ys;
674 }
675 if (bp->pixelmode) {
676 GC fg_gc, bg_gc;
677
678 if ((bp->pixmaps[0] = XCreatePixmap(display, window,
679 bp->xs, bp->ys, 1)) == None) {
680 free_bounce_screen(display, bp);
681 return;
682 }
683 bp->init_orients = 1;
684 gcv.foreground = 0;
685 gcv.background = 1;
686 if ((bg_gc = XCreateGC(display, bp->pixmaps[0],
687 GCForeground | GCBackground, &gcv)) == None) {
688 free_bounce_screen(display, bp);
689 return;
690 }
691 gcv.foreground = 1;
692 gcv.background = 0;
693 if ((fg_gc = XCreateGC(display, bp->pixmaps[0],
694 GCForeground | GCBackground, &gcv)) == None) {
695 XFreeGC(display, bg_gc);
696 free_bounce_screen(display, bp);
697 return;
698 }
699 XFillRectangle(display, bp->pixmaps[0], bg_gc,
700 0, 0, bp->xs, bp->ys);
701 XFillArc(display, bp->pixmaps[0], fg_gc,
702 0, 0, bp->xs, bp->ys, 0, 23040);
703 XFreeGC(display, bg_gc);
704 XFreeGC(display, fg_gc);
705 }
706 bp->avgsize = (bp->xs + bp->ys) / 2;
707 i = 0;
708 while (i < bp->nballs) {
709 bp->balls[i].vx = ((LRAND() & 1) ? -1 : 1) * (NRAND(MAX_STRENGTH) + 1);
710 bp->balls[i].x = (bp->balls[i].vx >= 0) ? 0 : bp->width - bp->xs;
711 bp->balls[i].y = NRAND(bp->height / 2);
712 if (i == collide(bp, i) || tryagain >= 8) {
713 if (MI_NPIXELS(mi) > 2)
714 bp->balls[i].color =
715 MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
716 else
717 bp->balls[i].color = MI_WHITE_PIXEL(mi);
718 bp->balls[i].xlast = -1;
719 bp->balls[i].ylast = 0;
720 bp->balls[i].orientlast = 0;
721 bp->balls[i].spincount = 1;
722 bp->balls[i].spindelay = 1;
723 bp->balls[i].vy = ((LRAND() & 1) ? -1 : 1) * NRAND(MAX_STRENGTH);
724 bp->balls[i].spindir = 0;
725 bp->balls[i].vang = 0;
726 bp->balls[i].orient = NRAND(ORIENTS);
727 i++;
728 } else
729 tryagain++;
730 }
731 MI_CLEARWINDOW(mi);
732 }
733
734 ENTRYPOINT void
draw_bounce(ModeInfo * mi)735 draw_bounce(ModeInfo * mi)
736 {
737 int i;
738 bouncestruct *bp;
739
740 if (bounces == NULL)
741 return;
742 bp = &bounces[MI_SCREEN(mi)];
743 if (bp->balls == NULL)
744 return;
745
746 MI_IS_DRAWN(mi) = True;
747 for (i = 0; i < bp->nballs; i++) {
748 drawball(mi, &bp->balls[i]);
749 moveball(mi, &bp->balls[i]);
750 }
751 for (i = 0; i < bp->nballs; i++)
752 checkCollision(bp, i);
753 if (!NRAND(TIME)) /* Put some randomness into the time */
754 bp->restartnum--;
755 if (!bp->restartnum)
756 init_bounce(mi);
757 }
758
759 ENTRYPOINT void
release_bounce(ModeInfo * mi)760 release_bounce(ModeInfo * mi)
761 {
762 if (bounces != NULL) {
763 int screen;
764
765 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
766 free_bounce_screen(MI_DISPLAY(mi), &bounces[screen]);
767 free(bounces);
768 bounces = (bouncestruct *) NULL;
769 }
770 }
771
772 #ifndef STANDALONE
773 ENTRYPOINT void
refresh_bounce(ModeInfo * mi)774 refresh_bounce(ModeInfo * mi)
775 {
776 bouncestruct *bp = &bounces[MI_SCREEN(mi)];
777
778 MI_CLEARWINDOW(mi);
779 bounce_windows(mi, bp);
780 }
781 #endif
782
783 XSCREENSAVER_MODULE ("Bounce", bounce)
784
785 #endif /* MODE_bounce */
786