http://ftp.x.org/contrib/applications/xscreensaver-2.23.tar.gz
[xscreensaver] / hacks / lmorph.c
index 70c91eee893e5c730166100eaeb45be3c0f4fc6b..f372c1eeff7c8463bda4cda0fe5c826c0c9fa7aa 100644 (file)
@@ -7,18 +7,37 @@
  *  DESCRIPTION     Bilinear interpolation for morphing line shapes.
  *
  *  WRITTEN BY      Sverre H. Huseby                Glenn T. Lines
- *                  Maridalsvn. 122, leil 101       Frysjavn. 3, 5. etg.
- *                  N-0461 Oslo                     N-0883 Oslo
+ *                  Kurvn. 30                       Ã˜stgaardsgt. 5
+ *                  N-0495 Oslo                     N-0474 Oslo
  *                  Norway                          Norway
  *
- *                  Phone:  +47 22 71 99 08         Phone:  +47 22 23 71 99
- *                  E-mail: sverrehu@ifi.uio.no     E-mail: gtl@si.sintef.no
+ *                  Phone:  +47 901 63 579          Phone:  +47 22 04 67 28
+ *                  E-mail: sverrehu@online.no      E-mail: gtl@si.sintef.no
+ *                  URL:    http://home.sol.no/~sverrehu/
  *
  *                  The original idea, and the bilinear interpolation
  *                  mathematics used, emerged in the head of the wise
- *                  Glenn Terje Lines.
+ *                  Glenn T. Lines.
  *
- *  MODIFICATIONS   march 1995
+ *  MODIFICATIONS   june 1998 (shh)
+ *                    * Minor code cleanup.
+ *
+ *                  march 1997 (shh)
+ *                    * Added -mailfile option to allow checking for
+ *                      new mail while the screensaver is active.
+ *
+ *                  january 1997 (shh)
+ *                    * Some code reformatting.
+ *                    * Added possibility to use float arithmetic.
+ *                    * Added -figtype option.
+ *                    * Made color blue default.
+ *
+ *                  december 1995 (jwz)
+ *                    * Function headers converted from ANSI to K&R.
+ *                    * Added posibility for random number of steps, and
+ *                      made this the default.
+ *
+ *                  march 1995 (shh)
  *                    * Converted from an MS-Windows program to X Window.
  *
  **************************************************************************/
  *                                                                        *
  **************************************************************************/
 
-/* Define MARGINS to make some space around the figure */
-#define MARGINS /**/
+/* define MARGINS to make some space around the figure. */
+#define MARGINS
+
+/* define USE_FLOAT to avoid using integer calculations in
+   createPoints. integer calculation is supposed to be faster, but it
+   won't work for displays larger than 2048x2048 or so pixels. */
+#undef USE_FLOAT
 
 #define MAXFIGS    20
 #define TWO_PI     (2.0 * M_PI)
 #define RND(x)     (random() % (x))
+
+#define FT_OPEN    1
+#define FT_CLOSED  2
+#define FT_ALL     (FT_OPEN | FT_CLOSED)
+
 static int
-    cFig = 0,                   /* Number of figure arrays. */
-    cPoint,                     /* Number of points in each array. */
-    nWork,                      /* Current work array number. */
-    nFrom,                      /* Current from array number. */
-    nTo;                        /* Current to array number. */
-static long
-    delay;                      /* usecs to wait between updates. */
+    numFigs = 0,                /* number of figure arrays. */
+    numPoints,                  /* number of points in each array. */
+    nWork,                      /* current work array number. */
+    nFrom,                      /* current from array number. */
+    nTo,                        /* current to array number. */
+    figType;
+static long delay;              /* usecs to wait between updates. */
 static XPoint
