From http://www.jwz.org/xscreensaver/xscreensaver-5.38.tar.gz
[xscreensaver] / hacks / thornbird.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* thornbird --- continuously varying Thornbird set */
3
4 #if 0
5 static const char sccsid[] = "@(#)thornbird.c   5.00 2000/11/01 xlockmore";
6 #endif
7
8 /*-
9  * Copyright (c) 1996 by Tim Auckland <tda10.geo@yahoo.com>
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  * "thornbird" shows a view of the "Bird in a Thornbush" fractal,
24  * continuously varying the three free parameters.
25  *
26  * Revision History:
27  * 01-Nov-2000: Allocation checks
28  * 04-Jun-1999: 3D tumble added by Tim Auckland
29  * 31-Jul-1997: Adapted from discrete.c Copyright (c) 1996 by Tim Auckland
30  */
31
32 #ifdef STANDALONE
33 # define MODE_thornbird
34 #define DEFAULTS        "*delay:    10000 \n" \
35                                         "*count:    100   \n" \
36                                          "*cycles:  400   \n" \
37                                          "*ncolors: 64    \n" \
38                                          "*fpsSolid: true    \n" \
39                                         "*ignoreRotation: True \n" \
40                                     "*lowrez: True \n" \
41
42 # define BRIGHT_COLORS
43 # define release_thornbird 0
44 # define reshape_thornbird 0
45 # define thornbird_handle_event 0
46 # include "xlockmore.h"         /* in xscreensaver distribution */
47 #else /* STANDALONE */
48 # include "xlock.h"             /* in xlockmore distribution */
49 #endif /* STANDALONE */
50
51 #ifdef MODE_thornbird
52
53 ENTRYPOINT ModeSpecOpt thornbird_opts =
54 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
55
56 #ifdef USE_MODULES
57 ModStruct   thornbird_description =
58 {"thornbird", "init_thornbird", "draw_thornbird", (char *) NULL,
59  "refresh_thornbird", "init_thornbird", "free_thornbird", &thornbird_opts,
60  1000, 800, 16, 1, 64, 1.0, "",
61  "Shows an animated Bird in a Thorn Bush fractal map", 0, NULL};
62
63 #endif
64
65 #define balance_rand(v) ((LRAND()/MAXRAND*(v))-((v)/2)) /* random around 0 */
66
67 typedef struct {
68         int         maxx;
69         int         maxy;       /* max of the screen */
70         double      a;
71         double      b;
72         double      c;
73         double      d;
74         double      e;
75         double      i;
76         double      j;          /* thornbird parameters */
77     struct {
78           double  f1;
79           double  f2;
80         }           liss;
81     struct {
82           double  theta;
83           double  dtheta;
84           double  phi;
85           double  dphi;
86         }           tumble;
87     int         inc;
88         int         pix;
89         int         count;
90         int         nbuffers;
91         XPoint    **pointBuffer;        /* pointer for XDrawPoints */
92 } thornbirdstruct;
93
94 static thornbirdstruct *thornbirds = (thornbirdstruct *) NULL;
95
96 ENTRYPOINT void
97 free_thornbird(ModeInfo * mi)
98 {
99         thornbirdstruct *hp = &thornbirds[MI_SCREEN(mi)];
100         if (hp->pointBuffer != NULL) {
101                 int         buffer;
102
103                 for (buffer = 0; buffer < hp->nbuffers; buffer++)
104                         if (hp->pointBuffer[buffer] != NULL)
105                                 (void) free((void *) hp->pointBuffer[buffer]);
106                 (void) free((void *) hp->pointBuffer);
107                 hp->pointBuffer = (XPoint **) NULL;
108         }
109 }
110
111 ENTRYPOINT void
112 init_thornbird (ModeInfo * mi)
113 {
114         thornbirdstruct *hp;
115
116         MI_INIT (mi, thornbirds);
117         hp = &thornbirds[MI_SCREEN(mi)];
118
119
120         hp->maxx = MI_WIDTH(mi);
121         hp->maxy = MI_HEIGHT(mi);
122
123         hp->b = 0.1;
124         hp->i = hp->j = 0.1;
125
126         hp->pix = 0;
127         hp->inc = 0;
128
129         hp->nbuffers = MI_CYCLES(mi);
130
131         if (hp->pointBuffer == NULL)
132                 if ((hp->pointBuffer = (XPoint **) calloc(MI_CYCLES(mi),
133                                 sizeof (XPoint *))) == NULL) {
134                         free_thornbird(mi);
135                         return;
136                 }
137
138         if (hp->pointBuffer[0] == NULL)
139                 if ((hp->pointBuffer[0] = (XPoint *) malloc(MI_COUNT(mi) *
140                                 sizeof (XPoint))) == NULL) {
141                         free_thornbird(mi);
142                         return;
143                 }
144
145         /* select frequencies for parameter variation */
146         hp->liss.f1 = LRAND() % 5000;
147         hp->liss.f2 = LRAND() % 2000;
148
149         /* choose random 3D tumbling */
150         hp->tumble.theta = 0;
151         hp->tumble.phi = 0;
152         hp->tumble.dtheta = balance_rand(0.001);
153         hp->tumble.dphi = balance_rand(0.005);
154
155         /* Clear the background. */
156         MI_CLEARWINDOW(mi);
157
158         hp->count = 0;
159 }
160
161
162 ENTRYPOINT void
163 draw_thornbird(ModeInfo * mi)
164 {
165         Display    *dsp = MI_DISPLAY(mi);
166         Window      win = MI_WINDOW(mi);
167         double      oldj, oldi;
168         int         batchcount = MI_COUNT(mi);
169         int         k;
170         XPoint     *xp;
171         GC          gc = MI_GC(mi);
172         int         erase;
173         int         current;
174
175         double      sint, cost, sinp, cosp;
176         thornbirdstruct *hp;
177
178         if (thornbirds == NULL)
179                 return;
180         hp = &thornbirds[MI_SCREEN(mi)];
181         if (hp->pointBuffer == NULL)
182                 return;
183
184         erase = (hp->inc + 1) % MI_CYCLES(mi);
185         current = hp->inc % MI_CYCLES(mi);
186         k = batchcount;
187
188
189         xp = hp->pointBuffer[current];
190
191         /* vary papameters */
192         hp->a = 1.99 + (0.4 * sin(hp->inc / hp->liss.f1) +
193                                         0.05 * cos(hp->inc / hp->liss.f2));
194         hp->c = 0.80 + (0.15 * cos(hp->inc / hp->liss.f1) +
195                                         0.05 * sin(hp->inc / hp->liss.f2));
196
197         /* vary view */
198         hp->tumble.theta += hp->tumble.dtheta;
199         hp->tumble.phi += hp->tumble.dphi;
200         sint = sin(hp->tumble.theta);
201         cost = cos(hp->tumble.theta);
202         sinp = sin(hp->tumble.phi);
203         cosp = cos(hp->tumble.phi);
204
205         while (k--) {
206                 oldj = hp->j;
207                 oldi = hp->i;
208
209                 hp->j = oldi;
210                 hp->i = (1 - hp->c) * cos(M_PI * hp->a * oldj) + hp->c * hp->b;
211                 hp->b = oldj;
212
213                 xp->x = (short)
214                   (hp->maxx / 2 * (1
215                                                    + sint*hp->j + cost*cosp*hp->i - cost*sinp*hp->b));
216                 xp->y = (short)
217                   (hp->maxy / 2 * (1
218                                                    - cost*hp->j + sint*cosp*hp->i - sint*sinp*hp->b));
219                 xp++;
220         }
221
222         MI_IS_DRAWN(mi) = True;
223
224     if (MI_COUNT(mi) < 1) MI_COUNT(mi) = 1;
225         if (hp->pointBuffer[erase] == NULL) {
226                 if ((hp->pointBuffer[erase] = (XPoint *) malloc(MI_COUNT(mi) *
227                                 sizeof (XPoint))) == NULL) {
228                         free_thornbird(mi);
229                         return;
230                 }
231         } else {
232                 XSetForeground(dsp, gc, MI_BLACK_PIXEL(mi));
233                 XDrawPoints(dsp, win, gc, hp->pointBuffer[erase],
234                             batchcount, CoordModeOrigin);
235         }
236         if (MI_NPIXELS(mi) > 2) {
237                 XSetForeground(dsp, gc, MI_PIXEL(mi, hp->pix));
238 #if 0
239                 if (erase == 0) /* change colours after "cycles" cycles */
240 #else
241         if (!((hp->inc + 1) % (1 + (MI_CYCLES(mi) / 3)))) /* jwz: sooner */
242 #endif
243                         if (++hp->pix >= MI_NPIXELS(mi))
244                                 hp->pix = 0;
245         } else
246                 XSetForeground(dsp, gc, MI_WHITE_PIXEL(mi));
247
248         XDrawPoints(dsp, win, gc, hp->pointBuffer[current],
249                     batchcount, CoordModeOrigin);
250         hp->inc++;
251 }
252
253 #ifndef STANDALONE
254 ENTRYPOINT void
255 refresh_thornbird (ModeInfo * mi)
256 {
257         MI_CLEARWINDOW(mi);
258 }
259 #endif
260
261
262 XSCREENSAVER_MODULE ("Thornbird", thornbird)
263
264 #endif /* MODE_thornbird */