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 "parser.h"
20 #include "interpolation.h"
21 #include "filters.h"
22 #include <errno.h>
23
24 static int flam3_conversion_failed;
25
flam3_atoi(char * nstr)26 int flam3_atoi(char *nstr) {
27
28 /* Note that this is NOT thread-safe, but simplifies things significantly. */
29 int res;
30 char *endp;
31
32 /* Reset errno */
33 errno=0;
34
35 /* Convert the string using strtol */
36 res = strtol(nstr, &endp, 10);
37
38 /* Check errno & return string */
39 if (endp!=nstr+strlen(nstr)) {
40 flam3_conversion_failed = 1;
41 fprintf(stderr,"flam3_atoi : Error converting :%s: extra chars\n",nstr);
42 }
43 if (errno) {
44 flam3_conversion_failed = 1;
45 fprintf(stderr,"flam3_atoi : Error converting :%s:\n",nstr);
46 }
47 return(res);
48 }
49
flam3_atof(char * nstr)50 double flam3_atof(char *nstr) {
51
52 /* Note that this is NOT thread-safe, but simplifies things significantly. */
53 double res;
54 char *endp;
55
56 /* Reset errno */
57 errno=0;
58
59 /* Convert the string using strtod */
60 res = strtod(nstr, &endp);
61
62 /* Check errno & return string */
63 if (endp!=nstr+strlen(nstr)) {
64 flam3_conversion_failed = 1;
65 fprintf(stderr,"flam3_atof: Error converting :%s: extra chars\n",nstr);
66 }
67 if (errno) {
68 flam3_conversion_failed = 1;
69 fprintf(stderr,"flam3_atof: Error converting :%s:\n",nstr);
70 }
71 return(res);
72 }
73
var2n(const char * s)74 int var2n(const char *s) {
75 int i;
76
77 for (i = 0; i < flam3_nvariations; i++)
78 if (!strcmp(s, flam3_variation_names[i])) return i;
79
80 return flam3_variation_none;
81 }
82
flam3_parse_hexformat_colors(char * colstr,flam3_genome * cp,int numcolors,int chan)83 int flam3_parse_hexformat_colors(char *colstr, flam3_genome *cp, int numcolors, int chan) {
84
85 int c_idx=0;
86 int col_count=0;
87 int r,g,b,a;
88 int sscanf_ret;
89 char tmps[2];
90 int skip = (int)fabs(chan);
91
92 /* Strip whitespace prior to first color */
93 while (isspace( (int)colstr[c_idx]))
94 c_idx++;
95
96 do {
97
98 /* Parse an RGB triplet at a time... */
99 a = 255;
100 if (chan==3)
101 sscanf_ret = sscanf(&(colstr[c_idx]),"%2x%2x%2x",&r,&g,&b);
102 else if (chan==-4)
103 sscanf_ret = sscanf(&(colstr[c_idx]),"00%2x%2x%2x",&r,&g,&b);
104 else // chan==4
105 sscanf_ret = sscanf(&(colstr[c_idx]),"%2x%2x%2x%2x",&r,&g,&b,&a);
106
107 if ((chan!=4 && sscanf_ret != 3) || (chan==4 && sscanf_ret != 4)) {
108 fprintf(stderr, "Error: Problem reading hexadecimal color data.\n");
109 return(1);
110 }
111
112 c_idx += 2*skip;
113
114 while (isspace( (int)colstr[c_idx]))
115 c_idx++;
116
117 cp->palette[col_count].color[0] = r / 255.0;
118 cp->palette[col_count].color[1] = g / 255.0;
119 cp->palette[col_count].color[2] = b / 255.0;
120 cp->palette[col_count].color[3] = a / 255.0;
121 cp->palette[col_count].index = col_count;
122
123 col_count++;
124
125 } while (col_count<numcolors);
126
127 if (sscanf(&(colstr[c_idx]),"%1s",tmps)>0) {
128 fprintf(stderr,"error: extra data at end of hex color data '%s'\n",&(colstr[c_idx]));
129 return(1);
130 }
131
132 return(0);
133 }
134
flam3_interp_missing_colors(flam3_genome * cp)135 int flam3_interp_missing_colors(flam3_genome *cp) {
136
137 /* Check for a non-full palette */
138 int minix,maxix;
139 int colorli,colorri;
140 int wrapmin,wrapmax;
141 int intl, intr;
142 int str,enr;
143 int i,j,k;
144 double prcr;
145
146 minix = 0;
147 for (i=0; i<256; i++) {
148 if (cp->palette[i].index >= 0) {
149 minix = i;
150 break;
151 }
152 }
153
154 if (i==256) {
155 /* No colors. Set all indices properly. */
156 for (i=0;i<256;i++)
157 cp->palette[i].index = i;
158 return(1);
159 }
160
161 wrapmin = minix + 256;
162
163 maxix = 255;
164 for (i=255;i>=0;i--) {
165 if (cp->palette[i].index >= 0) {
166 maxix = i;
167 break;
168 }
169 }
170
171 wrapmax = maxix - 256;
172
173 /* Loop over the indices looking for negs */
174 i = 0;
175 while(i<256) {
176
177 if (cp->palette[i].index < 0) {
178 /* Start of a range of negs */
179 str = i;
180 intl = i-1;
181 intr = i+1;
182 colorli = intl;
183 colorri = intr;
184 while (cp->palette[i].index<0 && i<256) {
185 enr = i;
186 intr = i+1;
187 colorri = intr;
188 i++;
189 }
190
191 if (intl==-1) {
192 intl = wrapmax;
193 colorli = maxix;
194 }
195
196 if (intr==256) {
197 intr = wrapmin;
198 colorri = minix;
199 }
200
201 for (j=str;j<=enr;j++) {
202
203 prcr = (j-intl)/(double)(intr-intl);
204
205 for (k=0;k<=3;k++)
206 cp->palette[j].color[k] = cp->palette[colorli].color[k] * (1.0-prcr) + cp->palette[colorri].color[k] * prcr;
207
208 cp->palette[j].index = j;
209 }
210
211 i = colorri+1;
212 } else
213 i ++;
214 }
215
216 return(0);
217 }
218
219
scan_for_flame_nodes(xmlNode * cur_node,char * parent_file,int default_flag,flam3_genome ** all_cps,int * all_ncps)220 void scan_for_flame_nodes(xmlNode *cur_node, char *parent_file, int default_flag, flam3_genome **all_cps, int *all_ncps) {
221
222 xmlNode *this_node = NULL;
223 flam3_genome loc_current_cp;
224 flam3_genome *genome_storage = *all_cps; /* To simplify semantics */
225 size_t f3_storage;
226 int pfe_success;
227 int col_success;
228
229 memset(&loc_current_cp,0,sizeof(flam3_genome));
230
231 /* Loop over this level of elements */
232 for (this_node=cur_node; this_node; this_node = this_node->next) {
233
234 /* Check to see if this element is a <flame> element */
235 if (this_node->type == XML_ELEMENT_NODE && !xmlStrcmp(this_node->name, (const xmlChar *)"flame")) {
236
237 /* This is a flame element. Parse it. */
238 clear_cp(&loc_current_cp, default_flag);
239
240 pfe_success = parse_flame_element(this_node,&loc_current_cp);
241
242 if (pfe_success>0) {
243 fprintf(stderr,"error parsing flame element\n");
244 all_cps = NULL; /* leaks memory but terminates */
245 /* !!! free all_cp properly !!! */
246 *all_ncps = 0;
247 return;
248 }
249
250 /* Copy this cp into the array */
251 f3_storage = (1+*all_ncps)*sizeof(flam3_genome);
252 genome_storage = realloc(genome_storage, f3_storage);
253
254 /* Must set value of pointer to new storage location */
255 *all_cps = genome_storage;
256
257 /* Clear out the realloc'd memory */
258 memset(&(genome_storage[*all_ncps]),0,sizeof(flam3_genome));
259
260 if (loc_current_cp.palette_index != -1) {
261 col_success = flam3_get_palette(loc_current_cp.palette_index, loc_current_cp.palette,
262 loc_current_cp.hue_rotation);
263 if (col_success < 0)
264 fprintf(stderr,"error retrieving palette %d, setting to all white\n",loc_current_cp.palette_index);
265 }
266
267 col_success = flam3_interp_missing_colors(&loc_current_cp);
268
269 loc_current_cp.genome_index = *all_ncps;
270 memset(loc_current_cp.parent_fname, 0, flam3_parent_fn_len);
271 strncpy(loc_current_cp.parent_fname,parent_file,flam3_parent_fn_len-1);
272
273 flam3_copy(&(genome_storage[*all_ncps]), &loc_current_cp);
274 (*all_ncps) ++;
275
276 } else {
277 /* Check all of the children of this element */
278 scan_for_flame_nodes(this_node->children, parent_file, default_flag, all_cps, all_ncps);
279 }
280 }
281
282 /* Clear the cp (frees allocated memory) */
283 clear_cp(&loc_current_cp, default_flag);
284
285 }
286
287
parse_flame_element(xmlNode * flame_node,flam3_genome * loc_current_cp)288 int parse_flame_element(xmlNode *flame_node, flam3_genome *loc_current_cp) {
289 flam3_genome *cp = loc_current_cp;
290 xmlNode *chld_node, *motion_node;
291 xmlNodePtr edit_node;
292 xmlAttrPtr att_ptr, cur_att;
293 int solo_xform=-1;
294 char *att_str;
295 int num_std_xforms=-1;
296 char tmps[2];
297 int i;
298 flam3_xform tmpcpy;
299 flam3_chaos_entry *xaos=NULL;
300 int num_xaos=0;
301
302 /* Reset the conversion error flag */
303 /* NOT threadsafe */
304 flam3_conversion_failed=0;
305
306 /* Store this flame element in the current cp */
307
308 /* Wipe out the current palette, replace with -1 for each element */
309 for (i=0;i<256;i++) {
310 cp->palette[i].color[0] = 0;
311 cp->palette[i].color[1] = 0;
312 cp->palette[i].color[2] = 0;
313 cp->palette[i].color[3] = 0;
314 cp->palette[i].index = -1;
315 }
316
317 /* The top level element is a flame element. */
318 /* Read the attributes of it and store them. */
319 att_ptr = flame_node->properties;
320
321 if (att_ptr==NULL) {
322 fprintf(stderr, "Error : <flame> element has no attributes.\n");
323 return(1);
324 }
325
326 memset(cp->flame_name,0,flam3_name_len+1);
327
328 for (cur_att = att_ptr; cur_att; cur_att = cur_att->next) {
329
330 att_str = (char *) xmlGetProp(flame_node,cur_att->name);
331
332 /* Compare attribute names */
333 if (!xmlStrcmp(cur_att->name, (const xmlChar *)"time")) {
334 cp->time = flam3_atof(att_str);
335 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"hsv_rgb_palette_blend")) {
336 cp->hsv_rgb_palette_blend = flam3_atof(att_str);
337 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"interpolation")) {
338 if (!strcmp("linear", att_str)) {
339 cp->interpolation = flam3_interpolation_linear;
340 } else if (!strcmp("smooth", att_str)) {
341 cp->interpolation = flam3_interpolation_smooth;
342 } else {
343 fprintf(stderr, "warning: unrecognized interpolation type %s.\n", att_str);
344 }
345 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"palette_interpolation")) {
346 if (!strcmp("hsv", att_str)) {
347 cp->palette_interpolation = flam3_palette_interpolation_hsv;
348 } else if (!strcmp("sweep", att_str)) {
349 cp->palette_interpolation = flam3_palette_interpolation_sweep;
350 } else if (!strcmp("hsv_circular", att_str)) {
351 cp->palette_interpolation = flam3_palette_interpolation_hsv_circular;
352 } else if (!strcmp("rgb", att_str)) {
353 cp->palette_interpolation = flam3_palette_interpolation_rgb;
354 } else {
355 fprintf(stderr, "warning: unrecognized palette interpolation type %s.\n", att_str);
356 }
357 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"interpolation_space") ||
358 !xmlStrcmp(cur_att->name, (const xmlChar *)"interpolation_type")) {
359
360 if (!strcmp("linear", att_str))
361 cp->interpolation_type = flam3_inttype_linear;
362 else if (!strcmp("log", att_str))
363 cp->interpolation_type = flam3_inttype_log;
364 else if (!strcmp("old", att_str))
365 cp->interpolation_type = flam3_inttype_compat;
366 else if (!strcmp("older", att_str))
367 cp->interpolation_type = flam3_inttype_older;
368 else
369 fprintf(stderr,"warning: unrecognized interpolation_type %s.\n",att_str);
370
371 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"name")) {
372 strncpy(cp->flame_name, att_str, flam3_name_len);
373 i = (int)strlen(cp->flame_name)-1;
374 while(i-->0) {
375 if (isspace(cp->flame_name[i]))
376 cp->flame_name[i] = '_';
377 }
378
379 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"palette")) {
380 cp->palette_index = flam3_atoi(att_str);
381 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"size")) {
382 if (sscanf(att_str, "%d %d%1s", &cp->width, &cp->height, tmps) != 2) {
383 fprintf(stderr,"error: invalid size attribute '%s'\n",att_str);
384 xmlFree(att_str);
385 return(1);
386 }
387 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"center")) {
388 if (sscanf(att_str, "%lf %lf%1s", &cp->center[0], &cp->center[1], tmps) != 2) {
389 fprintf(stderr,"error: invalid center attribute '%s'\n",att_str);
390 xmlFree(att_str);
391 return(1);
392 }
393 cp->rot_center[0] = cp->center[0];
394 cp->rot_center[1] = cp->center[1];
395 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"scale")) {
396 cp->pixels_per_unit = flam3_atof(att_str);
397 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"rotate")) {
398 cp->rotate = flam3_atof(att_str);
399 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"zoom")) {
400 cp->zoom = flam3_atof(att_str);
401 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"oversample")) {
402 cp->spatial_oversample = flam3_atoi(att_str);
403 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"supersample")) {
404 cp->spatial_oversample = flam3_atoi(att_str);
405 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"filter")) {
406 cp->spatial_filter_radius = flam3_atof(att_str);
407 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"filter_shape")) {
408 if (!strcmp("gaussian", att_str))
409 cp->spatial_filter_select = flam3_gaussian_kernel;
410 else if (!strcmp("hermite", att_str))
411 cp->spatial_filter_select = flam3_hermite_kernel;
412 else if (!strcmp("box", att_str))
413 cp->spatial_filter_select = flam3_box_kernel;
414 else if (!strcmp("triangle", att_str))
415 cp->spatial_filter_select = flam3_triangle_kernel;
416 else if (!strcmp("bell", att_str))
417 cp->spatial_filter_select = flam3_bell_kernel;
418 else if (!strcmp("bspline", att_str))
419 cp->spatial_filter_select = flam3_b_spline_kernel;
420 else if (!strcmp("mitchell", att_str))
421 cp->spatial_filter_select = flam3_mitchell_kernel;
422 else if (!strcmp("blackman", att_str))
423 cp->spatial_filter_select = flam3_blackman_kernel;
424 else if (!strcmp("catrom", att_str))
425 cp->spatial_filter_select = flam3_catrom_kernel;
426 else if (!strcmp("hanning", att_str))
427 cp->spatial_filter_select = flam3_hanning_kernel;
428 else if (!strcmp("hamming", att_str))
429 cp->spatial_filter_select = flam3_hamming_kernel;
430 else if (!strcmp("lanczos3", att_str))
431 cp->spatial_filter_select = flam3_lanczos3_kernel;
432 else if (!strcmp("lanczos2", att_str))
433 cp->spatial_filter_select = flam3_lanczos2_kernel;
434 else if (!strcmp("quadratic", att_str))
435 cp->spatial_filter_select = flam3_quadratic_kernel;
436 else
437 fprintf(stderr, "warning: unrecognized kernel shape %s. Using gaussian.\n", att_str);
438
439 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"temporal_filter_type")) {
440 if (!strcmp("box", att_str))
441 cp->temporal_filter_type = flam3_temporal_box;
442 else if (!strcmp("gaussian", att_str))
443 cp->temporal_filter_type = flam3_temporal_gaussian;
444 else if (!strcmp("exp",att_str))
445 cp->temporal_filter_type = flam3_temporal_exp;
446 else
447 fprintf(stderr, "warning: unrecognized temporal filter %s. Using box.\n",att_str);
448 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"temporal_filter_width")) {
449 cp->temporal_filter_width = flam3_atof(att_str);
450 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"temporal_filter_exp")) {
451 cp->temporal_filter_exp = flam3_atof(att_str);
452 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"palette_mode")) {
453 if (!strcmp("step", att_str))
454 cp->palette_mode = flam3_palette_mode_step;
455 else if (!strcmp("linear", att_str))
456 cp->palette_mode = flam3_palette_mode_linear;
457 else
458 fprintf(stderr,"warning: unrecognized palette mode %s. Using step.\n",att_str);
459 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"quality")) {
460 cp->sample_density = flam3_atof(att_str);
461 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"passes")) {
462 cp->nbatches = flam3_atoi(att_str);
463 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"temporal_samples")) {
464 cp->ntemporal_samples = flam3_atoi(att_str);
465 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"background")) {
466 if (sscanf(att_str, "%lf %lf %lf%1s", &cp->background[0], &cp->background[1], &cp->background[2], tmps) != 3) {
467 fprintf(stderr,"error: invalid background attribute '%s'\n",att_str);
468 xmlFree(att_str);
469 return(1);
470 }
471 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"brightness")) {
472 cp->brightness = flam3_atof(att_str);
473 /* } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"contrast")) {
474 cp->contrast = flam3_atof(att_str);*/
475 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"gamma")) {
476 cp->gamma = flam3_atof(att_str);
477 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"highlight_power")) {
478 cp->highlight_power = atof(att_str);
479 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"vibrancy")) {
480 cp->vibrancy = flam3_atof(att_str);
481 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"hue")) {
482 cp->hue_rotation = fmod(flam3_atof(att_str), 1.0);
483 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"estimator_radius")) {
484 cp->estimator = flam3_atof(att_str);
485 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"estimator_minimum")) {
486 cp->estimator_minimum = flam3_atof(att_str);
487 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"estimator_curve")) {
488 cp->estimator_curve = flam3_atof(att_str);
489 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"gamma_threshold")) {
490 cp->gam_lin_thresh = flam3_atof(att_str);
491 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"soloxform")) {
492 solo_xform = flam3_atof(att_str);
493 }
494
495 xmlFree(att_str);
496
497 }
498
499 /* Finished with flame attributes. Now look at children of flame element. */
500 for (chld_node=flame_node->children; chld_node; chld_node = chld_node->next) {
501
502 /* Is this a color node? */
503 if (!xmlStrcmp(chld_node->name, (const xmlChar *)"color")) {
504 int index = -1;
505 double r=0.0,g=0.0,b=0.0,a=0.0;
506
507 /* Loop through the attributes of the color element */
508 att_ptr = chld_node->properties;
509
510 if (att_ptr==NULL) {
511 fprintf(stderr,"Error: No attributes for color element.\n");
512 return(1);
513 }
514
515 for (cur_att=att_ptr; cur_att; cur_att = cur_att->next) {
516
517 att_str = (char *) xmlGetProp(chld_node,cur_att->name);
518
519 a = 255.0;
520
521 if (!xmlStrcmp(cur_att->name, (const xmlChar *)"index")) {
522 index = flam3_atoi(att_str);
523 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"rgb")) {
524 if (sscanf(att_str, "%lf %lf %lf%1s", &r, &g, &b, tmps) != 3) {
525 fprintf(stderr,"error: invalid rgb attribute '%s'\n",att_str);
526 xmlFree(att_str);
527 return(1);
528 }
529 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"rgba")) {
530 if (sscanf(att_str, "%lf %lf %lf %lf%1s", &r, &g, &b, &a, tmps) != 4) {
531 fprintf(stderr,"error: invalid rgba attribute '%s'\n",att_str);
532 xmlFree(att_str);
533 return(1);
534 }
535 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"a")) {
536 if (sscanf(att_str, "%lf%1s", &a, tmps) != 1) {
537 fprintf(stderr,"error: invalid a attribute '%s'\n",att_str);
538 xmlFree(att_str);
539 return(1);
540 }
541 } else {
542 fprintf(stderr,"Error: Unknown color attribute '%s'\n",cur_att->name);
543 xmlFree(att_str);
544 return(1);
545 }
546
547 xmlFree(att_str);
548 }
549
550 if (index >= 0 && index <= 255) {
551 cp->palette[index].color[3] = a / 255.0;
552 /* Don't forget to premultiply the palette... */
553 cp->palette[index].color[0] = cp->palette[index].color[3] * r / 255.0;
554 cp->palette[index].color[1] = cp->palette[index].color[3] * g / 255.0;
555 cp->palette[index].color[2] = cp->palette[index].color[3] * b / 255.0;
556 cp->palette[index].index = index;
557 } else {
558 fprintf(stderr,"Error: Color element with bad/missing index attribute (%d)\n",index);
559 return(1);
560 }
561 } else if (!xmlStrcmp(chld_node->name, (const xmlChar *)"colors")) {
562
563 int count = 0;
564
565 /* Loop through the attributes of the colors element */
566 att_ptr = chld_node->properties;
567
568 if (att_ptr==NULL) {
569 fprintf(stderr,"Error: No attributes for colors element.\n");
570 return(1);
571 }
572
573 for (cur_att=att_ptr; cur_att; cur_att = cur_att->next) {
574
575 att_str = (char *) xmlGetProp(chld_node,cur_att->name);
576
577 if (!xmlStrcmp(cur_att->name, (const xmlChar *)"count")) {
578 count = flam3_atoi(att_str);
579 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"data")) {
580 if (flam3_parse_hexformat_colors(att_str, cp, count, -4) > 0) {
581 fprintf(stderr,"error parsing hexformatted colors\n");
582 xmlFree(att_str);
583 return(1);
584 }
585 } else {
586 fprintf(stderr,"Error: Unknown color attribute '%s'\n",cur_att->name);
587 xmlFree(att_str);
588 return(1);
589 }
590
591 xmlFree(att_str);
592 }
593
594
595 } else if (!xmlStrcmp(chld_node->name, (const xmlChar *)"palette")) {
596
597 /* This could be either the old form of palette or the new form */
598 /* Make sure BOTH are not specified, otherwise either are ok */
599 int numcolors=0;
600 int numbytes=0;
601 int old_format=0;
602 int new_format=0;
603 int index0, index1;
604 double hue0, hue1;
605 double blend = 0.5;
606 index0 = index1 = flam3_palette_random;
607 hue0 = hue1 = 0.0;
608
609 /* Loop through the attributes of the palette element */
610 att_ptr = chld_node->properties;
611
612 if (att_ptr==NULL) {
613 fprintf(stderr,"Error: No attributes for palette element.\n");
614 return(1);
615 }
616
617 for (cur_att=att_ptr; cur_att; cur_att = cur_att->next) {
618
619 att_str = (char *) xmlGetProp(chld_node,cur_att->name);
620
621 if (!xmlStrcmp(cur_att->name, (const xmlChar *)"index0")) {
622 old_format++;
623 index0 = flam3_atoi(att_str);
624 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"index1")) {
625 old_format++;
626 index1 = flam3_atoi(att_str);
627 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"hue0")) {
628 old_format++;
629 hue0 = flam3_atof(att_str);
630 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"hue1")) {
631 old_format++;
632 hue1 = flam3_atof(att_str);
633 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"blend")) {
634 old_format++;
635 blend = flam3_atof(att_str);
636 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"count")) {
637 new_format++;
638 numcolors = flam3_atoi(att_str);
639 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"format")) {
640 new_format++;
641 if (!strcmp(att_str,"RGB"))
642 numbytes=3;
643 else if (!strcmp(att_str,"RGBA"))
644 numbytes=4;
645 else {
646 fprintf(stderr,"Error: Unrecognized palette format string (%s)\n",att_str);
647 xmlFree(att_str);
648 return(1);
649 }
650 } else {
651 fprintf(stderr,"Error: Unknown palette attribute '%s'\n",cur_att->name);
652 xmlFree(att_str);
653 return(1);
654 }
655
656 xmlFree(att_str);
657 }
658
659 /* Old or new format? */
660 if (new_format>0 && old_format>0) {
661 fprintf(stderr,"Error: mixing of old and new palette tag syntax not allowed.\n");
662 return(1);
663 }
664
665 if (old_format>0)
666 interpolate_cmap(cp->palette, blend, index0, hue0, index1, hue1);
667 else {
668
669 char *pal_str;
670
671 /* Read formatted string from contents of tag */
672
673 pal_str = (char *) xmlNodeGetContent(chld_node);
674
675 if (flam3_parse_hexformat_colors(pal_str, cp, numcolors, numbytes) > 0) {
676 fprintf(stderr,"error reading hexformatted colors\n");
677 xmlFree(pal_str);
678 return(1);
679 }
680
681 xmlFree(pal_str);
682 }
683 } else if (!xmlStrcmp(chld_node->name, (const xmlChar *)"symmetry")) {
684
685 int kind=0;
686 int bef,aft;
687
688 /* Loop through the attributes of the symmetry element */
689 att_ptr = chld_node->properties;
690
691 if (att_ptr==NULL) {
692 fprintf(stderr,"Error: No attributes for symmetry element.\n");
693 return(1);
694 }
695
696 for (cur_att=att_ptr; cur_att; cur_att = cur_att->next) {
697
698 att_str = (char *) xmlGetProp(chld_node,cur_att->name);
699
700 if (!xmlStrcmp(cur_att->name, (const xmlChar *)"kind")) {
701 kind = flam3_atoi(att_str);
702 } else {
703 fprintf(stderr,"Error: Unknown symmetry attribute '%s'\n",cur_att->name);
704 xmlFree(att_str);
705 return(1);
706 }
707
708 xmlFree(att_str);
709 }
710
711 bef = cp->num_xforms;
712 flam3_add_symmetry(cp,kind);
713 aft = cp->num_xforms;
714 num_std_xforms += (aft-bef);
715
716
717 } else if (!xmlStrcmp(chld_node->name, (const xmlChar *)"xform") ||
718 !xmlStrcmp(chld_node->name, (const xmlChar *)"finalxform")) {
719
720 int xf = cp->num_xforms;
721
722 if (!xmlStrcmp(chld_node->name, (const xmlChar *)"finalxform")) {
723
724 if (cp->final_xform_index >=0) {
725 fprintf(stderr,"Error: Cannot specify more than one final xform.\n");
726 return(1);
727 }
728
729 flam3_add_xforms(cp, 1, 0, 1);
730 cp->xform[xf].var[0]=0.0;
731 cp->final_xform_index = xf;
732 /* Now, if present, the xform enable defaults to on */
733 cp->final_xform_enable = 1;
734
735 } else {
736
737 /* Add one to the counter */
738 flam3_add_xforms(cp, 1, 0, 0);
739
740 /* If there was already a final xform, we have to change xf to point to the second to last xform */
741 if (cp->final_xform_index>=0)
742 xf--;
743
744 cp->xform[xf].var[0]=0.0;
745 num_std_xforms++;
746
747 }
748
749 if (parse_xform_xml(chld_node, &(cp->xform[xf]), &num_xaos, &xaos, num_std_xforms, 0) != 0)
750 return(1);
751
752 if (cp->final_xform_index == xf && cp->xform[xf].density != 0.0) {
753 fprintf(stderr,"Error: Final xforms should not have weight specified.\n");
754 return(1);
755 }
756
757 /* Check for non-zero motion_* params */
758 if (cp->xform[xf].motion_freq != 0 || cp->xform[xf].motion_func != 0) {
759 fprintf(stderr,"Error: Motion parameters should not be specified in xforms.\n");
760 return(1);
761 }
762
763
764 /* Motion Language: Check the xform element for children - should be named 'motion'. */
765 for (motion_node=chld_node->children; motion_node; motion_node = motion_node->next) {
766
767 if (!xmlStrcmp(motion_node->name, (const xmlChar *)"motion")) {
768
769 int nm = cp->xform[xf].num_motion;
770
771 /* Add motion element to xform */
772 flam3_add_motion_element( &cp->xform[xf] );
773
774 /* Read motion xml */
775 if (parse_xform_xml(motion_node, &(cp->xform[xf].motion[nm]), NULL, NULL, 0, 1) != 0)
776 return(1);
777
778 }
779
780 }
781
782 } else if (!xmlStrcmp(chld_node->name, (const xmlChar *)"edit")) {
783
784 /* Create a new XML document with this edit node as the root node */
785 cp->edits = xmlNewDoc( (const xmlChar *)"1.0");
786 edit_node = xmlCopyNode( chld_node, 1 );
787 xmlDocSetRootElement(cp->edits, edit_node);
788
789 }
790 } /* Done parsing flame element. */
791
792 num_std_xforms++;
793
794 for (i=0;i<num_std_xforms;i++) {
795
796 /* Adjust opacity with solo xform setting */
797 if (solo_xform>=0 && i!=solo_xform)
798 cp->xform[i].opacity = 0.0;
799
800 }
801
802 /* Set the chaos array entries with the values in the xaos list */
803 for (i=0;i<num_xaos;i++)
804 cp->chaos[xaos[i].from][xaos[i].to] = xaos[i].scalar;
805
806 free(xaos);
807
808 /* If there is a final xform in this cp, move it to the end of the list */
809 if (cp->final_xform_index >=0 && cp->final_xform_index != (cp->num_xforms-1)) {
810 /* Make a copy of the final xform */
811 tmpcpy = cp->xform[cp->final_xform_index];
812
813 /* Move each other xform up one */
814 for (i=cp->final_xform_index+1;i<cp->num_xforms;i++)
815 cp->xform[i-1] = cp->xform[i];
816
817 /* Put the final at the end */
818 cp->xform[cp->num_xforms-1] = tmpcpy;
819
820 cp->final_xform_index = cp->num_xforms - 1;
821 }
822
823 /* Check for bad parse */
824 if (flam3_conversion_failed) {
825 fprintf(stderr,"error: parsing a double or int attribute's value.\n");
826 return(1);
827 }
828
829 return(0);
830
831 }
832
parse_xform_xml(xmlNode * chld_node,flam3_xform * this_xform,int * num_xaos,flam3_chaos_entry ** xaos,int numstd,int motionxf)833 int parse_xform_xml(xmlNode *chld_node,flam3_xform *this_xform, int *num_xaos,
834 flam3_chaos_entry **xaos, int numstd, int motionxf) {
835
836 xmlAttrPtr att_ptr, cur_att;
837 char *att_str, *cpy;
838 char tmps[2];
839 int j,k;
840
841 /* Loop through the attributes of the xform element */
842 att_ptr = chld_node->properties;
843
844 if (att_ptr==NULL) {
845 fprintf(stderr,"Error: No attributes for element.\n");
846 return(1);
847 }
848
849 for (cur_att=att_ptr; cur_att; cur_att = cur_att->next) {
850
851 att_str = (char *) xmlGetProp(chld_node,cur_att->name);
852
853 cpy = att_str;
854 if (!xmlStrcmp(cur_att->name, (const xmlChar *)"weight")) {
855 this_xform->density = flam3_atof(att_str);
856 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"symmetry")) {
857 /* Deprecated. Set both color_speed and animate to this value. */
858 this_xform->color_speed = (1.0-flam3_atof(att_str))/2.0;
859 this_xform->animate = flam3_atof(att_str)>0 ? 0 : 1;
860 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"color_speed")) {
861 this_xform->color_speed = flam3_atof(att_str);
862 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"animate")) {
863 this_xform->animate = flam3_atof(att_str);
864 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"motion_frequency")) {
865 this_xform->motion_freq = flam3_atoi(att_str);
866 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"motion_function")) {
867 if (!strcmp("sin", att_str)) {
868 this_xform->motion_func = MOTION_SIN;
869 } else if (!strcmp("triangle",att_str)) {
870 this_xform->motion_func = MOTION_TRIANGLE;
871 } else if (!strcmp("hill",att_str)) {
872 this_xform->motion_func = MOTION_HILL;
873 } else {
874 fprintf(stderr,"Error: unknown motion function '%s'\n",att_str);
875 xmlFree(att_str);
876 return(1);
877 }
878
879 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"color")) {
880 double tmpc1;
881 this_xform->color = 0.0;
882 /* Try two coords first */
883 if (sscanf(att_str, "%lf %lf%1s", &this_xform->color, &tmpc1, tmps) != 2) {
884 /* Try one color */
885 if (sscanf(att_str, "%lf%1s", &this_xform->color,tmps) != 1) {
886 fprintf(stderr,"Error: malformed xform color attribute '%s'\n",att_str);
887 xmlFree(att_str);
888 return(1);
889 }
890 }
891 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"var1")) {
892 for (j=0; j < flam3_nvariations; j++) {
893 this_xform->var[j] = 0.0;
894 }
895 j = flam3_atoi(att_str);
896
897 if (j < 0 || j >= flam3_nvariations) {
898 fprintf(stderr,"Error: Bad variation (%d)\n",j);
899 xmlFree(att_str);
900 return(1);
901 }
902
903 this_xform->var[j] = 1.0;
904 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"var")) {
905 for (j=0; j < flam3_nvariations; j++) {
906 char *cpy2;
907 errno=0;
908 this_xform->var[j] = strtod(cpy, &cpy2);
909 if (errno != 0 || cpy==cpy2) {
910 fprintf(stderr,"error: bad value in var attribute '%s'\n",att_str);
911 xmlFree(att_str);
912 return(1);
913 }
914 cpy=cpy2;
915 }
916
917 if (cpy != att_str+strlen(att_str)) {
918 fprintf(stderr,"error: extra chars at the end of var attribute '%s'\n",att_str);
919 xmlFree(att_str);
920 return(1);
921 }
922 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"chaos")) {
923 /* Chaos scalars */
924
925 char *tok;
926 double scal;
927 int toi=0;
928
929 if (motionxf==1) {
930 fprintf(stderr,"error: motion element cannot have a chaos attribute.\n");
931 xmlFree(att_str);
932 return(1);
933 }
934
935 /* The att string contains at least one value, delimited by a space */
936 tok = strtok(cpy," ");
937 while (tok!=NULL) {
938 scal = flam3_atof(tok);
939
940 /* Skip 1.0 entries */
941 if (scal==1.0) {
942 toi++;
943 tok = strtok(NULL," ");
944 continue;
945 }
946
947 /* Realloc the xaos list */
948 *xaos = realloc((*xaos),(*num_xaos+1) * sizeof(flam3_chaos_entry));
949
950 /* Populate the xaos list */
951 (*xaos)[*num_xaos].from = numstd;
952 (*xaos)[*num_xaos].to = toi;
953 (*xaos)[*num_xaos].scalar = scal;
954 toi++;
955 (*num_xaos)++;
956
957 /* Get the next token */
958 tok = strtok(NULL," ");
959 }
960 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"plotmode")) {
961
962 if (motionxf==1) {
963 fprintf(stderr,"error: motion element cannot have a plotmode attribute.\n");
964 xmlFree(att_str);
965 return(1);
966 }
967
968 if (!strcmp("off", att_str))
969 this_xform->opacity = 0.0;
970 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"opacity")) {
971 this_xform->opacity = flam3_atof(att_str);
972
973 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"coefs")) {
974 for (k=0; k<3; k++) {
975 for (j=0; j<2; j++) {
976 char *cpy2;
977 errno = 0;
978 this_xform->c[k][j] = strtod(cpy, &cpy2);
979 if (errno != 0 || cpy==cpy2) {
980 fprintf(stderr,"error: bad value in coefs attribute '%s'\n",att_str);
981 xmlFree(att_str);
982 return(1);
983 }
984 cpy=cpy2;
985 }
986 }
987 if (cpy != att_str+strlen(att_str)) {
988 fprintf(stderr,"error: extra chars at the end of coefs attribute '%s'\n",att_str);
989 xmlFree(att_str);
990 return(1);
991 }
992 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"post")) {
993 for (k = 0; k < 3; k++) {
994 for (j = 0; j < 2; j++) {
995 char *cpy2;
996 errno = 0;
997 this_xform->post[k][j] = strtod(cpy, &cpy2);
998 if (errno != 0 || cpy==cpy2) {
999 fprintf(stderr,"error: bad value in post attribute '%s'\n",att_str);
1000 xmlFree(att_str);
1001 return(1);
1002 }
1003 cpy=cpy2;
1004 }
1005 }
1006 if (cpy != att_str+strlen(att_str)) {
1007 fprintf(stderr,"error: extra chars at end of post attribute '%s'\n",att_str);
1008 xmlFree(att_str);
1009 return(1);
1010 }
1011 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"blob_low")) {
1012 this_xform->blob_low = flam3_atof(att_str);
1013 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"blob_high")) {
1014 this_xform->blob_high = flam3_atof(att_str);
1015 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"blob_waves")) {
1016 this_xform->blob_waves = flam3_atof(att_str);
1017 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"pdj_a")) {
1018 this_xform->pdj_a = flam3_atof(att_str);
1019 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"pdj_b")) {
1020 this_xform->pdj_b = flam3_atof(att_str);
1021 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"pdj_c")) {
1022 this_xform->pdj_c = flam3_atof(att_str);
1023 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"pdj_d")) {
1024 this_xform->pdj_d = flam3_atof(att_str);
1025 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"fan2_x")) {
1026 this_xform->fan2_x = flam3_atof(att_str);
1027 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"fan2_y")) {
1028 this_xform->fan2_y = flam3_atof(att_str);
1029 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"rings2_val")) {
1030 this_xform->rings2_val = flam3_atof(att_str);
1031 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"perspective_angle")) {
1032 this_xform->perspective_angle = flam3_atof(att_str);
1033 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"perspective_dist")) {
1034 this_xform->perspective_dist = flam3_atof(att_str);
1035 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"julian_power")) {
1036 this_xform->julian_power = flam3_atof(att_str);
1037 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"julian_dist")) {
1038 this_xform->julian_dist = flam3_atof(att_str);
1039 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"juliascope_power")) {
1040 this_xform->juliascope_power = flam3_atof(att_str);
1041 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"juliascope_dist")) {
1042 this_xform->juliascope_dist = flam3_atof(att_str);
1043 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"radial_blur_angle")) {
1044 this_xform->radial_blur_angle = flam3_atof(att_str);
1045 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"pie_slices")) {
1046 this_xform->pie_slices = flam3_atof(att_str);
1047 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"pie_rotation")) {
1048 this_xform->pie_rotation = flam3_atof(att_str);
1049 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"pie_thickness")) {
1050 this_xform->pie_thickness = flam3_atof(att_str);
1051 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"ngon_sides")) {
1052 this_xform->ngon_sides = flam3_atof(att_str);
1053 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"ngon_power")) {
1054 this_xform->ngon_power = flam3_atof(att_str);
1055 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"ngon_circle")) {
1056 this_xform->ngon_circle = flam3_atof(att_str);
1057 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"ngon_corners")) {
1058 this_xform->ngon_corners = flam3_atof(att_str);
1059 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"curl_c1")) {
1060 this_xform->curl_c1 = flam3_atof(att_str);
1061 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"curl_c2")) {
1062 this_xform->curl_c2 = flam3_atof(att_str);
1063 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"rectangles_x")) {
1064 this_xform->rectangles_x = flam3_atof(att_str);
1065 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"rectangles_y")) {
1066 this_xform->rectangles_y = flam3_atof(att_str);
1067 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"amw_amp")) {
1068 this_xform->amw_amp = flam3_atof(att_str);
1069 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"disc2_rot")) {
1070 this_xform->disc2_rot = flam3_atof(att_str);
1071 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"disc2_twist")) {
1072 this_xform->disc2_twist = flam3_atof(att_str);
1073 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"super_shape_rnd")) {
1074 this_xform->super_shape_rnd = flam3_atof(att_str);
1075 /* Limit to [0,1] */
1076 if (this_xform->super_shape_rnd<0)
1077 this_xform->super_shape_rnd=0;
1078 else if (this_xform->super_shape_rnd>1)
1079 this_xform->super_shape_rnd=1;
1080 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"super_shape_m")) {
1081 this_xform->super_shape_m = flam3_atof(att_str);
1082 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"super_shape_n1")) {
1083 this_xform->super_shape_n1 = flam3_atof(att_str);
1084 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"super_shape_n2")) {
1085 this_xform->super_shape_n2 = flam3_atof(att_str);
1086 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"super_shape_n3")) {
1087 this_xform->super_shape_n3 = flam3_atof(att_str);
1088 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"super_shape_holes")) {
1089 this_xform->super_shape_holes = flam3_atof(att_str);
1090 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"flower_petals")) {
1091 this_xform->flower_petals = flam3_atof(att_str);
1092 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"flower_holes")) {
1093 this_xform->flower_holes = flam3_atof(att_str);
1094 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"conic_eccentricity")) {
1095 this_xform->conic_eccentricity = flam3_atof(att_str);
1096 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"conic_holes")) {
1097 this_xform->conic_holes = flam3_atof(att_str);
1098 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"parabola_height")) {
1099 this_xform->parabola_height = flam3_atof(att_str);
1100 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"parabola_width")) {
1101 this_xform->parabola_width = flam3_atof(att_str);
1102 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"bent2_x")) {
1103 this_xform->bent2_x = flam3_atof(att_str);
1104 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"bent2_y")) {
1105 this_xform->bent2_y = flam3_atof(att_str);
1106 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"bipolar_shift")) {
1107 this_xform->bipolar_shift = flam3_atof(att_str);
1108 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"cell_size")) {
1109 this_xform->cell_size = flam3_atof(att_str);
1110 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"cpow_i")) {
1111 this_xform->cpow_i = flam3_atof(att_str);
1112 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"cpow_r")) {
1113 this_xform->cpow_r = flam3_atof(att_str);
1114 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"cpow_power")) {
1115 this_xform->cpow_power = flam3_atof(att_str);
1116 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"curve_xamp")) {
1117 this_xform->curve_xamp = flam3_atof(att_str);
1118 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"curve_yamp")) {
1119 this_xform->curve_yamp = flam3_atof(att_str);
1120 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"curve_xlength")) {
1121 this_xform->curve_xlength = flam3_atof(att_str);
1122 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"curve_ylength")) {
1123 this_xform->curve_ylength = flam3_atof(att_str);
1124 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"escher_beta")) {
1125 this_xform->escher_beta = flam3_atof(att_str);
1126 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"lazysusan_x")) {
1127 this_xform->lazysusan_x = flam3_atof(att_str);
1128 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"lazysusan_y")) {
1129 this_xform->lazysusan_y = flam3_atof(att_str);
1130 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"lazysusan_spin")) {
1131 this_xform->lazysusan_spin = flam3_atof(att_str);
1132 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"lazysusan_space")) {
1133 this_xform->lazysusan_space = flam3_atof(att_str);
1134 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"lazysusan_twist")) {
1135 this_xform->lazysusan_twist = flam3_atof(att_str);
1136 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"modulus_x")) {
1137 this_xform->modulus_x = flam3_atof(att_str);
1138 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"modulus_y")) {
1139 this_xform->modulus_y = flam3_atof(att_str);
1140 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"oscilloscope_separation")) {
1141 this_xform->oscope_separation = flam3_atof(att_str);
1142 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"oscilloscope_frequency")) {
1143 this_xform->oscope_frequency = flam3_atof(att_str);
1144 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"oscilloscope_amplitude")) {
1145 this_xform->oscope_amplitude = flam3_atof(att_str);
1146 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"oscilloscope_damping")) {
1147 this_xform->oscope_damping = flam3_atof(att_str);
1148 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"oscope_separation")) {
1149 this_xform->oscope_separation = flam3_atof(att_str);
1150 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"oscope_frequency")) {
1151 this_xform->oscope_frequency = flam3_atof(att_str);
1152 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"oscope_amplitude")) {
1153 this_xform->oscope_amplitude = flam3_atof(att_str);
1154 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"oscope_damping")) {
1155 this_xform->oscope_damping = flam3_atof(att_str);
1156 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"popcorn2_x")) {
1157 this_xform->popcorn2_x = flam3_atof(att_str);
1158 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"popcorn2_y")) {
1159 this_xform->popcorn2_y = flam3_atof(att_str);
1160 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"popcorn2_c")) {
1161 this_xform->popcorn2_c = flam3_atof(att_str);
1162 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"separation_x")) {
1163 this_xform->separation_x = flam3_atof(att_str);
1164 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"separation_xinside")) {
1165 this_xform->separation_xinside = flam3_atof(att_str);
1166 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"separation_y")) {
1167 this_xform->separation_y = flam3_atof(att_str);
1168 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"separation_yinside")) {
1169 this_xform->separation_yinside = flam3_atof(att_str);
1170 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"split_xsize")) {
1171 this_xform->split_xsize = flam3_atof(att_str);
1172 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"split_ysize")) {
1173 this_xform->split_ysize = flam3_atof(att_str);
1174 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"splits_x")) {
1175 this_xform->splits_x = flam3_atof(att_str);
1176 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"splits_y")) {
1177 this_xform->splits_y = flam3_atof(att_str);
1178 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"stripes_space")) {
1179 this_xform->stripes_space = flam3_atof(att_str);
1180 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"stripes_warp")) {
1181 this_xform->stripes_warp = flam3_atof(att_str);
1182 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_angle")) {
1183 this_xform->wedge_angle = flam3_atof(att_str);
1184 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_hole")) {
1185 this_xform->wedge_hole = flam3_atof(att_str);
1186 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_count")) {
1187 this_xform->wedge_count = flam3_atof(att_str);
1188 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_swirl")) {
1189 this_xform->wedge_swirl = flam3_atof(att_str);
1190 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_julia_angle")) {
1191 this_xform->wedge_julia_angle = flam3_atof(att_str);
1192 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_julia_count")) {
1193 this_xform->wedge_julia_count = flam3_atof(att_str);
1194 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_julia_power")) {
1195 this_xform->wedge_julia_power = flam3_atof(att_str);
1196 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_julia_dist")) {
1197 this_xform->wedge_julia_dist = flam3_atof(att_str);
1198 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_sph_angle")) {
1199 this_xform->wedge_sph_angle = flam3_atof(att_str);
1200 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_sph_hole")) {
1201 this_xform->wedge_sph_hole = flam3_atof(att_str);
1202 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_sph_count")) {
1203 this_xform->wedge_sph_count = flam3_atof(att_str);
1204 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"wedge_sph_swirl")) {
1205 this_xform->wedge_sph_swirl = flam3_atof(att_str);
1206 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"whorl_inside")) {
1207 this_xform->whorl_inside = flam3_atof(att_str);
1208 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"whorl_outside")) {
1209 this_xform->whorl_outside = flam3_atof(att_str);
1210 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"waves2_scalex")) {
1211 this_xform->waves2_scalex = flam3_atof(att_str);
1212 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"waves2_scaley")) {
1213 this_xform->waves2_scaley = flam3_atof(att_str);
1214 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"waves2_freqx")) {
1215 this_xform->waves2_freqx = flam3_atof(att_str);
1216 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"waves2_freqy")) {
1217 this_xform->waves2_freqy = flam3_atof(att_str);
1218 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"auger_freq")) {
1219 this_xform->auger_freq = flam3_atof(att_str);
1220 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"auger_weight")) {
1221 this_xform->auger_weight = flam3_atof(att_str);
1222 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"auger_sym")) {
1223 this_xform->auger_sym = flam3_atof(att_str);
1224 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"auger_scale")) {
1225 this_xform->auger_scale = flam3_atof(att_str);
1226 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"flux_spread")) {
1227 this_xform->flux_spread = flam3_atof(att_str);
1228 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"Re_A") || !xmlStrcmp(cur_att->name, (const xmlChar *)"mobius_re_a")) {
1229 this_xform->mobius_re_a = flam3_atof(att_str);
1230 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"Re_B") || !xmlStrcmp(cur_att->name, (const xmlChar *)"mobius_re_b")) {
1231 this_xform->mobius_re_b = flam3_atof(att_str);
1232 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"Re_C") || !xmlStrcmp(cur_att->name, (const xmlChar *)"mobius_re_c")) {
1233 this_xform->mobius_re_c = flam3_atof(att_str);
1234 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"Re_D") || !xmlStrcmp(cur_att->name, (const xmlChar *)"mobius_re_d")) {
1235 this_xform->mobius_re_d = flam3_atof(att_str);
1236 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"Im_A") || !xmlStrcmp(cur_att->name, (const xmlChar *)"mobius_im_a")) {
1237 this_xform->mobius_im_a = flam3_atof(att_str);
1238 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"Im_B") || !xmlStrcmp(cur_att->name, (const xmlChar *)"mobius_im_b")) {
1239 this_xform->mobius_im_b = flam3_atof(att_str);
1240 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"Im_C") || !xmlStrcmp(cur_att->name, (const xmlChar *)"mobius_im_c")) {
1241 this_xform->mobius_im_c = flam3_atof(att_str);
1242 } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"Im_D") || !xmlStrcmp(cur_att->name, (const xmlChar *)"mobius_im_d")) {
1243 this_xform->mobius_im_d = flam3_atof(att_str);
1244 } else {
1245 int v = var2n((char *) cur_att->name);
1246 if (v != flam3_variation_none)
1247 this_xform->var[v] = flam3_atof(att_str);
1248 else
1249 fprintf(stderr,"Warning: unrecognized variation %s. Ignoring.\n",(char *)cur_att->name);
1250 }
1251
1252
1253 xmlFree(att_str);
1254 }
1255 return(0);
1256 }
1257
flam3_edit_print(FILE * f,xmlNodePtr editNode,int tabs,int formatting)1258 void flam3_edit_print(FILE *f, xmlNodePtr editNode, int tabs, int formatting) {
1259
1260 char *tab_string = " ";
1261 int ti,strl;
1262 xmlAttrPtr att_ptr=NULL,cur_att=NULL;
1263 xmlNodePtr chld_ptr=NULL, cur_chld=NULL;
1264 int indent_printed = 0;
1265 char *ai;
1266 int tablim = argi("print_edit_depth",0);
1267
1268 char *att_str,*cont_str,*cpy_string;
1269
1270 if (tablim>0 && tabs>tablim)
1271 return;
1272
1273 /* If this node is an XML_ELEMENT_NODE, print it and it's attributes */
1274 if (editNode->type==XML_ELEMENT_NODE) {
1275
1276 /* Print the node at the tab specified */
1277 if (formatting) {
1278 for (ti=0;ti<tabs;ti++)
1279 fprintf(f,"%s",tab_string);
1280 }
1281
1282 fprintf(f,"<%s",editNode->name);
1283
1284 /* This can either be an edit node or a sheep node */
1285 /* If it's an edit node, add one to the tab */
1286 if (!xmlStrcmp(editNode->name, (const xmlChar *)"edit")) {
1287 tabs ++;
1288 }
1289
1290 /* Print the attributes */
1291 att_ptr = editNode->properties;
1292
1293 for (cur_att = att_ptr; cur_att; cur_att = cur_att->next) {
1294
1295 att_str = (char *) xmlGetProp(editNode,cur_att->name);
1296 fprintf(f," %s=\"%s\"",cur_att->name,att_str);
1297 xmlFree(att_str);
1298 }
1299
1300 /* Does this node have children? */
1301 if (!editNode->children || (tablim>0 && tabs>tablim)) {
1302 /* Close the tag and subtract the tab */
1303 fprintf(f,"/>");
1304 if (formatting)
1305 fprintf(f,"\n");
1306 tabs--;
1307 } else {
1308
1309 /* Close the tag */
1310 fprintf(f,">");
1311
1312 if (formatting)
1313 fprintf(f,"\n");
1314
1315 /* Loop through the children and print them */
1316 chld_ptr = editNode->children;
1317
1318 indent_printed = 0;
1319
1320 for (cur_chld=chld_ptr; cur_chld; cur_chld = cur_chld->next) {
1321
1322 /* If child is an element, indent first and then print it. */
1323 if (cur_chld->type==XML_ELEMENT_NODE &&
1324 (!xmlStrcmp(cur_chld->name, (const xmlChar *)"edit") ||
1325 (!xmlStrcmp(cur_chld->name, (const xmlChar *)"sheep")))) {
1326
1327 if (indent_printed) {
1328 indent_printed = 0;
1329 fprintf(f,"\n");
1330 }
1331
1332 flam3_edit_print(f, cur_chld, tabs, 1);
1333
1334 } else {
1335
1336 /* Child is a text node. We don't want to indent more than once. */
1337 if (xmlIsBlankNode(cur_chld))
1338 continue;
1339
1340 if (indent_printed==0 && formatting==1) {
1341 for (ti=0;ti<tabs;ti++)
1342 fprintf(f,"%s",tab_string);
1343 indent_printed = 1;
1344 }
1345
1346 /* Print nodes without formatting. */
1347 flam3_edit_print(f, cur_chld, tabs, 0);
1348
1349 }
1350 }
1351
1352 if (indent_printed && formatting)
1353 fprintf(f,"\n");
1354
1355 /* Tab out. */
1356 tabs --;
1357 if (formatting) {
1358 for (ti=0;ti<tabs;ti++)
1359 fprintf(f,"%s",tab_string);
1360 }
1361
1362 /* Close the tag */
1363 fprintf(f,"</%s>",editNode->name);
1364
1365 if (formatting) {
1366 fprintf(f,"\n");
1367 }
1368 }
1369
1370 } else if (editNode->type==XML_TEXT_NODE) {
1371
1372 /* Print text node */
1373 cont_str = (char *) xmlNodeGetContent(editNode);
1374 cpy_string = &(cont_str[0]);
1375 while (isspace(*cpy_string))
1376 cpy_string++;
1377
1378 strl = (int)strlen(cont_str)-1;
1379
1380 while (isspace(cont_str[strl]))
1381 strl--;
1382
1383 cont_str[strl+1] = 0;
1384
1385 fprintf(f,"%s",cpy_string);
1386
1387 }
1388 }
1389
1390