X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Flisa.c;h=1a1159f62cdfadc9d4840033b6801d98d2b89497;hb=4361b69d3178d7fc98d0388f9a223af6c2651aba;hp=af680ea2057e4a3e4ff80c174011fc38943c659a;hpb=5b7bc6e70fb439cf4c4bf771ae9f94077fe4fe08;p=xscreensaver diff --git a/hacks/lisa.c b/hacks/lisa.c index af680ea2..1a1159f6 100644 --- a/hacks/lisa.c +++ b/hacks/lisa.c @@ -1,11 +1,12 @@ /* -*- Mode: C; tab-width: 4 -*- */ -/* lisa --- animated full-loop lisajous figures */ +/* lisa --- animated full-loop lissajous figures */ -#if !defined( lint ) && !defined( SABER ) -static const char sccsid[] = "@(#)lisa.c 4.04 97/07/28 xlockmore"; +#if 0 +static const char sccsid[] = "@(#)lisa.c 5.00 2000/11/01 xlockmore"; #endif -/* Copyright (c) 1997 by Caleb Cullen. +/*- + * 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, @@ -20,82 +21,125 @@ static const char sccsid[] = "@(#)lisa.c 4.04 97/07/28 xlockmore"; * other special, indirect and consequential damages. * * Revision History: - * 10-May-97: Compatible with xscreensaver + * 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 + * 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 lisajous + * 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 PROGCLASS "Lisa" -# define HACK_INIT init_lisa -# define HACK_DRAW draw_lisa -# define lisa_opts xlockmore_opts -# define DEFAULTS "*delay: 25000 \n" \ - "*count: 1 \n" \ - "*cycles: 256 \n" \ - "*size: -1 \n" \ - "*ncolors: 200 \n" +# define MODE_lisa +# define DEFAULTS "*delay: 17000 \n" \ + "*count: 1 \n" \ + "*cycles: 768 \n" \ + "*size: 500 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + # define UNIFORM_COLORS -# include "xlockmore.h" /* from the xscreensaver distribution */ - void refresh_lisa(ModeInfo * mi); - void change_lisa(ModeInfo * mi); -#else /* !STANDALONE */ -# include "xlock.h" /* from the xlockmore distribution */ -#endif /* !STANDALONE */ +# define reshape_lisa 0 +# define lisa_handle_event 0 +# 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 lisa_xrm_opts[] = +static XrmOptionDescRec opts[] = { - {"-additive", ".lisa.additive", XrmoptionNoArg, (caddr_t) "True"}, - {"+additive", ".lisa.additive", XrmoptionNoArg, (caddr_t) "False"} + {"-additive", ".lisa.additive", XrmoptionNoArg, "True"}, + {"+additive", ".lisa.additive", XrmoptionNoArg, "False"} }; -static argtype lisa_vars[] = +static argtype vars[] = { - {(caddr_t *) & additive, "additive", "Additive", DEF_ADDITIVE, t_Bool} + {&additive, "additive", "Additive", DEF_ADDITIVE, t_Bool} }; -static OptionStruct lisa_vars_desc[] = +static OptionStruct desc[] = { {"-/+additive", "turn on/off additive functions mode"} }; -ModeSpecOpt lisa_opts = -{2, lisa_xrm_opts, 1, lisa_vars, lisa_vars_desc}; +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", "release_lisa", + "refresh_lisa", "change_lisa", (char *) NULL, &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 10 +#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 lisasetcolor() \ -if (MI_NPIXELS(mi) > 2) { \ - XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_PIXEL(mi, loop->color)); \ - if (++(loop->color) >= MI_NPIXELS(mi)) { loop->color=0; } \ - } else { XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_WHITE_PIXEL(mi)); } -#define getRadius(context) \ - ((context->width > context->height)?context->height:context->width) * 3 / 8 -#define checkRadius(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 = getRadius(context) +#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 { @@ -105,55 +149,128 @@ typedef struct lisafunc_struct { } lisafuncs; typedef struct lisa_struct { - int radius, color, dx, dy, nsteps, nfuncs, melting; - double pistep, phi, theta; - XPoint center, *lastpoint; - lisafuncs *function[LISAMAXFUNCS]; + 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 *lisajous; - int width, height, nlisajous, loopcount; + lisas *lissajous; + int width, height, nlissajous, loopcount; int maxcycles; + Bool painted; } lisacons; -static lisacons *Lisa = NULL; +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}, - {1.0, 2.0}, 2, 2, 0}, + {1.0, 2.0}, + {2.0, 5.0}, 2, 2, 9}, { - {1.0, 2.0}, - {1.0, 1.0}, 2, 2, 1}, + {1.0, 2.0}, + {3.0, 5.0}, 2, 2, 10}, { - {1.0, 3.0}, - {1.0, 2.0}, 2, 2, 2}, + {1.0, 2.0}, + {2.0, 3.0}, 2, 2, 11}, { - {1.0, 3.0}, - {1.0, 3.0}, 2, 2, 3}, + {1.0, 3.0}, + {2.0, 3.0}, 2, 2, 12}, { - {2.0, 4.0}, - {1.0, 2.0}, 2, 2, 4}, + {2.0, 3.0}, + {1.0, 3.0}, 2, 2, 13}, { - {1.0, 4.0}, - {1.0, 3.0}, 2, 2, 5}, + {2.0, 4.0}, + {1.0, 3.0}, 2, 2, 14}, { - {1.0, 4.0}, - {1.0, 4.0}, 2, 2, 6}, + {1.0, 4.0}, + {2.0, 3.0}, 2, 2, 15}, { - {1.0, 5.0}, - {1.0, 5.0}, 2, 2, 7}, + {2.0, 4.0}, + {2.0, 3.0}, 2, 2, 16}, { - {2.0, 5.0}, - {2.0, 5.0}, 2, 2, 8}, + {1.0, 5.0}, + {2.0, 3.0}, 2, 2, 17}, { - {1.0, 0.0}, - {1.0, 0.0}, 1, 1, 9} + {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; + static void +free_lisa(lisacons *lc) +{ + 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; @@ -161,16 +278,25 @@ drawlisa(ModeInfo * mi, lisas * loop) lisacons *lc = &Lisa[MI_SCREEN(mi)]; lisafuncs **lf = loop->function; int phase = lc->loopcount % loop->nsteps; - int pctr, fctr, xctr, yctr; + int pctr, fctr, xctr, yctr, extra_points; double xprod, yprod, xsum, ysum; - /* Allocate the np array */ - np = (XPoint *) calloc(loop->nsteps, sizeof (XPoint)); + /* 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(lc); + return False; + } /* Update the center */ loop->center.x += loop->dx; loop->center.y += loop->dy; - checkRadius(loop, lc); + 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); @@ -204,42 +330,31 @@ drawlisa(ModeInfo * mi, lisas * loop) 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; + 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; + 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; + 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); + 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); + yprod = xprod = (double) loop->radius * + (double) (loop->melting) / (double) (loop->nsteps); } } else { xprod = yprod = (double) loop->radius; @@ -262,224 +377,371 @@ drawlisa(ModeInfo * mi, lisas * loop) 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]; } } - for (pctr = 0; pctr < loop->nsteps; pctr++) { + /* 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_WIN_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); + 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 */ - lisasetcolor(); + 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); + 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_WIN_BLACK_PIXEL(mi)); - XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), \ - MI_GC(mi), lp[pctr].x, lp[pctr].y); + 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 */ - lisasetcolor(); + SET_COLOR(); /* plot this cycle's point */ - XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), \ - MI_GC(mi), np[pctr].x, np[pctr].y); + 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 void +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; - double xprod, yprod, xsum, ysum; - - if (MI_NPIXELS(mi) > 2) { - loop->color = 0; - } else - loop->color = MI_WIN_WHITE_PIXEL(mi); - loop->nsteps = MI_CYCLES(mi); - if (loop->nsteps == 0) - loop->nsteps = 1; - lc->maxcycles = (MAXCYCLES * loop->nsteps) - 1; - 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 = MI_SIZE(mi); - checkRadius(loop, lc); - loop->dx = NRAND(XVMAX); - loop->dy = NRAND(YVMAX); - loop->dx++; - loop->dy++; - lf[0] = &Function[lc->loopcount % NUMSTDFUNCS]; - if ((lp = loop->lastpoint = (XPoint *) - calloc(loop->nsteps, sizeof (XPoint))) == NULL) - return; - phase = lc->loopcount % loop->nsteps; - - 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); + 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(lc); + 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; } - for (pctr = 0; pctr < loop->nsteps; pctr++) { - /* Set the color */ - lisasetcolor(); + 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 - 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 - XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), \ - lp[pctr].x, lp[pctr].y); -#endif + 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 */ } - - { - int line_width = -15; /* #### make this a resource */ - if (line_width == 0) - line_width = -8; - if (line_width < 0) - line_width = NRAND(-line_width)+1; - XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), line_width, - LineSolid, CapProjecting, JoinMiter); + } 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; } -void -init_lisa(ModeInfo * mi) +static void +refreshlisa(ModeInfo * mi) { - lisacons *lc; + lisacons *lc = &Lisa[MI_SCREEN(mi)]; int lctr; - if (Lisa == NULL) { - if ((Lisa = (lisacons *) calloc(MI_NUM_SCREENS(mi), sizeof (lisacons))) \ - == NULL) + for (lctr = 0; lctr < lc->nlissajous; lctr++) { + if (!drawlisa(mi, &lc->lissajous[lctr])) return; } +} + +ENTRYPOINT void +refresh_lisa(ModeInfo * mi) +{ + lisacons *lc; + + if (Lisa == NULL) + return; lc = &Lisa[MI_SCREEN(mi)]; - lc->width = MI_WIN_WIDTH(mi); - lc->height = MI_WIN_HEIGHT(mi); - lc->loopcount = 0; - lc->nlisajous = MI_BATCHCOUNT(mi); - if (lc->nlisajous <= 0) - lc->nlisajous = 1; + if (lc->lissajous == NULL) + return; - if (lc->lisajous == NULL) { - if ((lc->lisajous = (lisas *) calloc(lc->nlisajous, sizeof (lisas))) \ - == NULL) - return; - XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); - for (lctr = 0; lctr < lc->nlisajous; lctr++) { - initlisa(mi, &lc->lisajous[lctr]); - lc->loopcount++; - } - } else { - refresh_lisa(mi); + if (lc->painted) { + lc->painted = False; + MI_CLEARWINDOW(mi); + refreshlisa(mi); } - XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); } -void -draw_lisa(ModeInfo * mi) +static void +change_lisa(ModeInfo * mi) { - lisacons *lc = &Lisa[MI_SCREEN(mi)]; + lisas *loop; + int lctr, newfunc; + lisacons *lc; - if (++lc->loopcount > lc->maxcycles) { - change_lisa(mi); + 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 */ } - refresh_lisa(mi); + 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 */ + } } -void -refresh_lisa(ModeInfo * mi) +ENTRYPOINT void +init_lisa (ModeInfo * mi) { - lisacons *lc = &Lisa[MI_SCREEN(mi)]; int lctr; + lisacons *lc; - for (lctr = 0; lctr < lc->nlisajous; lctr++) { - drawlisa(mi, &lc->lisajous[lctr]); + MI_INIT (mi, Lisa, 0); + 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); } } -void -release_lisa(ModeInfo * mi) +ENTRYPOINT void +draw_lisa (ModeInfo * mi) { lisacons *lc; - int lctr, sctr; - if (Lisa) { - for (sctr = 0; sctr < MI_NUM_SCREENS(mi); sctr++) { - lc = &Lisa[sctr]; - while (lc->lisajous) { - for (lctr = 0; lctr < lc->nlisajous; lctr++) { - (void) free(lc->lisajous[lctr].lastpoint); - } - (void) free(lc->lisajous); - lc->lisajous = NULL; - } - } - (void) free(Lisa); - Lisa = NULL; + 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); } -void -change_lisa(ModeInfo * mi) +ENTRYPOINT void +release_lisa (ModeInfo * mi) { - lisacons *lc = &Lisa[MI_SCREEN(mi)]; - lisas *loop; - int lctr; + if (Lisa) { + int screen; - lc->loopcount = 0; - for (lctr = 0; lctr < lc->nlisajous; lctr++) { - loop = &lc->lisajous[lctr]; - loop->function[1] = &Function[(loop->function[0]->index + 1) % - NUMSTDFUNCS]; - loop->melting = loop->nsteps - 1; - loop->nfuncs = 2; + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_lisa(&Lisa[screen]); + (void) free(Lisa); + Lisa = (lisacons *) NULL; } } + +XSCREENSAVER_MODULE ("Lisa", lisa) + +#endif /* MODE_lisa */