1 /* -*- Mode: C; tab-width: 4 -*-
2 * drift --- drifting recursive fractal cosmic flames.
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)drift.c 4.02 97/04/01 xlockmore";
8 /* Copyright (c) 1991 by Patrick J. Naughton.
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.
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.
23 * 10-May-97: jwz@netscape.com: turned into a standalone program.
24 * 01-Jan-97: Moved new flame to drift. Compile time options now run time.
25 * 01-Jun-95: Updated by Scott Draves.
26 * 27-Jun-91: vary number of functions used.
27 * 24-Jun-91: fixed portability problem with integer mod (%).
28 * 06-Jun-91: Written. (received from Scott Draves, spot@cs.cmu.edu).
32 # define PROGCLASS "Drift"
33 # define HACK_INIT init_drift
34 # define HACK_DRAW draw_drift
35 # define drift_opts xlockmore_opts
36 # define DEFAULTS "*count: 30 \n" \
39 "*eraseSpeed: 400 \n" \
41 # define SMOOTH_COLORS
42 # include "xlockmore.h" /* from the xscreensaver distribution */
44 #else /* !STANDALONE */
45 # include "xlock.h" /* from the xlockmore distribution */
46 #endif /* !STANDALONE */
49 #define MAXBATCH1 200 /* mono */
50 #define MAXBATCH2 20 /* color */
51 #define FUSE 10 /* discard this many initial iterations */
55 #define DEF_GROW "False" /* Grow fractals instead of animating one at a time,
56 would then be like flame */
57 #define DEF_LISS "False" /* if this is defined then instead of a point
58 bouncing around in a high dimensional sphere, we
59 use lissojous figures. Only makes sense if
65 static XrmOptionDescRec opts[] =
67 {"-grow", ".drift.grow", XrmoptionNoArg, (caddr_t) "on"},
68 {"+grow", ".drift.grow", XrmoptionNoArg, (caddr_t) "off"},
69 {"-liss", ".drift.trail", XrmoptionNoArg, (caddr_t) "on"},
70 {"+liss", ".drift.trail", XrmoptionNoArg, (caddr_t) "off"}
72 static argtype vars[] =
74 {(caddr_t *) & grow, "grow", "Grow", DEF_GROW, t_Bool},
75 {(caddr_t *) & liss, "liss", "Liss", DEF_LISS, t_Bool}
77 static OptionStruct desc[] =
79 {"-/+grow", "turn on/off growing fractals, else they are animated"},
80 {"-/+liss", "turn on/off using lissojous figures to get points"}
83 ModeSpecOpt drift_opts = { 4, opts, 2, vars, desc };
87 /* shape of current flame */
89 double f[2][3][MAXLEV]; /* a bunch of non-homogeneous xforms */
90 int variation[10]; /* for each xform */
93 double df[2][3][MAXLEV];
95 /* high-level control */
96 int mode; /* 0->slow/single 1->fast/many */
97 int nfractals; /* draw this many fractals */
99 int fractal_len; /* pts/fractal */
101 int rainbow; /* more than one color per fractal
102 1-> computed by adding dimension to fractal */
104 int width, height; /* of window */
107 /* draw info about current flame */
108 int fuse; /* iterate this many before drawing */
109 int total_points; /* draw this many pts before fractal ends */
110 int npoints; /* how many we've computed but not drawn */
111 XPoint pts[MAXBATCH1]; /* here they are */
112 unsigned long pixcol;
113 /* when drawing in color, we have a buffer per color */
114 int ncpoints[NUMCOLORS];
115 XPoint cpts[NUMCOLORS][MAXBATCH2];
122 static driftstruct *drifts = NULL;
127 static short lasthalf = 0;
144 static long saved_random_bits = 0;
145 static int nbits = 0;
149 saved_random_bits = LRAND();
154 result = saved_random_bits & 1;
155 saved_random_bits >>= 1;
160 result = saved_random_bits & 3;
161 saved_random_bits >>= 2;
168 result = saved_random_bits & 3;
169 saved_random_bits >>= 2;
174 result = saved_random_bits & 7;
175 saved_random_bits >>= 3;
181 (void) fprintf(stderr, "bad arg to frandom\n");
187 #define DISTRIB_A (halfrandom(7000) + 9000)
188 #define DISTRIB_B ((frandom(3) + 1) * (frandom(3) + 1) * 120000)
189 #define LEN(x) (sizeof(x)/sizeof((x)[0]))
192 initmode(ModeInfo * mi, int mode)
194 driftstruct *dp = &drifts[MI_SCREEN(mi)];
196 #define VARIATION_LEN 14
200 dp->major_variation = halfrandom(VARIATION_LEN);
201 /* 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 6 */
202 dp->major_variation = ((dp->major_variation >= VARIATION_LEN >> 1) &&
203 (dp->major_variation < VARIATION_LEN - 1)) ?
204 (dp->major_variation + 1) >> 1 : dp->major_variation >> 1;
209 if (!dp->color || halfrandom(8)) {
210 dp->nfractals = halfrandom(30) + 5;
211 dp->fractal_len = DISTRIB_A;
213 dp->nfractals = halfrandom(5) + 5;
214 dp->fractal_len = DISTRIB_B;
217 dp->rainbow = dp->color;
219 dp->fractal_len = DISTRIB_B;
223 dp->rainbow = dp->color;
224 dp->fractal_len = 2000000;
226 dp->fractal_len = (dp->fractal_len * MI_BATCHCOUNT(mi)) / 20;
227 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
231 pick_df_coefs(ModeInfo * mi)
233 driftstruct *dp = &drifts[MI_SCREEN(mi)];
237 for (i = 0; i < dp->nxforms; i++) {
240 for (j = 0; j < 2; j++)
241 for (k = 0; k < 3; k++) {
242 dp->df[j][k][i] = ((double) halfrandom(1000) / 500.0 - 1.0);
243 r += dp->df[j][k][i] * dp->df[j][k][i];
245 r = (3 + halfrandom(5)) * 0.01 / sqrt(r);
246 for (j = 0; j < 2; j++)
247 for (k = 0; k < 3; k++)
248 dp->df[j][k][i] *= r;
253 initfractal(ModeInfo * mi)
255 driftstruct *dp = &drifts[MI_SCREEN(mi)];
261 dp->total_points = 0;
263 for (i = 0; i < MI_NPIXELS(mi); i++)
267 dp->nxforms = halfrandom(XFORM_LEN);
268 /* 2, 2, 2, 3, 3, 3, 4, 4, 5 */
269 dp->nxforms = (dp->nxforms >= XFORM_LEN - 1) + dp->nxforms / 3 + 2;
271 dp->c = dp->x = dp->y = 0.0;
272 if (dp->liss && !halfrandom(10)) {
277 for (i = 0; i < dp->nxforms; i++) {
278 if (NMAJORVARS == dp->major_variation)
279 dp->variation[i] = halfrandom(NMAJORVARS);
281 dp->variation[i] = dp->major_variation;
282 for (j = 0; j < 2; j++)
283 for (k = 0; k < 3; k++) {
285 dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]);
287 dp->f[j][k][i] = ((double) halfrandom(1000) / 500.0 - 1.0);
291 dp->pixcol = MI_PIXEL(mi, halfrandom(MI_NPIXELS(mi)));
293 dp->pixcol = MI_WIN_WHITE_PIXEL(mi);
299 init_drift(ModeInfo * mi)
303 if (drifts == NULL) {
304 if ((drifts = (driftstruct *) calloc(MI_NUM_SCREENS(mi),
305 sizeof (driftstruct))) == NULL)
308 dp = &drifts[MI_SCREEN(mi)];
310 dp->width = MI_WIN_WIDTH(mi);
311 dp->height = MI_WIN_HEIGHT(mi);
312 dp->color = MI_NPIXELS(mi) > 2;
314 if (MI_WIN_IS_FULLRANDOM(mi)) {
315 #if 1 /* jwz: even up the odds */
316 switch ((int) (LRAND() % 3)) {
317 case 0: dp->grow = True; dp->liss = False; break;
318 case 1: dp->grow = False; dp->liss = True; break;
319 default: dp->grow = False; dp->liss = False; break;
320 /* liss and grow don't work together. */
327 dp->liss = (Bool) (LRAND() & 1);
342 iter(driftstruct * dp)
344 int i = frandom(dp->nxforms);
349 nc = (dp->c + 1.0) / 2.0;
353 nx = dp->f[0][0][i] * dp->x + dp->f[0][1][i] * dp->y + dp->f[0][2][i];
354 ny = dp->f[1][0][i] * dp->x + dp->f[1][1][i] * dp->y + dp->f[1][2][i];
357 switch (dp->variation[i]) {
366 double r2 = nx * nx + ny * ny + 1e-6;
383 double r = (nx * nx + ny * ny); /* times k here is fun */
388 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
391 ny = c2 * t + c1 * ny;
392 nx = c1 * nx - c2 * ny;
400 /* Avoid atan2: DOMAIN error message */
401 if (nx == 0.0 && ny == 0.0)
404 r = atan2(nx, ny); /* times k here is fun */
409 nx = c1 * nx - c2 * ny;
410 ny = c2 * t + c1 * ny;
418 /* Avoid atan2: DOMAIN error message */
419 if (nx == 0.0 && ny == 0.0)
422 t = atan2(nx, ny) / M_PI;
424 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
427 ny = sqrt(nx * nx + ny * ny) - 1.0;
434 /* here are some others */
449 double u = nx, v = ny;
451 double emv = exp(-v);
453 nx = (ev + emv) * sin(u) / 2.0;
454 ny = (ev - emv) * cos(u) / 2.0;
471 double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
477 nx = atan(nx) / M_PI_2
478 ny = atan(ny) / M_PI_2
482 /* how to check nan too? some machines don't have finite().
483 don't need to check ny, it'll propogate */
484 if (nx > 1e4 || nx < -1e4) {
485 nx = halfrandom(1000) / 500.0 - 1.0;
486 ny = halfrandom(1000) / 500.0 - 1.0;
496 draw(ModeInfo * mi, driftstruct * dp, Drawable d)
498 Display *display = MI_DISPLAY(mi);
502 int fixed_x, fixed_y, npix, c, n;
508 if (!(x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0))
511 fixed_x = (int) ((dp->width / 2) * (x + 1.0));
512 fixed_y = (int) ((dp->height / 2) * (y + 1.0));
516 dp->pts[dp->npoints].x = fixed_x;
517 dp->pts[dp->npoints].y = fixed_y;
519 if (dp->npoints == MAXBATCH1) {
520 XSetForeground(display, gc, dp->pixcol);
521 XDrawPoints(display, d, gc, dp->pts, dp->npoints, CoordModeOrigin);
526 npix = MI_NPIXELS(mi);
527 c = (int) (dp->c * npix);
534 dp->cpts[c][n].x = fixed_x;
535 dp->cpts[c][n].y = fixed_y;
536 if (++dp->ncpoints[c] == MAXBATCH2) {
537 XSetForeground(display, gc, MI_PIXEL(mi, c));
538 XDrawPoints(display, d, gc, dp->cpts[c],
539 dp->ncpoints[c], CoordModeOrigin);
546 draw_flush(ModeInfo * mi, driftstruct * dp, Drawable d)
548 Display *display = MI_DISPLAY(mi);
552 int npix = MI_NPIXELS(mi);
555 for (i = 0; i < npix; i++) {
556 if (dp->ncpoints[i]) {
557 XSetForeground(display, gc, MI_PIXEL(mi, i));
558 XDrawPoints(display, d, gc, dp->cpts[i],
559 dp->ncpoints[i], CoordModeOrigin);
565 XSetForeground(display, gc, dp->pixcol);
566 XDrawPoints(display, d, gc, dp->pts,
567 dp->npoints, CoordModeOrigin);
574 draw_drift(ModeInfo * mi)
576 Window window = MI_WINDOW(mi);
577 driftstruct *dp = &drifts[MI_SCREEN(mi)];
583 draw(mi, dp, window);
584 if (dp->total_points++ > dp->fractal_len) {
585 draw_flush(mi, dp, window);
586 if (0 == --dp->nfractals) {
588 XSync(MI_DISPLAY(mi), False);
589 sleep(4); /* #### make settable */
590 erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
591 #endif /* STANDALONE */
592 initmode(mi, frandom(2));
601 draw_flush(mi, dp, window);
604 for (i = 0; i < dp->nxforms; i++)
605 for (j = 0; j < 2; j++)
606 for (k = 0; k < 3; k++) {
608 dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]);
610 double t = dp->f[j][k][i] += dp->df[j][k][i];
612 if (t < -1.0 || 1.0 < t)
613 dp->df[j][k][i] *= -1.0;
620 release_drift(ModeInfo * mi)
622 if (drifts != NULL) {
623 (void) free((void *) drifts);
629 refresh_drift(ModeInfo * mi)
631 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));