1 /**************************************************************************/
2 /* Copyright 2012 Tim Day */
3 /* */
4 /* This file is part of Evolvotron */
5 /* */
6 /* Evolvotron is free software: you can redistribute it and/or modify */
7 /* it under the terms of the GNU General Public License as published by */
8 /* the Free Software Foundation, either version 3 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* Evolvotron is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU General Public License */
17 /* along with Evolvotron. If not, see <http://www.gnu.org/licenses/>. */
18 /**************************************************************************/
19
20 /*! \file
21 \brief Standalone renderer for evolvotron function files.
22 */
23
24 #include "function_registry.h"
25 #include "mutatable_image.h"
26 #include "random.h"
27
28 #include <boost/program_options.hpp>
29
30 //! Application code
main(int argc,char * argv[])31 int main(int argc,char* argv[])
32 {
33 {
34 uint frames;
35 bool help;
36 bool jitter;
37 int multisample;
38 std::string output_filename;
39 std::string size;
40 bool verbose;
41
42 boost::program_options::options_description options_desc("Options");
43 boost::program_options::positional_options_description pos_options_desc;
44 {
45 using namespace boost::program_options;
46 options_desc.add_options()
47 ("frames,f" ,value<uint>(&frames)->default_value(1) ,"Frames in an animation")
48 ("help,h" ,bool_switch(&help) ,"Print command-line options help message and exit")
49 ("jitter,j" ,bool_switch(&jitter) ,"Enable rendering jitter")
50 ("multisample,m",value<int>(&multisample)->default_value(1),"Multisampling grid (NxN)")
51 ("output,o" ,value<std::string>(&output_filename) ,"Output filename (.png or .ppm suffix). (Or use first positional argument.)")
52 ("size,s" ,value<std::string>(&size)->default_value("512x515"),"Generated image size")
53 ("verbose,v" ,bool_switch(&verbose) ,"Log some details to stderr")
54 ;
55 pos_options_desc.add("output",1);
56 }
57
58 boost::program_options::variables_map options;
59 boost::program_options::store
60 (
61 boost::program_options::command_line_parser(argc,argv)
62 .options(options_desc).positional(pos_options_desc).run()
63 ,options
64 );
65 boost::program_options::notify(options);
66
67 if (help)
68 {
69 std::cerr << options_desc;
70 return 0;
71 }
72
73 if (verbose)
74 std::clog.rdbuf(std::cerr.rdbuf());
75 else
76 std::clog.rdbuf(sink_ostream.rdbuf());
77
78 //! \todo Could be done better maybe (set 'x' as input separator)
79 const std::string::size_type p=size.find("x");
80 if (p==std::string::npos || p==0 || p==size.size()-1)
81 {
82 std::cerr << "--size option argument isn't in <width>x<height> format\n";
83 return 1;
84 }
85 else
86 {
87 size[p]=' ';
88 }
89 int width=512;
90 int height=512;
91 std::stringstream(size) >> width >> height;
92
93 if (frames<1)
94 {
95 std::cerr << "Must specify at least 1 frame (option: -f <frames>)\n";
96 return 1;
97 }
98
99 if (output_filename.empty())
100 {
101 std::cerr << "Must specify an output filename\n";
102 return 1;
103 }
104
105 FunctionRegistry function_registry;
106
107 std::string report;
108 const boost::shared_ptr<const MutatableImage> imagefn(MutatableImage::load_function(function_registry,std::cin,report));
109
110 if (imagefn.get()==0)
111 {
112 std::cerr << "evolvotron_render: Error: Function not loaded due to errors:\n" << report;
113 return 1;
114 }
115 else if (!report.empty())
116 {
117 std::cerr << "evolvotron_render: Warning: Function loaded with warnings:\n" << report;
118 }
119
120 // Seed value pretty unimportant; only used for sample jitter.
121 Random01 r01(23);
122
123 for (uint frame=0;frame<frames;frame++)
124 {
125 std::vector<uint> image_data;
126 image_data.reserve(width*height);
127
128 uint pixels=0;
129 uint report=1;
130 const uint reports=20;
131 for (int row=0;row<height;row++)
132 for (int col=0;col<width;col++)
133 {
134 const XYZ v(imagefn->sampling_coordinate(col,row,frame,width,height,frames));
135
136 const XYZ colour(imagefn->get_rgb(col,row,frame,width,height,frames,(jitter ? &r01 : 0),multisample));
137
138 const uint col0=lrint(clamped(colour.x(),0.0,255.0));
139 const uint col1=lrint(clamped(colour.y(),0.0,255.0));
140 const uint col2=lrint(clamped(colour.z(),0.0,255.0));
141
142 image_data.push_back(((col0<<16)|(col1<<8)|(col2)));
143
144 pixels++;
145 if (pixels>=(report*width*height)/reports)
146 {
147 std::clog << "[" << (100*report)/reports << "%]";
148 report++;
149 }
150 }
151 std::clog << "\n";
152
153 {
154 //! \todo If filename is "-", write PPM to stdout (QImage save only supports write-to-a-filenames though)
155 QString save_filename(QString::fromLocal8Bit(output_filename.c_str()));
156
157 const char* save_format="PPM";
158 if (save_filename.toUpper().endsWith(".PPM"))
159 {
160 save_format="PPM";
161 }
162 else if (save_filename.toUpper().endsWith(".PNG"))
163 {
164 save_format="PNG";
165 }
166 else
167 {
168 std::cerr
169 << "evolvotron_render: Warning: Unrecognised file suffix. File will be written in "
170 << save_format
171 << " format.\n";
172 }
173
174 if (frames>1)
175 {
176 QString frame_component;
177 frame_component.sprintf(".f%06d",frame);
178 int insert_point=save_filename.lastIndexOf(QString("."));
179 if (insert_point==-1)
180 {
181 save_filename.append(frame_component);
182 }
183 else
184 {
185 save_filename.insert(insert_point,frame_component);
186 }
187 }
188
189 QImage image
190 (
191 reinterpret_cast<uchar*>(&(image_data[0])),
192 width,
193 height,
194 QImage::Format_RGB32
195 );
196
197 if (!image.save(save_filename,save_format))
198 {
199 std::cerr
200 << "evolvotron_render: Error: Couldn't save file "
201 << save_filename.toLocal8Bit().data()
202 << "\n";
203 return 1;
204 }
205
206 std::clog
207 << "Wrote file "
208 << save_filename.toLocal8Bit().data()
209 << "\n";
210 }
211 }
212 }
213
214 return 0;
215 }
216