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

Revision 20148, 11.4 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 * julia --- continuously varying Julia set.
3 */
4#if 0
5static const char sccsid[] = "@(#)julia.c       4.03 97/04/10 xlockmore";
6#endif
7
8/* Copyright (c) 1995 Sean McCullough <bankshot@mailhost.nmt.edu>.
9 *
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.
15 *
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.
21 *
22 * Revision History:
23 * 28-May-97: jwz@jwz.org: added interactive frobbing with the mouse.
24 * 10-May-97: jwz@jwz.org: turned into a standalone program.
25 * 02-Dec-95: snagged boilerplate from hop.c
26 *           used ifs {w0 = sqrt(x-c), w1 = -sqrt(x-c)} with random iteration
27 *           to plot the julia set, and sinusoidially varied parameter for set
28 *           and plotted parameter with a circle.
29 */
30
31/*-
32 * One thing to note is that batchcount is the *depth* of the search tree,
33 * so the number of points computed is 2^batchcount - 1.  I use 8 or 9
34 * on a dx266 and it looks okay.  The sinusoidal variation of the parameter
35 * might not be as interesting as it could, but it still gives an idea of
36 * the effect of the parameter.
37 */
38
39#ifdef STANDALONE
40# define PROGCLASS                                      "Julia"
41# define HACK_INIT                                      init_julia
42# define HACK_DRAW                                      draw_julia
43# define julia_opts                                     xlockmore_opts
44# define DEFAULTS       "*count:                1000  \n"                       \
45                                        "*cycles:               20    \n"                       \
46                                        "*delay:                10000 \n"                       \
47                                        "*ncolors:              200   \n"
48# define UNIFORM_COLORS
49# include "xlockmore.h"                         /* in xscreensaver distribution */
50#else  /* !STANDALONE */
51# include "xlock.h"                                     /* in xlockmore distribution */
52#endif /* !STANDALONE */
53
54
55static Bool track_p;
56
57#define DEF_MOUSE "False"
58
59static XrmOptionDescRec opts[] =
60{
61        {"-mouse", ".julia.mouse", XrmoptionNoArg, (caddr_t) "on"},
62        {"+mouse", ".julia.mouse", XrmoptionNoArg, (caddr_t) "off"},
63};
64static argtype vars[] =
65{
66        {(caddr_t *) & track_p, "mouse", "Mouse", DEF_MOUSE, t_Bool},
67};
68static OptionStruct desc[] =
69{
70        {"-/+mouse", "turn on/off mouse tracking"},
71};
72
73ModeSpecOpt julia_opts = { 2, opts, 1, vars, desc };
74
75
76#define numpoints ((0x2<<jp->depth)-1)
77
78typedef struct {
79        int         centerx;
80        int         centery;    /* center of the screen */
81        double      cr;
82        double      ci;         /* julia params */
83        int         depth;
84        int         inc;
85        int         circsize;
86        int         erase;
87        int         pix;
88        long        itree;
89        int         buffer;
90        int         nbuffers;
91        int         redrawing, redrawpos;
92        Pixmap      pixmap;
93        Cursor      cursor;
94        GC          stippledGC;
95        XPoint    **pointBuffer;        /* pointer for XDrawPoints */
96
97} juliastruct;
98
99static juliastruct *julias = NULL;
100
101/* How many segments to draw per cycle when redrawing */
102#define REDRAWSTEP 3
103
104static void
105apply(juliastruct * jp, register double xr, register double xi, int d)
106{
107        double      theta, r;
108
109        jp->pointBuffer[jp->buffer][jp->itree].x =
110                (int) (0.5 * xr * jp->centerx + jp->centerx);
111        jp->pointBuffer[jp->buffer][jp->itree].y =
112                (int) (0.5 * xi * jp->centery + jp->centery);
113        jp->itree++;
114
115        if (d > 0) {
116                xi -= jp->ci;
117                xr -= jp->cr;
118
119/* Avoid atan2: DOMAIN error message */
120                if (xi == 0.0 && xr == 0.0)
121                        theta = 0.0;
122                else
123                        theta = atan2(xi, xr) / 2.0;
124
125                /*r = pow(xi * xi + xr * xr, 0.25); */
126                r = sqrt(sqrt(xi * xi + xr * xr));      /* 3 times faster */
127
128                xr = r * cos(theta);
129                xi = r * sin(theta);
130
131                d--;
132                apply(jp, xr, xi, d);
133                apply(jp, -xr, -xi, d);
134        }
135}
136
137static void
138incr(ModeInfo * mi, juliastruct * jp)
139{
140        int cx, cy;
141
142        if (track_p)
143          {
144                Window r, c;
145                int rx, ry;
146                unsigned int m;
147                XQueryPointer(MI_DISPLAY(mi), MI_WINDOW(mi),
148                                          &r, &c, &rx, &ry, &cx, &cy, &m);
149                if (cx <= 0 || cy <= 0 ||
150                        cx >= MI_WIN_WIDTH(mi) || cy >= MI_WIN_HEIGHT(mi))
151                  goto NOTRACK;
152          }
153
154        if (track_p)
155          {
156                jp->cr = ((double) (cx + 2 - jp->centerx)) * 2 / jp->centerx;
157                jp->ci = ((double) (cy + 2 - jp->centery)) * 2 / jp->centery;
158          }
159        else
160          {
161          NOTRACK:
162                jp->cr = 1.5 * (sin(M_PI * (jp->inc / 300.0)) *
163                                                sin(jp->inc * M_PI / 200.0));
164                jp->ci = 1.5 * (cos(M_PI * (jp->inc / 300.0)) *
165                                                cos(jp->inc * M_PI / 200.0));
166
167                jp->cr += 0.5 * cos(M_PI * jp->inc / 400.0);
168                jp->ci += 0.5 * sin(M_PI * jp->inc / 400.0);
169          }
170}
171
172void
173init_julia(ModeInfo * mi)
174{
175        Display    *display = MI_DISPLAY(mi);
176        Window      window = MI_WINDOW(mi);
177        juliastruct *jp;
178        XGCValues   gcv;
179        int         i;
180
181        if (julias == NULL) {
182                if ((julias = (juliastruct *) calloc(MI_NUM_SCREENS(mi),
183                                              sizeof (juliastruct))) == NULL)
184                        return;
185        }
186        jp = &julias[MI_SCREEN(mi)];
187
188        jp->centerx = MI_WIN_WIDTH(mi) / 2;
189        jp->centery = MI_WIN_HEIGHT(mi) / 2;
190
191        jp->depth = MI_BATCHCOUNT(mi);
192        if (jp->depth > 10)
193                jp->depth = 10;
194
195
196        if (track_p && !jp->cursor)
197          {
198                Pixmap bit;
199                XColor black;
200                black.red = black.green = black.blue = 0;
201                black.flags = DoRed|DoGreen|DoBlue;
202                bit = XCreatePixmapFromBitmapData (display, window, "\000", 1, 1,
203                                                                                   MI_WIN_BLACK_PIXEL(mi),
204                                                                                   MI_WIN_BLACK_PIXEL(mi), 1);
205                jp->cursor = XCreatePixmapCursor (display, bit, bit, &black, &black,
206                                                                                  0, 0);
207                XFreePixmap (display, bit);
208          }
209
210        if (jp->pixmap != None &&
211            jp->circsize != (MIN(jp->centerx, jp->centery) / 60) * 2 + 1) {
212                XFreePixmap(display, jp->pixmap);
213                jp->pixmap = None;
214        }
215        if (jp->pixmap == None) {
216                GC          fg_gc = None, bg_gc = None;
217
218                jp->circsize = (MIN(jp->centerx, jp->centery) / 96) * 2 + 1;
219                jp->pixmap = XCreatePixmap(display, window, jp->circsize, jp->circsize, 1);
220                gcv.foreground = 1;
221                fg_gc = XCreateGC(display, jp->pixmap, GCForeground, &gcv);
222                gcv.foreground = 0;
223                bg_gc = XCreateGC(display, jp->pixmap, GCForeground, &gcv);
224                XFillRectangle(display, jp->pixmap, bg_gc,
225                               0, 0, jp->circsize, jp->circsize);
226                if (jp->circsize < 2)
227                        XDrawPoint(display, jp->pixmap, fg_gc, 0, 0);
228                else
229                        XFillArc(display, jp->pixmap, fg_gc,
230                                 0, 0, jp->circsize, jp->circsize, 0, 23040);
231                if (fg_gc != None)
232                        XFreeGC(display, fg_gc);
233                if (bg_gc != None)
234                        XFreeGC(display, bg_gc);
235        }
236
237        if (MI_WIN_IS_INROOT(mi))
238          ;
239        else if (jp->circsize > 0)
240          XDefineCursor (display, window, jp->cursor);
241        else
242          XUndefineCursor (display, window);
243
244        if (!jp->stippledGC) {
245                gcv.foreground = MI_WIN_BLACK_PIXEL(mi);
246                gcv.background = MI_WIN_BLACK_PIXEL(mi);
247                if ((jp->stippledGC = XCreateGC(display, window,
248                                 GCForeground | GCBackground, &gcv)) == None)
249                        return;
250        }
251        if (MI_NPIXELS(mi) > 2)
252                jp->pix = NRAND(MI_NPIXELS(mi));
253        jp->inc = ((LRAND() & 1) * 2 - 1) * NRAND(200);
254        jp->nbuffers = (MI_CYCLES(mi) + 1);
255        if (!jp->pointBuffer)
256                jp->pointBuffer = (XPoint **) calloc(jp->nbuffers, sizeof (XPoint *));
257        for (i = 0; i < jp->nbuffers; ++i)
258                if (jp->pointBuffer[i])
259                        (void) memset((char *) jp->pointBuffer[i], 0,
260                                      numpoints * sizeof (XPoint));
261                else
262                        jp->pointBuffer[i] = (XPoint *) calloc(numpoints, sizeof (XPoint));
263        jp->buffer = 0;
264        jp->redrawing = 0;
265        jp->erase = 0;
266        XClearWindow(display, window);
267}
268
269
270/* hack: moved here by jwz. */
271#define ERASE_IMAGE(d,w,g,x,y,xl,yl,xs,ys) \
272if (yl<y) \
273(y<yl+ys)?XFillRectangle(d,w,g,xl,yl,xs,y-yl): \
274XFillRectangle(d,w,g,xl,yl,xs,ys); \
275else if (yl>y) \
276(y>yl-ys)?XFillRectangle(d,w,g,xl,y+ys,xs,yl-y): \
277XFillRectangle(d,w,g,xl,yl,xs,ys); \
278if (xl<x) \
279(x<xl+xs)?XFillRectangle(d,w,g,xl,yl,x-xl,ys): \
280XFillRectangle(d,w,g,xl,yl,xs,ys); \
281else if (xl>x) \
282(x>xl-xs)?XFillRectangle(d,w,g,x+xs,yl,xl-x,ys): \
283XFillRectangle(d,w,g,xl,yl,xs,ys)
284
285
286void
287draw_julia(ModeInfo * mi)
288{
289        Display    *display = MI_DISPLAY(mi);
290        Window      window = MI_WINDOW(mi);
291        GC          gc = MI_GC(mi);
292        juliastruct *jp = &julias[MI_SCREEN(mi)];
293        double      r, theta;
294        register double xr = 0.0, xi = 0.0;
295        int         k = 64, rnd = 0, i, j;
296        XPoint     *xp = jp->pointBuffer[jp->buffer], old_circle, new_circle;
297
298        old_circle.x = (int) (jp->centerx * jp->cr / 2) + jp->centerx - 2;
299        old_circle.y = (int) (jp->centery * jp->ci / 2) + jp->centery - 2;
300        incr(mi, jp);
301        new_circle.x = (int) (jp->centerx * jp->cr / 2) + jp->centerx - 2;
302        new_circle.y = (int) (jp->centery * jp->ci / 2) + jp->centery - 2;
303        XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
304        ERASE_IMAGE(display, window, gc, new_circle.x, new_circle.y,
305                    old_circle.x, old_circle.y, jp->circsize, jp->circsize);
306        /* draw a circle at the c-parameter so you can see it's effect on the
307           structure of the julia set */
308        XSetTSOrigin(display, jp->stippledGC, new_circle.x, new_circle.y);
309        XSetForeground(display, jp->stippledGC, MI_WIN_WHITE_PIXEL(mi));
310        XSetStipple(display, jp->stippledGC, jp->pixmap);
311        XSetFillStyle(display, jp->stippledGC, FillOpaqueStippled);
312        XFillRectangle(display, window, jp->stippledGC, new_circle.x, new_circle.y,
313                       jp->circsize, jp->circsize);
314        XFlush(display);
315        if (jp->erase == 1) {
316                XDrawPoints(display, window, gc,
317                    jp->pointBuffer[jp->buffer], numpoints, CoordModeOrigin);
318        }
319        jp->inc++;
320        if (MI_NPIXELS(mi) > 2) {
321                XSetForeground(display, gc, MI_PIXEL(mi, jp->pix));
322                if (++jp->pix >= MI_NPIXELS(mi))
323                        jp->pix = 0;
324        } else
325                XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
326        while (k--) {
327
328                /* save calls to LRAND by using bit shifts over and over on the same
329                   int for 32 iterations, then get a new random int */
330                if (!(k % 32))
331                        rnd = LRAND();
332
333                /* complex sqrt: x^0.5 = radius^0.5*(cos(theta/2) + i*sin(theta/2)) */
334
335                xi -= jp->ci;
336                xr -= jp->cr;
337
338                /* Avoid atan2: DOMAIN error message */
339                if (xi == 0.0 && xr == 0.0)
340                        theta = 0.0;
341                else
342                        theta = atan2(xi, xr) / 2.0;
343
344                /*r = pow(xi * xi + xr * xr, 0.25); */
345                r = sqrt(sqrt(xi * xi + xr * xr));      /* 3 times faster */
346
347                xr = r * cos(theta);
348                xi = r * sin(theta);
349
350                if ((rnd >> (k % 32)) & 0x1) {
351                        xi = -xi;
352                        xr = -xr;
353                }
354                xp->x = jp->centerx + (int) ((jp->centerx >> 1) * xr);
355                xp->y = jp->centery + (int) ((jp->centery >> 1) * xi);
356                xp++;
357        }
358
359        jp->itree = 0;
360        apply(jp, xr, xi, jp->depth);
361
362        XDrawPoints(display, window, gc,
363                    jp->pointBuffer[jp->buffer], numpoints, CoordModeOrigin);
364
365        jp->buffer++;
366        if (jp->buffer > jp->nbuffers - 1) {
367                jp->buffer -= jp->nbuffers;
368                jp->erase = 1;
369        }
370        if (jp->redrawing) {
371                for (i = 0; i < REDRAWSTEP; i++) {
372                        j = (jp->buffer - jp->redrawpos + jp->nbuffers) % jp->nbuffers;
373                        XDrawPoints(display, window, gc,
374                             jp->pointBuffer[j], numpoints, CoordModeOrigin);
375
376                        if (++(jp->redrawpos) >= jp->nbuffers) {
377                                jp->redrawing = 0;
378                                break;
379                        }
380                }
381        }
382}
383
384void
385release_julia(ModeInfo * mi)
386{
387        if (julias != NULL) {
388                int         screen;
389
390                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
391                        Display    *display = MI_DISPLAY(mi);
392                        juliastruct *jp = &julias[screen];
393                        int         buffer;
394
395                        if (jp->pointBuffer) {
396                                for (buffer = 0; buffer < jp->nbuffers; buffer++)
397                                        if (jp->pointBuffer[buffer])
398                                                (void) free((void *) jp->pointBuffer[buffer]);
399                                (void) free((void *) jp->pointBuffer);
400                        }
401                        if (jp->stippledGC != None)
402                                XFreeGC(display, jp->stippledGC);
403                        if (jp->pixmap != None)
404                                XFreePixmap(display, jp->pixmap);
405                        if (jp->cursor)
406                          XFreeCursor (display, jp->cursor);
407                }
408                (void) free((void *) julias);
409                julias = NULL;
410        }
411}
412
413void
414refresh_julia(ModeInfo * mi)
415{
416        juliastruct *jp = &julias[MI_SCREEN(mi)];
417
418        jp->redrawing = 1;
419        jp->redrawpos = 0;
420}
Note: See TracBrowser for help on using the repository browser.