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