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

Revision 20148, 27.7 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/* flow --- flow of strange bees */
3
4#if 0
5static const char sccsid[] = "@(#)flow.c 4.10 98/04/24 xlockmore";
6#endif
7
8/*-
9 * Copyright (c) 1996 by Tim Auckland <Tim.Auckland@Sun.COM>
10 * Portions added by Stephen Davies are Copyright (c) 2000 Stephen Davies
11 *
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
17 *
18 * This file is provided AS IS with no warranties of any kind.  The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof.  In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
23 *
24 * "flow" shows a variety of continuous phase-space flows around strange
25 * attractors.  It includes the well-known Lorentz mask (the "Butterfly"
26 * of chaos fame), two forms of Rossler's "Folded Band" and Poincare'
27 * sections of the "Birkhoff Bagel" and Duffing's forced occilator.
28 *
29 * Revision History:
30 * 21-Feb-00: Major hackage by Chalky (Stephen Davies, chalky@null.net)
31 *            Forced perspective mode, added 3d box around attractor which
32 *            involved coding 3d-planar-clipping against the view-frustrum
33 *            thingy. Also made view alternate between piggybacking on a 'bee'
34 *            to zooming around outside the attractor. Most bees slow down and
35 *            stop, to make the structure of the attractor more obvious.
36 * 31-Nov-98: [TDA] Added Duffing  (what a strange day that was :) DAB)
37 *   Duffing's forced oscillator has been added to the formula list and
38 *   the parameters section has been updated to display it in Poincare'
39 *   section.
40 * 30-Nov-98: [TDA] Added travelling perspective option
41 *   A more exciting point-of-view has been added to all autonomous flows.
42 *   This views the flow as seen by a particle moving with the flow.  In the
43 *   metaphor of the original code, I've attached a camera to one of the
44 *   trained bees!
45 * 30-Nov-98: [TDA] Much code cleanup.
46 * 09-Apr-97: [TDA] Ported to xlockmore-4
47 * 18-Jul-96: Adapted from swarm.c Copyright (c) 1991 by Patrick J. Naughton.
48 * 31-Aug-90: Adapted from xswarm by Jeff Butterworth. (butterwo@ncsc.org)
49 */
50
51#ifdef STANDALONE
52# define PROGCLASS      "Flow"
53# define HACK_INIT      init_flow
54# define HACK_DRAW      draw_flow
55# define flow_opts      xlockmore_opts
56# define DEFAULTS       "*delay:                1000 \n" \
57                                        "*count:                500 \n" \
58                                        "*cycles:               3000 \n" \
59                                        "*ncolors:              200 \n" \
60        "*rotate:         True \n" \
61        "*ride:           True \n" \
62        "*zoom:           True \n" \
63        "*allow2d:        True \n" \
64        "*box:            True \n" \
65        "*slow:           True \n" \
66        "*freeze:         True \n"
67# define SMOOTH_COLORS
68# include "xlockmore.h"         /* in xscreensaver distribution */
69# include "erase.h"
70
71#else /* STANDALONE */
72# include "xlock.h"             /* in xlockmore distribution */
73#endif /* STANDALONE */
74
75XrmOptionDescRec flow_options[];
76ModeSpecOpt flow_opts = { 7, flow_options, 0, NULL, NULL };
77
78#ifdef USE_MODULES
79ModStruct   flow_description = {
80        "flow", "init_flow", "draw_flow", "release_flow",
81        "refresh_flow", "init_flow", NULL, &flow_opts,
82        1000, 1024, 3000, 1, 64, 1.0, "",
83        "Shows dynamic strange attractors", 0, NULL
84};
85
86#endif
87
88typedef struct {
89        double      x;
90        double      y;
91        double      z;
92} dvector;
93
94typedef struct {
95        double      a, b, c;
96} Par;
97
98/* Macros */
99#define X(t,b)  (sp->p[t][b].x)
100#define Y(t,b)  (sp->p[t][b].y)
101#define Z(t,b)  (sp->p[t][b].z)
102#define balance_rand(v) ((LRAND()/MAXRAND*(v))-((v)/2)) /* random around 0 */
103#define SCALE_X(A) (sp->width/2+sp->width/sp->size*(A))
104/*#define SCALE_Y(A) (sp->height/2+sp->height/sp->size*(A))*/
105#define SCALE_Y(A) (sp->height/2+sp->width/sp->size*(A))
106
107/* Mode of operation. Rotate, ride and zoom are mutually exclusive */
108typedef enum {
109        FLOW_ROTATE = 1, /* Rotate around attractor */
110        FLOW_RIDE = 2,   /* Ride a trained bee */
111        FLOW_ZOOM = 4,   /* Zoom in and out */
112        FLOW_2D = 8,     /* Allow 2D attractors */
113        FLOW_BOX = 16,    /* Compute a box around the attractor */
114        FLOW_SLOW = 32,   /* Some bees are slower (and have antifreeze) */
115        FLOW_FREEZE = 64  /* Freeze some of the bees in action */
116} FlowMode;
117
118#define FLOW_DEFAULT (FLOW_ROTATE|FLOW_RIDE|FLOW_ZOOM|FLOW_2D|\
119                FLOW_BOX|FLOW_SLOW|FLOW_FREEZE)
120
121typedef struct {
122        int         width;
123        int         height;
124        int         count;
125        double      size;
126       
127        int         beecount;   /* number of bees */
128        XSegment   *csegs;          /* bee lines */
129        int        *cnsegs;
130        XSegment   *old_segs;   /* old bee lines */
131        int         nold_segs;
132        double      step;
133        double          slow;
134        double          slow_view;
135        dvector     centre;             /* centre */
136        dvector         range;
137        struct {
138                double  depth;
139                double  height;
140        }           view;
141        dvector         circle[2]; /* POV that circles around the scene */
142        dvector    *p[2];   /* bee positions x[time][bee#] */
143        struct {
144                double  theta;
145                double  dtheta;
146                double  phi;
147                double  dphi;
148        }           tumble;
149        dvector  (*ODE) (Par par, double x, double y, double z);
150        Par         par;
151        FlowMode                mode; /* Mode of operation */
152} flowstruct;
153
154static flowstruct *flows = NULL;
155
156static dvector
157Lorentz(Par par, double x, double y, double z)
158{
159        dvector d;
160
161        d.x = par.a * (y - x);
162        d.y = x * (par.b - z) - y;
163        d.z = x * y - par.c * z;
164        return d;
165}
166
167static dvector
168Rossler(Par par, double x, double y, double z)
169{
170        dvector d;
171
172        d.x = -(y + par.a * z);
173        d.y = x + y * par.b;
174        d.z = par.c + z * (x - 5.7);
175        return d;
176}
177
178static dvector
179RosslerCone(Par par, double x, double y, double z)
180{
181        dvector d;
182
183        d.x = -(y + par.a * z);
184        d.y = x + y * par.b - z * z * par.c;
185        d.z = 0.2 + z * (x - 5.7);
186        return d;
187}
188
189static dvector
190Birkhoff(Par par, double x, double y, double z)
191{
192        dvector d;
193
194        d.x = -y + par.b * sin(z);
195        d.y = 0.7 * x + par.a * y * (0.1 - x * x);
196        d.z = par.c;
197        return d;
198}
199
200static dvector
201Duffing(Par par, double x, double y, double z)
202{
203        dvector d;
204
205        d.x = -par.a * x - y/2 - y * y * y/8 + par.b * cos(z);
206        d.y = 2*x;
207        d.z = par.c;
208        return d;
209}
210
211void init_clip(flowstruct *sp);
212
213void
214init_flow(ModeInfo * mi)
215{
216        flowstruct *sp;
217        int         b;
218        double      beemult = 1;
219        static int  allocated = 0;
220
221        if (flows == NULL) {
222                if ((flows = (flowstruct *) calloc(MI_NUM_SCREENS(mi),
223                                               sizeof (flowstruct))) == NULL)
224                        return;
225        }
226        sp = &flows[MI_SCREEN(mi)];
227
228        sp->count = 0;
229        sp->slow = 0.999;
230        sp->slow_view = 0.90;
231
232        sp->width = MI_WIDTH(mi);
233        sp->height = MI_HEIGHT(mi);
234
235        sp->tumble.theta = balance_rand(M_PI);
236        sp->tumble.phi = balance_rand(M_PI);
237        sp->tumble.dtheta = 0.002;
238        sp->tumble.dphi = 0.001;
239        sp->view.height = 0;
240        sp->view.depth = 0; /* no perspective view */
241        sp->mode = 0;
242   if (get_boolean_resource ("rotate", "Boolean")) sp->mode |= FLOW_ROTATE;
243   if (get_boolean_resource ("ride", "Boolean")) sp->mode |= FLOW_RIDE;
244   if (get_boolean_resource ("zoom", "Boolean")) sp->mode |= FLOW_ZOOM;
245   if (get_boolean_resource ("allow2d", "Boolean")) sp->mode |= FLOW_2D;
246   if (get_boolean_resource ("slow", "Boolean")) sp->mode |= FLOW_SLOW;
247   if (get_boolean_resource ("freeze", "Boolean")) sp->mode |= FLOW_FREEZE;
248   if (get_boolean_resource ("box", "Boolean")) sp->mode |= FLOW_BOX;
249
250        b = (sp->mode & FLOW_2D) ? 5 : 3;
251        b = NRAND(b);
252
253        /* If more than one of rotate, ride and zoom are set, choose one */
254        if (b < 3) {
255                int num = 0, modes[3];
256
257                if (sp->mode & FLOW_ROTATE) modes[num++] = FLOW_ROTATE;
258                if (sp->mode & FLOW_RIDE) modes[num++] = FLOW_RIDE;
259                if (sp->mode & FLOW_ZOOM) modes[num++] = FLOW_ZOOM;
260
261                sp->mode &= ~(FLOW_ROTATE | FLOW_RIDE | FLOW_ZOOM);
262
263                if (num) sp->mode |= modes[ NRAND(num) ];
264                else sp->mode |= FLOW_ZOOM;
265        }
266       
267        switch (b) {
268        case 0:
269                sp->view.depth = 10;
270                sp->view.height = 0.2;
271                beemult = 3;
272                sp->ODE = Lorentz;
273                sp->step = 0.02;
274                sp->size = 60;
275                sp->centre.x = 0;
276                sp->centre.y = 0;
277                sp->centre.z = 24;
278                sp->range.x = 5;
279                sp->range.y = 5;
280                sp->range.z = 1;
281                sp->par.a = 10 + balance_rand(5);
282                sp->par.b = 28 + balance_rand(5);
283                sp->par.c = 2 + balance_rand(1);
284                break;
285        case 1:
286                sp->view.depth = 10;
287                sp->view.height = 0.1;
288                beemult = 4;
289                sp->ODE = Rossler;
290                sp->step = 0.05;
291                sp->size = 24;
292                sp->centre.x = 0;
293                sp->centre.y = 0;
294                sp->centre.z = 3;
295                sp->range.x = 4;
296                sp->range.y = 4;
297                sp->range.z = 7;
298                sp->par.a = 2 + balance_rand(1);
299                sp->par.b = 0.2 + balance_rand(0.1);
300                sp->par.c = 0.2 + balance_rand(0.1);
301                break;
302        case 2:
303                sp->view.depth = 10;
304                sp->view.height = 0.1;
305                beemult = 3;
306                sp->ODE = RosslerCone;
307                sp->step = 0.05;
308                sp->size = 24;
309                sp->centre.x = 0;
310                sp->centre.y = 0;
311                sp->centre.z = 3;
312                sp->range.x = 4;
313                sp->range.y = 4;
314                sp->range.z = 4;
315                sp->par.a = 2;
316                sp->par.b = 0.2;
317                sp->par.c = 0.25 + balance_rand(0.09);
318                break;
319        case 3:
320                sp->ODE = Birkhoff;
321                sp->step = 0.04;
322                sp->size = 2.6;
323                sp->centre.x = 0;
324                sp->centre.y = 0;
325                sp->centre.z = 0;
326                sp->range.x = 3;
327                sp->range.y = 4;
328                sp->range.z = 0;
329                sp->par.a = 10 + balance_rand(5);
330                sp->par.b = 0.35 + balance_rand(0.25);
331                sp->par.c = 1.57;
332                sp->tumble.theta = 0;
333                sp->tumble.phi = 0;
334                sp->tumble.dtheta = 0;
335                sp->tumble.dphi = 0;
336                break;
337        case 4:
338        default:
339                sp->ODE = Duffing;
340                sp->step = 0.02;
341                sp->size = 30;
342                sp->centre.x = 0;
343                sp->centre.y = 0;
344                sp->centre.z = 0;
345                sp->range.x = 20;
346                sp->range.y = 20;
347                sp->range.z = 0;
348                sp->par.a = 0.2 + balance_rand(0.1);
349                sp->par.b = 27.0 + balance_rand(3.0);
350                sp->par.c = 1.33;
351                sp->tumble.theta = 0;
352                sp->tumble.phi = 0;
353                sp->tumble.dtheta = -NRAND(2)*sp->par.c*sp->step;
354                sp->tumble.dphi = 0;
355                beemult = 0.5;
356                break;
357        }
358
359        sp->view.depth *= 4;
360
361        sp->beecount = beemult * MI_COUNT(mi);
362        if (sp->beecount < 0)   /* random variations */
363                sp->beecount = NRAND(-sp->beecount) + 1; /* Minimum 1 */
364
365        /* Clear the background. */
366        MI_CLEARWINDOW(mi);
367
368        if(!allocated || sp->beecount != allocated){ /* reallocate */
369                if (sp->csegs != NULL) {
370                        (void) free((void *) sp->csegs);
371                        sp->csegs = NULL;
372                }
373                if (sp->cnsegs != NULL) {
374                        (void) free((void *) sp->cnsegs);
375                        sp->cnsegs = NULL;
376                }
377                if (sp->old_segs != NULL) {
378                        (void) free((void *) sp->old_segs);
379                        sp->old_segs = NULL;
380                }
381                if (sp->p[0] != NULL) {
382                        (void) free((void *) sp->p[0]);
383                        sp->p[0] = NULL;
384                }
385                if (sp->p[1] != NULL) {
386                        (void) free((void *) sp->p[1]);
387                        sp->p[1] = NULL;
388                }
389                allocated = sp->beecount;
390        }
391
392        /* Allocate memory. */
393
394        if (!sp->csegs) {
395                sp->csegs = (XSegment *) malloc(sizeof (XSegment) * sp->beecount
396                                                * MI_NPIXELS(mi));
397                sp->cnsegs = (int *) malloc(sizeof (int) * MI_NPIXELS(mi));
398
399                sp->old_segs = (XSegment *) malloc(sizeof (XSegment) * sp->beecount);
400                sp->p[0] = (dvector *) malloc(sizeof (dvector) * sp->beecount);
401                sp->p[1] = (dvector *) malloc(sizeof (dvector) * sp->beecount);
402        }
403
404        /* Initialize point positions, velocities, etc. */
405
406        for (b = 0; b < sp->beecount; b++) {
407                X(1, b) = X(0, b) = balance_rand(sp->range.x);
408                Y(1, b) = Y(0, b) = balance_rand(sp->range.y);
409                Z(1, b) = Z(0, b) = balance_rand(sp->range.z);
410        }
411
412        init_clip(sp);
413
414}
415
416/* Clipping planes */
417#define PLANES 5
418static double plane_orig[][2][3] = {
419        /* X goes into screen, Y goes right, Z goes down(up?) */
420        /* {Normal}, {Point} */
421        { {1.0, 0, 0}, {0.01, 0, 0} },
422        { {1.0, 1.0, 0.0}, {0, 0, 0} },
423        { {1.0,-1.0, 0.0}, {0, 0, 0} },
424        { {1.0, 0.0, 1.0}, {0, 0, 0} },
425        { {1.0, 0.0,-1.0}, {0, 0, 0} }
426};
427static double plane[PLANES][2][3];
428static double plane_d[PLANES];
429
430#define BOX_P 32
431#define BOX_L 36
432#define MIN_BOX (3)
433#define MAX_BOX (MIN_BOX + BOX_L)
434/* Points that make up the box (normalized coordinates) */
435static double box_orig[][3] = {
436        {1,1,1},   /* 0 */
437        {1,1,-1},  /* 1 */
438        {1,-1,-1}, /* 2 */
439        {1,-1,1},  /* 3 */
440        {-1,1,1},  /* 4 */
441        {-1,1,-1}, /* 5 */
442        {-1,-1,-1},/* 6 */
443        {-1,-1,1}, /* 7 */
444        {1, .8, .8},
445        {1, .8,-.8},
446        {1,-.8,-.8},
447        {1,-.8, .8},
448        { .8,1, .8},
449        { .8,1,-.8},
450        {-.8,1,-.8},
451        {-.8,1, .8},
452        { .8, .8,1},
453        { .8,-.8,1},
454        {-.8,-.8,1},
455        {-.8, .8,1},
456        {-1, .8, .8},
457        {-1, .8,-.8},
458        {-1,-.8,-.8},
459        {-1,-.8, .8},
460        { .8,-1, .8},
461        { .8,-1,-.8},
462        {-.8,-1,-.8},
463        {-.8,-1, .8},
464        { .8, .8,-1},
465        { .8,-.8,-1},
466        {-.8,-.8,-1},
467        {-.8, .8,-1}
468};
469
470/* Container for scaled box points */
471static double box[BOX_P][3];
472
473/* Lines connecting the box dots */
474static double lines[][2] = {
475        {0,1}, {1,2}, {2,3}, {3,0}, /* box */
476        {4,5}, {5,6}, {6,7}, {7,4},
477        {0,4}, {1,5}, {2,6}, {3,7},
478        {4+4,5+4}, {5+4,6+4}, {6+4,7+4}, {7+4,4+4},
479        {4+8,5+8}, {5+8,6+8}, {6+8,7+8}, {7+8,4+8},
480        {4+12,5+12}, {5+12,6+12}, {6+12,7+12}, {7+12,4+12},
481        {4+16,5+16}, {5+16,6+16}, {6+16,7+16}, {7+16,4+16},
482        {4+20,5+20}, {5+20,6+20}, {6+20,7+20}, {7+20,4+20},
483        {4+24,5+24}, {5+24,6+24}, {6+24,7+24}, {7+24,4+24},
484};
485       
486/* Boundaries of bees */
487double xmin, xmax;
488double ymin, ymax;
489double zmin, zmax;
490
491void init_clip(flowstruct *sp)
492{
493        int i;
494
495        /* Scale the planes to the screen. I had to invert the projection
496         * algorithms so that when projected they would be right at the edge of the
497         * screen. */
498
499    /* #### jwz: I'm not really sure what it means when sp->view.depth is 0
500       in here -- what's the right thing to do? */
501
502        double width = (sp->view.depth
503                    ? sp->size/sp->view.depth/2
504                    : 1);
505        double height = (sp->view.depth
506                     ? (sp->size/sp->view.depth/2*
507                        sp->view.height/sp->view.height)
508                     : 1);
509        for (i = 0; i < PLANES; i++) {
510                /* Copy orig planes into planes, expanding <-> clippings */
511                plane[i][0][0] = plane_orig[i][0][0];
512                plane[i][0][1] = plane_orig[i][0][1] / width;
513                plane[i][0][2] = plane_orig[i][0][2] / height;
514                plane[i][1][0] = plane_orig[i][1][0];
515                plane[i][1][1] = plane_orig[i][1][1];
516                plane[i][1][2] = plane_orig[i][1][2];
517               
518                /* Calculate the 'd' part of 'ax + by + cz = d' */
519                plane_d[i] = - plane[i][0][0] * plane[i][1][0];
520                plane_d[i] -= plane[i][0][1] * plane[i][1][1];
521                plane_d[i] -= plane[i][0][2] * plane[i][1][2];
522        }
523        xmin = X(0, i); xmax = X(0,i);
524        ymin = Y(0, i); ymax = Y(0,i);
525        zmin = Z(0, i); zmax = Z(0,i);
526}
527
528/* Scale the box defined above to fit around all points */
529void create_box(flowstruct *sp)
530{
531        int i = MAX_BOX;
532        double xmid, ymid, zmid;
533        double xsize, ysize, zsize;
534        double size;
535
536        /* Count every 5th point for speed.. */
537        for (; i < sp->beecount; i += 5) {
538                if ( X(0,i) < xmin ) xmin = X(0, i);
539                else if ( X(0,i) > xmax ) xmax = X(0, i);
540                if ( Y(0,i) < ymin ) ymin = Y(0, i);
541                else if ( Y(0,i) > ymax ) ymax = Y(0, i);
542                if ( Z(0,i) < zmin ) zmin = Z(0, i);
543                else if ( Z(0,i) > zmax ) zmax = Z(0, i);
544        }
545        xmid = (xmax+xmin)/2;
546        ymid = (ymax+ymin)/2;
547        zmid = (zmax+zmin)/2;
548        xsize = xmax - xmin;
549        ysize = ymax - ymin;
550        zsize = zmax - zmin;
551        size = xsize;
552        if (ysize> size) size = ysize;
553        if (zsize > size) size = zsize;
554        size /= 2;
555
556        /* Scale box */
557        for (i = 0; i < BOX_P; i++) {
558                box[i][0] = box_orig[i][0] * size + xmid;
559                box[i][1] = box_orig[i][1] * size + ymid;
560                box[i][2] = box_orig[i][2] * size + zmid;
561        }
562
563}
564
565/* Returns true if point is infront of the plane (rather than behind) */
566int infront_of(double x, double y, double z, int i)
567{
568        double sum = plane[i][0][0]*x + plane[i][0][1]*y + plane[i][0][2]*z + plane_d[i];
569        return sum >= 0.0;
570}
571
572/* Returns true if line was behind a clip plane, or clips the line */
573int clip(double *x1, double *y1, double *z1, double *x2, double *y2, double *z2)
574{
575        int i;
576        for (i = 0; i < PLANES; i++) {
577                double t;
578                double x, y, z; /* Intersection point */
579                double dx, dy, dz; /* line delta */
580                int front1, front2;
581                front1 = infront_of(*x1, *y1, *z1, i);
582                front2 = infront_of(*x2, *y2, *z2, i);
583                if (!front1 && !front2) return 1;
584                if (front1 && front2) continue;
585
586                dx = *x2 - *x1;
587                dy = *y2 - *y1;
588                dz = *z2 - *z1;
589
590                /* Find t in line equation */
591                t = ( plane_d[i] -
592                                plane[i][0][0]*(*x1) - plane[i][0][1]*(*y1) - plane[i][0][2]*(*z1) )
593                                /
594                        ( plane[i][0][0]*dx + plane[i][0][1]*dy + plane[i][0][2]*dz );
595
596                x = *x1 + dx * t;
597                y = *y1 + dy * t;
598                z = *z1 + dz * t;
599                /* Make point that was behind to be the intersect */
600                if (front2) {
601                        *x1 = x;
602                        *y1 = y;
603                        *z1 = z;
604                } else {
605                        *x2 = x;
606                        *y2 = y;
607                        *z2 = z;
608                }
609        }
610        return 0;
611}       
612
613
614void
615draw_flow(ModeInfo * mi)
616{
617        Display    *display = MI_DISPLAY(mi);
618        Window      window = MI_WINDOW(mi);
619        GC          gc = MI_GC(mi);
620        flowstruct *sp = &flows[MI_SCREEN(mi)];
621        int         b, c, i;
622        int         col, ix;
623        int                     new_view = 0;
624        double      M[3][3]; /* transformation matrix */
625        double          step_view = sp->step;
626        double          step_bees = sp->step;
627        double          step_slow = sp->step;
628        double          pp, pc;
629
630        create_box(sp);
631
632        if(!sp->view.depth){ /* simple 3D tumble */
633                double      sint, cost, sinp, cosp;
634                sp->tumble.theta += sp->tumble.dtheta;
635                sp->tumble.phi += sp->tumble.dphi;
636                sint = sin(sp->tumble.theta);
637                cost = cos(sp->tumble.theta);
638                sinp = sin(sp->tumble.phi);
639                cosp = cos(sp->tumble.phi);
640                M[0][0]= cost; M[0][1]=-sint*cosp; M[0][2]= sint*sinp;
641                M[1][0]= sint; M[1][1]= cost*cosp; M[1][2]=-cost*sinp;
642                M[2][0]= 0;    M[2][1]= 0;         M[2][2]= 1;
643        } else { /* initialize matrix */
644                M[0][0]= 0; M[0][1]= 0; M[0][2]= 0;
645                M[1][0]= 0; M[1][1]= 0; M[1][2]= 0;
646                M[2][0]= 0; M[2][1]= 0; M[2][2]= 0;
647
648        }
649
650        for (col = 0; col < MI_NPIXELS(mi); col++)
651                sp->cnsegs[col] = 0;
652
653        MI_IS_DRAWN(mi) = True;
654
655        /* Calculate circling POV */
656        sp->circle[1] = sp->circle[0];
657        sp->circle[0].x = sp->size * 2 * sin(sp->count / 40.0) * (0.6 + 0.4 *cos(sp->count / 100.0));
658        sp->circle[0].y = sp->size * 2 * cos(sp->count / 40.0) * (0.6 + 0.4 *cos(sp->count / 100.0));
659        sp->circle[0].z = sp->size * 2 * sin(sp->count / 421.0);
660
661        if (sp->mode & FLOW_ROTATE)
662                pp = 0;
663        else if (sp->mode & FLOW_RIDE)
664                pp = 1;
665        else /* ZOOM */
666                /* Bistable oscillator to switch between the trained bee and the circler */
667                pp = -sin(sin(sin(cos(sp->count / 150.0)*M_PI/2)*M_PI/2)*M_PI/2) *0.5 + 0.5;
668        pc = 1 - pp;
669
670
671        /* Slow down or speed up the bees / view: */
672
673        /* exponentially accelerate towards zero */
674        sp->slow = sp->slow * 1.005 - 0.005;
675        if (sp->slow < 0) sp->slow = 0;
676
677        sp->slow_view = sp->slow_view * 1.005 - 0.005;
678        if (sp->slow_view < 0) sp->slow_view = 0;
679
680        /* View speeds up, slow bees slow to half speed, and other bees will
681         * actually stop */
682        step_view = step_view * (1.01 - sp->slow_view * sp->slow_view) * 0.2;
683        step_slow = step_slow * (sp->slow + 0.5) / 2;
684        if (sp->mode & FLOW_SLOW)
685                step_bees = step_bees * sp->slow;
686        else
687                step_bees = step_slow;
688
689        /* <=- Bees -=> */
690        for (b = 0; b < sp->beecount; b++) {
691                /* Calc if this bee is slow. Note normal bees are exempt from
692                 * calculations once they slow to half speed, so that they remain as
693                 * frozen lines rather than barely-visible points */
694                int slow = ((b & 0x7) == 0);
695                if ( !(sp->mode & FLOW_FREEZE) ) slow = 1;
696                /* Age the arrays. */
697                if (b < 2 || sp->slow > 0.5 || slow) {
698                        X(1, b) = X(0, b);
699                        Y(1, b) = Y(0, b);
700                        Z(1, b) = Z(0, b);
701
702                        /* 2nd order Kunge Kutta */
703                        {
704                                dvector     k1, k2;
705                                double          step;
706
707                                if (b == 0 || b == 1) {
708                                        step = step_view;
709                                } else if (slow) {
710                                        step = step_slow;
711                                } else {
712                                        step = step_bees;
713                                }
714                                k1 = sp->ODE(sp->par, X(1, b), Y(1, b), Z(1, b));
715                                k1.x *= step;
716                                k1.y *= step;
717                                k1.z *= step;
718                                k2 = sp->ODE(sp->par, X(1, b) + k1.x, Y(1, b) + k1.y, Z(1, b) + k1.z);
719                                k2.x *= step;
720                                k2.y *= step;
721                                k2.z *= step;
722                                X(0, b) = X(1, b) + (k1.x + k2.x) / 2.0;
723                                Y(0, b) = Y(1, b) + (k1.y + k2.y) / 2.0;
724                                Z(0, b) = Z(1, b) + (k1.z + k2.z) / 2.0;
725                        }
726                }
727
728
729                /* Colour according to bee */
730                col = b % (MI_NPIXELS(mi) - 1);
731                ix = col * sp->beecount + sp->cnsegs[col];
732
733                /* Fill the segment lists. */
734
735                if(sp->view.depth) { /* perspective view has special points */
736                        if(b==0){ /* point of view */
737                                sp->centre.x = X(0, b) * pp + sp->circle[0].x * pc;
738                                sp->centre.y = Y(0, b) * pp + sp->circle[0].y * pc;
739                                sp->centre.z = Z(0, b) * pp + sp->circle[0].z * pc;
740                                /*printf("center: (%3.3f,%3.3f,%3.3f)\n",sp->centre.x, sp->centre.y, sp->centre.z);*/
741                        }else if(b==1){ /* neighbour: used to compute local axes */
742                                double x[3], p[3], x2=0, xp=0, C[3][3];
743                                int j;
744
745                                /* forward */                           
746                                x[0] = X(0, 0) - X(1, 0);
747                                x[1] = Y(0, 0) - Y(1, 0);
748                                x[2] = Z(0, 0) - Z(1, 0);
749                       
750                                /* neighbour */
751                                p[0] = X(0, 1) - X(1, 0);
752                                p[1] = Y(0, 1) - Y(1, 0);
753                                p[2] = Z(0, 1) - Z(1, 0);
754
755                                for(i=0; i<3; i++){
756                                        x2+= x[i]*x[i];    /* X . X */
757                                        xp+= x[i]*p[i];    /* X . P */
758                                        M[0][i] = x[i];    /* X */
759                                }
760
761                                for(i=0; i<3; i++)               /* (X x P) x X */
762                                        M[1][i] = x2*p[i] - xp*x[i]; /* == (X . X) P - (X . P) X */
763                               
764                                M[2][0] =  x[1]*p[2] - x[2]*p[1]; /* X x P */
765                                M[2][1] = -x[0]*p[2] + x[2]*p[0];
766                                M[2][2] =  x[0]*p[1] - x[1]*p[0];
767
768                                /* normalise axes */
769                                for(j=0; j<3; j++){
770                                        double A=0;
771                                        for(i=0; i<3; i++) A+=M[j][i]*M[j][i]; /* sum squares */
772                                        A=sqrt(A);
773                                        for(i=0; i<3; i++) M[j][i]/=A;
774                                }
775
776                                X(0, 1)=X(0, 0)+M[1][0]; /* adjust neighbour */
777                                Y(0, 1)=Y(0, 0)+M[1][1];
778                                Z(0, 1)=Z(0, 0)+M[1][2];
779
780                                /* Look at trained bee into C matrix */
781                                /* forward */                           
782                                x[0] = 0 - sp->circle[0].x;
783                                x[1] = 0 - sp->circle[0].y;
784                                x[2] = 0 - sp->circle[0].z;
785                       
786                                /* neighbour */
787                                p[0] = sp->circle[0].x - sp->circle[1].x;
788                                p[1] = sp->circle[0].y - sp->circle[1].y;
789                                p[2] = sp->circle[0].z - sp->circle[1].z;
790
791                                for(i=0; i<3; i++){
792                                        x2+= x[i]*x[i];    /* X . X */
793                                        xp+= x[i]*p[i];    /* X . P */
794                                        C[0][i] = x[i];    /* X */
795                                }
796
797                                for(i=0; i<3; i++)               /* (X x P) x X */
798                                        C[1][i] = x2*p[i] - xp*x[i]; /* == (X . X) P - (X . P) X */
799                               
800                                C[2][0] =  x[1]*p[2] - x[2]*p[1]; /* X x P */
801                                C[2][1] = -x[0]*p[2] + x[2]*p[0];
802                                C[2][2] =  x[0]*p[1] - x[1]*p[0];
803
804                                /* normalise axes */
805                                for(j=0; j<3; j++){
806                                        double A=0;
807                                        for(i=0; i<3; i++) A+=C[j][i]*C[j][i]; /* sum squares */
808                                        A=sqrt(A);
809                    if (A != 0) /* #### is this right? */
810                      for(i=0; i<3; i++) C[j][i]/=A;
811                                }
812
813                                /* Interpolate between Center and Trained Bee matrices */
814                                /* This isn't very accurate and leads to weird transformations
815                                 * (shearing, etc), but it works. Besides, sometimes they look
816                                 * cool :) */
817                                pp = pp * pp; /* Don't follow bee's direction until very close */
818                                pc = 1 - pp;
819                                for (i = 0; i < 3; i++)
820                                        for (j = 0; j < 3; j++)
821                                                M[i][j] = M[i][j] * pp + C[i][j] * pc;
822                               
823
824#if 0  /* display local axes for testing */
825                                X(1, b)=X(0, 0);
826                                Y(1, b)=Y(0, 0);
827                                Z(1, b)=Z(0, 0);
828                        }else if(b==2){
829                                X(0, b)=X(0, 0)+0.5*M[0][0];
830                                Y(0, b)=Y(0, 0)+0.5*M[0][1];
831                                Z(0, b)=Z(0, 0)+0.5*M[0][2];
832                                X(1, b)=X(0, 0);
833                                Y(1, b)=Y(0, 0);
834                                Z(1, b)=Z(0, 0);
835                        }else if(b==3){
836                                X(0, b)=X(0, 0)+1.5*M[2][0];
837                                Y(0, b)=Y(0, 0)+1.5*M[2][1];
838                                Z(0, b)=Z(0, 0)+1.5*M[2][2];
839                                X(1, b)=X(0, 0);
840                                Y(1, b)=Y(0, 0);
841                                Z(1, b)=Z(0, 0);
842#endif
843                        /* Draw a box... */
844                        }
845                }
846                        if (b >= MIN_BOX && b < MAX_BOX) {
847                                int p1 = lines[b-MIN_BOX][0];
848                                int p2 = lines[b-MIN_BOX][1];
849                                X(0, b) = box[p1][0]; Y(0, b) = box[p1][1]; Z(0, b) = box[p1][2];
850                                X(1, b) = box[p2][0]; Y(1, b) = box[p2][1]; Z(1, b) = box[p2][2];
851                        }
852               
853               
854#if 0   /* Original code */
855                for(i=0; i<2; i++){
856                        double x=X(i,b)-sp->centre.x;
857                        double y=Y(i,b)-sp->centre.y;
858                        double z=Z(i,b)-sp->centre.z;
859                        double X=M[0][0]*x + M[0][1]*y + M[0][2]*z;
860                        double Y=M[1][0]*x + M[1][1]*y + M[1][2]*z;
861                        double Z=M[2][0]*x + M[2][1]*y + M[2][2]*z+sp->view.height;
862                        double absx, absy;                             
863                        if(sp->view.depth){
864                                if(X <= 0) break;
865                                absx=SCALE_X(sp->view.depth*Y/X);
866                                absy=SCALE_Y(sp->view.depth*Z/X);
867                                if(absx < -sp->width || absx > 2*sp->width ||
868                                   absy < -sp->height || absy > 2*sp->height)
869                                        break;
870                        }else{
871                                absx=SCALE_X(X);
872                                absy=SCALE_Y(Y);
873                        }
874                        if(i){
875                                sp->csegs[ix].x1 = (short) absx;
876                                sp->csegs[ix].y1 = (short) absy;
877                        }else{
878                                sp->csegs[ix].x2 = (short) absx;
879                                sp->csegs[ix].y2 = (short) absy;
880                        }
881                }
882                if(i == 2) /* both assigned */
883                        sp->cnsegs[col]++;
884#else   
885                /* Chalky's code w/ clipping */
886                if (b < ((sp->mode & FLOW_BOX) ? 2 : MAX_BOX))
887                        continue;
888                do {
889                        double x1=X(0,b)-sp->centre.x;
890                        double y1=Y(0,b)-sp->centre.y;
891                        double z1=Z(0,b)-sp->centre.z;
892                        double X1=M[0][0]*x1 + M[0][1]*y1 + M[0][2]*z1;
893                        double Y1=M[1][0]*x1 + M[1][1]*y1 + M[1][2]*z1;
894                        double Z1=M[2][0]*x1 + M[2][1]*y1 + M[2][2]*z1+sp->view.height;
895                        double absx1, absy1;                           
896                        double x2=X(1,b)-sp->centre.x;
897                        double y2=Y(1,b)-sp->centre.y;
898                        double z2=Z(1,b)-sp->centre.z;
899                        double X2=M[0][0]*x2 + M[0][1]*y2 + M[0][2]*z2;
900                        double Y2=M[1][0]*x2 + M[1][1]*y2 + M[1][2]*z2;
901                        double Z2=M[2][0]*x2 + M[2][1]*y2 + M[2][2]*z2+sp->view.height;
902                        double absx2, absy2;                           
903                        if(sp->view.depth){
904                                /* Need clipping if: is part of box, or close to viewer */
905                                if ( (b >= MIN_BOX && b < MAX_BOX) || X1 <= 0.1 || X2 < 0.1)
906                                        if (clip(&X1, &Y1, &Z1, &X2, &Y2, &Z2))
907                                                break;
908                                if (X1 <= 0 || X2 <= 0) break;
909                                absx1=SCALE_X(sp->view.depth*Y1/X1);
910                                absy1=SCALE_Y(sp->view.depth*Z1/X1);
911                                if(absx1 < -sp->width || absx1 > 2*sp->width ||
912                                   absy1 < -sp->height || absy1 > 2*sp->height)
913                                        break;
914                                absx2=SCALE_X(sp->view.depth*Y2/X2);
915                                absy2=SCALE_Y(sp->view.depth*Z2/X2);
916                                if(absx2 < -sp->width || absx2 > 2*sp->width ||
917                                   absy2 < -sp->height || absy2 > 2*sp->height)
918                                        break;
919                        }else{
920                                absx1=SCALE_X(X1);
921                                absy1=SCALE_Y(Y1);
922                                absx2=SCALE_X(X2);
923                                absy2=SCALE_Y(Y2);
924                        }
925
926                        sp->csegs[ix].x1 = (short) absx1;
927                        sp->csegs[ix].y1 = (short) absy1;
928                        sp->csegs[ix].x2 = (short) absx2;
929                        sp->csegs[ix].y2 = (short) absy2;
930
931                        sp->cnsegs[col]++;
932                } while (0);
933#endif
934        }
935
936        if (sp->count) { /* erase */
937                XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
938                XDrawSegments(display, window, gc, sp->old_segs, sp->nold_segs);
939        }
940
941        if (MI_NPIXELS(mi) > 2){ /* render colour */
942                for (col = 0; col < MI_NPIXELS(mi); col++)
943                        if (sp->cnsegs[col] > 0) {
944                                XSetForeground(display, gc, MI_PIXEL(mi, col));
945                                XDrawSegments(display, window, gc,
946                                              sp->csegs + col * sp->beecount, sp->cnsegs[col]);
947                        }
948        } else {                /* render mono */
949                XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
950                XDrawSegments(display, window, gc,
951                                          sp->csegs + col * sp->beecount, sp->cnsegs[col]);
952        }
953
954        /* Copy to erase-list */
955        for (col = 0, c = 0; col < MI_NPIXELS(mi); col++)
956                for (b = 0; b < sp->cnsegs[col]; b++)
957                        sp->old_segs[c++] = (sp->csegs + col * sp->beecount)[b];
958        sp->nold_segs = c;
959
960        if (++sp->count > MI_CYCLES(mi)) /* pick a new flow */
961                init_flow(mi);
962
963        if (sp->count % (MI_CYCLES(mi)/4) == 0) { /* pick a new view */
964                new_view = 0; /* change to 1 .. */
965        }
966
967        if (X(0, 0) < xmin*2 || X(0, 0) > xmax*2) new_view = 1;
968        if (Y(0, 0) < ymin*2 || Y(0, 0) > ymax*2) new_view = 1;
969        if (Z(0, 0) < zmin*2 || Z(0, 0) > zmax*2) new_view = 1;
970
971        if (new_view) {
972                for (b = 0; b < 2; b++) {
973                        X(1, b) = X(0, b) = balance_rand(sp->range.x*4);
974                        Y(1, b) = Y(0, b) = balance_rand(sp->range.y*4);
975                        Z(1, b) = Z(0, b) = balance_rand(sp->range.z*4);
976                }
977                sp->slow_view = 0.90;
978        }
979}
980
981void
982release_flow(ModeInfo * mi)
983{
984        if (flows != NULL) {
985                int         screen;
986
987                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
988                        flowstruct *sp = &flows[screen];
989
990                        if (sp->csegs != NULL)
991                                (void) free((void *) sp->csegs);
992                        if (sp->cnsegs != NULL)
993                                (void) free((void *) sp->cnsegs);
994                        if (sp->old_segs != NULL)
995                                (void) free((void *) sp->old_segs);
996                        if (sp->p[0] != NULL)
997                                (void) free((void *) sp->p[0]);
998                        if (sp->p[1] != NULL)
999                                (void) free((void *) sp->p[1]);
1000                }
1001                (void) free((void *) flows);
1002                flows = NULL;
1003        }
1004}
1005
1006void
1007refresh_flow(ModeInfo * mi)
1008{
1009        MI_CLEARWINDOW(mi);
1010}
1011
1012XrmOptionDescRec flow_options[] =
1013{
1014        {"-rotate",  ".rotate", XrmoptionSepArg, 0},
1015        {"-ride",  ".ride", XrmoptionSepArg, 0},
1016        {"-zoom",  ".zoom", XrmoptionSepArg, 0},
1017        {"-box",  ".box", XrmoptionSepArg, 0},
1018        {"-slow",  ".slow", XrmoptionSepArg, 0},
1019        {"-freeze",  ".freeze", XrmoptionSepArg, 0},
1020        {"-allow2d",  ".allow2d", XrmoptionSepArg, 0},
1021  { 0, 0, 0, 0 }
1022};
1023
1024/*
1025char*        defaults[] =
1026{
1027        "*rotate:         True",
1028        "*ride:           True",
1029        "*zoom:           True",
1030        "*allow2d:        True",
1031        "*box:            True",
1032        "*slow:           True",
1033        "*freeze:         True",
1034  0
1035};
1036        */
Note: See TracBrowser for help on using the repository browser.