1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* starfish ---  */
3 
4 #if 0
5 static const char sccsid[] = "@(#)starfish.c	5.03 2003/05/01 xlockmore";
6 #endif
7 
8 /* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz AT jwz.org>
9 
10  * Permission to use, copy, modify, distribute, and sell this software and its
11  * documentation for any purpose is hereby granted without fee, provided that
12  * the above copyright notice appear in all copies and that both that
13  * copyright notice and this permission notice appear in supporting
14  * documentation.  No representations are made about the suitability of this
15  * software for any purpose.  It is provided "as is" without express or
16  * implied warranty.
17  *
18  * Revision History:
19  * 01-May-2003: Changed to work in a 64x64 window.
20  * 01-Nov-2000: Allocation checks
21  * 24-Feb-1998: xlockmore version by Jouk Jansen <joukj AT hrem.nano.tudelft.nl>
22  * 1997: original xscreensaver version by Jamie Zawinski <jwz AT jwz.org>
23  */
24 
25 #ifdef STANDALONE
26 #define MODE_starfish
27 #define DEFAULTS "*delay: 2000 \n" \
28 	"*cycles: 1000 \n" \
29 	"*ncolors: 200 \n" \
30 	"*fullrandom: True \n" \
31 	"*verbose: False \n" \
32 
33 # define free_starfish 0
34 # define reshape_starfish 0
35 # define starfish_handle_event 0
36 #include "xlockmore.h"		/* in xscreensaver distribution */
37 #else /* STANDALONE */
38 #include "xlock.h"		/* in xlockmore distribution */
39 #include "color.h"
40 #endif /* STANDALONE */
41 
42 #ifdef MODE_starfish
43 
44 #include "spline.h"
45 
46 #define DEF_ROTV  "-1"
47 #define DEF_THICKNESS  "-20"
48 #define DEF_CYCLE "True"
49 #define DEF_BLOB "False"
50 #define DEF_CYCLESPEED "3"
51 
52 static int  cyclespeed;
53 static float rotv, thickness;
54 
55 static Bool blob, cycle_p;
56 
57 static XrmOptionDescRec opts[] =
58 {
59 	{(char *) "-cyclespeed", (char *) "starfish.cyclespeed", XrmoptionSepArg, (caddr_t) NULL},
60 	{(char *) "-rotation", (char *) "starfish.rotation", XrmoptionSepArg, (caddr_t) NULL},
61 	{(char *) "-thickness", (char *) "starfish.thickness", XrmoptionSepArg, (caddr_t) NULL},
62 	{(char *) "-blob", (char *) ".starfish.blob", XrmoptionNoArg, (caddr_t) "on"},
63 	{(char *) "+blob", (char *) ".starfish.blob", XrmoptionNoArg, (caddr_t) "off"},
64 	{(char *) "-cycle", (char *) ".starfish.cycle", XrmoptionNoArg, (caddr_t) "on"},
65 	{(char *) "+cycle", (char *) ".starfish.cycle", XrmoptionNoArg, (caddr_t) "off"}
66 };
67 
68 static argtype vars[] =
69 {
70 	{(void *) & cyclespeed, (char *) "cyclespeed", (char *) "CycleSpeed", (char *) DEF_CYCLESPEED, t_Int},
71 	{(void *) & rotv, (char *) "rotation", (char *) "Rotation", (char *) DEF_ROTV, t_Float},
72 	{(void *) & thickness, (char *) "thickness", (char *) "Thickness", (char *) DEF_THICKNESS, t_Float},
73 	{(void *) & blob, (char *) "blob", (char *) "Blob", (char *) DEF_BLOB, t_Bool},
74 	{(void *) & cycle_p, (char *) "cycle", (char *) "Cycle", (char *) DEF_CYCLE, t_Bool}
75 };
76 
77 static OptionStruct desc[] =
78 {
79 	{(char *) "-cyclespeed num", (char *) "Cycling speed"},
80 	{(char *) "-rotation num", (char *) "Rotation velocity"},
81 	{(char *) "-thickness num", (char *) "Thickness"},
82 	{(char *) "-/+blob", (char *) "turn on/off blob"},
83 	{(char *) "-/+cycle", (char *) "turn on/off cycle"}
84 };
85 
86 ENTRYPOINT ModeSpecOpt starfish_opts =
87 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
88 
89 #ifdef USE_MODULES
90 ModStruct   starfish_description =
91 {"starfish", "init_starfish", "draw_starfish", "release_starfish",
92  "init_starfish", "init_starfish", (char *), &starfish_opts,
93  2000, 1, 1000, 1, 64, 1.0, "",
94  "Shows starfish", 0, NULL};
95 
96 #endif
97 
98 #define SCALE        1000	/* fixed-point math, for sub-pixel motion */
99 
100 #define RAND(n) ((long) ((LRAND() & 0x7fffffff) % ((long) (n))))
101 
102 #ifndef RANDSIGN
103 #define RANDSIGN() ((LRAND() & 1) ? 1 : -1)
104 #endif
105 
106 enum starfish_mode {
107 	pulse,
108 	zoom
109 };
110 
111 
112 typedef struct {
113 	enum starfish_mode mode;
114 	Bool        blob_p;
115 	int         skip;
116 	long        x, y;	/* position of midpoint */
117 	double      th;		/* angle of rotation */
118 	double      rotv;	/* rotational velocity */
119 	double      rota;	/* rotational acceleration */
120 	double      elasticity;	/* how fast it deforms: radial velocity */
121 	double      rot_max;
122 	long        min_r, max_r;	/* radius range */
123 	int         npoints;	/* control points */
124 	long       *r;		/* radii */
125 	spline     *splines;
126 	XPoint     *prev;
127 	int         n_prev;
128 	GC          gc;
129 	Colormap    cmap;
130 	XColor     *colors;
131 	int         ncolors;
132 	Bool        cycle_p, mono_p, no_colors;
133 	unsigned long fg_index;
134 	int         size, winwidth, winheight, stage, counter;
135 	float       thickness;
136 	unsigned long blackpixel, whitepixel, fg, bg;
137 	int         direction;
138 } starfishstruct;
139 
140 static starfishstruct *starfishes = (starfishstruct *) NULL;
141 
142 static void
free_starfish_screen(ModeInfo * mi,starfishstruct * sp)143 free_starfish_screen(ModeInfo *mi, starfishstruct * sp)
144 {
145 	Display *display = MI_DISPLAY(mi);
146 
147 	if (sp == NULL) {
148 		return;
149 	}
150 	if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
151 		MI_WHITE_PIXEL(mi) = sp->whitepixel;
152 		MI_BLACK_PIXEL(mi) = sp->blackpixel;
153 #ifndef STANDALONE
154 		MI_FG_PIXEL(mi) = sp->fg;
155 		MI_BG_PIXEL(mi) = sp->bg;
156 #endif
157 		if (sp->colors != NULL) {
158 #ifdef STANDALONE
159 			Screen *screen = MI_SCREENPTR(mi);
160 #endif
161 			if (sp->ncolors && !sp->no_colors)
162 				free_colors(
163 #ifdef STANDALONE
164 					screen,
165 #else
166 					display,
167 #endif
168 					sp->cmap, sp->colors, sp->ncolors);
169 			free(sp->colors);
170 			sp->colors = (XColor *) NULL;
171 		}
172 		if (sp->cmap != None) {
173 			XFreeColormap(display, sp->cmap);
174 			sp->cmap = None;
175 		}
176 	}
177 	if (sp->gc != None) {
178 		XFreeGC(display, sp->gc);
179 		sp->gc = None;
180 	}
181 	if (sp->splines != NULL) {
182 		free_spline(sp->splines);
183 		sp->splines = (spline *) NULL;
184 	}
185 	if (sp->r != NULL) {
186 		free(sp->r);
187 		sp->r = (long *) NULL;
188 	}
189 	if (sp->prev != NULL) {
190 		free(sp->prev);
191 		sp->prev = (XPoint *) NULL;
192 	}
193 	sp = NULL;
194 }
195 
196 static void
make_starfish(ModeInfo * mi)197 make_starfish(ModeInfo * mi)
198 {
199 	starfishstruct *sp = &starfishes[MI_SCREEN(mi)];
200 	int         i;
201 
202 	sp->elasticity = SCALE * sp->thickness;
203 
204 	if (sp->elasticity == 0.0)
205 		/* bell curve from 0-15, avg 7.5 */
206 		sp->elasticity = RAND(5 * SCALE) + RAND(5 * SCALE) + RAND(5 * SCALE);
207 
208 	if (sp->rotv == -1)
209 		/* bell curve from 0-12 degrees, avg 6 */
210 		sp->rotv = (double) 4.0 *((double) LRAND() / (double) MAXRAND +
211 			                (double) LRAND() / (double) MAXRAND +
212 			                (double) LRAND() / (double) MAXRAND);
213 
214 	sp->rotv /= 360;	/* convert degrees to ratio */
215 
216 	if (sp->blob_p) {
217 		sp->elasticity *= 3.0;
218 		sp->rotv *= 3;
219 	}
220 	sp->rot_max = sp->rotv * 2;
221 	sp->rota = 0.0004 + 0.0002 * (double) LRAND() / (double) MAXRAND;
222 
223 
224 	if (NRAND(20) == 5)
225 		sp->size = (int) (sp->size *
226 			(0.35 * ((double) LRAND() / (double) MAXRAND +
227 				 (double) LRAND() / (double) MAXRAND) + 0.3));
228 
229 	{
230 		static char skips[] =
231 		{2, 2, 2, 2, 3, 3, 3, 6, 6, 12};
232 
233 		sp->skip = skips[LRAND() % sizeof (skips)];
234 	}
235 
236 	if (!(LRAND() % (sp->skip == 2 ? 3 : 12)))
237 		sp->mode = zoom;
238 	else
239 		sp->mode = pulse;
240 
241 	sp->winwidth *= SCALE;
242 	sp->winheight *= SCALE;
243 	sp->size *= SCALE;
244 
245 	sp->max_r = sp->size;
246 	sp->min_r = SCALE;
247 	/* sp->min_r = 5 * SCALE; */
248 
249 	/* mid = ((sp->min_r + sp->max_r) / 2); */
250 
251 	sp->x = sp->winwidth / 2;
252 	sp->y = sp->winheight / 2;
253 
254 	sp->th = 2.0 * M_PI * ((double) LRAND() / (double) MAXRAND) * RANDSIGN();
255 
256 	{
257 		static char sizes[] =
258 		{3, 3, 3, 3, 3,
259 		 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
260 		 8, 8, 8, 10, 35};
261 		int         nsizes = sizeof (sizes);
262 
263 		if (sp->skip > 3)
264 			nsizes -= 4;
265 		sp->npoints = sp->skip * sizes[LRAND() % nsizes];
266 	}
267 
268 	if (sp->splines)
269 		free_spline(sp->splines);
270 	sp->splines = make_spline(sp->npoints);
271 
272 	if (sp->r != NULL)
273 		free(sp->r);
274 	if ((sp->r = (long *) malloc(sizeof (*sp->r) * sp->npoints)) == NULL) {
275 		free_starfish_screen(mi, sp);
276 		return;
277 	}
278 
279 	for (i = 0; i < sp->npoints; i++)
280 		sp->r[i] = ((i % sp->skip) == 0) ? 0 : sp->size;
281 }
282 
283 static void
throb_starfish(starfishstruct * sp)284 throb_starfish(starfishstruct * sp)
285 {
286 	int         i;
287 	double      frac = ((M_PI + M_PI) / sp->npoints);
288 
289 	for (i = 0; i < sp->npoints; i++) {
290 		double      r = sp->r[i];
291 		double      ra = (r > 0.0 ? r : -r);
292 		double      th = (sp->th > 0 ? sp->th : -sp->th);
293 		double      x, y;
294 		double      elasticity = sp->elasticity;
295 
296 		/* place control points evenly around perimiter, shifted by theta */
297 		x = sp->x + (ra * cos(i * frac + th));
298 		y = sp->y + (ra * sin(i * frac + th));
299 
300 		sp->splines->control_x[i] = x / SCALE;
301 		sp->splines->control_y[i] = y / SCALE;
302 
303 		if (sp->mode == zoom && ((i % sp->skip) == 0))
304 			continue;
305 
306 		/* Slow down near the end points: move fastest in the middle. */
307 		{
308 			double      ratio = ra / (double) (sp->max_r - sp->min_r);
309 
310 			if (ratio > 0.5)
311 				ratio = 1 - ratio;	/* flip */
312 			ratio *= 2.0;	/* normalize */
313 			ratio = (ratio * 0.9) + 0.1;	/* fudge */
314 			elasticity = elasticity * ratio;
315 		}
316 
317 
318 		/* Increase/decrease radius by elasticity */
319 		ra += (r >= 0.0 ? elasticity : -elasticity);
320 		if ((i % sp->skip) == 0)
321 			ra += (elasticity / 2.0);
322 
323 		r = ra * (r >= 0.0 ? 1.0 : -1.0);
324 
325 		/* If we've reached the end (too long or too short) reverse direction. */
326 		if ((ra > sp->max_r && r >= 0.0) ||
327 		    (ra < sp->min_r && r < 0.0))
328 			r = -r;
329 
330 		sp->r[i] = (long) r;
331 	}
332 }
333 
334 
335 static void
spin_starfish(starfishstruct * sp)336 spin_starfish(starfishstruct * sp)
337 {
338 	double      th = sp->th;
339 
340 	if (th < 0)
341 		th = -(th + sp->rotv);
342 	else
343 		th += sp->rotv;
344 
345 	if (th > (M_PI + M_PI))
346 		th -= (M_PI + M_PI);
347 	else if (th < 0)
348 		th += (M_PI + M_PI);
349 
350 	sp->th = (sp->th > 0 ? th : -th);
351 
352 	sp->rotv += sp->rota;
353 
354 	if (sp->rotv > sp->rot_max ||
355 	    sp->rotv < -sp->rot_max) {
356 		sp->rota = -sp->rota;
357 	}
358 	/* If it stops, start it going in the other direction. */
359 	else if (sp->rotv < 0) {
360 		if (LRAND() & 1) {
361 			/* keep going in the same direction */
362 			sp->rotv = 0;
363 			if (sp->rota < 0)
364 				sp->rota = -sp->rota;
365 		} else {
366 			/* reverse gears */
367 			sp->rotv = -sp->rotv;
368 			sp->rota = -sp->rota;
369 			sp->th = -sp->th;
370 		}
371 	}
372 	/* Alter direction of rotational acceleration randomly. */
373 	if (!(LRAND() % 120))
374 		sp->rota = -sp->rota;
375 
376 	/* Change acceleration very occasionally. */
377 	if (!(LRAND() % 200)) {
378 		if (LRAND() & 1)
379 			sp->rota *= 1.2;
380 		else
381 			sp->rota *= 0.8;
382 	}
383 }
384 
385 
386 static Bool
draw1_starfish(ModeInfo * mi,GC gc,starfishstruct * sp)387 draw1_starfish(ModeInfo *mi, GC gc, starfishstruct * sp)
388 {
389 	Display    *display = MI_DISPLAY(mi);
390 	Window      window = MI_WINDOW(mi);
391 
392 	compute_closed_spline(sp->splines);
393 	if (sp->prev) {
394 		XPoint     *points;
395 		int         i = sp->splines->n_points;
396 		int         j = sp->n_prev;
397 
398 		if ((points = (XPoint *) malloc(sizeof (XPoint) *
399 				(sp->n_prev + sp->splines->n_points + 2))) == NULL) {
400 			free_starfish_screen(mi, sp);
401 			return False;
402 		}
403 		(void) memcpy((char *) points, (char *) sp->splines->points,
404 			      (i * sizeof (*points)));
405 		(void) memcpy((char *) (points + i), (char *) sp->prev,
406 			      (j * sizeof (*points)));
407 
408 		if (sp->blob_p)
409 			XClearWindow(display, window);
410 		XFillPolygon(display, window, gc, points, i + j,
411 			     Complex, CoordModeOrigin);
412 		free(points);
413 
414 		free(sp->prev);
415 		sp->prev = (XPoint *) NULL;
416 	}
417 	if ((sp->prev = (XPoint *) malloc(sp->splines->n_points *
418 			sizeof (XPoint))) == NULL) {
419 		free_starfish_screen(mi, sp);
420 		return False;
421 	}
422 	(void) memcpy((char *) sp->prev, (char *) sp->splines->points,
423 		      sp->splines->n_points * sizeof (XPoint));
424 	sp->n_prev = sp->splines->n_points;
425 
426 #ifdef DEBUG
427 	if (sp->blob_p) {
428 		int         i;
429 
430 		for (i = 0; i < sp->npoints; i++)
431 			XDrawLine(display, window, gc, sp->x / SCALE, sp->y / SCALE,
432 			sp->splines->control_x[i], sp->splines->control_y[i]);
433 	}
434 #endif
435 	return True;
436 }
437 
438 #ifndef STANDALONE
439 extern char *background;
440 extern char *foreground;
441 #endif
442 
443 ENTRYPOINT void
init_starfish(ModeInfo * mi)444 init_starfish(ModeInfo * mi)
445 {
446 	Display    *display = MI_DISPLAY(mi);
447 	Window      window = MI_WINDOW(mi);
448 	XGCValues   gcv;
449 	starfishstruct *sp;
450 
451 /* initialize */
452 	MI_INIT(mi, starfishes);
453 	sp = &starfishes[MI_SCREEN(mi)];
454 
455 	if (MI_IS_FULLRANDOM(mi)) {
456 		if (NRAND(10) == 9)
457 			sp->blob_p = True;
458 		else
459 			sp->blob_p = False;
460 		if (NRAND(8) == 7)
461 			sp->cycle_p = False;
462 		else
463 			sp->cycle_p = True;
464 	} else {
465 		sp->blob_p = blob;
466 		sp->cycle_p = cycle_p;
467 	}
468 	sp->rotv = (double) rotv;
469 	sp->direction = (LRAND() & 1) ? 1 : -1;
470 	if (thickness < 0)
471 		sp->thickness = -thickness * (float) LRAND() / (float) MAXRAND;
472 	else
473 		sp->thickness = thickness;
474 	if (sp->blob_p)
475 		sp->fg_index = MI_BLACK_PIXEL(mi);
476 	else
477 		sp->fg_index = MI_WHITE_PIXEL(mi);
478 
479 	if (sp->gc == None) {
480 		if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
481 			XColor      color;
482 
483 #ifndef STANDALONE
484 			sp->fg = MI_FG_PIXEL(mi);
485 			sp->bg = MI_BG_PIXEL(mi);
486 #endif
487 			sp->blackpixel = MI_BLACK_PIXEL(mi);
488 			sp->whitepixel = MI_WHITE_PIXEL(mi);
489 			if ((sp->cmap = XCreateColormap(display, window,
490 					MI_VISUAL(mi), AllocNone)) == None) {
491 				free_starfish_screen(mi, sp);
492 				return;
493 			}
494 			XSetWindowColormap(display, window, sp->cmap);
495 			(void) XParseColor(display, sp->cmap, "black", &color);
496 			(void) XAllocColor(display, sp->cmap, &color);
497 			MI_BLACK_PIXEL(mi) = color.pixel;
498 			(void) XParseColor(display, sp->cmap, "white", &color);
499 			(void) XAllocColor(display, sp->cmap, &color);
500 			MI_WHITE_PIXEL(mi) = color.pixel;
501 #ifndef STANDALONE
502 			(void) XParseColor(display, sp->cmap, background, &color);
503 			(void) XAllocColor(display, sp->cmap, &color);
504 			MI_BG_PIXEL(mi) = color.pixel;
505 			(void) XParseColor(display, sp->cmap, foreground, &color);
506 			(void) XAllocColor(display, sp->cmap, &color);
507 			MI_FG_PIXEL(mi) = color.pixel;
508 #endif
509 			sp->colors = (XColor *) NULL;
510 			sp->ncolors = 0;
511 		}
512 		gcv.foreground = sp->fg_index;
513 		gcv.fill_rule = EvenOddRule;
514 		if ((sp->gc = XCreateGC(display, window,
515 				GCForeground | GCFillRule, &gcv)) == None) {
516 			free_starfish_screen(mi, sp);
517 			return;
518 		}
519 	}
520 	if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
521 #ifdef STANDALONE
522 		Screen *screen = MI_SCREENPTR(mi);
523 #endif
524 /* Set up colour map */
525 		if (sp->colors != NULL) {
526 			if (sp->ncolors && !sp->no_colors)
527 				free_colors(
528 #ifdef STANDALONE
529 					screen,
530 #else
531 					display,
532 #endif
533 					sp->cmap, sp->colors, sp->ncolors);
534 			free(sp->colors);
535 			sp->colors = (XColor *) NULL;
536 		}
537 		sp->ncolors = MI_NCOLORS(mi);
538 		if (sp->ncolors < 2)
539 			sp->ncolors = 2;
540 		if (sp->ncolors <= 2)
541 			sp->mono_p = True;
542 		else
543 			sp->mono_p = False;
544 
545 		if (sp->mono_p)
546 			sp->colors = (XColor *) NULL;
547 		else
548 			if ((sp->colors = (XColor *) malloc(sizeof (*sp->colors) *
549 					(sp->ncolors + 1))) == NULL) {
550 			free_starfish_screen(mi, sp);
551 			return;
552 		}
553 
554 		if (sp->mono_p || sp->blob_p)
555 			sp->cycle_p = False;
556 		if (!sp->mono_p) {
557 			if (LRAND() % 3)
558 				make_smooth_colormap(
559 #ifdef STANDALONE
560 					screen, MI_VISUAL(mi),
561 					sp->cmap, sp->colors, &sp->ncolors,
562 					True, &sp->cycle_p, True
563 #else
564 					mi,
565 					sp->cmap, sp->colors, &sp->ncolors,
566 					True, &sp->cycle_p
567 #endif
568 					);
569 			else
570 				make_uniform_colormap(
571 #ifdef STANDALONE
572 					screen, MI_VISUAL(mi),
573 					sp->cmap, sp->colors, &sp->ncolors,
574 					True, &sp->cycle_p, True
575 #else
576 					mi,
577 					sp->cmap, sp->colors, &sp->ncolors,
578 					True, &sp->cycle_p
579 #endif
580 					);
581 		}
582 		XInstallColormap(display, sp->cmap);
583 		if (sp->ncolors < 2) {
584 			sp->ncolors = 2;
585 			sp->no_colors = True;
586 		} else
587 			sp->no_colors = False;
588 		if (sp->ncolors <= 2)
589 			sp->mono_p = True;
590 
591 		if (sp->mono_p)
592 			sp->cycle_p = False;
593 
594 		sp->fg_index = 0;
595 
596 /*  if (!sp->mono_p && !sp->blob_p)
597    {
598    gcv.foreground = sp->colors[sp->fg_index].pixel;
599    XSetWindowBackground (display, window, gcv.foreground);
600    } */
601 
602 	} else
603 		sp->fg_index = NRAND(MI_NPIXELS(mi));
604 
605 	sp->size = (MI_WIDTH(mi) < MI_HEIGHT(mi) ? MI_WIDTH(mi) : MI_HEIGHT(mi));
606 	if (sp->blob_p)
607 		sp->size /= 2;
608 	else
609 		sp->size = (int) (sp->size * 1.3);
610 	sp->winwidth = MI_WIDTH(mi);
611 	sp->winheight = MI_HEIGHT(mi);
612 	MI_CLEARWINDOW(mi);
613 	if (sp->prev != NULL) {
614 		free(sp->prev);
615 		sp->prev = (XPoint *) NULL;
616 	}
617 	sp->stage = 0;
618 	sp->counter = 0;
619 	make_starfish(mi);
620 }
621 
622 static Bool
run_starfish(ModeInfo * mi)623 run_starfish(ModeInfo * mi)
624 {
625 	Display    *display = MI_DISPLAY(mi);
626 	starfishstruct *sp = &starfishes[MI_SCREEN(mi)];
627 
628 	throb_starfish(sp);
629 	spin_starfish(sp);
630 	if (!draw1_starfish(mi, sp->gc, sp))
631 		return False;
632 
633 	if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
634 		if (sp->mono_p) {
635 			if (!sp->blob_p) {
636 				sp->fg_index = (sp->fg_index == MI_BLACK_PIXEL(mi) ?
637 				    MI_BLACK_PIXEL(mi) : MI_BLACK_PIXEL(mi));
638 			}
639 			XSetForeground(display, sp->gc, sp->fg_index);
640 		} else {
641 			sp->fg_index = (sp->fg_index + 1) % sp->ncolors;
642 			XSetForeground(display, sp->gc, sp->colors[sp->fg_index].pixel);
643 		}
644 	} else {
645 		if (MI_NPIXELS(mi) > 2)
646 			XSetForeground(display, sp->gc, MI_PIXEL(mi, sp->fg_index));
647 		else if (sp->fg_index)
648 			XSetForeground(display, sp->gc, MI_BLACK_PIXEL(mi));
649 		else
650 			XSetForeground(display, sp->gc, MI_WHITE_PIXEL(mi));
651 		if (++sp->fg_index >= (unsigned int) MI_NPIXELS(mi))
652 			sp->fg_index = 0;
653 	}
654 	return True;
655 }
656 
657 ENTRYPOINT void
draw_starfish(ModeInfo * mi)658 draw_starfish(ModeInfo * mi)
659 {
660 	starfishstruct *sp;
661 
662 	if (starfishes == NULL)
663 		return;
664 	sp = &starfishes[MI_SCREEN(mi)];
665 	if (sp->r == NULL)
666 		return;
667 
668 	if (sp->no_colors) {
669 		free_starfish_screen(mi, sp);
670 		init_starfish(mi);
671 		return;
672 	}
673 	MI_IS_DRAWN(mi) = True;
674 
675 	if (!sp->stage) {
676 		if (!run_starfish(mi))
677 			return;
678 	} else if (sp->cycle_p) {
679 		rotate_colors(
680 #ifdef STANDALONE
681 			MI_SCREENPTR(mi),
682 #else
683 			MI_DISPLAY(mi),
684 #endif
685 			sp->cmap, sp->colors, sp->ncolors, sp->direction);
686 
687 		if (!NRAND(512))
688 			sp->direction = -sp->direction;
689 	}
690 	sp->stage++;
691 
692 	if (sp->stage > (2 * sp->blob_p + 1) * cyclespeed) {
693 		sp->stage = 0;
694 		sp->counter++;
695 	}
696 	if (sp->counter > MI_CYCLES(mi)) {
697 		/* Every now and then, restart the mode */
698 		init_starfish(mi);
699 	}
700 }
701 
702 ENTRYPOINT void
release_starfish(ModeInfo * mi)703 release_starfish(ModeInfo * mi)
704 {
705 	if (starfishes != NULL) {
706 		int         screen;
707 
708 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
709 			free_starfish_screen(mi, &starfishes[screen]);
710 		free(starfishes);
711 		starfishes = (starfishstruct *) NULL;
712 	}
713 }
714 
715 XSCREENSAVER_MODULE ("Starfish", starfish)
716 
717 #endif /* MODE_starfish */
718