1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* lisa --- animated full-loop lisajous figures */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)lisa.c 4.04 97/07/28 xlockmore";
8 /* Copyright (c) 1997 by Caleb Cullen.
10 * Permission to use, copy, modify, and distribute this software and its
11 * documentation for any purpose and without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and that
13 * both that copyright notice and this permission notice appear in
14 * supporting documentation.
16 * This file is provided AS IS with no warranties of any kind. The author
17 * shall have no liability with respect to the infringement of copyrights,
18 * trade secrets or any patents by this file or any part thereof. In no
19 * event will the author be liable for any lost revenue or profits or
20 * other special, indirect and consequential damages.
23 * 10-May-97: Compatible with xscreensaver
25 * The inspiration for this program, Lasp, was written by Adam B. Roach
26 * in 1990, assisted by me, Caleb Cullen. It was written first in C, then
27 * in assembly, and used pre-calculated data tables to graph lisajous
28 * figures on 386 machines and lower. This version bears only superficial
29 * resemblances to the original Lasp.
31 * The `lissie' module's source code was studied as an example of how
32 * to incorporate a new module into xlock. Resemblances to it are
33 * expected, but not intended to be plaigiaristic.
37 # define PROGCLASS "Lisa"
38 # define HACK_INIT init_lisa
39 # define HACK_DRAW draw_lisa
40 # define lisa_opts xlockmore_opts
41 # define DEFAULTS "*delay: 25000 \n" \
46 # define UNIFORM_COLORS
47 # include "xlockmore.h" /* from the xscreensaver distribution */
48 void refresh_lisa(ModeInfo * mi);
49 void change_lisa(ModeInfo * mi);
50 #else /* !STANDALONE */
51 # include "xlock.h" /* from the xlockmore distribution */
52 #endif /* !STANDALONE */
54 #define DEF_ADDITIVE "True"
58 static XrmOptionDescRec lisa_xrm_opts[] =
60 {"-additive", ".lisa.additive", XrmoptionNoArg, (caddr_t) "True"},
61 {"+additive", ".lisa.additive", XrmoptionNoArg, (caddr_t) "False"}
64 static argtype lisa_vars[] =
66 {(caddr_t *) & additive, "additive", "Additive", DEF_ADDITIVE, t_Bool}
69 static OptionStruct lisa_vars_desc[] =
71 {"-/+additive", "turn on/off additive functions mode"}
74 ModeSpecOpt lisa_opts =
75 {2, lisa_xrm_opts, 1, lisa_vars, lisa_vars_desc};
80 #define XVMAX 10 /* Maximum velocities */
82 #define LISAMAXFUNCS 2
83 #define NUMSTDFUNCS 10
86 #define lisasetcolor() \
87 if (MI_NPIXELS(mi) > 2) { \
88 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_PIXEL(mi, loop->color)); \
89 if (++(loop->color) >= MI_NPIXELS(mi)) { loop->color=0; } \
90 } else { XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_WHITE_PIXEL(mi)); }
91 #define getRadius(context) \
92 ((context->width > context->height)?context->height:context->width) * 3 / 8
93 #define checkRadius(loop, context) \
94 if ((context->height / 2 > MI_SIZE(mi)) && (context->width / 2 > MI_SIZE(mi))) \
95 loop->radius = MI_SIZE(mi); \
96 if ((loop->radius < 0) || \
97 (loop->radius > loop->center.x) || \
98 (loop->radius > loop->center.y)) loop->radius = getRadius(context)
101 typedef struct lisafunc_struct {
102 double xcoeff[2], ycoeff[2];
107 typedef struct lisa_struct {
108 int radius, color, dx, dy, nsteps, nfuncs, melting;
109 double pistep, phi, theta;
110 XPoint center, *lastpoint;
111 lisafuncs *function[LISAMAXFUNCS];
114 typedef struct lisacontext_struct {
116 int width, height, nlisajous, loopcount;
120 static lisacons *Lisa = NULL;
122 static lisafuncs Function[NUMSTDFUNCS] =
126 {1.0, 2.0}, 2, 2, 0},
129 {1.0, 1.0}, 2, 2, 1},
132 {1.0, 2.0}, 2, 2, 2},
135 {1.0, 3.0}, 2, 2, 3},
138 {1.0, 2.0}, 2, 2, 4},
141 {1.0, 3.0}, 2, 2, 5},
144 {1.0, 4.0}, 2, 2, 6},
147 {1.0, 5.0}, 2, 2, 7},
150 {2.0, 5.0}, 2, 2, 8},
157 drawlisa(ModeInfo * mi, lisas * loop)
160 XPoint *lp = loop->lastpoint;
161 lisacons *lc = &Lisa[MI_SCREEN(mi)];
162 lisafuncs **lf = loop->function;
163 int phase = lc->loopcount % loop->nsteps;
164 int pctr, fctr, xctr, yctr;
165 double xprod, yprod, xsum, ysum;
167 /* Allocate the np array */
168 np = (XPoint *) calloc(loop->nsteps, sizeof (XPoint));
170 /* Update the center */
171 loop->center.x += loop->dx;
172 loop->center.y += loop->dy;
173 checkRadius(loop, lc);
174 if ((loop->center.x - loop->radius) <= 0) {
175 loop->center.x = loop->radius;
176 loop->dx = NRAND(XVMAX);
177 } else if ((loop->center.x + loop->radius) >= lc->width) {
178 loop->center.x = lc->width - loop->radius;
179 loop->dx = -NRAND(XVMAX);
181 if ((loop->center.y - loop->radius) <= 0) {
182 loop->center.y = loop->radius;
183 loop->dy = NRAND(YVMAX);
184 } else if ((loop->center.y + loop->radius) >= lc->height) {
185 loop->center.y = lc->height - loop->radius;
186 loop->dy = -NRAND(YVMAX);
189 /* Now draw the points, and erase the ones from the last cycle */
191 for (pctr = 0; pctr < loop->nsteps; pctr++) {
193 loop->phi = (double) (pctr - phase) * loop->pistep;
194 loop->theta = (double) (pctr + phase) * loop->pistep;
202 xprod += sin(lf[fctr]->xcoeff[xctr] * loop->theta);
204 yprod += sin(lf[fctr]->ycoeff[yctr] * loop->phi);
208 *(double) (loop->nsteps - loop->melting) \
209 /(double) loop->nsteps;
211 *(double) (loop->nsteps - loop->melting) \
212 /(double) loop->nsteps;
215 *(double) loop->melting \
216 /(double) loop->nsteps;
218 *(double) loop->melting \
219 /(double) loop->nsteps;
227 *(double) loop->radius \
228 /(double) lf[fctr]->nx;
230 *(double) loop->radius \
231 /(double) lf[fctr]->ny;
236 yprod = xprod = (double) loop->radius \
237 *(double) (loop->nsteps - loop->melting) \
238 /(double) (loop->nsteps);
240 yprod = xprod = (double) loop->radius \
241 *(double) (loop->melting) \
242 /(double) (loop->nsteps);
245 xprod = yprod = (double) loop->radius;
248 xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta);
250 yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi);
255 if ((loop->nfuncs > 1) && (!loop->melting)) {
256 xsum /= (double) loop->nfuncs;
257 ysum /= (double) loop->nfuncs;
259 xsum += (double) loop->center.x;
260 ysum += (double) loop->center.y;
262 np[pctr].x = (int) ceil(xsum);
263 np[pctr].y = (int) ceil(ysum);
266 if (!--loop->melting) {
268 loop->function[0] = loop->function[1];
271 for (pctr = 0; pctr < loop->nsteps; pctr++) {
273 #if defined DRAWLINES
274 /* erase the last cycle's point */
275 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
276 XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), \
277 MI_GC(mi), lp[pctr].x, lp[pctr].y, \
278 lp[(pctr + 1) % loop->nsteps].x, \
279 lp[(pctr + 1) % loop->nsteps].y);
281 /* Set the new color */
284 /* plot this cycle's point */
285 XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), \
286 MI_GC(mi), np[pctr].x, np[pctr].y, \
287 np[(pctr + 1) % loop->nsteps].x, \
288 np[(pctr + 1) % loop->nsteps].y);
290 /* erase the last cycle's point */
291 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
292 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), \
293 MI_GC(mi), lp[pctr].x, lp[pctr].y);
295 /* Set the new color */
298 /* plot this cycle's point */
299 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), \
300 MI_GC(mi), np[pctr].x, np[pctr].y);
303 (void) free((void *) lp);
304 loop->lastpoint = np;
308 initlisa(ModeInfo * mi, lisas * loop)
310 lisacons *lc = &Lisa[MI_SCREEN(mi)];
311 lisafuncs **lf = loop->function;
313 int phase, pctr, fctr, xctr, yctr;
314 double xprod, yprod, xsum, ysum;
316 if (MI_NPIXELS(mi) > 2) {
319 loop->color = MI_WIN_WHITE_PIXEL(mi);
320 loop->nsteps = MI_CYCLES(mi);
321 if (loop->nsteps == 0)
323 lc->maxcycles = (MAXCYCLES * loop->nsteps) - 1;
326 loop->pistep = 2.0 * M_PI / (double) loop->nsteps;
327 loop->center.x = lc->width / 2;
328 loop->center.y = lc->height / 2;
329 loop->radius = MI_SIZE(mi);
330 checkRadius(loop, lc);
331 loop->dx = NRAND(XVMAX);
332 loop->dy = NRAND(YVMAX);
335 lf[0] = &Function[lc->loopcount % NUMSTDFUNCS];
336 if ((lp = loop->lastpoint = (XPoint *)
337 calloc(loop->nsteps, sizeof (XPoint))) == NULL)
339 phase = lc->loopcount % loop->nsteps;
341 for (pctr = 0; pctr < loop->nsteps; pctr++) {
342 loop->phi = (double) (pctr - phase) * loop->pistep;
343 loop->theta = (double) (pctr + phase) * loop->pistep;
347 xprod = yprod = (double) loop->radius;
351 xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta);
353 yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi);
357 if (loop->nfuncs > 1) {
361 xsum += (double) loop->center.x;
362 ysum += (double) loop->center.y;
364 lp[pctr].x = (int) ceil(xsum);
365 lp[pctr].y = (int) ceil(ysum);
367 for (pctr = 0; pctr < loop->nsteps; pctr++) {
370 #if defined DRAWLINES
371 XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), \
372 MI_GC(mi), lp[pctr].x, lp[pctr].y, \
373 lp[(pctr + 1) % loop->nsteps].x, \
374 lp[(pctr + 1) % loop->nsteps].y);
376 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), \
377 lp[pctr].x, lp[pctr].y);
382 int line_width = -15; /* #### make this a resource */
386 line_width = NRAND(-line_width)+1;
387 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), line_width,
388 LineSolid, CapProjecting, JoinMiter);
393 init_lisa(ModeInfo * mi)
399 if ((Lisa = (lisacons *) calloc(MI_NUM_SCREENS(mi), sizeof (lisacons))) \
403 lc = &Lisa[MI_SCREEN(mi)];
404 lc->width = MI_WIN_WIDTH(mi);
405 lc->height = MI_WIN_HEIGHT(mi);
407 lc->nlisajous = MI_BATCHCOUNT(mi);
408 if (lc->nlisajous <= 0)
411 if (lc->lisajous == NULL) {
412 if ((lc->lisajous = (lisas *) calloc(lc->nlisajous, sizeof (lisas))) \
415 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
416 for (lctr = 0; lctr < lc->nlisajous; lctr++) {
417 initlisa(mi, &lc->lisajous[lctr]);
423 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
427 draw_lisa(ModeInfo * mi)
429 lisacons *lc = &Lisa[MI_SCREEN(mi)];
431 if (++lc->loopcount > lc->maxcycles) {
438 refresh_lisa(ModeInfo * mi)
440 lisacons *lc = &Lisa[MI_SCREEN(mi)];
443 for (lctr = 0; lctr < lc->nlisajous; lctr++) {
444 drawlisa(mi, &lc->lisajous[lctr]);
449 release_lisa(ModeInfo * mi)
455 for (sctr = 0; sctr < MI_NUM_SCREENS(mi); sctr++) {
457 while (lc->lisajous) {
458 for (lctr = 0; lctr < lc->nlisajous; lctr++) {
459 (void) free(lc->lisajous[lctr].lastpoint);
461 (void) free(lc->lisajous);
471 change_lisa(ModeInfo * mi)
473 lisacons *lc = &Lisa[MI_SCREEN(mi)];
478 for (lctr = 0; lctr < lc->nlisajous; lctr++) {
479 loop = &lc->lisajous[lctr];
480 loop->function[1] = &Function[(loop->function[0]->index + 1) %
482 loop->melting = loop->nsteps - 1;