-    *aWork[2],                  /* Working arrays. */
-    *a[MAXFIGS],                /* The figure arrays. */
-    *aTmp,                      /* Used as source when interrupting morph */
-    *aPrev,                     /* Previous points displayed. */
-    *aCurr,                     /* The current points displayed. */  
-    *aFrom,                     /* Figure converting from. */
-    *aTo;                       /* Figure converting to. */
-static double
-    gam,
-    maxGamma = 1.0,
-    delta_gam;
-static GC
-    gcDraw, gcClear;
-static Display
-    *dpy;
-static Window
-    window;
+    *aWork[2],                  /* working arrays. */
+    *a[MAXFIGS],                /* the figure arrays. */
+    *aTmp,                      /* used as source when interrupting morph */
+    *aPrev,                     /* previous points displayed. */
+    *aCurr,                     /* the current points displayed. */  
+    *aFrom,                     /* figure converting from. */
+    *aTo;                       /* figure converting to. */
+static int         scrWidth, scrHeight;
+static double      currGamma, maxGamma = 1.0, deltaGamma;
+static GC          gcDraw, gcClear;
+static Display     *dpy;
+static Window      window;
 
 
 
@@ -79,20 +103,24 @@ static Window
 char *progclass = "LMorph";
 
 char *defaults [] = {
-    "LMorph.background: black",
-    "LMorph.foreground: green",
+    ".background: black",
+    ".foreground: blue",
     "*points: 150",
     "*steps: 0",
     "*delay: 50000",
+    "*figtype: all",
     0
 };
 
 XrmOptionDescRec options [] = {
-  { "-points", ".points", XrmoptionSepArg, 0 },
-  { "-steps",  ".steps",  XrmoptionSepArg, 0 },
-  { "-delay",  ".delay",  XrmoptionSepArg, 0 },
+  { "-points",      ".points",      XrmoptionSepArg, 0 },
+  { "-steps",       ".steps",       XrmoptionSepArg, 0 },
+  { "-delay",       ".delay",       XrmoptionSepArg, 0 },
+  { "-figtype",     ".figtype",     XrmoptionSepArg, 0 },
   { 0, 0, 0, 0 }
 };
