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 
20 #include "private.h"
21 #include "img.h"
22 #include "isaacs.h"
23 
main(int argc,char ** argv)24 int main(int argc, char **argv) {
25   char *ai, *fname;
26   char flamename[256];
27   char *prefix = args("prefix", "");
28   int first_frame = argi("begin", 0);
29   int last_frame = argi("end", 0);
30   int frame_time = argi("time", 0);
31   int dtime = argi("dtime", 1);
32   int do_fields = argi("fields", 0);
33   int write_genome = argi("write_genome",0);
34   double qs = argf("qs", 1.0);
35   double ss = argf("ss", 1.0);
36   char *format = getenv("format");
37   int verbose = argi("verbose", 1);
38   int transparency = argi("transparency", 0);
39   int bits = argi("bits", 33);
40   int sub_batch_size = argi("sub_batch_size", 10000);
41   int bpc = argi("bpc",8);
42   int earlyclip = argi("earlyclip",0);
43   int ftime, channels;
44   unsigned char *image;
45   flam3_genome *cps,center_cp;
46   int i, ncps = 0;
47   char *inf = getenv("in");
48   double pixel_aspect = argf("pixel_aspect", 1.0);
49   int num_threads = argi("nthreads",0);
50   FILE *in,*fp,*genfp;
51   flam3_frame f;
52   flam3_img_comments fpc;
53   stat_struct stats,stats2;
54 
55   char badval_string[64];
56   char numiter_string[64];
57   char rtime_string[64];
58 
59 #ifdef WIN32
60 
61   char *slashloc;
62   char exepath[256];
63   char palpath[256];
64   memset(exepath,0,256);
65   memset(palpath,0,256);
66    slashloc = strrchr(argv[0],'\\');
67 	if (NULL==slashloc) {
68 	   sprintf(palpath,"flam3_palettes=flam3-palettes.xml");
69 	} else {
70        strncpy(exepath,argv[0],slashloc-argv[0]+1);
71 	   sprintf(palpath,"flam3_palettes=%sflam3-palettes.xml",exepath);
72 	}
73 	putenv(palpath);
74 
75 #endif
76 
77 
78   memset(&center_cp,0, sizeof(flam3_genome));
79 
80   if (1 != argc) {
81       docstring();
82       exit(0);
83   }
84 
85    /* Init random number generators */
86    flam3_init_frame(&f);
87    flam3_srandom();
88 
89    /* Set the number of threads */
90    if (num_threads==0) {
91       num_threads = flam3_count_nthreads();
92       if (verbose > 1)
93          fprintf(stderr,"Automatically detected %d core(s)...\n",num_threads);
94    } else{
95       if (verbose)
96          fprintf(stderr,"Manually specified %d thread(s)...\n",num_threads);
97    }
98 
99   if (getenv("frame")) {
100     if (getenv("time")) {
101       fprintf(stderr, "cannot specify both time and frame.\n");
102       exit(1);
103     }
104     if (getenv("begin") || getenv("end")) {
105       fprintf(stderr, "cannot specify both frame and begin or end.\n");
106       exit(1);
107     }
108     first_frame = last_frame = atoi(getenv("frame"));
109   }
110 
111   if (getenv("time")) {
112     if (getenv("begin") || getenv("end")) {
113       fprintf(stderr, "cannot specify both time and begin or end.\n");
114       exit(1);
115     }
116     first_frame = last_frame = frame_time;
117   }
118 
119   if (NULL == format) format = "png";
120   if (strcmp(format, "jpg") &&
121       strcmp(format, "ppm") &&
122       strcmp(format, "png")) {
123       fprintf(stderr, "format must be either jpg, ppm, or png, not %s.\n", format);
124       exit(1);
125   }
126 
127 
128    if (pixel_aspect <= 0.0) {
129      fprintf(stderr, "pixel aspect ratio must be positive, not %g.\n",
130         pixel_aspect);
131      exit(1);
132    }
133 
134   if (inf)
135     in = fopen(inf, "rb");
136   else
137     in = stdin;
138   if (NULL == in) {
139     perror(inf);
140     exit(1);
141   }
142 
143   cps = flam3_parse_from_file(in, inf, flam3_defaults_on, &ncps);
144   if (inf)
145     fclose(in);
146   if (NULL == cps) {
147     fprintf(stderr," error reading genomes.\n");
148     exit(1);
149   }
150   if (0 == ncps) {
151     fprintf(stderr, "error: no genomes.\n");
152     exit(1);
153   }
154   for (i = 0; i < ncps; i++) {
155     cps[i].sample_density *= qs;
156     cps[i].height = (int)(cps[i].height * ss);
157     cps[i].width = (int)(cps[i].width * ss);
158     cps[i].pixels_per_unit *= ss;
159     if (cps[i].height<=0 || cps[i].width<=0) {
160        fprintf(stderr,"output image has dimension <=0, aborting.\n");
161        exit(1);
162     }
163     if (i > 0 && cps[i].time <= cps[i-1].time) {
164    fprintf(stderr, "error: control points must be sorted by time, but %g <= %g, index %d.\n",
165       cps[i].time, cps[i-1].time, i);
166    exit(1);
167     }
168     if ((cps[i].width != cps[0].width) ||
169    (cps[i].height != cps[0].height)) {
170       fprintf(stderr, "warning: flame %d at time %g size mismatch.  "
171          "(%d,%d) should be (%d,%d).\n",
172          i, cps[i].time,
173          cps[i].width, cps[i].height,
174          cps[0].width, cps[0].height);
175       cps[i].width = cps[0].width;
176       cps[i].height = cps[0].height;
177     }
178   }
179   if (!getenv("time") && !getenv("frame")) {
180     if (!getenv("begin")) {
181       first_frame = (int) cps[0].time;
182     }
183     if (!getenv("end")) {
184       last_frame = (int) cps[ncps-1].time - 1;
185       if (last_frame < first_frame) last_frame = first_frame;
186     }
187   }
188   channels = strcmp(format, "png") ? 3 : 4;
189 
190    /* Check for 16-bit-per-channel processing */
191    if ( (16 == bpc) && (strcmp(format,"png") != 0)) {
192 	fprintf(stderr,"Support for 16 bpc images is only present for the png format.\n");
193 	exit(1);
194    } else if (bpc != 8 && bpc != 16) {
195 	fprintf(stderr,"Unexpected bpc specified (%d)\n",bpc);
196 	exit(1);
197    }
198 
199 //  f.temporal_filter_radius = argf("blur", 0.5);
200   f.pixel_aspect_ratio = pixel_aspect;
201   f.genomes = cps;
202   f.ngenomes = ncps;
203   f.verbose = verbose;
204   f.bits = bits;
205   f.progress = 0;
206   f.earlyclip = earlyclip;
207   f.nthreads = num_threads;
208   f.sub_batch_size = sub_batch_size;
209 
210   if (16==bpc)
211      f.bytes_per_channel = 2;
212   else
213      f.bytes_per_channel = 1;
214 
215 
216   image = (void *) calloc((size_t)channels *
217 				   (size_t)cps[0].width *
218 				   (size_t)cps[0].height * f.bytes_per_channel, sizeof(char));
219 
220   if (dtime < 1) {
221     fprintf(stderr, "dtime must be positive, not %d.\n", dtime);
222     exit(1);
223   }
224 
225   for (ftime = first_frame; ftime <= last_frame; ftime += dtime) {
226     f.time = (double) ftime;
227 
228     if (verbose && ((last_frame-first_frame)/dtime) >= 1) {
229        fprintf(stderr, "time = %d/%d/%d\n", ftime, last_frame, dtime);
230     }
231 
232     if (do_fields) {
233 
234    if (flam3_render(&f, image, flam3_field_even, channels, transparency,&stats)) {
235       fprintf(stderr,"error rendering image: aborting.\n");
236       exit(1);
237    }
238    f.time += 0.5;
239    if (flam3_render(&f, image, flam3_field_odd, channels, transparency,&stats2)) {
240       fprintf(stderr,"error rendering image: aborting.\n");
241       exit(1);
242    }
243 
244    stats.badvals+=stats2.badvals;
245    stats.render_seconds+=stats2.render_seconds;
246    stats.num_iters+=stats2.num_iters;
247     } else {
248    if (flam3_render(&f, image, flam3_field_both, channels, transparency,&stats)) {
249       fprintf(stderr,"error rendering image: aborting.\n");
250       exit(1);
251    }
252     }
253 
254     if (getenv("out"))
255        fname = getenv("out");
256     else {
257        fname = malloc(strlen(prefix) + 20);
258        sprintf(fname, "%s%05d.%s", prefix, ftime, format);
259     }
260 
261     if (verbose)
262        fprintf(stderr, "writing %s...", fname);
263 
264     if (write_genome) {
265        sprintf(flamename,"%s.flam3",fname);
266 
267        /* get center genome */
268        flam3_interpolate(f.genomes, f.ngenomes, f.time, 0, &center_cp);
269 
270        /* write it out */
271        genfp = fopen(flamename,"w");
272        if (NULL == genfp) {
273            perror(flamename);
274            exit(1);
275        }
276 
277        flam3_print(genfp, &center_cp, NULL, flam3_print_edits);
278 
279        fclose(genfp);
280     }
281 
282     fp = fopen(fname, "wb");
283     if (NULL == fp) {
284        perror(fname);
285        exit(1);
286     }
287 
288     /* Get center cp for embedding in png file */
289     flam3_interpolate(f.genomes, f.ngenomes, f.time, 0, &center_cp);
290 
291     /* Convert to string */
292     fpc.genome = flam3_print_to_string(&center_cp);
293     sprintf(badval_string, "%g",stats.badvals/(double)stats.num_iters);
294     fpc.badvals = badval_string;
295     sprintf(numiter_string,"%g",(double)stats.num_iters);
296     fpc.numiters = numiter_string;
297     sprintf(rtime_string,"%d",stats.render_seconds);
298     fpc.rtime = rtime_string;
299 
300     if (!strcmp(format, "png")) {
301 
302        write_png(fp, image, cps[0].width, cps[0].height, &fpc, f.bytes_per_channel);
303 
304     } else if (!strcmp(format, "jpg")) {
305 
306        write_jpeg(fp, image, cps[0].width, cps[0].height, &fpc);
307 
308     } else {
309 	int size = 3 * cps[0].width * cps[0].height;
310        fprintf(fp, "P6\n");
311        fprintf(fp, "%d %d\n255\n", cps[0].width, cps[0].height);
312        if (size != fwrite(image, 1, size, fp)) {
313 	   perror(fname);
314        }
315     }
316 
317     /* Free string */
318     free(fpc.genome);
319 
320     clear_cp(&center_cp,0);
321 
322     fclose(fp);
323 
324     if (!getenv("out"))
325        free(fname);
326 
327   }
328 
329   for (i = 0; i < ncps; i++) {
330      xmlFreeDoc(cps[i].edits);
331      clear_cp(&cps[i],0);
332   }
333   free(cps);
334 
335   free(image);
336 
337   if (verbose)
338     fprintf(stderr, "done.\n");
339 
340   fflush(stderr);
341   return 0;
342 }
343