-
-/**************************************************************************
- *
- * FILE lmorph.c
- * MODULE OF xscreensaver
- *
- * 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
- * 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
- *
- * The original idea, and the bilinear interpolation
- * mathematics used, emerged in the head of the wise
- * Glenn Terje Lines.
+/* lmorph, Copyright (c) 1993-1999 Sverre H. Huseby and Glenn T. Lines
*
- * MODIFICATIONS march 1995
- * * Converted from an MS-Windows program to X Window.
- *
- **************************************************************************/
+ * 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.
+ */
+
+/*------------------------------------------------------------------------
+ |
+ | FILE lmorph.c
+ | MODULE OF xscreensaver
+ |
+ | DESCRIPTION Smooth and non-linear morphing between 1D curves.
+ |
+ | WRITTEN BY Sverre H. Huseby Glenn T. Lines
+ | Kurvn. 30 Østgaardsgt. 5
+ | N-0495 Oslo N-0474 Oslo
+ | Norway Norway
+ |
+ | Phone: +47 901 63 579 Phone: +47 22 04 67 28
+ | E-mail: sverrehu@online.no E-mail: glennli@ifi.uio.no
+ | URL: http://home.sol.no/~sverrehu/
+ |
+ | The original idea, and the bilinear interpolation
+ | mathematics used, emerged in the head of the wise
+ | Glenn T. Lines.
+ |
+ | MODIFICATIONS october 1999 (shh)
+ | * Removed option to use integer arithmetic.
+ | * Increased default number of points, and brightened
+ | the foreground color a little bit.
+ | * Minor code cleanup (very minor, that is).
+ | * Default number of steps is no longer random.
+ | * Added -linewidth option (and resource).
+ |
+ | october 1999 (gtl)
+ | * Added cubic interpolation between shapes
+ | * Added non-linear transformation speed
+ |
+ | june 1998 (shh)
+ | * Minor code cleanup.
+ |
+ | 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.
+ |
+ | november 1993 (gtl, shh, lots of beer)
+ | * Original Windows version (we didn't know better).
+ +----------------------------------------------------------------------*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include <math.h>
#include "screenhack.h"
-/**************************************************************************
- * *
- * P R I V A T E D A T A *
- * *
- **************************************************************************/
+/*-----------------------------------------------------------------------+
+| PRIVATE DATA |
++-----------------------------------------------------------------------*/
-/* Define MARGINS to make some space around the figure */
-#define MARGINS /**/
+/* define MARGINS to make some space around the figure. */
+#define MARGINS
#define MAXFIGS 20
#define TWO_PI (2.0 * M_PI)
#define RND(x) (random() % (x))
-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. */
-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;
-
-
-
-/**************************************************************************
- * *
- * P U B L I C D A T A *
- * *
- **************************************************************************/
-
-char *progclass = "LMorph";
-
-char *defaults [] = {
- "LMorph.background: black",
- "LMorph.foreground: green",
- "*points: 150",
- "*steps: 0",
- "*delay: 50000",
- 0
+
+#define FT_OPEN 1
+#define FT_CLOSED 2
+#define FT_ALL (FT_OPEN | FT_CLOSED)
+
+struct state {
+ Display *dpy;
+ Window window;
+
+ int numFigs; /* number of figure arrays. */
+ int numPoints; /* number of points in each array. */
+ int nWork; /* current work array number. */
+ int nFrom; /* current from array number. */
+ int nTo; /* current to array number. */
+ int nNext; /* current next array number (after to).*/
+ int shift; /* shifts the starting point of a figure */
+ int figType;
+
+ long delay; /* usecs to wait between updates. */
+
+ XPoint *aWork[2]; /* working arrays. */
+ XPoint *a[MAXFIGS]; /* the figure arrays. */
+ XPoint *aTmp; /* used as source when interrupting morph */
+ XPoint *aPrev; /* previous points displayed. */
+ XPoint *aCurr; /* the current points displayed. */
+ XPoint *aFrom; /* figure converting from. */
+ XPoint *aTo; /* figure converting to. */
+ XPoint *aNext; /* figure converting to next time. */
+ XPoint *aSlopeFrom; /* slope at start of morph */
+ XPoint *aSlopeTo; /* slope at end of morph */
+
+ int scrWidth, scrHeight;
+ double currGamma, maxGamma, deltaGamma;
+ GC gcDraw, gcClear;
};
-XrmOptionDescRec options [] = {
- { "-points", ".points", XrmoptionSepArg, 0 },
- { "-steps", ".steps", XrmoptionSepArg, 0 },
- { "-delay", ".delay", XrmoptionSepArg, 0 },
- { 0, 0, 0, 0 }
+
+/*-----------------------------------------------------------------------+
+| PUBLIC DATA |
++-----------------------------------------------------------------------*/
+
+static const char *lmorph_defaults [] = {
+ ".background: black",
+ ".foreground: #4444FF",
+ "*points: 200",
+ "*steps: 150",
+ "*delay: 70000",
+ "*figtype: all",
+ "*linewidth: 5",
+ 0
};
+static XrmOptionDescRec lmorph_options [] = {
+ { "-points", ".points", XrmoptionSepArg, 0 },
+ { "-steps", ".steps", XrmoptionSepArg, 0 },
+ { "-delay", ".delay", XrmoptionSepArg, 0 },
+ { "-figtype", ".figtype", XrmoptionSepArg, 0 },
+ { "-linewidth", ".linewidth", XrmoptionSepArg, 0 },
+ { 0, 0, 0, 0 }
+};
-/**************************************************************************
- * *
- * P R I V A T E F U N C T I O N S *
- * *
- **************************************************************************/
+/*-----------------------------------------------------------------------+
+| PRIVATE FUNCTIONS |
++-----------------------------------------------------------------------*/
static void *
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(struct state *st)
{
- XWindowAttributes wa;
- int q, w,
- mx, my, /* Max screen coordinates. */
- mp, /* Max point number. */
- s, rx, ry,
- marginx, marginy;
+ int q, w;
+ int mx, my; /* max screen coordinates. */
+ int mp; /* max point number. */
+ int s, rx, ry;
+ int 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 = st->scrWidth - 1;
+ my = st->scrHeight - 1;
+ mp = st->numPoints - 1;
+
+ st->aWork[0] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ st->aWork[1] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ st->aTmp = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+
+ if (st->figType & FT_CLOSED) {
+ /* rectangle */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ s = st->numPoints / 4;
+ for (q = 0; q < s; q++) {
+ st->a[st->numFigs][q].x = ((double) q / s) * mx;
+ st->a[st->numFigs][q].y = 0;
+ st->a[st->numFigs][s + q].x = mx;
+ st->a[st->numFigs][s + q].y = ((double) q / s) * my;
+ st->a[st->numFigs][2 * s + q].x = mx - ((double) q / s) * mx;
+ st->a[st->numFigs][2 * s + q].y = my;
+ st->a[st->numFigs][3 * s + q].x = 0;
+ st->a[st->numFigs][3 * s + q].y = my - ((double) q / s) * my;
+ }
+ for (q = 4 * s; q < st->numPoints; q++)
+ st->a[st->numFigs][q].x = st->a[st->numFigs][q].y = 0;
+ st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x;
+ st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y;
+ ++st->numFigs;
+
+ /* */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ rx = mx / 2;
+ ry = my / 2;
+ for (q = 0; q < st->numPoints; q++) {
+ st->a[st->numFigs][q].x = mx / 2 + rx * sin(1 * TWO_PI * (double) q / mp);
+ st->a[st->numFigs][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
+ }
+ st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x;
+ st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y;
+ ++st->numFigs;
+
+ /* */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ rx = mx / 2;
+ ry = my / 2;
+ for (q = 0; q < st->numPoints; q++) {
+ st->a[st->numFigs][q].x = mx / 2 + ry * sin(3 * TWO_PI * (double) q / mp);
+ st->a[st->numFigs][q].y = my / 2 + ry * cos(1 * TWO_PI * (double) q / mp);
+ }
+ st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x;
+ st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y;
+ ++st->numFigs;
+
+ /* */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ rx = mx / 2;
+ ry = my / 2;
+ for (q = 0; q < st->numPoints; q++) {
+ st->a[st->numFigs][q].x = mx / 2 + ry
+ * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
+ * sin(TWO_PI * (double) q / mp);
+ st->a[st->numFigs][q].y = my / 2 + ry
+ * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
+ * cos(TWO_PI * (double) q / mp);
+ }
+ st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x;
+ st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y;
+ ++st->numFigs;
+
+
+ /* */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ rx = mx / 2;
+ ry = my / 2;
+ for (q = 0; q < st->numPoints; q++) {
+ st->a[st->numFigs][q].x = mx / 2 + ry * sin(TWO_PI * (double) q / mp);
+ st->a[st->numFigs][q].y = my / 2 + ry * cos(TWO_PI * (double) q / mp);
+ }
+ st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x;
+ st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y;
+ ++st->numFigs;
+
+
+ /* */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ rx = mx / 2;
+ ry = my / 2;
+ for (q = 0; q < st->numPoints; q++) {
+ st->a[st->numFigs][q].x = mx / 2 + rx * cos(TWO_PI * (double) q / mp);
+ st->a[st->numFigs][q].y = my / 2 + ry * sin(TWO_PI * (double) q / mp);
+ }
+ st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x;
+ st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y;
+ ++st->numFigs;
+
+ /* */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ rx = mx / 2;
+ ry = my / 2;
+ for (q = 0; q < st->numPoints; q++) {
+ st->a[st->numFigs][q].x = mx / 2 + rx * sin(2 * TWO_PI * (double) q / mp);
+ st->a[st->numFigs][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
+ }
+ st->a[st->numFigs][mp].x = st->a[st->numFigs][0].x;
+ st->a[st->numFigs][mp].y = st->a[st->numFigs][0].y;
+ ++st->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 (st->figType & FT_OPEN) {
+ /* sine wave, one period */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ for (q = 0; q < st->numPoints; q++) {
+ st->a[st->numFigs][q].x = ((double) q / st->numPoints) * mx;
+ st->a[st->numFigs][q].y = (1.0 - sin(((double) q / mp) * TWO_PI))
+ * my / 2.0;
+ }
+ ++st->numFigs;
+
+ /* */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ for (q = 0; q < st->numPoints; q++) {
+ st->a[st->numFigs][q].x = ((double) q / mp) * mx;
+ st->a[st->numFigs][q].y = (1.0 - cos(((double) q / mp) * 3 * TWO_PI))
+ * my / 2.0;
+ }
+ ++st->numFigs;
+
+ /* spiral, one endpoint at bottom */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ rx = mx / 2;
+ ry = my / 2;
+ for (q = 0; q < st->numPoints; q++) {
+ st->a[st->numFigs][q].x = mx / 2 + ry * sin(5 * TWO_PI * (double) q / mp)
+ * ((double) q / mp);
+ st->a[st->numFigs][q].y = my / 2 + ry * cos(5 * TWO_PI * (double) q / mp)
+ * ((double) q / mp);
+ }
+ ++st->numFigs;
+
+ /* spiral, one endpoint at top */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ rx = mx / 2;
+ ry = my / 2;
+ for (q = 0; q < st->numPoints; q++) {
+ st->a[st->numFigs][q].x = mx / 2 + ry * sin(6 * TWO_PI * (double) q / mp)
+ * ((double) q / mp);
+ st->a[st->numFigs][q].y = my / 2 - ry * cos(6 * TWO_PI * (double) q / mp)
+ * ((double) q / mp);
+ }
+ ++st->numFigs;
+
+ /* */
+ st->a[st->numFigs] = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ for (q = 0; q < st->numPoints; q++) {
+ st->a[st->numFigs][q].x = ((double) q / mp) * mx;
+ st->a[st->numFigs][q].y = (1.0 - sin(((double) q / mp) * 5 * TWO_PI))
+ * my / 2.0;
+ }
+ ++st->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++) {
- a[q][w].x = marginx + a[q][w].x * scalex;
- a[q][w].y = marginy + a[q][w].y * scaley;
+ for (q = 0; q < st->numFigs; q++)
+ for (w = 0; w < st->numPoints; w++) {
+ st->a[q][w].x = marginx + st->a[q][w].x * scalex;
+ st->a[q][w].y = marginy + st->a[q][w].y * scaley;
}
#endif
}
+static void
+initLMorph(struct state *st)
+{
+ int steps;
+ XGCValues gcv;
+ XWindowAttributes wa;
+ Colormap cmap;
+ char *ft;
+ int i;
+
+ st->maxGamma = 1.0;
+ st->numPoints = get_integer_resource(st->dpy, "points", "Integer");
+ steps = get_integer_resource(st->dpy, "steps", "Integer");
+ st->delay = get_integer_resource(st->dpy, "delay", "Integer");
+ ft = get_string_resource(st->dpy, "figtype", "String");
+
+ if (strcmp(ft, "all") == 0)
+ st->figType = FT_ALL;
+ else if (strcmp(ft, "open") == 0)
+ st->figType = FT_OPEN;
+ else if (strcmp(ft, "closed") == 0)
+ st->figType = FT_CLOSED;
+ else {
+ fprintf(stderr, "figtype should be `all', `open' or `closed'.\n");
+ st->figType = FT_ALL;
+ }
+
+ if (steps <= 0)
+ steps = (random() % 400) + 100;
+
+ st->deltaGamma = 1.0 / steps;
+ XGetWindowAttributes(st->dpy, st->window, &wa);
+ st->scrWidth = wa.width;
+ st->scrHeight = wa.height;
+ cmap = wa.colormap;
+ gcv.foreground = get_pixel_resource(st->dpy, cmap, "foreground", "Foreground");
+ st->gcDraw = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
+ XSetForeground(st->dpy, st->gcDraw, gcv.foreground);
+ gcv.foreground = get_pixel_resource(st->dpy, cmap, "background", "Background");
+ st->gcClear = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
+ XClearWindow(st->dpy, st->window);
+
+ initPointArrays(st);
+ st->aCurr = st->aWork[st->nWork = 0];
+ st->aPrev = NULL;
+ st->currGamma = st->maxGamma + 1.0; /* force creation of new figure at startup */
+ st->nTo = RND(st->numFigs);
+ do {
+ st->nNext = RND(st->numFigs);
+ } while (st->nNext == st->nTo);
+
+ st->aSlopeTo = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ st->aSlopeFrom = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+ st->aNext = (XPoint *) xmalloc(st->numPoints * sizeof(XPoint));
+
+ for (i = 0; i < st->numPoints ; i++) {
+ st->aSlopeTo[i].x = 0.0;
+ st->aSlopeTo[i].y = 0.0;
+ }
+ { /* jwz for version 2.11 */
+ /* int width = random() % 10;*/
+ int width = get_integer_resource(st->dpy, "linewidth", "Integer");
+ int style = LineSolid;
+ int cap = (width > 1 ? CapRound : CapButt);
+ int join = (width > 1 ? JoinRound : JoinBevel);
+ if (width == 1)
+ width = 0;
+ XSetLineAttributes(st->dpy, st->gcDraw, width, style, cap, join);
+ XSetLineAttributes(st->dpy, st->gcClear, width, style, cap, join);
+ }
+}
-static void createPoints (void)
+/* 55% of execution time */
+static void
+createPoints(struct state *st)
{
int q;
- XPoint *pa = aCurr, *pa1 = aFrom, *pa2 = aTo;
- long lg, l1g;
+ XPoint *pa = st->aCurr, *pa1 = st->aFrom, *pa2 = st->aTo;
+ XPoint *qa1 = st->aSlopeFrom, *qa2 = st->aSlopeTo;
+ float fg, f1g;
+ float speed;
+
+ fg = st->currGamma;
+ f1g = 1.0 - st->currGamma;
+ for (q = st->numPoints; q; q--) {
+ speed = 0.45 * sin(TWO_PI * (double) (q + st->shift) / (st->numPoints - 1));
+ fg = st->currGamma + 1.67 * speed
+ * exp(-200.0 * (st->currGamma - 0.5 + 0.7 * speed)
+ * (st->currGamma - 0.5 + 0.7 * speed));
+
+ f1g = 1.0 - fg;
+ pa->x = (short) (f1g * f1g * f1g * pa1->x + f1g * f1g * fg
+ * (3 * pa1->x + qa1->x) + f1g * fg * fg
+ * (3 * pa2->x - qa2->x) + fg * fg * fg * pa2->x);
+ pa->y = (short) (f1g * f1g * f1g * pa1->y + f1g * f1g * fg
+ * (3 * pa1->y + qa1->y) + f1g * fg * fg
+ * (3 * pa2->y - qa2->y) + fg * fg * fg * pa2->y);
-
- 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;
+ ++qa1;
+ ++qa2;
}
}
-
-static void drawImage (void)
+/* 36% of execution time */
+static void
+drawImage(struct state *st)
{
- register int q;
+#if 0
+ 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,
+ /* 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, we draw the
+ * entire figure using XDrawLines() afterwards. */
+ if (st->aPrev) {
+ old0 = st->aPrev;
+ old1 = st->aPrev + 1;
+ new0 = st->aCurr;
+ new1 = st->aCurr + 1;
+ for (q = st->numPoints - 1; q; q--) {
+ XDrawLine(st->dpy, st->window, st->gcClear,
+ old0->x, old0->y, old1->x, old1->y);
+ XDrawLine(st->dpy, st->window, st->gcDraw,
new0->x, new0->y, new1->x, new1->y);
++old0;
++old1;
++new1;
}
}
- XDrawLines(dpy, window, gcDraw, aCurr, cPoint, CoordModeOrigin);
- XFlush(dpy);
-}
-
-static void initLMorph (void)
-{
- int steps;
- XGCValues gcv;
- XWindowAttributes wa;
- Colormap cmap;
-
- cPoint = get_integer_resource("points", "Integer");
- steps = get_integer_resource("steps", "Integer");
- delay = get_integer_resource("delay", "Integer");
-
- if (steps <= 0)
- steps = (random() % 400) + 100;
-
- delta_gam = 1.0 / steps;
- XGetWindowAttributes(dpy, window, &wa);
- cmap = wa.colormap;
- gcv.foreground = get_pixel_resource("foreground", "Foreground", dpy, cmap);
- gcDraw = XCreateGC(dpy, window, GCForeground, &gcv);
- XSetForeground(dpy, gcDraw, gcv.foreground);
- gcv.foreground = get_pixel_resource("background", "Background", dpy, cmap);
- gcClear = XCreateGC(dpy, window, GCForeground, &gcv);
- XClearWindow(dpy, window);
-
- initPointArrays();
- aCurr = aWork[nWork = 0];
- aPrev = NULL;
- gam = 2.0;
- nTo = RND(cFig);
-
- {
- int width = random() % 10;
- int style = LineSolid;
- int cap = (width > 1 ? CapRound : CapButt);
- int join = (width > 1 ? JoinRound : JoinBevel);
- if (width == 1) width = 0;
- XSetLineAttributes(dpy, gcDraw, width, style, cap, join);
- XSetLineAttributes(dpy, gcClear, width, style, cap, join);
- }
-
+#else
+ XClearWindow(st->dpy,st->window);
+#endif
+ XDrawLines(st->dpy, st->window, st->gcDraw, st->aCurr, st->numPoints, CoordModeOrigin);
}
-static void animateLMorph (void)
+/* neglectible % of execution time */
+static void
+animateLMorph(struct state *st)
{
- if (gam > maxGamma) {
- gam = 0.0;
- if (maxGamma == 1.0) {
- nFrom = nTo;
- aFrom = a[nFrom];
- } else {
- memcpy(aTmp, aCurr, cPoint * sizeof(XPoint));
- aFrom = aTmp;
- nFrom = -1;
- }
+ int i;
+ if (st->currGamma > st->maxGamma) {
+ st->currGamma = 0.0;
+ st->nFrom = st->nTo;
+ st->nTo = st->nNext;
+ st->aFrom = st->a[st->nFrom];
+ st->aTo = st->a[st->nTo];
do {
- nTo = RND(cFig);
- } while (nTo == nFrom);
- aTo = a[nTo];
+ st->nNext = RND(st->numFigs);
+ } while (st->nNext == st->nTo);
+ st->aNext = st->a[st->nNext];
+
+ st->shift = RND(st->numPoints);
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--) {
- p = aTo[i1];
- aTo[i1] = aTo[i2];
- aTo[i2] = p;
+ for (i1 = 0, i2 = st->numPoints - 1; i1 < st->numPoints / 2; i1++, i2--) {
+ p = st->aNext[i1];
+ st->aNext[i1] = st->aNext[i2];
+ st->aNext[i2] = p;
}
}
- /*
- * It may be nice to interrupt the next run.
- */
- if (RND(3) > 0)
- maxGamma = 0.1 + 0.7 * (RND(1001) / 1000.0);
- else
- maxGamma = 1.0;
+
+ /* calculate the slopes */
+ for (i = 0; i < st->numPoints ; i++) {
+ st->aSlopeFrom[i].x = st->aSlopeTo[i].x;
+ st->aSlopeFrom[i].y = st->aSlopeTo[i].y;
+ st->aSlopeTo[i].x = st->aNext[i].x - st->aTo[i].x;
+ st->aSlopeTo[i].y = (st->aNext[i].y - st->aTo[i].y);
+ }
}
- createPoints();
- drawImage();
- aPrev = aCurr;
- aCurr = aWork[nWork ^= 1];
+ createPoints(st);
+ drawImage(st);
+ st->aPrev = st->aCurr;
+ st->aCurr = st->aWork[st->nWork ^= 1];
- gam += delta_gam;
+ st->currGamma += st->deltaGamma;
}
+/*-----------------------------------------------------------------------+
+| PUBLIC FUNCTIONS |
++-----------------------------------------------------------------------*/
+static void *
+lmorph_init (Display *d, Window w)
+{
+ struct state *st = (struct state *) calloc (1, sizeof(*st));
+ st->dpy = d;
+ st->window = w;
+ initLMorph(st);
+ return st;
+}
-/**************************************************************************
- * *
- * P U B L I C F U N C T I O N S *
- * *
- **************************************************************************/
+static unsigned long
+lmorph_draw (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ animateLMorph(st);
+ return st->delay;
+}
-void
-screenhack(Display *disp, Window win)
+static void
+lmorph_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
{
- dpy = disp;
- window = win;
- initLMorph();
- for (;;) {
- animateLMorph();
- screenhack_usleep(delay);
- }
}
+
+static Bool
+lmorph_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ return False;
+}
+
+static void
+lmorph_free (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ free (st);
+}
+
+XSCREENSAVER_MODULE ("LMorph", lmorph)