+int options_size = (sizeof (options) / sizeof (options[0]));
+
 
 
 /**************************************************************************
@@ -113,308 +141,220 @@ xmalloc(size_t size)
     return ret;
 }
 
-
-
-static double frnd (void)
-{
-    /*
-     *  Hm. for some reason the second line (using RAND_MAX) didn't
-     *  work on some machines, so I always use the first.
-     */
-#ifndef dont_use_RAND_MAX
-    return (double) (random() & 0x7FFF) / 0x7FFF;
-#else  /* RAND_MAX */
-    return ((double) random()) / RAND_MAX;
-#endif /* RAND_MAX */
-}
-
-
-
-static void initPointArrays (void)
+static void
+initPointArrays(void)
 {
-    XWindowAttributes wa;
     int q, w,
-        mx, my,                 /* Max screen coordinates. */
-        mp,                     /* Max point number. */
+        mx, my,                 /* max screen coordinates. */
+        mp,                     /* max point number. */
         s, rx, ry,
         marginx, marginy;
     double scalex, scaley;
 
-    XGetWindowAttributes(dpy, window, &wa);
-    mx = wa.width - 1;
-    my = wa.height - 1;
-    mp = cPoint - 1;
-
-    aWork[0] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    aWork[1] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    aTmp     = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-
-
-    /*
-     *  Figure 0
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    s = cPoint / 4;
-    for (q = 0; q < s; q++) {
-        a[cFig][q].x = ((double) q / s) * mx;
-        a[cFig][q].y = 0;
-        a[cFig][s + q].x = mx;
-        a[cFig][s + q].y = ((double) q / s) * my;
-        a[cFig][2 * s + q].x = mx - ((double) q / s) * mx;
-        a[cFig][2 * s + q].y = my;
-        a[cFig][3 * s + q].x = 0;
-        a[cFig][3 * s + q].y = my - ((double) q / s) * my;
-    }
-    for (q = 4 * s; q < cPoint; q++) 
-        a[cFig][q].x = a[cFig][q].y = 0;
-    a[cFig][mp].x = a[cFig][0].x;
-    a[cFig][mp].y = a[cFig][0].y;
-    ++cFig;
-
-    /*
-     *  Figure 1
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = ((double) q / cPoint) * mx;
-        a[cFig][q].y = (1.0 - sin(((double) q / mp) * TWO_PI)) * my / 2.0;
-    }
-    ++cFig;
-
-    /*
-     *  Figure 2
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    rx = mx / 2;
-    ry = my / 2;
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = mx / 2 + rx * sin(1 * TWO_PI * (double) q / mp);
-        a[cFig][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
-    }
-    a[cFig][mp].x = a[cFig][0].x;
-    a[cFig][mp].y = a[cFig][0].y;
-    ++cFig;
-
-    /*
-     *  Figure 3
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    rx = mx / 2;
-    ry = my / 2;
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = mx / 2 + ry * sin(3 * TWO_PI * (double) q / mp);
-        a[cFig][q].y = my / 2 + ry * cos(1 * TWO_PI * (double) q / mp);
-    }
-    a[cFig][mp].x = a[cFig][0].x;
-    a[cFig][mp].y = a[cFig][0].y;
-    ++cFig;
-
-    /*
-     *  Figure 4
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    rx = mx / 2;
-    ry = my / 2;
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = mx / 2 + ry * (1 - 0.1 * frnd())
-           * sin(TWO_PI * (double) q / mp);
-        a[cFig][q].y = my / 2 + ry * (1 - 0.1 * frnd())
-           * cos(TWO_PI * (double) q / mp);
-    }
-    a[cFig][mp].x = a[cFig][0].x;
-    a[cFig][mp].y = a[cFig][0].y;
-    ++cFig;
-
-    /*
-     *  Figure 5
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    rx = mx / 2;
-    ry = my / 2;
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = mx / 2 + ry * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
-           * sin(TWO_PI * (double) q / mp);
-        a[cFig][q].y = my / 2 + ry * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
-           * cos(TWO_PI * (double) q / mp);
-    }
-    a[cFig][mp].x = a[cFig][0].x;
-    a[cFig][mp].y = a[cFig][0].y;
-    ++cFig;
-
-    /*
-     *  Figure 6
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    rx = mx / 2;
-    ry = my / 2;
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = mx / 2 + ry * sin(TWO_PI * (double) q / mp);
-        a[cFig][q].y = my / 2 + ry * cos(TWO_PI * (double) q / mp);
-    }
-    a[cFig][mp].x = a[cFig][0].x;
-    a[cFig][mp].y = a[cFig][0].y;
-    ++cFig;
-
-    /*
-     *  Figure 7
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    rx = mx / 2;
-    ry = my / 2;
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = mx / 2 + rx * cos(TWO_PI * (double) q / mp);
-        a[cFig][q].y = my / 2 + ry * sin(TWO_PI * (double) q / mp);
-    }
-    a[cFig][mp].x = a[cFig][0].x;
-    a[cFig][mp].y = a[cFig][0].y;
-    ++cFig;
-
-    /*
-     *  Figure 8
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = ((double) q / mp) * mx;
-        a[cFig][q].y = (1.0 - cos(((double) q / mp) * 3 * TWO_PI)) * my / 2.0;
-    }
-    ++cFig;
-
-    /*
-     *  Figure 9
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    rx = mx / 2;
-    ry = my / 2;
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = mx / 2 + rx * sin(2 * TWO_PI * (double) q / mp);
-        a[cFig][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
-    }
-    a[cFig][mp].x = a[cFig][0].x;
-    a[cFig][mp].y = a[cFig][0].y;
-    ++cFig;
-
-    /*
-     *  Figure 10
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    rx = mx / 2;
-    ry = my / 2;
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = mx / 2 + ry * sin(5 * TWO_PI * (double) q / mp)
-           * ((double) q / mp);
-        a[cFig][q].y = my / 2 + ry * cos(5 * TWO_PI * (double) q / mp)
-           * ((double) q / mp);
-    }
-    ++cFig;
-
-    /*
-     *  Figure 11
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    rx = mx / 2;
-    ry = my / 2;
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = mx / 2 + ry * sin(6 * TWO_PI * (double) q / mp)
-           * ((double) q / mp);
-        a[cFig][q].y = my / 2 - ry * cos(6 * TWO_PI * (double) q / mp)
-           * ((double) q / mp);
+    mx = scrWidth - 1;
+    my = scrHeight - 1;
+    mp = numPoints - 1;
+
+    aWork[0] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+    aWork[1] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+    aTmp     = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+
+    if (figType & FT_CLOSED) {
+       /* rectangle */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       s = numPoints / 4;
+       for (q = 0; q < s; q++) {
+           a[numFigs][q].x = ((double) q / s) * mx;
+           a[numFigs][q].y = 0;
+           a[numFigs][s + q].x = mx;
+           a[numFigs][s + q].y = ((double) q / s) * my;
+           a[numFigs][2 * s + q].x = mx - ((double) q / s) * mx;
+           a[numFigs][2 * s + q].y = my;
+           a[numFigs][3 * s + q].x = 0;
+           a[numFigs][3 * s + q].y = my - ((double) q / s) * my;
+       }
+       for (q = 4 * s; q < numPoints; q++) 
+           a[numFigs][q].x = a[numFigs][q].y = 0;
+       a[numFigs][mp].x = a[numFigs][0].x;
+       a[numFigs][mp].y = a[numFigs][0].y;
+       ++numFigs;
+
+       /*  */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       rx = mx / 2;
+       ry = my / 2;
+       for (q = 0; q < numPoints; q++) {
+           a[numFigs][q].x = mx / 2 + rx * sin(1 * TWO_PI * (double) q / mp);
+           a[numFigs][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
+       }
+       a[numFigs][mp].x = a[numFigs][0].x;
+       a[numFigs][mp].y = a[numFigs][0].y;
+       ++numFigs;
+
+       /*  */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       rx = mx / 2;
+       ry = my / 2;
+       for (q = 0; q < numPoints; q++) {
+           a[numFigs][q].x = mx / 2 + ry * sin(3 * TWO_PI * (double) q / mp);
+           a[numFigs][q].y = my / 2 + ry * cos(1 * TWO_PI * (double) q / mp);
+       }
+       a[numFigs][mp].x = a[numFigs][0].x;
+       a[numFigs][mp].y = a[numFigs][0].y;
+       ++numFigs;
+
+       /*  */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       rx = mx / 2;
+       ry = my / 2;
+       for (q = 0; q < numPoints; q++) {
+           a[numFigs][q].x = mx / 2 + ry 
+               * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
+               * sin(TWO_PI * (double) q / mp);
+           a[numFigs][q].y = my / 2 + ry
+               * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
+               * cos(TWO_PI * (double) q / mp);
+       }
+       a[numFigs][mp].x = a[numFigs][0].x;
+       a[numFigs][mp].y = a[numFigs][0].y;
+       ++numFigs;
+
+       /*  */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       rx = mx / 2;
+       ry = my / 2;
+       for (q = 0; q < numPoints; q++) {
+           a[numFigs][q].x = mx / 2 + ry * sin(TWO_PI * (double) q / mp);
+           a[numFigs][q].y = my / 2 + ry * cos(TWO_PI * (double) q / mp);
+       }
+       a[numFigs][mp].x = a[numFigs][0].x;
+       a[numFigs][mp].y = a[numFigs][0].y;
+       ++numFigs;
+
+       /*  */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       rx = mx / 2;
+       ry = my / 2;
+       for (q = 0; q < numPoints; q++) {
+           a[numFigs][q].x = mx / 2 + rx * cos(TWO_PI * (double) q / mp);
+           a[numFigs][q].y = my / 2 + ry * sin(TWO_PI * (double) q / mp);
+       }
+       a[numFigs][mp].x = a[numFigs][0].x;
+       a[numFigs][mp].y = a[numFigs][0].y;
+       ++numFigs;
+
+       /*  */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       rx = mx / 2;
+       ry = my / 2;
+       for (q = 0; q < numPoints; q++) {
+           a[numFigs][q].x = mx / 2 + rx * sin(2 * TWO_PI * (double) q / mp);
+           a[numFigs][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
+       }
+       a[numFigs][mp].x = a[numFigs][0].x;
+       a[numFigs][mp].y = a[numFigs][0].y;
+       ++numFigs;
     }
-    ++cFig;
-
-    /*
-     *  Figure 12
-     */
-    a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
-    for (q = 0; q < cPoint; q++) {
-        a[cFig][q].x = ((double) q / mp) * mx;
-        a[cFig][q].y = (1.0 - sin(((double) q / mp) * 5 * TWO_PI)) * my / 2.0;
+
+    if (figType & FT_OPEN) {
+       /* sine wave, one period */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       for (q = 0; q < numPoints; q++) {
+           a[numFigs][q].x = ((double) q / numPoints) * mx;
+           a[numFigs][q].y = (1.0 - sin(((double) q / mp) * TWO_PI))
+               * my / 2.0;
+       }
+       ++numFigs;
+
+       /*  */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       for (q = 0; q < numPoints; q++) {
+           a[numFigs][q].x = ((double) q / mp) * mx;
+           a[numFigs][q].y = (1.0 - cos(((double) q / mp) * 3 * TWO_PI))
+               * my / 2.0;
+       }
+       ++numFigs;
+
+       /* spiral, one endpoint at bottom */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       rx = mx / 2;
+       ry = my / 2;
+       for (q = 0; q < numPoints; q++) {
+           a[numFigs][q].x = mx / 2 + ry * sin(5 * TWO_PI * (double) q / mp)
+               * ((double) q / mp);
+           a[numFigs][q].y = my / 2 + ry * cos(5 * TWO_PI * (double) q / mp)
+               * ((double) q / mp);
+       }
+       ++numFigs;
+
+       /* spiral, one endpoint at top */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       rx = mx / 2;
+       ry = my / 2;
+       for (q = 0; q < numPoints; q++) {
+           a[numFigs][q].x = mx / 2 + ry * sin(6 * TWO_PI * (double) q / mp)
+               * ((double) q / mp);
+           a[numFigs][q].y = my / 2 - ry * cos(6 * TWO_PI * (double) q / mp)
+               * ((double) q / mp);
+       }
+       ++numFigs;
+
+       /*  */
+       a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
+       for (q = 0; q < numPoints; q++) {
+           a[numFigs][q].x = ((double) q / mp) * mx;
+           a[numFigs][q].y = (1.0 - sin(((double) q / mp) * 5 * TWO_PI))
+               * my / 2.0;
+       }
+       ++numFigs;
     }
-    ++cFig;
 
 #ifdef MARGINS
-    /*
-     *  Make some space around the figures.
-     */
+    /* make some space around the figures.  */
     marginx = (mx + 1) / 10;
     marginy = (my + 1) / 10;
     scalex = (double) ((mx + 1) - 2.0 * marginx) / (mx + 1.0);
     scaley = (double) ((my + 1) - 2.0 * marginy) / (my + 1.0);
-    for (q = 0; q < cFig; q++)
-       for (w = 0; w < cPoint; w++) {
+    for (q = 0; q < numFigs; q++)
+       for (w = 0; w < numPoints; w++) {
            a[q][w].x = marginx + a[q][w].x * scalex;
            a[q][w].y = marginy + a[q][w].y * scaley;
        }
 #endif
 }
 
-
-
-static void createPoints (void)
-{
-    int    q;
-    XPoint *pa = aCurr, *pa1 = aFrom, *pa2 = aTo;
-    long   lg, l1g;
-
-
-    lg = 8192L * gam, l1g = 8192L * (1.0 - gam);
-    for (q = 0; q < cPoint; q++) {
-        pa->x = (short) ((l1g * pa1->x + lg * pa2->x) / 8192L);
-        pa->y = (short) ((l1g * pa1->y + lg * pa2->y) / 8192L);
-        ++pa;
-        ++pa1;
-        ++pa2;
-    }
-}
-
-
-static void drawImage (void)
-{
-    register int q;
-    XPoint *old0, *old1, *new0, *new1;
-
-    /*
-     *  Problem: update the window without too much flickering. I do
-     *  this by handling each linesegment separately. First remove a
-     *  line, then draw the new line. The problem is that this leaves
-     *  small black pixels on the figure. To fix this, I draw the
-     *  entire figure using XDrawLines() afterwards.
-     */
-    if (aPrev) {
-       old0 = aPrev;
-       old1 = aPrev + 1;
-       new0 = aCurr;
-       new1 = aCurr + 1;
-       for (q = cPoint - 1; q; q--) {
-           XDrawLine(dpy, window, gcClear,
-                     old0->x, old0->y, old1->x, old1->y);
-           XDrawLine(dpy, window, gcDraw,
-                     new0->x, new0->y, new1->x, new1->y);
-           ++old0;
-           ++old1;
-           ++new0;
-           ++new1;
-       }
-    }
-    XDrawLines(dpy, window, gcDraw, aCurr, cPoint, CoordModeOrigin);
-    XFlush(dpy);
-}
-
-static void initLMorph (void)
+static void
+initLMorph(void)
 {
     int               steps;
     XGCValues         gcv;
     XWindowAttributes wa;
     Colormap          cmap;
+    char              *ft;
     
-    cPoint = get_integer_resource("points", "Integer");
+    numPoints = get_integer_resource("points", "Integer");
     steps = get_integer_resource("steps", "Integer");
     delay = get_integer_resource("delay", "Integer");
+    ft = get_string_resource("figtype", "String");
+
+    if (strcmp(ft, "all") == 0)
+       figType = FT_ALL;
+    else if (strcmp(ft, "open") == 0)
+       figType = FT_OPEN;
+    else if (strcmp(ft, "closed") == 0)
+       figType = FT_CLOSED;
+    else {
+       fprintf(stderr, "figtype should be `all', `open' or `closed'.\n");
+       figType = FT_ALL;
+    }
 
     if (steps <= 0)
       steps = (random() % 400) + 100;
 
-    delta_gam = 1.0 / steps;
+    deltaGamma = 1.0 / steps;
     XGetWindowAttributes(dpy, window, &wa);
+    scrWidth = wa.width;
+    scrHeight = wa.height;
     cmap = wa.colormap;
     gcv.foreground = get_pixel_resource("foreground", "Foreground", dpy, cmap);
     gcDraw = XCreateGC(dpy, window, GCForeground, &gcv);
@@ -423,13 +363,14 @@ static void initLMorph (void)
     gcClear = XCreateGC(dpy, window, GCForeground, &gcv);
     XClearWindow(dpy, window);
 
+    srandom(time(NULL));
     initPointArrays();
     aCurr = aWork[nWork = 0];
     aPrev = NULL;
-    gam = 2.0;
-    nTo = RND(cFig);
+    currGamma = maxGamma + 1.0;  /* force creation of new figure at startup */
+    nTo = RND(numFigs);
 
-    {
+    { /* jwz for version 2.11 */
       int width = random() % 10;
       int style = LineSolid;
       int cap   = (width > 1 ? CapRound  : CapButt);
@@ -438,45 +379,108 @@ static void initLMorph (void)
       XSetLineAttributes(dpy, gcDraw,  width, style, cap, join);
       XSetLineAttributes(dpy, gcClear, width, style, cap, join);
     }
+}
+
+/* 55% of execution time */
+static void
+createPoints(void)
+{
+    int             q;
+    XPoint *pa = aCurr, *pa1 = aFrom, *pa2 = aTo;
+#ifdef USE_FLOAT
+    float           fg, f1g;
+#else
+    long            lg, l1g;
+#endif
+
+#ifdef USE_FLOAT
+    fg  = currGamma;
+    f1g = 1.0 - currGamma;
+#else
+    lg  = 8192L * currGamma;
+    l1g = 8192L * (1.0 - currGamma);
+#endif
+    for (q = numPoints; q; q--) {
+#ifdef USE_FLOAT
+        pa->x = (short) (f1g * pa1->x + fg * pa2->x);
+        pa->y = (short) (f1g * pa1->y + fg * pa2->y);
+#else
+        pa->x = (short) ((l1g * pa1->x + lg * pa2->x) / 8192L);
+        pa->y = (short) ((l1g * pa1->y + lg * pa2->y) / 8192L);
+#endif
+        ++pa;
+        ++pa1;
+        ++pa2;
+    }
+}
+
+/* 36% of execution time */
+static void
+drawImage(void)
+{
+    int             q;
+    XPoint *old0, *old1, *new0, *new1;
+
+    /* Problem: update the window without too much flickering. I do
+     * this by handling each linesegment separately. First remove a
+     * line, then draw the new line. The problem is that this leaves
+     * small black pixels on the figure. To fix this, I draw the
+     * entire figure using XDrawLines() afterwards. */
+    if (aPrev) {
+       old0 = aPrev;
+       old1 = aPrev + 1;
+       new0 = aCurr;
+       new1 = aCurr + 1;
+       for (q = numPoints - 1; q; q--) {
+           XDrawLine(dpy, window, gcClear,
+                     old0->x, old0->y, old1->x, old1->y);
+           XDrawLine(dpy, window, gcDraw,
+                     new0->x, new0->y, new1->x, new1->y);
+           ++old0;
+           ++old1;
+           ++new0;
+           ++new1;
+       }
+    }
+    XDrawLines(dpy, window, gcDraw, aCurr, numPoints, CoordModeOrigin);
 
+    XFlush(dpy);
 }
 
-static void animateLMorph (void)
+/* neglectible % of execution time */
+static void
+animateLMorph(void)
 {
-    if (gam > maxGamma) {
-        gam = 0.0;
+    if (currGamma > maxGamma) {
+        currGamma = 0.0;
         if (maxGamma == 1.0) {
             nFrom = nTo;
             aFrom = a[nFrom];
         } else {
-            memcpy(aTmp, aCurr, cPoint * sizeof(XPoint));
+            memcpy(aTmp, aCurr, numPoints * sizeof(XPoint));
             aFrom = aTmp;
             nFrom = -1;
         }
         do {
-            nTo = RND(cFig);
+            nTo = RND(numFigs);
         } while (nTo == nFrom);
         aTo = a[nTo];
         if (RND(2)) {
-            /*
-             *  Reverse the array to get more variation.
-             */
+            /* reverse the array to get more variation. */
             int    i1, i2;
             XPoint p;
             
-            for (i1 = 0, i2 = cPoint - 1; i1 < cPoint / 2; i1++, i2--) {
+            for (i1 = 0, i2 = numPoints - 1; i1 < numPoints / 2; i1++, i2--) {
                 p = aTo[i1];
                 aTo[i1] = aTo[i2];
                 aTo[i2] = p;
             }
         }
-        /*
-         *  It may be nice to interrupt the next run.
-         */
-        if (RND(3) > 0)
-            maxGamma = 0.1 + 0.7 * (RND(1001) / 1000.0);
+        /* occationally interrupt the next run. */
+        if (RND(4) == 0)
+            maxGamma = 0.1 + 0.7 * (RND(1001) / 1000.0); /* partial run */
         else
-            maxGamma = 1.0;
+            maxGamma = 1.0;                              /* full run */
     }
 
     createPoints();
@@ -484,7 +488,7 @@ static void animateLMorph (void)
     aPrev = aCurr;
     aCurr = aWork[nWork ^= 1];
 
-    gam += delta_gam;
+    currGamma += deltaGamma;
 }