1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* lisa --- animated full-loop lisajous figures */
5 static const char sccsid[] = "@(#)lisa.c 5.00 2000/11/01 xlockmore";
9 * Copyright (c) 1997 by Caleb Cullen.
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
24 * 01-Nov-2000: Allocation checks
25 * 10-May-1997: Compatible with xscreensaver
27 * The inspiration for this program, Lasp, was written by Adam B. Roach
28 * in 1990, assisted by me, Caleb Cullen. It was written first in C, then
29 * in assembly, and used pre-calculated data tables to graph lisajous
30 * figures on 386 machines and lower. This version bears only superficial
31 * resemblances to the original Lasp.
33 * The `lissie' module's source code was studied as an example of how
34 * to incorporate a new module into xlock. Resemblances to it are
35 * expected, but not intended to be plaigiaristic.
40 # define DEFAULTS "*delay: 25000 \n" \
45 # define UNIFORM_COLORS
46 # define reshape_lisa 0
47 # define lisa_handle_event 0
48 # include "xlockmore.h" /* in xscreensaver distribution */
49 #else /* STANDALONE */
50 # include "xlock.h" /* in xlockmore distribution */
51 #endif /* STANDALONE */
55 #define DEF_ADDITIVE "True"
59 static XrmOptionDescRec opts[] =
61 {"-additive", ".lisa.additive", XrmoptionNoArg, "True"},
62 {"+additive", ".lisa.additive", XrmoptionNoArg, "False"}
65 static argtype vars[] =
67 {&additive, "additive", "Additive", DEF_ADDITIVE, t_Bool}
70 static OptionStruct desc[] =
72 {"-/+additive", "turn on/off additive functions mode"}
75 ENTRYPOINT ModeSpecOpt lisa_opts =
76 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
79 ModStruct lisa_description =
80 {"lisa", "init_lisa", "draw_lisa", "release_lisa",
81 "refresh_lisa", "change_lisa", (char *) NULL, &lisa_opts,
82 25000, 1, 256, -1, 64, 1.0, "",
83 "Shows animated lisajous loops", 0, NULL};
89 #define XVMAX 10 /* Maximum velocities */
91 #define LISAMAXFUNCS 2
92 #define NUMSTDFUNCS 10
95 #define lisasetcolor() \
96 if (MI_NPIXELS(mi) > 2) { \
97 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_PIXEL(mi, loop->color)); \
98 if (++(loop->color) >= (unsigned) MI_NPIXELS(mi)) { loop->color=0; } \
99 } else { XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); }
100 #define getRadius(context) \
101 ((context->width > context->height)?context->height:context->width) * 3 / 8
102 #define checkRadius(loop, context) \
103 if ((context->height / 2 > MI_SIZE(mi)) && (context->width / 2 > MI_SIZE(mi))) \
104 loop->radius = MI_SIZE(mi); \
105 if ((loop->radius < 0) || \
106 (loop->radius > loop->center.x) || \
107 (loop->radius > loop->center.y)) loop->radius = getRadius(context)
110 typedef struct lisafunc_struct {
111 double xcoeff[2], ycoeff[2];
116 typedef struct lisa_struct {
118 int radius, dx, dy, nsteps, nfuncs, melting;
119 double pistep, phi, theta;
120 XPoint center, *lastpoint;
121 lisafuncs *function[LISAMAXFUNCS];
125 typedef struct lisacontext_struct {
127 int width, height, nlisajous, loopcount;
132 static lisacons *Lisa = (lisacons *) NULL;
134 static lisafuncs Function[NUMSTDFUNCS] =
138 {1.0, 2.0}, 2, 2, 0},
141 {1.0, 1.0}, 2, 2, 1},
144 {1.0, 2.0}, 2, 2, 2},
147 {1.0, 3.0}, 2, 2, 3},
150 {1.0, 2.0}, 2, 2, 4},
153 {1.0, 3.0}, 2, 2, 5},
156 {1.0, 4.0}, 2, 2, 6},
159 {1.0, 5.0}, 2, 2, 7},
162 {2.0, 5.0}, 2, 2, 8},
169 free_lisa(lisacons *lc)
171 while (lc->lisajous) {
174 for (lctr = 0; lctr < lc->nlisajous; lctr++) {
175 (void) free((void *) lc->lisajous[lctr].lastpoint);
177 (void) free((void *) lc->lisajous);
178 lc->lisajous = (lisas *) NULL;
183 drawlisa(ModeInfo * mi, lisas * loop)
186 XPoint *lp = loop->lastpoint;
187 lisacons *lc = &Lisa[MI_SCREEN(mi)];
188 lisafuncs **lf = loop->function;
189 int phase = lc->loopcount % loop->nsteps;
190 int pctr, fctr, xctr, yctr;
191 double xprod, yprod, xsum, ysum;
193 /* Allocate the np array */
194 if ((np = (XPoint *) calloc(loop->nsteps, sizeof (XPoint))) == NULL) {
199 /* Update the center */
200 loop->center.x += loop->dx;
201 loop->center.y += loop->dy;
202 checkRadius(loop, lc);
203 if ((loop->center.x - loop->radius) <= 0) {
204 loop->center.x = loop->radius;
205 loop->dx = NRAND(XVMAX);
206 } else if ((loop->center.x + loop->radius) >= lc->width) {
207 loop->center.x = lc->width - loop->radius;
208 loop->dx = -NRAND(XVMAX);
210 if ((loop->center.y - loop->radius) <= 0) {
211 loop->center.y = loop->radius;
212 loop->dy = NRAND(YVMAX);
213 } else if ((loop->center.y + loop->radius) >= lc->height) {
214 loop->center.y = lc->height - loop->radius;
215 loop->dy = -NRAND(YVMAX);
218 /* Now draw the points, and erase the ones from the last cycle */
220 for (pctr = 0; pctr < loop->nsteps; pctr++) {
222 loop->phi = (double) (pctr - phase) * loop->pistep;
223 loop->theta = (double) (pctr + phase) * loop->pistep;
231 xprod += sin(lf[fctr]->xcoeff[xctr] * loop->theta);
233 yprod += sin(lf[fctr]->ycoeff[yctr] * loop->phi);
236 xsum += xprod * (double) (loop->nsteps - loop->melting) /
237 (double) loop->nsteps;
238 ysum += yprod * (double) (loop->nsteps - loop->melting) /
239 (double) loop->nsteps;
241 xsum += xprod * (double) loop->melting / (double) loop->nsteps;
242 ysum += yprod * (double) loop->melting / (double) loop->nsteps;
249 xsum = xsum * (double) loop->radius / (double) lf[fctr]->nx;
250 ysum = ysum * (double) loop->radius / (double) lf[fctr]->ny;
255 yprod = xprod = (double) loop->radius *
256 (double) (loop->nsteps - loop->melting) /
257 (double) (loop->nsteps);
259 yprod = xprod = (double) loop->radius *
260 (double) (loop->melting) / (double) (loop->nsteps);
263 xprod = yprod = (double) loop->radius;
266 xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta);
268 yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi);
273 if ((loop->nfuncs > 1) && (!loop->melting)) {
274 xsum /= (double) loop->nfuncs;
275 ysum /= (double) loop->nfuncs;
277 xsum += (double) loop->center.x;
278 ysum += (double) loop->center.y;
280 np[pctr].x = (int) ceil(xsum);
281 np[pctr].y = (int) ceil(ysum);
284 if (!--loop->melting) {
286 loop->function[0] = loop->function[1];
289 for (pctr = 0; pctr < loop->nsteps; pctr++) {
291 #if defined DRAWLINES
292 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth,
293 LineSolid, CapProjecting, JoinMiter);
294 /* erase the last cycle's point */
295 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
296 XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi),
297 MI_GC(mi), lp[pctr].x, lp[pctr].y,
298 lp[(pctr + 1) % loop->nsteps].x,
299 lp[(pctr + 1) % loop->nsteps].y);
301 /* Set the new color */
304 /* plot this cycle's point */
305 XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi),
306 MI_GC(mi), np[pctr].x, np[pctr].y,
307 np[(pctr + 1) % loop->nsteps].x,
308 np[(pctr + 1) % loop->nsteps].y);
309 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1,
310 LineSolid, CapProjecting, JoinMiter);
312 /* erase the last cycle's point */
313 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
314 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi),
315 MI_GC(mi), lp[pctr].x, lp[pctr].y);
317 /* Set the new color */
320 /* plot this cycle's point */
321 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi),
322 MI_GC(mi), np[pctr].x, np[pctr].y);
325 (void) free((void *) lp);
326 loop->lastpoint = np;
331 initlisa(ModeInfo * mi, lisas * loop)
333 lisacons *lc = &Lisa[MI_SCREEN(mi)];
334 lisafuncs **lf = loop->function;
336 int phase, pctr, fctr, xctr, yctr;
337 double xprod, yprod, xsum, ysum;
339 if (MI_NPIXELS(mi) > 2) {
342 loop->color = MI_WHITE_PIXEL(mi);
343 loop->nsteps = MI_CYCLES(mi);
344 if (loop->nsteps == 0)
346 lc->maxcycles = (MAXCYCLES * loop->nsteps) - 1;
349 loop->pistep = 2.0 * M_PI / (double) loop->nsteps;
350 loop->center.x = lc->width / 2;
351 loop->center.y = lc->height / 2;
352 loop->radius = (int) MI_SIZE(mi);
353 checkRadius(loop, lc);
354 loop->dx = NRAND(XVMAX);
355 loop->dy = NRAND(YVMAX);
358 lf[0] = &Function[lc->loopcount % NUMSTDFUNCS];
359 if ((lp = loop->lastpoint = (XPoint *)
360 calloc(loop->nsteps, sizeof (XPoint))) == NULL) {
364 phase = lc->loopcount % loop->nsteps;
366 for (pctr = 0; pctr < loop->nsteps; pctr++) {
367 loop->phi = (double) (pctr - phase) * loop->pistep;
368 loop->theta = (double) (pctr + phase) * loop->pistep;
372 xprod = yprod = (double) loop->radius;
376 xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta);
378 yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi);
382 if (loop->nfuncs > 1) {
386 xsum += (double) loop->center.x;
387 ysum += (double) loop->center.y;
389 lp[pctr].x = (int) ceil(xsum);
390 lp[pctr].y = (int) ceil(ysum);
392 #if defined DRAWLINES
394 loop->linewidth = -8; /* #### make this a resource */
396 if (loop->linewidth == 0)
398 if (loop->linewidth < 0)
399 loop->linewidth = NRAND(-loop->linewidth) + 1;
400 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth,
401 LineSolid, CapProjecting, JoinMiter);
404 for (pctr = 0; pctr < loop->nsteps; pctr++) {
407 #if defined DRAWLINES
408 XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi),
409 MI_GC(mi), lp[pctr].x, lp[pctr].y,
410 lp[(pctr + 1) % loop->nsteps].x,
411 lp[(pctr + 1) % loop->nsteps].y);
413 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
414 lp[pctr].x, lp[pctr].y);
417 #if defined DRAWLINES
418 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1,
419 LineSolid, CapProjecting, JoinMiter);
425 refreshlisa(ModeInfo * mi)
427 lisacons *lc = &Lisa[MI_SCREEN(mi)];
430 for (lctr = 0; lctr < lc->nlisajous; lctr++) {
431 if (!drawlisa(mi, &lc->lisajous[lctr]))
437 refresh_lisa(ModeInfo * mi)
443 lc = &Lisa[MI_SCREEN(mi)];
444 if (lc->lisajous == NULL)
455 change_lisa(ModeInfo * mi)
463 lc = &Lisa[MI_SCREEN(mi)];
464 if (lc->lisajous == NULL)
468 for (lctr = 0; lctr < lc->nlisajous; lctr++) {
469 loop = &lc->lisajous[lctr];
470 loop->function[1] = &Function[(loop->function[0]->index + 1) %
472 loop->melting = loop->nsteps - 1;
478 init_lisa (ModeInfo * mi)
484 if ((Lisa = (lisacons *) calloc(MI_NUM_SCREENS(mi),
485 sizeof (lisacons))) == NULL)
488 lc = &Lisa[MI_SCREEN(mi)];
489 lc->width = MI_WIDTH(mi);
490 lc->height = MI_HEIGHT(mi);
492 lc->nlisajous = MI_COUNT(mi);
493 if (lc->nlisajous <= 0)
498 if (lc->lisajous == NULL) {
499 if ((lc->lisajous = (lisas *) calloc(lc->nlisajous,
500 sizeof (lisas))) == NULL)
502 for (lctr = 0; lctr < lc->nlisajous; lctr++) {
503 if (!initlisa(mi, &lc->lisajous[lctr]))
513 draw_lisa (ModeInfo * mi)
519 lc = &Lisa[MI_SCREEN(mi)];
520 if (lc->lisajous == NULL)
523 #ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
524 XClearWindow (MI_DISPLAY(mi), MI_WINDOW(mi));
527 MI_IS_DRAWN(mi) = True;
529 if (++lc->loopcount > lc->maxcycles) {
536 release_lisa (ModeInfo * mi)
541 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
542 free_lisa(&Lisa[screen]);
544 Lisa = (lisacons *) NULL;
548 XSCREENSAVER_MODULE ("Lisa", lisa)
550 #endif /* MODE_lisa */