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@jwz.org: 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 # define SMOOTH_COLORS
40 # include "xlockmore.h" /* from the xscreensaver distribution */
42 #else /* !STANDALONE */
43 # include "xlock.h" /* from the xlockmore distribution */
44 #endif /* !STANDALONE */
47 #define MAXBATCH1 200 /* mono */
48 #define MAXBATCH2 20 /* color */
49 #define FUSE 10 /* discard this many initial iterations */
53 #define DEF_GROW "False" /* Grow fractals instead of animating one at a time,
54 would then be like flame */
55 #define DEF_LISS "False" /* if this is defined then instead of a point
56 bouncing around in a high dimensional sphere, we
57 use lissojous figures. Only makes sense if
63 static XrmOptionDescRec opts[] =
65 {"-grow", ".drift.grow", XrmoptionNoArg, (caddr_t) "on"},
66 {"+grow", ".drift.grow", XrmoptionNoArg, (caddr_t) "off"},
67 {"-liss", ".drift.trail", XrmoptionNoArg, (caddr_t) "on"},
68 {"+liss", ".drift.trail", XrmoptionNoArg, (caddr_t) "off"}
70 static argtype vars[] =
72 {(caddr_t *) & grow, "grow", "Grow", DEF_GROW, t_Bool},
73 {(caddr_t *) & liss, "liss", "Liss", DEF_LISS, t_Bool}
75 static OptionStruct desc[] =
77 {"-/+grow", "turn on/off growing fractals, else they are animated"},
78 {"-/+liss", "turn on/off using lissojous figures to get points"}
81 ModeSpecOpt drift_opts = { 4, opts, 2, vars, desc };
85 /* shape of current flame */
87 double f[2][3][MAXLEV]; /* a bunch of non-homogeneous xforms */
88 int variation[10]; /* for each xform */
91 double df[2][3][MAXLEV];
93 /* high-level control */
94 int mode; /* 0->slow/single 1->fast/many */
95 int nfractals; /* draw this many fractals */
97 int fractal_len; /* pts/fractal */
99 int rainbow; /* more than one color per fractal
100 1-> computed by adding dimension to fractal */
102 int width, height; /* of window */
105 /* draw info about current flame */
106 int fuse; /* iterate this many before drawing */
107 int total_points; /* draw this many pts before fractal ends */
108 int npoints; /* how many we've computed but not drawn */
109 XPoint pts[MAXBATCH1]; /* here they are */
110 unsigned long pixcol;
111 /* when drawing in color, we have a buffer per color */
112 int ncpoints[NUMCOLORS];
113 XPoint cpts[NUMCOLORS][MAXBATCH2];
120 static driftstruct *drifts = NULL;
125 static short lasthalf = 0;
142 static long saved_random_bits = 0;
143 static int nbits = 0;
147 saved_random_bits = LRAND();
152 result = saved_random_bits & 1;
153 saved_random_bits >>= 1;
158 result = saved_random_bits & 3;
159 saved_random_bits >>= 2;
166 result = saved_random_bits & 3;
167 saved_random_bits >>= 2;
172 result = saved_random_bits & 7;
173 saved_random_bits >>= 3;
179 (void) fprintf(stderr, "bad arg to frandom\n");
185 #define DISTRIB_A (halfrandom(7000) + 9000)
186 #define DISTRIB_B ((frandom(3) + 1) * (frandom(3) + 1) * 120000)
187 #define LEN(x) (sizeof(x)/sizeof((x)[0]))
190 initmode(ModeInfo * mi, int mode)
192 driftstruct *dp = &drifts[MI_SCREEN(mi)];
194 #define VARIATION_LEN 14
198 dp->major_variation = halfrandom(VARIATION_LEN);
199 /* 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 6 */
200 dp->major_variation = ((dp->major_variation >= VARIATION_LEN >> 1) &&
201 (dp->major_variation < VARIATION_LEN - 1)) ?
202 (dp->major_variation + 1) >> 1 : dp->major_variation >> 1;
207 if (!dp->color || halfrandom(8)) {
208 dp->nfractals = halfrandom(30) + 5;
209 dp->fractal_len = DISTRIB_A;
211 dp->nfractals = halfrandom(5) + 5;
212 dp->fractal_len = DISTRIB_B;
215 dp->rainbow = dp->color;
217 dp->fractal_len = DISTRIB_B;
221 dp->rainbow = dp->color;
222 dp->fractal_len = 2000000;
224 dp->fractal_len = (dp->fractal_len * MI_BATCHCOUNT(mi)) / 20;
225 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
229 pick_df_coefs(ModeInfo * mi)
231 driftstruct *dp = &drifts[MI_SCREEN(mi)];
235 for (i = 0; i < dp->nxforms; i++) {
238 for (j = 0; j < 2; j++)
239 for (k = 0; k < 3; k++) {
240 dp->df[j][k][i] = ((double) halfrandom(1000) / 500.0 - 1.0);
241 r += dp->df[j][k][i] * dp->df[j][k][i];
243 r = (3 + halfrandom(5)) * 0.01 / sqrt(r);
244 for (j = 0; j < 2; j++)
245 for (k = 0; k < 3; k++)
246 dp->df[j][k][i] *= r;
251 initfractal(ModeInfo * mi)
253 driftstruct *dp = &drifts[MI_SCREEN(mi)];
259 dp->total_points = 0;
261 for (i = 0; i < MI_NPIXELS(mi); i++)
265 dp->nxforms = halfrandom(XFORM_LEN);
266 /* 2, 2, 2, 3, 3, 3, 4, 4, 5 */
267 dp->nxforms = (dp->nxforms >= XFORM_LEN - 1) + dp->nxforms / 3 + 2;
269 dp->c = dp->x = dp->y = 0.0;
270 if (dp->liss && !halfrandom(10)) {
275 for (i = 0; i < dp->nxforms; i++) {
276 if (NMAJORVARS == dp->major_variation)
277 dp->variation[i] = halfrandom(NMAJORVARS);
279 dp->variation[i] = dp->major_variation;
280 for (j = 0; j < 2; j++)
281 for (k = 0; k < 3; k++) {
283 dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]);
285 dp->f[j][k][i] = ((double) halfrandom(1000) / 500.0 - 1.0);
289 dp->pixcol = MI_PIXEL(mi, halfrandom(MI_NPIXELS(mi)));
291 dp->pixcol = MI_WIN_WHITE_PIXEL(mi);
297 init_drift(ModeInfo * mi)
301 if (drifts == NULL) {
302 if ((drifts = (driftstruct *) calloc(MI_NUM_SCREENS(mi),
303 sizeof (driftstruct))) == NULL)
306 dp = &drifts[MI_SCREEN(mi)];
308 dp->width = MI_WIN_WIDTH(mi);
309 dp->height = MI_WIN_HEIGHT(mi);
310 dp->color = MI_NPIXELS(mi) > 2;
312 if (MI_WIN_IS_FULLRANDOM(mi)) {
313 #if 1 /* jwz: even up the odds */
314 switch ((int) (LRAND() % 3)) {
315 case 0: dp->grow = True; dp->liss = False; break;
316 case 1: dp->grow = False; dp->liss = True; break;
317 default: dp->grow = False; dp->liss = False; break;
318 /* liss and grow don't work together. */
325 dp->liss = (Bool) (LRAND() & 1);
340 iter(driftstruct * dp)
342 int i = frandom(dp->nxforms);
347 nc = (dp->c + 1.0) / 2.0;
351 nx = dp->f[0][0][i] * dp->x + dp->f[0][1][i] * dp->y + dp->f[0][2][i];
352 ny = dp->f[1][0][i] * dp->x + dp->f[1][1][i] * dp->y + dp->f[1][2][i];
355 switch (dp->variation[i]) {
364 double r2 = nx * nx + ny * ny + 1e-6;
381 double r = (nx * nx + ny * ny); /* times k here is fun */
386 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
389 ny = c2 * t + c1 * ny;
390 nx = c1 * nx - c2 * ny;
398 /* Avoid atan2: DOMAIN error message */
399 if (nx == 0.0 && ny == 0.0)
402 r = atan2(nx, ny); /* times k here is fun */
407 nx = c1 * nx - c2 * ny;
408 ny = c2 * t + c1 * ny;
416 /* Avoid atan2: DOMAIN error message */
417 if (nx == 0.0 && ny == 0.0)
420 t = atan2(nx, ny) / M_PI;
422 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
425 ny = sqrt(nx * nx + ny * ny) - 1.0;
432 /* here are some others */
447 double u = nx, v = ny;
449 double emv = exp(-v);
451 nx = (ev + emv) * sin(u) / 2.0;
452 ny = (ev - emv) * cos(u) / 2.0;
469 double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
475 nx = atan(nx) / M_PI_2
476 ny = atan(ny) / M_PI_2
480 /* how to check nan too? some machines don't have finite().
481 don't need to check ny, it'll propogate */
482 if (nx > 1e4 || nx < -1e4) {
483 nx = halfrandom(1000) / 500.0 - 1.0;
484 ny = halfrandom(1000) / 500.0 - 1.0;
494 draw(ModeInfo * mi, driftstruct * dp, Drawable d)
496 Display *display = MI_DISPLAY(mi);
500 int fixed_x, fixed_y, npix, c, n;
506 if (!(x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0))
509 fixed_x = (int) ((dp->width / 2) * (x + 1.0));
510 fixed_y = (int) ((dp->height / 2) * (y + 1.0));
514 dp->pts[dp->npoints].x = fixed_x;
515 dp->pts[dp->npoints].y = fixed_y;
517 if (dp->npoints == MAXBATCH1) {
518 XSetForeground(display, gc, dp->pixcol);
519 XDrawPoints(display, d, gc, dp->pts, dp->npoints, CoordModeOrigin);
524 npix = MI_NPIXELS(mi);
525 c = (int) (dp->c * npix);
532 dp->cpts[c][n].x = fixed_x;
533 dp->cpts[c][n].y = fixed_y;
534 if (++dp->ncpoints[c] == MAXBATCH2) {
535 XSetForeground(display, gc, MI_PIXEL(mi, c));
536 XDrawPoints(display, d, gc, dp->cpts[c],
537 dp->ncpoints[c], CoordModeOrigin);
544 draw_flush(ModeInfo * mi, driftstruct * dp, Drawable d)
546 Display *display = MI_DISPLAY(mi);
550 int npix = MI_NPIXELS(mi);
553 for (i = 0; i < npix; i++) {
554 if (dp->ncpoints[i]) {
555 XSetForeground(display, gc, MI_PIXEL(mi, i));
556 XDrawPoints(display, d, gc, dp->cpts[i],
557 dp->ncpoints[i], CoordModeOrigin);
563 XSetForeground(display, gc, dp->pixcol);
564 XDrawPoints(display, d, gc, dp->pts,
565 dp->npoints, CoordModeOrigin);
572 draw_drift(ModeInfo * mi)
574 Window window = MI_WINDOW(mi);
575 driftstruct *dp = &drifts[MI_SCREEN(mi)];
581 draw(mi, dp, window);
582 if (dp->total_points++ > dp->fractal_len) {
583 draw_flush(mi, dp, window);
584 if (0 == --dp->nfractals) {
586 XSync(MI_DISPLAY(mi), False);
587 sleep(4); /* #### make settable */
588 erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
589 #endif /* STANDALONE */
590 initmode(mi, frandom(2));
599 draw_flush(mi, dp, window);
602 for (i = 0; i < dp->nxforms; i++)
603 for (j = 0; j < 2; j++)
604 for (k = 0; k < 3; k++) {
606 dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]);
608 double t = dp->f[j][k][i] += dp->df[j][k][i];
610 if (t < -1.0 || 1.0 < t)
611 dp->df[j][k][i] *= -1.0;
618 release_drift(ModeInfo * mi)
620 if (drifts != NULL) {
621 (void) free((void *) drifts);
627 refresh_drift(ModeInfo * mi)
629 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));