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 #include "private.h"
20 #include "isaacs.h"
21 #include "config.h"
22 
23 int verbose;
24 
get_extras()25 char *get_extras() {
26   char *e = getenv("extras");
27   return e;
28 }
29 
gprint(flam3_genome * cp,int extras)30 void gprint(flam3_genome *cp, int extras) {
31     if (getenv("noedits"))
32         flam3_print(stdout, cp, extras ? get_extras() : NULL, flam3_dont_print_edits);
33     else
34         flam3_print(stdout, cp, extras ? get_extras() : NULL, flam3_print_edits);
35 }
36 
37 
test_cp(flam3_genome * cp)38 void test_cp(flam3_genome *cp) {
39    cp->time = 0.0;
40    cp->interpolation = flam3_interpolation_linear;
41    cp->palette_interpolation = flam3_palette_interpolation_hsv;
42    cp->hsv_rgb_palette_blend = 0.0;
43    cp->background[0] = 0.0;
44    cp->background[1] = 0.0;
45    cp->background[2] = 0.0;
46    cp->center[0] = 0.0;
47    cp->center[1] = 0.0;
48    cp->rotate = 0.0;
49    cp->pixels_per_unit = 64;
50    cp->width = 128;
51    cp->height = 128;
52    cp->spatial_oversample = 1;
53    cp->spatial_filter_radius = 0.5;
54    cp->spatial_filter_select = 0;
55    cp->highlight_power= 1.0;
56    cp->zoom = 0.0;
57    cp->sample_density = 1;
58    cp->nbatches = 1;
59    cp->ntemporal_samples = 1;
60    cp->estimator = 0.0;
61    cp->estimator_minimum = 0.0;
62    cp->estimator_curve = 0.6;
63 }
64 
string_to_cp(char * s,int * n,int defaults)65 flam3_genome *string_to_cp(char *s, int *n, int defaults) {
66   flam3_genome *cp;
67   FILE *fp;
68 
69   fp = fopen(s, "rb");
70   if (NULL == fp) {
71     perror(s);
72     exit(1);
73   }
74   cp = flam3_parse_from_file(fp, s, defaults, n);
75   if (NULL == cp) {
76       fprintf(stderr, "could not read genome from %s.\n", s);
77       exit(1);
78   }
79   return cp;
80 }
81 
create_new_editdoc(char * action,flam3_genome * parent0,flam3_genome * parent1)82 xmlDocPtr create_new_editdoc(char *action, flam3_genome *parent0, flam3_genome *parent1) {
83 
84    xmlDocPtr doc = NULL, comment_doc = NULL;
85    xmlNodePtr root_node = NULL, node = NULL, nodecopy = NULL;
86    xmlNodePtr root_comment = NULL;
87    struct tm *localt;
88    time_t mytime;
89    char *ai;
90    char timestring[100];
91    char *nick = getenv("nick");
92    char *url = getenv("url");
93    char *id = getenv("id");
94    char *gen = getenv("gen");
95    char *comment = getenv("comment");
96    int sheep_gen = argi("sheep_gen",-1);
97    int sheep_id = argi("sheep_id",-1);
98    char buffer[100];
99    char comment_string[100];
100 
101    doc = xmlNewDoc( (const xmlChar *)"1.0");
102 
103    /* Create the root node, called "edit" */
104    root_node = xmlNewNode(NULL, (const xmlChar *)"edit");
105    xmlDocSetRootElement(doc,root_node);
106    /* Add the edit attributes */
107 
108    /* date */
109    mytime = time(NULL);
110    localt = localtime(&mytime);
111    /* XXX use standard time format including timezone */
112    strftime(timestring, 100, "%a %b %e %H:%M:%S %z %Y", localt);
113    xmlNewProp(root_node, (const xmlChar *)"date", (const xmlChar *)timestring);
114 
115    /* nick */
116    if (nick) {
117       xmlNewProp(root_node, (const xmlChar *)"nick", (const xmlChar *)nick);
118    }
119 
120    /* url */
121    if (url) {
122       xmlNewProp(root_node, (const xmlChar *)"url", (const xmlChar *)url);
123    }
124 
125    if (id) {
126       xmlNewProp(root_node, (const xmlChar *)"id", (const xmlChar *)id);
127    }
128 
129    if (gen) {
130       xmlNewProp(root_node, (const xmlChar *)"gen", (const xmlChar *)gen);
131    }
132 
133    /* action */
134    xmlNewProp(root_node, (const xmlChar *)"action", (const xmlChar *)action);
135 
136    /* sheep info */
137    if (sheep_gen > 0 && sheep_id > 0) {
138       /* Create a child node of the root node called sheep */
139       node = xmlNewChild(root_node, NULL, (const xmlChar *)"sheep", NULL);
140 
141       /* Create the sheep attributes */
142       sprintf(buffer, "%d", sheep_gen);
143       xmlNewProp(node, (const xmlChar *)"generation", (const xmlChar *)buffer);
144 
145       sprintf(buffer, "%d", sheep_id);
146       xmlNewProp(node, (const xmlChar *)"id", (const xmlChar *)buffer);
147    }
148 
149    /* Check for the parents */
150    /* If Parent 0 not specified, this is a randomly generated genome. */
151    if (parent0) {
152       if (parent0->edits) {
153          /* Copy the node from the parent */
154          node = xmlDocGetRootElement(parent0->edits);
155          nodecopy = xmlCopyNode(node, 1);
156          xmlNewProp(nodecopy,(const xmlChar *)"filename", (const xmlChar *)parent0->parent_fname);
157          sprintf(buffer,"%d",parent0->genome_index);
158          xmlNewProp(nodecopy,(const xmlChar *)"index", (const xmlChar *)buffer);
159          xmlAddChild(root_node, nodecopy);
160       } else {
161          /* Insert a (parent has no edit) message */
162          nodecopy = xmlNewChild(root_node, NULL, (const xmlChar *)"edit",NULL);
163          xmlNewProp(nodecopy,(const xmlChar *)"filename", (const xmlChar *)parent0->parent_fname);
164          sprintf(buffer,"%d",parent0->genome_index);
165          xmlNewProp(nodecopy,(const xmlChar *)"index", (const xmlChar *)buffer);
166 
167       }
168    }
169 
170    if (parent1) {
171 
172       if (parent1->edits) {
173          /* Copy the node from the parent */
174          node = xmlDocGetRootElement(parent1->edits);
175          nodecopy = xmlCopyNode(node, 1);
176          xmlNewProp(nodecopy,(const xmlChar *)"filename", (const xmlChar *)parent1->parent_fname);
177          sprintf(buffer,"%d",parent1->genome_index);
178          xmlNewProp(nodecopy,(const xmlChar *)"index", (const xmlChar *)buffer);
179          xmlAddChild(root_node, nodecopy);
180       } else {
181          /* Insert a (parent has no edit) message */
182          nodecopy = xmlNewChild(root_node, NULL, (const xmlChar *)"edit",NULL);
183          xmlNewProp(nodecopy,(const xmlChar *)"filename", (const xmlChar *)parent1->parent_fname);
184          sprintf(buffer,"%d",parent1->genome_index);
185          xmlNewProp(nodecopy,(const xmlChar *)"index", (const xmlChar *)buffer);
186       }
187    }
188 
189    /* Comment string */
190    /* This one's hard, since we have to treat the comment string as   */
191    /* a valid XML document.  Create a new document using the comment  */
192    /* string as the in-memory document, and then copy all children of */
193    /* the root node into the edit structure                           */
194    /* Parsing the comment string should be done once and then copied  */
195    /* for each call to create_new_editdoc, but that's for later.      */
196    if (comment) {
197 
198       sprintf(comment_string,"<comm>%s</comm>",comment);
199 
200       comment_doc = xmlReadMemory(comment_string, strlen(comment_string), "comment.env", NULL, XML_PARSE_NONET);
201 
202       /* Check for errors */
203       if (comment_doc==NULL) {
204          fprintf(stderr, "Failed to parse comment into XML!\n");
205          exit(1);
206       }
207 
208       /* Loop through the children of the new document and copy */
209       /* them into the root_node */
210       root_comment = xmlDocGetRootElement(comment_doc);
211 
212       for (node=root_comment->children; node; node = node->next) {
213 
214          nodecopy = xmlCopyNode(node,1);
215          xmlAddChild(root_node, nodecopy);
216       }
217 
218       /* Free the created document */
219       xmlFreeDoc(comment_doc);
220    }
221 
222 
223    /* return the xml doc */
224    return(doc);
225 }
226 
offset(flam3_genome * g)227 void offset(flam3_genome *g) {
228     char *os = getenv("offset");
229     double ox, oy;
230     if (NULL == os) return;
231     sscanf(os, "%lf:%lf", &ox, &oy);
232     g->center[0] += ox / (g->pixels_per_unit * g->spatial_oversample);
233     g->center[1] += oy / (g->pixels_per_unit * g->spatial_oversample);
234 }
235 
spin(int frame,double blend,flam3_genome * parent,flam3_genome * templ)236 void spin(int frame, double blend, flam3_genome *parent, flam3_genome *templ)
237 {
238    flam3_genome *result;
239    char action[50];
240    xmlDocPtr doc;
241 
242    /* Spin the parent blend*360 degrees */
243    result = sheep_loop(parent,blend);
244 
245    /* Apply the template if necessary */
246    if (templ)
247       flam3_apply_template(result, templ);
248 
249    /* Set genome parameters accordingly */
250    result->time = (double)frame;
251    result->interpolation = flam3_interpolation_linear;
252    result->palette_interpolation = flam3_palette_interpolation_hsv_circular;
253    result->hsv_rgb_palette_blend = 0.0;
254 
255    /* Force linear interpolation - unsure if this is still necessary     */
256    /* I believe we put this in so that older clients could render frames */
257 //   result->interpolation_type = flam3_inttype_linear;
258 
259    /* Create the edit doc xml */
260    sprintf(action,"rotate %g",blend*360.0);
261    doc = create_new_editdoc(action, parent, (flam3_genome *)NULL);
262    result->edits = doc;
263 
264    /* Subpixel jitter */
265    offset(result);
266 
267    /* Make the name of the flame the time */
268    sprintf(result->flame_name,"%f",result->time);
269 
270    /* Print the resulting xml */
271    gprint(result, 1);
272 
273    /* Clear out the xml doc */
274    xmlFreeDoc(result->edits);
275 
276    /* Clear the result cp */
277    clear_cp(result,flam3_defaults_on);
278 
279    /* Free the cp allocated in flam3_sheep_loop */
280    free(result);
281 }
282 
spin_inter(int frame,double blend,int seqflag,flam3_genome * parents,flam3_genome * templ)283 void spin_inter(int frame, double blend, int seqflag, flam3_genome *parents, flam3_genome *templ) {
284 
285    flam3_genome *result;
286    char action[50];
287    xmlDocPtr doc;
288    char *ai;
289    double stagger = argf("stagger", 0.0);
290 
291    /* Interpolate between spun parents */
292    result = sheep_edge(parents, blend, seqflag, stagger);
293 
294    /* Unsure why we check for random palettes on both ends... */
295    if ((parents[0].palette_index != flam3_palette_random) &&
296       (parents[1].palette_index != flam3_palette_random)) {
297 
298          result->palette_index = flam3_palette_interpolated;
299          result->palette_index0 = parents[0].palette_index;
300          result->hue_rotation0 = parents[0].hue_rotation;
301          result->palette_index1 = parents[1].palette_index;
302          result->hue_rotation1 = parents[1].hue_rotation;
303          result->palette_blend = blend;
304    }
305 
306    /* Apply template if necessary */
307    if (templ)
308       flam3_apply_template(result, templ);
309 
310    /* Set genome attributes */
311    result->time = (double)frame;
312 //   result->interpolation_type = flam3_inttype_linear;
313 
314    /* Create the edit doc xml */
315    sprintf(action,"interpolate %g",blend*360.0);
316    doc = create_new_editdoc(action, &parents[0], &parents[1]);
317    result->edits = doc;
318 
319    /* Subpixel jitter */
320    offset(result);
321 
322    /* Make the name of the flame the time */
323    sprintf(result->flame_name,"%f",result->time);
324 
325    /* Print the genome */
326    gprint(result, 1);
327 
328    /* Clean up */
329    xmlFreeDoc(result->edits);
330 
331    /* Free genome storage */
332    clear_cp(result,flam3_defaults_on);
333    free(result);
334 }
335 
truncate_variations(flam3_genome * g,int max_vars,char * action)336 void truncate_variations(flam3_genome *g, int max_vars, char *action) {
337    int i, j, nvars, smallest;
338    double sv=0;
339    char trunc_note[30];
340 
341    for (i = 0; i < g->num_xforms; i++) {
342       double d = g->xform[i].density;
343 
344 /*      if (0.0 < d && d < 0.001) */
345 
346       if (d < 0.001 && (g->final_xform_index != i)) {
347          sprintf(trunc_note," trunc_density %d",i);
348          //strcat(action,trunc_note);
349          add_to_action(action,trunc_note);
350          flam3_delete_xform(g, i);
351 
352 /*         g->xform[i].density = 0.0;
353       } else if (d > 0.0) {
354 */
355       } else {
356          do {
357             nvars = 0;
358             smallest = -1;
359             for (j = 0; j < flam3_nvariations; j++) {
360                double v = g->xform[i].var[j];
361                if (v != 0.0) {
362                   nvars++;
363                   if (-1 == smallest || fabs(v) < sv) {
364                      smallest = j;
365                      sv = fabs(v);
366                   }
367                }
368             }
369             if (nvars > max_vars) {
370                sprintf(trunc_note," trunc %d %d",i,smallest);
371                //strcat(action,trunc_note);
372                add_to_action(action,trunc_note);
373                g->xform[i].var[smallest] = 0.0;
374             }
375          } while (nvars > max_vars);
376       }
377    }
378 }
379 
golden_bit(randctx * rc)380 static double golden_bit(randctx *rc) {
381   return flam3_random_isaac_bit(rc)?0.38196:0.61804;
382 }
383 
print_find_parents(xmlNode * node,int last,int level)384 static void print_find_parents(xmlNode *node, int last, int level) {
385   xmlAttrPtr att_ptr, cur_att;
386   xmlNodePtr chld_ptr=NULL, cur_chld=NULL;
387   xmlNode *this_node;
388   int next_last;
389   //for (i = 0; i < level; i++)
390   // fprintf(stdout, "+");
391   // fprintf(stdout, "pfp %d ", last);
392   for (this_node=node; this_node; this_node = this_node->next) {
393     if (this_node->type == XML_ELEMENT_NODE) {
394       // fprintf(stdout, "nname=%s ", this_node->name);
395       if (!xmlStrcmp(this_node->name, (const xmlChar *)"edit")) {
396 	att_ptr = node->properties;
397 	next_last = 0;
398 	if (last) {
399 	  char *pgen = NULL, *pid = NULL;
400 	  for (cur_att = att_ptr; cur_att; cur_att = cur_att->next) {
401 	    if (!xmlStrcmp(cur_att->name, (const xmlChar *)"gen")) {
402 	      char *att_str = (char *) xmlGetProp(node,cur_att->name);
403 	      pgen = att_str;
404 	    }
405 	    if (!xmlStrcmp(cur_att->name, (const xmlChar *)"id")) {
406 	      char *att_str = (char *) xmlGetProp(node,cur_att->name);
407 	      pid = att_str;
408 	    }
409 	  }
410 	  if (pgen) printf("GEN=%s ", pgen);
411 	  if (pid) printf("ID=%s", pid);
412 	  if (pid || pgen)
413 	    printf("\n");
414 	} else {
415 	  for (cur_att = att_ptr; cur_att; cur_att = cur_att->next) {
416 	    char *att_str = (char *) xmlGetProp(node,cur_att->name);
417 	    // fprintf(stdout, "name=%s val=%s ", cur_att->name, att_str);
418 	    if (!xmlStrcmp(cur_att->name, (const xmlChar *)"action")) {
419 	      if (!strncmp(att_str, "cross", 5) || !strncmp(att_str, "mutate", 6)) {
420 		next_last = 1;
421 	      }
422 	    }
423 	  }
424 	  // fprintf(stdout, "\n");
425 	  chld_ptr = node->children;
426 	  for (cur_chld=chld_ptr; cur_chld; cur_chld = cur_chld->next)
427 	    print_find_parents(cur_chld, next_last, level + 1);
428 	}
429       }
430     }
431     return;
432   }
433 }
434 
435 int
main(argc,argv)436 main(argc, argv)
437    int argc;
438    char **argv;
439 {
440    int debug = 0;
441    int count;
442    char *ai;
443    unsigned char *image;
444    flam3_genome *templ = NULL;
445    flam3_genome cp_orig, cp_save;
446    int i, j;
447    double avg_pix, fraction_black, fraction_white;
448    double avg_thresh = argf("avg", 20.0);
449    double black_thresh = argf("black", 0.01);
450    double white_limit = argf("white", 0.05);
451    int nframes = argi("nframes", 100);
452    int sym = argi("symmetry", 0);
453    int enclosed = argi("enclosed", 1);
454    char *clone = getenv("clone");
455    char *clone_all = getenv("clone_all");
456    char *animate = getenv("animate");
457    char *mutate = getenv("mutate");
458    char *cross0 = getenv("cross0");
459    char *cross1 = getenv("cross1");
460    char *method = getenv("method");
461    char *inter = getenv("inter");
462    char *find_parents = getenv("find_parents");
463    char *rotate = getenv("rotate");
464    char *strip = getenv("strip");
465    char *sequence = getenv("sequence");
466    int loops = argi("loops", 1);
467    int frame = argi("frame", 0);
468    int rep, repeat = argi("repeat", 1);
469    double speed = argf("speed", 0.1);
470    int bits = argi("bits", 33);
471    int ntries = argi("tries", 10);
472    char *use_vars = getenv("use_vars");
473    char *dont_use_vars = getenv("dont_use_vars");
474    flam3_genome *parent0=NULL, *parent1=NULL;
475    flam3_genome selp0, selp1;
476    flam3_genome *aselp0, *aselp1;
477    int parent0_n, parent1_n;
478    int num_threads = 1;
479    flam3_genome *cp;
480    int ncp;
481 
482    int ivars[max_specified_vars];
483    int novars[max_specified_vars];
484    int num_ivars = 0;
485    int num_novars = 0;
486    char *var_tok;
487 
488    flam3_frame f;
489    char action[flam3_max_action_length];
490 
491    stat_struct stats;
492 
493 
494 
495 #ifdef WIN32
496 
497    char *slashloc;
498    char exepath[256];
499    char palpath[256];
500    memset(exepath,0,256);
501    memset(palpath,0,256);
502    slashloc = strrchr(argv[0],'\\');
503 	if (NULL==slashloc) {
504 	   sprintf(palpath,"flam3_palettes=flam3-palettes.xml");
505 	} else {
506        strncpy(exepath,argv[0],slashloc-argv[0]+1);
507 	   sprintf(palpath,"flam3_palettes=%sflam3-palettes.xml",exepath);
508 	}
509 	putenv(palpath);
510 
511 #endif
512 
513    if (argc>1) {
514       if (strcmp("--version",argv[1])==0) {
515          printf("FLAM3-%s\n",flam3_version());
516          exit(0);
517       } else {
518          printf("unrecognized option %s, aborting.\n",argv[1]);
519          exit(-1);
520       }
521    }
522 
523    verbose = argi("verbose", 0);
524 
525    memset(&cp_orig, 0, sizeof(flam3_genome));
526    memset(&cp_save, 0, sizeof(flam3_genome));
527    memset(&selp0, 0, sizeof(flam3_genome));
528    memset(&selp1, 0, sizeof(flam3_genome));
529 
530    if (1 != argc) {
531       docstring();
532       exit(0);
533    }
534 
535    /* Init random number generators */
536    flam3_init_frame(&f);
537    flam3_srandom();
538 
539    //f.temporal_filter_radius = 0.0;
540    f.bits = bits;
541    f.bytes_per_channel = 1;
542    f.earlyclip = 1;
543    f.verbose = 0;
544    f.genomes = &cp_orig;
545    f.ngenomes = 1;
546    f.pixel_aspect_ratio = 1.0;
547    f.progress = 0;
548    f.nthreads = num_threads;
549    f.sub_batch_size = 10000;
550    test_cp(&cp_orig);  // just for the width & height
551 
552    /* Are the variations to be used specified? */
553    if (use_vars && dont_use_vars) {
554       fprintf(stderr,"use_vars and dont_use_vars cannot both be specified.  Terminating.\n");
555       exit(-1);
556    }
557 
558    /* Specify reasonable defaults if nothing is specified */
559    if (!use_vars && !dont_use_vars) {
560       novars[num_novars++] = VAR_NOISE;
561       novars[num_novars++] = VAR_BLUR;
562       novars[num_novars++] = VAR_GAUSSIAN_BLUR;
563       novars[num_novars++] = VAR_RADIAL_BLUR;
564       novars[num_novars++] = VAR_NGON;
565       novars[num_novars++] = VAR_SQUARE;
566       novars[num_novars++] = VAR_RAYS;
567       novars[num_novars++] = VAR_CROSS;
568       novars[num_novars++] = VAR_PRE_BLUR;
569       novars[num_novars++] = VAR_SEPARATION;
570       novars[num_novars++] = VAR_SPLIT;
571       novars[num_novars++] = VAR_SPLITS;
572 
573 
574 
575       /* Loop over the novars and set ivars to the complement */
576       for (i=0;i<flam3_nvariations;i++) {
577          for (j=0;j<num_novars;j++) {
578             if (novars[j] == i)
579                break;
580          }
581          if (j==num_novars)
582             ivars[num_ivars++] = i;
583       }
584 
585    } else {
586 
587       if (use_vars) {
588          /* Parse comma-separated list of variations to use */
589          var_tok = strtok(use_vars,",");
590          ivars[num_ivars++] = atoi(var_tok);
591          while(1) {
592             var_tok = strtok(NULL,",");
593 
594             if (var_tok==NULL)
595                break;
596 
597             ivars[num_ivars++] = atoi(var_tok);
598 
599             if (num_ivars==max_specified_vars) {
600                fprintf(stderr,"Maximum number of user-specified variations exceeded.  Truncating.\n");
601                break;
602             }
603          }
604 
605          /* Error checking */
606          for (i=0;i<num_ivars;i++) {
607             if (ivars[i]<0 || ivars[i]>=flam3_nvariations) {
608                fprintf(stderr,"specified variation list includes bad value. (%d)\n",ivars[i]);
609                exit(1);
610             }
611          }
612       } else if (dont_use_vars) {
613          /* Parse comma-separated list of variations NOT to use */
614          var_tok = strtok(dont_use_vars,",");
615          novars[num_novars++] = atoi(var_tok);
616          while(1) {
617             var_tok = strtok(NULL,",");
618 
619             if (var_tok==NULL)
620                break;
621 
622             novars[num_novars++] = atoi(var_tok);
623 
624             if (num_novars==max_specified_vars) {
625                fprintf(stderr,"Maximum number of user-specified variations exceeded.  Truncating.\n");
626                break;
627             }
628          }
629 
630          /* Loop over the novars and set ivars to the complement */
631          for (i=0;i<flam3_nvariations;i++) {
632             for (j=0;j<num_novars;j++) {
633                if (novars[j] == i)
634                   break;
635             }
636             if (j==num_novars)
637                ivars[num_ivars++] = i;
638          }
639       }
640    }
641 
642    if (1 < (!!mutate + !!(cross0 || cross1) +
643        !!inter + !!rotate + !!clone + !!strip )) {
644       fprintf(stderr,
645       "can only specify one of mutate, clone, cross, rotate, strip, or inter.\n");
646       exit(1);
647    }
648 
649    if ( (!cross0) ^ (!cross1) ) {
650       fprintf(stderr, "must specify both crossover arguments.\n");
651       exit(1);
652    }
653 
654    if (method && (!cross0 && !mutate)) {
655       fprintf(stderr, "cannot specify method unless doing crossover or mutate.\n");
656       exit(1);
657    }
658 
659    if (getenv("template")) {
660       char *tf = getenv("template");
661 
662       templ = string_to_cp(tf, &ncp, flam3_defaults_off);
663       if (1 < ncp) {
664          fprintf(stderr, "more than one control point in template, "
665             "ignoring all but first.\n");
666       } else if (0 == ncp) {
667          fprintf(stderr, "no control points in template.\n");
668          exit(1);
669       }
670 
671    }
672 
673    /* Methods for genetic manipulation begin here */
674 
675    if (clone_all) {
676 
677      cp = string_to_cp(clone_all, &ncp, flam3_defaults_on);
678 
679       printf("<clone_all version=\"FLAM3-%s\">\n", flam3_version());
680       for (i = 0; i < ncp; i++) {
681          if (templ) flam3_apply_template(&cp[i], templ);
682          offset(&cp[i]);
683          gprint(&cp[i], 1);
684       }
685       printf("</clone_all>\n");
686 
687       exit(0);
688    }
689 
690    if (animate) {
691       flam3_genome interpolated;
692       int first_frame,last_frame;
693       int ftime,iscp;
694       double stagger = argf("stagger", 0.0);
695       cp = string_to_cp(animate, &ncp, flam3_defaults_on);
696 
697 
698       for (i = 0; i < ncp; i++) {
699          if (i > 0 && cp[i].time <= cp[i-1].time) {
700             fprintf(stderr, "error: control points must be sorted by time, but %g <= %g, index %d.\n",
701             cp[i].time, cp[i-1].time, i);
702             exit(1);
703          }
704          /* Strip out all motion elements here */
705          for (j=0;j<cp[i].num_xforms;j++)
706             flam3_delete_motion_elements(&cp[i].xform[j]);
707 
708       }
709 
710       if (!getenv("begin"))
711          first_frame = (int) cp[0].time;
712       else
713          first_frame = argi("begin",0);
714 
715       if (!getenv("end"))
716          last_frame = (int) cp[ncp-1].time;
717       else
718          last_frame = argi("end",0);
719 
720       if (last_frame < first_frame) last_frame = first_frame;
721 
722       printf("<animate version=\"FLAM3-%s\">\n", flam3_version());
723 
724       for (ftime = first_frame; ftime <= last_frame; ftime += 1) {
725          iscp=0;
726          for (i=0;i<ncp;i++) {
727             if ( ftime==cp[i].time ) {
728                flam3_copy(&interpolated, &(cp[i]) );
729                iscp=1;
730             }
731          }
732          if (iscp==0) {
733             flam3_interpolate(cp, ncp, (double)ftime, stagger, &interpolated);
734             for (i=0;i<ncp;i++) {
735                if ( ftime==cp[i].time-1 ) {
736                   iscp=1;
737                }
738             }
739             if (iscp==0)
740                interpolated.interpolation_type = flam3_inttype_linear;
741          }
742 
743          if (templ) flam3_apply_template(&interpolated, templ);
744          gprint(&interpolated, 1);
745       }
746       printf("</animate>\n");
747       exit(0);
748    }
749 
750 
751    if (sequence) {
752       double blend;
753       int seqflag;
754       int framecount;
755 
756       if (nframes <= 0) {
757          fprintf(stderr, "nframes must be positive, not %d.\n", nframes);
758          exit(1);
759       }
760 
761       cp = string_to_cp(sequence, &ncp, flam3_defaults_on);
762 
763       if (enclosed) printf("<sequence version=\"FLAM3-%s\">\n", flam3_version());
764       framecount = 0;
765 #if 1
766       for (i = 0; i < ncp; i++) {
767          if (loops) {
768             for (frame = 0; frame < nframes; frame++) {
769                blend = frame/(double)nframes;
770                spin(framecount++, blend, &cp[i], templ);
771             }
772          }
773          if (i < ncp-1)
774         for (frame = 0; frame < nframes; frame++) {
775            if (0==frame || nframes-1==frame)
776               seqflag=1;
777            else
778               seqflag=0;
779        blend = frame/(double)nframes;
780        spin_inter(framecount++, blend, seqflag, &cp[i], templ);
781         }
782       }
783       spin(framecount, 0.0, &cp[ncp-1], templ);
784 #else
785       if (1) {
786      flam3_genome res;
787      memset(&res, 0, sizeof(flam3_genome));
788      res.final_xform_index = -1;
789      flam3_add_xforms(&res, cp[0].num_xforms, 0);
790 
791      if (ncp < 4) {
792          fprintf(stderr, "catmull-rom requires 4 or more control points.\n");
793          exit(1);
794      }
795      for (i = 0; i < ncp - 3; i++) {
796          for (frame = 0; frame < nframes; frame++) {
797         blend = frame/(double)nframes;
798         interpolate_catmull_rom(cp+i, blend, &res);
799         res.time = frame + i * nframes;
800         gprint(&res, 0);
801         fflush(stdout);
802          }
803      }
804       }
805 #endif
806       if (enclosed) printf("</sequence>\n");
807       exit(0);
808    }
809 
810    if (inter || rotate) {
811 
812       double blend, spread;
813       char *fname = inter?inter:rotate;
814       int ni;
815 
816       if (nframes <= 0) {
817          fprintf(stderr, "nframes must be positive, not %d.\n", nframes);
818          exit(1);
819       }
820 
821       blend = frame/(double)nframes;
822       spread = 1.0/nframes;
823 
824       cp = string_to_cp(fname, &ncp, flam3_defaults_on);
825 
826       if (enclosed) printf("<pick version=\"FLAM3-%s\">\n", flam3_version());
827       if (rotate) {
828          if (1 != ncp) {
829             fprintf(stderr, "rotation requires one control point, not %d.\n", ncp);
830             exit(1);
831          }
832          spin(frame - 1, blend - spread, cp, templ);
833          spin(frame    , blend         , cp, templ);
834          spin(frame + 1, blend + spread, cp, templ);
835       } else {
836          if (2 != ncp) {
837             fprintf(stderr, "interpolation requires two control points, not %d.\n", ncp);
838             exit(1);
839          }
840          spin_inter(frame - 1, blend - spread, 0, cp, templ);
841          spin_inter(frame    , blend         , 0, cp, templ);
842          spin_inter(frame + 1, blend + spread, 0, cp, templ);
843       }
844       if (enclosed) printf("</pick>\n");
845 
846       for (ni=0;ni<ncp;ni++) {
847          xmlFreeDoc(cp[ni].edits);
848          clear_cp(&cp[ni],flam3_defaults_on);
849       }
850       free(cp);
851 
852       exit(0);
853    }
854 
855    if (strip) {
856 
857      cp = string_to_cp(strip, &ncp, flam3_defaults_on);
858 
859       if (enclosed) printf("<pick version=\"FLAM3-%s\">\n", flam3_version());
860 
861       for (i = 0; i < ncp; i++) {
862          double old_center[2];
863 
864          /* Strip out motion elements */
865          for (j=0;j<cp[i].num_xforms;j++)
866             flam3_delete_motion_elements(&cp[i].xform[j]);
867 
868          old_center[0] = cp[i].center[0];
869          old_center[1] = cp[i].center[1];
870          cp[i].height /= nframes;
871          cp[i].center[1] = cp[i].center[1] - ((nframes - 1) * cp[i].height) /
872             (2 * cp[i].pixels_per_unit * pow(2.0, cp[i].zoom));
873          cp[i].center[1] += cp[i].height * frame / ( cp[i].pixels_per_unit * pow(2.0,cp[i].zoom) );
874          rotate_by(cp[i].center, old_center, cp[i].rotate);
875 
876          if (templ) flam3_apply_template(&cp[i], templ);
877          offset(&cp[i]);
878          gprint(&cp[i], 1);
879       }
880 
881       if (enclosed) printf("</pick>\n");
882       exit(0);
883    }
884 
885    if (find_parents) {
886      cp = string_to_cp(find_parents, &ncp, flam3_defaults_on);
887      if (1 != ncp) {
888        fprintf(stderr, "can only find parents of one genome\n");
889        exit(1);
890      }
891      xmlDocPtr edits = cp[0].edits;
892      xmlNode *rootnode = xmlDocGetRootElement(edits);
893      print_find_parents(rootnode, 0, 0);
894      exit(0);
895    }
896 
897    /* pick a control point until it looks good enough */
898    if (repeat <= 0) {
899      fprintf(stderr, "repeat must be positive, not %d.\n", repeat);
900      exit(1);
901    }
902 
903    if (enclosed) printf("<pick version=\"FLAM3-%s\">\n", flam3_version());
904    image = (unsigned char *) malloc(3 * cp_orig.width * cp_orig.height);
905 
906    for (rep = 0; rep < repeat; rep++) {
907 
908       if (verbose)
909          fprintf(stderr, "flame = %d/%d..", rep+1, repeat);
910 
911       count = 0;
912 
913       if (clone) {
914 
915 	parent0 = string_to_cp(clone, &parent0_n, flam3_defaults_on);
916          /* Action is 'clone' with trunc_vars concat */
917          sprintf(action,"clone");
918 
919          if (getenv("clone_action"))
920             sprintf(action,"clone %s", getenv("clone_action"));
921 
922          flam3_copy(&selp0, &(parent0[random()%parent0_n]));
923          flam3_copy(&cp_save, &selp0);
924          aselp0 = &selp0;
925          aselp1 = NULL;
926          truncate_variations(&cp_save, 5, action);
927 
928          cp_save.edits = create_new_editdoc(action, aselp0, aselp1);
929 
930       } else {
931          int did_color;
932 
933          do {
934 
935             int random_mode=0;
936 
937             if (verbose) fprintf(stderr, ".");
938             did_color = 0;
939             f.time = (double) 0.0;
940             action[0] = 0;
941 
942             if (mutate) {
943                int mutmeth;
944 
945                parent0 = string_to_cp(mutate, &parent0_n, flam3_defaults_on);
946                flam3_copy(&selp0, &(parent0[((unsigned)irand(&f.rc))%parent0_n]));
947                flam3_copy(&cp_orig, &selp0);
948                aselp0 = &selp0;
949                aselp1 = NULL;
950 
951                if (NULL == getenv("method"))
952                   mutmeth = MUTATE_NOT_SPECIFIED;
953                else if (!strcmp(method,"all_vars"))
954                   mutmeth = MUTATE_ALL_VARIATIONS;
955                else if (!strcmp(method,"one_xform"))
956                   mutmeth = MUTATE_ONE_XFORM_COEFS;
957                else if (!strcmp(method,"add_symmetry"))
958                   mutmeth = MUTATE_ADD_SYMMETRY;
959                else if (!strcmp(method,"post_xforms"))
960                   mutmeth = MUTATE_POST_XFORMS;
961                else if (!strcmp(method,"color_palette"))
962                   mutmeth = MUTATE_COLOR_PALETTE;
963                else if (!strcmp(method,"delete_xform"))
964                   mutmeth = MUTATE_DELETE_XFORM;
965                else if (!strcmp(method,"all_coefs"))
966                   mutmeth = MUTATE_ALL_COEFS;
967                else {
968                   fprintf(stderr,"method '%s' not defined for mutate.  defaulting to random.\n",method);
969                   mutmeth = MUTATE_NOT_SPECIFIED;
970                }
971 
972                flam3_mutate(&cp_orig, mutmeth, ivars, num_ivars, sym, speed, &f.rc, action);
973 
974                /* Scan string returned for 'mutate color' */
975                if ( strstr(action,"mutate color") )
976                   did_color = 1;
977 
978                if (cp_orig.flame_name[0]) {
979                   char tm[flam3_name_len+1];
980                   strncpy(tm, cp_orig.flame_name, flam3_name_len);
981                   snprintf(cp_orig.flame_name, flam3_name_len, "mutation %d of %s", rep, tm);
982                }
983 
984             } else if (cross0) {
985                int i0, i1;
986                int crossmeth;
987 
988                parent0 = string_to_cp(cross0, &parent0_n, flam3_defaults_on);
989                parent1 = string_to_cp(cross1, &parent1_n, flam3_defaults_on);
990 
991                i0 = ((unsigned)irand(&f.rc))%parent0_n;
992                i1 = ((unsigned)irand(&f.rc))%parent1_n;
993 
994                flam3_copy(&selp0, &(parent0[i0]));
995                flam3_copy(&selp1, &(parent1[i1]));
996 
997                aselp0 = &selp0;
998                aselp1 = &selp1;
999 
1000                if (NULL == getenv("method"))
1001                   crossmeth = CROSS_NOT_SPECIFIED;
1002                else if (!strcmp(method,"union"))
1003                   crossmeth = CROSS_UNION;
1004                else if (!strcmp(method,"interpolate"))
1005                   crossmeth = CROSS_INTERPOLATE;
1006                else if (!strcmp(method,"alternate"))
1007                   crossmeth = CROSS_ALTERNATE;
1008                else {
1009                   fprintf(stderr,"method '%s' not defined for cross.  defaulting to random.\n",method);
1010                   crossmeth = CROSS_NOT_SPECIFIED;
1011                }
1012 
1013                flam3_cross(&parent0[i0], &parent1[i1], &cp_orig, crossmeth, &f.rc, action);
1014 
1015                if (parent0[i0].flame_name[0] || parent1[i1].flame_name[0]) {
1016                   snprintf(cp_orig.flame_name, flam3_name_len, "%d of %s x %s",
1017                            rep, parent0[i0].flame_name, parent1[i1].flame_name);
1018                }
1019 
1020             } else {
1021                sprintf(action,"random");
1022                random_mode=1;
1023                flam3_random(&cp_orig, ivars, num_ivars, sym, 0);
1024 
1025 
1026                aselp0 = NULL;
1027                aselp1 = NULL;
1028             }
1029 
1030             /* Adjust bounding box half the time */
1031             if (flam3_random_bit(&f.rc) || random_mode) {
1032                double bmin[2], bmax[2];
1033                flam3_estimate_bounding_box(&cp_orig, 0.01, 100000, bmin, bmax, &f.rc);
1034                if (flam3_random_isaac_01(&f.rc) < 0.3) {
1035                   cp_orig.center[0] = (bmin[0] + bmax[0]) / 2.0;
1036                   cp_orig.center[1] = (bmin[1] + bmax[1]) / 2.0;
1037                   add_to_action(action," recentered");
1038                } else {
1039                   double mix0, mix1;
1040                   if (flam3_random_isaac_bit(&f.rc)) {
1041                      mix0 = golden_bit(&f.rc) + flam3_random_isaac_11(&f.rc)/5;
1042                      mix1 = golden_bit(&f.rc);
1043                      add_to_action(action," reframed0");
1044                   } else if (flam3_random_isaac_bit(&f.rc)) {
1045                      mix0 = golden_bit(&f.rc);
1046                      mix1 = golden_bit(&f.rc) + flam3_random_isaac_11(&f.rc)/5;
1047                      add_to_action(action," reframed1");
1048                   } else {
1049                      mix0 = golden_bit(&f.rc) + flam3_random_isaac_11(&f.rc)/5;
1050                      mix1 = golden_bit(&f.rc) + flam3_random_isaac_11(&f.rc)/5;
1051                      add_to_action(action," reframed2");
1052                   }
1053                   cp_orig.center[0] = mix0 * bmin[0] + (1-mix0)*bmax[0];
1054                   cp_orig.center[1] = mix1 * bmin[1] + (1-mix1)*bmax[1];
1055                }
1056                cp_orig.rot_center[0] = cp_orig.center[0];
1057                cp_orig.rot_center[1] = cp_orig.center[1];
1058                cp_orig.pixels_per_unit = cp_orig.width / (bmax[0] - bmin[0]);
1059             }
1060 
1061             truncate_variations(&cp_orig, 5, action);
1062 
1063             if (!did_color && random()&1) {
1064                if (debug)
1065                   fprintf(stderr,"improving colors...\n");
1066 
1067                flam3_improve_colors(&cp_orig, 100, 0, 10);
1068                //strcat(action," improved colors");
1069                add_to_action(action," improved colors");
1070             }
1071 
1072             cp_orig.edits = create_new_editdoc(action, aselp0, aselp1);
1073             flam3_copy(&cp_save, &cp_orig);
1074             test_cp(&cp_orig);
1075             if (flam3_render(&f, image, flam3_field_both, 3, 0, &stats)) {
1076                fprintf(stderr,"error rendering test image: aborting.\n");
1077                exit(1);
1078             }
1079 
1080             if (1) {
1081                int n, tot, totb, totw;
1082                n = cp_orig.width * cp_orig.height;
1083                tot = 0;
1084                totb = 0;
1085                totw = 0;
1086                for (i = 0; i < 3*n; i+=3) {
1087 
1088                   tot += (image[i]+image[i+1]+image[i+2]);
1089                   if (0 == image[i] && 0 == image[i+1] && 0 == image[i+2]) totb++;
1090                   if (255 == image[i] && 255 == image[i+1] && 255 == image[i+2]) totw++;
1091 
1092                   // printf("%d ", image[i]);
1093                }
1094 
1095                avg_pix = (tot / (double)(3*n));
1096                fraction_black = totb / (double)n;
1097                fraction_white = totw / (double)n;
1098 
1099                if (debug)
1100                   fprintf(stderr,
1101                      "avg_pix=%g fraction_black=%g fraction_white=%g n=%g\n",
1102                      avg_pix, fraction_black, fraction_white, (double)n);
1103 
1104             } else {
1105                avg_pix = avg_thresh + 1.0;
1106                fraction_black = black_thresh + 1.0;
1107                fraction_white = white_limit - 1.0;
1108             }
1109 
1110             clear_cp(&cp_orig,flam3_defaults_on);
1111 
1112             count++;
1113          } while ((avg_pix < avg_thresh ||
1114                    fraction_black < black_thresh ||
1115                    fraction_white > white_limit) &&
1116                    count < ntries);
1117 
1118          if (ntries == count) {
1119             fprintf(stderr, "warning: reached maximum attempts, giving up.\n");
1120          }
1121 
1122       }
1123 
1124       if (templ)
1125          flam3_apply_template(&cp_save,templ);
1126 
1127       cp_save.time = (double)rep;
1128 
1129       if (1) {
1130          char *maxforms = getenv("maxforms");
1131          if (maxforms && atoi(maxforms)) {
1132             cp_save.symmetry = 0;
1133             while (cp_save.num_xforms > atoi(maxforms))
1134                flam3_delete_xform(&cp_save, cp_save.num_xforms - 1);
1135          }
1136       }
1137 
1138       gprint(&cp_save, 1);
1139       fflush(stdout);
1140 
1141       /* Free created documents */
1142       /* (Only free once, since the copy is a ptr to the original) */
1143       xmlFreeDoc(cp_save.edits);
1144       clear_cp(&cp_save,0);
1145 
1146       if (verbose) {
1147          fprintf(stderr, "\ndone.  action = %s\n", action);
1148       }
1149 
1150    }
1151    if (enclosed) printf("</pick>\n");
1152    free(image);
1153 
1154    return 0;
1155 }
1156