Cycles: merge of changes from tomato branch.
[blender-staging.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, tile;
70         double total_time, sample_time;
71         string status, substatus;
72
73         /* get status */
74         sample = options.session->progress.get_sample();
75         options.session->progress.get_tile(tile, total_time, sample_time);
76         options.session->progress.get_status(status, substatus);
77
78         if(substatus != "")
79                 status += ": " + substatus;
80
81         /* print status */
82         status = string_printf("Sample %d   %s", sample, status.c_str());
83         session_print(status);
84 }
85
86 static BufferParams& session_buffer_params()
87 {
88         static BufferParams buffer_params;
89         buffer_params.width = options.width;
90         buffer_params.height = options.height;
91         buffer_params.full_width = options.width;
92         buffer_params.full_height = options.height;
93
94         return buffer_params;
95 }
96
97 static void session_init()
98 {
99         options.session = new Session(options.session_params);
100         options.session->reset(session_buffer_params(), options.session_params.samples);
101         options.session->scene = options.scene;
102         
103         if(options.session_params.background && !options.quiet)
104                 options.session->progress.set_update_callback(function_bind(&session_print_status));
105         else
106                 options.session->progress.set_update_callback(function_bind(&view_redraw));
107
108         options.session->start();
109
110         options.scene = NULL;
111 }
112
113 static void scene_init(int width, int height)
114 {
115         options.scene = new Scene(options.scene_params, options.session_params.device);
116         xml_read_file(options.scene, options.filepath.c_str());
117         
118         if (width == 0 || height == 0) {
119                 options.width = options.scene->camera->width;
120                 options.height = options.scene->camera->height;
121         }
122 }
123
124 static void session_exit()
125 {
126         if(options.session) {
127                 delete options.session;
128                 options.session = NULL;
129         }
130         if(options.scene) {
131                 delete options.scene;
132                 options.scene = NULL;
133         }
134
135         if(options.session_params.background && !options.quiet) {
136                 session_print("Finished Rendering.");
137                 printf("\n");
138         }
139 }
140
141 static void display_info(Progress& progress)
142 {
143         static double latency = 0.0;
144         static double last = 0;
145         double elapsed = time_dt();
146         string str;
147
148         latency = (elapsed - last);
149         last = elapsed;
150
151         int sample, tile;
152         double total_time, sample_time;
153         string status, substatus;
154
155         sample = progress.get_sample();
156         progress.get_tile(tile, total_time, sample_time);
157         progress.get_status(status, substatus);
158
159         if(substatus != "")
160                 status += ": " + substatus;
161
162         str = string_printf("latency: %.4f        sample: %d        total: %.4f        average: %.4f        %s",
163                 latency, sample, total_time, sample_time, status.c_str());
164
165         view_display_info(str.c_str());
166 }
167
168 static void display()
169 {
170         options.session->draw(session_buffer_params());
171
172         display_info(options.session->progress);
173 }
174
175 static void resize(int width, int height)
176 {
177         options.width = width;
178         options.height = height;
179
180         if(options.session)
181                 options.session->reset(session_buffer_params(), options.session_params.samples);
182 }
183
184 void keyboard(unsigned char key)
185 {
186         if(key == 'r')
187                 options.session->reset(session_buffer_params(), options.session_params.samples);
188         else if(key == 27) // escape
189                 options.session->progress.set_cancel("Cancelled");
190 }
191
192 static int files_parse(int argc, const char *argv[])
193 {
194         if(argc > 0)
195                 options.filepath = argv[0];
196
197         return 0;
198 }
199
200 static void options_parse(int argc, const char **argv)
201 {
202         options.width = 0;
203         options.height = 0;
204         options.filepath = "";
205         options.session = NULL;
206         options.quiet = false;
207
208         /* device names */
209         string device_names = "";
210         string devicename = "cpu";
211         bool list = false;
212
213         vector<DeviceType>& types = Device::available_types();
214
215         foreach(DeviceType type, types) {
216                 if(device_names != "")
217                         device_names += ", ";
218
219                 device_names += Device::string_from_type(type);
220         }
221
222         /* shading system */
223         string ssname = "svm";
224         string shadingsystems = "Shading system to use: svm";
225
226 #ifdef WITH_OSL
227         shadingsystems += ", osl"; 
228 #endif
229
230         /* parse options */
231         ArgParse ap;
232         bool help = false;
233
234         ap.options ("Usage: cycles_test [options] file.xml",
235                 "%*", files_parse, "",
236                 "--device %s", &devicename, ("Devices to use: " + device_names).c_str(),
237                 "--shadingsys %s", &ssname, "Shading system to use: svm, osl",
238                 "--background", &options.session_params.background, "Render in background, without user interface",
239                 "--quiet", &options.quiet, "In background mode, don't print progress messages",
240                 "--samples %d", &options.session_params.samples, "Number of samples to render",
241                 "--output %s", &options.session_params.output_path, "File path to write output image",
242                 "--threads %d", &options.session_params.threads, "CPU Rendering Threads",
243                 "--width  %d", &options.width, "Window width in pixel",
244                 "--height %d", &options.height, "Window height in pixel",
245                 "--list-devices", &list, "List information about all available devices",
246                 "--help", &help, "Print help message",
247                 NULL);
248         
249         if(ap.parse(argc, argv) < 0) {
250                 fprintf(stderr, "%s\n", ap.geterror().c_str());
251                 ap.usage();
252                 exit(EXIT_FAILURE);
253         }
254         else if(list) {
255                 vector<DeviceInfo>& devices = Device::available_devices();
256                 printf("Devices:\n");
257
258                 foreach(DeviceInfo& info, devices) {
259                         printf("    %s%s\n",
260                                 info.description.c_str(),
261                                 (info.display_device)? " (display)": "");
262                 }
263
264                 exit(EXIT_SUCCESS);
265         }
266         else if(help || options.filepath == "") {
267                 ap.usage();
268                 exit(EXIT_SUCCESS);
269         }
270
271         if(ssname == "osl")
272                 options.scene_params.shadingsystem = SceneParams::OSL;
273         else if(ssname == "svm")
274                 options.scene_params.shadingsystem = SceneParams::SVM;
275
276         /* find matching device */
277         DeviceType device_type = Device::type_from_string(devicename.c_str());
278         vector<DeviceInfo>& devices = Device::available_devices();
279         DeviceInfo device_info;
280         bool device_available = false;
281
282         foreach(DeviceInfo& device, devices) {
283                 if(device_type == device.type) {
284                         options.session_params.device = device;
285                         device_available = true;
286                         break;
287                 }
288         }
289
290         /* handle invalid configurations */
291         if(options.session_params.device.type == DEVICE_NONE || !device_available) {
292                 fprintf(stderr, "Unknown device: %s\n", devicename.c_str());
293                 exit(EXIT_FAILURE);
294         }
295 #ifdef WITH_OSL
296         else if(!(ssname == "osl" || ssname == "svm")) {
297 #else
298         else if(!(ssname == "svm")) {
299 #endif
300                 fprintf(stderr, "Unknown shading system: %s\n", ssname.c_str());
301                 exit(EXIT_FAILURE);
302         }
303         else if(options.scene_params.shadingsystem == SceneParams::OSL && options.session_params.device.type != DEVICE_CPU) {
304                 fprintf(stderr, "OSL shading system only works with CPU device\n");
305                 exit(EXIT_FAILURE);
306         }
307         else if(options.session_params.samples < 0) {
308                 fprintf(stderr, "Invalid number of samples: %d\n", options.session_params.samples);
309                 exit(EXIT_FAILURE);
310         }
311         else if(options.filepath == "") {
312                 fprintf(stderr, "No file path specified\n");
313                 exit(EXIT_FAILURE);
314         }
315
316         /* load scene */
317         scene_init(options.width, options.height);
318 }
319
320 CCL_NAMESPACE_END
321
322 using namespace ccl;
323
324 int main(int argc, const char **argv)
325 {
326         path_init("../build/bin/2.59/scripts/addons/cycles/");
327
328         options_parse(argc, argv);
329
330         if(options.session_params.background) {
331                 session_init();
332                 options.session->wait();
333                 session_exit();
334         }
335         else {
336                 string title = "Cycles: " + path_filename(options.filepath);
337
338                 /* init/exit are callback so they run while GL is initialized */
339                 view_main_loop(title.c_str(), options.width, options.height,
340                         session_init, session_exit, resize, display, keyboard);
341         }
342
343         return 0;
344 }
345