ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / hacks / helix.c
diff --git a/hacks/helix.c b/hacks/helix.c
new file mode 100644 (file)
index 0000000..27c9d43
--- /dev/null
@@ -0,0 +1,306 @@
+/* xscreensaver, Copyright (c) 1992, 1995, 1996, 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.
+ */
+
+/* Algorithm from a Mac program by Chris Tate, written in 1988 or so. */
+
+/* 18-Sep-97: Johannes Keukelaar (johannes@nada.kth.se): Improved screen
+ *            eraser.
+ * 10-May-97: merged ellipse code by Dan Stromberg <strombrg@nis.acs.uci.edu>
+ *            as found in xlockmore 4.03a10.
+ * 1992:      jwz created.
+ */
+
+#include <math.h>
+#include "screenhack.h"
+#include "erase.h"
+
+static double sins [360];
+static double coss [360];
+
+static GC draw_gc;
+static unsigned int default_fg_pixel;
+static int sleep_time;
+
+static void
+init_helix (Display *dpy, Window window)
+{
+  int i;
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  Colormap cmap;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+  gcv.foreground = default_fg_pixel =
+    get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+  draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+  gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
+
+  for (i = 0; i < 360; i++)
+    {
+      sins [i] = sin ((((double) i) / 180.0) * M_PI);
+      coss [i] = cos ((((double) i) / 180.0) * M_PI);
+    }
+}
+
+static int
+gcd (int a, int b)
+{
+  while (b > 0)
+    {
+      int tmp;
+      tmp = a % b;
+      a = b;
+      b = tmp;
+    }
+  return (a < 0 ? -a : a);
+}
+
+static void
+helix (Display *dpy, Window window,
+       int radius1, int radius2, int d_angle,
+       int factor1, int factor2, int factor3, int factor4)
+{
+  XWindowAttributes xgwa;
+  int width, height;
+  int xmid, ymid;
+  int x1, y1, x2, y2, angle, limit;
+  int i;
+
+  XClearWindow (dpy, window);
+  XGetWindowAttributes (dpy, window, &xgwa);
+  width = xgwa.width;
+  height = xgwa.height;
+
+  xmid = width / 2;
+  ymid = height / 2;
+  x1 = xmid;
+  y1 = ymid + radius2;
+  x2 = xmid;
+  y2 = ymid + radius1;
+  angle = 0;
+  limit = 1 + (360 / gcd (360, d_angle));
+  
+  for (i = 0; i < limit; i++)
+    {
+      int tmp;
+#define pmod(x,y) (tmp=((x) % (y)), (tmp >= 0 ? tmp : (tmp + (y))))
+
+      x1 = xmid + (((double) radius1) * sins [pmod ((angle * factor1), 360)]);
+      y1 = ymid + (((double) radius2) * coss [pmod ((angle * factor2), 360)]);
+      XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
+      x2 = xmid + (((double) radius2) * sins [pmod ((angle * factor3), 360)]);
+      y2 = ymid + (((double) radius1) * coss [pmod ((angle * factor4), 360)]);
+
+      XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
+      angle += d_angle;
+      XFlush (dpy);
+    }
+}
+
+static void
+trig (Display *dpy, Window window,
+      int d_angle, int factor1, int factor2,
+      int offset, int d_angle_offset, int dir, int density)
+{
+  XWindowAttributes xgwa;
+  int width, height;
+  int xmid, ymid;
+  int x1, y1, x2, y2;
+  int tmp, angle;
+  Colormap cmap;
+
+  XClearWindow (dpy, window);
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+  width = xgwa.width;
+  height = xgwa.height;
+
+  xmid = width / 2;
+  ymid = height / 2;
+
+  while (d_angle >= -360 && d_angle <= 360)
+    {
+      angle = d_angle + d_angle_offset;
+      x1 = (sins [pmod(angle * factor1, 360)] * xmid) + xmid;
+      y1 = (coss [pmod(angle * factor1, 360)] * ymid) + ymid;
+      x2 = (sins [pmod(angle * factor2 + offset, 360)] * xmid) + xmid;
+      y2 = (coss [pmod(angle * factor2 + offset, 360)] * ymid) + ymid;
+      XDrawLine(dpy, window, draw_gc, x1, y1, x2, y2);
+      tmp = (int) 360 / (2 * density * factor1 * factor2);
+      if (tmp == 0)    /* Do not want it getting stuck... */
+       tmp = 1;        /* Would not need if floating point */
+      d_angle += dir * tmp;
+    }
+}
+
+#define min(a,b) ((a)<(b)?(a):(b))
+
+static void
+random_helix (Display *dpy, Window window, XColor *color, Bool *got_color)
+{
+  Colormap cmap;
+  int width, height;
+  int radius, radius1, radius2, d_angle, factor1, factor2, factor3, factor4;
+  double divisor;
+  XWindowAttributes xgwa;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  width = xgwa.width;
+  height = xgwa.height;
+  cmap = xgwa.colormap;
+
+  radius = min (width, height) / 2;
+
+  d_angle = 0;
+  factor1 = 2;
+  factor2 = 2;
+  factor3 = 2;
+  factor4 = 2;
+
+  divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
+
+  if ((random () & 1) == 0)
+    {
+      radius1 = radius;
+      radius2 = radius / divisor;
+    }
+  else
+    {
+      radius2 = radius;
+      radius1 = radius / divisor;
+    }
+
+  while (gcd (360, d_angle) >= 2)
+    d_angle = random () % 360;
+
+#define random_factor()                                \
+  (((random() % 7) ? ((random() & 1) + 1) : 3) \
+   * (((random() & 1) * 2) - 1))
+
+  while (gcd (gcd (gcd (factor1, factor2), factor3), factor4) != 1)
+    {
+      factor1 = random_factor ();
+      factor2 = random_factor ();
+      factor3 = random_factor ();
+      factor4 = random_factor ();
+    }
+
+  if (mono_p)
+    XSetForeground (dpy, draw_gc, default_fg_pixel);
+  else
+    {
+      hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
+                 &color->red, &color->green, &color->blue);
+      if ((*got_color = XAllocColor (dpy, cmap, color)))
+       XSetForeground (dpy, draw_gc, color->pixel);
+      else
+       XSetForeground (dpy, draw_gc, default_fg_pixel);
+    }
+  helix (dpy, window, radius1, radius2, d_angle,
+        factor1, factor2, factor3, factor4);
+}
+
+static void
+random_trig (Display *dpy, Window window, XColor *color, Bool *got_color)
+{
+  Colormap cmap;
+  int width, height;
+  int radius, d_angle, factor1, factor2;
+  int offset, d_angle_offset, dir, density;
+
+  XWindowAttributes xgwa;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  width = xgwa.width;
+  height = xgwa.height;
+  cmap = xgwa.colormap;
+
+  radius = min (width, height) / 2;
+
+  d_angle = 0;
+  factor1 = (random() % 8) + 1;
+  do {
+    factor2 = (random() % 8) + 1;
+  } while (factor1 == factor2);
+
+  dir = (random() & 1) ? 1 : -1;
+  d_angle_offset = random() % 360;
+  offset = ((random() % ((360 / 4) - 1)) + 1) / 4;
+  density = 1 << ((random() % 4) + 4); /* Higher density, higher angles */
+
+  if (mono_p)
+    XSetForeground (dpy, draw_gc, default_fg_pixel);
+  else
+    {
+      hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
+                 &color->red, &color->green, &color->blue);
+      if ((*got_color = XAllocColor (dpy, cmap, color)))
+       XSetForeground (dpy, draw_gc, color->pixel);
+      else
+       XSetForeground (dpy, draw_gc, default_fg_pixel);
+    }
+  trig (dpy, window, d_angle, factor1, factor2,
+       offset, d_angle_offset, dir, density);
+}
+
+static void
+random_helix_or_trig (Display *dpy, Window window)
+{
+  Bool free_color = False;
+  XColor color;
+  int width, height;
+  XWindowAttributes xgwa;
+  Colormap cmap;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  width = xgwa.width;
+  height = xgwa.height;
+  cmap = xgwa.colormap;
+
+  if (random() & 1)
+    random_helix(dpy, window, &color, &free_color);
+  else
+    random_trig(dpy, window, &color, &free_color);
+
+  XSync (dpy, False);
+  screenhack_handle_events (dpy);
+  sleep ( sleep_time );
+
+  screenhack_handle_events (dpy);
+  erase_full_window(dpy, window);
+
+  if (free_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
+  XSync (dpy, False);
+  screenhack_handle_events (dpy);
+  sleep (1);
+}
+
+\f
+char *progclass = "Helix";
+
+char *defaults [] = {
+  ".background: black",
+  "*delay:      5",
+  0
+};
+
+XrmOptionDescRec options [] = {   
+  { "-delay",           ".delay",               XrmoptionSepArg, 0 },
+  { 0 },
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (Display *dpy, Window window)
+{
+  sleep_time = get_integer_resource("delay", "Integer");
+  init_helix (dpy, window);
+  while (1)
+    random_helix_or_trig (dpy, window);
+}