http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.01.tar.gz
[xscreensaver] / hacks / lisa.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* lisa --- animated full-loop lisajous figures */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)lisa.c        5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10  * Copyright (c) 1997 by Caleb Cullen.
11  *
12  * Permission to use, copy, modify, and distribute this software and its
13  * documentation for any purpose and without fee is hereby granted,
14  * provided that the above copyright notice appear in all copies and that
15  * both that copyright notice and this permission notice appear in
16  * supporting documentation.
17  *
18  * This file is provided AS IS with no warranties of any kind.  The author
19  * shall have no liability with respect to the infringement of copyrights,
20  * trade secrets or any patents by this file or any part thereof.  In no
21  * event will the author be liable for any lost revenue or profits or
22  * other special, indirect and consequential damages.
23  *
24  * Revision History:
25  * 01-Nov-2000: Allocation checks
26  * 10-May-1997: Compatible with xscreensaver
27  *
28  * The inspiration for this program, Lasp, was written by Adam B. Roach
29  * in 1990, assisted by me, Caleb Cullen.  It was written first in C, then
30  * in assembly, and used pre-calculated data tables to graph lisajous
31  * figures on 386 machines and lower.  This version bears only superficial
32  * resemblances to the original Lasp.
33  *
34  * The `lissie' module's source code was studied as an example of how
35  * to incorporate a new module into xlock.  Resemblances to it are
36  * expected, but not intended to be plaigiaristic.
37  */
38
39 #ifdef STANDALONE
40 #define MODE_lisa
41 #define PROGCLASS "Lisa"
42 #define HACK_INIT init_lisa
43 #define HACK_DRAW draw_lisa
44 #define lisa_opts xlockmore_opts
45 #define DEFAULTS "*delay: 25000 \n" \
46  "*count: 1 \n" \
47  "*cycles: 256 \n" \
48  "*size: -1 \n" \
49  "*ncolors: 200 \n"
50 #define UNIFORM_COLORS
51 #include "xlockmore.h"          /* in xscreensaver distribution */
52
53 #else /* STANDALONE */
54 #include "xlock.h"              /* in xlockmore distribution */
55
56 #endif /* STANDALONE */
57
58 #ifdef MODE_lisa
59
60 #define  DEF_ADDITIVE     "True"
61
62 static Bool additive;
63
64 static XrmOptionDescRec opts[] =
65 {
66         {(char *) "-additive", (char *) ".lisa.additive", XrmoptionNoArg, (caddr_t) "True"},
67         {(char *) "+additive", (char *) ".lisa.additive", XrmoptionNoArg, (caddr_t) "False"}
68 };
69
70 static argtype vars[] =
71 {
72         {(caddr_t *) & additive, (char *) "additive", (char *) "Additive", (char *) DEF_ADDITIVE, t_Bool}
73 };
74
75 static OptionStruct desc[] =
76 {
77         {(char *) "-/+additive", (char *) "turn on/off additive functions mode"}
78 };
79
80 ModeSpecOpt lisa_opts =
81 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
82
83 #ifdef USE_MODULES
84 ModStruct   lisa_description =
85 {"lisa", "init_lisa", "draw_lisa", "release_lisa",
86  "refresh_lisa", "change_lisa", (char *) NULL, &lisa_opts,
87  25000, 1, 256, -1, 64, 1.0, "",
88  "Shows animated lisajous loops", 0, NULL};
89
90 #endif
91
92 #define  DRAWLINES    1
93 #define  TWOLOOPS     1
94 #define  XVMAX        10        /* Maximum velocities */
95 #define  YVMAX        10
96 #define  LISAMAXFUNCS 2
97 #define  NUMSTDFUNCS  10
98 #define  MAXCYCLES    3
99 #define  MINLISAS     1
100 #define  lisasetcolor() \
101 if (MI_NPIXELS(mi) > 2) { \
102   XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_PIXEL(mi, loop->color)); \
103   if (++(loop->color) >= (unsigned) MI_NPIXELS(mi)) { loop->color=0; } \
104   } else { XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); }
105 #define getRadius(context) \
106   ((context->width > context->height)?context->height:context->width) * 3 / 8
107 #define checkRadius(loop, context) \
108   if ((context->height / 2 > MI_SIZE(mi)) && (context->width / 2 > MI_SIZE(mi))) \
109       loop->radius = MI_SIZE(mi); \
110   if ((loop->radius < 0) || \
111       (loop->radius > loop->center.x) || \
112       (loop->radius > loop->center.y)) loop->radius = getRadius(context)
113
114
115 typedef struct lisafunc_struct {
116         double      xcoeff[2], ycoeff[2];
117         int         nx, ny;
118         int         index;
119 } lisafuncs;
120
121 typedef struct lisa_struct {
122         unsigned long color;
123         int         radius, dx, dy, nsteps, nfuncs, melting;
124         double      pistep, phi, theta;
125         XPoint      center, *lastpoint;
126         lisafuncs  *function[LISAMAXFUNCS];
127         int         linewidth;
128 } lisas;
129
130 typedef struct lisacontext_struct {
131         lisas      *lisajous;
132         int         width, height, nlisajous, loopcount;
133         int         maxcycles;
134         Bool        painted;
135 } lisacons;
136
137 static lisacons *Lisa = (lisacons *) NULL;
138
139 static lisafuncs Function[NUMSTDFUNCS] =
140 {
141         {
142                 {1.0, 2.0},
143                 {1.0, 2.0}, 2, 2, 0},
144         {
145                 {1.0, 2.0},
146                 {1.0, 1.0}, 2, 2, 1},
147         {
148                 {1.0, 3.0},
149                 {1.0, 2.0}, 2, 2, 2},
150         {
151                 {1.0, 3.0},
152                 {1.0, 3.0}, 2, 2, 3},
153         {
154                 {2.0, 4.0},
155                 {1.0, 2.0}, 2, 2, 4},
156         {
157                 {1.0, 4.0},
158                 {1.0, 3.0}, 2, 2, 5},
159         {
160                 {1.0, 4.0},
161                 {1.0, 4.0}, 2, 2, 6},
162         {
163                 {1.0, 5.0},
164                 {1.0, 5.0}, 2, 2, 7},
165         {
166                 {2.0, 5.0},
167                 {2.0, 5.0}, 2, 2, 8},
168         {
169                 {1.0, 0.0},
170                 {1.0, 0.0}, 1, 1, 9}
171 };
172
173 static void
174 free_lisa(lisacons *lc)
175 {
176         while (lc->lisajous) {
177                 int    lctr;
178
179                 for (lctr = 0; lctr < lc->nlisajous; lctr++) {
180                         (void) free((void *) lc->lisajous[lctr].lastpoint);
181                 }
182                 (void) free((void *) lc->lisajous);
183                 lc->lisajous = (lisas *) NULL;
184         }
185 }
186
187 static Bool
188 drawlisa(ModeInfo * mi, lisas * loop)
189 {
190         XPoint     *np;
191         XPoint     *lp = loop->lastpoint;
192         lisacons   *lc = &Lisa[MI_SCREEN(mi)];
193         lisafuncs **lf = loop->function;
194         int         phase = lc->loopcount % loop->nsteps;
195         int         pctr, fctr, xctr, yctr;
196         double      xprod, yprod, xsum, ysum;
197
198         /* Allocate the np array */
199         if ((np = (XPoint *) calloc(loop->nsteps, sizeof (XPoint))) == NULL) {
200                 free_lisa(lc);
201                 return False;
202         }
203
204         /* Update the center */
205         loop->center.x += loop->dx;
206         loop->center.y += loop->dy;
207         checkRadius(loop, lc);
208         if ((loop->center.x - loop->radius) <= 0) {
209                 loop->center.x = loop->radius;
210                 loop->dx = NRAND(XVMAX);
211         } else if ((loop->center.x + loop->radius) >= lc->width) {
212                 loop->center.x = lc->width - loop->radius;
213                 loop->dx = -NRAND(XVMAX);
214         };
215         if ((loop->center.y - loop->radius) <= 0) {
216                 loop->center.y = loop->radius;
217                 loop->dy = NRAND(YVMAX);
218         } else if ((loop->center.y + loop->radius) >= lc->height) {
219                 loop->center.y = lc->height - loop->radius;
220                 loop->dy = -NRAND(YVMAX);
221         };
222
223         /* Now draw the points, and erase the ones from the last cycle */
224
225         for (pctr = 0; pctr < loop->nsteps; pctr++) {
226                 fctr = loop->nfuncs;
227                 loop->phi = (double) (pctr - phase) * loop->pistep;
228                 loop->theta = (double) (pctr + phase) * loop->pistep;
229                 xsum = ysum = 0;
230                 while (fctr--) {
231                         xctr = lf[fctr]->nx;
232                         yctr = lf[fctr]->ny;
233                         if (additive) {
234                                 xprod = yprod = 0.0;
235                                 while (xctr--)
236                                         xprod += sin(lf[fctr]->xcoeff[xctr] * loop->theta);
237                                 while (yctr--)
238                                         yprod += sin(lf[fctr]->ycoeff[yctr] * loop->phi);
239                                 if (loop->melting) {
240                                         if (fctr) {
241                                                 xsum += xprod * (double) (loop->nsteps - loop->melting) /
242                                                         (double) loop->nsteps;
243                                                 ysum += yprod * (double) (loop->nsteps - loop->melting) /
244                                                         (double) loop->nsteps;
245                                         } else {
246                                                 xsum += xprod * (double) loop->melting / (double) loop->nsteps;
247                                                 ysum += yprod * (double) loop->melting / (double) loop->nsteps;
248                                         }
249                                 } else {
250                                         xsum = xprod;
251                                         ysum = yprod;
252                                 }
253                                 if (!fctr) {
254                                         xsum = xsum * (double) loop->radius / (double) lf[fctr]->nx;
255                                         ysum = ysum * (double) loop->radius / (double) lf[fctr]->ny;
256                                 }
257                         } else {
258                                 if (loop->melting) {
259                                         if (fctr) {
260                                                 yprod = xprod = (double) loop->radius *
261                                                         (double) (loop->nsteps - loop->melting) /
262                                                         (double) (loop->nsteps);
263                                         } else {
264                                                 yprod = xprod = (double) loop->radius *
265                                                         (double) (loop->melting) / (double) (loop->nsteps);
266                                         }
267                                 } else {
268                                         xprod = yprod = (double) loop->radius;
269                                 }
270                                 while (xctr--)
271                                         xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta);
272                                 while (yctr--)
273                                         yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi);
274                                 xsum += xprod;
275                                 ysum += yprod;
276                         }
277                 }
278                 if ((loop->nfuncs > 1) && (!loop->melting)) {
279                         xsum /= (double) loop->nfuncs;
280                         ysum /= (double) loop->nfuncs;
281                 }
282                 xsum += (double) loop->center.x;
283                 ysum += (double) loop->center.y;
284
285                 np[pctr].x = (int) ceil(xsum);
286                 np[pctr].y = (int) ceil(ysum);
287         }
288         if (loop->melting) {
289                 if (!--loop->melting) {
290                         loop->nfuncs = 1;
291                         loop->function[0] = loop->function[1];
292                 }
293         }
294         for (pctr = 0; pctr < loop->nsteps; pctr++) {
295
296 #if defined DRAWLINES
297                 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth,
298                                    LineSolid, CapProjecting, JoinMiter);
299                 /* erase the last cycle's point */
300                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
301                 XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi),
302                           MI_GC(mi), lp[pctr].x, lp[pctr].y,
303                           lp[(pctr + 1) % loop->nsteps].x,
304                           lp[(pctr + 1) % loop->nsteps].y);
305
306                 /* Set the new color */
307                 lisasetcolor();
308
309                 /* plot this cycle's point */
310                 XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi),
311                           MI_GC(mi), np[pctr].x, np[pctr].y,
312                           np[(pctr + 1) % loop->nsteps].x,
313                           np[(pctr + 1) % loop->nsteps].y);
314                 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1,
315                                    LineSolid, CapProjecting, JoinMiter);
316 #else
317                 /* erase the last cycle's point */
318                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
319                 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi),
320                            MI_GC(mi), lp[pctr].x, lp[pctr].y);
321
322                 /* Set the new color */
323                 lisasetcolor();
324
325                 /* plot this cycle's point */
326                 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi),
327                            MI_GC(mi), np[pctr].x, np[pctr].y);
328 #endif
329         }
330         (void) free((void *) lp);
331         loop->lastpoint = np;
332         return True;
333 }
334
335 static Bool 
336 initlisa(ModeInfo * mi, lisas * loop)
337 {
338         lisacons   *lc = &Lisa[MI_SCREEN(mi)];
339         lisafuncs **lf = loop->function;
340         XPoint     *lp;
341         int         phase, pctr, fctr, xctr, yctr;
342         double      xprod, yprod, xsum, ysum;
343
344         if (MI_NPIXELS(mi) > 2) {
345                 loop->color = 0;
346         } else
347                 loop->color = MI_WHITE_PIXEL(mi);
348         loop->nsteps = MI_CYCLES(mi);
349         if (loop->nsteps == 0)
350                 loop->nsteps = 1;
351         lc->maxcycles = (MAXCYCLES * loop->nsteps) - 1;
352         loop->melting = 0;
353         loop->nfuncs = 1;
354         loop->pistep = 2.0 * M_PI / (double) loop->nsteps;
355         loop->center.x = lc->width / 2;
356         loop->center.y = lc->height / 2;
357         loop->radius = (int) MI_SIZE(mi);
358         checkRadius(loop, lc);
359         loop->dx = NRAND(XVMAX);
360         loop->dy = NRAND(YVMAX);
361         loop->dx++;
362         loop->dy++;
363         lf[0] = &Function[lc->loopcount % NUMSTDFUNCS];
364         if ((lp = loop->lastpoint = (XPoint *)
365              calloc(loop->nsteps, sizeof (XPoint))) == NULL) {
366                 free_lisa(lc);
367                 return False;
368         }
369         phase = lc->loopcount % loop->nsteps;
370
371         for (pctr = 0; pctr < loop->nsteps; pctr++) {
372                 loop->phi = (double) (pctr - phase) * loop->pistep;
373                 loop->theta = (double) (pctr + phase) * loop->pistep;
374                 fctr = loop->nfuncs;
375                 xsum = ysum = 0.0;
376                 while (fctr--) {
377                         xprod = yprod = (double) loop->radius;
378                         xctr = lf[fctr]->nx;
379                         yctr = lf[fctr]->ny;
380                         while (xctr--)
381                                 xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta);
382                         while (yctr--)
383                                 yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi);
384                         xsum += xprod;
385                         ysum += yprod;
386                 }
387                 if (loop->nfuncs > 1) {
388                         xsum /= 2.0;
389                         ysum /= 2.0;
390                 }
391                 xsum += (double) loop->center.x;
392                 ysum += (double) loop->center.y;
393
394                 lp[pctr].x = (int) ceil(xsum);
395                 lp[pctr].y = (int) ceil(ysum);
396         }
397 #if defined DRAWLINES
398         {
399                 loop->linewidth = -8;   /* #### make this a resource */
400
401                 if (loop->linewidth == 0)
402                         loop->linewidth = 1;
403                 if (loop->linewidth < 0)
404                         loop->linewidth = NRAND(-loop->linewidth) + 1;
405                 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth,
406                                    LineSolid, CapProjecting, JoinMiter);
407         }
408 #endif
409         for (pctr = 0; pctr < loop->nsteps; pctr++) {
410                 /* Set the color */
411                 lisasetcolor();
412 #if defined DRAWLINES
413                 XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi),
414                           MI_GC(mi), lp[pctr].x, lp[pctr].y,
415                           lp[(pctr + 1) % loop->nsteps].x,
416                           lp[(pctr + 1) % loop->nsteps].y);
417 #else
418                 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
419                            lp[pctr].x, lp[pctr].y);
420 #endif
421         }
422 #if defined DRAWLINES
423         XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1,
424                            LineSolid, CapProjecting, JoinMiter);
425 #endif
426         return True;
427 }
428
429 static void
430 refreshlisa(ModeInfo * mi)
431 {
432         lisacons   *lc = &Lisa[MI_SCREEN(mi)];
433         int         lctr;
434
435         for (lctr = 0; lctr < lc->nlisajous; lctr++) {
436                 if (!drawlisa(mi, &lc->lisajous[lctr]))
437                         return;
438         }
439 }
440
441 void
442 refresh_lisa(ModeInfo * mi)
443 {
444         lisacons   *lc;
445
446         if (Lisa == NULL)
447                 return;
448         lc = &Lisa[MI_SCREEN(mi)];
449         if (lc->lisajous == NULL)
450                 return;
451
452         if (lc->painted) {
453                 lc->painted = False;
454                 MI_CLEARWINDOW(mi);
455                 refreshlisa(mi);
456         }
457 }
458
459 void
460 change_lisa(ModeInfo * mi)
461 {
462         lisas      *loop;
463         int         lctr;
464         lisacons   *lc;
465
466         if (Lisa == NULL)
467                 return;
468         lc = &Lisa[MI_SCREEN(mi)];
469         if (lc->lisajous == NULL)
470                 return;
471
472         lc->loopcount = 0;
473         for (lctr = 0; lctr < lc->nlisajous; lctr++) {
474                 loop = &lc->lisajous[lctr];
475                 loop->function[1] = &Function[(loop->function[0]->index + 1) %
476                                               NUMSTDFUNCS];
477                 loop->melting = loop->nsteps - 1;
478                 loop->nfuncs = 2;
479         }
480 }
481
482 void
483 init_lisa(ModeInfo * mi)
484 {
485         int         lctr;
486         lisacons   *lc;
487
488         if (Lisa == NULL) {
489                 if ((Lisa = (lisacons *) calloc(MI_NUM_SCREENS(mi),
490                                  sizeof (lisacons))) == NULL)
491                         return;
492         }
493         lc = &Lisa[MI_SCREEN(mi)];
494         lc->width = MI_WIDTH(mi);
495         lc->height = MI_HEIGHT(mi);
496         lc->loopcount = 0;
497         lc->nlisajous = MI_COUNT(mi);
498         if (lc->nlisajous <= 0)
499                 lc->nlisajous = 1;
500         MI_CLEARWINDOW(mi);
501         lc->painted = False;
502
503         if (lc->lisajous == NULL) {
504                 if ((lc->lisajous = (lisas *) calloc(lc->nlisajous,
505                                 sizeof (lisas))) == NULL)
506                         return;
507                 for (lctr = 0; lctr < lc->nlisajous; lctr++) {
508                         if (!initlisa(mi, &lc->lisajous[lctr]))
509                                 return;
510                         lc->loopcount++;
511                 }
512         } else {
513                 refreshlisa(mi);
514         }
515 }
516
517 void
518 draw_lisa(ModeInfo * mi)
519 {
520         lisacons   *lc;
521
522         if (Lisa == NULL)
523                 return;
524         lc = &Lisa[MI_SCREEN(mi)];
525         if (lc->lisajous == NULL)
526                 return;
527
528         MI_IS_DRAWN(mi) = True;
529         lc->painted = True;
530         if (++lc->loopcount > lc->maxcycles) {
531                 change_lisa(mi);
532         }
533         refreshlisa(mi);
534 }
535
536 void
537 release_lisa(ModeInfo * mi)
538 {
539         if (Lisa) {
540                 int    screen;
541
542                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
543                         free_lisa(&Lisa[screen]);
544                 (void) free(Lisa);
545                 Lisa = (lisacons *) NULL;
546         }
547 }
548
549 #endif /* MODE_lisa */