http://ftp.aanet.ru/pub/Linux/X11/apps/xscreensaver-2.31.tar.gz
[xscreensaver] / hacks / flame.c
old mode 100755 (executable)
new mode 100644 (file)
index e010b9d..521d3cb
@@ -1,4 +1,5 @@
-/* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@mcom.com>
+/* xscreensaver, Copyright (c) 1993, 1995, 1996
+ *  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
@@ -10,7 +11,7 @@
  */
 
 /* This file was ported from xlock for use in xscreensaver (and standalone)
- * by jwz on 18-Oct-93.  Original copyright reads:
+ * by jwz on 18-Oct-93.  (And again, 11-May-97.)  Original copyright reads:
  *
  *   static char sccsid[] = "@(#)flame.c 1.4 91/09/27 XLOCK";
  *
  *                    Mountain View, CA  94043
  *
  * Revision History:
+ * 01-Jun-95: This should look more like the original with some updates by
+ *            Scott Draves.
  * 27-Jun-91: vary number of functions used.
  * 24-Jun-91: fixed portability problem with integer mod (%).
- * 06-Jun-91: Written. (received from Scott Graves, spot@cs.cmu.edu).
+ * 06-Jun-91: Written. (received from Scott Draves, spot@cs.cmu.edu).
  */
 
+#include <math.h>
 #include "screenhack.h"
 
-/*#include <math.h>*/
-
 #define POINT_BUFFER_SIZE 10
 #define MAXLEV 4
+#define MAXKINDS  10
 
 static double f[2][3][MAXLEV]; /* three non-homogeneous transforms */
 static int max_total;
 static int max_levels;
 static int max_points;
 static int cur_level;
+static int variation;
 static int snum;
 static int anum;
 static int num_points;
 static int total_points;
 static int pixcol;
-static int npixels;
-static unsigned long *pixels;
+static int ncolors;
+static XColor *colors;
 static XPoint points [POINT_BUFFER_SIZE];
 static GC gc;
 
@@ -72,8 +76,7 @@ static int delay, delay2;
 static int width, height;
 
 static short
-halfrandom (mv)
-     int mv;
+halfrandom (int mv)
 {
   static short lasthalf = 0;
   unsigned long r;
@@ -91,11 +94,8 @@ halfrandom (mv)
   return (r % mv);
 }
 
-
 static void
-init_flame (dpy, window)
-     Display *dpy;
-     Window window;
+init_flame (Display *dpy, Window window)
 {
   XGCValues gcv;
   XWindowAttributes xgwa;
@@ -118,25 +118,19 @@ init_flame (dpy, window)
   delay2 = get_integer_resource ("delay2", "Integer");
   if (delay2 < 0) delay2 = 0;
 
+  variation = random() % MAXKINDS;
+
   if (mono_p)
-    npixels = 0;
+    ncolors = 0;
   else
     {
-      int i = get_integer_resource ("ncolors", "Integer");
-      double saturation = 1.0;
-      double value = 1.0;
-      XColor color;
-      if (i <= 0) i = 128;
-
-      pixels = (unsigned long *) malloc ((i+1) * sizeof (*pixels));
-      for (npixels = 0; npixels < i; npixels++)
-       {
-         hsv_to_rgb ((360*npixels)/i, saturation, value,
-                     &color.red, &color.green, &color.blue);
-         if (! XAllocColor (dpy, cmap, &color))
-           break;
-         pixels [npixels] = color.pixel;
-       }
+      ncolors = get_integer_resource ("colors", "Integer");
+      if (ncolors <= 0) ncolors = 128;
+      colors = (XColor *) malloc ((ncolors+1) * sizeof (*colors));
+      make_smooth_colormap (dpy, xgwa.visual, xgwa.colormap, colors, &ncolors,
+                           True, 0, True);
+      if (ncolors <= 2)
+       mono_p = True, ncolors = 0;
     }
 
   gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
@@ -144,19 +138,15 @@ init_flame (dpy, window)
 
   if (! mono_p)
     {
-      pixcol = halfrandom (npixels);
-      gcv.foreground = (pixels [pixcol]);
+      pixcol = halfrandom (ncolors);
+      gcv.foreground = (colors [pixcol].pixel);
     }
 
   gc = XCreateGC (dpy, window, GCForeground | GCBackground, &gcv);
 }
 
 static int
