source: trunk/third/xscreensaver/hacks/lisa.c @ 20148

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