more updates
[synfig.git] / synfig-core / trunk / src / tool / main.cpp
1 /* === S I N F G =========================================================== */
2 /*!     \file main.cpp
3 **      \brief SINFG Tool
4 **
5 **      $Id: main.cpp,v 1.9 2005/01/23 04:41:10 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2002 Robert B. Quattlebaum Jr.
9 **
10 **      This software and associated documentation
11 **      are CONFIDENTIAL and PROPRIETARY property of
12 **      the above-mentioned copyright holder.
13 **
14 **      You may not copy, print, publish, or in any
15 **      other way distribute this software without
16 **      a prior written agreement with
17 **      the copyright holder.
18 **      \endlegal
19 */
20 /* ========================================================================= */
21
22 /* === H E A D E R S ======================================================= */
23
24 #ifdef USING_PCH
25 #       include "pch.h"
26 #else
27 #ifdef HAVE_CONFIG_H
28 #       include <config.h>
29 #endif
30
31 #include <iostream>
32 #include <ETL/stringf>
33 #include <list>
34 #include <ETL/clock>
35 #include <algorithm>
36
37 #include <sinfg/loadcanvas.h>
38 #include <sinfg/savecanvas.h>
39 #include <sinfg/target_scanline.h>
40 #include <sinfg/module.h>
41 #include <sinfg/importer.h>
42 #include <sinfg/layer.h>
43 #include <sinfg/canvas.h>
44 #include <sinfg/target.h>
45 #include <sinfg/time.h>
46 #include <sinfg/string.h>
47 #include <sinfg/paramdesc.h>
48 #include <sinfg/main.h>
49 #include <sinfg/guid.h>
50 #endif
51
52 using namespace std;
53 using namespace etl;
54 using namespace sinfg;
55
56 /* === M A C R O S ========================================================= */
57
58 enum exit_code
59 {
60         SINFGTOOL_OK                            =0,
61         SINFGTOOL_FILENOTFOUND          =1,
62         SINFGTOOL_BORRED                        =2,
63         SINFGTOOL_HELP                          =3,
64         SINFGTOOL_UNKNOWNARGUMENT       =4,     
65         SINFGTOOL_UNKNOWNERROR          =5,     
66         SINFGTOOL_INVALIDTARGET         =6,     
67         SINFGTOOL_RENDERFAILURE         =7,     
68         SINFGTOOL_BLANK                         =8,
69         SINFGTOOL_BADVERSION            =9
70 };
71
72 #ifndef VERSION
73 #define VERSION "unknown"
74 #define PACKAGE "sinfg-tool"
75 #endif
76
77 #ifdef DEFAULT_QUALITY
78 #undef DEFAULT_QUALITY
79 #endif
80
81 #define DEFAULT_QUALITY         2
82 #define VERBOSE_OUT(x) if(verbosity>=(x))std::cerr
83
84 /* === G L O B A L S ======================================================= */
85
86 const char *progname;
87 int verbosity=0;
88 bool be_quiet=false;
89 bool print_benchmarks=false;
90
91 /* === M E T H O D S ======================================================= */
92
93 class Progress : public sinfg::ProgressCallback
94 {
95         const char *program;
96         
97 public:
98         
99         Progress(const char *name):program(name) { }
100         
101         virtual bool
102         task(const String &task)
103         {
104                 VERBOSE_OUT(1)<<program<<": "<<task<<std::endl;
105                 return true;
106         }
107
108         virtual bool
109         error(const String &task)
110         {
111                 std::cerr<<program<<": "<<_("error")<<": "<<task<<std::endl;
112                 return true;
113         }
114
115         virtual bool
116         warning(const String &task)
117         {
118                 std::cerr<<program<<": "<<_("warning")<<": "<<task<<std::endl;
119                 return true;
120         }
121
122         virtual bool
123         amount_complete(int current, int total)
124         {
125                 return true;
126         }
127 };
128
129 class RenderProgress : public sinfg::ProgressCallback
130 {
131         string taskname;
132         
133         etl::clock clk;
134         int clk_scanline; // The scanline at which the clock was reset
135         etl::clock clk2;
136
137         float last_time;        
138 public:
139         
140         RenderProgress():clk_scanline(0) { }
141         
142         virtual bool
143         task(const String &thetask)
144         {
145                 taskname=thetask;
146                 return true;
147         }
148
149         virtual bool
150         error(const String &task)
151         {
152                 std::cout<<_("error")<<": "<<task<<std::endl;
153                 return true;
154         }
155
156         virtual bool
157         warning(const String &task)
158         {
159                 std::cout<<_("warning")<<": "<<task<<std::endl;
160                 return true;
161         }
162
163         virtual bool
164         amount_complete(int scanline, int h)
165         {
166                 if(be_quiet)return true;
167                 if(scanline!=h)
168                 {
169                         const float time(clk()*(float)(h-scanline)/(float)(scanline-clk_scanline));
170                         const float delta(time-last_time);
171
172                         int weeks=0,days=0,hours=0,minutes=0,seconds=0;
173
174                         last_time=time;
175
176                         if(clk2()<0.2)
177                                 return true;
178                         clk2.reset();
179                                 
180                         if(scanline)
181                                 seconds=(int)time+1;
182                         else
183                         {
184                                 //cerr<<"reset"<<endl;
185                                 clk.reset();
186                                 clk_scanline=scanline;
187                         }
188                         
189                         if(seconds<0)
190                         {
191                                 clk.reset();
192                                 clk_scanline=scanline;
193                                 seconds=0;
194                         }
195                         while(seconds>=60)
196                                 minutes++,seconds-=60;
197                         while(minutes>=60)
198                                 hours++,minutes-=60;
199                         while(hours>=24)
200                                 days++,hours-=24;
201                         while(days>=7)
202                                 weeks++,days-=7;
203                         
204                         cerr<<taskname<<": "<<_("Line")<<" "<<scanline<<_(" of ")<<h<<" -- ";
205                         //cerr<<time/(h-clk_scanline)<<" ";
206                         /*
207                         if(delta>=-time/(h-clk_scanline)  )
208                                 cerr<<">";
209                         */
210                         if(delta>=0 && clk()>4.0 && scanline>clk_scanline+200)
211                         {
212                                 //cerr<<"reset"<<endl;
213                                 clk.reset();
214                                 clk_scanline=scanline;                          
215                         }
216                         
217                         if(weeks)
218                                 cerr<<weeks<<"w ";
219                         if(days)
220                                 cerr<<days<<"d ";
221                         if(hours)
222                                 cerr<<hours<<"h ";
223                         if(minutes)
224                                 cerr<<minutes<<"m ";
225                         if(seconds)
226                                 cerr<<seconds<<"s ";
227                         
228                         cerr<<"           \r";
229                 }
230                 else
231                         cerr<<taskname<<": "<<_("DONE")<<"                        "<<endl;;
232                 return true;
233         }
234 };
235
236 struct Job
237 {
238         String filename;
239         String outfilename;
240         
241         RendDesc desc;
242
243         Canvas::Handle root;
244         Canvas::Handle canvas;
245         Target::Handle target;
246         
247         int quality;
248         bool sifout;
249 };
250
251 typedef list<String> arg_list_t;
252 typedef list<Job> job_list_t;
253
254 void guid_test()
255 {
256         cout<<"GUID Test"<<endl;
257         for(int i=20;i;i--)
258         {
259                 cout<<sinfg::GUID().get_string()<<' '<<sinfg::GUID().get_string()<<endl;
260         }
261 }
262
263 void signal_test_func()
264 {
265         cout<<"**SIGNAL CALLED**"<<endl;
266 }
267
268 void signal_test()
269 {
270         sigc::signal<void> sig;
271         sigc::connection conn;
272         cout<<"Signal Test"<<endl;
273         conn=sig.connect(sigc::ptr_fun(signal_test_func));
274         cout<<"Next line should exclaim signal called."<<endl;
275         sig();
276         conn.disconnect();
277         cout<<"Next line should NOT exclaim signal called."<<endl;
278         sig();
279         cout<<"done."<<endl;
280 }
281
282 /* === P R O C E D U R E S ================================================= */
283
284 void display_help(int amount)
285 {
286         class Argument
287         {
288         public:
289                 Argument(const char *flag,const char *arg, string description)
290                 {
291                         const char spaces[]="                      ";
292                         if(arg)
293                                 cerr<<strprintf(" %s %s %s",flag, arg, spaces+strlen(arg)+strlen(flag)+1)+description<<endl;
294                         else
295                                 cerr<<strprintf(" %s %s",flag,spaces+strlen(flag))+description<<endl;
296                 
297                 }
298         };
299         cerr<<_("syntax: ")<<progname<<" [DEFAULT OPTIONS] ([SIF FILE] [SPECIFIC OPTIONS])..."<<endl;
300         cerr<<endl;
301         if(amount>=1)
302         {
303                 Argument("-t","<output type>",_("Specify output target (Default:unknown)"));
304                 Argument("-w","<pixel width>",_("Set the image width (Use zero for file default)"));
305                 Argument("-h","<pixel height>",_("Set the image height (Use zero for file default)"));
306                 Argument("-s","<image dist>",_("Set the diagonal size of image window (Span)"));
307                 Argument("-a","<1...30>",_("Set antialias amount for parametric renderer."));
308                 Argument("-Q","<0...10>",strprintf(_("Specify image quality for accelerated renderer (default=%d)"),DEFAULT_QUALITY).c_str());
309                 Argument("-g","<amount>",_("Gamma (default=2.2)"));
310                 Argument("-v",NULL,_("Verbose Output (add more for more verbosity)"));
311                 Argument("-q",NULL,_("Quiet mode (No progress/time-remaining display)"));
312                 Argument("-c","<canvas id>",_("Render the canvas with the given id instead of the root."));
313                 Argument("-o","<output file>",_("Specify output filename"));
314                 Argument("-T","<# of threads>",_("Enable multithreaded renderer using specified # of threads"));
315
316                 Argument("-b",NULL,_("Print Benchmarks"));
317
318                 Argument("--fps","<framerate>",_("Set the frame rate"));
319                 Argument("--time","<time>",_("Render a single frame at <seconds>"));
320                 Argument("--begin-time","<time>",_("Set the starting time"));
321                 Argument("--end-time","<time>",_("Set the ending time"));
322                 Argument("--dpi","<res>",_("Set the dots-per-inch"));
323                 Argument("--append","<filename>",_("Append layers in <filename> to composition"));
324
325                 Argument("--layer-info","<layer>",_("Print out layer's description, parameter info, etc."));
326                 Argument("--layers",NULL,_("Print out the list of available layers"));
327                 Argument("--targets",NULL,_("Print out the list of available targets"));
328                 Argument("--importers",NULL,_("Print out the list of available importers"));
329                 Argument("--valuenodes",NULL,_("Print out the list of available ValueNodes"));
330                 Argument("--modules",NULL,_("Print out the list of loaded modules"));
331                 Argument("--version",NULL,_("Print out version information"));
332                 Argument("--info",NULL,_("Print out misc build information"));
333                 Argument("--license",NULL,_("Print out license information"));
334
335 #ifdef _DEBUG
336                 Argument("--guid-test",NULL,_("Test GUID generation"));
337                 Argument("--signal-test",NULL,_("Test signal implementation"));
338 #endif
339         }
340         else
341
342         Argument("--help",NULL,_("Print out usage and syntax info"));
343         cerr<<endl;
344 }
345
346 int process_global_flags(arg_list_t &arg_list)
347 {
348         arg_list_t::iterator iter, next;
349         
350         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
351         {
352                 if(*iter == "--")
353                         return SINFGTOOL_OK;
354
355                 if(*iter == "--signal-test")
356                 {
357                         signal_test();
358                         return SINFGTOOL_HELP;
359                 }
360                 
361                 if(*iter == "--guid-test")
362                 {
363                         guid_test();
364                         return SINFGTOOL_HELP;
365                 }
366
367                 
368                 if(*iter == "--help")
369                 {
370                         display_help(1);
371
372                         return SINFGTOOL_HELP;
373                 }
374
375                 if(*iter == "--info")
376                 {
377                         cout<<PACKAGE"-"VERSION<<endl;
378                         cout<<"Compiled on "__DATE__ " at "__TIME__;
379 #ifdef __GNUC__
380                         cout<<" with GCC "<<__VERSION__;
381 #endif
382 #ifdef _MSC_VER
383                         cout<<" with Microsoft Visual C++ "<<(_MSC_VER>>8)<<'.'<<(_MSC_VER&255);
384 #endif
385 #ifdef __TCPLUSPLUS__
386                         cout<<" with Borland Turbo C++ "<<(__TCPLUSPLUS__>>8)<<'.'<<((__TCPLUSPLUS__&255)>>4)<<'.'<<(__TCPLUSPLUS__&15);
387 #endif
388
389                         cout<<endl<<SINFG_COPYRIGHT<<endl;
390                         cout<<endl;
391                         return SINFGTOOL_HELP;
392                 }
393
394                 if(*iter == "--layers")
395                 {
396                         Progress p(PACKAGE);
397                         sinfg::Main sinfg_main(dirname(progname),&p);
398                         sinfg::Layer::Book::iterator iter=sinfg::Layer::book().begin();
399                         for(;iter!=sinfg::Layer::book().end();iter++)
400                                 cout<<iter->first<<endl;
401
402                         return SINFGTOOL_HELP;
403                 }
404
405                 if(*iter == "--layer-info")
406                 {
407                         Progress p(PACKAGE);
408                         sinfg::Main sinfg_main(dirname(progname),&p);
409                         iter=next++;
410                         Layer::Handle layer=sinfg::Layer::create(*iter);
411                         cout<<"Layer Name: "<<layer->get_name()<<endl;
412                         cout<<"Localized Layer Name: "<<layer->get_local_name()<<endl;
413                         cout<<"Version: "<<layer->get_version()<<endl;
414                         Layer::Vocab vocab=layer->get_param_vocab();
415                         for(;!vocab.empty();vocab.pop_front())
416                         {
417                                 cout<<"param - "<<vocab.front().get_name();
418                                 if(!vocab.front().get_critical())
419                                         cout<<" (not critical)";
420                                 cout<<endl<<"\tLocalized Name: "<<vocab.front().get_local_name()<<endl;
421                                 if(!vocab.front().get_description().empty())
422                                         cout<<"\tDescription: "<<vocab.front().get_description()<<endl;
423                                 if(!vocab.front().get_hint().empty())
424                                         cout<<"\tHint: "<<vocab.front().get_hint()<<endl;
425                         }
426
427                         return SINFGTOOL_HELP;
428                 }
429
430                 if(*iter == "--modules")
431                 {
432                         Progress p(PACKAGE);
433                         sinfg::Main sinfg_main(dirname(progname),&p);
434                         sinfg::Module::Book::iterator iter=sinfg::Module::book().begin();
435                         for(;iter!=sinfg::Module::book().end();iter++)
436                                 cout<<iter->first<<endl;
437                         return SINFGTOOL_HELP;
438                 }
439
440                 if(*iter == "--targets")
441                 {
442                         Progress p(PACKAGE);
443                         sinfg::Main sinfg_main(dirname(progname),&p);
444                         sinfg::Target::Book::iterator iter=sinfg::Target::book().begin();
445                         for(;iter!=sinfg::Target::book().end();iter++)
446                                 cout<<iter->first<<endl;
447                                 
448                         return SINFGTOOL_HELP;
449                 }
450
451                 if(*iter == "--valuenodes")
452                 {
453                         Progress p(PACKAGE);
454                         sinfg::Main sinfg_main(dirname(progname),&p);
455                         sinfg::LinkableValueNode::Book::iterator iter=sinfg::LinkableValueNode::book().begin();
456                         for(;iter!=sinfg::LinkableValueNode::book().end();iter++)
457                                 cout<<iter->first<<endl;
458                                 
459                         return SINFGTOOL_HELP;
460                 }
461
462                 if(*iter == "--importers")
463                 {
464                         Progress p(PACKAGE);
465                         sinfg::Main sinfg_main(dirname(progname),&p);
466                         sinfg::Importer::Book::iterator iter=sinfg::Importer::book().begin();
467                         for(;iter!=sinfg::Importer::book().end();iter++)
468                                 cout<<iter->first<<endl;
469                                 
470                         return SINFGTOOL_HELP;
471                 }
472
473                 if(*iter == "--version")
474                 {
475                         cerr<<PACKAGE<<" "<<VERSION<<endl;
476                 
477                         arg_list.erase(iter);
478                         
479                         return SINFGTOOL_HELP;
480                 }
481
482                 if(*iter == "--license")
483                 {
484                         cerr<<PACKAGE<<" "<<VERSION<<endl;
485                         cout<<SINFG_COPYRIGHT<<endl<<endl;
486                         cerr<<"\
487 **      This software and associated documentation\n\
488 **      are CONFIDENTIAL and PROPRIETARY property of\n\
489 **      the above-mentioned copyright holder.\n\
490 **\n\
491 **      You may not use, copy, print, publish, or in\n\
492 **      any other way distribute or exploit this software\n\
493 **      without a prior written agreement with the\n\
494 **      copyright holder. " << endl << endl;    
495                         arg_list.erase(iter);
496                         
497                         return SINFGTOOL_HELP;
498                 }
499
500                 if(*iter == "-v")
501                 {
502                         verbosity++;
503                         
504                         arg_list.erase(iter);
505                         
506                         continue;
507                 }
508
509                 if(*iter == "-q")
510                 {
511                         be_quiet=true;
512
513                         arg_list.erase(iter);
514
515                         continue;
516                 }
517                 if(*iter == "-b")
518                 {
519                         print_benchmarks=true;
520
521                         arg_list.erase(iter);
522
523                         continue;
524                 }
525         }
526         
527         return SINFGTOOL_OK;
528 }
529
530 int extract_arg_cluster(arg_list_t &arg_list,arg_list_t &cluster)
531 {
532         arg_list_t::iterator iter, next;
533         
534         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
535         {
536                 if(*iter->begin() != '-')
537                 {
538                         //cerr<<*iter->begin()<<"-----------"<<endl;
539                         return SINFGTOOL_OK;
540                 }
541
542                 if(
543                         *iter=="-t" ||
544                         *iter=="-w" ||
545                         *iter=="-h" ||
546                         *iter=="-a" ||
547                         *iter=="-g" ||
548                         *iter=="-o" ||
549                         *iter=="-s" ||
550                         *iter=="-Q" ||
551                         *iter=="-c" ||
552                         *iter=="--fps" ||
553                         *iter=="--start-time" ||
554                         *iter=="--begin-time" ||
555                         *iter=="--end-time" ||
556                         *iter=="--start-frame" ||
557                         *iter=="--end-frame" ||
558                         *iter=="--time" ||
559                         *iter=="--frame" ||
560                         *iter=="--dpi" ||
561                         *iter=="--dpi-x" ||
562                         *iter=="--dpi-y" ||
563                         *iter=="--append" ||
564                         *iter=="-T" )
565                 {
566                         cluster.push_back(*iter);
567                         arg_list.erase(iter);
568                         iter=next++;
569                 }
570                         
571                 cluster.push_back(*iter);
572                 arg_list.erase(iter);
573         }
574         
575         return SINFGTOOL_OK;
576 }
577
578 int extract_RendDesc(arg_list_t &arg_list,RendDesc &desc)
579 {
580         arg_list_t::iterator iter, next;
581         int w=0,h=0;
582         float span=0;
583         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
584         {
585                 if(*iter=="-w")
586                 {
587                         arg_list.erase(iter);
588                         iter=next++;
589                         w=atoi(iter->c_str());
590                         arg_list.erase(iter);
591                 }
592                 if(*iter=="-h")
593                 {
594                         arg_list.erase(iter);
595                         iter=next++;
596                         h=atoi(iter->c_str());
597                         arg_list.erase(iter);
598                 }
599                 if(*iter=="-a")
600                 {
601             int a;
602                         arg_list.erase(iter);
603                         iter=next++;
604                         a=atoi(iter->c_str());
605                         desc.set_antialias(a);
606                         VERBOSE_OUT(1)<<strprintf(_("Antialiasing set to %d, (%d samples per pixel)"),a,a*a)<<endl;
607                         arg_list.erase(iter);
608                 }
609                 if(*iter=="-s")
610                 {
611                         arg_list.erase(iter);
612                         iter=next++;
613                         span=atof(iter->c_str());
614                         VERBOSE_OUT(1)<<strprintf(_("Span set to %d units"),span)<<endl;
615                         arg_list.erase(iter);
616                 }
617                 if(*iter=="--fps")
618                 {
619                         arg_list.erase(iter);
620                         iter=next++;
621                         float fps=atof(iter->c_str());
622                         desc.set_frame_rate(fps);
623                         arg_list.erase(iter);
624                         VERBOSE_OUT(1)<<strprintf(_("Frame rate set to %d frames per second"),fps)<<endl;
625                 }
626                 if(*iter=="--dpi")
627                 {
628                         arg_list.erase(iter);
629                         iter=next++;
630                         float dpi=atof(iter->c_str());
631                         float dots_per_meter=dpi*39.3700787402;
632                         desc.set_x_res(dots_per_meter).set_y_res(dots_per_meter);
633                         arg_list.erase(iter);
634                         VERBOSE_OUT(1)<<strprintf(_("Physical resolution set to %f dpi"),dpi)<<endl;
635                 }
636                 if(*iter=="--dpi-x")
637                 {
638                         arg_list.erase(iter);
639                         iter=next++;
640                         float dpi=atof(iter->c_str());
641                         float dots_per_meter=dpi*39.3700787402;
642                         desc.set_x_res(dots_per_meter);
643                         arg_list.erase(iter);
644                         VERBOSE_OUT(1)<<strprintf(_("Physical X resolution set to %f dpi"),dpi)<<endl;
645                 }
646                 if(*iter=="--dpi-y")
647                 {
648                         arg_list.erase(iter);
649                         iter=next++;
650                         float dpi=atof(iter->c_str());
651                         float dots_per_meter=dpi*39.3700787402;
652                         desc.set_y_res(dots_per_meter);
653                         arg_list.erase(iter);
654                         VERBOSE_OUT(1)<<strprintf(_("Physical Y resolution set to %f dpi"),dpi)<<endl;
655                 }
656                 if(*iter=="--start-time" || *iter=="--begin-time")
657                 {
658                         arg_list.erase(iter);
659                         iter=next++;
660                         desc.set_time_start(Time(*iter,desc.get_frame_rate()));
661                         arg_list.erase(iter);
662                 }
663                 if(*iter=="--end-time")
664                 {
665                         arg_list.erase(iter);
666                         iter=next++;
667                         desc.set_time_end(Time(*iter,desc.get_frame_rate()));
668                         arg_list.erase(iter);
669                 }
670                 if(*iter=="--time")
671                 {
672                         arg_list.erase(iter);
673                         iter=next++;
674                         desc.set_time(Time(*iter,desc.get_frame_rate()));
675                         VERBOSE_OUT(1)<<_("Rendering frame at ")<<desc.get_time_start().get_string(desc.get_frame_rate())<<endl;
676                         arg_list.erase(iter);
677                 }
678                 if(*iter=="-g")
679                 {
680                         sinfg::warning("Gamma argument is currently ignored");
681                         //arg_list.erase(iter);
682                         //iter=next++;
683                         //desc.set_gamma(Gamma(atof(iter->c_str())));
684                         //arg_list.erase(iter);
685                 }
686         }
687         if(w&&h)
688         {
689                 desc.set_wh(w,h);
690                 VERBOSE_OUT(1)<<strprintf(_("Resolution set to %dx%d"),w,h)<<endl;
691         }
692         else
693         {
694                 if(w)
695                 {
696                         VERBOSE_OUT(1)<<strprintf(_("Width set to %d pixels"),w)<<endl;
697                         desc.set_w(w);
698                 }
699                 if(h)
700                 {
701                         VERBOSE_OUT(1)<<strprintf(_("Height set to %d pixels"),h)<<endl;
702                         desc.set_h(h);
703                 }
704         }
705         if(span)
706                 desc.set_span(span);
707         return SINFGTOOL_OK;
708 }
709
710 int extract_quality(arg_list_t &arg_list,int &quality)
711 {
712         arg_list_t::iterator iter, next;
713         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
714         {
715                 if(*iter=="-Q")
716                 {
717                         arg_list.erase(iter);
718                         iter=next++;
719                         quality=atoi(iter->c_str());
720                         VERBOSE_OUT(1)<<strprintf(_("Quality set to %d"),quality)<<endl;
721                         arg_list.erase(iter);
722                 }
723         }
724         
725         return SINFGTOOL_OK;
726 }
727
728 int extract_threads(arg_list_t &arg_list,int &threads)
729 {
730         arg_list_t::iterator iter, next;
731         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
732         {
733                 if(*iter=="-T")
734                 {
735                         arg_list.erase(iter);
736                         iter=next++;
737                         threads=atoi(iter->c_str());
738                         VERBOSE_OUT(1)<<strprintf(_("Threads set to %d"),threads)<<endl;
739                         arg_list.erase(iter);
740                 }
741         }
742         
743         return SINFGTOOL_OK;
744 }
745
746 int extract_target(arg_list_t &arg_list,string &type)
747 {
748         arg_list_t::iterator iter, next;
749         type.clear();
750         
751         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
752         {
753                 if(*iter=="-t")
754                 {
755                         arg_list.erase(iter);
756                         iter=next++;
757                         type=*iter;
758                         arg_list.erase(iter);
759                 }
760         }
761
762         return SINFGTOOL_OK;
763 }
764
765 int extract_append(arg_list_t &arg_list,string &filename)
766 {
767         arg_list_t::iterator iter, next;
768         filename.clear();
769         
770         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
771         {
772                 if(*iter=="--append")
773                 {
774                         arg_list.erase(iter);
775                         iter=next++;
776                         filename=*iter;
777                         arg_list.erase(iter);
778                 }
779         }
780
781         return SINFGTOOL_OK;
782 }
783
784 int extract_outfile(arg_list_t &arg_list,string &outfile)
785 {
786         arg_list_t::iterator iter, next;
787         int ret=SINFGTOOL_FILENOTFOUND;
788         outfile.clear();
789         
790         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
791         {
792                 if(*iter=="-o")
793                 {
794                         arg_list.erase(iter);
795                         iter=next++;
796                         outfile=*iter;
797                         arg_list.erase(iter);
798                         ret=SINFGTOOL_OK;
799                 }
800         }
801
802         return ret;
803 }
804
805 int extract_canvasid(arg_list_t &arg_list,string &canvasid)
806 {
807         arg_list_t::iterator iter, next;
808         //canvasid.clear();
809         
810         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
811         {
812                 if(*iter=="-c")
813                 {
814                         arg_list.erase(iter);
815                         iter=next++;
816                         canvasid=*iter;
817                         arg_list.erase(iter);
818                 }
819         }
820
821         return SINFGTOOL_OK;
822 }
823
824 /* === M E T H O D S ======================================================= */
825
826 /* === E N T R Y P O I N T ================================================= */
827
828 int main(int argc, char *argv[])
829 {
830         int i;
831         arg_list_t arg_list;
832         job_list_t job_list;
833         
834         progname=argv[0];
835         Progress p(argv[0]);
836         
837         if(!SINFG_CHECK_VERSION())
838         {
839                 cerr<<_("FATAL: Sinfg Version Mismatch")<<endl;
840                 return SINFGTOOL_BADVERSION;
841         }
842         if(argc==1)
843         {
844                 display_help(0);
845                 return SINFGTOOL_BLANK;
846         }
847
848         for(i=1;i<argc;i++)
849                 arg_list.push_back(argv[i]);
850         
851         if((i=process_global_flags(arg_list)))
852                 return i;
853
854         VERBOSE_OUT(1)<<_("verbosity set to ")<<verbosity<<endl;
855         sinfg::Main sinfg_main(dirname(progname),&p);
856         
857         {
858                 arg_list_t defaults, imageargs;
859                 
860                 // Grab the defaults before the first file
861                 extract_arg_cluster(arg_list,defaults);
862                 
863                 while(arg_list.size())
864                 {
865                         string target_name;
866                         job_list.push_front(Job());
867                         int threads=0;
868                         
869                         imageargs=defaults;
870                         job_list.front().filename=arg_list.front();
871                         arg_list.pop_front();
872
873                         extract_arg_cluster(arg_list,imageargs);                        
874                         
875                         // Open the composition
876                         {
877                                 job_list.front().root=open_canvas(job_list.front().filename);
878                         }
879                         if(!job_list.front().root)
880                         {
881                                 cerr<<_("Unable to open ")<<job_list.front().filename<<"."<<endl;
882                                 cerr<<_("Throwing out job...")<<endl;
883                                 job_list.pop_front();
884                                 continue;
885                         }
886
887                         job_list.front().root->set_time(0);
888                         
889                         string canvasid;
890                         extract_canvasid(imageargs,canvasid);
891                         if(!canvasid.empty())
892                         {
893                                 try
894                                 {
895                                         job_list.front().canvas=job_list.front().root->find_canvas(canvasid);
896                                 }
897                                 catch(Exception::IDNotFound)
898                                 {
899                                         cerr<<_("Unable to find canvas with ID \"")<<canvasid<<_("\" in ")<<job_list.front().filename<<"."<<endl;
900                                         cerr<<_("Throwing out job...")<<endl;
901                                         job_list.pop_front();
902                                         continue;
903                                         
904                                 }
905                                 catch(Exception::BadLinkName)
906                                 {
907                                         cerr<<_("Invalid canvas name \"")<<canvasid<<_("\" in ")<<job_list.front().filename<<"."<<endl;
908                                         cerr<<_("Throwing out job...")<<endl;
909                                         job_list.pop_front();
910                                         continue;
911                                         
912                                 }
913                         }
914                         else
915                                 job_list.front().canvas=job_list.front().root;
916                         
917                         extract_RendDesc(imageargs,job_list.front().canvas->rend_desc());
918                         extract_target(imageargs,target_name);
919                         extract_threads(imageargs,threads);
920                         job_list.front().quality=DEFAULT_QUALITY;
921                         extract_quality(imageargs,job_list.front().quality);
922                         VERBOSE_OUT(2)<<_("Quality set to ")<<job_list.front().quality<<endl;
923                         job_list.front().desc=job_list.front().canvas->rend_desc();
924                         extract_outfile(imageargs,job_list.front().outfilename);
925
926                         // Extract composite
927                         do{
928                                 string composite_file;
929                                 extract_append(imageargs,composite_file);
930                                 if(!composite_file.empty())
931                                 {
932                                         Canvas::Handle composite(open_canvas(composite_file));
933                                         if(!composite)
934                                                 break;
935                                         Canvas::reverse_iterator iter;
936                                         for(iter=composite->rbegin();iter!=composite->rend();++iter)
937                                         {
938                                                 Layer::Handle layer(*iter);
939                                                 if(layer->active())
940                                                         job_list.front().canvas->push_front(layer->clone());
941                                         }
942                                         VERBOSE_OUT(2)<<_("Appended contents of ")<<composite_file<<endl;
943                                 }
944                         }while(false);
945                         
946                         VERBOSE_OUT(4)<<_("Attempting to determine target/outfile...")<<endl;
947                         
948                         // If the target type is not yet defined,
949                         // try to figure it out from the outfile.
950                         if(target_name.empty() && !job_list.front().outfilename.empty())
951                         try
952                         {
953                                 VERBOSE_OUT(3)<<_("Target name undefined, attempting to figure it out")<<endl;
954                                 string ext=string(find(job_list.front().outfilename.begin(),job_list.front().outfilename.end(),'.')+1,job_list.front().outfilename.end());
955                                 if(Target::ext_book().count(ext))
956                                         target_name=Target::ext_book()[ext];
957                                 else
958                                         target_name=ext;
959                         }
960                         catch(std::length_error)
961                         {
962                                 sinfg::warning("Length error caught when attempting to figure out target name");
963                         }
964
965                         // If the target type is STILL not yet defined, then
966                         // set it to a some sort of default
967                         if(target_name.empty())
968                         {
969                                 VERBOSE_OUT(2)<<_("Defaulting to PNG target...")<<endl;
970                                 target_name="png";
971                         }
972
973                         // If no output filename was provided, then
974                         // create a output filename based on the
975                         // given input filename. (ie: change the extension)
976                         if(job_list.front().outfilename.empty())
977                         {
978                                 job_list.front().outfilename=job_list.front().filename;
979                                 job_list.front().outfilename.erase(find(job_list.front().outfilename.begin(),job_list.front().outfilename.end(),'.'),job_list.front().outfilename.end());
980                                 job_list.front().outfilename+='.';
981                                 if(Target::book().count(target_name))
982                                         job_list.front().outfilename+=Target::book()[target_name].second;
983                                 else
984                                         job_list.front().outfilename+=target_name;
985                         }
986
987                         VERBOSE_OUT(4)<<"target_name="<<target_name<<endl;
988                         VERBOSE_OUT(4)<<"outfile_name="<<job_list.front().outfilename<<endl;
989                         
990                         VERBOSE_OUT(4)<<_("Creating the target...")<<endl;
991                         job_list.front().target=sinfg::Target::create(target_name,job_list.front().outfilename);
992                         
993                         if(target_name=="sif")
994                         {
995                                 job_list.front().sifout=true;
996                         }
997                         else
998                         {
999                                 if(!job_list.front().target)
1000                                 {
1001                                         cerr<<_("Unknown target for ")<<job_list.front().filename<<": "<<target_name<<endl;
1002                                         cerr<<_("Throwing out job...")<<endl;
1003                                         job_list.pop_front();
1004                                         continue;
1005                                 }
1006                                 job_list.front().sifout=false;
1007                         }
1008
1009                         // Set the Canvas on the Target
1010                         if(job_list.front().target)
1011                         {
1012                                 VERBOSE_OUT(4)<<_("Setting the canvas on the target...")<<endl;
1013                                 job_list.front().target->set_canvas(job_list.front().canvas);
1014                                 VERBOSE_OUT(4)<<_("Setting the quality of the target...")<<endl;                                
1015                                 job_list.front().target->set_quality(job_list.front().quality);
1016                         }
1017                         
1018                         // Set the threads for the target
1019                         if(job_list.front().target && Target_Scanline::Handle::cast_dynamic(job_list.front().target))
1020                         {
1021                                 Target_Scanline::Handle::cast_dynamic(job_list.front().target)->set_threads(threads);
1022                         }
1023                         
1024                         if(imageargs.size())
1025                         {
1026                                 cerr<<_("Unidentified arguments for ")<<job_list.front().filename<<": ";
1027                                 for(;imageargs.size();imageargs.pop_front())
1028                                         cerr<<' '<<imageargs.front();
1029                                 cerr<<endl;
1030                                 cerr<<_("Throwing out job...")<<endl;
1031                                 job_list.pop_front();
1032                                 continue;
1033                         }
1034                         //string bleh;
1035                         //getline(cin,bleh);
1036                 }
1037         }
1038         
1039         if(arg_list.size())
1040         {
1041                 cerr<<_("Unidentified arguments:");
1042                 for(;arg_list.size();arg_list.pop_front())
1043                         cerr<<' '<<arg_list.front();
1044                 cerr<<endl;
1045                 return SINFGTOOL_UNKNOWNARGUMENT;
1046         }
1047         
1048         if(!job_list.size())
1049         {
1050                 cerr<<_("Nothing to do!")<<endl;
1051                 return SINFGTOOL_BORRED;
1052         }
1053         
1054         for(;job_list.size();job_list.pop_front())
1055         {
1056                 VERBOSE_OUT(3)<<job_list.front().filename<<" -- "<<endl<<'\t'<<
1057                 strprintf("w:%d, h:%d, a:%d, pxaspect:%f, imaspect:%f, span:%f",
1058                         job_list.front().desc.get_w(),
1059                         job_list.front().desc.get_h(),
1060                         job_list.front().desc.get_antialias(),
1061                         job_list.front().desc.get_pixel_aspect(),
1062                         job_list.front().desc.get_image_aspect(),
1063                         job_list.front().desc.get_span()
1064                         )<<endl<<'\t'<<
1065                 strprintf("tl:[%f,%f], br:[%f,%f], focus:[%f,%f]",
1066                         job_list.front().desc.get_tl()[0],job_list.front().desc.get_tl()[1],
1067                         job_list.front().desc.get_br()[0],job_list.front().desc.get_br()[1],
1068                         job_list.front().desc.get_focus()[0],job_list.front().desc.get_focus()[1]
1069                         )<<endl;
1070                 
1071                 RenderProgress p;
1072                 p.task(job_list.front().filename+" ==> "+job_list.front().outfilename);
1073                 if(!job_list.front().sifout)
1074                 {
1075                         VERBOSE_OUT(1)<<_("Rendering...")<<endl;
1076                         etl::clock timer;
1077                         timer.reset();
1078                         // Call the render member of the target
1079                         if(!job_list.front().target->render(&p))
1080                         {
1081                                 cerr<<"Render Failure."<<endl;
1082                                 return SINFGTOOL_RENDERFAILURE;
1083                         }
1084                         if(print_benchmarks)
1085                         {
1086                                 cout<<job_list.front().filename+": Rendered in "<<timer()<<" seconds."<<endl;
1087                         }
1088                 }
1089                 else
1090                 {
1091                         if(!save_canvas(job_list.front().outfilename,job_list.front().canvas))
1092                         {
1093                                 cerr<<"Render Failure."<<endl;
1094                                 return SINFGTOOL_RENDERFAILURE;
1095                         }
1096                 }
1097         }
1098         
1099         job_list.clear();
1100         
1101         VERBOSE_OUT(1)<<_("Done.")<<endl;
1102         
1103         return SINFGTOOL_OK;
1104 }