summaryrefslogtreecommitdiffstats
path: root/hacks/lisa.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/lisa.c')
-rw-r--r--hacks/lisa.c739
1 files changed, 739 insertions, 0 deletions
diff --git a/hacks/lisa.c b/hacks/lisa.c
new file mode 100644
index 0000000..d0303b8
--- /dev/null
+++ b/hacks/lisa.c
@@ -0,0 +1,739 @@
+/* -*- Mode: C; tab-width: 4 -*- */
+/* lisa --- animated full-loop lissajous figures */
+
+#if 0
+static const char sccsid[] = "@(#)lisa.c 5.00 2000/11/01 xlockmore";
+#endif
+
+/*-
+ * Copyright (c) 1997, 2006 by Caleb Cullen.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind. The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof. In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * Revision History:
+ * 23-Feb-2006: fixed color-cycling issues
+ * 01-Nov-2000: Allocation checks
+ * 10-May-1997: Compatible with xscreensaver
+ *
+ * The inspiration for this program, Lasp, was written by Adam B. Roach
+ * in 1990, assisted by me, Caleb Cullen. It was written first in C, then
+ * in assembly, and used pre-calculated data tables to graph lissajous
+ * figures on 386 machines and lower. This version bears only superficial
+ * resemblances to the original Lasp.
+ *
+ * The `lissie' module's source code was studied as an example of how
+ * to incorporate a new module into xlock. Resemblances to it are
+ * expected, but not intended to be plaigiaristic.
+ *
+ * February, 2006: 21st Century Update for Lisa
+ * + fixed color-mapping: the 'beginning' of the loop always uses the
+ * same (starting) pixel value, causing the loop's coloration to
+ * appear solid rather than flickering as in the previous version
+ * + all lines/points in a single color are drawn at once using XDrawLines()
+ * or XDrawPoints(); the artifacting evident in the previous version
+ * has been masked by the use of CapNotLast to separate individual drawn
+ * areas with intentional "whitespace" (typically black)
+ * + added many new elements to the Function[] array
+ * + randomized selection of next function
+ * + introduced concept of "rarely-chosen" functions
+ * + cleaned up code somewhat, standardized capitalization, commented all
+ * #directives with block labels
+ */
+
+#ifdef STANDALONE
+# define MODE_lisa
+# define DEFAULTS "*delay: 17000 \n" \
+ "*count: 1 \n" \
+ "*cycles: 768 \n" \
+ "*size: 500 \n" \
+ "*ncolors: 64 \n" \
+ "*fpsSolid: true \n" \
+ "*lowrez: True \n" \
+
+# define UNIFORM_COLORS
+# define release_lisa 0
+# define reshape_lisa 0
+# define lisa_handle_event xlockmore_no_events
+# include "xlockmore.h" /* in xscreensaver distribution */
+#else /* STANDALONE */
+#include "xlock.h" /* in xlockmore distribution */
+
+#endif /* STANDALONE */
+
+#ifdef MODE_lisa
+
+#define DEF_ADDITIVE "True"
+
+static Bool additive;
+
+static XrmOptionDescRec opts[] =
+{
+ {"-additive", ".lisa.additive", XrmoptionNoArg, "True"},
+ {"+additive", ".lisa.additive", XrmoptionNoArg, "False"}
+};
+
+static argtype vars[] =
+{
+ {&additive, "additive", "Additive", DEF_ADDITIVE, t_Bool}
+};
+
+static OptionStruct desc[] =
+{
+ {"-/+additive", "turn on/off additive functions mode"}
+};
+
+ENTRYPOINT ModeSpecOpt lisa_opts =
+{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
+
+#ifdef USE_MODULES
+ModStruct lisa_description =
+{"lisa", "init_lisa", "draw_lisa", (char *) NULL,
+ "refresh_lisa", "change_lisa", "free_lisa", &lisa_opts,
+ 17000, 1, 768, -1, 64, 1.0, "",
+ "Shows animated lissajous figures", 0, NULL};
+
+#endif
+
+#define DRAWLINES 1
+/* #define FOLLOW_FUNC_ORDER 1 */
+#define TWOLOOPS 1
+#define XVMAX 10 /* Maximum velocities */
+#define YVMAX 10
+#define LISAMAXFUNCS 2
+#define NUMSTDFUNCS 28
+#define RAREFUNCMIN 25
+#define RAREFUNCODDS 4 /* 1:n chance a rare function will be re-randomized */
+#define MAXCYCLES 3
+#define MINLISAS 1
+#define STARTCOLOR 0
+#define STARTFUNC 24 /* if negative, is upper-bound on randomization */
+#define LINEWIDTH -8 /* if negative, is upper-bound on randomization */
+#define LINESTYLE LineSolid /* an insane man might have fun with this :) */
+#define LINECAP CapNotLast /* anything else looks pretty crappy */
+#define LINEJOIN JoinBevel /* this ought to be fastest */
+#define SET_COLOR() \
+ if (MI_NPIXELS(mi) > 2) { \
+ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_PIXEL(mi, loop->color)); \
+ if (loop->cstep \
+ && pctr % loop->cstep == 0 \
+ && ++(loop->color) >= (unsigned) MI_NPIXELS(mi)) \
+ { loop->color=STARTCOLOR; } \
+ } else { XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); }
+#define GET_RADIUS(context) \
+ ((context->width > context->height)?context->height:context->width) * 3 / 8
+#define CHECK_RADIUS(loop, context) \
+ if ((context->height / 2 > MI_SIZE(mi)) && (context->width / 2 > MI_SIZE(mi))) \
+ loop->radius = MI_SIZE(mi); \
+ if ((loop->radius < 0) || \
+ (loop->radius > loop->center.x) || \
+ (loop->radius > loop->center.y)) loop->radius = GET_RADIUS(context)
+#define PRINT_FUNC(funcptr) \
+ printf("new function -- #%d:\n\tx = sin(%gs) * sin(%gs)\n\ty = sin(%gt) * sin(%gt)\n", \
+ funcptr->index, \
+ funcptr->xcoeff[0], funcptr->xcoeff[1], \
+ funcptr->ycoeff[0], funcptr->ycoeff[1])
+
+
+typedef struct lisafunc_struct {
+ double xcoeff[2], ycoeff[2];
+ int nx, ny;
+ int index;
+} lisafuncs;
+
+typedef struct lisa_struct {
+ unsigned long color;
+ int radius, dx, dy, nsteps, nfuncs, melting, cstep;
+ double pistep, phi, theta;
+ XPoint center, *lastpoint;
+ lisafuncs *function[LISAMAXFUNCS];
+ int linewidth;
+} lisas;
+
+typedef struct lisacontext_struct {
+ lisas *lissajous;
+ int width, height, nlissajous, loopcount;
+ int maxcycles;
+ Bool painted;
+} lisacons;
+
+static lisacons *Lisa = (lisacons *) NULL;
+
+static lisafuncs Function[NUMSTDFUNCS] =
+ {
+ {
+ {1.0, 2.0},
+ {1.0, 2.0}, 2, 2, 0},
+ {
+ {1.0, 2.0},
+ {1.0, 1.0}, 2, 2, 1},
+ {
+ {1.0, 3.0},
+ {1.0, 2.0}, 2, 2, 2},
+ {
+ {1.0, 3.0},
+ {1.0, 3.0}, 2, 2, 3},
+ {
+ {2.0, 4.0},
+ {1.0, 2.0}, 2, 2, 4},
+ {
+ {1.0, 4.0},
+ {1.0, 3.0}, 2, 2, 5},
+ {
+ {1.0, 4.0},
+ {1.0, 4.0}, 2, 2, 6},
+ {
+ {1.0, 5.0},
+ {1.0, 5.0}, 2, 2, 7},
+ {
+ {2.0, 5.0},
+ {2.0, 5.0}, 2, 2, 8},
+ {
+ {1.0, 2.0},
+ {2.0, 5.0}, 2, 2, 9},
+ {
+ {1.0, 2.0},
+ {3.0, 5.0}, 2, 2, 10},
+ {
+ {1.0, 2.0},
+ {2.0, 3.0}, 2, 2, 11},
+ {
+ {1.0, 3.0},
+ {2.0, 3.0}, 2, 2, 12},
+ {
+ {2.0, 3.0},
+ {1.0, 3.0}, 2, 2, 13},
+ {
+ {2.0, 4.0},
+ {1.0, 3.0}, 2, 2, 14},
+ {
+ {1.0, 4.0},
+ {2.0, 3.0}, 2, 2, 15},
+ {
+ {2.0, 4.0},
+ {2.0, 3.0}, 2, 2, 16},
+ {
+ {1.0, 5.0},
+ {2.0, 3.0}, 2, 2, 17},
+ {
+ {2.0, 5.0},
+ {2.0, 3.0}, 2, 2, 18},
+ {
+ {1.0, 5.0},
+ {2.0, 5.0}, 2, 2, 19},
+ {
+ {1.0, 3.0},
+ {2.0, 7.0}, 2, 2, 20},
+ {
+ {2.0, 3.0},
+ {5.0, 7.0}, 2, 2, 21},
+ {
+ {1.0, 2.0},
+ {3.0, 7.0}, 2, 2, 22},
+ {
+ {2.0, 5.0},
+ {5.0, 7.0}, 2, 2, 23},
+ {
+ {5.0, 7.0},
+ {5.0, 7.0}, 2, 2, 24},
+ { /* functions past here are 'rare' and won't */
+ {2.0, 7.0}, /* show up as often. tweak the #defines above */
+ {1.0, 7.0}, 2, 2, 25}, /* to see them more frequently */
+ {
+ {2.0, 9.0},
+ {1.0, 7.0}, 2, 2, 26},
+ {
+ {5.0, 11.0},
+ {2.0, 9.0}, 2, 2, 27}
+};
+
+int xMaxLines;
+
+ENTRYPOINT void
+free_lisa(ModeInfo * mi)
+{
+ lisacons *lc = &Lisa[MI_SCREEN(mi)];
+ while (lc->lissajous) {
+ int lctr;
+
+ for (lctr = 0; lctr < lc->nlissajous; lctr++) {
+ (void) free((void *) lc->lissajous[lctr].lastpoint);
+ }
+ (void) free((void *) lc->lissajous);
+ lc->lissajous = (lisas *) NULL;
+ }
+}
+
+static Bool
+drawlisa(ModeInfo * mi, lisas * loop)
+{
+ XPoint *np;
+ XPoint *lp = loop->lastpoint;
+ lisacons *lc = &Lisa[MI_SCREEN(mi)];
+ lisafuncs **lf = loop->function;
+ int phase = lc->loopcount % loop->nsteps;
+ int pctr, fctr, xctr, yctr, extra_points;
+ double xprod, yprod, xsum, ysum;
+
+ /* why carry this around in the struct when we can calculate it on demand? */
+ extra_points = loop->cstep - (loop->nsteps % loop->cstep);
+
+ /* Allocate the np (new point) array (with padding) */
+ if ((np = (XPoint *) calloc(loop->nsteps+extra_points, sizeof (XPoint))) == NULL) {
+ free_lisa(mi);
+ return False;
+ }
+
+ /* Update the center */
+ loop->center.x += loop->dx;
+ loop->center.y += loop->dy;
+ CHECK_RADIUS(loop, lc);
+
+ /* check for overlaps -- where the figure might go off the screen */
+
+ if ((loop->center.x - loop->radius) <= 0) {
+ loop->center.x = loop->radius;
+ loop->dx = NRAND(XVMAX);
+ } else if ((loop->center.x + loop->radius) >= lc->width) {
+ loop->center.x = lc->width - loop->radius;
+ loop->dx = -NRAND(XVMAX);
+ };
+ if ((loop->center.y - loop->radius) <= 0) {
+ loop->center.y = loop->radius;
+ loop->dy = NRAND(YVMAX);
+ } else if ((loop->center.y + loop->radius) >= lc->height) {
+ loop->center.y = lc->height - loop->radius;
+ loop->dy = -NRAND(YVMAX);
+ };
+
+ /* Now draw the points, and erase the ones from the last cycle */
+
+ for (pctr = 0; pctr < loop->nsteps; pctr++) {
+ fctr = loop->nfuncs;
+ loop->phi = (double) (pctr - phase) * loop->pistep;
+ loop->theta = (double) (pctr + phase) * loop->pistep;
+ xsum = ysum = 0;
+ while (fctr--) {
+ xctr = lf[fctr]->nx;
+ yctr = lf[fctr]->ny;
+ if (additive) {
+ xprod = yprod = 0.0;
+ while (xctr--)
+ xprod += sin(lf[fctr]->xcoeff[xctr] * loop->theta);
+ while (yctr--)
+ yprod += sin(lf[fctr]->ycoeff[yctr] * loop->phi);
+ if (loop->melting) {
+ if (fctr) {
+ xsum += xprod * (double) (loop->nsteps - loop->melting) /
+ (double) loop->nsteps;
+ ysum += yprod * (double) (loop->nsteps - loop->melting) /
+ (double) loop->nsteps;
+ } else {
+ xsum += xprod * (double) loop->melting / (double) loop->nsteps;
+ ysum += yprod * (double) loop->melting / (double) loop->nsteps;
+ }
+ } else {
+ xsum = xprod;
+ ysum = yprod;
+ }
+ if (!fctr) {
+ xsum = xsum * (double) loop->radius / (double) lf[fctr]->nx;
+ ysum = ysum * (double) loop->radius / (double) lf[fctr]->ny;
+ }
+ } else {
+ if (loop->melting) {
+ if (fctr) {
+ yprod = xprod = (double) loop->radius *
+ (double) (loop->nsteps - loop->melting) /
+ (double) (loop->nsteps);
+ } else {
+ yprod = xprod = (double) loop->radius *
+ (double) (loop->melting) / (double) (loop->nsteps);
+ }
+ } else {
+ xprod = yprod = (double) loop->radius;
+ }
+ while (xctr--)
+ xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta);
+ while (yctr--)
+ yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi);
+ xsum += xprod;
+ ysum += yprod;
+ }
+ }
+ if ((loop->nfuncs > 1) && (!loop->melting)) {
+ xsum /= (double) loop->nfuncs;
+ ysum /= (double) loop->nfuncs;
+ }
+ xsum += (double) loop->center.x;
+ ysum += (double) loop->center.y;
+
+ np[pctr].x = (int) ceil(xsum);
+ np[pctr].y = (int) ceil(ysum);
+ }
+ /* fill in extra points */
+ for (pctr=loop->nsteps; pctr < loop->nsteps+extra_points; pctr++) {
+ np[pctr].x = np[pctr - loop->nsteps].x;
+ np[pctr].y = np[pctr - loop->nsteps].y;
+ }
+ if (loop->melting) {
+ if (!--loop->melting) {
+ loop->nfuncs = 1;
+ loop->function[0] = loop->function[1];
+ }
+ }
+
+ /* reset starting color each time to prevent ass-like appearance */
+ loop->color = STARTCOLOR;
+
+ if (loop->cstep < xMaxLines) {
+ /* printf("Drawing dashes\n"); */
+ for (pctr = 0; pctr < loop->nsteps; pctr+=loop->cstep) {
+#if defined DRAWLINES
+ XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth,
+ LINESTYLE, LINECAP, LINEJOIN);
+ /* erase the last cycle's point */
+ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
+ XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), &lp[pctr],
+ loop->cstep, CoordModeOrigin);
+
+ /* Set the new color */
+ SET_COLOR();
+
+ /* plot this cycle's point */
+ XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
+ &np[pctr], loop->cstep, CoordModeOrigin);
+ XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1,
+ LINESTYLE, LINECAP, LINEJOIN);
+#else
+ /* erase the last cycle's point */
+ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
+ XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
+ &lp[pctr], loop->cstep, CoordModeOrigin);
+
+ /* Set the new color */
+ SET_COLOR();
+
+ /* plot this cycle's point */
+ XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi),
+ MI_GC(mi), &np[pctr], loop->cstep, CoordModeOrigin);
+#endif
+ }
+ } else { /* on my system, cstep is larger than 65532/2 if we get here */
+ for (pctr = 0; pctr < loop->nsteps; pctr++) {
+#if defined DRAWLINES
+ XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth,
+ LINESTYLE, LINECAP, LINEJOIN);
+ /* erase the last cycle's point */
+ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
+ XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi),
+ MI_GC(mi), lp[pctr].x, lp[pctr].y,
+ lp[(pctr + 1) % loop->nsteps].x,
+ lp[(pctr + 1) % loop->nsteps].y);
+
+ /* Set the new color */
+ SET_COLOR();
+
+ /* plot this cycle's point */
+ XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi),
+ MI_GC(mi), np[pctr].x, np[pctr].y,
+ np[(pctr + 1) % loop->nsteps].x,
+ np[(pctr + 1) % loop->nsteps].y);
+ XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1,
+ LINESTYLE, LINECAP, LINEJOIN);
+#else /* DRAWLINES */
+ /* erase the last cycle's point */
+ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
+ XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi),
+ MI_GC(mi), lp[pctr].x, lp[pctr].y);
+
+ /* Set the new color */
+ SET_COLOR();
+
+ /* plot this cycle's point */
+ XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi),
+ MI_GC(mi), np[pctr].x, np[pctr].y);
+#endif /* DRAWLINES */
+ }
+ }
+ (void) free((void *) lp);
+ loop->lastpoint = np;
+ return True;
+}
+
+static Bool
+initlisa(ModeInfo * mi, lisas * loop)
+{
+ lisacons *lc = &Lisa[MI_SCREEN(mi)];
+ lisafuncs **lf = loop->function;
+ XPoint *lp;
+ int phase, pctr, fctr, xctr, yctr, extra_points;
+ double xprod, yprod, xsum, ysum;
+
+ xMaxLines = (XMaxRequestSize(MI_DISPLAY(mi))-3)/2;
+ /* printf("Got xMaxLines = %d\n", xMaxLines); */
+ loop->nsteps = MI_CYCLES(mi);
+ if (loop->nsteps == 0)
+ loop->nsteps = 1;
+ if (MI_NPIXELS(mi) > 2) {
+ loop->color = STARTCOLOR;
+ loop->cstep = (loop->nsteps > MI_NPIXELS(mi)) ? loop->nsteps / MI_NPIXELS(mi) : 1;
+ } else {
+ loop->color = MI_WHITE_PIXEL(mi);
+ loop->cstep = 0;
+ }
+ extra_points = loop->cstep - (loop->nsteps % loop->cstep);
+ lc->maxcycles = (MAXCYCLES * loop->nsteps) - 1;
+ loop->cstep = ( loop->nsteps > MI_NPIXELS(mi) ) ? loop->nsteps / MI_NPIXELS(mi) : 1;
+ /* printf("Got cstep = %d\n", loop->cstep); */
+ loop->melting = 0;
+ loop->nfuncs = 1;
+ loop->pistep = 2.0 * M_PI / (double) loop->nsteps;
+ loop->center.x = lc->width / 2;
+ loop->center.y = lc->height / 2;
+ loop->radius = (int) MI_SIZE(mi);
+ CHECK_RADIUS(loop, lc);
+ loop->dx = NRAND(XVMAX);
+ loop->dy = NRAND(YVMAX);
+ loop->dx++;
+ loop->dy++;
+#if defined STARTFUNC
+ lf[0] = &Function[STARTFUNC];
+#else /* STARTFUNC */
+ lf[0] = &Function[NRAND(NUMSTDFUNCS)];
+#endif /* STARTFUNC */
+
+ if ((lp = loop->lastpoint = (XPoint *)
+ calloc(loop->nsteps+extra_points, sizeof (XPoint))) == NULL) {
+ free_lisa(mi);
+ return False;
+ }
+ phase = lc->loopcount % loop->nsteps;
+
+#if defined DEBUG
+ printf( "nsteps = %d\tcstep = %d\tmrs = %d\textra_points = %d\n",
+ loop->nsteps, loop->cstep, xMaxLines, extra_points );
+ PRINT_FUNC(lf[0]);
+#endif /* DEBUG */
+
+ for (pctr = 0; pctr < loop->nsteps; pctr++) {
+ loop->phi = (double) (pctr - phase) * loop->pistep;
+ loop->theta = (double) (pctr + phase) * loop->pistep;
+ fctr = loop->nfuncs;
+ xsum = ysum = 0.0;
+ while (fctr--) {
+ xprod = yprod = (double) loop->radius;
+ xctr = lf[fctr]->nx;
+ yctr = lf[fctr]->ny;
+ while (xctr--)
+ xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta);
+ while (yctr--)
+ yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi);
+ xsum += xprod;
+ ysum += yprod;
+ }
+ if (loop->nfuncs > 1) {
+ xsum /= 2.0;
+ ysum /= 2.0;
+ }
+ xsum += (double) loop->center.x;
+ ysum += (double) loop->center.y;
+
+ lp[pctr].x = (int) ceil(xsum);
+ lp[pctr].y = (int) ceil(ysum);
+ }
+ /* this fills in the extra points, so we can use segment-drawing calls */
+ for (pctr = loop->nsteps; pctr < loop->nsteps + extra_points; pctr++) {
+ lp[pctr].x=lp[pctr - loop->nsteps].x;
+ lp[pctr].y=lp[pctr - loop->nsteps].y;
+ }
+#if defined DRAWLINES
+ loop->linewidth = LINEWIDTH; /* #### make this a resource */
+
+ if (loop->linewidth == 0)
+ loop->linewidth = 1;
+ if (loop->linewidth < 0)
+ loop->linewidth = NRAND(-loop->linewidth) + 1;
+ XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth,
+ LINESTYLE, LINECAP, LINEJOIN);
+#endif /* DRAWLINES */
+
+ if ( loop->cstep < xMaxLines ) {
+ /* we can send each color segment in a single request
+ * because the max request length is long enough
+ * and because we have padded out the array to have extra elements
+ * to support calls which would otherwise fall off the end*/
+ for (pctr = 0; pctr < loop->nsteps; pctr+=loop->cstep) {
+ /* Set the color */
+ SET_COLOR();
+
+#if defined DRAWLINES
+ XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi),
+ MI_GC(mi), &lp[pctr], loop->cstep, CoordModeOrigin );
+#else /* DRAWLINES */
+ XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
+ &lp[pctr], loop->cstep, CoordModeOrigin );
+#endif /* DRAWLINES */
+ }
+ } else { /* do it one by one as before */
+ for (pctr = 0; pctr < loop->nsteps; pctr++ ) {
+ SET_COLOR();
+
+#if defined DRAWLINES
+ XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
+ lp[pctr].x, lp[pctr].y,
+ lp[pctr+1 % loop->nsteps].x, lp[pctr+1 % loop->nsteps].y);
+#else /* DRAWLINES */
+ XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
+ lp[pctr].x, lp[pctr].y);
+#endif /* DRAWLINES */
+ }
+ }
+
+#if defined DRAWLINES
+ XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1,
+ LINESTYLE, LINECAP, LINEJOIN);
+#endif /* DRAWLINES */
+ return True;
+}
+
+static void
+refreshlisa(ModeInfo * mi)
+{
+ lisacons *lc = &Lisa[MI_SCREEN(mi)];
+ int lctr;
+
+ for (lctr = 0; lctr < lc->nlissajous; lctr++) {
+ if (!drawlisa(mi, &lc->lissajous[lctr]))
+ return;
+ }
+}
+
+#ifndef STANDALONE
+ENTRYPOINT void
+refresh_lisa(ModeInfo * mi)
+{
+ lisacons *lc;
+
+ if (Lisa == NULL)
+ return;
+ lc = &Lisa[MI_SCREEN(mi)];
+ if (lc->lissajous == NULL)
+ return;
+
+ if (lc->painted) {
+ lc->painted = False;
+ MI_CLEARWINDOW(mi);
+ refreshlisa(mi);
+ }
+}
+#endif
+
+static void
+change_lisa(ModeInfo * mi)
+{
+ lisas *loop;
+ int lctr, newfunc;
+ lisacons *lc;
+
+ if (Lisa == NULL)
+ return;
+ lc = &Lisa[MI_SCREEN(mi)];
+ if (lc->lissajous == NULL)
+ return;
+
+ lc->loopcount = 0;
+ for (lctr = 0; lctr < lc->nlissajous; lctr++) {
+ loop = &lc->lissajous[lctr]; /* count through the loops we're drawing */
+ newfunc = NRAND(NUMSTDFUNCS); /* choose a new function at random */
+#if defined FOLLOW_FUNC_ORDER
+ loop->function[1] =
+ &Function[(loop->function[0]->index + 1) % NUMSTDFUNCS];
+#else /* FOLLOW_FUNC_ORDER */
+ if (newfunc == loop->function[0]->index) {
+ ++newfunc;
+ newfunc %= NUMSTDFUNCS; /* take the next if we got the one we have */
+ }
+ if (newfunc >= RAREFUNCMIN \
+ && !(random() % RAREFUNCODDS) \
+ && (newfunc = NRAND(NUMSTDFUNCS)) == loop->function[0]->index) {
+ ++newfunc;
+ newfunc %= NUMSTDFUNCS;
+ }
+ loop->function[1] = /* set 2nd function pointer on the loop */
+ &Function[newfunc]; /* to the new function we just chose */
+#endif /* FOLLOW_FUNC_ORDER */
+#if defined DEBUG
+ PRINT_FUNC(loop->function[1]);
+#endif /* DEBUG */
+ loop->melting = loop->nsteps - 1; /* melt the two functions together */
+ loop->nfuncs = 2; /* simultaneously for a full cycle */
+ }
+}
+
+ENTRYPOINT void
+init_lisa (ModeInfo * mi)
+{
+ int lctr;
+ lisacons *lc;
+
+ MI_INIT (mi, Lisa);
+ lc = &Lisa[MI_SCREEN(mi)];
+ lc->width = MI_WIDTH(mi);
+ lc->height = MI_HEIGHT(mi);
+ lc->loopcount = 0;
+ lc->nlissajous = MI_COUNT(mi);
+ if (lc->nlissajous <= 0)
+ lc->nlissajous = 1;
+ MI_CLEARWINDOW(mi);
+ lc->painted = False;
+
+ if (lc->lissajous == NULL) {
+ if ((lc->lissajous = (lisas *) calloc(lc->nlissajous,
+ sizeof (lisas))) == NULL)
+ return;
+ for (lctr = 0; lctr < lc->nlissajous; lctr++) {
+ if (!initlisa(mi, &lc->lissajous[lctr]))
+ return;
+ lc->loopcount++;
+ }
+ } else {
+ refreshlisa(mi);
+ }
+}
+
+ENTRYPOINT void
+draw_lisa (ModeInfo * mi)
+{
+ lisacons *lc;
+
+ if (Lisa == NULL)
+ return;
+ lc = &Lisa[MI_SCREEN(mi)];
+ if (lc->lissajous == NULL)
+ return;
+
+#ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */
+ XClearWindow (MI_DISPLAY(mi), MI_WINDOW(mi));
+#endif
+
+ MI_IS_DRAWN(mi) = True;
+ lc->painted = True;
+ if (++lc->loopcount > lc->maxcycles) {
+ change_lisa(mi);
+ }
+ refreshlisa(mi);
+}
+
+XSCREENSAVER_MODULE ("Lisa", lisa)
+
+#endif /* MODE_lisa */