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