/* -*- 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 */