Cycles: code refactoring, to do render layer visibility test a bit different,
[blender.git] / intern / cycles / app / cycles_test.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include <stdio.h>
20
21 #include "buffers.h"
22 #include "camera.h"
23 #include "device.h"
24 #include "scene.h"
25 #include "session.h"
26
27 #include "util_args.h"
28 #include "util_foreach.h"
29 #include "util_function.h"
30 #include "util_path.h"
31 #include "util_progress.h"
32 #include "util_string.h"
33 #include "util_time.h"
34 #include "util_view.h"
35
36 #include "cycles_xml.h"
37
38 CCL_NAMESPACE_BEGIN
39
40 struct Options {
41         Session *session;
42         Scene *scene;
43         string filepath;
44         int width, height;
45         SceneParams scene_params;
46         SessionParams session_params;
47         bool quiet;
48 } options;
49
50 static void session_print(const string& str)
51 {
52         /* print with carriage return to overwrite previous */
53         printf("\r%s", str.c_str());
54
55         /* add spaces to overwrite longer previous print */
56         static int maxlen = 0;
57         int len = str.size();
58         maxlen = max(len, maxlen);
59
60         for(int i = len; i < maxlen; i++)
61                 printf(" ");
62
63         /* flush because we don't write an end of line */
64         fflush(stdout);
65 }
66
67 static void session_print_status()
68 {
69         int sample;
70         double total_time, sample_time;
71         string status, substatus;
72
73         /* get status */
74         options.session->progress.get_sample(sample, total_time, sample_time);
75         options.session->progress.get_status(status, substatus);
76
77         if(substatus != "")
78                 status += ": " + substatus;
79
80         /* print status */
81         status = string_printf("Sample %d   %s", sample, status.c_str());
82         session_print(status);
83 }
84
85 static BufferParams& session_buffer_params()
86 {
87         static BufferParams buffer_params;
88         buffer_params.width = options.width;
89         buffer_params.height = options.height;
90         buffer_params.full_width = options.width;
91         buffer_params.full_height = options.height;
92
93         return buffer_params;
94 }
95
96 static void session_init()
97 {
98         options.session = new Session(options.session_params);
99         options.session->reset(session_buffer_params(), options.session_params.samples);
100         options.session->scene = options.scene;
101         
102         if(options.session_params.background && !options.quiet)
103                 options.session->progress.set_update_callback(function_bind(&session_print_status));
104         else
105                 options.session->progress.set_update_callback(function_bind(&view_redraw));
106
107         options.session->start();
108
109         options.scene = NULL;
110 }
111
112 static void scene_init()
113 {
114         options.scene = new Scene(options.scene_params);
115         xml_read_file(options.scene, options.filepath.c_str());
116         options.width = options.scene->camera->width;
117         options.height = options.scene->camera->height;
118 }
119
120 static void session_exit()
121 {
122         if(options.session) {
123                 delete options.session;
124                 options.session = NULL;
125         }
126         if(options.scene) {
127                 delete options.scene;
128                 options.scene = NULL;
129         }
130
131         if(options.session_params.background && !options.quiet) {
132                 session_print("Finished Rendering.");
133                 printf("\n");
134         }
135 }
136
137 static void display_info(Progress& progress)
138 {
139         static double latency = 0.0;
140         static double last = 0;
141         double elapsed = time_dt();
142         string str;
143
144         latency = (elapsed - last);
145         last = elapsed;
146
147         int sample;
148         double total_time, sample_time;
149         string status, substatus;
150
151         progress.get_sample(sample, total_time, sample_time);
152         progress.get_status(status, substatus);
153
154         if(substatus != "")
155                 status += ": " + substatus;
156
157         str = string_printf("latency: %.4f        sample: %d        total: %.4f        average: %.4f        %s",
158                 latency, sample, total_time, sample_time, status.c_str());
159
160         view_display_info(str.c_str());
161 }
162
163 static void display()
164 {
165         options.session->draw(session_buffer_params());
166
167         display_info(options.session->progress);
168 }
169
170 static void resize(int width, int height)
171 {
172         options.width= width;
173         options.height= height;
174
175         if(options.session)
176                 options.session->reset(session_buffer_params(), options.session_params.samples);
177 }
178
179 void keyboard(unsigned char key)
180 {
181         if(key == 'r')
182                 options.session->reset(session_buffer_params(), options.session_params.samples);
183         else if(key == 27) // escape
184                 options.session->progress.set_cancel("Cancelled");
185 }
186
187 static int files_parse(int argc, const char *argv[])
188 {
189         if(argc > 0)
190                 options.filepath = argv[0];
191
192         return 0;
193 }
194
195 static void options_parse(int argc, const char **argv)
196 {
197         options.width= 1024;
198         options.height= 512;
199         options.filepath = "";
200         options.session = NULL;
201         options.quiet = false;
202
203         /* devices */
204         string devices = "";
205         string devicename = "cpu";
206
207         vector<DeviceType> types = Device::available_types();
208
209         foreach(DeviceType type, types) {
210                 if(devices != "")
211                         devices += ", ";
212
213                 devices += Device::string_from_type(type);
214         }
215
216         /* shading system */
217         string ssname = "svm";
218         string shadingsystems = "Shading system to use: svm";
219
220 #ifdef WITH_OSL
221         shadingsystems += ", osl"; 
222 #endif
223
224         /* parse options */
225         ArgParse ap;
226         bool help = false;
227
228         ap.options ("Usage: cycles_test [options] file.xml",
229                 "%*", files_parse, "",
230                 "--device %s", &devicename, ("Devices to use: " + devices).c_str(),
231                 "--shadingsys %s", &ssname, "Shading system to use: svm, osl",
232                 "--background", &options.session_params.background, "Render in background, without user interface",
233                 "--quiet", &options.quiet, "In background mode, don't print progress messages",
234                 "--samples %d", &options.session_params.samples, "Number of samples to render",
235                 "--output %s", &options.session_params.output_path, "File path to write output image",
236                 "--threads %d", &options.session_params.threads, "CPU Rendering Threads",
237                 "--help", &help, "Print help message",
238                 NULL);
239         
240         if(ap.parse(argc, argv) < 0) {
241                 fprintf(stderr, "%s\n", ap.error_message().c_str());
242                 ap.usage();
243                 exit(EXIT_FAILURE);
244         }
245         else if(help || options.filepath == "") {
246                 ap.usage();
247                 exit(EXIT_SUCCESS);
248         }
249
250         options.session_params.device_type = Device::type_from_string(devicename.c_str());
251
252         if(ssname == "osl")
253                 options.scene_params.shadingsystem = SceneParams::OSL;
254         else if(ssname == "svm")
255                 options.scene_params.shadingsystem = SceneParams::SVM;
256
257         /* handle invalid configurations */
258         bool type_available = false;
259
260         foreach(DeviceType dtype, types)
261                 if(options.session_params.device_type == dtype)
262                         type_available = true;
263
264         if(options.session_params.device_type == DEVICE_NONE || !type_available) {
265                 fprintf(stderr, "Unknown device: %s\n", devicename.c_str());
266                 exit(EXIT_FAILURE);
267         }
268 #ifdef WITH_OSL
269         else if(!(ssname == "osl" || ssname == "svm")) {
270 #else
271         else if(!(ssname == "svm")) {
272 #endif
273                 fprintf(stderr, "Unknown shading system: %s\n", ssname.c_str());
274                 exit(EXIT_FAILURE);
275         }
276         else if(options.scene_params.shadingsystem == SceneParams::OSL && options.session_params.device_type != DEVICE_CPU) {
277                 fprintf(stderr, "OSL shading system only works with CPU device\n");
278                 exit(EXIT_FAILURE);
279         }
280         else if(options.session_params.samples < 0) {
281                 fprintf(stderr, "Invalid number of samples: %d\n", options.session_params.samples);
282                 exit(EXIT_FAILURE);
283         }
284         else if(options.filepath == "") {
285                 fprintf(stderr, "No file path specified\n");
286                 exit(EXIT_FAILURE);
287         }
288
289         /* load scene */
290         scene_init();
291 }
292
293 CCL_NAMESPACE_END
294
295 using namespace ccl;
296
297 int main(int argc, const char **argv)
298 {
299         path_init("../build/bin/2.59/scripts/addons/cycles/");
300
301         options_parse(argc, argv);
302
303         if(options.session_params.background) {
304                 session_init();
305                 options.session->wait();
306                 session_exit();
307         }
308         else {
309                 string title = "Cycles: " + path_filename(options.filepath);
310
311                 /* init/exit are callback so they run while GL is initialized */
312                 view_main_loop(title.c_str(), options.width, options.height,
313                         session_init, session_exit, resize, display, keyboard);
314         }
315
316         return 0;
317 }
318