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