1 /*
2     FLAM3 - cosmic recursive fractal flames
3     Copyright (C) 1992-2009 Spotworks LLC
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #ifndef _MSC_VER /* VC++ */
20 #define _GNU_SOURCE
21 #endif
22 
23 #include "private.h"
24 #include "img.h"
25 #include "config.h"
26 #include "variations.h"
27 #include "interpolation.h"
28 #include "parser.h"
29 #include "filters.h"
30 #include "palettes.h"
31 #include <limits.h>
32 #include <locale.h>
33 #include <math.h>
34 #ifdef HAVE_STDINT_H
35 #include <stdint.h>
36 #endif
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #include <errno.h>
41 
42 #ifdef HAVE_LIBPTHREAD
43 #include <pthread.h>
44 #endif
45 
46 #ifdef __APPLE__
47 #include <mach/mach.h>
48 #include <mach/mach_error.h>
49 #define flam3_os "OSX"
50 #else
51 #ifdef _WIN32
52 #define WINVER 0x0500
53 #include <windows.h>
54 #define flam3_os "WIN"
55 #else
56 #define flam3_os "LNX"
57 #endif
58 #endif
59 
60 
61 
flam3_version()62 char *flam3_version() {
63 
64   if (strcmp(GIT_REV, ""))
65     return flam3_os "-" GIT_REV;
66   return flam3_os "-" VERSION;
67 }
68 
69 
70 #define CHOOSE_XFORM_GRAIN 16384
71 #define CHOOSE_XFORM_GRAIN_M1 16383
72 
73 #define random_distrib(v) ((v)[random()%vlen(v)])
74 
75 
flam3_create_xform_distrib(flam3_genome * cp)76 unsigned short *flam3_create_xform_distrib(flam3_genome *cp) {
77 
78    /* Xform distrib is created in this function             */
79    int numrows;
80    int dist_row,i;
81    unsigned short *xform_distrib;
82 
83    numrows = cp->num_xforms - (cp->final_xform_index>=0) + 1;
84    xform_distrib = calloc(numrows*CHOOSE_XFORM_GRAIN,sizeof(unsigned short));
85 
86    /* First, set up the first row of the xform_distrib (raw weights) */
87    flam3_create_chaos_distrib(cp, -1, xform_distrib);
88 
89    /* Check for non-unity chaos */
90    cp->chaos_enable = 1 - flam3_check_unity_chaos(cp);
91 
92    if (cp->chaos_enable) {
93 
94       /* Now set up a row for each of the xforms */
95       dist_row = 0;
96       for (i=0;i<cp->num_xforms;i++) {
97 
98          if (cp->final_xform_index == i)
99             continue;
100          else
101             dist_row++;
102 
103          if (flam3_create_chaos_distrib(cp, i, &(xform_distrib[CHOOSE_XFORM_GRAIN*(dist_row)]))) {
104             free(xform_distrib);
105             return(NULL);
106          }
107       }
108    }
109 
110    return(xform_distrib);
111 }
112 
113 /* Run this on a copy of a genome to get a strip of the output */
flam3_make_strip(flam3_genome * cp,int nstrips,int stripnum)114 int flam3_make_strip(flam3_genome *cp, int nstrips, int stripnum) {
115 
116     double old_center[2];
117     int j;
118 
119     /* Strip out motion elements */
120     for (j=0;j<cp->num_xforms;j++)
121     flam3_delete_motion_elements(&cp->xform[j]);
122 
123     old_center[0] = cp->center[0];
124     old_center[1] = cp->center[1];
125     cp->height /= nstrips;
126     cp->center[1] = cp->center[1] - ((nstrips - 1) * cp->height) / (2 * cp->pixels_per_unit * pow(2.0, cp->zoom));
127     cp->center[1] += cp->height * stripnum / ( cp->pixels_per_unit * pow(2.0,cp->zoom) );
128     rotate_by(cp->center, old_center, cp->rotate);
129 
130     return(0);
131 }
132 
133 
rotate_by(double * p,double * center,double by)134 void rotate_by(double *p, double *center, double by) {
135     double r[2];
136     double th = by * 2 * M_PI / 360.0;
137     double c = cos(th);
138     double s = -sin(th);
139     p[0] -= center[0];
140     p[1] -= center[1];
141     r[0] = c * p[0] - s * p[1];
142     r[1] = s * p[0] + c * p[1];
143     p[0] = r[0] + center[0];
144     p[1] = r[1] + center[1];
145 }
146 
147 
flam3_check_unity_chaos(flam3_genome * cp)148 int flam3_check_unity_chaos(flam3_genome *cp) {
149 
150    int i,j;
151    int num_std;
152    int unity=1;
153    num_std = cp->num_xforms - (cp->final_xform_index >= 0);
154 
155    for (i=0;i<num_std;i++) {
156       for (j=0;j<num_std;j++) {
157          if ( fabs(cp->chaos[i][j]-1.0) > EPS)
158             unity=0;
159       }
160    }
161 
162    return(unity);
163 }
164 
flam3_create_chaos_distrib(flam3_genome * cp,int xi,unsigned short * xform_distrib)165 int flam3_create_chaos_distrib(flam3_genome *cp, int xi, unsigned short *xform_distrib) {
166 
167    /* Xform distrib is a preallocated array of CHOOSE_XFORM_GRAIN chars */
168    /* address of array is passed in, contents are modified              */
169    double t,r,dr;
170    int i,j;
171    int num_std;
172 
173    //fprintf(stdout,"storing at %ld\n",xform_distrib);
174 
175    num_std = cp->num_xforms - (cp->final_xform_index >= 0);
176 
177    dr = 0.0;
178    for (i = 0; i < num_std; i++) {
179       double d = cp->xform[i].density;
180 
181       if (xi>=0)
182          d *= cp->chaos[xi][i];
183 
184       //fprintf(stdout,"%f ",d);
185       if (d < 0.0) {
186          fprintf(stderr, "xform weight must be non-negative, not %g.\n", d);
187          return(1);
188       }
189 
190       dr += d;
191    }
192 
193    //fprintf(stdout,"dr=%f\n",dr);
194 
195    if (dr == 0.0) {
196       fprintf(stderr, "cannot iterate empty flame.\n");
197       return(1);
198    }
199 
200    dr = dr / CHOOSE_XFORM_GRAIN;
201 
202    j = 0;
203    t = cp->xform[0].density;
204    if (xi>=0)
205      t *= cp->chaos[xi][0];
206    r = 0.0;
207    for (i = 0; i < CHOOSE_XFORM_GRAIN; i++) {
208       while (r >= t) {
209          j++;
210 
211          if (xi>=0)
212             t += cp->xform[j].density*cp->chaos[xi][j];
213          else
214             t += cp->xform[j].density;
215 
216       }
217       //fprintf(stdout,"%d ",j);
218       xform_distrib[i] = j;
219       r += dr;
220    }
221    //fprintf(stdout,"\n---\n");
222 
223    return(0);
224 }
225 /*
226  * run the function system described by CP forward N generations.  store
227  * the N resulting 4-vectors in SAMPLES.  the initial point is passed in
228  * SAMPLES[0..3].  ignore the first FUSE iterations.
229  */
230 
231 
flam3_iterate(flam3_genome * cp,int n,int fuse,double * samples,unsigned short * xform_distrib,randctx * rc)232 int flam3_iterate(flam3_genome *cp, int n, int fuse,  double *samples, unsigned short *xform_distrib, randctx *rc) {
233    int i;
234    double p[4], q[4];
235    int consec = 0;
236    int badvals = 0;
237    int lastxf=0;
238    int fn;
239 
240    p[0] = samples[0];
241    p[1] = samples[1];
242    p[2] = samples[2];
243    p[3] = samples[3];
244 
245    /* Perform precalculations */
246    for (i=0;i<cp->num_xforms;i++)
247       xform_precalc(cp,i);
248 
249    for (i = -4*fuse; i < 4*n; i+=4) {
250 
251 //         fn = xform_distrib[ lastxf*CHOOSE_XFORM_GRAIN + (((unsigned)irand(rc)) % CHOOSE_XFORM_GRAIN)];
252       if (cp->chaos_enable)
253          fn = xform_distrib[ lastxf*CHOOSE_XFORM_GRAIN + (((unsigned)irand(rc)) & CHOOSE_XFORM_GRAIN_M1)];
254       else
255          fn = xform_distrib[ ((unsigned)irand(rc)) & CHOOSE_XFORM_GRAIN_M1 ];
256 
257       if (apply_xform(cp, fn, p, q, rc)>0) {
258          consec ++;
259          badvals ++;
260          if (consec<5) {
261             p[0] = q[0];
262             p[1] = q[1];
263             p[2] = q[2];
264             p[3] = q[3];
265             i -= 4;
266             continue;
267          } else
268             consec = 0;
269       } else
270          consec = 0;
271 
272       /* Store the last used transform */
273       lastxf = fn+1;
274 
275       p[0] = q[0];
276       p[1] = q[1];
277       p[2] = q[2];
278       p[3] = q[3];
279 
280       if (cp->final_xform_enable == 1) {
281          if (cp->xform[cp->final_xform_index].opacity==1 ||
282                 flam3_random_isaac_01(rc)<cp->xform[cp->final_xform_index].opacity) {
283              apply_xform(cp, cp->final_xform_index, p, q, rc);
284              /* Keep the opacity from the original xform */
285              q[3] = p[3];
286          }
287       }
288 
289       /* if fuse over, store it */
290       if (i >= 0) {
291          samples[i] = q[0];
292          samples[i+1] = q[1];
293          samples[i+2] = q[2];
294          samples[i+3] = q[3];
295       }
296    }
297 
298    return(badvals);
299 }
300 
flam3_xform_preview(flam3_genome * cp,int xi,double range,int numvals,int depth,double * result,randctx * rc)301 int flam3_xform_preview(flam3_genome *cp, int xi, double range, int numvals, int depth, double *result, randctx *rc) {
302 
303    /* We will evaluate the 'xi'th xform 'depth' times, over the following values:           */
304    /* x in [-range : range], y in [-range : range], with 2* (2*numvals+1)^2 values returned */
305    double p[4];
306    double incr;
307    int outi;
308    int xx,yy,dd;
309    double oldweight;
310 
311    outi=0;
312 
313    oldweight = cp->xform[xi].density;
314    cp->xform[xi].density = 1.0;
315 
316    /* Prepare the function pointers */
317    if (prepare_precalc_flags(cp)) {
318       cp->xform[xi].density = oldweight;
319       return(1);
320    }
321 
322    /* Calculate increment */
323    incr = range / (double)numvals;
324 
325    /* Perform precalculations */
326    xform_precalc(cp,xi);
327 
328    /* Loop over the grid */
329    for (xx=-numvals;xx<=numvals;xx++) {
330       for (yy=-numvals;yy<=numvals;yy++) {
331 
332          /* Calculate the input coordinates */
333          p[0] = (double)xx * incr;
334          p[1] = (double)yy * incr;
335 
336          /* Loop over the depth */
337          for (dd=0;dd<depth;dd++)
338             apply_xform(cp, xi, p, p, rc);
339 
340          result[outi] = p[0];
341          result[outi+1] = p[1];
342 
343          outi += 2;
344       }
345    }
346    cp->xform[xi].density = oldweight;
347 
348    return(0);
349 }
350 
flam3_colorhist(flam3_genome * cp,int num_batches,randctx * rc,double * hist)351 int flam3_colorhist(flam3_genome *cp, int num_batches, randctx *rc, double *hist) {
352 
353   int lp,plp;
354   int mycolor;
355   unsigned short *xform_distrib;
356   int sbs = 10000;
357   double sub_batch[4*10000];
358 
359   memset(hist,0,256*sizeof(double));
360 
361   // get into the attractor
362   if (prepare_precalc_flags(cp))
363      return(1);
364 
365   xform_distrib = flam3_create_xform_distrib(cp);
366 
367   for (lp=0;lp<num_batches;lp++) {
368 
369     sub_batch[0] = flam3_random_isaac_11(rc);
370     sub_batch[1] = flam3_random_isaac_11(rc);
371     sub_batch[2] = 0;
372     sub_batch[3] = 0;
373 
374 
375     if (xform_distrib==NULL)
376        return(1);
377     flam3_iterate(cp, sbs, 20, sub_batch, xform_distrib, rc);
378 
379     // histogram the colors in the sub_batch array
380     for (plp=0;plp<4*sbs;plp+=4) {
381       mycolor = (int)(sub_batch[plp+2]*CMAP_SIZE);
382       if (mycolor<0) mycolor=0;
383       if (mycolor>CMAP_SIZE_M1) mycolor=CMAP_SIZE_M1;
384 
385       hist[mycolor] += 1;
386     }
387   }
388 
389   free(xform_distrib);
390   for (plp=0;plp<256;plp++)
391     hist[plp] /= (float)(num_batches*sbs);
392 
393   return(0);
394 }
395 
sheep_loop(flam3_genome * cp,double blend)396 flam3_genome *sheep_loop(flam3_genome *cp, double blend) {
397 
398    flam3_genome *result;
399    int i;
400 
401    /* Allocate the genome - this must be freed by calling function */
402    result = calloc(1,sizeof(flam3_genome));
403 
404    /* Clear it */
405    clear_cp(result,flam3_defaults_on);
406 
407    /* Copy the original */
408    flam3_copy(result,cp);
409 
410    /*
411     * Insert motion magic here :
412     * if there are motion elements, we will modify the contents of
413     * the result genome before flam3_rotate is called.
414     */
415    for (i=0;i<cp->num_xforms;i++) {
416       if (cp->xform[i].num_motion>0) {
417          /* Apply motion parameters to result.xform[i] using blend parameter */
418          apply_motion_parameters(&cp->xform[i], &result->xform[i], blend);
419       }
420 
421       /* Delete the motion parameters from the result */
422       flam3_delete_motion_elements(&result->xform[i]);
423    }
424 
425    /* Rotate the affines */
426    flam3_rotate(result, blend*360.0,result->interpolation_type);
427 
428    return(result);
429 }
430 
431 
432 
433 
sheep_edge(flam3_genome * cp,double blend,int seqflag,double stagger)434 flam3_genome *sheep_edge(flam3_genome *cp, double blend, int seqflag, double stagger) {
435 
436    flam3_genome spun[2];
437    flam3_genome prealign[2];
438    flam3_genome *result;
439    int i,si;
440    char *ai;
441 
442    memset(spun, 0, 2*sizeof(flam3_genome));
443    memset(prealign, 0, 2*sizeof(flam3_genome));
444 
445    /* Allocate the memory for the result */
446    result = calloc(1,sizeof(flam3_genome));
447 
448    /*
449     * Insert motion magic here :
450     * if there are motion elements, we will modify the contents of
451     * the prealign genomes before we rotate and interpolate.
452     */
453 
454    for (si=0;si<2;si++) {
455       flam3_copy(&prealign[si], &cp[si]);
456       for (i=0;i<cp[si].num_xforms;i++) {
457          if (cp[si].xform[i].num_motion>0) {
458             /* Apply motion parameters to result.xform[i] using blend parameter */
459             apply_motion_parameters(&cp[si].xform[i], &prealign[si].xform[i], blend);
460          }
461       }
462    }
463 
464    /* Use the un-padded original for blend=0 when creating a sequence */
465    /* This keeps the original interpolation type intact               */
466    if (seqflag && 0.0 == blend) {
467       flam3_copy(result, &prealign[0]);
468    } else {
469 
470       /* Align what we're going to interpolate */
471       flam3_align(spun, prealign, 2);
472 
473       spun[0].time = 0.0;
474       spun[1].time = 1.0;
475 
476       /* Call this first to establish the asymmetric reference angles */
477       establish_asymmetric_refangles(spun,2);
478 
479       /* Rotate the aligned xforms */
480       flam3_rotate(&spun[0], blend*360.0, spun[0].interpolation_type);
481       flam3_rotate(&spun[1], blend*360.0, spun[0].interpolation_type);
482 
483       //fprintf(stderr, "xyzzy %d %d\n", spun[0].palette_interpolation, spun[1].palette_interpolation);
484 
485       /* Now call the interpolation */
486       if (argi("unsmoother",0) == 0)
487          flam3_interpolate(spun, 2, smoother(blend), stagger, result);
488       else
489          flam3_interpolate(spun, 2, blend, stagger, result);
490 
491 
492      /* Interpolation type no longer needs to be forced to linear mode */
493 //     if (!seqflag)
494 //        result.interpolation_type = flam3_inttype_linear;
495    }
496 
497    /* Clear the genomes we used */
498    clear_cp(&spun[0],flam3_defaults_on);
499    clear_cp(&spun[1],flam3_defaults_on);
500    clear_cp(&prealign[0],flam3_defaults_on);
501    clear_cp(&prealign[1],flam3_defaults_on);
502 
503    /* Make sure there are no motion elements in the result */
504    for (i=0;i<result->num_xforms;i++)
505       flam3_delete_motion_elements(&result->xform[i]);
506 
507    return(result);
508 }
509 
510 
511 /* BY is angle in degrees */
flam3_rotate(flam3_genome * cp,double by,int interpolation_type)512 void flam3_rotate(flam3_genome *cp, double by, int interpolation_type) {
513    int i;
514    for (i = 0; i < cp->num_xforms; i++) {
515       double r[2][2];
516       double T[2][2];
517       double U[2][2];
518       double dtheta = by * 2.0 * M_PI / 360.0;
519 
520       /* Don't rotate xforms with > 0 animate values */
521       if (cp->xform[i].animate == 0.0)
522          continue;
523 
524       if (cp->xform[i].padding == 1) {
525          if (interpolation_type == flam3_inttype_compat) {
526             /* gen 202 era flam3 did not rotate padded xforms */
527             continue;
528          } else if (interpolation_type == flam3_inttype_older) {
529             /* not sure if 198 era flam3 rotated padded xforms */
530             continue;
531          } else if (interpolation_type == flam3_inttype_linear) {
532             /* don't rotate for prettier symsings */
533             continue;
534          } else if (interpolation_type == flam3_inttype_log) {
535             /* Current flam3: what do we prefer? */
536             //continue;
537          }
538       }
539 
540       /* Do NOT rotate final xforms */
541       if (cp->final_xform_enable==1 && cp->final_xform_index==i)
542          continue;
543 
544       r[1][1] = r[0][0] = cos(dtheta);
545       r[0][1] = sin(dtheta);
546       r[1][0] = -r[0][1];
547       T[0][0] = cp->xform[i].c[0][0];
548       T[1][0] = cp->xform[i].c[1][0];
549       T[0][1] = cp->xform[i].c[0][1];
550       T[1][1] = cp->xform[i].c[1][1];
551       mult_matrix(r, T, U);
552       cp->xform[i].c[0][0] = U[0][0];
553       cp->xform[i].c[1][0] = U[1][0];
554       cp->xform[i].c[0][1] = U[0][1];
555       cp->xform[i].c[1][1] = U[1][1];
556    }
557 }
558 
559 #define APPMOT(x)  do { addto->x += mot[i].x * motion_funcs(func,freq*blend); } while (0);
560 
apply_motion_parameters(flam3_xform * xf,flam3_xform * addto,double blend)561 void apply_motion_parameters(flam3_xform *xf, flam3_xform *addto, double blend) {
562 
563    int i,j,k;
564    int freq;
565    int func;
566    flam3_xform* mot;
567 
568    mot = xf->motion;
569 
570    /* Loop over the motion elements and add their contribution to the original vals */
571    for (i=0; i<xf->num_motion; i++) {
572 
573       freq = mot[i].motion_freq;
574       func = mot[i].motion_func;
575 
576       APPMOT(density); /* Must ensure > 0 after all is applied */
577       APPMOT(color); /* Must ensure [0,1] after all is applied */
578 
579       APPMOT(opacity);
580       APPMOT(color_speed);
581       APPMOT(animate);
582       APPMOT(blob_low);
583       APPMOT(blob_high);
584       APPMOT(blob_waves);
585       APPMOT(pdj_a);
586       APPMOT(pdj_b);
587       APPMOT(pdj_c);
588       APPMOT(pdj_d);
589       APPMOT(fan2_x);
590       APPMOT(fan2_y);
591       APPMOT(rings2_val);
592       APPMOT(perspective_angle);
593       APPMOT(perspective_dist);
594       APPMOT(julian_power);
595       APPMOT(julian_dist);
596       APPMOT(juliascope_power);
597       APPMOT(juliascope_dist);
598       APPMOT(radial_blur_angle);
599       APPMOT(pie_slices);
600       APPMOT(pie_rotation);
601       APPMOT(pie_thickness);
602       APPMOT(ngon_sides);
603       APPMOT(ngon_power);
604       APPMOT(ngon_circle);
605       APPMOT(ngon_corners);
606       APPMOT(curl_c1);
607       APPMOT(curl_c2);
608       APPMOT(rectangles_x);
609       APPMOT(rectangles_y);
610       APPMOT(amw_amp);
611       APPMOT(disc2_rot);
612       APPMOT(disc2_twist);
613       APPMOT(super_shape_rnd);
614       APPMOT(super_shape_m);
615       APPMOT(super_shape_n1);
616       APPMOT(super_shape_n2);
617       APPMOT(super_shape_n3);
618       APPMOT(super_shape_holes);
619       APPMOT(flower_petals);
620       APPMOT(flower_holes);
621       APPMOT(conic_eccentricity);
622       APPMOT(conic_holes);
623       APPMOT(parabola_height);
624       APPMOT(parabola_width);
625       APPMOT(bent2_x);
626       APPMOT(bent2_y);
627       APPMOT(bipolar_shift);
628       APPMOT(cell_size);
629       APPMOT(cpow_r);
630       APPMOT(cpow_i);
631       APPMOT(cpow_power);
632       APPMOT(curve_xamp);
633       APPMOT(curve_yamp);
634       APPMOT(curve_xlength);
635       APPMOT(curve_ylength);
636       APPMOT(escher_beta);
637       APPMOT(lazysusan_x);
638       APPMOT(lazysusan_y);
639       APPMOT(lazysusan_twist);
640       APPMOT(lazysusan_space);
641       APPMOT(lazysusan_spin);
642       APPMOT(modulus_x);
643       APPMOT(modulus_y);
644       APPMOT(oscope_separation);
645       APPMOT(oscope_frequency);
646       APPMOT(oscope_amplitude);
647       APPMOT(oscope_damping);
648       APPMOT(popcorn2_x);
649       APPMOT(popcorn2_y);
650       APPMOT(popcorn2_c);
651       APPMOT(separation_x);
652       APPMOT(separation_xinside);
653       APPMOT(separation_y);
654       APPMOT(separation_yinside);
655       APPMOT(split_xsize);
656       APPMOT(split_ysize);
657       APPMOT(splits_x);
658       APPMOT(splits_y);
659       APPMOT(stripes_space);
660       APPMOT(stripes_warp);
661       APPMOT(wedge_angle);
662       APPMOT(wedge_hole);
663       APPMOT(wedge_count);
664       APPMOT(wedge_swirl);
665       APPMOT(wedge_julia_angle);
666       APPMOT(wedge_julia_count);
667       APPMOT(wedge_julia_power);
668       APPMOT(wedge_julia_dist);
669       APPMOT(wedge_sph_angle);
670       APPMOT(wedge_sph_hole);
671       APPMOT(wedge_sph_count);
672       APPMOT(wedge_sph_swirl);
673       APPMOT(whorl_inside);
674       APPMOT(whorl_outside);
675       APPMOT(waves2_scalex);
676       APPMOT(waves2_scaley);
677       APPMOT(waves2_freqx);
678       APPMOT(waves2_freqy);
679       APPMOT(auger_sym);
680       APPMOT(auger_weight);
681       APPMOT(auger_freq);
682       APPMOT(auger_scale);
683       APPMOT(flux_spread);
684       APPMOT(mobius_re_a);
685       APPMOT(mobius_re_b);
686       APPMOT(mobius_re_c);
687       APPMOT(mobius_re_d);
688       APPMOT(mobius_im_a);
689       APPMOT(mobius_im_b);
690       APPMOT(mobius_im_c);
691       APPMOT(mobius_im_d);
692 
693       for (j = 0; j < flam3_nvariations; j++)
694          APPMOT(var[j]);
695 
696       for (j=0; j<3; j++) {
697          for (k=0; k<2; k++) {
698             APPMOT(c[j][k]);
699             APPMOT(post[j][k]);
700          }
701       }
702 
703    }
704 
705    /* Make sure certain params are within reasonable bounds */
706    if (addto->color<0) addto->color=0;
707    if (addto->color>1) addto->color=1;
708    if (addto->density<0) addto->density=0;
709 
710 }
711 
712 
713 /*
714  * create a control point that interpolates between the control points
715  * passed in CPS.  CPS must be sorted by time.
716  */
flam3_interpolate(flam3_genome cps[],int ncps,double time,double stagger,flam3_genome * result)717 void flam3_interpolate(flam3_genome cps[], int ncps,
718              double time, double stagger, flam3_genome *result) {
719    int i1, i2;
720    double c[2];
721    flam3_genome cpi[4];
722    int smoothflag = 0;
723 
724    if (1 == ncps) {
725       flam3_copy(result, &(cps[0]));
726       return;
727    }
728 
729    if (cps[0].time >= time) {
730       i1 = 0;
731       i2 = 1;
732    } else if (cps[ncps - 1].time <= time) {
733       i1 = ncps - 2;
734       i2 = ncps - 1;
735    } else {
736       i1 = 0;
737       while (cps[i1].time < time)
738          i1++;
739 
740       i1--;
741       i2 = i1 + 1;
742 
743    }
744 
745    c[0] = (cps[i2].time - time) / (cps[i2].time - cps[i1].time);
746    c[1] = 1.0 - c[0];
747 
748    memset(cpi, 0, 4*sizeof(flam3_genome));
749 
750    /* To interpolate the xforms, we will make copies of the source cps  */
751    /* and ensure that they both have the same number before progressing */
752    if (flam3_interpolation_linear == cps[i1].interpolation) {
753        flam3_align(&cpi[0], &cps[i1], 2);
754        smoothflag = 0;
755 
756    } else {
757        if (0 == i1) {
758           fprintf(stderr, "error: cannot use smooth interpolation on first segment.\n");
759           fprintf(stderr, "reverting to linear interpolation.\n");
760           flam3_align(&cpi[0], &cps[i1], 2);
761           smoothflag = 0;
762        }
763 
764        if (ncps-1 == i2) {
765           fprintf(stderr, "error: cannot use smooth interpolation on last segment.\n");
766           fprintf(stderr, "reverting to linear interpolation.\n");
767           flam3_align(&cpi[0], &cps[i1], 2);
768           smoothflag = 0;
769        }
770 
771        flam3_align(&cpi[0], &cps[i1-1], 4);
772        smoothflag = 1;
773    }
774 
775    /* Clear the destination cp */
776    clear_cp(result, 1);
777 
778    if (cpi[0].final_xform_index >= 0) {
779       flam3_add_xforms(result, cpi[0].num_xforms-1, 0, 0);
780       flam3_add_xforms(result, 1, 0, 1);
781    } else
782       flam3_add_xforms(result, cpi[0].num_xforms, 0, 0);
783 
784 
785    result->time = time;
786    result->interpolation = flam3_interpolation_linear;
787    result->interpolation_type = cpi[0].interpolation_type;
788    result->palette_interpolation = flam3_palette_interpolation_hsv_circular;
789    result->hsv_rgb_palette_blend = 0.0;
790 
791    if (!smoothflag) {
792        flam3_interpolate_n(result, 2, cpi, c, stagger);
793    } else {
794        interpolate_catmull_rom(cpi, c[1], result);
795        clear_cp(&(cpi[2]),0);
796        clear_cp(&(cpi[3]),0);
797    }
798 
799    clear_cp(&(cpi[0]),0);
800    clear_cp(&(cpi[1]),0);
801 
802 }
803 
flam3_copy_params(flam3_xform * dest,flam3_xform * src,int varn)804 void flam3_copy_params(flam3_xform *dest, flam3_xform *src, int varn) {
805 
806    /* We only want to copy param var coefs for this one */
807    if (varn==VAR_BLOB) {
808       /* Blob */
809       dest->blob_low = src->blob_low;
810       dest->blob_high = src->blob_high;
811       dest->blob_waves = src->blob_waves;
812    } else if (varn==VAR_PDJ) {
813       /* PDJ */
814       dest->pdj_a = src->pdj_a;
815       dest->pdj_b = src->pdj_b;
816       dest->pdj_c = src->pdj_c;
817       dest->pdj_d = src->pdj_d;
818    } else if (varn==VAR_FAN2) {
819       /* Fan2 */
820       dest->fan2_x = src->fan2_x;
821       dest->fan2_y = src->fan2_y;
822    } else if (varn==VAR_RINGS2) {
823       /* Rings2 */
824       dest->rings2_val = src->rings2_val;
825    } else if (varn==VAR_PERSPECTIVE) {
826       /* Perspective */
827       dest->perspective_angle = src->perspective_angle;
828       dest->perspective_dist = src->perspective_dist;
829       dest->persp_vsin = src->persp_vsin;
830       dest->persp_vfcos = src->persp_vfcos;
831    } else if (varn==VAR_JULIAN) {
832       /* Julia_N */
833       dest->julian_power = src->julian_power;
834       dest->julian_dist = src->julian_dist;
835       dest->julian_rN = src->julian_rN;
836       dest->julian_cn = src->julian_cn;
837    } else if (varn==VAR_JULIASCOPE) {
838       /* Julia_Scope */
839       dest->juliascope_power = src->juliascope_power;
840       dest->juliascope_dist = src->juliascope_dist;
841       dest->juliascope_rN = src->juliascope_rN;
842       dest->juliascope_cn = src->juliascope_cn;
843    } else if (varn==VAR_RADIAL_BLUR) {
844       /* Radial Blur */
845       dest->radial_blur_angle = src->radial_blur_angle;
846    } else if (varn==VAR_PIE) {
847       /* Pie */
848       dest->pie_slices = src->pie_slices;
849       dest->pie_rotation = src->pie_rotation;
850       dest->pie_thickness = src->pie_thickness;
851    } else if (varn==VAR_NGON) {
852       /* Ngon */
853       dest->ngon_sides = src->ngon_sides;
854       dest->ngon_power = src->ngon_power;
855       dest->ngon_corners = src->ngon_corners;
856       dest->ngon_circle = src->ngon_circle;
857    } else if (varn==VAR_CURL) {
858       /* Curl */
859       dest->curl_c1 = src->curl_c1;
860       dest->curl_c2 = src->curl_c2;
861    } else if (varn==VAR_RECTANGLES) {
862       /* Rect */
863       dest->rectangles_x = src->rectangles_x;
864       dest->rectangles_y = src->rectangles_y;
865    } else if (varn==VAR_DISC2) {
866       /* Disc2 */
867       dest->disc2_rot = src->disc2_rot;
868       dest->disc2_twist = src->disc2_twist;
869    } else if (varn==VAR_SUPER_SHAPE) {
870       /* Supershape */
871       dest->super_shape_rnd = src->super_shape_rnd;
872       dest->super_shape_m = src->super_shape_m;
873       dest->super_shape_n1 = src->super_shape_n1;
874       dest->super_shape_n2 = src->super_shape_n2;
875       dest->super_shape_n3 = src->super_shape_n3;
876       dest->super_shape_holes = src->super_shape_holes;
877    } else if (varn==VAR_FLOWER) {
878       /* Flower */
879       dest->flower_petals = src->flower_petals;
880       dest->flower_petals = src->flower_petals;
881    } else if (varn==VAR_CONIC) {
882       /* Conic */
883       dest->conic_eccentricity = src->conic_eccentricity;
884       dest->conic_holes = src->conic_holes;
885    } else if (varn==VAR_PARABOLA) {
886       /* Parabola */
887       dest->parabola_height = src->parabola_height;
888       dest->parabola_width = src->parabola_width;
889    } else if (varn==VAR_BENT2) {
890       /* Bent2 */
891       dest->bent2_x = src->bent2_x;
892       dest->bent2_y = src->bent2_y;
893    } else if (varn==VAR_BIPOLAR) {
894       /* Bipolar */
895       dest->bipolar_shift = src->bipolar_shift;
896    } else if (varn==VAR_CELL) {
897       /* Cell */
898       dest->cell_size = src->cell_size;
899    } else if (varn==VAR_CPOW) {
900       /* Cpow */
901       dest->cpow_i = src->cpow_i;
902       dest->cpow_r = src->cpow_r;
903       dest->cpow_power = src->cpow_power;
904    } else if (varn==VAR_CURVE) {
905       /* Curve */
906       dest->curve_xamp = src->curve_xamp;
907       dest->curve_yamp = src->curve_yamp;
908       dest->curve_xlength = src->curve_xlength;
909       dest->curve_ylength = src->curve_ylength;
910    } else if (varn==VAR_ESCHER) {
911       /* Escher */
912       dest->escher_beta = src->escher_beta;
913    } else if (varn==VAR_LAZYSUSAN) {
914       /* Lazysusan */
915       dest->lazysusan_x = src->lazysusan_x;
916       dest->lazysusan_y = src->lazysusan_y;
917       dest->lazysusan_spin = src->lazysusan_spin;
918       dest->lazysusan_space = src->lazysusan_space;
919       dest->lazysusan_twist = src->lazysusan_twist;
920    } else if (varn==VAR_MODULUS) {
921       /* Modulus */
922       dest->modulus_x = src->modulus_x;
923       dest->modulus_y = src->modulus_y;
924    } else if (varn==VAR_OSCILLOSCOPE) {
925       /* Oscope */
926       dest->oscope_separation = src->oscope_separation;
927       dest->oscope_frequency = src->oscope_frequency;
928       dest->oscope_amplitude = src->oscope_amplitude;
929       dest->oscope_damping = src->oscope_damping;
930    } else if (varn==VAR_POPCORN2) {
931       /* Popcorn2 */
932       dest->popcorn2_x = src->popcorn2_x;
933       dest->popcorn2_y = src->popcorn2_y;
934       dest->popcorn2_c = src->popcorn2_c;
935    } else if (varn==VAR_SEPARATION) {
936       /* Separation */
937       dest->separation_x = src->separation_x;
938       dest->separation_y = src->separation_y;
939       dest->separation_xinside = src->separation_xinside;
940       dest->separation_yinside = src->separation_yinside;
941    } else if (varn==VAR_SPLIT) {
942       /* Split */
943       dest->split_xsize = src->split_xsize;
944       dest->split_ysize = src->split_ysize;
945    } else if (varn==VAR_SPLITS) {
946       /* Splits */
947       dest->splits_x = src->splits_x;
948       dest->splits_y = src->splits_y;
949    } else if (varn==VAR_STRIPES) {
950       /* Stripes */
951       dest->stripes_space = src->stripes_space;
952       dest->stripes_warp = src->stripes_warp;
953    } else if (varn==VAR_WEDGE) {
954       /* Wedge */
955       dest->wedge_angle = src->wedge_angle;
956       dest->wedge_hole = src->wedge_hole;
957       dest->wedge_count = src->wedge_count;
958       dest->wedge_swirl = src->wedge_swirl;
959    } else if (varn==VAR_WEDGE_JULIA) {
960       /* Wedge_Julia */
961       dest->wedge_julia_angle = src->wedge_julia_angle;
962       dest->wedge_julia_count = src->wedge_julia_count;
963       dest->wedge_julia_power = src->wedge_julia_power;
964       dest->wedge_julia_dist = src->wedge_julia_dist;
965       dest->wedgeJulia_cf = src->wedgeJulia_cf;
966       dest->wedgeJulia_cn = src->wedgeJulia_cn;
967       dest->wedgeJulia_rN = src->wedgeJulia_rN;
968    } else if (varn==VAR_WEDGE_SPH) {
969       /* Wedge_sph */
970       dest->wedge_sph_angle = src->wedge_sph_angle;
971       dest->wedge_sph_hole = src->wedge_sph_hole;
972       dest->wedge_sph_count = src->wedge_sph_count;
973       dest->wedge_sph_swirl = src->wedge_sph_swirl;
974    } else if (varn==VAR_WHORL) {
975       /* whorl */
976       dest->whorl_inside = src->whorl_inside;
977       dest->whorl_outside = src->whorl_outside;
978    } else if (varn==VAR_WAVES2) {
979       /* waves2 */
980       dest->waves2_scalex = src->waves2_scalex;
981       dest->waves2_scaley = src->waves2_scaley;
982       dest->waves2_freqx = src->waves2_freqx;
983       dest->waves2_freqy = src->waves2_freqy;
984    } else if (varn==VAR_AUGER) {
985       /* auger */
986       dest->auger_sym = src->auger_sym;
987       dest->auger_weight = src->auger_weight;
988       dest->auger_freq = src->auger_freq;
989       dest->auger_scale = src->auger_scale;
990    } else if (varn==VAR_FLUX) {
991       /* flux */
992       dest->flux_spread = src->flux_spread;
993    } else if (varn==VAR_MOBIUS) {
994       /* mobius */
995       dest->mobius_re_a = src->mobius_re_a;
996       dest->mobius_re_b = src->mobius_re_b;
997       dest->mobius_re_c = src->mobius_re_c;
998       dest->mobius_re_d = src->mobius_re_d;
999       dest->mobius_im_a = src->mobius_im_a;
1000       dest->mobius_im_b = src->mobius_im_b;
1001       dest->mobius_im_c = src->mobius_im_c;
1002       dest->mobius_im_d = src->mobius_im_d;
1003    }
1004 }
1005 
1006 /* Motion support functions */
flam3_add_motion_element(flam3_xform * xf)1007 void flam3_add_motion_element(flam3_xform *xf) {
1008 
1009    /* Add one to the xform's count of motion elements */
1010    xf->num_motion++;
1011 
1012    /* Reallocate the motion storage to include the empty space */
1013    xf->motion = (struct xform *)realloc(xf->motion, xf->num_motion * sizeof(struct xform));
1014 
1015    /* Initialize the motion element */
1016    /* In this case, all elements should be set to 0 */
1017    memset( &(xf->motion[xf->num_motion-1]), 0, sizeof(struct xform));
1018 
1019 }
1020 
1021 /* Motion support functions */
flam3_delete_motion_elements(flam3_xform * xf)1022 void flam3_delete_motion_elements(flam3_xform *xf) {
1023 
1024    /* Free the motion elements */
1025    if (xf->num_motion>0) {
1026       free(xf->motion);
1027       xf->num_motion = 0;
1028    }
1029 
1030 }
1031 
1032 /* Xform support functions */
flam3_add_xforms(flam3_genome * thiscp,int num_to_add,int interp_padding,int final_flag)1033 void flam3_add_xforms(flam3_genome *thiscp, int num_to_add, int interp_padding, int final_flag) {
1034 
1035    int i,j;
1036    int old_num = thiscp->num_xforms;
1037    int oldstd,numstd;
1038    flam3_xform tmp;
1039 
1040    oldstd = thiscp->num_xforms - (thiscp->final_xform_index >= 0);
1041 
1042    /* !!! must make sure that if final_flag is specified, we don't already have a final xform! !!! */
1043 
1044 //   if (thiscp->num_xforms > 0)
1045       thiscp->xform = (flam3_xform *)realloc(thiscp->xform, (thiscp->num_xforms + num_to_add) * sizeof(flam3_xform));
1046 //   else
1047 //      thiscp->xform = (flam3_xform *)malloc(num_to_add * sizeof(flam3_xform));
1048 
1049    thiscp->num_xforms += num_to_add;
1050 
1051    /* Initialize all the new xforms */
1052    initialize_xforms(thiscp, old_num);
1053 
1054    /* Set the padding flag for the new xforms */
1055    if (interp_padding) {
1056       for (i = old_num ; i < thiscp->num_xforms ; i++)
1057          thiscp->xform[i].padding=1;
1058    }
1059 
1060    /* If the final xform is not the last xform in the list, make it so */
1061    if (thiscp->final_xform_index >= 0 && thiscp->final_xform_index != thiscp->num_xforms-1) {
1062       tmp = thiscp->xform[thiscp->final_xform_index];
1063       for (i=thiscp->final_xform_index; i < thiscp->num_xforms-1; i++)
1064          thiscp->xform[i] = thiscp->xform[i+1];
1065 
1066       thiscp->final_xform_index = thiscp->num_xforms-1;
1067       thiscp->xform[thiscp->final_xform_index] = tmp;
1068    }
1069 
1070    if (final_flag) {
1071       /* Set the final xform index */
1072       thiscp->final_xform_enable = 1;
1073       thiscp->final_xform_index = thiscp->num_xforms-1;
1074    } else {
1075       /* Handle the chaos array */
1076       numstd = thiscp->num_xforms - (thiscp->final_xform_index>=0);
1077 
1078       /* Pad existing rows */
1079       for (i=0;i<oldstd;i++) {
1080          thiscp->chaos[i] = realloc(thiscp->chaos[i], numstd * sizeof(double));
1081          for (j=oldstd; j<numstd; j++)
1082             thiscp->chaos[i][j] = 1.0;
1083       }
1084 
1085       /* Add new rows */
1086       thiscp->chaos = realloc(thiscp->chaos,numstd * sizeof(double *));
1087       for (i=oldstd; i<numstd; i++) {
1088          thiscp->chaos[i] = malloc(numstd * sizeof(double));
1089          for (j=0;j<numstd;j++)
1090             thiscp->chaos[i][j] = 1.0;
1091       }
1092    }
1093 }
1094 
flam3_delete_xform(flam3_genome * thiscp,int idx_to_delete)1095 void flam3_delete_xform(flam3_genome *thiscp, int idx_to_delete) {
1096 
1097    int i,j;
1098    int num_std = thiscp->num_xforms - (thiscp->final_xform_index >= 0);
1099 
1100    if (thiscp->final_xform_index != idx_to_delete) {
1101       /* We're going to delete the nth std xform. */
1102 
1103       /* Delete the nth_std row of the chaos array */
1104       free(thiscp->chaos[idx_to_delete]);
1105 
1106       /* Shift the pointers down one */
1107       for (i=idx_to_delete+1;i<num_std;i++)
1108          thiscp->chaos[i-1] = thiscp->chaos[i];
1109 
1110       /* Realloc the pointer array */
1111       thiscp->chaos = realloc(thiscp->chaos,(num_std-1)*sizeof(double *));
1112       num_std--;
1113 
1114       /* Loop over all of the rows and remove the nth_std element from them */
1115       for (i=0;i<num_std;i++) {
1116          for (j=idx_to_delete+1;j<num_std+1;j++) {
1117             thiscp->chaos[i][j-1] = thiscp->chaos[i][j];
1118          }
1119          /* Realloc the vector to have one less element */
1120          thiscp->chaos[i] = realloc(thiscp->chaos[i],num_std*sizeof(double));
1121 
1122       }
1123    }
1124 
1125    /* Handle the final xform index */
1126    if (thiscp->final_xform_index == idx_to_delete) {
1127       thiscp->final_xform_index = -1;
1128       thiscp->final_xform_enable = 0;
1129    } else if (thiscp->final_xform_index > idx_to_delete) {
1130       thiscp->final_xform_index--;
1131    }
1132 
1133    /* Delete the motion elements of the banished xform */
1134    flam3_delete_motion_elements(&(thiscp->xform[idx_to_delete]));
1135 
1136    /* Move all of the xforms down one - this does not require manual motion xform adjustment */
1137    for (i=idx_to_delete; i<thiscp->num_xforms-1; i++)
1138       thiscp->xform[i] = thiscp->xform[i+1];
1139 
1140    thiscp->num_xforms--;
1141 
1142    /* Reduce the memory storage by one xform */
1143    thiscp->xform = (flam3_xform *)realloc(thiscp->xform, sizeof(flam3_xform) * thiscp->num_xforms);
1144 
1145 }
1146 
flam3_copy_xform(flam3_xform * dest,flam3_xform * src)1147 void flam3_copy_xform(flam3_xform *dest, flam3_xform *src) {
1148 
1149    int j;
1150 
1151    /* Make sure the dest doesn't have motion already */
1152    if (dest->num_motion>0)
1153       flam3_delete_motion_elements(dest);
1154 
1155    /* Copy everything */
1156    *dest = *src;
1157 
1158    /* Reset motion in dest and copy it */
1159    dest->num_motion=0;
1160    dest->motion=NULL;
1161 
1162    if (src->num_motion>0) {
1163       for (j=0;j<src->num_motion;j++)
1164          flam3_add_motion_element(dest);
1165 
1166       memcpy(dest->motion,src->motion,src->num_motion*sizeof(flam3_xform));
1167    }
1168 }
1169 
1170 /* Copy one control point to another */
flam3_copy(flam3_genome * dest,flam3_genome * src)1171 void flam3_copy(flam3_genome *dest, flam3_genome *src) {
1172 
1173    int i,ii;
1174    int numstd;
1175 
1176    /* If there are any xforms in dest before the copy, clean them up */
1177    clear_cp(dest, 1);
1178 
1179    /* Copy main contents of genome */
1180    memcpy(dest, src, sizeof(flam3_genome));
1181 
1182    /* Only the pointer to the xform was copied, not the actual xforms. */
1183    /* We need to create new xform memory storage for this new cp       */
1184    /* This goes for chaos, too.                                        */
1185    dest->num_xforms = 0;
1186    dest->final_xform_index = -1;
1187    dest->xform = NULL;
1188    dest->chaos = NULL;
1189 
1190    /* Add the standard xforms first */
1191    numstd = src->num_xforms-(src->final_xform_index>=0);
1192    flam3_add_xforms(dest, numstd, 0, 0);
1193    for (i=0;i<numstd;i++)
1194       flam3_copy_xform(&dest->xform[i], &src->xform[i]);
1195 
1196    /* Add the final x if it's present */
1197    if (src->final_xform_index>=0) {
1198       i = src->final_xform_index;
1199       flam3_add_xforms(dest, 1, 0, 1);
1200       ii = dest->final_xform_index;
1201       flam3_copy_xform(&dest->xform[ii],&src->xform[i]);
1202    }
1203 
1204    /* Also, only the pointer to the chaos array was copied.
1205     * We have to take care of that as well.                 */
1206    for (i=0;i<numstd;i++)
1207       memcpy(dest->chaos[i],src->chaos[i], numstd * sizeof(double));
1208 
1209 }
1210 
flam3_copyx(flam3_genome * dest,flam3_genome * src,int dest_std_xforms,int dest_final_xform)1211 void flam3_copyx(flam3_genome *dest, flam3_genome *src, int dest_std_xforms, int dest_final_xform) {
1212 
1213    int i,numsrcstd;
1214 
1215    /* If there are any xforms in dest before the copy, clean them up */
1216    clear_cp(dest, 1);
1217 
1218    /* Copy main contents of genome */
1219    memcpy(dest, src, sizeof(flam3_genome));
1220 
1221    /* Only the pointer to the xform was copied, not the actual xforms. */
1222    /* We need to create new xform memory storage for this new cp       */
1223    /* This goes for chaos, too.                                        */
1224    dest->num_xforms = 0;
1225    dest->xform = NULL;
1226    dest->chaos = NULL;
1227    dest->final_xform_index = -1;
1228 
1229    /* Add the padded standard xform list */
1230    /* Set the pad to 1 for these */
1231    flam3_add_xforms(dest, dest_std_xforms, 1, 0);
1232 
1233    numsrcstd = src->num_xforms - (src->final_xform_index >= 0);
1234 
1235    for(i=0;i<numsrcstd;i++) {
1236 
1237       /* When we copy the old xform, the pad is set to 0 */
1238       flam3_copy_xform(&dest->xform[i],&src->xform[i]);
1239 
1240       /* Copy the initial chaos from the src - the rest are already 1 */
1241       memcpy(dest->chaos[i], src->chaos[i], numsrcstd*sizeof(double));
1242 
1243    }
1244 
1245    /* Add the final xform if necessary */
1246    if (dest_final_xform > 0) {
1247       flam3_add_xforms(dest, dest_final_xform, 1, 1);
1248 
1249       if (src->final_xform_enable > 0) {
1250 
1251          i = src->final_xform_index;
1252 
1253          flam3_copy_xform(&dest->xform[dest->num_xforms-1],&src->xform[i]);
1254 
1255       } else {
1256          /* Interpolated-against final xforms need animate & color_speed set to 0.0 */
1257          dest->xform[dest->num_xforms-1].num_motion = 0;
1258          dest->xform[dest->num_xforms-1].motion=NULL;
1259          dest->xform[dest->num_xforms-1].animate=0.0;
1260          dest->xform[dest->num_xforms-1].color_speed=0.0;
1261       }
1262 
1263    } else {
1264       dest->final_xform_index = -1;
1265       dest->final_xform_enable = 0;
1266    }
1267 
1268 }
1269 
clear_cp(flam3_genome * cp,int default_flag)1270 void clear_cp(flam3_genome *cp, int default_flag) {
1271     cp->palette_index = flam3_palette_random;
1272     cp->center[0] = 0.0;
1273     cp->center[1] = 0.0;
1274     cp->rot_center[0] = 0.0;
1275     cp->rot_center[1] = 0.0;
1276     cp->gamma = 4.0;
1277     cp->vibrancy = 1.0;
1278     cp->contrast = 1.0;
1279     cp->brightness = 4.0;
1280     cp->symmetry = 0;
1281     cp->hue_rotation = 0.0;
1282     cp->rotate = 0.0;
1283     cp->pixels_per_unit = 50;
1284     cp->interpolation = flam3_interpolation_linear;
1285     cp->palette_interpolation = flam3_palette_interpolation_hsv_circular;
1286     cp->hsv_rgb_palette_blend = 0.0;
1287 
1288     cp->genome_index = 0;
1289     memset(cp->parent_fname,0,flam3_parent_fn_len);
1290 
1291     if (default_flag==flam3_defaults_on) {
1292        /* If defaults are on, set to reasonable values */
1293        cp->highlight_power = -1.0;
1294        cp->background[0] = 0.0;
1295        cp->background[1] = 0.0;
1296        cp->background[2] = 0.0;
1297        cp->width = 100;
1298        cp->height = 100;
1299        cp->spatial_oversample = 1;
1300        cp->spatial_filter_radius = 0.5;
1301        cp->zoom = 0.0;
1302        cp->sample_density = 1;
1303        /* Density estimation stuff defaulting to ON */
1304        cp->estimator = 9.0;
1305        cp->estimator_minimum = 0.0;
1306        cp->estimator_curve = 0.4;
1307        cp->gam_lin_thresh = 0.01;
1308 //       cp->motion_exp = 0.0;
1309        cp->nbatches = 1;
1310        cp->ntemporal_samples = 1000;
1311        cp->spatial_filter_select = flam3_gaussian_kernel;
1312        cp->interpolation_type = flam3_inttype_log;
1313        cp->temporal_filter_type = flam3_temporal_box;
1314        cp->temporal_filter_width = 1.0;
1315        cp->temporal_filter_exp = 0.0;
1316        cp->palette_mode = flam3_palette_mode_step;
1317 
1318     } else {
1319        /* Defaults are off, so set to UN-reasonable values. */
1320        cp->highlight_power = -1.0;
1321        cp->background[0] = -1.0;
1322        cp->background[1] = -1.0;
1323        cp->background[2] = -1.0;
1324        cp->zoom = 999999999;
1325        cp->spatial_oversample = -1;
1326        cp->spatial_filter_radius = -1;
1327        cp->nbatches = -1;
1328        cp->ntemporal_samples = -1;
1329        cp->width = -1;
1330        cp->height = -1;
1331        cp->sample_density = -1;
1332        cp->estimator = -1;
1333        cp->estimator_minimum = -1;
1334        cp->estimator_curve = -1;
1335        cp->gam_lin_thresh = -1;
1336 //       cp->motion_exp = -999;
1337        cp->nbatches = 0;
1338        cp->ntemporal_samples = 0;
1339        cp->spatial_filter_select = -1;
1340        cp->interpolation_type = -1;
1341        cp->temporal_filter_type = -1;
1342        cp->temporal_filter_width = -1;
1343        cp->temporal_filter_exp = -999;
1344        cp->palette_mode = -1;
1345     }
1346 
1347     if (cp->xform != NULL && cp->num_xforms > 0) {
1348         int i;
1349         int ns = cp->num_xforms - (cp->final_xform_index>=0);
1350 
1351        for (i=0;i<ns;i++) {
1352           free(cp->chaos[i]);
1353        }
1354        free(cp->chaos);
1355        cp->chaos=NULL;
1356 
1357       for (i=0;i<cp->num_xforms;i++)
1358          flam3_delete_motion_elements(&cp->xform[i]);
1359 
1360        free(cp->xform);
1361        cp->xform=NULL;
1362 
1363        cp->num_xforms = 0;
1364     }
1365 
1366     cp->final_xform_enable = 0;
1367     cp->final_xform_index = -1;
1368 
1369 }
1370 
1371 
flam3_count_nthreads(void)1372 int flam3_count_nthreads(void) {
1373    int nthreads;
1374 #ifndef HAVE_LIBPTHREAD
1375    return(1);
1376 #endif
1377 
1378 #ifdef _WIN32
1379    SYSTEM_INFO sysInfo;
1380    GetSystemInfo(&sysInfo);
1381    nthreads = sysInfo.dwNumberOfProcessors;
1382 #else
1383 #ifdef __APPLE__
1384    kern_return_t    kr;
1385    host_name_port_t   host;
1386    unsigned int     size;
1387    struct host_basic_info   hi;
1388 
1389    host = mach_host_self();
1390    size = sizeof(hi)/sizeof(int);
1391    kr = host_info(host, HOST_BASIC_INFO, (host_info_t)&hi, &size);
1392    if (kr != KERN_SUCCESS) {
1393        mach_error("host_info():", kr);
1394        /* set threads to 1 on error */
1395        nthreads = 1;
1396    } else
1397        nthreads = hi.avail_cpus;
1398 #else
1399 #ifndef _SC_NPROCESSORS_ONLN
1400    char line[MAXBUF];
1401    FILE *f = fopen("/proc/cpuinfo", "r");
1402    if (NULL == f) goto def;
1403    nthreads = 0;
1404    while (fgets(line, MAXBUF, f)) {
1405       if (!strncmp("processor\t:", line, 11))
1406          nthreads++;
1407    }
1408    fclose(f);
1409    if (nthreads < 1) goto def;
1410    return (nthreads);
1411 def:
1412    fprintf(stderr, "could not read /proc/cpuinfo, using one render thread.\n");
1413    nthreads = 1;
1414 #else
1415    nthreads = sysconf(_SC_NPROCESSORS_ONLN);
1416    if (nthreads < 1) nthreads = 1;
1417 #endif
1418 #endif
1419 #endif
1420    return (nthreads);
1421 }
1422 
flam3_parse_xml2(char * xmldata,char * xmlfilename,int default_flag,int * ncps)1423 flam3_genome *flam3_parse_xml2(char *xmldata, char *xmlfilename, int default_flag, int *ncps) {
1424 
1425    xmlDocPtr doc; /* Parsed XML document tree */
1426    xmlNode *rootnode;
1427    char *bn;
1428    int i;
1429    int loc_all_ncps=0;
1430    flam3_genome *loc_all_cp=NULL;
1431    char* locale = NULL;
1432    char* lorig  = setlocale(LC_NUMERIC, NULL);
1433 
1434    /* Parse XML string into internal document */
1435    /* Forbid network access during read       */
1436    doc = xmlReadMemory(xmldata, (int)strlen(xmldata), xmlfilename, NULL, XML_PARSE_NONET);
1437 
1438    /* Check for errors */
1439    if (doc==NULL) {
1440       fprintf(stderr, "Failed to parse %s\n", xmlfilename);
1441       return NULL;
1442    }
1443 
1444    /* What is the root node of the document? */
1445    rootnode = xmlDocGetRootElement(doc);
1446 
1447    // force use of "C" locale when writing reals.
1448    // first save away the current settings.
1449    if (lorig == NULL)
1450       fprintf(stderr, "error: couldn't get current locale\n");
1451    else {
1452       int slen = strlen(lorig) + 1;
1453       locale = (char*)malloc(slen);
1454       if (locale != NULL)
1455          memcpy(locale, lorig, slen);
1456    }
1457    if (setlocale(LC_NUMERIC, "C") == NULL)
1458       fprintf(stderr, "error: couldn't set C locale\n");
1459 
1460    /* Scan for <flame> nodes, starting with this node */
1461    bn = basename(xmlfilename);
1462 
1463    /* Have to use &loc_all_cp since the memory gets allocated in scan_for_flame_nodes */
1464    scan_for_flame_nodes(rootnode, bn, default_flag,&loc_all_cp,&loc_all_ncps);
1465 
1466    // restore locale
1467    if (locale != NULL) {
1468       if (setlocale(LC_NUMERIC, locale) == NULL)
1469          fprintf(stderr, "error: couldn't replace locale settings\n");
1470       free(locale);
1471    }
1472 
1473    xmlFreeDoc(doc);
1474 
1475    *ncps = loc_all_ncps;
1476 
1477    /* Check to see if the first control point or the second-to-last */
1478    /* control point has interpolation="smooth".  This is invalid    */
1479    /* and should be reset to linear (with a warning).               */
1480    if (loc_all_ncps>=1) {
1481       if (loc_all_cp[0].interpolation == flam3_interpolation_smooth) {
1482          fprintf(stderr,"Warning: smooth interpolation cannot be used for first segment.\n"
1483                         "         switching to linear.\n");
1484          loc_all_cp[0].interpolation = flam3_interpolation_linear;
1485       }
1486    }
1487 
1488    if (loc_all_ncps>=2) {
1489       if (loc_all_cp[(loc_all_ncps)-2].interpolation == flam3_interpolation_smooth) {
1490          fprintf(stderr,"Warning: smooth interpolation cannot be used for last segment.\n"
1491                         "         switching to linear.\n");
1492          loc_all_cp[loc_all_ncps-2].interpolation = flam3_interpolation_linear;
1493       }
1494    }
1495 
1496    /* Finally, ensure that consecutive 'rotate' parameters never exceed */
1497    /* a difference of more than 180 degrees (+/-) for interpolation.    */
1498    /* An adjustment of +/- 360 degrees is made until this is true.      */
1499    if (*ncps>1) {
1500 
1501       for (i=1;i<*ncps;i++) {
1502 
1503          /* Only do this adjustment if we're not in compat mode */
1504          if (flam3_inttype_compat != loc_all_cp[i-1].interpolation_type
1505         && flam3_inttype_older != loc_all_cp[i-1].interpolation_type) {
1506 
1507             while (loc_all_cp[i].rotate < loc_all_cp[i-1].rotate-180)
1508                loc_all_cp[i].rotate += 360;
1509 
1510             while (loc_all_cp[i].rotate > loc_all_cp[i-1].rotate+180)
1511                loc_all_cp[i].rotate -= 360;
1512          }
1513       }
1514    }
1515 
1516    //Note that concurrent calls to flam3, if in parallel, potentially segfault
1517    //if this function is called.  technically it's required but it doesn't
1518    //leak memory continuously.
1519    //xmlCleanupParser();
1520 
1521    return loc_all_cp;
1522 }
1523 
flam3_parse_from_file(FILE * f,char * fname,int default_flag,int * ncps)1524 flam3_genome * flam3_parse_from_file(FILE *f, char *fname, int default_flag, int *ncps) {
1525    int i, c, slen = 5000;
1526    char *s, *snew;
1527    flam3_genome *ret;
1528 
1529    /* Incrementally read XML file into a string */
1530    s = malloc(slen);
1531    i = 0;
1532    do {
1533       c = getc(f);
1534       if (EOF == c)
1535          break;
1536       s[i++] = c;
1537       if (i == slen-1) {
1538          slen *= 2;
1539          snew = realloc(s, slen);
1540          if (snew==NULL) {
1541             fprintf(stderr,"XML file too large to be read. continuing with partial file.\n");
1542             break;
1543          } else
1544             s = snew;
1545       }
1546    } while (1);
1547 
1548    /* Null-terminate the read XML data */
1549    s[i] = 0;
1550 
1551    /* Parse the XML string */
1552    if (fname)
1553       ret = flam3_parse_xml2(s, fname, default_flag, ncps);
1554    else
1555       ret = flam3_parse_xml2(s, "stdin", default_flag, ncps);
1556 
1557    free(s);
1558 
1559    return(ret);
1560 
1561 }
1562 
1563 
flam3_apply_template(flam3_genome * cp,flam3_genome * templ)1564 void flam3_apply_template(flam3_genome *cp, flam3_genome *templ) {
1565 
1566    /* Check for invalid values - only replace those with valid ones */
1567    if (templ->background[0] >= 0)
1568       cp->background[0] = templ->background[0];
1569    if (templ->background[1] >= 0)
1570       cp->background[1] = templ->background[1];
1571    if (templ->background[1] >= 0)
1572       cp->background[2] = templ->background[2];
1573    if (templ->zoom < 999999998)
1574       cp->zoom = templ->zoom;
1575    if (templ->spatial_oversample > 0)
1576       cp->spatial_oversample = templ->spatial_oversample;
1577    if (templ->spatial_filter_radius >= 0)
1578       cp->spatial_filter_radius = templ->spatial_filter_radius;
1579    if (templ->sample_density > 0)
1580       cp->sample_density = templ->sample_density;
1581    if (templ->nbatches > 0)
1582       cp->nbatches = templ->nbatches;
1583    if (templ->ntemporal_samples > 0)
1584       cp->ntemporal_samples = templ->ntemporal_samples;
1585    if (templ->width > 0) {
1586       /* preserving scale should be an option */
1587       // cp->pixels_per_unit = cp->pixels_per_unit * templ->width / cp->width;
1588       cp->pixels_per_unit = cp->pixels_per_unit * templ->height / cp->height;
1589       cp->width = templ->width;
1590    }
1591    if (templ->height > 0)
1592       cp->height = templ->height;
1593    if (templ->estimator >= 0)
1594       cp->estimator = templ->estimator;
1595    if (templ->estimator_minimum >= 0)
1596       cp->estimator_minimum = templ->estimator_minimum;
1597    if (templ->estimator_curve >= 0)
1598       cp->estimator_curve = templ->estimator_curve;
1599    if (templ->gam_lin_thresh >= 0)
1600       cp->gam_lin_thresh = templ->gam_lin_thresh;
1601    if (templ->nbatches>0)
1602       cp->nbatches = templ->nbatches;
1603    if (templ->ntemporal_samples>0)
1604       cp->ntemporal_samples = templ->ntemporal_samples;
1605    if (templ->spatial_filter_select>0)
1606       cp->spatial_filter_select = templ->spatial_filter_select;
1607    if (templ->interpolation >= 0)
1608       cp->interpolation = templ->interpolation;
1609    if (templ->interpolation_type >= 0)
1610       cp->interpolation_type = templ->interpolation_type;
1611    if (templ->temporal_filter_type >= 0)
1612       cp->temporal_filter_type = templ->temporal_filter_type;
1613    if (templ->temporal_filter_width > 0)
1614       cp->temporal_filter_width = templ->temporal_filter_width;
1615    if (templ->temporal_filter_exp > -900)
1616       cp->temporal_filter_exp = templ->temporal_filter_exp;
1617    if (templ->highlight_power >=0)
1618       cp->highlight_power = templ->highlight_power;
1619    if (templ->palette_mode >= 0)
1620       cp->palette_mode = templ->palette_mode;
1621    if (templ->palette_interpolation >= 0)
1622       cp->palette_interpolation = templ->palette_interpolation;
1623    if (templ->hsv_rgb_palette_blend >= 0)
1624       cp->hsv_rgb_palette_blend = templ->hsv_rgb_palette_blend;
1625 
1626 }
1627 
flam3_print_to_string(flam3_genome * cp)1628 char *flam3_print_to_string(flam3_genome *cp) {
1629 
1630    FILE *tmpflame;
1631    long stringbytes;
1632    char *genome_string;
1633 
1634    int using_tmpdir = 0;
1635    char tmpnam[256];
1636 
1637    tmpflame = tmpfile();
1638    if (NULL==tmpflame) {
1639 #ifdef _WIN32
1640        // This might be a permissions problem, so let's try to open a
1641        // tempfile in the env var TEMP's area instead
1642        char* tmp_path = getenv("TEMP");
1643 
1644        if (tmp_path != NULL) {
1645           strcpy(tmpnam, tmp_path);
1646           strcat(tmpnam, "\\fr0st.tmp");
1647           tmpflame = fopen(tmpnam, "w+");
1648           if (tmpflame != NULL) {
1649              using_tmpdir = 1;
1650           }
1651        }
1652 #endif
1653        if (using_tmpdir == 0) {
1654           perror("FLAM3: opening temporary file");
1655           return (NULL);
1656        }
1657    }
1658    flam3_print(tmpflame,cp,NULL,flam3_dont_print_edits);
1659    stringbytes = ftell(tmpflame);
1660    fseek(tmpflame,0L, SEEK_SET);
1661    genome_string = (char *)calloc(stringbytes+1,1);
1662    if (stringbytes != fread(genome_string, 1, stringbytes, tmpflame)) {
1663        perror("FLAM3: reading string from temp file");
1664    }
1665    fclose(tmpflame);
1666 
1667    if (using_tmpdir)
1668       unlink(tmpnam);
1669 
1670    return(genome_string);
1671 }
1672 
1673 
flam3_print(FILE * f,flam3_genome * cp,char * extra_attributes,int print_edits)1674 void flam3_print(FILE *f, flam3_genome *cp, char *extra_attributes, int print_edits) {
1675    int i,numstd;
1676    int flam27_flag;
1677    char *ai;
1678 
1679    // force use of "C" locale when writing reals.
1680    // first save away the current settings.
1681    char* locale = NULL;
1682    char* lorig  = setlocale(LC_NUMERIC, NULL);
1683    if (lorig == NULL)
1684       fprintf(stderr, "error: couldn't get current locale\n");
1685    else {
1686       int slen = strlen(lorig) + 1;
1687       locale = (char*)malloc(slen);
1688       if (locale != NULL)
1689       memcpy(locale, lorig, slen);
1690    }
1691    if (setlocale(LC_NUMERIC, "C") == NULL)
1692       fprintf(stderr, "error: couldn't set C locale\n");
1693 
1694 
1695    flam27_flag = argi("flam27",0);
1696 
1697    fprintf(f, "<flame version=\"FLAM3-%s\" time=\"%g\"", flam3_version(),cp->time);
1698 
1699    if (cp->flame_name[0]!=0)
1700       fprintf(f, " name=\"%s\"",cp->flame_name);
1701 
1702    fprintf(f, " size=\"%d %d\"", cp->width, cp->height);
1703    fprintf(f, " center=\"%g %g\"", cp->center[0], cp->center[1]);
1704    fprintf(f, " scale=\"%g\"", cp->pixels_per_unit);
1705 
1706    if (cp->zoom != 0.0)
1707       fprintf(f, " zoom=\"%g\"", cp->zoom);
1708 
1709    fprintf(f, " rotate=\"%g\"", cp->rotate);
1710    fprintf(f, " supersample=\"%d\"", cp->spatial_oversample);
1711    fprintf(f, " filter=\"%g\"", cp->spatial_filter_radius);
1712 
1713    /* Need to print the correct kernel to use */
1714    if (cp->spatial_filter_select == flam3_gaussian_kernel)
1715       fprintf(f, " filter_shape=\"gaussian\"");
1716    else if (cp->spatial_filter_select == flam3_hermite_kernel)
1717       fprintf(f, " filter_shape=\"hermite\"");
1718    else if (cp->spatial_filter_select == flam3_box_kernel)
1719       fprintf(f, " filter_shape=\"box\"");
1720    else if (cp->spatial_filter_select == flam3_triangle_kernel)
1721       fprintf(f, " filter_shape=\"triangle\"");
1722    else if (cp->spatial_filter_select == flam3_bell_kernel)
1723       fprintf(f, " filter_shape=\"bell\"");
1724    else if (cp->spatial_filter_select == flam3_b_spline_kernel)
1725       fprintf(f, " filter_shape=\"bspline\"");
1726    else if (cp->spatial_filter_select == flam3_mitchell_kernel)
1727       fprintf(f, " filter_shape=\"mitchell\"");
1728    else if (cp->spatial_filter_select == flam3_blackman_kernel)
1729       fprintf(f, " filter_shape=\"blackman\"");
1730    else if (cp->spatial_filter_select == flam3_catrom_kernel)
1731       fprintf(f, " filter_shape=\"catrom\"");
1732    else if (cp->spatial_filter_select == flam3_hanning_kernel)
1733       fprintf(f, " filter_shape=\"hanning\"");
1734    else if (cp->spatial_filter_select == flam3_hamming_kernel)
1735       fprintf(f, " filter_shape=\"hamming\"");
1736    else if (cp->spatial_filter_select == flam3_lanczos3_kernel)
1737       fprintf(f, " filter_shape=\"lanczos3\"");
1738    else if (cp->spatial_filter_select == flam3_lanczos2_kernel)
1739       fprintf(f, " filter_shape=\"lanczos2\"");
1740    else if (cp->spatial_filter_select == flam3_quadratic_kernel)
1741       fprintf(f, " filter_shape=\"quadratic\"");
1742 
1743    if (cp->temporal_filter_type == flam3_temporal_box)
1744       fprintf(f, " temporal_filter_type=\"box\"");
1745    else if (cp->temporal_filter_type == flam3_temporal_gaussian)
1746       fprintf(f, " temporal_filter_type=\"gaussian\"");
1747    else if (cp->temporal_filter_type == flam3_temporal_exp)
1748       fprintf(f, " temporal_filter_type=\"exp\" temporal_filter_exp=\"%g\"",cp->temporal_filter_exp);
1749 
1750    fprintf(f, " temporal_filter_width=\"%g\"",cp->temporal_filter_width);
1751 
1752 
1753 
1754    fprintf(f, " quality=\"%g\"", cp->sample_density);
1755    fprintf(f, " passes=\"%d\"", cp->nbatches);
1756    fprintf(f, " temporal_samples=\"%d\"", cp->ntemporal_samples);
1757    fprintf(f, " background=\"%g %g %g\"",
1758       cp->background[0], cp->background[1], cp->background[2]);
1759    fprintf(f, " brightness=\"%g\"", cp->brightness);
1760    fprintf(f, " gamma=\"%g\"", cp->gamma);
1761 
1762    if (!flam27_flag)
1763       fprintf(f, " highlight_power=\"%g\"", cp->highlight_power);
1764 
1765    fprintf(f, " vibrancy=\"%g\"", cp->vibrancy);
1766    fprintf(f, " estimator_radius=\"%g\" estimator_minimum=\"%g\" estimator_curve=\"%g\"",
1767       cp->estimator, cp->estimator_minimum, cp->estimator_curve);
1768    fprintf(f, " gamma_threshold=\"%g\"", cp->gam_lin_thresh);
1769 
1770    if (flam3_palette_mode_step == cp->palette_mode)
1771       fprintf(f, " palette_mode=\"step\"");
1772    else if (flam3_palette_mode_linear == cp->palette_mode)
1773       fprintf(f, " palette_mode=\"linear\"");
1774 
1775    if (flam3_interpolation_linear != cp->interpolation)
1776        fprintf(f, " interpolation=\"smooth\"");
1777 
1778    if (flam3_inttype_linear == cp->interpolation_type)
1779        fprintf(f, " interpolation_type=\"linear\"");
1780    else if (flam3_inttype_log == cp->interpolation_type)
1781        fprintf(f, " interpolation_type=\"log\"");
1782    else if (flam3_inttype_compat == cp->interpolation_type)
1783        fprintf(f, " interpolation_type=\"old\"");
1784    else if (flam3_inttype_older == cp->interpolation_type)
1785        fprintf(f, " interpolation_type=\"older\"");
1786 
1787 
1788    if (flam3_palette_interpolation_sweep == cp->palette_interpolation)
1789        fprintf(f, " palette_interpolation=\"sweep\"");
1790    else if (flam3_palette_interpolation_rgb == cp->palette_interpolation)
1791        fprintf(f, " palette_interpolation=\"rgb\"");
1792    else if (flam3_palette_interpolation_hsv == cp->palette_interpolation)
1793        fprintf(f, " palette_interpolation=\"hsv\"");
1794    else if (flam3_palette_interpolation_hsv_circular == cp->palette_interpolation) {
1795        fprintf(f, " palette_interpolation=\"hsv_circular\"");
1796        if (cp->hsv_rgb_palette_blend > 0.0)
1797            fprintf(f, " hsv_rgb_palette_blend=\"%g\"", cp->hsv_rgb_palette_blend);
1798    }
1799 
1800    if (extra_attributes)
1801       fprintf(f, " %s", extra_attributes);
1802 
1803    fprintf(f, ">\n");
1804 
1805    if (cp->symmetry)
1806       fprintf(f, "   <symmetry kind=\"%d\"/>\n", cp->symmetry);
1807 
1808    numstd = cp->num_xforms - (cp->final_xform_index>=0);
1809 
1810    for (i = 0; i < cp->num_xforms; i++) {
1811 
1812       if (i==cp->final_xform_index)
1813          flam3_print_xform(f, &cp->xform[i], 1, numstd, NULL, 0);
1814       else
1815          flam3_print_xform(f, &cp->xform[i], 0, numstd, cp->chaos[i], 0);
1816 
1817    }
1818 
1819    int hexpalette = argi("hexpalette",0);
1820 
1821    if (hexpalette) {
1822 
1823       fprintf(f,"   <palette count=\"256\" format=\"RGB\">");
1824 
1825       for (i=0; i < 256; i++) {
1826 
1827          int r, g, b;
1828          r = rint(cp->palette[i].color[0] * 255.0);
1829          g = rint(cp->palette[i].color[1] * 255.0);
1830          b = rint(cp->palette[i].color[2] * 255.0);
1831 
1832          if (i % 8 == 0) {
1833             fprintf(f,"\n");
1834             fprintf(f,"      ");
1835          }
1836 
1837          fprintf(f,"%2x%2x%2x",r,g,b);
1838 
1839       }
1840 
1841       fprintf(f,"\n");
1842       fprintf(f,"   </palette>\n");
1843 
1844    } else {
1845    for (i = 0; i < 256; i++) {
1846       double r, g, b, a;
1847       r = (cp->palette[i].color[0] * 255.0);
1848       g = (cp->palette[i].color[1] * 255.0);
1849       b = (cp->palette[i].color[2] * 255.0);
1850       a = (cp->palette[i].color[3] * 255.0);
1851 
1852       fprintf(f, "   ");
1853 
1854       if (flam27_flag || a==255.0) {
1855 
1856          if (flam27_flag && a!=255.0)
1857             fprintf(stderr,"alpha channel in palette cannot be stored in 2.7 compatibility mode; truncating\n");
1858 
1859          if (getenv("intpalette"))
1860             fprintf(f, "<color index=\"%d\" rgb=\"%d %d %d\"/>", i, (int)rint(r), (int)rint(g), (int)rint(b));
1861          else {
1862 #ifdef USE_FLOAT_INDICES
1863             fprintf(f, "<color index=\"%.10g\" rgb=\"%.6g %.6g %.6g\"/>", cp->palette[i].index, r, g, b);
1864 #else
1865             fprintf(f, "<color index=\"%d\" rgb=\"%.6g %.6g %.6g\"/>", i, r, g, b);
1866 #endif
1867          }
1868       } else {
1869          if (getenv("intpalette"))
1870             fprintf(f, "   <color index=\"%d\" rgba=\"%d %d %d %d\"/>", i, (int)rint(r), (int)rint(g), (int)rint(b), (int)rint(a));
1871          else
1872             fprintf(f, "   <color index=\"%d\" rgba=\"%.6g %.6g %.6g %.6g\"/>", i, r, g, b, a);
1873       }
1874 //      if (i%4 == 3)
1875          fprintf(f, "\n");
1876 
1877    }
1878    }
1879 
1880    if (cp->edits != NULL && print_edits==flam3_print_edits) {
1881 
1882       /* We need a custom script for printing these */
1883       /* and it needs to be recursive               */
1884       xmlNodePtr elem_node = xmlDocGetRootElement(cp->edits);
1885       flam3_edit_print(f,elem_node, 1, 1);
1886    }
1887    fprintf(f, "</flame>\n");
1888 
1889    if (locale != NULL) {
1890       if (setlocale(LC_NUMERIC, locale) == NULL)
1891          fprintf(stderr, "error: couldn't restore locale settings\n");
1892       free(locale);
1893    }
1894 }
1895 
1896 #define PRINTNON(p) do { if (x->p != 0.0) fprintf(f, #p "=\"%f\" ",x->p); } while(0)
1897 
1898 
flam3_print_xform(FILE * f,flam3_xform * x,int final_flag,int numstd,double * chaos_row,int motion_flag)1899 void flam3_print_xform(FILE *f, flam3_xform *x, int final_flag, int numstd, double *chaos_row, int motion_flag) {
1900 
1901    int blob_var=0,pdj_var=0,fan2_var=0,rings2_var=0,perspective_var=0;
1902    int juliaN_var=0,juliaScope_var=0,radialBlur_var=0,pie_var=0,disc2_var=0;
1903    int ngon_var=0,curl_var=0,rectangles_var=0,supershape_var=0;
1904    int flower_var=0,conic_var=0,parabola_var=0,bent2_var=0,bipolar_var=0;
1905    int cell_var=0,cpow_var=0,curve_var=0,escher_var=0,lazys_var=0;
1906    int modulus_var=0,oscope_var=0,popcorn2_var=0,separation_var=0;
1907    int split_var=0,splits_var=0,stripes_var=0,wedge_var=0,wedgeJ_var=0;
1908    int wedgeS_var=0,whorl_var=0,waves2_var=0,auger_var=0,flux_var=0;
1909    int mobius_var=0;
1910 
1911    int j;
1912    int lnv;
1913 
1914    int flam27_flag;
1915    char *ai;
1916 
1917    flam27_flag = argi("flam27",0);
1918 
1919    /* Motion flag will not be set if flam27_flag is set */
1920    if (motion_flag) {
1921       fprintf(f, "      <motion motion_frequency=\"%d\" ",x->motion_freq);
1922       if (x->motion_func == MOTION_SIN)
1923          fprintf(f, "motion_function=\"sin\" ");
1924       else if (x->motion_func == MOTION_TRIANGLE)
1925          fprintf(f, "motion_function=\"triangle\" ");
1926       else if (x->motion_func == MOTION_HILL)
1927          fprintf(f, "motion_function=\"hill\" ");
1928    } else {
1929       if (final_flag)
1930          fprintf(f, "   <finalxform ");
1931       else
1932          fprintf(f, "   <xform weight=\"%g\" ", x->density);
1933    }
1934 
1935    if (!motion_flag || x->color != 0.0)
1936       fprintf(f, "color=\"%g\" ", x->color);
1937 
1938    if (flam27_flag)
1939       fprintf(f, "symmetry=\"%g\" ", 1.0-2.0*x->color_speed);
1940    else if (!motion_flag || x->color_speed != 0.0)
1941       fprintf(f, "color_speed=\"%g\" ", x->color_speed);
1942 
1943    if (!final_flag && !motion_flag && !flam27_flag)
1944       fprintf(f, "animate=\"%g\" ", x->animate);
1945 
1946    lnv = flam27_flag ? 54:flam3_nvariations;
1947 
1948    for (j = 0; j < lnv; j++) {
1949       double v = x->var[j];
1950       if (j == VAR_TWINTRIAN) continue;
1951       if (0.0 != v) {
1952          fprintf(f, "%s=\"%g\" ", flam3_variation_names[j], v);
1953          if (j==VAR_BLOB)
1954             blob_var=1;
1955          else if (j==VAR_PDJ)
1956             pdj_var=1;
1957          else if (j==VAR_FAN2)
1958             fan2_var=1;
1959          else if (j==VAR_RINGS2)
1960             rings2_var=1;
1961          else if (j==VAR_PERSPECTIVE)
1962             perspective_var=1;
1963          else if (j==VAR_JULIAN)
1964             juliaN_var=1;
1965          else if (j==VAR_JULIASCOPE)
1966             juliaScope_var=1;
1967          else if (j==VAR_RADIAL_BLUR)
1968             radialBlur_var=1;
1969          else if (j==VAR_PIE)
1970             pie_var=1;
1971          else if (j==VAR_NGON)
1972             ngon_var=1;
1973          else if (j==VAR_CURL)
1974             curl_var=1;
1975          else if (j==VAR_RECTANGLES)
1976             rectangles_var=1;
1977          else if (j==VAR_DISC2)
1978             disc2_var=1;
1979          else if (j==VAR_SUPER_SHAPE)
1980             supershape_var=1;
1981          else if (j==VAR_FLOWER)
1982             flower_var=1;
1983          else if (j==VAR_CONIC)
1984             conic_var=1;
1985          else if (j==VAR_PARABOLA)
1986             parabola_var=1;
1987          else if (j==VAR_BENT2)
1988             bent2_var=1;
1989          else if (j==VAR_BIPOLAR)
1990             bipolar_var=1;
1991          else if (j==VAR_CELL)
1992             cell_var=1;
1993          else if (j==VAR_CPOW)
1994             cpow_var=1;
1995          else if (j==VAR_CURVE)
1996             curve_var=1;
1997          else if (j==VAR_ESCHER)
1998             escher_var=1;
1999          else if (j==VAR_LAZYSUSAN)
2000             lazys_var=1;
2001          else if (j==VAR_MODULUS)
2002             modulus_var=1;
2003          else if (j==VAR_OSCILLOSCOPE)
2004             oscope_var=1;
2005          else if (j==VAR_POPCORN2)
2006             popcorn2_var=1;
2007          else if (j==VAR_SPLIT)
2008             split_var=1;
2009          else if (j==VAR_SPLITS)
2010             splits_var=1;
2011          else if (j==VAR_STRIPES)
2012             stripes_var=1;
2013          else if (j==VAR_WEDGE)
2014             wedge_var=1;
2015          else if (j==VAR_WEDGE_JULIA)
2016             wedgeJ_var=1;
2017          else if (j==VAR_WEDGE_SPH)
2018             wedgeS_var=1;
2019          else if (j==VAR_WHORL)
2020             whorl_var=1;
2021          else if (j==VAR_WAVES2)
2022             waves2_var=1;
2023          else if (j==VAR_AUGER)
2024             auger_var=1;
2025          else if (j==VAR_FLUX)
2026             flux_var=1;
2027          else if (j==VAR_MOBIUS)
2028             mobius_var=1;
2029       }
2030    }
2031 
2032    if (!motion_flag) {
2033       if (blob_var==1) {
2034          fprintf(f, "blob_low=\"%g\" ", x->blob_low);
2035          fprintf(f, "blob_high=\"%g\" ", x->blob_high);
2036          fprintf(f, "blob_waves=\"%g\" ", x->blob_waves);
2037       }
2038 
2039       if (pdj_var==1) {
2040          fprintf(f, "pdj_a=\"%g\" ", x->pdj_a);
2041          fprintf(f, "pdj_b=\"%g\" ", x->pdj_b);
2042          fprintf(f, "pdj_c=\"%g\" ", x->pdj_c);
2043          fprintf(f, "pdj_d=\"%g\" ", x->pdj_d);
2044       }
2045 
2046       if (fan2_var==1) {
2047          fprintf(f, "fan2_x=\"%g\" ", x->fan2_x);
2048          fprintf(f, "fan2_y=\"%g\" ", x->fan2_y);
2049       }
2050 
2051       if (rings2_var==1) {
2052          fprintf(f, "rings2_val=\"%g\" ", x->rings2_val);
2053       }
2054 
2055       if (perspective_var==1) {
2056          fprintf(f, "perspective_angle=\"%g\" ", x->perspective_angle);
2057          fprintf(f, "perspective_dist=\"%g\" ", x->perspective_dist);
2058       }
2059 
2060       if (juliaN_var==1) {
2061          fprintf(f, "julian_power=\"%g\" ", x->julian_power);
2062          fprintf(f, "julian_dist=\"%g\" ", x->julian_dist);
2063       }
2064 
2065       if (juliaScope_var==1) {
2066          fprintf(f, "juliascope_power=\"%g\" ", x->juliascope_power);
2067          fprintf(f, "juliascope_dist=\"%g\" ", x->juliascope_dist);
2068       }
2069 
2070       if (radialBlur_var==1) {
2071          fprintf(f, "radial_blur_angle=\"%g\" ", x->radial_blur_angle);
2072       }
2073 
2074       if (pie_var==1) {
2075          fprintf(f, "pie_slices=\"%g\" ", x->pie_slices);
2076          fprintf(f, "pie_rotation=\"%g\" ", x->pie_rotation);
2077          fprintf(f, "pie_thickness=\"%g\" ", x->pie_thickness);
2078       }
2079 
2080       if (ngon_var==1) {
2081          fprintf(f, "ngon_sides=\"%g\" ", x->ngon_sides);
2082          fprintf(f, "ngon_power=\"%g\" ", x->ngon_power);
2083          fprintf(f, "ngon_corners=\"%g\" ", x->ngon_corners);
2084          fprintf(f, "ngon_circle=\"%g\" ", x->ngon_circle);
2085       }
2086 
2087       if (curl_var==1) {
2088          fprintf(f, "curl_c1=\"%g\" ", x->curl_c1);
2089          fprintf(f, "curl_c2=\"%g\" ", x->curl_c2);
2090       }
2091 
2092       if (rectangles_var==1) {
2093          fprintf(f, "rectangles_x=\"%g\" ", x->rectangles_x);
2094          fprintf(f, "rectangles_y=\"%g\" ", x->rectangles_y);
2095       }
2096 
2097       if (disc2_var==1) {
2098          fprintf(f, "disc2_rot=\"%g\" ", x->disc2_rot);
2099          fprintf(f, "disc2_twist=\"%g\" ", x->disc2_twist);
2100       }
2101 
2102       if (supershape_var==1) {
2103          fprintf(f, "super_shape_rnd=\"%g\" ", x->super_shape_rnd);
2104          fprintf(f, "super_shape_m=\"%g\" ", x->super_shape_m);
2105          fprintf(f, "super_shape_n1=\"%g\" ", x->super_shape_n1);
2106          fprintf(f, "super_shape_n2=\"%g\" ", x->super_shape_n2);
2107          fprintf(f, "super_shape_n3=\"%g\" ", x->super_shape_n3);
2108          fprintf(f, "super_shape_holes=\"%g\" ", x->super_shape_holes);
2109       }
2110 
2111       if (flower_var==1) {
2112          fprintf(f, "flower_petals=\"%g\" ", x->flower_petals);
2113          fprintf(f, "flower_holes=\"%g\" ", x->flower_holes);
2114       }
2115 
2116       if (conic_var==1) {
2117          fprintf(f, "conic_eccentricity=\"%g\" ", x->conic_eccentricity);
2118          fprintf(f, "conic_holes=\"%g\" ", x->conic_holes);
2119       }
2120 
2121       if (parabola_var==1) {
2122          fprintf(f, "parabola_height=\"%g\" ", x->parabola_height);
2123          fprintf(f, "parabola_width=\"%g\" ", x->parabola_width);
2124       }
2125 
2126       if (bent2_var==1) {
2127          fprintf(f, "bent2_x=\"%g\" ", x->bent2_x);
2128          fprintf(f, "bent2_y=\"%g\" ", x->bent2_y);
2129       }
2130 
2131       if (bipolar_var==1) {
2132          fprintf(f, "bipolar_shift=\"%g\" ", x->bipolar_shift);
2133       }
2134 
2135       if (cell_var==1) {
2136          fprintf(f, "cell_size=\"%g\" ", x->cell_size);
2137       }
2138 
2139       if (cpow_var==1) {
2140          fprintf(f, "cpow_i=\"%g\" ", x->cpow_i);
2141          fprintf(f, "cpow_r=\"%g\" ", x->cpow_r);
2142          fprintf(f, "cpow_power=\"%g\" ", x->cpow_power);
2143       }
2144 
2145       if (curve_var==1) {
2146          fprintf(f, "curve_xamp=\"%g\" ", x->curve_xamp);
2147          fprintf(f, "curve_yamp=\"%g\" ", x->curve_yamp);
2148          fprintf(f, "curve_xlength=\"%g\" ", x->curve_xlength);
2149          fprintf(f, "curve_ylength=\"%g\" ", x->curve_ylength);
2150       }
2151 
2152       if (escher_var==1) {
2153          fprintf(f, "escher_beta=\"%g\" ", x->escher_beta);
2154       }
2155 
2156       if (lazys_var==1) {
2157          fprintf(f, "lazysusan_x=\"%g\" ", x->lazysusan_x);
2158          fprintf(f, "lazysusan_y=\"%g\" ", x->lazysusan_y);
2159          fprintf(f, "lazysusan_spin=\"%g\" ", x->lazysusan_spin);
2160          fprintf(f, "lazysusan_space=\"%g\" ", x->lazysusan_space);
2161          fprintf(f, "lazysusan_twist=\"%g\" ", x->lazysusan_twist);
2162       }
2163 
2164       if (modulus_var==1) {
2165          fprintf(f, "modulus_x=\"%g\" ", x->modulus_x);
2166          fprintf(f, "modulus_y=\"%g\" ", x->modulus_y);
2167       }
2168 
2169       if (oscope_var==1) {
2170          fprintf(f, "oscilloscope_separation=\"%g\" ", x->oscope_separation);
2171          fprintf(f, "oscilloscope_frequency=\"%g\" ", x->oscope_frequency);
2172          fprintf(f, "oscilloscope_amplitude=\"%g\" ", x->oscope_amplitude);
2173          fprintf(f, "oscilloscope_damping=\"%g\" ", x->oscope_damping);
2174       }
2175 
2176       if (popcorn2_var==1) {
2177          fprintf(f, "popcorn2_x=\"%g\" ", x->popcorn2_x);
2178          fprintf(f, "popcorn2_y=\"%g\" ", x->popcorn2_y);
2179          fprintf(f, "popcorn2_c=\"%g\" ", x->popcorn2_c);
2180       }
2181 
2182       if (separation_var==1) {
2183          fprintf(f, "separation_x=\"%g\" ", x->separation_x);
2184          fprintf(f, "separation_y=\"%g\" ", x->separation_y);
2185          fprintf(f, "separation_xinside=\"%g\" ", x->separation_xinside);
2186          fprintf(f, "separation_yinside=\"%g\" ", x->separation_yinside);
2187       }
2188 
2189       if (split_var==1) {
2190          fprintf(f, "split_xsize=\"%g\" ", x->split_xsize);
2191          fprintf(f, "split_ysize=\"%g\" ", x->split_ysize);
2192       }
2193 
2194       if (splits_var==1) {
2195          fprintf(f, "splits_x=\"%g\" ", x->splits_x);
2196          fprintf(f, "splits_y=\"%g\" ", x->splits_y);
2197       }
2198 
2199       if (stripes_var==1) {
2200          fprintf(f, "stripes_space=\"%g\" ", x->stripes_space);
2201          fprintf(f, "stripes_warp=\"%g\" ", x->stripes_warp);
2202       }
2203 
2204       if (wedge_var==1) {
2205          fprintf(f, "wedge_angle=\"%g\" ", x->wedge_angle);
2206          fprintf(f, "wedge_hole=\"%g\" ", x->wedge_hole);
2207          fprintf(f, "wedge_count=\"%g\" ", x->wedge_count);
2208          fprintf(f, "wedge_swirl=\"%g\" ", x->wedge_swirl);
2209       }
2210 
2211       if (wedgeJ_var==1) {
2212          fprintf(f, "wedge_julia_angle=\"%g\" ", x->wedge_julia_angle);
2213          fprintf(f, "wedge_julia_count=\"%g\" ", x->wedge_julia_count);
2214          fprintf(f, "wedge_julia_power=\"%g\" ", x->wedge_julia_power);
2215          fprintf(f, "wedge_julia_dist=\"%g\" ", x->wedge_julia_dist);
2216       }
2217 
2218       if (wedgeS_var==1) {
2219          fprintf(f, "wedge_sph_angle=\"%g\" ", x->wedge_sph_angle);
2220          fprintf(f, "wedge_sph_hole=\"%g\" ", x->wedge_sph_hole);
2221          fprintf(f, "wedge_sph_count=\"%g\" ", x->wedge_sph_count);
2222          fprintf(f, "wedge_sph_swirl=\"%g\" ", x->wedge_sph_swirl);
2223       }
2224 
2225       if (whorl_var==1) {
2226          fprintf(f, "whorl_inside=\"%g\" ", x->whorl_inside);
2227          fprintf(f, "whorl_outside=\"%g\" ", x->whorl_outside);
2228       }
2229 
2230       if (waves2_var==1) {
2231          fprintf(f, "waves2_scalex=\"%g\" ", x->waves2_scalex);
2232          fprintf(f, "waves2_scaley=\"%g\" ", x->waves2_scaley);
2233          fprintf(f, "waves2_freqx=\"%g\" ", x->waves2_freqx);
2234          fprintf(f, "waves2_freqy=\"%g\" ", x->waves2_freqy);
2235       }
2236 
2237       if (auger_var==1) {
2238          fprintf(f, "auger_sym=\"%g\" ", x->auger_sym);
2239          fprintf(f, "auger_weight=\"%g\" ", x->auger_weight);
2240          fprintf(f, "auger_freq=\"%g\" ", x->auger_freq);
2241          fprintf(f, "auger_scale=\"%g\" ", x->auger_scale);
2242       }
2243 
2244       if (flux_var==1)
2245          fprintf(f, "flux_spread=\"%g\" ", x->flux_spread);
2246 
2247       if (mobius_var==1) {
2248          fprintf(f, "mobius_re_a=\"%g\" ", x->mobius_re_a);
2249          fprintf(f, "mobius_im_a=\"%g\" ", x->mobius_im_a);
2250          fprintf(f, "mobius_re_b=\"%g\" ", x->mobius_re_b);
2251          fprintf(f, "mobius_im_b=\"%g\" ", x->mobius_im_b);
2252          fprintf(f, "mobius_re_c=\"%g\" ", x->mobius_re_c);
2253          fprintf(f, "mobius_im_c=\"%g\" ", x->mobius_im_c);
2254          fprintf(f, "mobius_re_d=\"%g\" ", x->mobius_re_d);
2255          fprintf(f, "mobius_im_d=\"%g\" ", x->mobius_im_d);
2256       }
2257 
2258       fprintf(f, "coefs=\"");
2259       for (j = 0; j < 3; j++) {
2260          if (j) fprintf(f, " ");
2261          fprintf(f, "%g %g", x->c[j][0], x->c[j][1]);
2262       }
2263       fprintf(f, "\"");
2264 
2265       if (!id_matrix(x->post)) {
2266          fprintf(f, " post=\"");
2267          for (j = 0; j < 3; j++) {
2268             if (j) fprintf(f, " ");
2269             fprintf(f, "%g %g", x->post[j][0], x->post[j][1]);
2270          }
2271          fprintf(f, "\"");
2272       }
2273 
2274 
2275    } else {
2276       /* For motion, print any parameter if it's nonzero */
2277       PRINTNON(blob_low);
2278       PRINTNON(blob_high);
2279       PRINTNON(blob_waves);
2280 
2281       PRINTNON(pdj_a);
2282       PRINTNON(pdj_b);
2283       PRINTNON(pdj_c);
2284       PRINTNON(pdj_d);
2285 
2286       PRINTNON(fan2_x);
2287       PRINTNON(fan2_y);
2288 
2289       PRINTNON(rings2_val);
2290 
2291       PRINTNON(perspective_angle);
2292       PRINTNON(perspective_dist);
2293 
2294       PRINTNON(julian_power);
2295       PRINTNON(julian_dist);
2296 
2297       PRINTNON(juliascope_power);
2298       PRINTNON(juliascope_dist);
2299 
2300       PRINTNON(radial_blur_angle);
2301 
2302       PRINTNON(pie_slices);
2303       PRINTNON(pie_rotation);
2304       PRINTNON(pie_thickness);
2305 
2306       PRINTNON(ngon_sides);
2307       PRINTNON(ngon_power);
2308       PRINTNON(ngon_corners);
2309       PRINTNON(ngon_circle);
2310 
2311       PRINTNON(curl_c1);
2312       PRINTNON(curl_c2);
2313 
2314       PRINTNON(rectangles_x);
2315       PRINTNON(rectangles_y);
2316 
2317       PRINTNON(disc2_rot);
2318       PRINTNON(disc2_twist);
2319 
2320       PRINTNON(super_shape_rnd);
2321       PRINTNON(super_shape_m);
2322       PRINTNON(super_shape_n1);
2323       PRINTNON(super_shape_n2);
2324       PRINTNON(super_shape_n3);
2325       PRINTNON(super_shape_holes);
2326 
2327       PRINTNON(flower_petals);
2328       PRINTNON(flower_holes);
2329 
2330       PRINTNON(conic_eccentricity);
2331       PRINTNON(conic_holes);
2332 
2333       PRINTNON(parabola_height);
2334       PRINTNON(parabola_width);
2335 
2336       PRINTNON(bent2_x);
2337       PRINTNON(bent2_y);
2338 
2339       PRINTNON(bipolar_shift);
2340 
2341       PRINTNON(cell_size);
2342 
2343       PRINTNON(cpow_i);
2344       PRINTNON(cpow_r);
2345       PRINTNON(cpow_power);
2346 
2347       PRINTNON(curve_xamp);
2348       PRINTNON(curve_yamp);
2349       PRINTNON(curve_xlength);
2350       PRINTNON(curve_ylength);
2351 
2352       PRINTNON(escher_beta);
2353 
2354       PRINTNON(lazysusan_x);
2355       PRINTNON(lazysusan_y);
2356       PRINTNON(lazysusan_spin);
2357       PRINTNON(lazysusan_space);
2358       PRINTNON(lazysusan_twist);
2359 
2360       PRINTNON(modulus_x);
2361       PRINTNON(modulus_y);
2362 
2363       PRINTNON(oscope_separation);
2364       PRINTNON(oscope_frequency);
2365       PRINTNON(oscope_amplitude);
2366       PRINTNON(oscope_damping);
2367 
2368       PRINTNON(popcorn2_x);
2369       PRINTNON(popcorn2_y);
2370       PRINTNON(popcorn2_c);
2371 
2372       PRINTNON(separation_x);
2373       PRINTNON(separation_y);
2374       PRINTNON(separation_xinside);
2375       PRINTNON(separation_yinside);
2376 
2377       PRINTNON(split_xsize);
2378       PRINTNON(split_ysize);
2379 
2380       PRINTNON(splits_x);
2381       PRINTNON(splits_y);
2382 
2383       PRINTNON(stripes_space);
2384       PRINTNON(stripes_warp);
2385 
2386       PRINTNON(wedge_angle);
2387       PRINTNON(wedge_hole);
2388       PRINTNON(wedge_count);
2389       PRINTNON(wedge_swirl);
2390 
2391       PRINTNON(wedge_julia_angle);
2392       PRINTNON(wedge_julia_count);
2393       PRINTNON(wedge_julia_power);
2394       PRINTNON(wedge_julia_dist);
2395 
2396       PRINTNON(wedge_sph_angle);
2397       PRINTNON(wedge_sph_hole);
2398       PRINTNON(wedge_sph_count);
2399       PRINTNON(wedge_sph_swirl);
2400 
2401       PRINTNON(whorl_inside);
2402       PRINTNON(whorl_outside);
2403 
2404       PRINTNON(waves2_scalex);
2405       PRINTNON(waves2_scaley);
2406       PRINTNON(waves2_freqx);
2407       PRINTNON(waves2_freqy);
2408 
2409       PRINTNON(auger_sym);
2410       PRINTNON(auger_weight);
2411       PRINTNON(auger_freq);
2412       PRINTNON(auger_scale);
2413 
2414       PRINTNON(flux_spread);
2415 
2416       PRINTNON(mobius_re_a);
2417       PRINTNON(mobius_im_a);
2418       PRINTNON(mobius_re_b);
2419       PRINTNON(mobius_im_b);
2420       PRINTNON(mobius_re_c);
2421       PRINTNON(mobius_im_c);
2422       PRINTNON(mobius_re_d);
2423       PRINTNON(mobius_im_d);
2424 
2425       if (!zero_matrix(x->c)) {
2426          fprintf(f, "coefs=\"");
2427          for (j = 0; j < 3; j++) {
2428             if (j) fprintf(f, " ");
2429             fprintf(f, "%g %g", x->c[j][0], x->c[j][1]);
2430          }
2431          fprintf(f, "\"");
2432       }
2433 
2434       if (!zero_matrix(x->post)) {
2435          fprintf(f, " post=\"");
2436          for (j = 0; j < 3; j++) {
2437             if (j) fprintf(f, " ");
2438             fprintf(f, "%g %g", x->post[j][0], x->post[j][1]);
2439          }
2440          fprintf(f, "\"");
2441       }
2442    }
2443 
2444    if (!final_flag && !motion_flag && !flam27_flag) {
2445 
2446       /* Print out the chaos row for this xform */
2447       int numcols = numstd;
2448 
2449       while (numcols > 0 && chaos_row[numcols-1]==1.0)
2450          numcols--;
2451 
2452       if (numcols>0) {
2453          fprintf(f, " chaos=\"");
2454          for (j=0;j<numcols;j++)
2455             fprintf(f, "%g ",chaos_row[j]);
2456          fprintf(f, "\"");
2457       }
2458 
2459 
2460    }
2461 
2462    if (!flam27_flag && !motion_flag) {
2463       fprintf(f, " opacity=\"%g\"",x->opacity);
2464    }
2465 
2466    if (!motion_flag && x->num_motion>0 && !flam27_flag) {
2467       int nm;
2468 
2469       fprintf(f,">\n");
2470 
2471       for (nm=0; nm<x->num_motion; nm++)
2472          flam3_print_xform(f, &(x->motion[nm]), 0, 0, NULL, 1);
2473 
2474       if (final_flag)
2475          fprintf(f,"   </finalxform>\n");
2476       else
2477          fprintf(f,"   </xform>\n");
2478 
2479    } else
2480       fprintf(f, "/>\n");
2481 }
2482 
2483 
2484 /* returns a uniform variable from 0 to 1 */
flam3_random01()2485 double flam3_random01() {
2486    return (random() & 0xfffffff) / (double) 0xfffffff;
2487 }
2488 
flam3_random11()2489 double flam3_random11() {
2490    return ((random() & 0xfffffff) - 0x7ffffff) / (double) 0x7ffffff;
2491 }
2492 
2493 /* This function must be called prior to rendering a frame */
flam3_init_frame(flam3_frame * f)2494 void flam3_init_frame(flam3_frame *f) {
2495 
2496    char *ai;
2497    char *isaac_seed = args("isaac_seed",NULL);
2498    long int default_isaac_seed = (long int)time(0);
2499 
2500    /* Clear out the isaac state */
2501    memset(f->rc.randrsl, 0, RANDSIZ*sizeof(ub4));
2502 
2503    /* Set the isaac seed */
2504    if (NULL == isaac_seed) {
2505       int lp;
2506       /* No isaac seed specified.  Use the system time to initialize. */
2507       for (lp = 0; lp < RANDSIZ; lp++)
2508          f->rc.randrsl[lp] = default_isaac_seed;
2509    } else {
2510       /* Use the specified string */
2511       strncpy((char *)&f->rc.randrsl,(const char *)isaac_seed, RANDSIZ*sizeof(ub4));
2512    }
2513 
2514    /* Initialize the random number generator */
2515    irandinit(&f->rc,1);
2516 }
2517 
2518 /* returns uniform variable from ISAAC rng */
flam3_random_isaac_01(randctx * ct)2519 double flam3_random_isaac_01(randctx *ct) {
2520    return ((int)irand(ct) & 0xfffffff) / (double) 0xfffffff;
2521 }
2522 
flam3_random_isaac_11(randctx * ct)2523 double flam3_random_isaac_11(randctx *ct) {
2524    return (((int)irand(ct) & 0xfffffff) - 0x7ffffff) / (double) 0x7ffffff;
2525 }
2526 
flam3_random_bit()2527 int flam3_random_bit() {
2528   /* might not be threadsafe */
2529   static int n = 0;
2530   static int l;
2531   if (0 == n) {
2532     l = random();
2533     n = 20;
2534   } else {
2535     l = l >> 1;
2536     n--;
2537   }
2538   return l & 1;
2539 }
2540 
flam3_random_isaac_bit(randctx * ct)2541 int flam3_random_isaac_bit(randctx *ct) {
2542    int tmp = irand(ct);
2543    return tmp & 1;
2544 }
2545 
round6(double x)2546 static double round6(double x) {
2547   x *= 1e6;
2548   if (x < 0) x -= 1.0;
2549   return 1e-6*(int)(x+0.5);
2550 }
2551 
2552 /* sym=2 or more means rotational
2553    sym=1 means identity, ie no symmetry
2554    sym=0 means pick a random symmetry (maybe none)
2555    sym=-1 means bilateral (reflection)
2556    sym=-2 or less means rotational and reflective
2557 */
flam3_add_symmetry(flam3_genome * cp,int sym)2558 void flam3_add_symmetry(flam3_genome *cp, int sym) {
2559    int i, j, k;
2560    double a;
2561    int result = 0;
2562 
2563    if (0 == sym) {
2564       static int sym_distrib[] = {
2565          -4, -3,
2566          -2, -2, -2,
2567          -1, -1, -1,
2568          2, 2, 2,
2569          3, 3,
2570          4, 4,
2571       };
2572       if (random()&1) {
2573          sym = random_distrib(sym_distrib);
2574       } else if (random()&31) {
2575          sym = (random()%13)-6;
2576       } else {
2577          sym = (random()%51)-25;
2578       }
2579    }
2580 
2581    if (1 == sym || 0 == sym) return;
2582 
2583    cp->symmetry = sym;
2584 
2585    if (sym < 0) {
2586 
2587       i = cp->num_xforms;
2588       if (cp->final_xform_enable)
2589          i -= 1;
2590 
2591       flam3_add_xforms(cp,1,0,0);
2592 
2593       cp->xform[i].density = 1.0;
2594       cp->xform[i].color_speed = 0.0;
2595       cp->xform[i].animate = 0.0;
2596       cp->xform[i].var[0] = 1.0;
2597       for (j = 1; j < flam3_nvariations; j++)
2598          cp->xform[i].var[j] = 0;
2599       cp->xform[i].color = 1.0;
2600       cp->xform[i].c[0][0] = -1.0;
2601       cp->xform[i].c[0][1] = 0.0;
2602       cp->xform[i].c[1][0] = 0.0;
2603       cp->xform[i].c[1][1] = 1.0;
2604       cp->xform[i].c[2][0] = 0.0;
2605       cp->xform[i].c[2][1] = 0.0;
2606 
2607       result++;
2608       sym = -sym;
2609    }
2610 
2611    a = 2*M_PI/sym;
2612 
2613    for (k = 1; k < sym; k++) {
2614 
2615       i = cp->num_xforms;
2616       if (cp->final_xform_enable)
2617          i -= 1;
2618 
2619       flam3_add_xforms(cp, 1, 0,0);
2620 
2621       cp->xform[i].density = 1.0;
2622       cp->xform[i].color_speed = 0.0;
2623       cp->xform[i].animate = 0.0;
2624       cp->xform[i].var[0] = 1.0;
2625       for (j = 1; j < flam3_nvariations; j++)
2626          cp->xform[i].var[j] = 0;
2627       cp->xform[i].color = (sym<3) ? 0.0 : ((k-1.0)/(sym-2.0));
2628       cp->xform[i].c[0][0] = round6(cos(k*a));
2629       cp->xform[i].c[0][1] = round6(sin(k*a));
2630       cp->xform[i].c[1][0] = round6(-cp->xform[i].c[0][1]);
2631       cp->xform[i].c[1][1] = cp->xform[i].c[0][0];
2632       cp->xform[i].c[2][0] = 0.0;
2633       cp->xform[i].c[2][1] = 0.0;
2634 
2635       result++;
2636    }
2637 
2638    qsort((char *) &cp->xform[cp->num_xforms-result], result,
2639       sizeof(flam3_xform), compare_xforms);
2640 
2641 }
2642 
add_to_action(char * action,char * addtoaction)2643 void add_to_action(char *action, char *addtoaction) {
2644 
2645    /* action is a flam3_max_action_length array */
2646    if (action != NULL) {
2647 
2648       int alen = strlen(action);
2649       int addlen = strlen(addtoaction);
2650 
2651       if (alen+addlen < flam3_max_action_length)
2652          strcat(action,addtoaction);
2653       else
2654          fprintf(stderr,"action string too long, truncating...\n");
2655    }
2656 }
2657 
2658 
flam3_cross(flam3_genome * cp0,flam3_genome * cp1,flam3_genome * out,int cross_mode,randctx * rc,char * action)2659 void flam3_cross(flam3_genome *cp0, flam3_genome *cp1, flam3_genome *out, int cross_mode, randctx *rc, char *action) {
2660 
2661    int i,j, rb;
2662    char ministr[10];
2663 
2664    if (cross_mode == CROSS_NOT_SPECIFIED) {
2665 
2666       double s = flam3_random_isaac_01(rc);
2667 
2668       if (s < 0.1)
2669          cross_mode = CROSS_UNION;
2670       else if (s < 0.2)
2671          cross_mode = CROSS_INTERPOLATE;
2672       else
2673          cross_mode = CROSS_ALTERNATE;
2674 
2675    }
2676 
2677    if (cross_mode == CROSS_UNION) {
2678 
2679       flam3_xform mycopy;
2680 
2681       /* Make a copy of cp0 */
2682       flam3_copy(out, cp0);
2683 
2684       for (j=0;j<cp1->num_xforms;j++) {
2685          /* Skip over the final xform, if it's present.    */
2686          /* Default behavior keeps the final from parent0. */
2687          if (cp1->final_xform_index == j)
2688             continue;
2689 
2690          i = out->num_xforms;
2691          if (out->final_xform_enable)
2692             i -= 1;
2693 
2694          flam3_add_xforms(out, 1, 0, 0);
2695          flam3_copy_xform(&out->xform[i],&cp1->xform[j]);
2696       }
2697 
2698       /* Put the final xform last (if there is one) */
2699       /* We do not need to do complicated xform copies here since we're just moving them around */
2700       if (out->final_xform_index >= 0) {
2701          mycopy = out->xform[out->final_xform_index];
2702          out->xform[out->final_xform_index] = out->xform[out->num_xforms-1];
2703          out->xform[out->num_xforms-1] = mycopy;
2704          out->final_xform_index = out->num_xforms-1;
2705       }
2706 
2707       add_to_action(action,"cross union");
2708 
2709    } else if (cross_mode == CROSS_INTERPOLATE) {
2710 
2711       /* linearly interpolate somewhere between the two */
2712       flam3_genome parents[2];
2713       double t = flam3_random_isaac_01(rc);
2714 
2715       memset(parents, 0, 2*sizeof(flam3_genome));
2716 
2717       flam3_copy(&(parents[0]), cp0);
2718       flam3_copy(&(parents[1]), cp1);
2719 
2720       parents[0].time = 0.0;
2721       parents[1].time = 1.0;
2722       flam3_interpolate(parents, 2, t, 0, out);
2723 
2724       for (i=0;i<out->num_xforms;i++)
2725          flam3_delete_motion_elements(&out->xform[i]);
2726 
2727       clear_cp(&parents[0],flam3_defaults_on);
2728       clear_cp(&parents[1],flam3_defaults_on);
2729 
2730       sprintf(ministr,"%7.5g",t);
2731 
2732       add_to_action(action,"cross interpolate ");
2733       add_to_action(action,ministr);
2734 
2735    } else {
2736 
2737       /* alternate mode */
2738       int got0, got1, used_parent;
2739       char *trystr;
2740 
2741       trystr = calloc(4 * (cp0->num_xforms + cp1->num_xforms), sizeof(char));
2742 
2743       /* each xform comes from a random parent, possible for an entire parent to be excluded */
2744       do {
2745 
2746          trystr[0] = 0;
2747          got0 = got1 = 0;
2748          rb = flam3_random_isaac_bit(rc);
2749          sprintf(ministr,"%d:",rb);
2750          strcat(trystr,ministr);
2751 
2752          /* Copy the parent, sorting the final xform to the end if it's present. */
2753          if (rb)
2754             flam3_copyx(out, cp1, cp1->num_xforms - (cp1->final_xform_index > 0), cp1->final_xform_enable);
2755          else
2756             flam3_copyx(out, cp0, cp0->num_xforms - (cp0->final_xform_index > 0), cp0->final_xform_enable);
2757 
2758          used_parent = rb;
2759 
2760          /* Only replace non-final xforms */
2761 
2762          for (i = 0; i < out->num_xforms - out->final_xform_enable; i++) {
2763             rb = flam3_random_isaac_bit(rc);
2764 
2765             /* Replace xform if bit is 1 */
2766             if (rb==1) {
2767                if (used_parent==0) {
2768                   if (i < cp1->num_xforms && cp1->xform[i].density > 0) {
2769                      flam3_copy_xform(&out->xform[i],&cp1->xform[i]);
2770                      sprintf(ministr," 1");
2771                      got1 = 1;
2772                   } else {
2773                      sprintf(ministr," 0");
2774                      got0 = 1;
2775                   }
2776                } else {
2777                   if (i < cp0->num_xforms && cp0->xform[i].density > 0) {
2778                      flam3_copy_xform(&out->xform[i],&cp0->xform[i]);
2779                      sprintf(ministr," 0");
2780                      got0 = 1;
2781                   } else {
2782                      sprintf(ministr," 1");
2783                      got1 = 1;
2784                   }
2785                }
2786             } else {
2787                sprintf(ministr," %d",used_parent);
2788                if (used_parent)
2789                   got1 = 1;
2790                else
2791                   got0 = 1;
2792             }
2793 
2794             strcat(trystr,ministr);
2795          }
2796 
2797          if (used_parent==0 && cp0->final_xform_enable)
2798             got0 = 1;
2799          else if (used_parent==1 && cp1->final_xform_enable)
2800             got1 = 1;
2801 
2802       } while ((i > 1) && !(got0 && got1));
2803 
2804       add_to_action(action,"cross alternate ");
2805       add_to_action(action,trystr);
2806 
2807       free(trystr);
2808    }
2809 
2810    /* reset color coords */
2811    for (i = 0; i < out->num_xforms; i++) {
2812       out->xform[i].color = i&1;
2813    }
2814 
2815    /* Potentially genetically cross the two colormaps together */
2816    if (flam3_random_isaac_01(rc) < 0.4) {
2817 
2818       /* Select the starting parent */
2819       int startParent=flam3_random_isaac_bit(rc);
2820       int ci;
2821 
2822       add_to_action(action," cmap_cross");
2823       sprintf(ministr," %d:",startParent);
2824       add_to_action(action,ministr);
2825 
2826       /* Loop over the entries, switching to the other parent 1% of the time */
2827       for (ci=0;ci<256;ci++) {
2828          if (flam3_random_isaac_01(rc)<.01) {
2829             startParent = 1-startParent;
2830             sprintf(ministr," %d",ci);
2831             add_to_action(action,ministr);
2832          }
2833 
2834          out->palette[ci] = startParent ? cp1->palette[ci]: cp0->palette[ci];
2835       }
2836    }
2837 
2838 }
2839 
flam3_mutate(flam3_genome * cp,int mutate_mode,int * ivars,int ivars_n,int sym,double speed,randctx * rc,char * action)2840 void flam3_mutate(flam3_genome *cp, int mutate_mode, int *ivars, int ivars_n, int sym, double speed, randctx *rc, char *action) {
2841 
2842    double randselect;
2843    flam3_genome mutation;
2844    int i,j,done;
2845    char ministr[30];
2846 
2847    /* If mutate_mode = -1, choose a random mutation mode */
2848    if (mutate_mode == MUTATE_NOT_SPECIFIED) {
2849 
2850       randselect = flam3_random_isaac_01(rc);
2851 
2852       if (randselect < 0.1)
2853          mutate_mode = MUTATE_ALL_VARIATIONS;
2854       else if (randselect < 0.3)
2855          mutate_mode = MUTATE_ONE_XFORM_COEFS;
2856       else if (randselect < 0.5)
2857          mutate_mode = MUTATE_ADD_SYMMETRY;
2858       else if (randselect < 0.6)
2859          mutate_mode = MUTATE_POST_XFORMS;
2860       else if (randselect < 0.7)
2861          mutate_mode = MUTATE_COLOR_PALETTE;
2862       else if (randselect < 0.8)
2863          mutate_mode = MUTATE_DELETE_XFORM;
2864       else
2865          mutate_mode = MUTATE_ALL_COEFS;
2866 
2867    }
2868 
2869    memset(&mutation, 0, sizeof(flam3_genome));
2870 
2871    if (mutate_mode == MUTATE_ALL_VARIATIONS) {
2872 
2873       add_to_action(action,"mutate all variations");
2874 
2875       do {
2876          /* Create a random flame, and use the variations */
2877          /* to replace those in the original              */
2878          flam3_random(&mutation, ivars, ivars_n, sym, cp->num_xforms);
2879          for (i = 0; i < cp->num_xforms; i++) {
2880             for (j = 0; j < flam3_nvariations; j++) {
2881                if (cp->xform[i].var[j] != mutation.xform[i].var[j]) {
2882 
2883                   /* Copy the new var weights */
2884                   cp->xform[i].var[j] = mutation.xform[i].var[j];
2885 
2886                   /* Copy parameters for this variation only */
2887                   flam3_copy_params(&(cp->xform[i]),&(mutation.xform[i]),j);
2888 
2889                   done = 1;
2890                }
2891             }
2892          }
2893       } while (!done);
2894 
2895    } else if (mutate_mode == MUTATE_ONE_XFORM_COEFS) {
2896 
2897       int modxf;
2898 
2899       /* Generate a 2-xform random */
2900       flam3_random(&mutation, ivars, ivars_n, sym, 2);
2901 
2902       /* Which xform do we mutate? */
2903       modxf = ((unsigned)irand(rc)) % cp->num_xforms;
2904 
2905       add_to_action(action,"mutate xform ");
2906       sprintf(ministr,"%d coefs",modxf);
2907       add_to_action(action,ministr);
2908 
2909       /* if less than 3 xforms, then change only the translation part */
2910       if (2 >= cp->num_xforms) {
2911          for (j = 0; j < 2; j++)
2912             cp->xform[modxf].c[2][j] = mutation.xform[0].c[2][j];
2913       } else {
2914          for (i = 0; i < 3; i++)
2915             for (j = 0; j < 2; j++)
2916                cp->xform[modxf].c[i][j] = mutation.xform[0].c[i][j];
2917       }
2918 
2919    } else if (mutate_mode == MUTATE_ADD_SYMMETRY) {
2920 
2921       add_to_action(action,"mutate symmetry");
2922       flam3_add_symmetry(cp, 0);
2923 
2924    } else if (mutate_mode == MUTATE_POST_XFORMS) {
2925 
2926       int b = 1 + ((unsigned)irand(rc))%6;
2927       int same = ((unsigned)irand(rc))&3; /* 25% chance of using the same post for all of them */
2928 
2929       sprintf(ministr,"(%d%s)",b,(same>0) ? " same" : "");
2930       add_to_action(action,"mutate post xforms ");
2931       add_to_action(action,ministr);
2932       for (i = 0; i < cp->num_xforms; i++) {
2933          int copy = (i > 0) && same;
2934 
2935          if (copy) { /* Copy the post from the first xform to the rest of them */
2936             for (j = 0; j < 3; j++) {
2937                cp->xform[i].post[j][0] = cp->xform[0].post[j][0];
2938                cp->xform[i].post[j][1] = cp->xform[0].post[j][1];
2939             }
2940 
2941          } else {
2942 
2943             if (b&1) { /* 50% chance */
2944 
2945                double f = M_PI * flam3_random_isaac_11(rc);
2946                double t[2][2];
2947 
2948                t[0][0] = (cp->xform[i].c[0][0] * cos(f) + cp->xform[i].c[0][1] * -sin(f));
2949                t[0][1] = (cp->xform[i].c[0][0] * sin(f) + cp->xform[i].c[0][1] * cos(f));
2950                t[1][0] = (cp->xform[i].c[1][0] * cos(f) + cp->xform[i].c[1][1] * -sin(f));
2951                t[1][1] = (cp->xform[i].c[1][0] * sin(f) + cp->xform[i].c[1][1] * cos(f));
2952 
2953                cp->xform[i].c[0][0] = t[0][0];
2954                cp->xform[i].c[0][1] = t[0][1];
2955                cp->xform[i].c[1][0] = t[1][0];
2956                cp->xform[i].c[1][1] = t[1][1];
2957 
2958                f *= -1.0;
2959 
2960                t[0][0] = (cp->xform[i].post[0][0] * cos(f) + cp->xform[i].post[0][1] * -sin(f));
2961                t[0][1] = (cp->xform[i].post[0][0] * sin(f) + cp->xform[i].post[0][1] * cos(f));
2962                t[1][0] = (cp->xform[i].post[1][0] * cos(f) + cp->xform[i].post[1][1] * -sin(f));
2963                t[1][1] = (cp->xform[i].post[1][0] * sin(f) + cp->xform[i].post[1][1] * cos(f));
2964 
2965                cp->xform[i].post[0][0] = t[0][0];
2966                cp->xform[i].post[0][1] = t[0][1];
2967                cp->xform[i].post[1][0] = t[1][0];
2968                cp->xform[i].post[1][1] = t[1][1];
2969 
2970             }
2971 
2972             if (b&2) { /* 33% chance */
2973 
2974                double f = 0.2 + flam3_random_isaac_01(rc);
2975                double g = 0.2 + flam3_random_isaac_01(rc);
2976 
2977                if (flam3_random_isaac_bit(rc))
2978                   f = 1.0 / f;
2979 
2980                if (flam3_random_isaac_bit(rc))
2981                   g = f;
2982                else {
2983                   if (flam3_random_isaac_bit(rc))
2984                      g = 1.0 / g;
2985                }
2986 
2987                cp->xform[i].c[0][0] /= f;
2988                cp->xform[i].c[0][1] /= f;
2989                cp->xform[i].c[1][1] /= g;
2990                cp->xform[i].c[1][0] /= g;
2991                cp->xform[i].post[0][0] *= f;
2992                cp->xform[i].post[1][0] *= f;
2993                cp->xform[i].post[0][1] *= g;
2994                cp->xform[i].post[1][1] *= g;
2995             }
2996 
2997             if (b&4) { /* 16% chance */
2998 
2999                double f = flam3_random_isaac_11(rc);
3000                double g = flam3_random_isaac_11(rc);
3001 
3002                cp->xform[i].c[2][0] -= f;
3003                cp->xform[i].c[2][1] -= g;
3004                cp->xform[i].post[2][0] += f;
3005                cp->xform[i].post[2][1] += g;
3006             }
3007          }
3008       }
3009    } else if (mutate_mode == MUTATE_COLOR_PALETTE) {
3010 
3011       double s = flam3_random_isaac_01(rc);
3012 
3013       if (s < 0.4) { /* randomize xform color coords */
3014 
3015          flam3_improve_colors(cp, 100, 0, 10);
3016          add_to_action(action,"mutate color coords");
3017 
3018       } else if (s < 0.8) { /* randomize xform color coords and palette */
3019 
3020          flam3_improve_colors(cp, 25, 1, 10);
3021          add_to_action(action,"mutate color all");
3022 
3023       } else { /* randomize palette only */
3024 
3025          cp->palette_index = flam3_get_palette(flam3_palette_random, cp->palette, cp->hue_rotation);
3026          /* if our palette retrieval fails, skip the mutation */
3027          if (cp->palette_index >= 0)
3028             add_to_action(action,"mutate color palette");
3029          else
3030             fprintf(stderr,"failure getting random palette, palette set to white\n");
3031 
3032       }
3033    } else if (mutate_mode == MUTATE_DELETE_XFORM) {
3034 
3035       int nx = ((unsigned)irand(rc))%cp->num_xforms;
3036       sprintf(ministr,"%d",nx);
3037       add_to_action(action,"mutate delete xform ");
3038       add_to_action(action,ministr);
3039 
3040       if (cp->num_xforms > 1)
3041          flam3_delete_xform(cp,nx);
3042 
3043    } else { /* MUTATE_ALL_COEFS */
3044 
3045       int x;
3046       add_to_action(action,"mutate all coefs");
3047       flam3_random(&mutation, ivars, ivars_n, sym, cp->num_xforms);
3048 
3049       /* change all the coefs by a fraction of the random */
3050       for (x = 0; x < cp->num_xforms; x++) {
3051          for (i = 0; i < 3; i++) {
3052             for (j = 0; j < 2; j++) {
3053                cp->xform[x].c[i][j] += speed * mutation.xform[x].c[i][j];
3054 
3055             }
3056          }
3057          /* Eventually, we can mutate the parametric variation coefs here. */
3058       }
3059    }
3060 
3061    clear_cp(&mutation,flam3_defaults_on);
3062 
3063 }
3064 
random_var()3065 static int random_var() {
3066   return random() % flam3_nvariations;
3067 }
3068 
random_varn(int n)3069 static int random_varn(int n) {
3070    return random() % n;
3071 }
3072 
flam3_random(flam3_genome * cp,int * ivars,int ivars_n,int sym,int spec_xforms)3073 void flam3_random(flam3_genome *cp, int *ivars, int ivars_n, int sym, int spec_xforms) {
3074 
3075    int i, nxforms, var, samed, multid, samepost, postid, addfinal=0;
3076    int finum = -1;
3077    int n;
3078    char *ai;
3079    int f27 = argi("flam27",0);
3080    int mvar = f27 ? 54 : flam3_nvariations;
3081    double sum;
3082 
3083    static int xform_distrib[] = {
3084      2, 2, 2, 2,
3085      3, 3, 3, 3,
3086      4, 4, 4,
3087      5, 5,
3088      6
3089    };
3090 
3091    clear_cp(cp,flam3_defaults_on);
3092 
3093    cp->hue_rotation = (random()&7) ? 0.0 : flam3_random01();
3094    cp->palette_index = flam3_get_palette(flam3_palette_random, cp->palette, cp->hue_rotation);
3095    if (cp->palette_index < 0)
3096       fprintf(stderr,"error getting palette from xml file, setting to all white\n");
3097    cp->time = 0.0;
3098    cp->interpolation = flam3_interpolation_linear;
3099    cp->palette_interpolation = flam3_palette_interpolation_hsv_circular;
3100    cp->hsv_rgb_palette_blend = 0.0;
3101 
3102    /* Choose the number of xforms */
3103    if (spec_xforms>0) {
3104       nxforms = spec_xforms;
3105       flam3_add_xforms(cp,nxforms,0,0);
3106    } else {
3107       nxforms = random_distrib(xform_distrib);
3108       flam3_add_xforms(cp,nxforms,0,0);
3109       /* Add a final xform 15% of the time */
3110       addfinal = flam3_random01() < 0.15;
3111       if (addfinal) {
3112          flam3_add_xforms(cp,1,0,1);
3113          nxforms = nxforms + addfinal;
3114          finum = nxforms-1;
3115       }
3116    }
3117 
3118    /* If first input variation is 'flam3_variation_random' */
3119    /* choose one to use or decide to use multiple    */
3120    if (flam3_variation_random == ivars[0]) {
3121       if (flam3_random_bit()) {
3122          var = random_varn(mvar);
3123       } else {
3124          var = flam3_variation_random;
3125       }
3126    } else {
3127       var = flam3_variation_random_fromspecified;
3128    }
3129 
3130    samed = flam3_random_bit();
3131    multid = flam3_random_bit();
3132    postid = flam3_random01() < 0.6;
3133    samepost = flam3_random_bit();
3134 
3135    /* Loop over xforms */
3136    for (i = 0; i < nxforms; i++) {
3137       int j, k;
3138       cp->xform[i].density = 1.0 / nxforms;
3139       cp->xform[i].color = i&1;
3140       cp->xform[i].color_speed = 0.5;
3141       cp->xform[i].animate = 1.0;
3142       for (j = 0; j < 3; j++) {
3143          for (k = 0; k < 2; k++) {
3144             cp->xform[i].c[j][k] = flam3_random11();
3145             cp->xform[i].post[j][k] = (double)(k==j);
3146          }
3147       }
3148 
3149       if ( i != finum ) {
3150 
3151          if (!postid) {
3152 
3153             for (j = 0; j < 3; j++)
3154             for (k = 0; k < 2; k++) {
3155                if (samepost || (i==0))
3156                   cp->xform[i].post[j][k] = flam3_random11();
3157                else
3158                   cp->xform[i].post[j][k] = cp->xform[0].post[j][k];
3159             }
3160          }
3161 
3162          /* Clear all variation coefs */
3163          for (j = 0; j < flam3_nvariations; j++)
3164             cp->xform[i].var[j] = 0.0;
3165 
3166          if (flam3_variation_random != var &&
3167                flam3_variation_random_fromspecified != var) {
3168 
3169             /* Use only one variation specified for all xforms */
3170             cp->xform[i].var[var] = 1.0;
3171 
3172          } else if (multid && flam3_variation_random == var) {
3173 
3174            /* Choose a random var for this xform */
3175              cp->xform[i].var[random_varn(mvar)] = 1.0;
3176 
3177          } else {
3178 
3179             if (samed && i > 0) {
3180 
3181                /* Copy the same variations from the previous xform */
3182                for (j = 0; j < flam3_nvariations; j++) {
3183                   cp->xform[i].var[j] = cp->xform[i-1].var[j];
3184                   flam3_copy_params(&(cp->xform[i]),&(cp->xform[i-1]),j);
3185                }
3186 
3187             } else {
3188 
3189                /* Choose a random number of vars to use, at least 2 */
3190                /* but less than flam3_nvariations.Probability leans */
3191                /* towards fewer variations.                         */
3192                n = 2;
3193                while ((flam3_random_bit()) && (n<mvar))
3194                   n++;
3195 
3196                /* Randomly choose n variations, and change their weights. */
3197                /* A var can be selected more than once, further reducing  */
3198                /* the probability that multiple vars are used.            */
3199                for (j = 0; j < n; j++) {
3200                   if (flam3_variation_random_fromspecified != var)
3201                      cp->xform[i].var[random_varn(mvar)] = flam3_random01();
3202                   else
3203                      cp->xform[i].var[ivars[random_varn(ivars_n)]] = flam3_random01();
3204                }
3205 
3206                /* Normalize weights to 1.0 total. */
3207                sum = 0.0;
3208                for (j = 0; j < flam3_nvariations; j++)
3209                   sum += cp->xform[i].var[j];
3210                if (sum == 0.0)
3211                   cp->xform[i].var[random_var()] = 1.0;
3212                else {
3213                   for (j = 0; j < flam3_nvariations; j++)
3214                      cp->xform[i].var[j] /= sum;
3215                }
3216             }
3217          }
3218       } else {
3219          /* Handle final xform randomness. */
3220          n = 1;
3221          if (flam3_random_bit()) n++;
3222 
3223          /* Randomly choose n variations, and change their weights. */
3224          /* A var can be selected more than once, further reducing  */
3225          /* the probability that multiple vars are used.            */
3226          for (j = 0; j < n; j++) {
3227             if (flam3_variation_random_fromspecified != var)
3228                cp->xform[i].var[random_varn(mvar)] = flam3_random01();
3229             else
3230                cp->xform[i].var[ivars[random_varn(ivars_n)]] = flam3_random01();
3231          }
3232 
3233          /* Normalize weights to 1.0 total. */
3234          sum = 0.0;
3235          for (j = 0; j < flam3_nvariations; j++)
3236             sum += cp->xform[i].var[j];
3237          if (sum == 0.0)
3238             cp->xform[i].var[random_var()] = 1.0;
3239          else {
3240             for (j = 0; j < flam3_nvariations; j++)
3241                cp->xform[i].var[j] /= sum;
3242          }
3243       }
3244 
3245       /* Generate random params for parametric variations, if selected. */
3246       if (cp->xform[i].var[VAR_BLOB] > 0) {
3247          /* Create random params for blob */
3248          cp->xform[i].blob_low = 0.2 + 0.5 * flam3_random01();
3249          cp->xform[i].blob_high = 0.8 + 0.4 * flam3_random01();
3250          cp->xform[i].blob_waves = (int)(2 + 5 * flam3_random01());
3251       }
3252 
3253       if (cp->xform[i].var[VAR_PDJ] > 0) {
3254          /* Create random params for PDJ */
3255          cp->xform[i].pdj_a = 3.0 * flam3_random11();
3256          cp->xform[i].pdj_b = 3.0 * flam3_random11();
3257          cp->xform[i].pdj_c = 3.0 * flam3_random11();
3258          cp->xform[i].pdj_d = 3.0 * flam3_random11();
3259       }
3260 
3261       if (cp->xform[i].var[VAR_FAN2] > 0) {
3262          /* Create random params for fan2 */
3263          cp->xform[i].fan2_x = flam3_random11();
3264          cp->xform[i].fan2_y = flam3_random11();
3265       }
3266 
3267       if (cp->xform[i].var[VAR_RINGS2] > 0) {
3268          /* Create random params for rings2 */
3269          cp->xform[i].rings2_val = 2*flam3_random01();
3270       }
3271 
3272       if (cp->xform[i].var[VAR_PERSPECTIVE] > 0) {
3273 
3274          /* Create random params for perspective */
3275          cp->xform[i].perspective_angle = flam3_random01();
3276          cp->xform[i].perspective_dist = 2*flam3_random01() + 1.0;
3277 
3278       }
3279 
3280       if (cp->xform[i].var[VAR_JULIAN] > 0) {
3281 
3282          /* Create random params for julian */
3283          cp->xform[i].julian_power = (int)(5*flam3_random01() + 2);
3284          cp->xform[i].julian_dist = 1.0;
3285 
3286       }
3287 
3288       if (cp->xform[i].var[VAR_JULIASCOPE] > 0) {
3289 
3290          /* Create random params for juliaScope */
3291          cp->xform[i].juliascope_power = (int)(5*flam3_random01() + 2);
3292          cp->xform[i].juliascope_dist = 1.0;
3293 
3294       }
3295 
3296       if (cp->xform[i].var[VAR_RADIAL_BLUR] > 0) {
3297 
3298          /* Create random params for radialBlur */
3299          cp->xform[i].radial_blur_angle = (2 * flam3_random01() - 1);
3300 
3301       }
3302 
3303       if (cp->xform[i].var[VAR_PIE] > 0) {
3304          /* Create random params for pie */
3305          cp->xform[i].pie_slices = (int) 10.0*flam3_random01();
3306          cp->xform[i].pie_thickness = flam3_random01();
3307          cp->xform[i].pie_rotation = 2.0 * M_PI * flam3_random11();
3308       }
3309 
3310       if (cp->xform[i].var[VAR_NGON] > 0) {
3311          /* Create random params for ngon */
3312          cp->xform[i].ngon_sides = (int) flam3_random01()* 10 + 3;
3313          cp->xform[i].ngon_power = 3*flam3_random01() + 1;
3314          cp->xform[i].ngon_circle = 3*flam3_random01();
3315          cp->xform[i].ngon_corners = 2*flam3_random01()*cp->xform[i].ngon_circle;
3316       }
3317 
3318       if (cp->xform[i].var[VAR_CURL] > 0) {
3319          /* Create random params for curl */
3320          cp->xform[i].curl_c1 = flam3_random01();
3321          cp->xform[i].curl_c2 = flam3_random01();
3322       }
3323 
3324       if (cp->xform[i].var[VAR_RECTANGLES] > 0) {
3325          /* Create random params for rectangles */
3326          cp->xform[i].rectangles_x = flam3_random01();
3327          cp->xform[i].rectangles_y = flam3_random01();
3328       }
3329 
3330       if (cp->xform[i].var[VAR_DISC2] > 0) {
3331       /* Create random params for disc2 */
3332       cp->xform[i].disc2_rot = 0.5 * flam3_random01();
3333       cp->xform[i].disc2_twist = 0.5 * flam3_random01();
3334 
3335       }
3336 
3337       if (cp->xform[i].var[VAR_SUPER_SHAPE] > 0) {
3338          /* Create random params for supershape */
3339          cp->xform[i].super_shape_rnd = flam3_random01();
3340          cp->xform[i].super_shape_m = (int) flam3_random01()*6;
3341          cp->xform[i].super_shape_n1 = flam3_random01()*40;
3342          cp->xform[i].super_shape_n2 = flam3_random01()*20;
3343          cp->xform[i].super_shape_n3 = cp->xform[i].super_shape_n2;
3344          cp->xform[i].super_shape_holes = 0.0;
3345       }
3346 
3347       if (cp->xform[i].var[VAR_FLOWER] > 0) {
3348          /* Create random params for flower */
3349          cp->xform[i].flower_petals = 4 * flam3_random01();
3350          cp->xform[i].flower_holes = flam3_random01();
3351       }
3352 
3353       if (cp->xform[i].var[VAR_CONIC] > 0) {
3354          /* Create random params for conic */
3355          cp->xform[i].conic_eccentricity = flam3_random01();
3356          cp->xform[i].conic_holes = flam3_random01();
3357       }
3358 
3359       if (cp->xform[i].var[VAR_PARABOLA] > 0) {
3360          /* Create random params for parabola */
3361          cp->xform[i].parabola_height = 0.5 + flam3_random01();
3362          cp->xform[i].parabola_width = 0.5 + flam3_random01();
3363       }
3364 
3365       if (cp->xform[i].var[VAR_BENT2] > 0) {
3366          /* Create random params for bent2 */
3367          cp->xform[i].bent2_x = 3*(-0.5 + flam3_random01());
3368          cp->xform[i].bent2_y = 3*(-0.5 + flam3_random01());
3369       }
3370 
3371       if (cp->xform[i].var[VAR_BIPOLAR] > 0) {
3372          /* Create random params for bipolar */
3373          cp->xform[i].bipolar_shift = 2.0 * flam3_random01() - 1;
3374       }
3375 
3376       if (cp->xform[i].var[VAR_CELL] > 0) {
3377          /* Create random params for cell */
3378          cp->xform[i].cell_size = 2.0 * flam3_random01() + 0.5;
3379       }
3380 
3381       if (cp->xform[i].var[VAR_CPOW] > 0) {
3382          /* Create random params for cpow */
3383          cp->xform[i].cpow_r = 3.0 * flam3_random01();
3384          cp->xform[i].cpow_i = flam3_random01() - 0.5;
3385          cp->xform[i].cpow_power = (int)(5.0 * flam3_random01());
3386       }
3387 
3388       if (cp->xform[i].var[VAR_CURVE] > 0) {
3389          /* Create random params for curve */
3390          cp->xform[i].curve_xamp = 5 * (flam3_random01()-.5);
3391          cp->xform[i].curve_yamp = 4 * (flam3_random01()-.5);
3392          cp->xform[i].curve_xlength = 2 * (flam3_random01()+.5);
3393          cp->xform[i].curve_ylength = 2 * (flam3_random01()+.5);
3394       }
3395 
3396       if (cp->xform[i].var[VAR_ESCHER] > 0) {
3397          /* Create random params for escher */
3398          cp->xform[i].escher_beta = M_PI * flam3_random11();
3399       }
3400 
3401       if (cp->xform[i].var[VAR_LAZYSUSAN] > 0) {
3402          /* Create random params for lazysusan */
3403          cp->xform[i].lazysusan_x = 2.0*flam3_random11();
3404          cp->xform[i].lazysusan_y = 2.0*flam3_random11();
3405          cp->xform[i].lazysusan_spin = M_PI*flam3_random11();
3406          cp->xform[i].lazysusan_space = 2.0*flam3_random11();
3407          cp->xform[i].lazysusan_twist = 2.0*flam3_random11();
3408       }
3409 
3410       if (cp->xform[i].var[VAR_MODULUS] > 0) {
3411          /* Create random params for modulus */
3412          cp->xform[i].modulus_x = flam3_random11();
3413          cp->xform[i].modulus_y = flam3_random11();
3414       }
3415 
3416       if (cp->xform[i].var[VAR_OSCILLOSCOPE] > 0) {
3417          /* Create random params for oscope */
3418          cp->xform[i].oscope_separation = 1.0 + flam3_random11();
3419          cp->xform[i].oscope_frequency = M_PI * flam3_random11();
3420          cp->xform[i].oscope_amplitude = 1.0 + 2 * flam3_random01();
3421          cp->xform[i].oscope_damping = flam3_random01();
3422       }
3423 
3424       if (cp->xform[i].var[VAR_POPCORN2] > 0) {
3425          /* Create random params for popcorn2 */
3426          cp->xform[i].popcorn2_x = 0.2 * flam3_random01();
3427          cp->xform[i].popcorn2_y = 0.2 * flam3_random01();
3428          cp->xform[i].popcorn2_c = 5 * flam3_random01();
3429       }
3430 
3431       if (cp->xform[i].var[VAR_SEPARATION] > 0) {
3432          /* Create random params for separation */
3433          cp->xform[i].separation_x = 1 + flam3_random11();
3434          cp->xform[i].separation_y = 1 + flam3_random11();
3435          cp->xform[i].separation_xinside = flam3_random11();
3436          cp->xform[i].separation_yinside = flam3_random11();
3437       }
3438 
3439       if (cp->xform[i].var[VAR_SPLIT] > 0) {
3440          /* Create random params for split */
3441          cp->xform[i].split_xsize = flam3_random11();
3442          cp->xform[i].split_ysize = flam3_random11();
3443       }
3444 
3445       if (cp->xform[i].var[VAR_SPLITS] > 0) {
3446          /* Create random params for splits */
3447          cp->xform[i].splits_x = flam3_random11();
3448          cp->xform[i].splits_y = flam3_random11();
3449       }
3450 
3451       if (cp->xform[i].var[VAR_STRIPES] > 0) {
3452          /* Create random params for stripes */
3453          cp->xform[i].stripes_space = flam3_random01();
3454          cp->xform[i].stripes_warp = 5*flam3_random01();
3455       }
3456 
3457       if (cp->xform[i].var[VAR_WEDGE] > 0) {
3458          /* Create random params for wedge */
3459          cp->xform[i].wedge_angle = M_PI*flam3_random01();
3460          cp->xform[i].wedge_hole = 0.5*flam3_random11();
3461          cp->xform[i].wedge_count = floor(5*flam3_random01())+1;
3462          cp->xform[i].wedge_swirl = flam3_random01();
3463       }
3464 
3465       if (cp->xform[i].var[VAR_WEDGE_JULIA] > 0) {
3466 
3467          /* Create random params for wedge_julia */
3468          cp->xform[i].wedge_julia_power = (int)(5*flam3_random01() + 2);
3469          cp->xform[i].wedge_julia_dist = 1.0;
3470          cp->xform[i].wedge_julia_count = (int)(3*flam3_random01() + 1);
3471          cp->xform[i].wedge_julia_angle = M_PI * flam3_random01();
3472 
3473       }
3474 
3475       if (cp->xform[i].var[VAR_WEDGE_SPH] > 0) {
3476          /* Create random params for wedge_sph */
3477          cp->xform[i].wedge_sph_angle = M_PI*flam3_random01();
3478          cp->xform[i].wedge_sph_hole = 0.5*flam3_random11();
3479          cp->xform[i].wedge_sph_count = floor(5*flam3_random01())+1;
3480          cp->xform[i].wedge_sph_swirl = flam3_random01();
3481       }
3482 
3483       if (cp->xform[i].var[VAR_WHORL] > 0) {
3484          /* Create random params for whorl */
3485          cp->xform[i].whorl_inside = flam3_random01();
3486          cp->xform[i].whorl_outside = flam3_random01();
3487       }
3488 
3489       if (cp->xform[i].var[VAR_WAVES2] > 0) {
3490          /* Create random params for waves2 */
3491          cp->xform[i].waves2_scalex = 0.5 + flam3_random01();
3492          cp->xform[i].waves2_scaley = 0.5 + flam3_random01();
3493          cp->xform[i].waves2_freqx = 4 * flam3_random01();
3494          cp->xform[i].waves2_freqy = 4 * flam3_random01();
3495       }
3496 
3497       if (cp->xform[i].var[VAR_AUGER] > 0) {
3498          /* Create random params for auger */
3499          cp->xform[i].auger_sym = 0;
3500          cp->xform[i].auger_weight = 0.5 + flam3_random01()/2.0;
3501          cp->xform[i].auger_freq = floor(5*flam3_random01())+1;
3502          cp->xform[i].auger_scale = flam3_random01();
3503       }
3504 
3505       if (cp->xform[i].var[VAR_FLUX] > 0) {
3506          /* Create random params for flux */
3507          cp->xform[i].flux_spread = 0.5 + flam3_random01()/2.0;
3508       }
3509 
3510       if (cp->xform[i].var[VAR_MOBIUS] > 0) {
3511          /* Create random params for mobius */
3512          cp->xform[i].mobius_re_a = flam3_random11();
3513          cp->xform[i].mobius_im_a = flam3_random11();
3514          cp->xform[i].mobius_re_b = flam3_random11();
3515          cp->xform[i].mobius_im_b = flam3_random11();
3516          cp->xform[i].mobius_re_c = flam3_random11();
3517          cp->xform[i].mobius_im_c = flam3_random11();
3518          cp->xform[i].mobius_re_d = flam3_random11();
3519          cp->xform[i].mobius_im_d = flam3_random11();
3520       }
3521 
3522    }
3523 
3524    /* Randomly add symmetry (but not if we've already added a final xform) */
3525    if (sym || (!(random()%4) && !addfinal))
3526       flam3_add_symmetry(cp, sym);
3527    else
3528       cp->symmetry = 0;
3529 
3530    //qsort((char *) cp->xform, (cp->num_xforms-addfinal), sizeof(flam3_xform), compare_xforms);
3531 
3532 
3533 }
3534 
3535 
sort_by_x(const void * av,const void * bv)3536 static int sort_by_x(const void *av, const void *bv) {
3537     double *a = (double *) av;
3538     double *b = (double *) bv;
3539     if (a[0] < b[0]) return -1;
3540     if (a[0] > b[0]) return 1;
3541     return 0;
3542 }
3543 
sort_by_y(const void * av,const void * bv)3544 static int sort_by_y(const void *av, const void *bv) {
3545     double *a = (double *) av;
3546     double *b = (double *) bv;
3547     if (a[1] < b[1]) return -1;
3548     if (a[1] > b[1]) return 1;
3549     return 0;
3550 }
3551 
3552 
3553 /* Memory helper functions because
3554 
3555     Python on Windows uses the MSVCR71.dll version of the C Runtime and
3556     mingw uses the MSVCRT.dll version. */
3557 
flam3_malloc(size_t size)3558 void *flam3_malloc(size_t size) {
3559 
3560    return (malloc(size));
3561 
3562 }
3563 
flam3_free(void * ptr)3564 void flam3_free(void *ptr) {
3565 
3566    free(ptr);
3567 
3568 }
3569 
3570 /*
3571  * find a 2d bounding box that does not enclose eps of the fractal density
3572  * in each compass direction.
3573  */
flam3_estimate_bounding_box(flam3_genome * cp,double eps,int nsamples,double * bmin,double * bmax,randctx * rc)3574 int flam3_estimate_bounding_box(flam3_genome *cp, double eps, int nsamples,
3575              double *bmin, double *bmax, randctx *rc) {
3576    int i;
3577    int low_target, high_target;
3578    double min[2], max[2];
3579    double *points;
3580    int bv;
3581    unsigned short *xform_distrib;
3582 
3583    if (nsamples <= 0) nsamples = 10000;
3584 
3585    points = (double *) malloc(sizeof(double) * 4 * nsamples);
3586    points[0] = flam3_random_isaac_11(rc);
3587    points[1] = flam3_random_isaac_11(rc);
3588    points[2] = 0.0;
3589    points[3] = 0.0;
3590 
3591    if (prepare_precalc_flags(cp))
3592       return(-1);
3593    xform_distrib = flam3_create_xform_distrib(cp);
3594    if (xform_distrib==NULL)
3595       return(-1);
3596    bv=flam3_iterate(cp, nsamples, 20, points, xform_distrib, rc);
3597    free(xform_distrib);
3598 
3599    if ( bv/(double)nsamples > eps )
3600       eps = 3*bv/(double)nsamples;
3601 
3602    if ( eps > 0.3 )
3603       eps = 0.3;
3604 
3605    low_target = (int)(nsamples * eps);
3606    high_target = nsamples - low_target;
3607 
3608 
3609    min[0] = min[1] =  1e10;
3610    max[0] = max[1] = -1e10;
3611 
3612    for (i = 0; i < nsamples; i++) {
3613       double *p = &points[4*i];
3614       if (p[0] < min[0]) min[0] = p[0];
3615       if (p[1] < min[1]) min[1] = p[1];
3616       if (p[0] > max[0]) max[0] = p[0];
3617       if (p[1] > max[1]) max[1] = p[1];
3618    }
3619 
3620    if (low_target == 0) {
3621       bmin[0] = min[0];
3622       bmin[1] = min[1];
3623       bmax[0] = max[0];
3624       bmax[1] = max[1];
3625       free(points);
3626       return(bv);
3627    }
3628 
3629    qsort(points, nsamples, sizeof(double) * 4, sort_by_x);
3630    bmin[0] = points[4 * low_target];
3631    bmax[0] = points[4 * high_target];
3632 
3633    qsort(points, nsamples, sizeof(double) * 4, sort_by_y);
3634    bmin[1] = points[4 * low_target + 1];
3635    bmax[1] = points[4 * high_target + 1];
3636    free(points);
3637 
3638    return(bv);
3639 }
3640 
3641 
3642 typedef double bucket_double[5];
3643 typedef double abucket_double[4];
3644 typedef unsigned int bucket_int[5];
3645 typedef unsigned int abucket_int[4];
3646 typedef float bucket_float[5];
3647 typedef float abucket_float[4];
3648 
3649 #ifdef HAVE_GCC_64BIT_ATOMIC_OPS
3650 static inline void
double_atomic_add(double * dest,double delta)3651 double_atomic_add(double *dest, double delta)
3652 {
3653    uint64_t *int_ptr = (uint64_t *)dest;
3654    union {
3655       double dblval;
3656       uint64_t intval;
3657    } old_val, new_val;
3658    int success;
3659 
3660    do {
3661       old_val.dblval = *dest;
3662       new_val.dblval = old_val.dblval + delta;
3663       success = __sync_bool_compare_and_swap(
3664          int_ptr, old_val.intval, new_val.intval);
3665    } while (!success);
3666 }
3667 #endif /* HAVE_GCC_64BIT_ATOMIC_OPS */
3668 
3669 #ifdef HAVE_GCC_ATOMIC_OPS
3670 static inline void
float_atomic_add(float * dest,float delta)3671 float_atomic_add(float *dest, float delta)
3672 {
3673    uint32_t *int_ptr = (uint32_t *)dest;
3674    union {
3675       float fltval;
3676       uint32_t intval;
3677    } old_val, new_val;
3678    int success;
3679 
3680    do {
3681       old_val.fltval = *dest;
3682       new_val.fltval = old_val.fltval + delta;
3683       success = __sync_bool_compare_and_swap(
3684          int_ptr, old_val.intval, new_val.intval);
3685    } while (!success);
3686 }
3687 
3688 static inline void
uint_atomic_add(unsigned int * dest,unsigned int delta)3689 uint_atomic_add(unsigned int *dest, unsigned int delta)
3690 {
3691    unsigned int old_val, new_val;
3692    int success;
3693 
3694    do {
3695       old_val = *dest;
3696       if (UINT_MAX - old_val > delta)
3697          new_val = old_val + delta;
3698       else
3699          new_val = UINT_MAX;
3700       success = __sync_bool_compare_and_swap(
3701          dest, old_val, new_val);
3702    } while (!success);
3703 }
3704 
3705 static inline void
ushort_atomic_add(unsigned short * dest,unsigned short delta)3706 ushort_atomic_add(unsigned short *dest, unsigned short delta)
3707 {
3708    unsigned short old_val, new_val;
3709    int success;
3710 
3711    do {
3712       old_val = *dest;
3713       if (USHRT_MAX - old_val > delta)
3714          new_val = old_val + delta;
3715       else
3716          new_val = USHRT_MAX;
3717       success = __sync_bool_compare_and_swap(
3718          dest, old_val, new_val);
3719    } while (!success);
3720 }
3721 #endif /* HAVE_GCC_ATOMIC_OPS */
3722 
3723 /* 64-bit datatypes */
3724 #define bucket bucket_double
3725 #define abucket abucket_double
3726 #define abump_no_overflow(dest, delta) do {dest += delta;} while (0)
3727 #define add_c_to_accum(acc,i,ii,j,jj,wid,hgt,c) do { \
3728    if ( (j) + (jj) >=0 && (j) + (jj) < (hgt) && (i) + (ii) >=0 && (i) + (ii) < (wid)) { \
3729    abucket *a = (acc) + ( (i) + (ii) ) + ( (j) + (jj) ) * (wid); \
3730    abump_no_overflow(a[0][0],(c)[0]); \
3731    abump_no_overflow(a[0][1],(c)[1]); \
3732    abump_no_overflow(a[0][2],(c)[2]); \
3733    abump_no_overflow(a[0][3],(c)[3]); \
3734    } \
3735 } while (0)
3736 /* single-threaded */
3737 #define USE_LOCKS
3738 #define bump_no_overflow(dest, delta)  do {dest += delta;} while (0)
3739 #define render_rectangle render_rectangle_double
3740 #define iter_thread iter_thread_double
3741 #define de_thread_helper de_thread_helper_64
3742 #define de_thread de_thread_64
3743 #include "rect.c"
3744 #ifdef HAVE_GCC_64BIT_ATOMIC_OPS
3745    /* multi-threaded */
3746    #undef USE_LOCKS
3747    #undef bump_no_overflow
3748    #undef render_rectangle
3749    #undef iter_thread
3750    #undef de_thread_helper
3751    #undef de_thread
3752    #define bump_no_overflow(dest, delta)  double_atomic_add(&dest, delta)
3753    #define render_rectangle render_rectangle_double_mt
3754    #define iter_thread iter_thread_double_mt
3755    #define de_thread_helper de_thread_helper_64_mt
3756    #define de_thread de_thread_64_mt
3757    #include "rect.c"
3758 #else /* !HAVE_GCC_64BIT_ATOMIC_OPS */
3759    #define render_rectangle_double_mt render_rectangle_double
3760 #endif /* HAVE_GCC_64BIT_ATOMIC_OPS */
3761 #undef render_rectangle
3762 #undef iter_thread
3763 #undef add_c_to_accum
3764 #undef bucket
3765 #undef abucket
3766 #undef bump_no_overflow
3767 #undef abump_no_overflow
3768 #undef de_thread_helper
3769 #undef de_thread
3770 
3771 /* 32-bit datatypes */
3772 #define bucket bucket_int
3773 #define abucket abucket_int
3774 #define abump_no_overflow(dest, delta) do { \
3775    if (UINT_MAX - dest > delta) dest += delta; else dest = UINT_MAX; \
3776 } while (0)
3777 #define add_c_to_accum(acc,i,ii,j,jj,wid,hgt,c) do { \
3778    if ( (j) + (jj) >=0 && (j) + (jj) < (hgt) && (i) + (ii) >=0 && (i) + (ii) < (wid)) { \
3779    abucket *a = (acc) + ( (i) + (ii) ) + ( (j) + (jj) ) * (wid); \
3780    abump_no_overflow(a[0][0],(c)[0]); \
3781    abump_no_overflow(a[0][1],(c)[1]); \
3782    abump_no_overflow(a[0][2],(c)[2]); \
3783    abump_no_overflow(a[0][3],(c)[3]); \
3784    } \
3785 } while (0)
3786 /* single-threaded */
3787 #define USE_LOCKS
3788 #define bump_no_overflow(dest, delta) do { \
3789    if (UINT_MAX - dest > delta) dest += delta; else dest = UINT_MAX; \
3790 } while (0)
3791 #define render_rectangle render_rectangle_int
3792 #define iter_thread iter_thread_int
3793 #define de_thread_helper de_thread_helper_32
3794 #define de_thread de_thread_32
3795 #include "rect.c"
3796 #ifdef HAVE_GCC_ATOMIC_OPS
3797    /* multi-threaded */
3798    #undef USE_LOCKS
3799    #undef bump_no_overflow
3800    #undef render_rectangle
3801    #undef iter_thread
3802    #undef de_thread_helper
3803    #undef de_thread
3804    #define bump_no_overflow(dest, delta)  uint_atomic_add(&dest, delta)
3805    #define render_rectangle render_rectangle_int_mt
3806    #define iter_thread iter_thread_int_mt
3807    #define de_thread_helper de_thread_helper_32_mt
3808    #define de_thread de_thread_32_mt
3809    #include "rect.c"
3810 #else /* !HAVE_GCC_ATOMIC_OPS */
3811    #define render_rectangle_int_mt render_rectangle_int
3812 #endif /* HAVE_GCC_ATOMIC_OPS */
3813 #undef iter_thread
3814 #undef render_rectangle
3815 #undef add_c_to_accum
3816 #undef bucket
3817 #undef abucket
3818 #undef bump_no_overflow
3819 #undef abump_no_overflow
3820 #undef de_thread_helper
3821 #undef de_thread
3822 
3823 /* experimental 32-bit datatypes (called 33) */
3824 #define bucket bucket_int
3825 #define abucket abucket_float
3826 #define abump_no_overflow(dest, delta) do {dest += delta;} while (0)
3827 #define add_c_to_accum(acc,i,ii,j,jj,wid,hgt,c) do { \
3828    if ( (j) + (jj) >=0 && (j) + (jj) < (hgt) && (i) + (ii) >=0 && (i) + (ii) < (wid)) { \
3829    abucket *a = (acc) + ( (i) + (ii) ) + ( (j) + (jj) ) * (wid); \
3830    abump_no_overflow(a[0][0],(c)[0]); \
3831    abump_no_overflow(a[0][1],(c)[1]); \
3832    abump_no_overflow(a[0][2],(c)[2]); \
3833    abump_no_overflow(a[0][3],(c)[3]); \
3834    } \
3835 } while (0)
3836 /* single-threaded */
3837 #define USE_LOCKS
3838 #define bump_no_overflow(dest, delta) do { \
3839    if (UINT_MAX - dest > delta) dest += delta; else dest = UINT_MAX; \
3840 } while (0)
3841 #define render_rectangle render_rectangle_float
3842 #define iter_thread iter_thread_float
3843 #define de_thread_helper de_thread_helper_33
3844 #define de_thread de_thread_33
3845 #include "rect.c"
3846 #ifdef HAVE_GCC_ATOMIC_OPS
3847    /* multi-threaded */
3848    #undef USE_LOCKS
3849    #undef bump_no_overflow
3850    #undef render_rectangle
3851    #undef iter_thread
3852    #undef de_thread_helper
3853    #undef de_thread
3854    #define bump_no_overflow(dest, delta)  uint_atomic_add(&dest, delta)
3855    #define render_rectangle render_rectangle_float_mt
3856    #define iter_thread iter_thread_float_mt
3857    #define de_thread_helper de_thread_helper_33_mt
3858    #define de_thread de_thread_33_mt
3859    #include "rect.c"
3860 #else /* !HAVE_GCC_ATOMIC_OPS */
3861    #define render_rectangle_float_mt render_rectangle_float
3862 #endif /* HAVE_GCC_ATOMIC_OPS */
3863 #undef iter_thread
3864 #undef render_rectangle
3865 #undef add_c_to_accum
3866 #undef bucket
3867 #undef abucket
3868 #undef bump_no_overflow
3869 #undef abump_no_overflow
3870 #undef de_thread_helper
3871 #undef de_thread
3872 
3873 
flam3_render_memory_required(flam3_frame * spec)3874 double flam3_render_memory_required(flam3_frame *spec)
3875 {
3876   flam3_genome *cps = spec->genomes;
3877   int real_bits = spec->bits;
3878   int real_bytes;
3879 
3880   if (33 == real_bits) real_bits = 32;
3881 
3882   real_bytes = real_bits / 8;
3883 
3884   return
3885     (double) cps[0].spatial_oversample * cps[0].spatial_oversample *
3886     (double) cps[0].width * cps[0].height * real_bytes * 9.0;
3887 }
3888 
bits_error(flam3_frame * spec)3889 void bits_error(flam3_frame *spec) {
3890       fprintf(stderr, "flam3: bits must be 32, 33, or 64 not %d.\n",
3891          spec->bits);
3892 }
3893 
flam3_render(flam3_frame * spec,void * out,int field,int nchan,int trans,stat_struct * stats)3894 int flam3_render(flam3_frame *spec, void *out,
3895         int field, int nchan, int trans, stat_struct *stats) {
3896 
3897   int retval;
3898 
3899   if (spec->nthreads <= 2) {
3900     /* single-threaded or 2 threads without atomic operations */
3901     switch (spec->bits) {
3902     case 32:
3903       retval = render_rectangle_int(spec, out, field, nchan, trans, stats);
3904       return(retval);
3905     case 33:
3906       retval = render_rectangle_float(spec, out, field, nchan, trans, stats);
3907       return(retval);
3908     case 64:
3909       retval = render_rectangle_double(spec, out, field, nchan, trans, stats);
3910       return(retval);
3911     default:
3912       bits_error(spec);
3913       return(1);
3914     }
3915   } else {
3916     /* 3+ threads using atomic ops if available */
3917     switch (spec->bits) {
3918     case 32:
3919       retval = render_rectangle_int_mt(spec, out, field, nchan, trans, stats);
3920       return(retval);
3921     case 33:
3922       retval = render_rectangle_float_mt(spec, out, field, nchan, trans, stats);
3923       return(retval);
3924     case 64:
3925       retval = render_rectangle_double_mt(spec, out, field, nchan, trans, stats);
3926       return(retval);
3927     default:
3928       bits_error(spec);
3929       return(1);
3930     }
3931   }
3932 }
3933 
3934 
flam3_srandom()3935 void flam3_srandom() {
3936    unsigned int seed;
3937    char *s = getenv("seed");
3938 
3939    if (s)
3940       seed = atoi(s);
3941    else
3942       seed = time(0) + getpid();
3943 
3944    srandom(seed);
3945 }
3946 
3947 
3948 /* correlation dimension, after clint sprott.
3949    computes slope of the correlation sum at a size scale
3950    the order of 2% the size of the attractor or the camera. */
flam3_dimension(flam3_genome * cp,int ntries,int clip_to_camera)3951 double flam3_dimension(flam3_genome *cp, int ntries, int clip_to_camera) {
3952   double fd;
3953   double *hist;
3954   double bmin[2];
3955   double bmax[2];
3956   double d2max;
3957   int lp;
3958   long int default_isaac_seed = (long int)time(0);
3959   randctx rc;
3960   int SBS = 10000;
3961   int i, n1=0, n2=0, got, nclipped;
3962 
3963   /* Set up the isaac rng */
3964   for (lp = 0; lp < RANDSIZ; lp++)
3965      rc.randrsl[lp] = default_isaac_seed;
3966 
3967   irandinit(&rc,1);
3968 
3969   if (ntries < 2) ntries = 3000*1000;
3970 
3971   if (clip_to_camera) {
3972     double scale, ppux, corner0, corner1;
3973     scale = pow(2.0, cp->zoom);
3974     ppux = cp->pixels_per_unit * scale;
3975     corner0 = cp->center[0] - cp->width / ppux / 2.0;
3976     corner1 = cp->center[1] - cp->height / ppux / 2.0;
3977     bmin[0] = corner0;
3978     bmin[1] = corner1;
3979     bmax[0] = corner0 + cp->width  / ppux;
3980     bmax[1] = corner1 + cp->height / ppux;
3981   } else {
3982     if (flam3_estimate_bounding_box(cp, 0.0, 0, bmin, bmax, &rc)<0)
3983        return(-1.0);
3984 
3985   }
3986 
3987   d2max =
3988     (bmax[0] - bmin[0]) * (bmax[0] - bmin[0]) +
3989     (bmax[1] - bmin[1]) * (bmax[1] - bmin[1]);
3990 
3991   //  fprintf(stderr, "d2max=%g %g %g %g %g\n", d2max,
3992   //  bmin[0], bmin[1], bmax[0], bmax[1]);
3993 
3994   hist = malloc(2 * ntries * sizeof(double));
3995 
3996   got = 0;
3997   nclipped = 0;
3998   while (got < 2*ntries) {
3999     double subb[40000];
4000     int i4, clipped;
4001     unsigned short *xform_distrib;
4002     subb[0] = flam3_random_isaac_11(&rc);
4003     subb[1] = flam3_random_isaac_11(&rc);
4004     subb[2] = 0.0;
4005     subb[3] = 0.0;
4006     if (prepare_precalc_flags(cp))
4007       return(-1.0);
4008     xform_distrib = flam3_create_xform_distrib(cp);
4009     if (xform_distrib==NULL)
4010       return(-1.0);
4011     flam3_iterate(cp, SBS, 20, subb, xform_distrib, &rc);
4012     free(xform_distrib);
4013     i4 = 0;
4014     for (i = 0; i < SBS; i++) {
4015       if (got == 2*ntries) break;
4016       clipped = clip_to_camera &&
4017    ((subb[i4] < bmin[0]) ||
4018     (subb[i4+1] < bmin[1]) ||
4019     (subb[i4] > bmax[0]) ||
4020     (subb[i4+1] > bmax[1]));
4021       if (!clipped) {
4022    hist[got] = subb[i4];
4023    hist[got+1] = subb[i4+1];
4024    got += 2;
4025       } else {
4026    nclipped++;
4027    if (nclipped > 10 * ntries) {
4028        fprintf(stderr, "warning: too much clipping, "
4029           "flam3_dimension giving up.\n");
4030        return sqrt(-1.0);
4031    }
4032       }
4033       i4 += 4;
4034     }
4035   }
4036   if (0)
4037     fprintf(stderr, "cliprate=%g\n", nclipped/(ntries+(double)nclipped));
4038 
4039   for (i = 0; i < ntries; i++) {
4040     int ri;
4041     double dx, dy, d2;
4042     double tx, ty;
4043 
4044     tx = hist[2*i];
4045     ty = hist[2*i+1];
4046 
4047     do {
4048       ri = 2 * (random() % ntries);
4049     } while (ri == i);
4050 
4051     dx = hist[ri] - tx;
4052     dy = hist[ri+1] - ty;
4053     d2 = dx*dx + dy*dy;
4054     if (d2 < 0.004 * d2max) n2++;
4055     if (d2 < 0.00004 * d2max) n1++;
4056   }
4057 
4058   fd = 0.434294 * log(n2 / (n1 - 0.5));
4059 
4060   if (0)
4061     fprintf(stderr, "n1=%d n2=%d\n", n1, n2);
4062 
4063   free(hist);
4064   return fd;
4065 }
4066 
flam3_lyapunov(flam3_genome * cp,int ntries)4067 double flam3_lyapunov(flam3_genome *cp, int ntries) {
4068   double p[4];
4069   double x, y;
4070   double xn, yn;
4071   double xn2, yn2;
4072   double dx, dy, r;
4073   double eps = 1e-5;
4074   int i;
4075   double sum = 0.0;
4076   unsigned short *xform_distrib;
4077 
4078   int lp;
4079   long int default_isaac_seed = (long int)time(0);
4080   randctx rc;
4081 
4082   /* Set up the isaac rng */
4083   for (lp = 0; lp < RANDSIZ; lp++)
4084      rc.randrsl[lp] = default_isaac_seed;
4085 
4086   irandinit(&rc,1);
4087 
4088 
4089   if (ntries < 1) ntries = 10000;
4090 
4091   for (i = 0; i < ntries; i++) {
4092     x = flam3_random_isaac_11(&rc);
4093     y = flam3_random_isaac_11(&rc);
4094 
4095     p[0] = x;
4096     p[1] = y;
4097     p[2] = 0.0;
4098     p[3] = 0.0;
4099 
4100     // get into the attractor
4101     if (prepare_precalc_flags(cp))
4102       return(-1.0);
4103     xform_distrib = flam3_create_xform_distrib(cp);
4104     if (xform_distrib==NULL)
4105       return(-1.0);
4106 
4107     flam3_iterate(cp, 1, 20+(random()%10), p, xform_distrib, &rc);
4108     free(xform_distrib);
4109 
4110     x = p[0];
4111     y = p[1];
4112 
4113     // take one deterministic step
4114     srandom(i);
4115 
4116     if (prepare_precalc_flags(cp))
4117       return(-1.0);
4118     xform_distrib = flam3_create_xform_distrib(cp);
4119     if (xform_distrib==NULL)
4120       return(-1.0);
4121 
4122     flam3_iterate(cp, 1, 0, p, xform_distrib, &rc);
4123     free(xform_distrib);
4124 
4125     xn = p[0];
4126     yn = p[1];
4127 
4128     do {
4129       dx = flam3_random_isaac_11(&rc);
4130       dy = flam3_random_isaac_11(&rc);
4131       r = sqrt(dx * dx + dy * dy);
4132     } while (r == 0.0);
4133     dx /= r;
4134     dy /= r;
4135 
4136     dx *= eps;
4137     dy *= eps;
4138 
4139     p[0] = x + dx;
4140     p[1] = y + dy;
4141     p[2] = 0.0;
4142 
4143     // take the same step but with eps
4144     srandom(i);
4145     if (prepare_precalc_flags(cp))
4146       return(-1.0);
4147     xform_distrib = flam3_create_xform_distrib(cp);
4148     if (xform_distrib==NULL)
4149       return(-1.0);
4150 
4151     flam3_iterate(cp, 1, 0, p, xform_distrib, &rc);
4152     free(xform_distrib);
4153 
4154     xn2 = p[0];
4155     yn2 = p[1];
4156 
4157     r = sqrt((xn-xn2)*(xn-xn2) + (yn-yn2)*(yn-yn2));
4158 
4159     sum += log(r/eps);
4160   }
4161   return sum/(log(2.0)*ntries);
4162 }
4163 
4164