ftp://ftp.sunet.se/pub/vendor/sco/skunkware/osr5/x11/savers/xscreensaver/xscreensaver...
[xscreensaver] / hacks / goop.c
diff --git a/hacks/goop.c b/hacks/goop.c
deleted file mode 100644 (file)
index ef0e8e6..0000000
+++ /dev/null
@@ -1,535 +0,0 @@
-/* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@jwz.org>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation.  No representations are made about the suitability of this
- * software for any purpose.  It is provided "as is" without express or 
- * implied warranty.
- */
-
-#include <math.h>
-#include "screenhack.h"
-#include "spline.h"
-#include "alpha.h"
-
-
-/* This is pretty compute-intensive, probably due to the large number of
-   polygon fills.  I tried introducing a scaling factor to make the spline
-   code emit fewer line segments, but that made the edges very rough.
-   However, tuning *maxVelocity, *elasticity and *delay can result in much
-   smoother looking animation.  I tuned these for a 1280x1024 Indy display,
-   but I don't know whether these values will be reasonable for a slower
-   machine...
-
-   The more planes the better -- SGIs have a 12-bit pseudocolor display
-   (4096 colormap cells) which is mostly useless, except for this program,
-   where it means you can have 11 or 12 mutually-transparent objects instead
-   of only 7 or 8.  But, if you are using the 12-bit visual, you should crank
-   down the velocity and elasticity, or server slowness will cause the
-   animation to look jerky (yes, it's sad but true, SGI's X server is
-   perceptibly slower when using plane masks on a 12-bit visual than on an
-   8-bit visual.)  Using -max-velocity 0.5 -elasticity 0.9 seems to work ok
-   on my Indy R5k with visual 0x27 and the bottom-of-the-line 24-bit graphics
-   board.
-
-   It might look better if each blob had an outline, which was a *slightly*
-   darker color than the center, to give them a bit more definition -- but
-   that would mean using two planes per blob.  (Or maybe allocating the
-   outline colors outside of the plane-space?  Then the outlines wouldn't be
-   transparent, but maybe that wouldn't be so noticeable?)
-
-   Oh, for an alpha channel... maybe I should rewrite this in GL.  Then the
-   blobs could have thickness, and curved edges with specular reflections...
- */
-
-
-#define SCALE       10000  /* fixed-point math, for sub-pixel motion */
-#define DEF_COUNT   12    /* When planes and count are 0, how many blobs. */
-
-
-#define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
-#define RANDSIGN() ((random() & 1) ? 1 : -1)
-
-struct blob {
-  long x, y;           /* position of midpoint */
-  long dx, dy;         /* velocity and direction */
-  double torque;       /* rotational speed */
-  double th;           /* angle of rotation */
-  long elasticity;     /* how fast they deform */
-  long max_velocity;   /* speed limit */
-  long min_r, max_r;   /* radius range */
-  int npoints;         /* control points */
-  long *r;             /* radii */
-  spline *spline;
-};
-
-struct layer {
-  int nblobs;
-  struct blob **blobs;
-  Pixmap pixmap;
-  unsigned long pixel;
-  GC gc;
-};
-
-enum goop_mode {
-  transparent,
-  opaque,
-  xor,
-  outline
-};
-
-struct goop {
-  enum goop_mode mode;
-  int width, height;
-  int nlayers;
-  struct layer **layers;
-  unsigned long background;
-  Pixmap pixmap;
-  GC pixmap_gc;
-  GC window_gc;
-};
-
-
-static struct blob *
-make_blob (int maxx, int maxy, int size)
-{
-  struct blob *b = (struct blob *) calloc(1, sizeof(*b));
-  int i;
-  int mid;
-
-  maxx *= SCALE;
-  maxy *= SCALE;
-  size *= SCALE;
-
-  b->max_r = size/2;
-  b->min_r = size/10;
-
-  if (b->min_r < (5*SCALE)) b->min_r = (5*SCALE);
-  mid = ((b->min_r + b->max_r) / 2);
-
-  b->torque       = get_float_resource ("torque", "Torque");
-  b->elasticity   = SCALE * get_float_resource ("elasticity", "Elasticity");
-  b->max_velocity = SCALE * get_float_resource ("maxVelocity", "MaxVelocity");
-
-  b->x = RAND(maxx);
-  b->y = RAND(maxy);
-
-  b->dx = RAND(b->max_velocity) * RANDSIGN();
-  b->dy = RAND(b->max_velocity) * RANDSIGN();
-  b->th = frand(M_PI+M_PI) * RANDSIGN();
-  b->npoints = (random() % 5) + 5;
-
-  b->spline = make_spline (b->npoints);
-  b->r = (long *) malloc (sizeof(*b->r) * b->npoints);
-  for (i = 0; i < b->npoints; i++)
-    b->r[i] = ((random() % mid) + (mid/2)) * RANDSIGN();
-  return b;
-}
-
-static void 
-throb_blob (struct blob *b)
-{
-  int i;
-  double frac = ((M_PI+M_PI) / b->npoints);
-
-  for (i = 0; i < b->npoints; i++)
-    {
-      long r = b->r[i];
-      long ra = (r > 0 ? r : -r);
-      double th = (b->th > 0 ? b->th : -b->th);
-      long x, y;
-
-      /* place control points evenly around perimiter, shifted by theta */
-      x = b->x + ra * cos (i * frac + th);
-      y = b->y + ra * sin (i * frac + th);
-
-      b->spline->control_x[i] = x / SCALE;
-      b->spline->control_y[i] = y / SCALE;
-
-      /* alter the radius by a random amount, in the direction in which
-        it had been going (the sign of the radius indicates direction.) */
-      ra += (RAND(b->elasticity) * (r > 0 ? 1 : -1));
-      r = ra * (r >= 0 ? 1 : -1);
-
-      /* If we've reached the end (too long or too short) reverse direction. */
-      if ((ra > b->max_r && r >= 0) ||
-         (ra < b->min_r && r < 0))
-       r = -r;
-      /* And reverse direction in mid-course once every 50 times. */
-      else if (! (random() % 50))
-       r = -r;
-
-      b->r[i] = r;
-    }
-}
-
-static void
-move_blob (struct blob *b, int maxx, int maxy)
-{
-  maxx *= SCALE;
-  maxy *= SCALE;
-
-  b->x += b->dx;
-  b->y += b->dy;
-
-  /* If we've reached the edge of the box, reverse direction. */
-  if ((b->x > maxx && b->dx >= 0) ||
-      (b->x < 0    && b->dx < 0))
-    {
-      b->dx = -b->dx;
-    }
-  if ((b->y > maxy && b->dy >= 0) ||
-      (b->y < 0    && b->dy < 0))
-    {
-      b->dy = -b->dy;
-    }
-
-  /* Alter velocity randomly. */
-  if (! (random() % 10))
-    {
-      b->dx += (RAND(b->max_velocity/2) * RANDSIGN());
-      b->dy += (RAND(b->max_velocity/2) * RANDSIGN());
-
-      /* Throttle velocity */
-      if (b->dx > b->max_velocity || b->dx < -b->max_velocity)
-       b->dx /= 2;
-      if (b->dy > b->max_velocity || b->dy < -b->max_velocity)
-       b->dy /= 2;
-    }
-
-  {
-    double th = b->th;
-    double d = (b->torque == 0 ? 0 : frand(b->torque));
-    if (th < 0)
-      th = -(th + d);
-    else
-      th += d;
-
-    if (th > (M_PI+M_PI))
-      th -= (M_PI+M_PI);
-    else if (th < 0)
-      th += (M_PI+M_PI);
-
-    b->th = (b->th > 0 ? th : -th);
-  }
-
-  /* Alter direction of rotation randomly. */
-  if (! (random() % 100))
-    b->th *= -1;
-}
-
-static void
-draw_blob (Display *dpy, Drawable drawable, GC gc, struct blob *b,
-          Bool fill_p)
-{
-  compute_closed_spline (b->spline);
-#ifdef DEBUG
-  {
-    int i;
-    for (i = 0; i < b->npoints; i++)
-      XDrawLine (dpy, drawable, gc, b->x/SCALE, b->y/SCALE,
-                b->spline->control_x[i], b->spline->control_y[i]);
-  }
-#else
-  if (fill_p)
-    XFillPolygon (dpy, drawable, gc, b->spline->points, b->spline->n_points,
-                 Nonconvex, CoordModeOrigin);
-  else
-#endif
-    XDrawLines (dpy, drawable, gc, b->spline->points, b->spline->n_points,
-               CoordModeOrigin);
-}
-
-
-static struct layer *
-make_layer (Display *dpy, Window window, int width, int height, int nblobs)
-{
-  int i;
-  struct layer *layer = (struct layer *) calloc(1, sizeof(*layer));
-  int blob_min, blob_max;
-  XGCValues gcv;
-  layer->nblobs = nblobs;
-
-  layer->blobs = (struct blob **) malloc(sizeof(*layer->blobs)*layer->nblobs);
-
-  blob_max = (width < height ? width : height) / 2;
-  blob_min = (blob_max * 2) / 3;
-  for (i = 0; i < layer->nblobs; i++)
-    layer->blobs[i] = make_blob (width, height,
-                                (random() % (blob_max-blob_min)) + blob_min);
-
-  layer->pixmap = XCreatePixmap (dpy, window, width, height, 1);
-  layer->gc = XCreateGC (dpy, layer->pixmap, 0, &gcv);
-
-  return layer;
-}
-
-static void
-draw_layer_plane (Display *dpy, struct layer *layer, int width, int height)
-{
-  int i;
-  XSetForeground (dpy, layer->gc, 1L);
-  XFillRectangle (dpy, layer->pixmap, layer->gc, 0, 0, width, height);
-  XSetForeground (dpy, layer->gc, 0L);
-  for (i = 0; i < layer->nblobs; i++)
-    {
-      throb_blob (layer->blobs[i]);
-      move_blob (layer->blobs[i], width, height);
-      draw_blob (dpy, layer->pixmap, layer->gc, layer->blobs[i], True);
-    }
-}
-
-
-static void
-draw_layer_blobs (Display *dpy, Drawable drawable, GC gc,
-                 struct layer *layer, int width, int height,
-                 Bool fill_p)
-{
-  int i;
-  for (i = 0; i < layer->nblobs; i++)
-    {
-      throb_blob (layer->blobs[i]);
-      move_blob (layer->blobs[i], width, height);
-      draw_blob (dpy, drawable, gc, layer->blobs[i], fill_p);
-    }
-}
-
-
-static struct goop *
-make_goop (Display *dpy, Window window, Colormap cmap,
-          int width, int height, long depth)
-{
-  int i;
-  struct goop *goop = (struct goop *) calloc(1, sizeof(*goop));
-  XGCValues gcv;
-  int nblobs = get_integer_resource ("count", "Count");
-
-  unsigned long *plane_masks = 0;
-  unsigned long base_pixel = 0;
-
-  goop->mode = (get_boolean_resource("xor", "Xor")
-               ? xor
-               : (get_boolean_resource("transparent", "Transparent")
-                  ? transparent
-                  : opaque));
-
-  goop->width = width;
-  goop->height = height;
-
-
-  goop->nlayers = get_integer_resource ("planes", "Planes");
-  if (goop->nlayers <= 0)
-    goop->nlayers = (random() % (depth-2)) + 2;
-  goop->layers = (struct layer **) malloc(sizeof(*goop->layers)*goop->nlayers);
-
-
-  if (mono_p && goop->mode == transparent)
-    goop->mode = opaque;
-
-  /* Try to allocate some color planes before committing to nlayers.
-   */
-  if (goop->mode == transparent)
-    {
-      Bool additive_p = get_boolean_resource ("additive", "Additive");
-      int nplanes = goop->nlayers;
-      allocate_alpha_colors (dpy, cmap, &nplanes, additive_p, &plane_masks,
-                            &base_pixel);
-      if (nplanes > 1)
-       goop->nlayers = nplanes;
-      else
-       {
-         fprintf (stderr,
-         "%s: couldn't allocate any color planes; turning transparency off.\n",
-                  progname);
-         goop->mode = opaque;
-       }
-    }
-
-  {
-    int lblobs[32];
-    int total = DEF_COUNT;
-    memset (lblobs, 0, sizeof(lblobs));
-    if (nblobs <= 0)
-      while (total)
-       for (i = 0; total && i < goop->nlayers; i++)
-         lblobs[i]++, total--;
-    for (i = 0; i < goop->nlayers; i++)
-      goop->layers[i] = make_layer (dpy, window, width, height, 
-                                   (nblobs > 0 ? nblobs : lblobs[i]));
-  }
-
-  if (goop->mode == transparent && plane_masks)
-    {
-      for (i = 0; i < goop->nlayers; i++)
-       goop->layers[i]->pixel = base_pixel | plane_masks[i];
-      goop->background = base_pixel;
-    }
-  if (plane_masks)
-    free (plane_masks);
-
-  if (goop->mode != transparent)
-    {
-      XColor color;
-      color.flags = DoRed|DoGreen|DoBlue;
-
-      goop->background =
-       get_pixel_resource ("background", "Background", dpy,cmap);
-
-      for (i = 0; i < goop->nlayers; i++)
-       {
-         int H = random() % 360;                          /* range 0-360    */
-         double S = ((double) (random()%70) + 30)/100.0;  /* range 30%-100% */
-         double V = ((double) (random()%34) + 66)/100.0;  /* range 66%-100% */
-         hsv_to_rgb (H, S, V, &color.red, &color.green, &color.blue);
-         if (XAllocColor (dpy, cmap, &color))
-           goop->layers[i]->pixel = color.pixel;
-         else
-           goop->layers[i]->pixel =
-             WhitePixelOfScreen(DefaultScreenOfDisplay(dpy));
-       }
-    }
-
-  goop->pixmap = XCreatePixmap (dpy, window, width, height,
-                               (goop->mode == xor ? 1L : depth));
-
-  gcv.background = goop->background;
-  gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
-  gcv.line_width = get_integer_resource ("thickness","Thickness");
-  goop->pixmap_gc = XCreateGC (dpy, goop->pixmap, GCLineWidth, &gcv);
-  goop->window_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
-
-  return goop;
-}
-
-static struct goop *
-init_goop (Display *dpy, Window window)
-{
-  XWindowAttributes xgwa;
-  XGetWindowAttributes (dpy, window, &xgwa);
-
-  return make_goop (dpy, window, xgwa.colormap,
-                   xgwa.width, xgwa.height, xgwa.depth);
-}
-
-static void
-run_goop (Display *dpy, Window window, struct goop *goop)
-{
-  int i;
-
-  switch (goop->mode)
-    {
-    case transparent:
-
-      for (i = 0; i < goop->nlayers; i++)
-       draw_layer_plane (dpy, goop->layers[i], goop->width, goop->height);
-
-      XSetForeground (dpy, goop->pixmap_gc, goop->background);
-      XSetPlaneMask (dpy, goop->pixmap_gc, AllPlanes);
-      XFillRectangle (dpy, goop->pixmap, goop->pixmap_gc, 0, 0,
-                     goop->width, goop->height);
-      XSetForeground (dpy, goop->pixmap_gc, ~0L);
-      for (i = 0; i < goop->nlayers; i++)
-       {
-         XSetPlaneMask (dpy, goop->pixmap_gc, goop->layers[i]->pixel);
-/*
-         XSetForeground (dpy, goop->pixmap_gc, ~0L);
-         XFillRectangle (dpy, goop->pixmap, goop->pixmap_gc, 0, 0,
-                         goop->width, goop->height);
-         XSetForeground (dpy, goop->pixmap_gc, 0L);
- */
-         draw_layer_blobs (dpy, goop->pixmap, goop->pixmap_gc,
-                           goop->layers[i], goop->width, goop->height,
-                           True);
-       }
-      XCopyArea (dpy, goop->pixmap, window, goop->window_gc, 0, 0,
-                goop->width, goop->height, 0, 0);
-      break;
-
-    case xor:
-      XSetFunction (dpy, goop->pixmap_gc, GXcopy);
-      XSetForeground (dpy, goop->pixmap_gc, 0);
-      XFillRectangle (dpy, goop->pixmap, goop->pixmap_gc, 0, 0,
-                     goop->width, goop->height);
-      XSetFunction (dpy, goop->pixmap_gc, GXxor);
-      XSetForeground (dpy, goop->pixmap_gc, 1);
-      for (i = 0; i < goop->nlayers; i++)
-       draw_layer_blobs (dpy, goop->pixmap, goop->pixmap_gc,
-                         goop->layers[i], goop->width, goop->height,
-                         (goop->mode != outline));
-      XCopyPlane (dpy, goop->pixmap, window, goop->window_gc, 0, 0,
-                 goop->width, goop->height, 0, 0, 1L);
-      break;
-
-    case opaque:
-    case outline:
-      XSetForeground (dpy, goop->pixmap_gc, goop->background);
-      XFillRectangle (dpy, goop->pixmap, goop->pixmap_gc, 0, 0,
-                     goop->width, goop->height);
-      for (i = 0; i < goop->nlayers; i++)
-       {
-         XSetForeground (dpy, goop->pixmap_gc, goop->layers[i]->pixel);
-         draw_layer_blobs (dpy, goop->pixmap, goop->pixmap_gc,
-                           goop->layers[i], goop->width, goop->height,
-                           (goop->mode != outline));
-       }
-      XCopyArea (dpy, goop->pixmap, window, goop->window_gc, 0, 0,
-                goop->width, goop->height, 0, 0);
-      break;
-
-    default:
-      abort ();
-      break;
-    }
-}
-
-\f
-char *progclass = "Goop";
-
-char *defaults [] = {
-  ".background:                black",
-  ".foreground:                white",
-  "*delay:             12000",
-  "*transparent:       true",
-  "*additive:          true",
-  "*xor:               false",
-  "*count:             0",
-  "*planes:            0",
-  "*thickness:         5",
-  "*torque:            0.0075",
-  "*elasticity:                1.8",
-  "*maxVelocity:       1.2",
-  0
-};
-
-XrmOptionDescRec options [] = {
-  { "-delay",          ".delay",       XrmoptionSepArg, 0 },
-  { "-count",          ".count",       XrmoptionSepArg, 0 },
-  { "-planes",         ".planes",      XrmoptionSepArg, 0 },
-  { "-transparent",    ".transparent", XrmoptionNoArg, "True" },
-  { "-non-transparent",        ".transparent", XrmoptionNoArg, "False" },
-  { "-additive",       ".additive",    XrmoptionNoArg, "True" },
-  { "-subtractive",    ".additive",    XrmoptionNoArg, "false" },
-  { "-xor",            ".xor",         XrmoptionNoArg, "true" },
-  { "-no-xor",         ".xor",         XrmoptionNoArg, "false" },
-  { "-thickness",      ".thickness",   XrmoptionSepArg, 0 },
-  { "-torque",         ".torque",      XrmoptionSepArg, 0 },
-  { "-elasticity",     ".elasticity",  XrmoptionSepArg, 0 },
-  { "-max-velocity",   ".maxVelocity", XrmoptionSepArg, 0 },
-  { 0, 0, 0, 0 }
-};
-
-void
-screenhack (Display *dpy, Window window)
-{
-  struct goop *g = init_goop (dpy, window);
-  int delay = get_integer_resource ("delay", "Integer");
-  while (1)
-    {
-      run_goop (dpy, window, g);
-      XSync (dpy, False);
-      screenhack_handle_events (dpy);
-      if (delay) usleep (delay);
-    }
-}