1 /* xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
14 #include <sys/time.h> /* for gettimeofday() */
15 #include "screenhack.h"
21 static XColor *colors;
26 #define SCALE 1000 /* fixed-point math, for sub-pixel motion */
29 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
30 #define RANDSIGN() ((random() & 1) ? 1 : -1)
39 enum starfish_mode mode;
42 long x, y; /* position of midpoint */
43 double th; /* angle of rotation */
44 double rotv; /* rotational velocity */
45 double rota; /* rotational acceleration */
46 long elasticity; /* how fast it deforms: radial velocity */
48 long min_r, max_r; /* radius range */
49 int npoints; /* control points */
56 static struct starfish *
57 make_starfish (int maxx, int maxy, int size)
59 struct starfish *s = (struct starfish *) calloc(1, sizeof(*s));
63 s->blob_p = get_boolean_resource ("blob", "Blob");
64 s->elasticity = SCALE * get_float_resource ("thickness", "Thickness");
66 if (s->elasticity == 0)
67 /* bell curve from 0-15, avg 7.5 */
68 s->elasticity = RAND(5*SCALE) + RAND(5*SCALE) + RAND(5*SCALE);
70 s->rotv = get_float_resource ("rotation", "Rotation");
72 /* bell curve from 0-12 degrees, avg 6 */
73 s->rotv = frand(4) + frand(4) + frand(4);
75 s->rotv /= 360; /* convert degrees to ratio */
83 s->rot_max = s->rotv * 2;
84 s->rota = 0.0004 + frand(0.0002);
87 if (! (random() % 20))
88 size *= frand(0.35) + frand(0.35) + 0.3;
91 static char skips[] = { 2, 2, 2, 2,
95 s->skip = skips[random() % sizeof(skips)];
98 if (! (random() % (s->skip == 2 ? 3 : 12)))
110 if (s->min_r < (5*SCALE)) s->min_r = (5*SCALE);
111 mid = ((s->min_r + s->max_r) / 2);
116 s->th = frand(M_PI+M_PI) * RANDSIGN();
119 static char sizes[] = { 3, 3, 3, 3, 3,
125 int nsizes = sizeof(sizes);
128 s->npoints = s->skip * sizes[random() % nsizes];
131 s->spline = make_spline (s->npoints);
132 s->r = (long *) malloc (sizeof(*s->r) * s->npoints);
134 for (i = 0; i < s->npoints; i++)
135 s->r[i] = ((i % s->skip) == 0) ? 0 : size;
142 free_starfish (struct starfish *s)
144 if (s->r) free (s->r);
145 if (s->prev) free (s->prev);
148 if (s->spline->control_x) free (s->spline->control_x);
149 if (s->spline->control_y) free (s->spline->control_y);
150 if (s->spline->points) free (s->spline->points);
158 throb_starfish (struct starfish *s)
161 double frac = ((M_PI+M_PI) / s->npoints);
163 for (i = 0; i < s->npoints; i++)
166 long ra = (r > 0 ? r : -r);
167 double th = (s->th > 0 ? s->th : -s->th);
169 long elasticity = s->elasticity;
171 /* place control points evenly around perimiter, shifted by theta */
172 x = s->x + ra * cos (i * frac + th);
173 y = s->y + ra * sin (i * frac + th);
175 s->spline->control_x[i] = x / SCALE;
176 s->spline->control_y[i] = y / SCALE;
178 if (s->mode == zoom && ((i % s->skip) == 0))
181 /* Slow down near the end points: move fastest in the middle. */
183 double ratio = (double)ra / (double)(s->max_r - s->min_r);
184 if (ratio > 0.5) ratio = 1-ratio; /* flip */
185 ratio *= 2; /* normalize */
186 ratio = (ratio * 0.9) + 0.1; /* fudge */
191 /* Increase/decrease radius by elasticity */
192 ra += (r >= 0 ? elasticity : -elasticity);
193 if ((i % s->skip) == 0)
194 ra += (elasticity / 2);
196 r = ra * (r >= 0 ? 1 : -1);
198 /* If we've reached the end (too long or too short) reverse direction. */
199 if ((ra > s->max_r && r >= 0) ||
200 (ra < s->min_r && r < 0))
209 spin_starfish (struct starfish *s)
213 th = -(th + s->rotv);
217 if (th > (M_PI+M_PI))
222 s->th = (s->th > 0 ? th : -th);
226 if (s->rotv > s->rot_max ||
227 s->rotv < -s->rot_max)
231 /* If it stops, start it going in the other direction. */
232 else if (s->rotv < 0)
236 /* keep going in the same direction */
251 /* Alter direction of rotational acceleration randomly. */
252 if (! (random() % 120))
255 /* Change acceleration very occasionally. */
256 if (! (random() % 200))
267 draw_starfish (Display *dpy, Drawable drawable, GC gc, struct starfish *s,
270 compute_closed_spline (s->spline);
273 XPoint *points = (XPoint *)
274 malloc (sizeof(XPoint) * (s->n_prev + s->spline->n_points + 2));
275 int i = s->spline->n_points;
277 memcpy (points, s->spline->points, (i * sizeof(*points)));
278 memcpy (points+i, s->prev, (j * sizeof(*points)));
281 XClearWindow (dpy, drawable);
282 XFillPolygon (dpy, drawable, gc, points, i+j, Complex, CoordModeOrigin);
289 s->prev = (XPoint *) malloc (s->spline->n_points * sizeof(XPoint));
290 memcpy (s->prev, s->spline->points, s->spline->n_points * sizeof(XPoint));
291 s->n_prev = s->spline->n_points;
297 for (i = 0; i < s->npoints; i++)
298 XDrawLine (dpy, drawable, gc, s->x/SCALE, s->y/SCALE,
299 s->spline->control_x[i], s->spline->control_y[i]);
305 static struct starfish *
306 make_window_starfish (Display *dpy, Window window)
308 XWindowAttributes xgwa;
310 Bool blob_p = get_boolean_resource ("blob", "Blob");
311 XGetWindowAttributes (dpy, window, &xgwa);
312 size = (xgwa.width < xgwa.height ? xgwa.width : xgwa.height);
313 if (blob_p) size /= 2;
315 return make_starfish (xgwa.width, xgwa.height, size);
319 static struct starfish *
320 init_starfish (Display *dpy, Window window)
322 static Bool first_time = True;
324 XWindowAttributes xgwa;
325 Bool blob_p = get_boolean_resource ("blob", "Blob");
326 XGetWindowAttributes (dpy, window, &xgwa);
328 cmap = xgwa.colormap;
329 cycle_p = get_boolean_resource ("cycle", "Cycle");
333 if (colors && ncolors)
334 free_colors (dpy, cmap, colors, ncolors);
340 ncolors = get_integer_resource ("colors", "Colors");
341 if (ncolors < 2) ncolors = 2;
342 if (ncolors <= 2) mono_p = True;
347 colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
349 if (mono_p || blob_p)
354 else if (random() % 3)
355 make_smooth_colormap (dpy, xgwa.visual, cmap, colors, &ncolors,
356 True, &cycle_p, True);
358 make_uniform_colormap (dpy, xgwa.visual, cmap, colors, &ncolors,
359 True, &cycle_p, True);
361 if (ncolors < 2) ncolors = 2;
362 if (ncolors <= 2) mono_p = True;
364 if (mono_p) cycle_p = False;
368 if (!mono_p && !blob_p)
370 gcv.foreground = colors[fg_index].pixel;
371 XSetWindowBackground (dpy, window, gcv.foreground);
376 XClearWindow (dpy, window);
380 gcv.fill_rule = EvenOddRule;
381 gc = XCreateGC (dpy, window, GCForeground | GCFillRule, &gcv);
383 return make_window_starfish (dpy, window);
389 run_starfish (Display *dpy, Window window, struct starfish *s)
393 draw_starfish (dpy, window, gc, s, False);
397 static Bool init = False;
398 static unsigned long black, white;
401 black = get_pixel_resource ("background", "Background", dpy, cmap);
402 white = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
405 XSetForeground (dpy, gc, fg_index);
409 fg_index = (fg_index == black ? white : black);
410 XSetForeground (dpy, gc, fg_index);
415 fg_index = (fg_index + 1) % ncolors;
416 XSetForeground (dpy, gc, colors [fg_index].pixel);
423 char *progclass = "Starfish";
425 char *defaults [] = {
426 ".background: black",
427 ".foreground: white",
429 "*cycleDelay: 100000",
430 "*thickness: 0", /* pixels, 0 = random */
431 "*rotation: -1", /* degrees, -1 = "random" */
440 XrmOptionDescRec options [] = {
441 { "-delay", ".delay", XrmoptionSepArg, 0 },
442 { "-delay2", ".delay2", XrmoptionSepArg, 0 },
443 { "-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0 },
444 { "-thickness", ".thickness", XrmoptionSepArg, 0 },
445 { "-rotation", ".rotation", XrmoptionSepArg, 0 },
446 { "-colors", ".colors", XrmoptionSepArg, 0 },
447 { "-cycle", ".cycle", XrmoptionNoArg, "True" },
448 { "-no-cycle", ".cycle", XrmoptionNoArg, "False" },
449 { "-duration", ".duration", XrmoptionSepArg, 0 },
450 { "-blob", ".blob", XrmoptionNoArg, "True" },
451 { "-no-blob", ".blob", XrmoptionNoArg, "False" },
456 screenhack (Display *dpy, Window window)
458 struct starfish *s = init_starfish (dpy, window);
459 int delay = get_integer_resource ("delay", "Delay");
460 int delay2 = get_integer_resource ("delay2", "Delay") * 1000000;
461 int cycle_delay = get_integer_resource ("cycleDelay", "Delay");
462 int duration = get_seconds_resource ("duration", "Seconds");
463 Bool blob_p = get_boolean_resource ("blob", "Blob");
464 time_t start = time ((time_t) 0);
466 int direction = (random() % 1) ? 1 : -1;
473 run_starfish (dpy, window, s);
476 screenhack_handle_events (dpy);
477 if (cycle_p && cycle_delay)
479 if (cycle_delay <= delay)
484 rotate_colors (dpy, cmap, colors, ncolors, direction);
491 static long tick = 0;
492 if (tick >= cycle_delay)
494 rotate_colors (dpy, cmap, colors, ncolors, direction);
502 if (! (random() % 1000))
503 direction = -direction;
510 now = time ((time_t) 0);
511 if (start + duration < now)
517 if (delay2 && !blob_p && cycle_p)
522 rotate_colors (dpy, cmap, colors, ncolors, direction);
523 screenhack_handle_events (dpy);
529 /* Every now and then, pick new colors; otherwise, just build
530 a new starfish with the current colors. */
531 if (! (random () % 10))
532 s = init_starfish (dpy, window);
534 s = make_window_starfish(dpy, window);