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