1 
2 /*
3 
4   *	Original Author Unknow.
5 
6   *	8/10/88 - Ported from X10 to X11R3 by:
7 
8 		Jonathan Greenblatt (jonnyg@rover.umd.edu)
9 
10   *	Cleaned up by Dave Lemke (lemke@sun.com)
11 
12   *	Ported to monocrome by Jonathan Greenblatt (jonnyg@rover.umd.edu)
13 
14   *     05/02/1996 Added TrueColor support by TJ Phan (phan@aur.alcatel.com)
15 
16   TODO:
17 
18 	Parameter parsing needs to be redone.
19 
20   *	Throughout 1991 improved for animation and color and multiple
21   	fish types.  Broke monocrome in the process.
22   	Eric Bina (ebina@ncsa.uiuc.edu)
23 
24   *	1992 added extra color remapping control options, as well as ways
25 	to let the fish swim on the root window, or an image of the users
26 	choice.  Eric Bina (ebina@ncsa.uiuc.edu)
27 
28 */
29 
30 #ifndef hpux
31 #include <sys/time.h>
32 #else
33 #include <time.h>
34 #endif
35 
36 #include <stdio.h>
37 #ifdef sgi
38 #define _BSD_SIGNALS
39 #endif
40 #include <signal.h>
41 #include <X11/Xlib.h>
42 #include <X11/Xutil.h>
43 
44 #include "vroot.h"
45 #include "xfishy.h"
46 #include "bubbles.h"
47 #include "medcut.h"
48 
49 /* constants are based on rand(3C) returning an integer between 0 and 32767 */
50 
51 #if defined(ultrix) || defined(sun)
52 #define  RAND_I_1_16   134217728
53 #define  RAND_F_1_8    268435455.875
54 #define  RAND_I_1_4    536870911
55 #define  RAND_I_1_2   1073741823
56 #define  RAND_I_3_4   1610612735
57 #define  RAND_F_MAX   2147483647.0
58 #else
59 #if defined(__FreeBSD__) || defined(__OpenBSD__)
60 #include <stdlib.h>
61 #include <unistd.h>
62 
63 #define  RAND_I_1_16   (RAND_MAX>>4)
64 #define  RAND_F_1_8    ((float)(RAND_MAX>>3))
65 #define  RAND_I_1_4    (RAND_MAX>>2)
66 #define  RAND_I_1_2    (RAND_MAX>>1)
67 #define  RAND_I_3_4    ((RAND_MAX>>2)*3)
68 #define  RAND_F_MAX    ((float)RAND_MAX)
69 #else
70 #define  RAND_I_1_16   2048
71 #define  RAND_F_1_8    4096.0
72 #define  RAND_I_1_4    8096
73 #define  RAND_I_1_2   16384
74 #define  RAND_I_3_4   24575
75 #define  RAND_F_MAX   32767.0
76 #endif
77 #endif
78 
79 extern unsigned char *ReadBitmap();
80 
81 
82 /* externals for pixmap and bimaps from xfishy.h */
83 
84 
85 /* typedefs for bubble and fish structures, also caddr_t (not used in X.h) */
86 typedef struct {
87     int         x,
88                 y,
89                 s,
90 		erased,
91                 i;
92 }           bubble;
93 typedef struct {
94     int         x,
95                 y,
96                 d,
97                 frame,
98                 type,
99                 i;
100 }           fish;
101 typedef unsigned char *caddrt;
102 
103 
104 /* bubble increment and yes check tables */
105 int         binc[] = {0, 64, 56, 48, 40, 32, 24, 16, 8};
106 char       *yess[] = {"yes", "Yes", "YES", "on", "On", "ON"};
107 
108 
109 char       *pname,		/* program name from argv[0] */
110             sname[64],		/* host:display specification */
111             cname[64];		/* colorname specification */
112 char	    picname[256];	/* name of the background picture file */
113 int         *Allocated;		/* mark the used colors */
114 int         AllocCnt;		/* count number of colors used */
115 int         mlimit = 0;		/* num colors to median cut to. 0 = no limit */
116 int         climit = 0;		/* limit on color use. 0 = no limit */
117 int         DoubleBuf = 0;	/* Should we use double buffering */
118 int         Overlap = 0;	/* Should fish swim over each other */
119 int         DoClipping = 0;	/* Should clip masks be used. */
120 int         blimit = 32,	/* bubble limit */
121             flimit = 10,	/* fish limit */
122             pmode = 1,		/* pop mode, (1 for lower, 0 for raise) */
123             width,		/* width of initial window in pixels */
124             height,		/* height of initial window in pixels */
125             screen,		/* Default screen of this display */
126 	    Init_B,
127 	    *cmap;		/* Initialize bubbles with random y value */
128 int	    Pwidth;		/* width of background picture */
129 int	    Pheight;		/* height of background picture */
130 int	    Pcnt;		/* number of colors in background picture */
131 unsigned char *Pdata;		/* data from background picture */
132 double      rate = 0.2,		/* update interval in seconds */
133             smooth = 0.2;	/* smoothness increment multiplier */
134 bubble     *binfo;		/* bubble info structures, allocated
135 				 * dynamically  */
136 fish       *finfo;		/* fish info structures, allocated dynamically */
137 Display    *Dpy;
138 XImage     *xfishA[NUM_FISH][3]; /* fish pixmaps (1 is left-fish, 2 is
139 				  * right-fish) */
140 XImage     *xfishB[NUM_FISH][3]; /* fish pixmaps (1 is left-fish, 2 is
141 				  * right-fish) */
142 Pixmap      pfishA[NUM_FISH][3];
143 Pixmap      pfishB[NUM_FISH][3];
144 
145 Pixmap      mfishA[NUM_FISH][3]; /* masking pixmaps for fish to use as */
146 Pixmap      mfishB[NUM_FISH][3]; /*  clipmasks */
147 
148 Pixmap      PicMap;		/* pixmap for background picture */
149 
150 Pixmap      PixBuf;		/* Pixmap buffer for double buffering */
151 Pixmap      ClipBuf;		/* Clipmask buffer for double buffering */
152 
153 Pixmap      xbubbles[9];	/* bubbles bitmaps (1 to 8, by size in pixels)*/
154 Window      wid;		/* aqaurium window */
155 unsigned long white, black,bcolor;
156 Colormap    colormap;
157 GC          c0gc, cpgc;		/* GCs to operateon the Clipmask buffer */
158 GC          pgc;
159 GC          gc,
160             bgc;
161 
162 
163 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
164 Output desired error message and exit.
165 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
166 void
msgdie(message)167 msgdie(message)
168     char       *message;
169 {
170     fprintf(stderr, "%s: %s\n", pname, message);
171     exit(1);
172 }
173 
174 
175 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
176 Set up program defaults, get X defaults, parse command line using getopts.
177 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
178 void
parse(argc,argv)179 parse(argc, argv)
180     int         argc;
181     char      **argv;
182 {
183     int         c,
184                 i;
185     char       *p;
186     extern int  optind;
187     extern char *optarg;
188     extern double atof();
189 
190     pname = argv[0];
191     strcpy(sname, getenv("DISPLAY"));
192     strcpy(cname, "MediumAquamarine");
193     picname[0] = '\0';
194 
195     if ((p = XGetDefault(Dpy, pname, "BubbleLimit")) != NULL)
196 	blimit = atoi(p);
197     if ((p = XGetDefault(Dpy, pname, "ColorLimit")) != NULL)
198 	climit = atoi(p);
199     if ((p = XGetDefault(Dpy, pname, "MedianCutLimit")) != NULL)
200 	mlimit = atoi(p);
201     if ((p = XGetDefault(Dpy, pname, "DoClipping")) != NULL)
202 	DoClipping = atoi(p);
203     if ((p = XGetDefault(Dpy, pname, "DoubleBuffer")) != NULL)
204 	DoubleBuf = atoi(p);
205     if ((p = XGetDefault(Dpy, pname, "Overlap")) != NULL)
206 	Overlap = atoi(p);
207     if ((p = XGetDefault(Dpy, pname, "Color")) != NULL)
208 	strcpy(cname, p);
209     if ((p = XGetDefault(Dpy, pname, "Picture")) != NULL)
210 	strcpy(picname, p);
211     if ((p = XGetDefault(Dpy, pname, "FishLimit")) != NULL)
212 	flimit = atoi(p);
213     if ((p = XGetDefault(Dpy, pname, "IncMult")) != NULL)
214 	smooth = atof(p);
215     if ((p = XGetDefault(Dpy, pname, "Rate")) != NULL)
216 	rate = atof(p);
217     if ((p = XGetDefault(Dpy, pname, "Secure")) != NULL)
218 	for (i = 0; i < 6; i++)
219 	    if (strcmp(p, yess[i]) == 0)
220 		pmode = 0;
221 
222     while ((c = getopt(argc, argv, "dDob:C:c:p:m:f:i:r:s")) != EOF) {
223 	switch (c) {
224 	case 'd':
225 	    DoClipping = 1;
226 	    break;
227 	case 'D':
228 	    DoubleBuf = 1;
229 	    break;
230 	case 'o':
231 	    Overlap = 1;
232 	    break;
233 	case 'b':
234 	    blimit = atoi(optarg);
235 	    break;
236 	case 'C':
237 	    climit = atoi(optarg);
238 	    break;
239 	case 'm':
240 	    mlimit = atoi(optarg);
241 	    break;
242 	case 'c':
243 	    strcpy(cname, optarg);
244 	    break;
245 	case 'p':
246 	    strcpy(picname, optarg);
247 	    break;
248 	case 'f':
249 	    flimit = atoi(optarg);
250 	    break;
251 	case 'i':
252 	    smooth = atof(optarg);
253 	    break;
254 	case 'r':
255 	    rate = atof(optarg);
256 	    break;
257 	case 's':
258 	    pmode = 0;
259 	    break;
260 	case '?':
261 	    fprintf(stderr, "usage: %s\n", pname);
262 	    fprintf(stderr, "\t\t[-c color]  background color\n");
263 	    fprintf(stderr, "\t\t[-b limit]  number of bubbles (default 32)\n");
264 	    fprintf(stderr, "\t\t[-f limit]  number of fish (default 10)\n");
265 	    fprintf(stderr, "\t\t[-i mult]   move interval (default 0.2)\n");
266 	    fprintf(stderr, "\t\t[-r rate]   move frequency (default 0.2)\n");
267 	    fprintf(stderr, "\t\t[-m num]    median cut to this many colors\n");
268 	    fprintf(stderr, "\t\t[-C num]    use only this many color cells\n");
269 	    fprintf(stderr, "\t\t[-d]        clip fish, swim on root window\n");
270 	    fprintf(stderr, "\t\t[-p file]   fish swim on picture in file\n");
271 	    fprintf(stderr, "\t\t[host:display]\n");
272 	    exit(1);
273 	}
274     }
275 
276     if (optind < argc)
277 	strcpy(sname, argv[optind]);
278 
279 	/*
280 	 * DoubleBuf is only useful if we are doing clipping on our
281 	 * own background picture, otherwise turn it off.
282 	 */
283 	if ((DoubleBuf)&&((!DoClipping)||(picname[0] == '\0')))
284 	{
285 		DoubleBuf = 0;
286 	}
287 }
288 
289 
290 void
erasefish(f,x,y,d)291 erasefish(f, x, y, d)
292 	fish *f;
293 	int x, y, d;
294 {
295 	/*
296 	 * for something as small as a bubble, it was never worth the
297 	 * effort of using clipmasks to only turn of the bubble itself, so
298 	 * we just clear the whole rectangle.
299 	 */
300 	XClearArea(Dpy, wid, x, y, rwidth[f->type], rheight[f->type], False);
301 /*
302 	XGCValues   gcv;
303 
304 	if (f->frame)
305 	{
306 		gcv.foreground = cmap[0];
307 		gcv.fill_style = FillTiled;
308 		gcv.fill_style = FillSolid;
309 		gcv.tile = pfishB[f->type][d];
310 		gcv.ts_x_origin = f->x;
311 		gcv.ts_y_origin = f->y;
312 		gcv.clip_mask = mfishB[f->type][d];
313 		gcv.clip_x_origin = x;
314 		gcv.clip_y_origin = y;
315 		XChangeGC(Dpy, gc, GCForeground | GCClipMask |
316 			GCTile | GCTileStipXOrigin | GCTileStipYOrigin |
317 			GCFillStyle | GCClipXOrigin | GCClipYOrigin,
318 			&gcv);
319 		XCopyPlane(Dpy, mfishB[f->type][d], wid, gc, 0, 0,
320 			rwidth[f->type], rheight[f->type],
321 			x, y, (unsigned long)1);
322 	}
323 	else
324 	{
325 		gcv.foreground = cmap[0];
326 		gcv.fill_style = FillTiled;
327 		gcv.fill_style = FillSolid;
328 		gcv.tile = pfishA[f->type][d];
329 		gcv.ts_x_origin = f->x;
330 		gcv.ts_y_origin = f->y;
331 		gcv.clip_mask = mfishA[f->type][d];
332 		gcv.clip_x_origin = x;
333 		gcv.clip_y_origin = y;
334 		XChangeGC(Dpy, gc, GCForeground | GCClipMask |
335 			GCTile | GCTileStipXOrigin | GCTileStipYOrigin |
336 			GCFillStyle | GCClipXOrigin | GCClipYOrigin,
337 			&gcv);
338 		XCopyPlane(Dpy, mfishA[f->type][d], wid, gc, 0, 0,
339 			rwidth[f->type], rheight[f->type],
340 			x, y, (unsigned long)1);
341 	}
342 */
343 }
344 
345 
346 /*
347  * Just places a fish.  Normally this is all you need for animation, since
348  * placeing the fish places an entire rectangle which erases most of the old
349  * fish (the rest being cleaned up by the function that called putfish.
350  * If DoClipping is set, this function is only called when placing a new
351  * fish, otherwise newfish is called.
352  */
353 void
putfish(f)354 putfish(f)
355 	fish *f;
356 {
357 	XGCValues   gcv;
358 
359 	if (f->frame)
360 	{
361 		/*
362 		 * If we have a pixmap of the fish use it, otherwise use
363 		 * the XImage of the fish.  In reality we will never use
364 		 * the XImage since X dies if the pixmap create failed
365 		 */
366 		if (pfishA[f->type][f->d])
367 		{
368 			/*
369 			 * Clipping overrides background picture because
370 			 * the clipping prevents the drawing of any background
371 			 * anyway.
372 			 * DoClipping says just print a fish leaving the
373 			 * background unchanged.
374 			 * If there is a background picture, we use a buffer
375 			 * to prevent flashing, we combine the background
376 			 * picture and the fish, and then copy the
377 			 * whole rectangle in.
378 			 * Default is just copy in fish in with a background
379 			 * color.
380 			 */
381 			if (DoClipping)
382 			{
383 				gcv.clip_mask = mfishA[f->type][f->d];
384 				gcv.clip_x_origin = f->x;
385 				gcv.clip_y_origin = f->y;
386 				XChangeGC(Dpy, gc,
387 				    GCClipMask | GCClipXOrigin | GCClipYOrigin,
388 				    &gcv);
389 				XCopyArea(Dpy, pfishA[f->type][f->d], wid, gc,
390 					0, 0, rwidth[f->type], rheight[f->type],
391 					f->x, f->y);
392 			}
393 			else if (picname[0] != '\0')
394 			{
395 				gcv.fill_style = FillTiled;
396 				gcv.tile = PicMap;
397 				gcv.ts_x_origin = -(f->x);
398 				gcv.ts_y_origin = -(f->y);
399 				gcv.clip_mask = None;
400 				XChangeGC(Dpy, pgc, (GCFillStyle |
401 					GCTile | GCTileStipXOrigin |
402 					GCTileStipYOrigin | GCClipMask),
403 					&gcv);
404 				XFillRectangle(Dpy, PixBuf, pgc, 0, 0,
405 					rwidth[f->type], rheight[f->type]);
406 
407 				gcv.clip_mask = mfishA[f->type][f->d];
408 				gcv.clip_x_origin = 0;
409 				gcv.clip_y_origin = 0;
410 				XChangeGC(Dpy, pgc,
411 				    GCClipMask | GCClipXOrigin | GCClipYOrigin,
412 				    &gcv);
413 				XCopyArea(Dpy, pfishA[f->type][f->d],PixBuf,pgc,
414 					0, 0, rwidth[f->type], rheight[f->type],
415 					0, 0);
416 
417 				XCopyArea(Dpy, PixBuf, wid, gc,
418 					0, 0, rwidth[f->type], rheight[f->type],
419 					f->x, f->y);
420 			}
421 			else
422 			{
423 				XCopyArea(Dpy, pfishA[f->type][f->d], wid, gc,
424 					0, 0, rwidth[f->type], rheight[f->type],
425 					f->x, f->y);
426 			}
427 		}
428 		else
429 		{
430 			XPutImage(Dpy, wid, gc, xfishA[f->type][f->d], 0, 0,
431 				f->x, f->y, rwidth[f->type], rheight[f->type]);
432 		}
433 		f->frame = 0;
434 	}
435 	else
436 	{
437 		/*
438 		 * same as the above, only for the second frame of animation
439 		 */
440 		if (pfishB[f->type][f->d])
441 		{
442 			if (DoClipping)
443 			{
444 				gcv.clip_mask = mfishB[f->type][f->d];
445 				gcv.clip_x_origin = f->x;
446 				gcv.clip_y_origin = f->y;
447 				XChangeGC(Dpy, gc,
448 				    GCClipMask | GCClipXOrigin | GCClipYOrigin,
449 				    &gcv);
450 				XCopyArea(Dpy, pfishB[f->type][f->d], wid, gc,
451 					0, 0, rwidth[f->type], rheight[f->type],
452 					f->x, f->y);
453 			}
454 			else if (picname[0] != '\0')
455 			{
456 				gcv.fill_style = FillTiled;
457 				gcv.tile = PicMap;
458 				gcv.ts_x_origin = -(f->x);
459 				gcv.ts_y_origin = -(f->y);
460 				gcv.clip_mask = None;
461 				XChangeGC(Dpy, pgc, (GCFillStyle |
462 					GCTile | GCTileStipXOrigin |
463 					GCTileStipYOrigin | GCClipMask),
464 					&gcv);
465 				XFillRectangle(Dpy, PixBuf, pgc, 0, 0,
466 					rwidth[f->type], rheight[f->type]);
467 
468 				gcv.clip_mask = mfishB[f->type][f->d];
469 				gcv.clip_x_origin = 0;
470 				gcv.clip_y_origin = 0;
471 				XChangeGC(Dpy, pgc,
472 				    GCClipMask | GCClipXOrigin | GCClipYOrigin,
473 				    &gcv);
474 				XCopyArea(Dpy, pfishB[f->type][f->d],PixBuf,pgc,
475 					0, 0, rwidth[f->type], rheight[f->type],
476 					0, 0);
477 
478 				XCopyArea(Dpy, PixBuf, wid, gc,
479 					0, 0, rwidth[f->type], rheight[f->type],
480 					f->x, f->y);
481 			}
482 			else
483 			{
484 				XCopyArea(Dpy, pfishB[f->type][f->d], wid, gc,
485 					0, 0, rwidth[f->type], rheight[f->type],
486 					f->x, f->y);
487 			}
488 		}
489 		else
490 		{
491 			XPutImage(Dpy, wid, gc, xfishB[f->type][f->d], 0, 0,
492 				f->x, f->y, rwidth[f->type], rheight[f->type]);
493 		}
494 		f->frame = 1;
495 	}
496 }
497 
498 
499 /*
500  * This function can only be called if DoClipping is True.  It is used to
501  * move a clipmasked fish.  First the area under the fish is cleared,
502  * and then the new fish is masked in.
503  * The parameters x, y, amd d are from the old fish that is being
504  * erased before the new fish is drawn.
505  */
506 void
movefish(f,x,y,d)507 movefish(f, x, y, d)
508 	fish *f;
509 	int x, y, d;
510 {
511 	XGCValues   gcv;
512 	int bx, by, bw, bh;
513 
514 	/*
515 	 * If we are going to double buffer, we need to find the bounding
516 	 * rectangle of the overlap of the bounding rectangles of the old
517 	 * and the new fish.
518 	 */
519 	if (DoubleBuf)
520 	{
521 		if (x < f->x)
522 		{
523 			bx = x;
524 			bw = f->x - x + rwidth[f->type];
525 		}
526 		else
527 		{
528 			bx = f->x;
529 			bw = x - f->x + rwidth[f->type];
530 		}
531 		if (y < f->y)
532 		{
533 			by = y;
534 			bh = f->y - y +rheight[f->type];
535 		}
536 		else
537 		{
538 			by = f->y;
539 			bh = y - f->y +rheight[f->type];
540 		}
541 	}
542 
543 	if (f->frame)
544 	{
545 		/*
546 		 * If there is a pixmap use it.
547 		 * This branchis always taken since right now, if the pixmap
548 		 * allocation failed, the program dies.
549 		 */
550 		if (pfishA[f->type][f->d])
551 		{
552 			/*
553 			 * A pointless if, you now only come here if
554 			 * DoClipping is set, I've just been too lazy to
555 			 * clean up my code.
556 			 */
557 			if (DoClipping)
558 			{
559 				/*
560 				 * Set up the masked gc for when we eventually
561 				 * draw the fish.  Origin is different for
562 				 * whether we are drawing into the buffer
563 				 * or into the window
564 				 */
565 				gcv.clip_mask = mfishA[f->type][f->d];
566 				if (DoubleBuf)
567 				{
568 					gcv.clip_x_origin = f->x - bx;
569 					gcv.clip_y_origin = f->y - by;
570 				}
571 				else
572 				{
573 					gcv.clip_x_origin = f->x;
574 					gcv.clip_y_origin = f->y;
575 				}
576 				XChangeGC(Dpy, gc,
577 				    GCClipMask | GCClipXOrigin | GCClipYOrigin,
578 				    &gcv);
579 
580 				/*
581 				 * If we have a background picture we want to
582 				 * clear to that background, otherwise we just
583 				 * do an XCleararea, and let the root restore
584 				 * the background.
585 				 */
586 				if (picname[0] != '\0')
587 				{
588 					gcv.fill_style = FillTiled;
589 					gcv.tile = PicMap;
590 					gcv.clip_mask = mfishB[f->type][d];
591 				    if (DoubleBuf)
592 				    {
593 					gcv.ts_x_origin = 0 - bx;
594 					gcv.ts_y_origin = 0 - by;
595 					gcv.clip_x_origin = x - bx;
596 					gcv.clip_y_origin = y - by;
597 				    }
598 				    else
599 				    {
600 					gcv.ts_x_origin = 0;
601 					gcv.ts_y_origin = 0;
602 					gcv.clip_x_origin = x;
603 					gcv.clip_y_origin = y;
604 				    }
605 					XChangeGC(Dpy, pgc, (GCFillStyle |
606 						GCTile | GCTileStipXOrigin |
607 						GCTileStipYOrigin | GCClipMask |
608 						GCClipXOrigin | GCClipYOrigin),
609 						&gcv);
610 
611 				    /*
612 				     * if bouble buffering we clear the buffer
613 				     * to the backgound picture, and then
614 				     * shape the clip buffer to the shape of
615 				     * the fish being erased.
616 				     */
617 				    if (DoubleBuf)
618 				    {
619 					XFillRectangle(Dpy, PixBuf, pgc,
620 						x - bx, y - by,
621 						rwidth[f->type],
622 						rheight[f->type]);
623 					XFillRectangle(Dpy, ClipBuf, c0gc, 0, 0,
624 						500, 500);
625 					XCopyArea(Dpy, mfishB[f->type][d],
626 						ClipBuf, cpgc, 0, 0,
627 						rwidth[f->type],
628 						rheight[f->type],
629 						x - bx, y - by);
630 				    }
631 				    else
632 				    {
633 					XFillRectangle(Dpy, wid, pgc, x, y,
634 						rwidth[f->type],
635 						rheight[f->type]);
636 				    }
637 				}
638 				else
639 				{
640 				    XClearArea(Dpy, wid, x, y,
641 					rwidth[f->type], rheight[f->type], 0);
642 				}
643 			}
644 		    /*
645 		     * Now we just copy in the new fish with a clipmasked gc.
646 		     * But if we doublebuffered, we copy the new fish into
647 		     * the buffer, combine the new fishes clipmask in, and
648 		     * then mask the whole lot from the buffer to the window.
649 		     */
650 		    if (DoubleBuf)
651 		    {
652 			XCopyArea(Dpy, pfishA[f->type][f->d], PixBuf, gc, 0, 0,
653 				rwidth[f->type], rheight[f->type],
654 				f->x - bx, f->y - by);
655 			XCopyArea(Dpy, mfishA[f->type][f->d], ClipBuf, cpgc,
656 				0, 0, rwidth[f->type], rheight[f->type],
657 				f->x - bx, f->y - by);
658 			gcv.clip_mask = ClipBuf;
659 			gcv.clip_x_origin = bx;
660 			gcv.clip_y_origin = by;
661 			XChangeGC(Dpy, gc,
662 			    GCClipMask | GCClipXOrigin | GCClipYOrigin,
663 			    &gcv);
664 			XCopyArea(Dpy, PixBuf, wid, gc, 0, 0, bw, bh, bx, by);
665 		    }
666 		    else
667 		    {
668 			XCopyArea(Dpy, pfishA[f->type][f->d], wid, gc, 0, 0,
669 				rwidth[f->type], rheight[f->type], f->x, f->y);
670 		    }
671 		}
672 		else
673 		{
674 			if (DoClipping)
675 			{
676 				if (picname[0] != '\0')
677 				{
678 					gcv.fill_style = FillTiled;
679 					gcv.tile = PicMap;
680 					gcv.ts_x_origin = 0;
681 					gcv.ts_y_origin = 0;
682 					gcv.clip_mask = mfishB[f->type][d];
683 					gcv.clip_x_origin = x;
684 					gcv.clip_y_origin = y;
685 					XChangeGC(Dpy, pgc, (GCFillStyle |
686 						GCTile | GCTileStipXOrigin |
687 						GCTileStipYOrigin | GCClipMask |
688 						GCClipXOrigin | GCClipYOrigin),
689 						&gcv);
690 					XFillRectangle(Dpy, wid, pgc, x, y,
691 						rwidth[f->type],
692 						rheight[f->type]);
693 				}
694 				else
695 				{
696 				    XClearArea(Dpy, wid, x, y,
697 					rwidth[f->type], rheight[f->type], 0);
698 				}
699 			}
700 			XPutImage(Dpy, wid, gc, xfishA[f->type][f->d], 0, 0,
701 				f->x, f->y, rwidth[f->type], rheight[f->type]);
702 		}
703 		f->frame = 0;
704 	}
705 	else
706 	{
707 		/*
708 		 * Same as above, only for the second frame of animation.
709 		 */
710 		if (pfishB[f->type][f->d])
711 		{
712 			if (DoClipping)
713 			{
714 				gcv.clip_mask = mfishB[f->type][f->d];
715 				if (DoubleBuf)
716 				{
717 					gcv.clip_x_origin = f->x - bx;
718 					gcv.clip_y_origin = f->y - by;
719 				}
720 				else
721 				{
722 					gcv.clip_x_origin = f->x;
723 					gcv.clip_y_origin = f->y;
724 				}
725 				XChangeGC(Dpy, gc,
726 				    GCClipMask | GCClipXOrigin | GCClipYOrigin,
727 				    &gcv);
728 				if (picname[0] != '\0')
729 				{
730 					gcv.fill_style = FillTiled;
731 					gcv.tile = PicMap;
732 					gcv.clip_mask = mfishA[f->type][d];
733 				    if (DoubleBuf)
734 				    {
735 					gcv.ts_x_origin = 0 - bx;
736 					gcv.ts_y_origin = 0 - by;
737 					gcv.clip_x_origin = x - bx;
738 					gcv.clip_y_origin = y - by;
739 				    }
740 				    else
741 				    {
742 					gcv.ts_x_origin = 0;
743 					gcv.ts_y_origin = 0;
744 					gcv.clip_x_origin = x;
745 					gcv.clip_y_origin = y;
746 				    }
747 					XChangeGC(Dpy, pgc, (GCFillStyle |
748 						GCTile | GCTileStipXOrigin |
749 						GCTileStipYOrigin | GCClipMask |
750 						GCClipXOrigin | GCClipYOrigin),
751 						&gcv);
752 				    if (DoubleBuf)
753 				    {
754 					XFillRectangle(Dpy, PixBuf, pgc,
755 						x - bx, y - by,
756 						rwidth[f->type],
757 						rheight[f->type]);
758 					XFillRectangle(Dpy, ClipBuf, c0gc, 0, 0,
759 						500, 500);
760 					XCopyArea(Dpy, mfishA[f->type][d],
761 						ClipBuf, cpgc, 0, 0,
762 						rwidth[f->type],
763 						rheight[f->type],
764 						x - bx, y - by);
765 				    }
766 				    else
767 				    {
768 					XFillRectangle(Dpy, wid, pgc, x, y,
769 						rwidth[f->type],
770 						rheight[f->type]);
771 				    }
772 				}
773 				else
774 				{
775 				    XClearArea(Dpy, wid, x, y,
776 					rwidth[f->type], rheight[f->type], 0);
777 				}
778 			}
779 		    if (DoubleBuf)
780 		    {
781 			XCopyArea(Dpy, pfishB[f->type][f->d], PixBuf, gc, 0, 0,
782 				rwidth[f->type], rheight[f->type],
783 				f->x - bx, f->y - by);
784 			XCopyArea(Dpy, mfishB[f->type][f->d], ClipBuf, cpgc,
785 				0, 0, rwidth[f->type], rheight[f->type],
786 				f->x - bx, f->y - by);
787 			gcv.clip_mask = ClipBuf;
788 			gcv.clip_x_origin = bx;
789 			gcv.clip_y_origin = by;
790 			XChangeGC(Dpy, gc,
791 			    GCClipMask | GCClipXOrigin | GCClipYOrigin,
792 			    &gcv);
793 			XCopyArea(Dpy, PixBuf, wid, gc, 0, 0, bw, bh, bx, by);
794 		    }
795 		    else
796 		    {
797 			XCopyArea(Dpy, pfishB[f->type][f->d], wid, gc, 0, 0,
798 				rwidth[f->type], rheight[f->type], f->x, f->y);
799 		    }
800 		}
801 		else
802 		{
803 			if (DoClipping)
804 			{
805 				if (picname[0] != '\0')
806 				{
807 					gcv.fill_style = FillTiled;
808 					gcv.tile = PicMap;
809 					gcv.ts_x_origin = 0;
810 					gcv.ts_y_origin = 0;
811 					gcv.clip_mask = mfishA[f->type][d];
812 					gcv.clip_x_origin = x;
813 					gcv.clip_y_origin = y;
814 					XChangeGC(Dpy, pgc, (GCFillStyle |
815 						GCTile | GCTileStipXOrigin |
816 						GCTileStipYOrigin | GCClipMask |
817 						GCClipXOrigin | GCClipYOrigin),
818 						&gcv);
819 					XFillRectangle(Dpy, wid, pgc, x, y,
820 						rwidth[f->type],
821 						rheight[f->type]);
822 				}
823 				else
824 				{
825 				    XClearArea(Dpy, wid, x, y,
826 					rwidth[f->type], rheight[f->type], 0);
827 				}
828 			}
829 			XPutImage(Dpy, wid, gc, xfishB[f->type][f->d], 0, 0,
830 				f->x, f->y, rwidth[f->type], rheight[f->type]);
831 		}
832 		f->frame = 1;
833 	}
834 }
835 
836 
erasebubble(b,s)837 erasebubble(b, s)
838     bubble     *b;
839     int         s;
840 {
841 	XClearArea(Dpy, wid, b->x, b->y, s, s, 0);
842 }
843 
844 
putbubble(b,s,c)845 putbubble(b, s, c)
846     bubble     *b;
847     int         s;
848     unsigned long c;
849 {
850     XGCValues   gcv;
851 
852     gcv.foreground = c;
853     gcv.clip_mask = xbubbles[s];
854     gcv.clip_x_origin = b->x;
855     gcv.clip_y_origin = b->y;
856     XChangeGC(Dpy, bgc, GCForeground | GCClipMask | GCClipXOrigin |
857 	      GCClipYOrigin, &gcv);
858     XFillRectangle(Dpy, wid, bgc, b->x, b->y, s, s);
859 }
860 
861 
862 /*
863  * Find the closest color by allocating it, or picking an already allocated
864  * color
865  */
866 Visual (*visual_info) = NULL;
867 int r_mask, g_mask, b_mask;
868 int r_shift=0, g_shift=0, b_shift=0;
869 int r_bits=0, g_bits=0, b_bits=0;
870 void
FindColor(Dpy,colormap,colr)871 FindColor(Dpy, colormap, colr)
872 	Display *Dpy;
873 	Colormap colormap;
874 	XColor *colr;
875 {
876 	int i, match;
877 	double rd, gd, bd, dist, mindist;
878 	int cindx;
879 	XColor def_colrs[256];
880 	int NumCells;
881 
882 	if( visual_info == NULL &&  DefaultDepth(Dpy, DefaultScreen(Dpy)) >= 16 )
883 	{
884 	   visual_info = DefaultVisual(Dpy, DefaultScreen(Dpy));
885 	   r_mask = visual_info->red_mask;
886 	   while( !(r_mask & 1) )
887 	   {
888 	      r_mask >>= 1;
889 	      r_shift++;
890 	   }
891 	   while( r_mask & 1 )
892 	   {
893 	      r_mask >>= 1;
894 	      r_bits++;
895 	   }
896 
897 	   g_mask = visual_info->green_mask;
898 	   while( !(g_mask & 1) )
899 	   {
900 	      g_mask >>= 1;
901 	      g_shift++;
902 	   }
903 	   while( g_mask & 1 )
904 	   {
905 	      g_mask >>= 1;
906 	      g_bits++;
907 	   }
908 
909 	   b_mask = visual_info->blue_mask;
910 	   while( !(b_mask &1) )
911 	   {
912 	      b_mask >>= 1;
913 	      b_shift++;
914 	   }
915 	   while( b_mask & 1 )
916 	   {
917 	      b_mask >>= 1;
918 	      b_bits++;
919 	   }
920 	}
921 
922 	if( DefaultDepth(Dpy, DefaultScreen(Dpy)) > 8 )
923 	{
924 	   colr->red >>= 16 - r_bits;
925 	   colr->green >>= 16 - g_bits;
926 	   colr->blue >>= 16 - b_bits;
927 
928 	   colr->pixel = ((colr->red << r_shift) & visual_info->red_mask) |
929 	      ((colr->green << g_shift) & visual_info->green_mask) |
930 	      ((colr->blue << b_shift) & visual_info->blue_mask);
931 	   return;
932 	}
933 
934 	if (AllocCnt < climit)
935 	{
936 		match = XAllocColor(Dpy, colormap, colr);
937 	}
938 	else
939 	{
940 		match = 0;
941 	}
942 	if (match == 0)
943 	{
944 		NumCells = DisplayCells(Dpy, DefaultScreen(Dpy));
945 		for (i=0; i<NumCells; i++)
946 		{
947 			def_colrs[i].pixel = i;
948 		}
949 		XQueryColors(Dpy, colormap, def_colrs, NumCells);
950 		mindist = 65536.0 * 65536.0;
951 		cindx = colr->pixel;
952 		for (i=0; i<NumCells; i++)
953 		{
954 			rd = (def_colrs[i].red - colr->red) / 256.0;
955 			gd = (def_colrs[i].green - colr->green) / 256.0;
956 			bd = (def_colrs[i].blue - colr->blue) / 256.0;
957 			dist = (rd * rd * rd * rd) +
958 				(gd * gd * gd * gd) +
959 				(bd * bd * bd * bd);
960 			if (dist < mindist)
961 			{
962 				mindist = dist;
963 				cindx = def_colrs[i].pixel;
964 			}
965 		}
966 		colr->pixel = cindx;
967 		colr->red = def_colrs[cindx].red;
968 		colr->green = def_colrs[cindx].green;
969 		colr->blue = def_colrs[cindx].blue;
970 	}
971 	else
972 	{
973 		if (Allocated[colr->pixel] == 0)
974 		{
975 			Allocated[colr->pixel] = 1;
976 			AllocCnt++;
977 		}
978 	}
979 }
980 
981 
982 int
ColorUsage(data,width,height,colrs)983 ColorUsage(data, width, height, colrs)
984 	unsigned char *data;
985 	int width, height;
986 	struct colr_data *colrs;
987 {
988 	int mapping[256];
989 	int i, size;
990 	int cnt, indx;
991 	unsigned char *ptr;
992 	struct colr_data newcol[256];
993 
994 	for (i=0; i<256; i++)
995 	{
996 		mapping[i] = -1;
997 	}
998 
999 	size = width * height;
1000 	cnt = 0;
1001 	ptr = data;
1002 	for (i=0; i<size; i++)
1003 	{
1004 		indx = (int)*ptr;
1005 		if (mapping[indx] == -1)
1006 		{
1007 			mapping[indx] = cnt;
1008 			newcol[cnt].red = colrs[indx].red;
1009 			newcol[cnt].green = colrs[indx].green;
1010 			newcol[cnt].blue = colrs[indx].blue;
1011 			cnt++;
1012 		}
1013 		ptr++;
1014 	}
1015 
1016 	ptr = data;
1017 	for (i=0; i<size; i++)
1018 	{
1019 		indx = (int)*ptr;
1020 		*ptr = (unsigned char)mapping[indx];
1021 		ptr++;
1022 	}
1023 
1024 	for (i=0; i<cnt; i++)
1025 	{
1026 		colrs[i].red = newcol[i].red;
1027 		colrs[i].green = newcol[i].green;
1028 		colrs[i].blue = newcol[i].blue;
1029 	}
1030 	for (i=cnt; i<256; i++)
1031 	{
1032 		colrs[i].red = 0;
1033 		colrs[i].green = 0;
1034 		colrs[i].blue = 0;
1035 	}
1036 
1037 	return(cnt);
1038 }
1039 
1040 
1041 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1042 Initialize colormap for background color and required fish colors.
1043 The fish colors are coded in xfishy.h as a trio of tables.
1044 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1045 void
init_colormap()1046 init_colormap()
1047 {
1048 	FILE *fp;
1049 	int i, j, cnt;
1050 	int NumCells;
1051 	XColor hdef, edef;
1052 	struct colr_data *cdp;
1053 	struct colr_data colrs[256];
1054 
1055 	colormap = XDefaultColormap(Dpy, screen);
1056 
1057 	if (colormap == NULL)
1058 	{
1059 		return;
1060 	}
1061 
1062 	NumCells = DisplayCells(Dpy, DefaultScreen(Dpy));
1063 	Allocated = (int *)malloc(NumCells * sizeof(int));
1064 	for (i=0; i<NumCells; i++)
1065 	{
1066 		Allocated[i] = 0;
1067 	}
1068 	AllocCnt = 0;
1069 	if ((climit <= 0)||(climit > NumCells))
1070 	{
1071 		climit = NumCells;
1072 	}
1073 
1074 	Pcnt = 0;
1075 	if (picname[0] != '\0')
1076 	{
1077 		fp = fopen(picname, "r");
1078 		if (fp == NULL)
1079 		{
1080 			fprintf(stderr, "Cannot open picture %s for reading\n",
1081 				picname);
1082 		}
1083 		else
1084 		{
1085 			Pdata = ReadBitmap(fp, &Pwidth, &Pheight, colrs);
1086 			fclose(fp);
1087 			Pcnt = ColorUsage(Pdata, Pwidth, Pheight, colrs);
1088 		}
1089 	}
1090 
1091 	cnt = 0;
1092 	cnt += Pcnt;
1093 	for (i=0; i<NUM_FISH; i++)
1094 	{
1095 		cnt += rcolors[i];
1096 	}
1097 	cmap = (int *) malloc((cnt + 1) * sizeof(int));
1098 
1099 	XLookupColor(Dpy, colormap, cname, &hdef, &edef);
1100 	hdef.flags = DoRed|DoGreen|DoBlue;
1101 	FindColor(Dpy, colormap, &hdef);
1102 	cmap[0] = hdef.pixel;
1103 
1104 	if (mlimit > 0)
1105 	{
1106 		MedianInit();
1107 	}
1108 
1109 	if (mlimit > 0)
1110 	{
1111 		if (picname[0] != '\0')
1112 		{
1113 			MedianCount(Pdata, Pwidth, Pheight, colrs);
1114 		}
1115 		for (j=0; j<NUM_FISH; j++)
1116 		{
1117 			int *rp, *gp, *bp;
1118 
1119 			cdp = (struct colr_data *)malloc(rcolors[j] *
1120 				sizeof(struct colr_data));
1121 			rp = rreds[j];
1122 			gp = rgreens[j];
1123 			bp = rblues[j];
1124 			for (i = 0; i < rcolors[j]; i++)
1125 			{
1126 				cdp[i].red = *rp++;
1127 				cdp[i].green = *gp++;
1128 				cdp[i].blue = *bp++;
1129 			}
1130 			MedianCount((unsigned char *)xfishRasterA[j],
1131 				(int)rwidth[j], (int)rheight[j], cdp);
1132 			free((char *)cdp);
1133 		}
1134 		MedianSplit(mlimit);
1135 	}
1136 
1137 	cnt = 1;
1138 	if (picname[0] != '\0')
1139 	{
1140 		for (i = 0; i < Pcnt; i++)
1141 		{
1142 			int rv, gv, bv;
1143 
1144 			rv = colrs[i].red;
1145 			gv = colrs[i].green;
1146 			bv = colrs[i].blue;
1147 
1148 			if (mlimit > 0)
1149 			{
1150 				ConvertColor(&rv, &gv, &bv);
1151 			}
1152 
1153 			hdef.red = rv;
1154 			hdef.green = gv;
1155 			hdef.blue = bv;
1156 			hdef.flags = DoRed|DoGreen|DoBlue;
1157 			FindColor(Dpy, colormap, &hdef);
1158 			cmap[cnt] = hdef.pixel;
1159 			cnt++;
1160 		}
1161 	}
1162 	for (j=0; j<NUM_FISH; j++)
1163 	{
1164 		int *rp, *gp, *bp;
1165 
1166 		rp = rreds[j];
1167 		gp = rgreens[j];
1168 		bp = rblues[j];
1169 		for (i = 0; i < rcolors[j]; i++)
1170 		{
1171 			int rv, gv, bv;
1172 
1173 			rv = *rp++;
1174 			gv = *gp++;
1175 			bv = *bp++;
1176 
1177 			if (mlimit > 0)
1178 			{
1179 				ConvertColor(&rv, &gv, &bv);
1180 			}
1181 
1182 			hdef.red = rv;
1183 			hdef.green = gv;
1184 			hdef.blue = bv;
1185 			hdef.flags = DoRed|DoGreen|DoBlue;
1186 			FindColor(Dpy, colormap, &hdef);
1187 			cmap[cnt] = hdef.pixel;
1188 			if (i == rback[j])
1189 			{
1190 				cmap[cnt] = cmap[0];
1191 			}
1192 			cnt++;
1193 		}
1194 	}
1195 
1196 	bcolor = white;
1197 }
1198 
1199 
1200 /*
1201  * Make am image of appropriate depth for display from image data.
1202  */
1203 XImage *
MakeImage(data,width,height)1204 MakeImage(data, width, height)
1205 	unsigned char *data;
1206 	int width, height;
1207 {
1208 	int linepad, shiftnum;
1209 	int shiftstart, shiftstop, shiftinc;
1210 	int bytesperline;
1211 	int depth, temp;
1212 	int w, h;
1213 	XImage *newimage;
1214 	unsigned char *bit_data, *bitp, *datap;
1215 
1216 	depth = DefaultDepth(Dpy, DefaultScreen(Dpy));
1217 	if ((depth != 1)&&(depth != 2)&&(depth != 4)&&(depth != 8))
1218 	{
1219 		fprintf(stderr, "Don't know how to format image for display of depth %d\n", depth);
1220 		exit(1);
1221 	}
1222 
1223 	if (BitmapBitOrder(Dpy) == LSBFirst)
1224 	{
1225 		shiftstart = 0;
1226 		shiftstop = 8;
1227 		shiftinc = depth;
1228 	}
1229 	else
1230 	{
1231 		shiftstart = 8 - depth;
1232 		shiftstop = -depth;
1233 		shiftinc = -depth;
1234 	}
1235 	linepad = 8 - (width % 8);
1236 	bit_data = (unsigned char *)malloc(((width + linepad) * height) + 1);
1237 	bitp = bit_data;
1238 	datap = data;
1239 	*bitp = 0;
1240 	shiftnum = shiftstart;
1241 	for (h=0; h<height; h++)
1242 	{
1243 		for (w=0; w<width; w++)
1244 		{
1245 			temp = *datap++ << shiftnum;
1246 			*bitp = *bitp | temp;
1247 			shiftnum = shiftnum + shiftinc;
1248 			if (shiftnum == shiftstop)
1249 			{
1250 				shiftnum = shiftstart;
1251 				bitp++;
1252 				*bitp = 0;
1253 			}
1254 		}
1255 		for (w=0; w<linepad; w++)
1256 		{
1257 			shiftnum = shiftnum + shiftinc;
1258 			if (shiftnum == shiftstop)
1259 			{
1260 				shiftnum = shiftstart;
1261 				bitp++;
1262 				*bitp = 0;
1263 			}
1264 		}
1265 	}
1266 
1267 	bytesperline = (width  * depth / 8 + linepad);
1268 	newimage = XCreateImage(Dpy, DefaultVisual(Dpy, screen), depth,
1269 		ZPixmap, 0, (char *)bit_data,
1270 		(width + linepad), height, 8, bytesperline);
1271 
1272 	return(newimage);
1273 }
1274 
1275 
1276 
1277 static unsigned char bits[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
1278 
1279 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1280 Calibrate the pixmaps and bimaps.  The right-fish data is coded in xfishy.h,
1281 this is transformed to create the left-fish.  The eight bubbles are coded
1282 in bubbles.h as a two dimensional array.
1283 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1284 void
init_pixmap()1285 init_pixmap()
1286 {
1287 	register caddrt p, q, x1A, x1B, x2A, x2B;
1288 	unsigned char *data;
1289 	register int i, j, k;
1290 	int cnt, wcnt;
1291 
1292 	cnt = 1;
1293 	cnt += Pcnt;
1294 	for (k=0; k<NUM_FISH; k++)
1295 	{
1296 
1297 	/*
1298 	 * The clipmasks must be created before we remap colors.
1299 	 * otherwise an opaque color might get remapped to a
1300 	 * transparent color.
1301 	 */
1302 	if ((DoClipping)||(picname[0] != '\0'))
1303 	{
1304 		data = (unsigned char *) malloc((rwidth[k]+7) / 8 * rheight[k]);
1305 
1306 		p = (caddrt) xfishRasterA[k];
1307 		q = data;
1308 		wcnt = 0;
1309 		for (i = 0; i < ((rwidth[k]+7) / 8 * rheight[k]); i++)
1310 		{
1311 			unsigned char bt = 0x00;
1312 			for (j = 0; j < 8; j++)
1313 			{
1314 				if (*p != rback[k])
1315 				{
1316 					bt = bt | bits[j];
1317 				}
1318 				wcnt++;
1319 				p++;
1320 				if (wcnt == rwidth[k])
1321 				{
1322 					wcnt = 0;
1323 					break;
1324 				}
1325 			}
1326 			*q++ = bt;
1327 		}
1328 		mfishA[k][2] = XCreateBitmapFromData(Dpy, wid,
1329 			(char *)data, rwidth[k], rheight[k]);
1330 
1331 		p = (caddrt) xfishRasterA[k];
1332 		p = p + rwidth[k] - 1;
1333 		q = data;
1334 		wcnt = 0;
1335 		for (i = 0; i < ((rwidth[k]+7) / 8 * rheight[k]); i++)
1336 		{
1337 			unsigned char bt = 0x00;
1338 			for (j = 0; j < 8; j++)
1339 			{
1340 				if (*p != rback[k])
1341 				{
1342 					bt = bt | bits[j];
1343 				}
1344 				wcnt++;
1345 				p--;
1346 				if (wcnt == rwidth[k])
1347 				{
1348 					wcnt = 0;
1349 					p = p + (2 * rwidth[k]);
1350 					break;
1351 				}
1352 			}
1353 			*q++ = bt;
1354 		}
1355 		mfishA[k][1] = XCreateBitmapFromData(Dpy, wid,
1356 			(char *)data, rwidth[k], rheight[k]);
1357 
1358 		p = (caddrt) xfishRasterB[k];
1359 		q = data;
1360 		wcnt = 0;
1361 		for (i = 0; i < ((rwidth[k]+7) / 8 * rheight[k]); i++)
1362 		{
1363 			unsigned char bt = 0x00;
1364 			for (j = 0; j < 8; j++)
1365 			{
1366 				if (*p != rback[k])
1367 				{
1368 					bt = bt | bits[j];
1369 				}
1370 				wcnt++;
1371 				p++;
1372 				if (wcnt == rwidth[k])
1373 				{
1374 					wcnt = 0;
1375 					break;
1376 				}
1377 			}
1378 			*q++ = bt;
1379 		}
1380 		mfishB[k][2] = XCreateBitmapFromData(Dpy, wid,
1381 			(char *)data, rwidth[k], rheight[k]);
1382 
1383 		p = (caddrt) xfishRasterB[k];
1384 		p = p + rwidth[k] - 1;
1385 		q = data;
1386 		wcnt = 0;
1387 		for (i = 0; i < ((rwidth[k]+7) / 8 * rheight[k]); i++)
1388 		{
1389 			unsigned char bt = 0x00;
1390 			for (j = 0; j < 8; j++)
1391 			{
1392 				if (*p != rback[k])
1393 				{
1394 					bt = bt | bits[j];
1395 				}
1396 				wcnt++;
1397 				p--;
1398 				if (wcnt == rwidth[k])
1399 				{
1400 					wcnt = 0;
1401 					p = p + (2 * rwidth[k]);
1402 					break;
1403 				}
1404 			}
1405 			*q++ = bt;
1406 		}
1407 		mfishB[k][1] = XCreateBitmapFromData(Dpy, wid,
1408 			(char *)data, rwidth[k], rheight[k]);
1409 
1410 		free((char *)data);
1411 	}
1412 
1413 	if( DisplayPlanes(Dpy, screen) < 8 )
1414 	{
1415 
1416 		j = rwidth[k] * rheight[k];
1417 		x1A = (caddrt) malloc(rwidth[k] * rheight[k]);
1418 		p = (caddrt) xfishRasterA[k];
1419 
1420 
1421 		q = x1A;
1422 		for (i = 0; i < j; i++)
1423 		{
1424 			*q = cmap[cnt + (int)(*p)];
1425 			p++;
1426 			q++;
1427 		}
1428 
1429 		x1B = (caddrt) malloc(rwidth[k] * rheight[k]);
1430 		p = (caddrt) xfishRasterB[k];
1431 		q = x1B;
1432 		for (i = 0; i < j; i++)
1433 		{
1434 			*q = cmap[cnt + (int)(*p)];
1435 			p++;
1436 			q++;
1437 		}
1438 
1439 		x2A = (caddrt) malloc(rwidth[k] * rheight[k]);
1440 		for (i = 0; i < rheight[k]; i++)
1441 		{
1442 			p = x1A + i * rwidth[k];
1443 			q = x2A + (i + 1) * rwidth[k] - 1;
1444 			for (j = 0; j < rwidth[k]; j++)
1445 			{
1446 				*q-- = *p++;
1447 			}
1448 		}
1449 
1450 		x2B = (caddrt) malloc(rwidth[k] * rheight[k]);
1451 		for (i = 0; i < rheight[k]; i++)
1452 		{
1453 			p = x1B + i * rwidth[k];
1454 			q = x2B + (i + 1) * rwidth[k] - 1;
1455 			for (j = 0; j < rwidth[k]; j++)
1456 			{
1457 				*q-- = *p++;
1458 			}
1459 		}
1460 
1461 		xfishA[k][2] = MakeImage(x1A, rwidth[k], rheight[k]);
1462 		xfishA[k][1] = MakeImage(x2A, rwidth[k], rheight[k]);
1463 		xfishB[k][2] = MakeImage(x1B, rwidth[k], rheight[k]);
1464 		xfishB[k][1] = MakeImage(x2B, rwidth[k], rheight[k]);
1465 
1466 		free((char *)x1A);
1467 		free((char *)x2A);
1468 		free((char *)x1B);
1469 		free((char *)x2B);
1470 
1471 	}
1472 	else
1473 	{
1474 		i = DisplayPlanes(Dpy, screen);
1475 
1476 		xfishA[k][2] = XGetImage(Dpy, DefaultRootWindow(Dpy), 0, 0, rwidth[k], rheight[k], 0, ZPixmap);
1477 
1478 		p = (caddrt) xfishRasterA[k];
1479 
1480 		for (j = 0; j < rheight[k]; j++)
1481 		{
1482 		   for( i = 0; i < rwidth[k]; i++ )
1483 		   {
1484 		      XPutPixel(xfishA[k][2], i, j, cmap[cnt + (int)(*p)]);
1485 		      p++;
1486 		   }
1487 		}
1488 
1489 		xfishB[k][2] = XGetImage(Dpy, DefaultRootWindow(Dpy), 0, 0, rwidth[k], rheight[k], 0, ZPixmap);
1490 
1491 		p = (caddrt) xfishRasterB[k];
1492 
1493 		for (j = 0; j < rheight[k]; j++)
1494 		{
1495 		   for( i = 0; i < rwidth[k]; i++ )
1496 		   {
1497 		      XPutPixel(xfishB[k][2], i, j, cmap[cnt + (int)(*p)]);
1498 		      p++;
1499 		   }
1500 		}
1501 
1502 		xfishA[k][1] = XGetImage(Dpy, DefaultRootWindow(Dpy), 0, 0, rwidth[k], rheight[k], 0, ZPixmap);
1503 
1504 		for (j = 0; j < rheight[k]; j++)
1505 		{
1506 		   for( i = 0; i < rwidth[k]; i++ )
1507 		   {
1508 		      XPutPixel(xfishA[k][1], i, j,
1509 				XGetPixel(xfishA[k][2], rwidth[k] - i -1, j));
1510 		   }
1511 		}
1512 
1513 		xfishB[k][1] = XGetImage(Dpy, DefaultRootWindow(Dpy), 0, 0, rwidth[k], rheight[k], 0, ZPixmap);
1514 
1515 		for (j = 0; j < rheight[k]; j++)
1516 		{
1517 		   for( i = 0; i < rwidth[k]; i++ )
1518 		   {
1519 		      XPutPixel(xfishB[k][1], i, j,
1520 				XGetPixel(xfishB[k][2], rwidth[k] - i - 1, j));
1521 		   }
1522 		}
1523 
1524 	}
1525 
1526 
1527 		i = DisplayPlanes(Dpy, screen);
1528 
1529 		pfishA[k][1] = XCreatePixmap(Dpy, wid,
1530 			rwidth[k], rheight[k], i);
1531 		pfishA[k][2] = XCreatePixmap(Dpy, wid,
1532 			rwidth[k], rheight[k], i);
1533 		pfishB[k][1] = XCreatePixmap(Dpy, wid,
1534 			rwidth[k], rheight[k], i);
1535 		pfishB[k][2] = XCreatePixmap(Dpy, wid,
1536 			rwidth[k], rheight[k], i);
1537 
1538 		if (pfishA[k][1])
1539 		{
1540 			XPutImage(Dpy, pfishA[k][1], gc, xfishA[k][1], 0, 0,
1541 				0, 0, rwidth[k], rheight[k]);
1542 		}
1543 		if (pfishA[k][2])
1544 		{
1545 			XPutImage(Dpy, pfishA[k][2], gc, xfishA[k][2], 0, 0,
1546 				0, 0, rwidth[k], rheight[k]);
1547 		}
1548 		if (pfishB[k][1])
1549 		{
1550 			XPutImage(Dpy, pfishB[k][1], gc, xfishB[k][1], 0, 0,
1551 				0, 0, rwidth[k], rheight[k]);
1552 		}
1553 		if (pfishB[k][2])
1554 		{
1555 			XPutImage(Dpy, pfishB[k][2], gc, xfishB[k][2], 0, 0,
1556 				0, 0, rwidth[k], rheight[k]);
1557 		}
1558 
1559 		cnt += rcolors[k];
1560 	}
1561 
1562 	for (i = 1; i <= 8; i++)
1563 	{
1564 		xbubbles[i] = XCreateBitmapFromData(Dpy, wid,
1565 			(char *)xbBits[i], i, i);
1566 	}
1567 }
1568 
1569 
1570 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1571 Toggle secure mode on receipt of signal
1572 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1573 #ifdef sgi
1574 int
1575 #else
1576 void
1577 #endif
toggle_secure()1578 toggle_secure()
1579 {
1580     pmode = !pmode;
1581     if (pmode)
1582 	XLowerWindow(Dpy, wid);
1583     else
1584 	XRaiseWindow(Dpy, wid);
1585     XFlush(Dpy);
1586 #ifdef sgi
1587     return(1);
1588 #endif
1589 }
1590 
1591 
1592 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1593 Initialize signal so that SIGUSR1 causes secure mode to toggle.
1594 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1595 void
init_signals()1596 init_signals()
1597 {
1598 }
1599 
1600 
1601 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1602 Variety of initialization calls, including getting the window up and running.
1603 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1604 void
initialize()1605 initialize()
1606 {
1607     XWindowAttributes winfo;
1608     XSetWindowAttributes attr;
1609     XGCValues   vals;
1610     XSizeHints  xsh;
1611     XImage *pimage;
1612     int i, size, cnt;
1613     unsigned char *ndata;
1614     unsigned char *ptr1, *ptr2;
1615 
1616     XGetWindowAttributes(Dpy, DefaultRootWindow(Dpy), &winfo);
1617     width = winfo.width;
1618     height = winfo.height;
1619 
1620     init_colormap();
1621 
1622     if (picname[0] != '\0')
1623     {
1624 	size = Pwidth * Pheight;
1625 	ndata = (unsigned char *)malloc(size);
1626 	ptr1 = Pdata;
1627 	ptr2 = ndata;
1628 	cnt = 1;
1629 	for (i = 0; i < size; i++)
1630 	{
1631 		*ptr2 = cmap[cnt + (int)(*ptr1)];
1632 		ptr1++;
1633 		ptr2++;
1634 	}
1635 	pimage = MakeImage(ndata, Pwidth, Pheight);
1636 	free((char *)ndata);
1637 	i = DisplayPlanes(Dpy, screen);
1638 	PicMap = XCreatePixmap(Dpy, DefaultRootWindow(Dpy), Pwidth, Pheight, i);
1639 	if (PicMap == NULL)
1640 	{
1641 		fprintf(stderr, "Cannot create background pixmap\n");
1642 		picname[0] = '\0';
1643 	}
1644     }
1645 
1646     if ((DoubleBuf)||(picname[0] != '\0'))
1647     {
1648 	i = DisplayPlanes(Dpy, screen);
1649 	PixBuf = XCreatePixmap(Dpy, DefaultRootWindow(Dpy), 500, 500, i);
1650 	ClipBuf = XCreatePixmap(Dpy, DefaultRootWindow(Dpy), 500, 500, 1);
1651 	c0gc = XCreateGC(Dpy, ClipBuf, 0, NULL);
1652 	XSetForeground(Dpy, c0gc, (unsigned long)0);
1653 	XSetFunction(Dpy, c0gc, GXcopy);
1654 	cpgc = XCreateGC(Dpy, ClipBuf, 0, NULL);
1655 	XSetFunction(Dpy, cpgc, GXor);
1656     }
1657 
1658 
1659     attr.override_redirect = True;
1660     attr.background_pixel = cmap[0];
1661 
1662 if ((!DoClipping)||(picname[0] != '\0'))
1663 {
1664     wid = XCreateWindow(Dpy, DefaultRootWindow(Dpy),
1665 	1, 1, width - 2, height - 2, 0,
1666 	CopyFromParent, CopyFromParent, CopyFromParent,
1667 	CWBackPixel | CWOverrideRedirect, &attr);
1668 
1669     if (!wid)
1670 	msgdie("XCreateWindow failed");
1671 }
1672 else
1673 {
1674     wid = DefaultRootWindow(Dpy);
1675     XClearArea(Dpy, wid, 0, 0, 0, 0, False);
1676 }
1677 
1678     vals.foreground = vals.background = cmap[0];
1679     vals.graphics_exposures = False;
1680     gc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures,
1681 	&vals);
1682     pgc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures,
1683 	&vals);
1684     bgc = XCreateGC(Dpy, wid, GCForeground | GCBackground | GCGraphicsExposures,
1685 	&vals);
1686 
1687     for (i=0; i<NUM_FISH; i++)
1688     {
1689 	pfishA[i][0] = 0;
1690 	pfishA[i][1] = 0;
1691 	pfishA[i][2] = 0;
1692 	pfishB[i][0] = 0;
1693 	pfishB[i][1] = 0;
1694 	pfishB[i][2] = 0;
1695 
1696 	mfishA[i][0] = 0;
1697 	mfishA[i][1] = 0;
1698 	mfishA[i][2] = 0;
1699 	mfishB[i][0] = 0;
1700 	mfishB[i][1] = 0;
1701 	mfishB[i][2] = 0;
1702     }
1703 
1704     init_pixmap();
1705     init_signals();
1706 
1707 if ((!DoClipping)||(picname[0] != '\0'))
1708 {
1709     XStoreName(Dpy, wid, pname);
1710 
1711     xsh.flags = USSize | USPosition | PPosition | PSize;
1712     xsh.x = xsh.y = 0;
1713     xsh.width = width;
1714     xsh.height = height;
1715     XSetNormalHints(Dpy, wid, &xsh);
1716 
1717     XMapWindow(Dpy, wid);
1718     if (picname[0] != '\0')
1719     {
1720 	XPutImage(Dpy, PicMap, gc, pimage, 0, 0, 0, 0, Pwidth, Pheight);
1721 	XSetWindowBackgroundPixmap(Dpy, wid, PicMap);
1722     }
1723 }
1724 
1725     binfo = (bubble *) malloc(blimit * sizeof(bubble));
1726     finfo = (fish *) malloc(flimit * sizeof(fish));
1727 }
1728 
1729 
1730 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1731 Create a new bubble.  Placement along the x axis is random, as is the size of
1732 the bubble.  Increment value is determined by speed.
1733 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1734 void
new_bubble(b0)1735 new_bubble(b0)
1736     bubble     *b0;
1737 {
1738     register int s;
1739     register bubble *b = b0;
1740 
1741     b->x = width * (rand() / RAND_F_MAX);
1742     if (Init_B)
1743 	b->y = (height / 16) * (rand() / RAND_I_1_16 + 1) - 1;
1744     else
1745 	b->y = height - 1;
1746     b->s = s = 1.0 + rand() / RAND_F_1_8;
1747     if ((b->i = smooth * height / (float) binc[s]) == 0)
1748 	b->i = 1;
1749     b->erased = 0;
1750     putbubble(b, s, bcolor);
1751 }
1752 
1753 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1754 Erase old bubbles, move and draw new bubbles.  Random left-right factor
1755 can move bubble one size-unit in either direction.
1756 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1757 void
step_bubbles()1758 step_bubbles()
1759 {
1760 	register int i, j, s;
1761 	register bubble *b;
1762 
1763 	for (i = 0; i < blimit; i++)
1764 	{
1765 		b = &binfo[i];
1766 		s = b->s;
1767 		/* clear */
1768 		if ((b->y > 0)&&(b->erased == 0))
1769 		{
1770 			if ((DoClipping)||(picname[0] != '\0'))
1771 			{
1772 				erasebubble(b, s);
1773 			}
1774 			else
1775 			{
1776 				putbubble(b, s, cmap[0]);
1777 			}
1778 		}
1779 		if ((b->y -= b->i) > 0)
1780 		{
1781 			j = rand();
1782 			if (j < RAND_I_1_4)
1783 			{
1784 				b->x -= s;
1785 			}
1786 			else if (j > RAND_I_3_4)
1787 			{
1788 				b->x += s;
1789 			}
1790 			putbubble(b, s, bcolor);
1791 		}
1792 		else
1793 		{
1794 			if (rand() < RAND_I_1_4)
1795 			{
1796 				new_bubble(b);
1797 			}
1798 		}
1799 		b->erased = 0;
1800 	}
1801 }
1802 
1803 
1804 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1805 Fish over bubble collision detection.  The specified fish is checked against
1806 all bubbles for overlap.  This way we don't try and erase bubbles that are
1807 already gone.
1808 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1809 void
collide_bubbles(f0,ofx,ofy)1810 collide_bubbles(f0, ofx, ofy)
1811 	fish *f0;
1812 	int ofx, ofy;
1813 {
1814 	int i, delta;
1815 	register fish *f = f0;
1816 	register bubble *b;
1817 
1818 	for (i = 0; i < blimit; i++)
1819 	{
1820 		b = &binfo[i];
1821 		delta = b->x - ofx;
1822 		if ((delta >= 0)&&(delta <= (rwidth[f->type] - b->s)))
1823 		{
1824 			delta = b->y - ofy;
1825 			if ((delta >= 0)&&(delta <= (rheight[f->type] - b->s)))
1826 			{
1827 				b->erased = 1;
1828 				continue;
1829 			}
1830 		}
1831 		delta = b->x - f->x;
1832 		if ((delta >= 0)&&(delta <= (rwidth[f->type] - b->s)))
1833 		{
1834 			delta = b->y - f->y;
1835 			if ((delta >= 0)&&(delta <= (rheight[f->type] - b->s)))
1836 			{
1837 				b->erased = 1;
1838 				continue;
1839 			}
1840 		}
1841 	}
1842 }
1843 
1844 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1845 Fish collision detection.  The specified fish is checked against all other
1846 fish for overlap.  The xt parameter specifies a x axis multiplier for overlap.
1847 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1848 int
collide_fish(f0,xt)1849 collide_fish(f0, xt)
1850 	fish *f0;
1851 	int xt;
1852 {
1853 	int i, j;
1854 	register fish *f = f0;
1855 
1856 	if (Overlap)
1857 	{
1858 		return(0);
1859 	}
1860 
1861 	for (i = 0; i < flimit; i++)
1862 	{
1863 		if (&finfo[i] != f)
1864 		{
1865 			j = finfo[i].y - f->y;
1866 			if ((j > -rheight[finfo[i].type]) &&
1867 			    (j < rheight[f->type]))
1868 			{
1869 				j = finfo[i].x - f->x;
1870 				if ((j > -xt * rwidth[finfo[i].type]) &&
1871 				    (j < xt * rwidth[f->type]))
1872 				{
1873 					return (1);
1874 				}
1875 			}
1876 		}
1877 	}
1878 	return (0);
1879 }
1880 
1881 
1882 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1883 Create a new fish.   Placement along the y axis is random, as is the side
1884 >from which the fish appears.  Direction is determined from side.  Increment
1885 is also random.
1886 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1887 void
new_fish(f0)1888 new_fish(f0)
1889 	fish *f0;
1890 {
1891 	int i, collide;
1892 	fish *f = f0;
1893 
1894 	f->type = rand() % NUM_FISH;
1895 	for (i = 0, collide = 1; (i < 16) && (collide); i++)
1896 	{
1897 		f->y = (height - rheight[f->type]) * (rand() / RAND_F_MAX);
1898 		if ((f->i = smooth * width /
1899 			(8.0 * (1.0 + rand() / RAND_F_1_8))) == 0)
1900 		{
1901 			f->i = 1;
1902 		}
1903 		if (rand() < RAND_I_1_2)
1904 		{
1905 			f->d = 1;
1906 			f->x = width;
1907 		}
1908 		else
1909 		{
1910 			f->d = 2;
1911 			f->x = -rwidth[f->type];
1912 		}
1913 		collide = collide_fish(f, 2);
1914 	}
1915 
1916 	if (!collide)
1917 	{
1918 		putfish(f);
1919 	}
1920 	else
1921 	{
1922 		f->d = 0;
1923 	}
1924 
1925 	f->frame = 0;
1926 }
1927 
1928 
1929 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1930 Move all the fish.  Clearing old fish is accomplished by masking only the
1931 exposed areas of the old fish.  Random up-down factor can move fish 1/4 a
1932 fish height in either direction, if no collisions are caused.
1933 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1934 void
move_fish()1935 move_fish()
1936 {
1937 	register int i, j, x, y, ofx, ofy, ofd, done;
1938 	register fish *f;
1939 
1940 	for (i = 0; i < flimit; i++)
1941 	{
1942 		f = &finfo[i];
1943 		if (f->d)
1944 		{
1945 			ofx = f->x;
1946 			ofy = f->y;
1947 			ofd = f->d;
1948 
1949 			if (f->d == 1)
1950 			{
1951 				done = ((f->x -= f->i) < -rwidth[f->type]);
1952 				x = f->x + rwidth[f->type];
1953 			}
1954 			else if (f->d == 2)
1955 			{
1956 				done = ((f->x += f->i) > width);
1957 				x = f->x - f->i;
1958 			}
1959 
1960 			if (!collide_fish(f, 1))
1961 			{
1962 				if (!done)
1963 				{
1964 					j = rand();
1965 					if (j < RAND_I_1_4)
1966 					{
1967 						y = f->i / 4;
1968 					}
1969 					else if (j > RAND_I_3_4)
1970 					{
1971 						y = f->i / -4;
1972 					}
1973 					else
1974 					{
1975 						y = 0;
1976 					}
1977 
1978 					if (y)
1979 					{
1980 						f->y += y;
1981 						if (collide_fish(f, 1))
1982 						{
1983 							f->y -= y;
1984 							y = 0;
1985 						}
1986 						else
1987 						{
1988 							if (y > 0)
1989 							{
1990 								j = f->y - y;
1991 							}
1992 							else
1993 							{
1994 								j = f->y +
1995 								   rheight
1996 								      [f->type];
1997 								y *= -1;
1998 							}
1999 						}
2000 					}
2001 				if (DoClipping)
2002 				{
2003 					movefish(f, ofx, ofy, ofd);
2004 				}
2005 				else
2006 				{
2007 					putfish(f);
2008 					XClearArea(Dpy, wid, x, ofy,
2009 						f->i, rheight[f->type], 0);
2010 					if (y)
2011 					{
2012 						XClearArea(Dpy, wid, ofx, j,
2013 							rwidth[f->type], y, 0);
2014 					}
2015 				}
2016 
2017 				}
2018 				else
2019 				{
2020 					XClearArea(Dpy, wid, x, f->y,
2021 						f->i, rheight[f->type], 0);
2022 					new_fish(f);
2023 				}
2024 			}
2025 			else
2026 			{
2027 				if ((f->d = 3 - f->d) == 1)
2028 				{
2029 					f->x = f->x - 2 * f->i;
2030 					x = f->x + rwidth[f->type];
2031 				}
2032 				else
2033 				{
2034 					f->x = f->x + 2 * f->i;
2035 					x = f->x - f->i;
2036 				}
2037 				if (DoClipping)
2038 				{
2039 					movefish(f, ofx, ofy, ofd);
2040 				}
2041 				else
2042 				{
2043 					putfish(f);
2044 					XClearArea(Dpy, wid, x, f->y,
2045 						f->i, rheight[f->type], 0);
2046 				}
2047 			}
2048 			if ((!DoClipping)||(picname[0] == '\0'))
2049 			{
2050 				collide_bubbles(f, ofx, ofy);
2051 			}
2052 		}
2053 		else
2054 		{
2055 			new_fish(f);
2056 		}
2057 	}
2058 }
2059 
2060 
2061 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2062 Higher-resolution sleep
2063 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2064 void
high_res_sleep(seconds)2065 high_res_sleep(seconds)
2066     double      seconds;
2067 {
2068 #ifndef __FreeBSD__
2069     int         fds = 0;
2070 #endif
2071     struct timeval timeout;
2072 #ifdef __FreeBSD__
2073     fd_set fds;
2074     FD_ZERO(&fds);
2075 #endif
2076 
2077     timeout.tv_sec = seconds;
2078     timeout.tv_usec = (seconds - timeout.tv_sec) * 1000000.0;
2079     select(0, &fds, &fds, &fds, &timeout);
2080 }
2081 
2082 
2083 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2084 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2085 void
main(argc,argv)2086 main(argc, argv)
2087     int         argc;
2088     char      **argv;
2089 {
2090     int         i;
2091     XEvent      ev;
2092 
2093     if ((Dpy = XOpenDisplay("")) == 0)
2094 	msgdie("XOpenDisplay failed");
2095     screen = DefaultScreen(Dpy);
2096 
2097     white = WhitePixel(Dpy, screen);
2098     black = BlackPixel(Dpy, screen);
2099     parse(argc, argv);
2100     initialize();
2101 
2102     srand((unsigned) getpid());
2103 
2104     Init_B = 1;
2105     for (i = 0; i < blimit; i++)
2106 	new_bubble(&binfo[i]);
2107     for (i = 0; i < flimit; i++)
2108     {
2109 	finfo[i].x = 0;
2110 	finfo[i].y = 0;
2111 	finfo[i].type = 0;
2112     }
2113     for (i = 0; i < flimit; i++)
2114 	new_fish(&finfo[i]);
2115     if (pmode)
2116 	XLowerWindow(Dpy, wid);
2117     else
2118 	XRaiseWindow(Dpy, wid);
2119     XFlush(Dpy);
2120 
2121     Init_B = 0;
2122 
2123     for (;;) {
2124 	if (XPending(Dpy))
2125 	    XNextEvent(Dpy, &ev);
2126 
2127 	high_res_sleep(rate);
2128 
2129 	move_fish();
2130 
2131 	step_bubbles();
2132 
2133 	if (pmode)
2134 	    XLowerWindow(Dpy, wid);
2135 	else
2136 	    XRaiseWindow(Dpy, wid);
2137     }
2138 }
2139 
2140