-recurse (x, y, l, dpy, win)
-     register double x, y;
-     register int l;
-     Display *dpy;
-     Window win;
+recurse (double x, double y, int l, Display *dpy, Window win)
 {
   int xp, yp, i;
   double nx, ny;
@@ -185,12 +175,134 @@ recurse (x, y, l, dpy, win)
     {
       for (i = 0; i < snum; i++)
        {
+
+         /* Scale back when values get very large. Spot sez:
+            "I think this happens on HPUX.  I think it's non-IEEE
+            to generate an exception instead of a silent NaN."
+          */
+         if ((abs(x) > 1.0E5) || (abs(y) > 1.0E5))
+           x = x / y;
+
          nx = f[0][0][i] * x + f[0][1][i] * y + f[0][2][i];
          ny = f[1][0][i] * x + f[1][1][i] * y + f[1][2][i];
          if (i < anum)
            {
-             nx = sin(nx);
-             ny = sin(ny);
+             switch (variation)
+               {
+               case 0: /* sinusoidal */
+                 nx = sin(nx);
+                 ny = sin(ny);
+                 break;
+               case 1: /* complex */
+                 {
+                   double r2 = nx * nx + ny * ny + 1e-6;
+                   nx = nx / r2;
+                   ny = ny / r2;
+                 }
+                 break;
+               case 2: /* bent */
+                 if (nx < 0.0)
+                   nx = nx * 2.0;
+                 if (ny < 0.0)
+                   ny = ny / 2.0;
+                 break;
+               case 3: /* swirl */
+                 {
+                   double r = (nx * nx + ny * ny);     /* times k here is fun */
+                   double c1 = sin(r);
+                   double c2 = cos(r);
+                   double t = nx;
+
+                   if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
+                     ny = 1e4;
+                   else
+                     ny = c2 * t + c1 * ny;
+                   nx = c1 * nx - c2 * ny;
+                 }
+                 break;
+               case 4: /* horseshoe */
+                 {
+                   double r, c1, c2, t;
+
+                   /* Avoid atan2: DOMAIN error message */
+                   if (nx == 0.0 && ny == 0.0)
+                     r = 0.0;
+                   else
+                     r = atan2(nx, ny);      /* times k here is fun */
+                   c1 = sin(r);
+                   c2 = cos(r);
+                   t = nx;
+
+                   nx = c1 * nx - c2 * ny;
+                   ny = c2 * t + c1 * ny;
+                 }
+                 break;
+               case 5: /* drape */
+                 {
+                   double t;
+
+                   /* Avoid atan2: DOMAIN error message */
+                   if (nx == 0.0 && ny == 0.0)
+                     t = 0.0;
+                   else
+                     t = atan2(nx, ny) / M_PI;
+
+                   if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
+                     ny = 1e4;
+                   else
+                     ny = sqrt(nx * nx + ny * ny) - 1.0;
+                   nx = t;
+                 }
+                 break;
+               case 6: /* broken */
+                 if (nx > 1.0)
+                   nx = nx - 1.0;
+                 if (nx < -1.0)
+                   nx = nx + 1.0;
+                 if (ny > 1.0)
+                   ny = ny - 1.0;
+                 if (ny < -1.0)
+                   ny = ny + 1.0;
+                 break;
+               case 7: /* spherical */
+                 {
+                   double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
+
+                   nx = nx / r;
+                   ny = ny / r;
+                 }
+                 break;
+               case 8: /*  */
+                 nx = atan(nx) / M_PI_2;
+                 ny = atan(ny) / M_PI_2;
+                 break;
+/* #if 0 */  /* core dumps on some machines, why not all? */
+               case 9: /* complex sine */
+                 {
+                   double u = nx;
+                   double v = ny;
+                   double ev = exp(v);
+                   double emv = exp(-v);
+
+                   nx = (ev + emv) * sin(u) / 2.0;
+                   ny = (ev - emv) * cos(u) / 2.0;
+                 }
+                 break;
+               case 10:        /* polynomial */
+                 if (nx < 0)
+                   nx = -nx * nx;
+                 else
+                   nx = nx * nx;
+                 if (ny < 0)
+                   ny = -ny * ny;
+                 else
+                   ny = ny * ny;
+                 break;
+/* #endif */
+               default:
+                 nx = sin(nx);
+                 ny = sin(ny);
+               }
            }
          if (!recurse (nx, ny, l + 1, dpy, win))
            return 0;
@@ -201,9 +313,7 @@ recurse (x, y, l, dpy, win)
 
 
 static void
-flame (dpy, window)
-     Display *dpy;
-     Window window;
+flame (Display *dpy, Window window)
 {
   int i, j, k;
   static int alt = 0;
@@ -213,14 +323,16 @@ flame (dpy, window)
       if (delay2) usleep (delay2);
       XClearWindow (dpy, window);
       alt = !alt;
+
+      variation = random() % MAXKINDS;
     }
   else
     {
-      if (npixels > 2)
+      if (ncolors > 2)
        {
-         XSetForeground (dpy, gc, pixels [pixcol]);
+         XSetForeground (dpy, gc, colors [pixcol].pixel);
          if (--pixcol < 0)
-           pixcol = npixels - 1;
+           pixcol = ncolors - 1;
        }
     }
 
@@ -248,13 +360,30 @@ flame (dpy, window)
   if (delay) usleep (delay);
 }
 
+
+#ifdef __hpux
+/* I don't understand why this is necessary, but I'm told that this program
+   does nothing at all on HP-sUX without it.
+ */
+#undef random
+#undef srandom
+#include <math.h>
+int matherr(x)
+   register struct exception *x;
+{
+  if (x->type == PLOSS) return 1;
+  else return 0;
+}
+#endif /* __hpux */
+
+
 \f
 char *progclass = "Flame";
 
 char *defaults [] = {
-  "Flame.background:   black",         /* to placate SGI */
-  "Flame.foreground:   white",
-  "*colors:    128",
+  ".background:        black",
+  ".foreground:        white",
+  "*colors:    64",
   "*iterations:        25",
   "*delay:     50000",
   "*delay2:    2000000",
@@ -263,18 +392,16 @@ char *defaults [] = {
 };
 
 XrmOptionDescRec options [] = {
-  { "-ncolors",                ".colors",      XrmoptionSepArg, 0 },
+  { "-colors",         ".colors",      XrmoptionSepArg, 0 },
   { "-iterations",     ".iterations",  XrmoptionSepArg, 0 },
   { "-delay",          ".delay",       XrmoptionSepArg, 0 },
   { "-delay2",         ".delay2",      XrmoptionSepArg, 0 },
-  { "-points",         ".points",      XrmoptionSepArg, 0 }
+  { "-points",         ".points",      XrmoptionSepArg, 0 },
+  { 0, 0, 0, 0 }
 };
-int options_size = (sizeof (options) / sizeof (options[0]));
 
 void
-screenhack (dpy, window)
-     Display *dpy;
-     Window window;
+screenhack (Display *dpy, Window window)
 {
   init_flame (dpy, window);
   while (1)