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

Revision 20148, 15.0 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/* drift --- drifting recursive fractal cosmic flames */
3
4#if 0
5static const char sccsid[] = "@(#)drift.c       5.00 2000/11/01 xlockmore";
6#endif
7
8/*-
9 * Copyright (c) 1991 by Patrick J. Naughton.
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: Jamie Zawinski <jwz@jwz.org> compatible with xscreensaver
26 * 01-Jan-1997: Moved new flame to drift.  Compile time options now run time.
27 * 01-Jun-1995: Updated by Scott Draves.
28 * 27-Jun-1991: vary number of functions used.
29 * 24-Jun-1991: fixed portability problem with integer mod (%).
30 * 06-Jun-1991: Written, received from Scott Draves <spot@cs.cmu.edu>
31 */
32
33#ifdef STANDALONE
34#define MODE_drift
35#define PROGCLASS "Drift"
36#define HACK_INIT init_drift
37#define HACK_DRAW draw_drift
38#define drift_opts xlockmore_opts
39#define DEFAULTS "*delay: 10000 \n" \
40 "*count: 30 \n" \
41 "*ncolors: 200 \n"
42#define SMOOTH_COLORS
43#include "xlockmore.h"          /* in xscreensaver distribution */
44#include "erase.h"
45#else /* STANDALONE */
46#include "xlock.h"              /* in xlockmore distribution */
47
48#endif /* STANDALONE */
49
50#ifdef MODE_drift
51
52#define DEF_GROW "False"        /* Grow fractals instead of animating one at a time,
53                                   would then be like flame */
54#define DEF_LISS "False"        /* if this is defined then instead of a point
55                                   bouncing around in a high dimensional sphere, we
56                                   use lissojous figures.  Only makes sense if
57                                   grow is false. */
58
59static Bool grow;
60static Bool liss;
61
62static XrmOptionDescRec opts[] =
63{
64        {(char *) "-grow", (char *) ".drift.grow", XrmoptionNoArg, (caddr_t) "on"},
65        {(char *) "+grow", (char *) ".drift.grow", XrmoptionNoArg, (caddr_t) "off"},
66        {(char *) "-liss", (char *) ".drift.trail", XrmoptionNoArg, (caddr_t) "on"},
67        {(char *) "+liss", (char *) ".drift.trail", XrmoptionNoArg, (caddr_t) "off"}
68};
69static argtype vars[] =
70{
71        {(caddr_t *) & grow, (char *) "grow", (char *) "Grow", (char *) DEF_GROW, t_Bool},
72        {(caddr_t *) & liss, (char *) "liss", (char *) "Liss", (char *) DEF_LISS, t_Bool}
73};
74static OptionStruct desc[] =
75{
76        {(char *) "-/+grow", (char *) "turn on/off growing fractals, else they are animated"},
77        {(char *) "-/+liss", (char *) "turn on/off using lissojous figures to get points"}
78};
79
80ModeSpecOpt drift_opts =
81{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
82
83#ifdef USE_MODULES
84ModStruct   drift_description =
85{"drift", "init_drift", "draw_drift", "release_drift",
86 "refresh_drift", "init_drift", (char *) NULL, &drift_opts,
87 10000, 30, 1, 1, 64, 1.0, "",
88 "Shows cosmic drifting flame fractals", 0, NULL};
89
90#endif
91
92#define MAXBATCH1       200     /* mono */
93#define MAXBATCH2       20      /* color */
94#define FUSE            10      /* discard this many initial iterations */
95#define NMAJORVARS      7
96#define MAXLEV 10
97
98typedef struct {
99        /* shape of current flame */
100        int         nxforms;
101        double      f[2][3][MAXLEV];    /* a bunch of non-homogeneous xforms */
102        int         variation[10];      /* for each xform */
103
104        /* Animation */
105        double      df[2][3][MAXLEV];
106
107        /* high-level control */
108        int         mode;       /* 0->slow/single 1->fast/many */
109        int         nfractals;  /* draw this many fractals */
110        int         major_variation;
111        int         fractal_len;        /* pts/fractal */
112        int         color;
113        int         rainbow;    /* more than one color per fractal
114                                   1-> computed by adding dimension to fractal */
115
116        int         width, height;      /* of window */
117        int         timer;
118
119        /* draw info about current flame */
120        int         fuse;       /* iterate this many before drawing */
121        int         total_points;       /* draw this many pts before fractal ends */
122        int         npoints;    /* how many we've computed but not drawn */
123        XPoint      pts[MAXBATCH1];     /* here they are */
124        unsigned long pixcol;
125        /* when drawing in color, we have a buffer per color */
126        int        *ncpoints;
127        XPoint     *cpts;
128
129        double      x, y, c;
130        int         liss_time;
131        Bool        grow, liss;
132
133        short       lasthalf;
134        long        saved_random_bits;
135        int         nbits;
136} driftstruct;
137
138static driftstruct *drifts = (driftstruct *) NULL;
139
140static short
141halfrandom(driftstruct * dp, int mv)
142{
143        unsigned long r;
144
145        if (dp->lasthalf) {
146                r = dp->lasthalf;
147                dp->lasthalf = 0;
148        } else {
149                r = LRAND();
150                dp->lasthalf = (short) (r >> 16);
151        }
152        r = r % mv;
153        return r;
154}
155
156static int
157frandom(driftstruct * dp, int n)
158{
159        int         result;
160
161        if (3 > dp->nbits) {
162                dp->saved_random_bits = LRAND();
163                dp->nbits = 31;
164        }
165        switch (n) {
166                case 2:
167                        result = (int) (dp->saved_random_bits & 1);
168                        dp->saved_random_bits >>= 1;
169                        dp->nbits -= 1;
170                        return result;
171
172                case 3:
173                        result = (int) (dp->saved_random_bits & 3);
174                        dp->saved_random_bits >>= 2;
175                        dp->nbits -= 2;
176                        if (3 == result)
177                                return frandom(dp, 3);
178                        return result;
179
180                case 4:
181                        result = (int) (dp->saved_random_bits & 3);
182                        dp->saved_random_bits >>= 2;
183                        dp->nbits -= 2;
184                        return result;
185
186                case 5:
187                        result = (int) (dp->saved_random_bits & 7);
188                        dp->saved_random_bits >>= 3;
189                        dp->nbits -= 3;
190                        if (4 < result)
191                                return frandom(dp, 5);
192                        return result;
193                default:
194                        (void) fprintf(stderr, "bad arg to frandom\n");
195        }
196        return 0;
197}
198
199#define DISTRIB_A (halfrandom(dp, 7000) + 9000)
200#define DISTRIB_B ((frandom(dp, 3) + 1) * (frandom(dp, 3) + 1) * 120000)
201#define LEN(x) (sizeof(x)/sizeof((x)[0]))
202
203static void
204initmode(ModeInfo * mi, int mode)
205{
206        driftstruct *dp = &drifts[MI_SCREEN(mi)];
207
208#define VARIATION_LEN 14
209
210        dp->mode = mode;
211
212        dp->major_variation = halfrandom(dp, VARIATION_LEN);
213        /*  0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 6 */
214        dp->major_variation = ((dp->major_variation >= VARIATION_LEN >> 1) &&
215                               (dp->major_variation < VARIATION_LEN - 1)) ?
216                (dp->major_variation + 1) >> 1 : dp->major_variation >> 1;
217
218        if (dp->grow) {
219                dp->rainbow = 0;
220                if (mode) {
221                        if (!dp->color || halfrandom(dp, 8)) {
222                                dp->nfractals = halfrandom(dp, 30) + 5;
223                                dp->fractal_len = DISTRIB_A;
224                        } else {
225                                dp->nfractals = halfrandom(dp, 5) + 5;
226                                dp->fractal_len = DISTRIB_B;
227                        }
228                } else {
229                        dp->rainbow = dp->color;
230                        dp->nfractals = 1;
231                        dp->fractal_len = DISTRIB_B;
232                }
233        } else {
234                dp->nfractals = 1;
235                dp->rainbow = dp->color;
236                dp->fractal_len = 2000000;
237        }
238        dp->fractal_len = (dp->fractal_len * MI_COUNT(mi)) / 20;
239
240        MI_CLEARWINDOW(mi);
241}
242
243static void
244pick_df_coefs(ModeInfo * mi)
245{
246        driftstruct *dp = &drifts[MI_SCREEN(mi)];
247        int         i, j, k;
248        double      r;
249
250        for (i = 0; i < dp->nxforms; i++) {
251
252                r = 1e-6;
253                for (j = 0; j < 2; j++)
254                        for (k = 0; k < 3; k++) {
255                                dp->df[j][k][i] = ((double) halfrandom(dp, 1000) / 500.0 - 1.0);
256                                r += dp->df[j][k][i] * dp->df[j][k][i];
257                        }
258                r = (3 + halfrandom(dp, 5)) * 0.01 / sqrt(r);
259                for (j = 0; j < 2; j++)
260                        for (k = 0; k < 3; k++)
261                                dp->df[j][k][i] *= r;
262        }
263}
264
265static void
266free_drift(driftstruct *dp)
267{
268        if (dp->ncpoints != NULL) {
269                (void) free((void *) dp->ncpoints);
270                dp->ncpoints = (int *) NULL;
271        }
272        if (dp->cpts != NULL) {
273                (void) free((void *) dp->cpts);
274                dp->cpts = (XPoint *) NULL;
275        }
276}
277
278static void
279initfractal(ModeInfo * mi)
280{
281        driftstruct *dp = &drifts[MI_SCREEN(mi)];
282        int         i, j, k;
283
284#define XFORM_LEN 9
285
286        dp->fuse = FUSE;
287        dp->total_points = 0;
288
289        if (!dp->ncpoints) {
290                if ((dp->ncpoints = (int *) malloc(sizeof (int) * MI_NCOLORS(mi))) ==
291                        NULL) {
292                        free_drift(dp);
293                        return;
294                }
295        }
296        if (!dp->cpts) {
297                if ((dp->cpts = (XPoint *) malloc(MAXBATCH2 * sizeof (XPoint) *
298                         MI_NCOLORS(mi))) == NULL) {
299                        free_drift(dp);
300                        return;
301                }
302        }
303
304        if (dp->rainbow)
305                for (i = 0; i < MI_NPIXELS(mi); i++)
306                        dp->ncpoints[i] = 0;
307        else
308                dp->npoints = 0;
309        dp->nxforms = halfrandom(dp, XFORM_LEN);
310        /* 2, 2, 2, 3, 3, 3, 4, 4, 5 */
311        dp->nxforms = (dp->nxforms >= XFORM_LEN - 1) + dp->nxforms / 3 + 2;
312
313        dp->c = dp->x = dp->y = 0.0;
314        if (dp->liss && !halfrandom(dp, 10)) {
315                dp->liss_time = 0;
316        }
317        if (!dp->grow)
318                pick_df_coefs(mi);
319        for (i = 0; i < dp->nxforms; i++) {
320                if (NMAJORVARS == dp->major_variation)
321                        dp->variation[i] = halfrandom(dp, NMAJORVARS);
322                else
323                        dp->variation[i] = dp->major_variation;
324                for (j = 0; j < 2; j++)
325                        for (k = 0; k < 3; k++) {
326                                if (dp->liss)
327                                        dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]);
328                                else
329                                        dp->f[j][k][i] = ((double) halfrandom(dp, 1000) / 500.0 - 1.0);
330                        }
331        }
332        if (dp->color)
333                dp->pixcol = MI_PIXEL(mi, halfrandom(dp, MI_NPIXELS(mi)));
334        else
335                dp->pixcol = MI_WHITE_PIXEL(mi);
336
337}
338
339
340void
341init_drift(ModeInfo * mi)
342{
343        driftstruct *dp;
344
345        if (drifts == NULL) {
346                if ((drifts = (driftstruct *) calloc(MI_NUM_SCREENS(mi),
347                                              sizeof (driftstruct))) == NULL)
348                        return;
349        }
350        dp = &drifts[MI_SCREEN(mi)];
351
352        dp->width = MI_WIDTH(mi);
353        dp->height = MI_HEIGHT(mi);
354        dp->color = MI_NPIXELS(mi) > 2;
355
356        if (MI_IS_FULLRANDOM(mi)) {
357                if (NRAND(3) == 0)
358                        dp->grow = True;
359                else {
360                        dp->grow = False;
361                        dp->liss = (Bool) (LRAND() & 1);
362                }
363        } else {
364                dp->grow = grow;
365                if (dp->grow)
366                        dp->liss = False;
367                else
368                        dp->liss = liss;
369        }
370        initmode(mi, 1);
371        initfractal(mi);
372}
373
374static void
375iter(driftstruct * dp)
376{
377        int         i = frandom(dp, dp->nxforms);
378        double      nx, ny, nc;
379
380
381        if (i)
382                nc = (dp->c + 1.0) / 2.0;
383        else
384                nc = dp->c / 2.0;
385
386        nx = dp->f[0][0][i] * dp->x + dp->f[0][1][i] * dp->y + dp->f[0][2][i];
387        ny = dp->f[1][0][i] * dp->x + dp->f[1][1][i] * dp->y + dp->f[1][2][i];
388
389
390        switch (dp->variation[i]) {
391                case 1:
392                        /* sinusoidal */
393                        nx = sin(nx);
394                        ny = sin(ny);
395                        break;
396                case 2:
397                        {
398                                /* complex */
399                                double      r2 = nx * nx + ny * ny + 1e-6;
400
401                                nx = nx / r2;
402                                ny = ny / r2;
403                                break;
404                        }
405                case 3:
406                        /* bent */
407                        if (nx < 0.0)
408                                nx = nx * 2.0;
409                        if (ny < 0.0)
410                                ny = ny / 2.0;
411                        break;
412                case 4:
413                        {
414                                /* swirl */
415
416                                double      r = (nx * nx + ny * ny);    /* times k here is fun */
417                                double      c1 = sin(r);
418                                double      c2 = cos(r);
419                                double      t = nx;
420
421                                if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
422                                        ny = 1e4;
423                                else
424                                        ny = c2 * t + c1 * ny;
425                                nx = c1 * nx - c2 * ny;
426                                break;
427                        }
428                case 5:
429                        {
430                                /* horseshoe */
431                                double      r, c1, c2, t;
432
433                                /* Avoid atan2: DOMAIN error message */
434                                if (nx == 0.0 && ny == 0.0)
435                                        r = 0.0;
436                                else
437                                        r = atan2(nx, ny);      /* times k here is fun */
438                                c1 = sin(r);
439                                c2 = cos(r);
440                                t = nx;
441
442                                nx = c1 * nx - c2 * ny;
443                                ny = c2 * t + c1 * ny;
444                                break;
445                        }
446                case 6:
447                        {
448                                /* drape */
449                                double      t;
450
451                                /* Avoid atan2: DOMAIN error message */
452                                if (nx == 0.0 && ny == 0.0)
453                                        t = 0.0;
454                                else
455                                        t = atan2(nx, ny) / M_PI;
456
457                                if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
458                                        ny = 1e4;
459                                else
460                                        ny = sqrt(nx * nx + ny * ny) - 1.0;
461                                nx = t;
462                                break;
463                        }
464        }
465
466#if 0
467        /* here are some others */
468        {
469                /* broken */
470                if (nx > 1.0)
471                        nx = nx - 1.0;
472                if (nx < -1.0)
473                        nx = nx + 1.0;
474                if (ny > 1.0)
475                        ny = ny - 1.0;
476                if (ny < -1.0)
477                        ny = ny + 1.0;
478                break;
479        }
480        {
481                /* complex sine */
482                double      u = nx, v = ny;
483                double      ev = exp(v);
484                double      emv = exp(-v);
485
486                nx = (ev + emv) * sin(u) / 2.0;
487                ny = (ev - emv) * cos(u) / 2.0;
488        }
489        {
490
491                /* polynomial */
492                if (nx < 0)
493                        nx = -nx * nx;
494                else
495                        nx = nx * nx;
496
497                if (ny < 0)
498                        ny = -ny * ny;
499                else
500                        ny = ny * ny;
501        }
502        {
503                /* spherical */
504                double      r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
505
506                nx = nx / r;
507                ny = ny / r;
508        }
509        {
510                nx = atan(nx) / M_PI_2
511                        ny = atan(ny) / M_PI_2
512        }
513#endif
514
515        /* how to check nan too?  some machines don't have finite().
516           don't need to check ny, it'll propogate */
517        if (nx > 1e4 || nx < -1e4) {
518                nx = halfrandom(dp, 1000) / 500.0 - 1.0;
519                ny = halfrandom(dp, 1000) / 500.0 - 1.0;
520                dp->fuse = FUSE;
521        }
522        dp->x = nx;
523        dp->y = ny;
524        dp->c = nc;
525
526}
527
528static void
529draw(ModeInfo * mi, driftstruct * dp, Drawable d)
530{
531        Display    *display = MI_DISPLAY(mi);
532        GC          gc = MI_GC(mi);
533        double      x = dp->x;
534        double      y = dp->y;
535        int         fixed_x, fixed_y, npix, c, n;
536
537        if (dp->fuse) {
538                dp->fuse--;
539                return;
540        }
541        if (!(x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0))
542                return;
543
544        fixed_x = (int) ((dp->width / 2) * (x + 1.0));
545        fixed_y = (int) ((dp->height / 2) * (y + 1.0));
546
547        if (!dp->rainbow) {
548
549                dp->pts[dp->npoints].x = fixed_x;
550                dp->pts[dp->npoints].y = fixed_y;
551                dp->npoints++;
552                if (dp->npoints == MAXBATCH1) {
553                        XSetForeground(display, gc, dp->pixcol);
554                        XDrawPoints(display, d, gc, dp->pts, dp->npoints, CoordModeOrigin);
555                        dp->npoints = 0;
556                }
557        } else {
558
559                npix = MI_NPIXELS(mi);
560                c = (int) (dp->c * npix);
561
562                if (c < 0)
563                        c = 0;
564                if (c >= npix)
565                        c = npix - 1;
566                n = dp->ncpoints[c];
567                dp->cpts[c * MAXBATCH2 + n].x = fixed_x;
568                dp->cpts[c * MAXBATCH2 + n].y = fixed_y;
569                if (++dp->ncpoints[c] == MAXBATCH2) {
570                        XSetForeground(display, gc, MI_PIXEL(mi, c));
571                        XDrawPoints(display, d, gc, &(dp->cpts[c * MAXBATCH2]),
572                                    dp->ncpoints[c], CoordModeOrigin);
573                        dp->ncpoints[c] = 0;
574                }
575        }
576}
577
578static void
579draw_flush(ModeInfo * mi, driftstruct * dp, Drawable d)
580{
581        Display    *display = MI_DISPLAY(mi);
582        GC          gc = MI_GC(mi);
583
584        if (dp->rainbow) {
585                int         npix = MI_NPIXELS(mi);
586                int         i;
587
588                for (i = 0; i < npix; i++) {
589                        if (dp->ncpoints[i]) {
590                                XSetForeground(display, gc, MI_PIXEL(mi, i));
591                                XDrawPoints(display, d, gc, &(dp->cpts[i * MAXBATCH2]),
592                                            dp->ncpoints[i], CoordModeOrigin);
593                                dp->ncpoints[i] = 0;
594                        }
595                }
596        } else {
597                if (dp->npoints)
598                        XSetForeground(display, gc, dp->pixcol);
599                XDrawPoints(display, d, gc, dp->pts,
600                            dp->npoints, CoordModeOrigin);
601                dp->npoints = 0;
602        }
603}
604
605
606void
607draw_drift(ModeInfo * mi)
608{
609        Window      window = MI_WINDOW(mi);
610        driftstruct *dp;
611
612        if (drifts == NULL)
613                return;
614        dp = &drifts[MI_SCREEN(mi)];
615        if (dp->ncpoints == NULL)
616                return;
617
618        MI_IS_DRAWN(mi) = True;
619        dp->timer = 3000;
620        while (dp->timer) {
621                iter(dp);
622                draw(mi, dp, window);
623                if (dp->total_points++ > dp->fractal_len) {
624                        draw_flush(mi, dp, window);
625                        if (0 == --dp->nfractals) {
626#ifdef STANDALONE
627                          XSync(MI_DISPLAY(mi), False);
628                          sleep(4); /* #### make settable */
629                          erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
630#endif /* STANDALONE */
631                                initmode(mi, frandom(dp, 2));
632                        }
633                        initfractal(mi);
634                }
635                dp->timer--;
636        }
637        if (!dp->grow) {
638                int         i, j, k;
639
640                draw_flush(mi, dp, window);
641                if (dp->liss)
642                        dp->liss_time++;
643                for (i = 0; i < dp->nxforms; i++)
644                        for (j = 0; j < 2; j++)
645                                for (k = 0; k < 3; k++) {
646                                        if (dp->liss)
647                                                dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]);
648                                        else {
649                                                double      t = dp->f[j][k][i] += dp->df[j][k][i];
650
651                                                if (t < -1.0 || 1.0 < t)
652                                                        dp->df[j][k][i] *= -1.0;
653                                        }
654                                }
655        }
656}
657
658void
659release_drift(ModeInfo * mi)
660{
661        if (drifts != NULL) {
662                int         screen;
663
664                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
665                        free_drift(&drifts[screen]);
666                (void) free((void *) drifts);
667                drifts = (driftstruct *) NULL;
668        }
669}
670
671void
672refresh_drift(ModeInfo * mi)
673{
674        MI_CLEARWINDOW(mi);
675}
676
677#endif /* MODE_drift */
Note: See TracBrowser for help on using the repository browser.