1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* drift --- drifting recursive fractal cosmic flames */
5 static const char sccsid[] = "@(#)drift.c 5.00 2000/11/01 xlockmore";
9 * Copyright (c) 1991 by Patrick J. Naughton.
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.
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.
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>
35 # define DEFAULTS "*delay: 10000 \n" \
38 "*fpsSolid: true \n" \
39 "*ignoreRotation: True \n" \
41 # define SMOOTH_COLORS
42 # include "xlockmore.h" /* in xscreensaver distribution */
44 #else /* STANDALONE */
45 # define ENTRYPOINT /**/
46 # include "xlock.h" /* in xlockmore distribution */
47 #endif /* STANDALONE */
51 #define DEF_GROW "False" /* Grow fractals instead of animating one at a time,
52 would then be like flame */
53 #define DEF_LISS "False" /* if this is defined then instead of a point
54 bouncing around in a high dimensional sphere, we
55 use lissojous figures. Only makes sense if
61 static XrmOptionDescRec opts[] =
63 {"-grow", ".drift.grow", XrmoptionNoArg, "on"},
64 {"+grow", ".drift.grow", XrmoptionNoArg, "off"},
65 {"-liss", ".drift.trail", XrmoptionNoArg, "on"},
66 {"+liss", ".drift.trail", XrmoptionNoArg, "off"}
68 static argtype vars[] =
70 {&grow, "grow", "Grow", DEF_GROW, t_Bool},
71 {&liss, "trail", "Trail", DEF_LISS, t_Bool}
73 static OptionStruct desc[] =
75 {"-/+grow", "turn on/off growing fractals, else they are animated"},
76 {"-/+liss", "turn on/off using lissojous figures to get points"}
79 ENTRYPOINT ModeSpecOpt drift_opts =
80 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
83 ModStruct drift_description =
84 {"drift", "init_drift", "draw_drift", "release_drift",
85 "refresh_drift", "init_drift", (char *) NULL, &drift_opts,
86 10000, 30, 1, 1, 64, 1.0, "",
87 "Shows cosmic drifting flame fractals", 0, NULL};
91 #define MAXBATCH1 200 /* mono */
92 #define MAXBATCH2 20 /* color */
93 #define FUSE 10 /* discard this many initial iterations */
98 /* shape of current flame */
100 double f[2][3][MAXLEV]; /* a bunch of non-homogeneous xforms */
101 int variation[10]; /* for each xform */
104 double df[2][3][MAXLEV];
106 /* high-level control */
107 int mode; /* 0->slow/single 1->fast/many */
108 int nfractals; /* draw this many fractals */
110 int fractal_len; /* pts/fractal */
112 int rainbow; /* more than one color per fractal
113 1-> computed by adding dimension to fractal */
115 int width, height; /* of window */
118 /* draw info about current flame */
119 int fuse; /* iterate this many before drawing */
120 int total_points; /* draw this many pts before fractal ends */
121 int npoints; /* how many we've computed but not drawn */
122 XPoint pts[MAXBATCH1]; /* here they are */
123 unsigned long pixcol;
124 /* when drawing in color, we have a buffer per color */
133 long saved_random_bits;
138 eraser_state *eraser;
142 static driftstruct *drifts = (driftstruct *) NULL;
145 halfrandom(driftstruct * dp, int mv)
154 dp->lasthalf = (short) (r >> 16);
161 frandom(driftstruct * dp, int n)
166 dp->saved_random_bits = LRAND();
171 result = (int) (dp->saved_random_bits & 1);
172 dp->saved_random_bits >>= 1;
177 result = (int) (dp->saved_random_bits & 3);
178 dp->saved_random_bits >>= 2;
181 return frandom(dp, 3);
185 result = (int) (dp->saved_random_bits & 3);
186 dp->saved_random_bits >>= 2;
191 result = (int) (dp->saved_random_bits & 7);
192 dp->saved_random_bits >>= 3;
195 return frandom(dp, 5);
198 (void) fprintf(stderr, "bad arg to frandom\n");
203 #define DISTRIB_A (halfrandom(dp, 7000) + 9000)
204 #define DISTRIB_B ((frandom(dp, 3) + 1) * (frandom(dp, 3) + 1) * 120000)
205 #define LEN(x) (sizeof(x)/sizeof((x)[0]))
208 initmode(ModeInfo * mi, int mode)
210 driftstruct *dp = &drifts[MI_SCREEN(mi)];
212 #define VARIATION_LEN 14
216 dp->major_variation = halfrandom(dp, VARIATION_LEN);
217 /* 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 6 */
218 dp->major_variation = ((dp->major_variation >= VARIATION_LEN >> 1) &&
219 (dp->major_variation < VARIATION_LEN - 1)) ?
220 (dp->major_variation + 1) >> 1 : dp->major_variation >> 1;
225 if (!dp->color || halfrandom(dp, 8)) {
226 dp->nfractals = halfrandom(dp, 30) + 5;
227 dp->fractal_len = DISTRIB_A;
229 dp->nfractals = halfrandom(dp, 5) + 5;
230 dp->fractal_len = DISTRIB_B;
233 dp->rainbow = dp->color;
235 dp->fractal_len = DISTRIB_B;
239 dp->rainbow = dp->color;
240 dp->fractal_len = 2000000;
242 dp->fractal_len = (dp->fractal_len * MI_COUNT(mi)) / 20;
250 pick_df_coefs(ModeInfo * mi)
252 driftstruct *dp = &drifts[MI_SCREEN(mi)];
256 for (i = 0; i < dp->nxforms; i++) {
259 for (j = 0; j < 2; j++)
260 for (k = 0; k < 3; k++) {
261 dp->df[j][k][i] = ((double) halfrandom(dp, 1000) / 500.0 - 1.0);
262 r += dp->df[j][k][i] * dp->df[j][k][i];
264 r = (3 + halfrandom(dp, 5)) * 0.01 / sqrt(r);
265 for (j = 0; j < 2; j++)
266 for (k = 0; k < 3; k++)
267 dp->df[j][k][i] *= r;
272 free_drift(driftstruct *dp)
274 if (dp->ncpoints != NULL) {
275 (void) free((void *) dp->ncpoints);
276 dp->ncpoints = (int *) NULL;
278 if (dp->cpts != NULL) {
279 (void) free((void *) dp->cpts);
280 dp->cpts = (XPoint *) NULL;
285 initfractal(ModeInfo * mi)
287 driftstruct *dp = &drifts[MI_SCREEN(mi)];
293 dp->total_points = 0;
296 if ((dp->ncpoints = (int *) malloc(sizeof (int) * MI_NCOLORS(mi))) ==
303 if ((dp->cpts = (XPoint *) malloc(MAXBATCH2 * sizeof (XPoint) *
304 MI_NCOLORS(mi))) == NULL) {
311 for (i = 0; i < MI_NPIXELS(mi); i++)
315 dp->nxforms = halfrandom(dp, XFORM_LEN);
316 /* 2, 2, 2, 3, 3, 3, 4, 4, 5 */
317 dp->nxforms = (dp->nxforms >= XFORM_LEN - 1) + dp->nxforms / 3 + 2;
319 dp->c = dp->x = dp->y = 0.0;
320 if (dp->liss && !halfrandom(dp, 10)) {
325 for (i = 0; i < dp->nxforms; i++) {
326 if (NMAJORVARS == dp->major_variation)
327 dp->variation[i] = halfrandom(dp, NMAJORVARS);
329 dp->variation[i] = dp->major_variation;
330 for (j = 0; j < 2; j++)
331 for (k = 0; k < 3; k++) {
333 dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]);
335 dp->f[j][k][i] = ((double) halfrandom(dp, 1000) / 500.0 - 1.0);
339 dp->pixcol = MI_PIXEL(mi, halfrandom(dp, MI_NPIXELS(mi)));
341 dp->pixcol = MI_WHITE_PIXEL(mi);
347 init_drift(ModeInfo * mi)
351 if (drifts == NULL) {
352 if ((drifts = (driftstruct *) calloc(MI_NUM_SCREENS(mi),
353 sizeof (driftstruct))) == NULL)
356 dp = &drifts[MI_SCREEN(mi)];
358 dp->width = MI_WIDTH(mi);
359 dp->height = MI_HEIGHT(mi);
360 dp->color = MI_NPIXELS(mi) > 2;
362 if (MI_IS_FULLRANDOM(mi)) {
367 dp->liss = (Bool) (LRAND() & 1);
381 iter(driftstruct * dp)
383 int i = frandom(dp, dp->nxforms);
388 nc = (dp->c + 1.0) / 2.0;
392 nx = dp->f[0][0][i] * dp->x + dp->f[0][1][i] * dp->y + dp->f[0][2][i];
393 ny = dp->f[1][0][i] * dp->x + dp->f[1][1][i] * dp->y + dp->f[1][2][i];
396 switch (dp->variation[i]) {
405 double r2 = nx * nx + ny * ny + 1e-6;
422 double r = (nx * nx + ny * ny); /* times k here is fun */
427 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
430 ny = c2 * t + c1 * ny;
431 nx = c1 * nx - c2 * ny;
439 /* Avoid atan2: DOMAIN error message */
440 if (nx == 0.0 && ny == 0.0)
443 r = atan2(nx, ny); /* times k here is fun */
448 nx = c1 * nx - c2 * ny;
449 ny = c2 * t + c1 * ny;
457 /* Avoid atan2: DOMAIN error message */
458 if (nx == 0.0 && ny == 0.0)
461 t = atan2(nx, ny) / M_PI;
463 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
466 ny = sqrt(nx * nx + ny * ny) - 1.0;
473 /* here are some others */
488 double u = nx, v = ny;
490 double emv = exp(-v);
492 nx = (ev + emv) * sin(u) / 2.0;
493 ny = (ev - emv) * cos(u) / 2.0;
510 double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
516 nx = atan(nx) / M_PI_2
517 ny = atan(ny) / M_PI_2
521 /* how to check nan too? some machines don't have finite().
522 don't need to check ny, it'll propogate */
523 if (nx > 1e4 || nx < -1e4) {
524 nx = halfrandom(dp, 1000) / 500.0 - 1.0;
525 ny = halfrandom(dp, 1000) / 500.0 - 1.0;
535 draw(ModeInfo * mi, driftstruct * dp, Drawable d)
537 Display *display = MI_DISPLAY(mi);
541 int fixed_x, fixed_y, npix, c, n;
547 if (!(x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0))
550 fixed_x = (int) ((dp->width / 2) * (x + 1.0));
551 fixed_y = (int) ((dp->height / 2) * (y + 1.0));
555 dp->pts[dp->npoints].x = fixed_x;
556 dp->pts[dp->npoints].y = fixed_y;
558 if (dp->npoints == MAXBATCH1) {
559 XSetForeground(display, gc, dp->pixcol);
560 XDrawPoints(display, d, gc, dp->pts, dp->npoints, CoordModeOrigin);
565 npix = MI_NPIXELS(mi);
566 c = (int) (dp->c * npix);
573 dp->cpts[c * MAXBATCH2 + n].x = fixed_x;
574 dp->cpts[c * MAXBATCH2 + n].y = fixed_y;
575 if (++dp->ncpoints[c] == MAXBATCH2) {
576 XSetForeground(display, gc, MI_PIXEL(mi, c));
577 XDrawPoints(display, d, gc, &(dp->cpts[c * MAXBATCH2]),
578 dp->ncpoints[c], CoordModeOrigin);
585 draw_flush(ModeInfo * mi, driftstruct * dp, Drawable d)
587 Display *display = MI_DISPLAY(mi);
591 int npix = MI_NPIXELS(mi);
594 for (i = 0; i < npix; i++) {
595 if (dp->ncpoints[i]) {
596 XSetForeground(display, gc, MI_PIXEL(mi, i));
597 XDrawPoints(display, d, gc, &(dp->cpts[i * MAXBATCH2]),
598 dp->ncpoints[i], CoordModeOrigin);
604 XSetForeground(display, gc, dp->pixcol);
605 XDrawPoints(display, d, gc, dp->pts,
606 dp->npoints, CoordModeOrigin);
613 draw_drift(ModeInfo * mi)
615 Window window = MI_WINDOW(mi);
620 dp = &drifts[MI_SCREEN(mi)];
621 if (dp->ncpoints == NULL)
624 if (dp->erase_countdown) {
625 if (!--dp->erase_countdown) {
626 dp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), dp->eraser);
631 dp->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), dp->eraser);
635 MI_IS_DRAWN(mi) = True;
639 draw(mi, dp, window);
640 if (dp->total_points++ > dp->fractal_len) {
641 draw_flush(mi, dp, window);
642 if (0 == --dp->nfractals) {
644 dp->erase_countdown = 4 * 1000000 / MI_PAUSE(mi);
645 #endif /* STANDALONE */
646 initmode(mi, frandom(dp, 2));
655 draw_flush(mi, dp, window);
658 for (i = 0; i < dp->nxforms; i++)
659 for (j = 0; j < 2; j++)
660 for (k = 0; k < 3; k++) {
662 dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]);
664 double t = dp->f[j][k][i] += dp->df[j][k][i];
666 if (t < -1.0 || 1.0 < t)
667 dp->df[j][k][i] *= -1.0;
674 release_drift(ModeInfo * mi)
676 if (drifts != NULL) {
679 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
680 free_drift(&drifts[screen]);
681 (void) free((void *) drifts);
682 drifts = (driftstruct *) NULL;
687 reshape_drift(ModeInfo * mi, int width, int height)
694 refresh_drift(ModeInfo * mi)
700 drift_handle_event (ModeInfo *mi, XEvent *event)
702 if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
704 reshape_drift (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
711 XSCREENSAVER_MODULE ("Drift", drift)
713 #endif /* MODE_drift */