source: trunk/third/xscreensaver/hacks/starfish.c @ 20148

Revision 20148, 12.2 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski <jwz@jwz.org>
2 *
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
9 * implied warranty.
10 */
11
12#include <math.h>
13#include <time.h>
14#include <sys/time.h> /* for gettimeofday() */
15#include "screenhack.h"
16#include "spline.h"
17
18
19static Colormap cmap;
20static Bool cycle_p;
21static XColor *colors;
22static int ncolors;
23static int fg_index;
24static GC gc;
25
26#define SCALE        1000       /* fixed-point math, for sub-pixel motion */
27
28
29#define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
30#define RANDSIGN() ((random() & 1) ? 1 : -1)
31
32enum starfish_mode {
33  pulse,
34  zoom
35};
36 
37
38struct starfish {
39  enum starfish_mode mode;
40  Bool blob_p;
41  int skip;
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 */
47  double rot_max;
48  long min_r, max_r;    /* radius range */
49  int npoints;          /* control points */
50  long *r;              /* radii */
51  spline *spline;
52  XPoint *prev;
53  int n_prev;
54};
55
56static struct starfish *
57make_starfish (int maxx, int maxy, int size)
58{
59  struct starfish *s = (struct starfish *) calloc(1, sizeof(*s));
60  int i;
61  int mid;
62
63  s->blob_p = get_boolean_resource ("blob", "Blob");
64  s->elasticity = SCALE * get_float_resource ("thickness", "Thickness");
65
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);
69
70  s->rotv = get_float_resource ("rotation", "Rotation");
71  if (s->rotv == -1)
72    /* bell curve from 0-12 degrees, avg 6 */
73    s->rotv = frand(4) + frand(4) + frand(4);
74
75  s->rotv /= 360;  /* convert degrees to ratio */
76
77  if (s->blob_p)
78    {
79      s->elasticity *= 3;
80      s->rotv *= 3;
81    }
82
83  s->rot_max = s->rotv * 2;
84  s->rota = 0.0004 + frand(0.0002);
85
86
87  if (! (random() % 20))
88    size *= frand(0.35) + frand(0.35) + 0.3;
89
90  {
91    static char skips[] = { 2, 2, 2, 2,
92                            3, 3, 3,
93                            6, 6,
94                            12 };
95    s->skip = skips[random() % sizeof(skips)];
96  }
97
98  if (! (random() % (s->skip == 2 ? 3 : 12)))
99    s->mode = zoom;
100  else
101    s->mode = pulse;
102
103  maxx *= SCALE;
104  maxy *= SCALE;
105  size *= SCALE;
106
107  s->max_r = size;
108  s->min_r = 0;
109
110  if (s->min_r < (5*SCALE)) s->min_r = (5*SCALE);
111  mid = ((s->min_r + s->max_r) / 2);
112
113  s->x = maxx/2;
114  s->y = maxy/2;
115
116  s->th = frand(M_PI+M_PI) * RANDSIGN();
117
118  {
119    static char sizes[] = { 3, 3, 3, 3, 3,
120                            4, 4, 4, 4,
121                            5, 5, 5, 5, 5, 5,
122                            8, 8, 8,
123                            10,
124                            35 };
125    int nsizes = sizeof(sizes);
126    if (s->skip > 3)
127      nsizes -= 4;
128    s->npoints = s->skip * sizes[random() % nsizes];
129  }
130
131  s->spline = make_spline (s->npoints);
132  s->r = (long *) malloc (sizeof(*s->r) * s->npoints);
133
134  for (i = 0; i < s->npoints; i++)
135    s->r[i] = ((i % s->skip) == 0) ? 0 : size;
136
137  return s;
138}
139
140
141static void
142free_starfish (struct starfish *s)
143{
144  if (s->r) free (s->r);
145  if (s->prev) free (s->prev);
146  if (s->spline)
147    {
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);
151      free (s->spline);
152    }
153  free (s);
154}
155
156
157static void
158throb_starfish (struct starfish *s)
159{
160  int i;
161  double frac = ((M_PI+M_PI) / s->npoints);
162
163  for (i = 0; i < s->npoints; i++)
164    {
165      long r = s->r[i];
166      long ra = (r > 0 ? r : -r);
167      double th = (s->th > 0 ? s->th : -s->th);
168      long x, y;
169      long elasticity = s->elasticity;
170
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);
174
175      s->spline->control_x[i] = x / SCALE;
176      s->spline->control_y[i] = y / SCALE;
177
178      if (s->mode == zoom && ((i % s->skip) == 0))
179        continue;
180
181      /* Slow down near the end points: move fastest in the middle. */
182      {
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 */
187        elasticity *= ratio;
188      }
189
190
191      /* Increase/decrease radius by elasticity */
192      ra += (r >= 0 ? elasticity : -elasticity);
193      if ((i % s->skip) == 0)
194        ra += (elasticity / 2);
195
196      r = ra * (r >= 0 ? 1 : -1);
197
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))
201        r = -r;
202
203      s->r[i] = r;
204    }
205}
206
207
208static void
209spin_starfish (struct starfish *s)
210{
211  double th = s->th;
212  if (th < 0)
213    th = -(th + s->rotv);
214  else
215    th += s->rotv;
216
217  if (th > (M_PI+M_PI))
218    th -= (M_PI+M_PI);
219  else if (th < 0)
220    th += (M_PI+M_PI);
221
222  s->th = (s->th > 0 ? th : -th);
223
224  s->rotv += s->rota;
225
226  if (s->rotv > s->rot_max ||
227      s->rotv < -s->rot_max)
228    {
229      s->rota = -s->rota;
230    }
231  /* If it stops, start it going in the other direction. */
232  else if (s->rotv < 0)
233    {
234      if (random() & 1)
235        {
236          /* keep going in the same direction */
237          s->rotv = 0;
238          if (s->rota < 0)
239            s->rota = -s->rota;
240        }
241      else
242        {
243          /* reverse gears */
244          s->rotv = -s->rotv;
245          s->rota = -s->rota;
246          s->th = -s->th;
247        }
248    }
249
250
251  /* Alter direction of rotational acceleration randomly. */
252  if (! (random() % 120))
253    s->rota = -s->rota;
254
255  /* Change acceleration very occasionally. */
256  if (! (random() % 200))
257    {
258      if (random() & 1)
259        s->rota *= 1.2;
260      else
261        s->rota *= 0.8;
262    }
263}
264
265
266static void
267draw_starfish (Display *dpy, Drawable drawable, GC gc, struct starfish *s,
268           Bool fill_p)
269{
270  compute_closed_spline (s->spline);
271  if (s->prev)
272    {
273      XPoint *points = (XPoint *)
274        malloc (sizeof(XPoint) * (s->n_prev + s->spline->n_points + 2));
275      int i = s->spline->n_points;
276      int j = s->n_prev;
277      memcpy (points, s->spline->points, (i * sizeof(*points)));
278      memcpy (points+i, s->prev, (j * sizeof(*points)));
279
280      if (s->blob_p)
281        XClearWindow (dpy, drawable);
282      XFillPolygon (dpy, drawable, gc, points, i+j, Complex, CoordModeOrigin);
283      free (points);
284
285      free (s->prev);
286      s->prev = 0;
287    }
288
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;
292
293#ifdef DEBUG
294  if (s->blob_p)
295    {
296      int i;
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]);
300    }
301#endif
302}
303
304
305static struct starfish *
306make_window_starfish (Display *dpy, Window window)
307{
308  XWindowAttributes xgwa;
309  int size;
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;
314  else size *= 1.3;
315  return make_starfish (xgwa.width, xgwa.height, size);
316}
317
318
319static struct starfish *
320init_starfish (Display *dpy, Window window)
321{
322  static Bool first_time = True;
323  XGCValues gcv;
324  XWindowAttributes xgwa;
325  Bool blob_p = get_boolean_resource ("blob", "Blob");
326  XGetWindowAttributes (dpy, window, &xgwa);
327
328  cmap = xgwa.colormap;
329  cycle_p = get_boolean_resource ("cycle", "Cycle");
330
331  if (!first_time)
332    {
333      if (colors && ncolors)
334        free_colors (dpy, cmap, colors, ncolors);
335      if (colors)
336        free (colors);
337      colors = 0;
338    }
339
340  ncolors = get_integer_resource ("colors", "Colors");
341  if (ncolors < 2) ncolors = 2;
342  if (ncolors <= 2) mono_p = True;
343
344  if (mono_p)
345    colors = 0;
346  else
347    colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
348
349  if (mono_p || blob_p)
350    cycle_p = False;
351
352  if (mono_p)
353    ;
354  else if (random() % 3)
355    make_smooth_colormap (dpy, xgwa.visual, cmap, colors, &ncolors,
356                          True, &cycle_p, True);
357  else
358    make_uniform_colormap (dpy, xgwa.visual, cmap, colors, &ncolors,
359                           True, &cycle_p, True);
360
361  if (ncolors < 2) ncolors = 2;
362  if (ncolors <= 2) mono_p = True;
363
364  if (mono_p) cycle_p = False;
365
366  fg_index = 0;
367
368  if (!mono_p && !blob_p)
369    {
370      gcv.foreground = colors[fg_index].pixel;
371      XSetWindowBackground (dpy, window, gcv.foreground);
372    }
373
374  if (first_time)
375    {
376      XClearWindow (dpy, window);
377      first_time = False;
378    }
379
380  gcv.fill_rule = EvenOddRule;
381  gc = XCreateGC (dpy, window, GCForeground | GCFillRule, &gcv);
382
383  return make_window_starfish (dpy, window);
384}
385
386
387
388static void
389run_starfish (Display *dpy, Window window, struct starfish *s)
390{
391  throb_starfish (s);
392  spin_starfish (s);
393  draw_starfish (dpy, window, gc, s, False);
394
395  if (mono_p)
396    {
397      static Bool init = False;
398      static unsigned long black, white;
399      if (!init)
400        {
401          black = get_pixel_resource ("background", "Background", dpy, cmap);
402          white = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
403          init = True;
404          fg_index = white;
405          XSetForeground (dpy, gc, fg_index);
406        }
407      else if (!s->blob_p)
408        {
409          fg_index = (fg_index == black ? white : black);
410          XSetForeground (dpy, gc, fg_index);
411        }
412    }
413  else
414    {
415      fg_index = (fg_index + 1) % ncolors;
416      XSetForeground (dpy, gc, colors [fg_index].pixel);
417    }
418}
419
420
421
422
423char *progclass = "Starfish";
424
425char *defaults [] = {
426  ".background:         black",
427  ".foreground:         white",
428  "*delay:              10000",
429  "*cycleDelay:         100000",
430  "*thickness:          0",             /* pixels, 0 = random */
431  "*rotation:           -1",            /* degrees, -1 = "random" */
432  "*colors:             200",
433  "*cycle:              true",
434  "*duration:           30",
435  "*delay2:             5",
436  "*blob:               false",
437  0
438};
439
440XrmOptionDescRec 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" },
452  { 0, 0, 0, 0 }
453};
454
455void
456screenhack (Display *dpy, Window window)
457{
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);
465  time_t now;
466  int direction = (random() % 1) ? 1 : -1;
467
468  if (blob_p)
469    delay *= 3;
470
471  while (1)
472    {
473      run_starfish (dpy, window, s);
474      XSync (dpy, False);
475
476      screenhack_handle_events (dpy);
477      if (cycle_p && cycle_delay)
478        {
479          if (cycle_delay <= delay)
480            {
481              int i = 0;
482              while (i < delay)
483                {
484                  rotate_colors (dpy, cmap, colors, ncolors, direction);
485                  usleep(cycle_delay);
486                  i += cycle_delay;
487                }
488            }
489          else
490            {
491              static long tick = 0;
492              if (tick >= cycle_delay)
493                {
494                  rotate_colors (dpy, cmap, colors, ncolors, direction);
495                  tick = 0;
496                }
497              if (delay)
498                usleep(delay);
499              tick += delay;
500            }
501
502          if (! (random() % 1000))
503            direction = -direction;
504        }
505      else if (delay)
506        usleep (delay);
507
508      if (duration > 0)
509        {
510          now = time ((time_t) 0);
511          if (start + duration < now)
512            {
513              start = now;
514
515              free_starfish (s);
516
517              if (delay2 && !blob_p && cycle_p)
518                {
519                  int i = 0;
520                  while (i < delay2)
521                    {
522                      rotate_colors (dpy, cmap, colors, ncolors, direction);
523                      screenhack_handle_events (dpy);
524                      usleep(cycle_delay);
525                      i += cycle_delay;
526                    }
527                }
528
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);
533              else
534                s = make_window_starfish(dpy, window);
535            }
536        }
537    }
538}
Note: See TracBrowser for help on using the repository browser.