Cycles: Code cleanup, spaces around keywords
[blender-staging.git] / intern / cycles / app / cycles_standalone.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18
19 #include "buffers.h"
20 #include "camera.h"
21 #include "device.h"
22 #include "scene.h"
23 #include "session.h"
24
25 #include "util_args.h"
26 #include "util_foreach.h"
27 #include "util_function.h"
28 #include "util_logging.h"
29 #include "util_path.h"
30 #include "util_progress.h"
31 #include "util_string.h"
32 #include "util_time.h"
33 #include "util_transform.h"
34
35 #ifdef WITH_CYCLES_STANDALONE_GUI
36 #include "util_view.h"
37 #endif
38
39 #include "cycles_xml.h"
40
41 CCL_NAMESPACE_BEGIN
42
43 struct Options {
44         Session *session;
45         Scene *scene;
46         string filepath;
47         int width, height;
48         SceneParams scene_params;
49         SessionParams session_params;
50         bool quiet;
51         bool show_help, interactive, pause;
52 } options;
53
54 static void session_print(const string& str)
55 {
56         /* print with carriage return to overwrite previous */
57         printf("\r%s", str.c_str());
58
59         /* add spaces to overwrite longer previous print */
60         static int maxlen = 0;
61         int len = str.size();
62         maxlen = max(len, maxlen);
63
64         for(int i = len; i < maxlen; i++)
65                 printf(" ");
66
67         /* flush because we don't write an end of line */
68         fflush(stdout);
69 }
70
71 static void session_print_status()
72 {
73         int sample, tile;
74         double total_time, sample_time, render_time;
75         string status, substatus;
76
77         /* get status */
78         sample = options.session->progress.get_sample();
79         options.session->progress.get_tile(tile, total_time, sample_time, render_time);
80         options.session->progress.get_status(status, substatus);
81
82         if(substatus != "")
83                 status += ": " + substatus;
84
85         /* print status */
86         status = string_printf("Sample %d   %s", sample, status.c_str());
87         session_print(status);
88 }
89
90 static BufferParams& session_buffer_params()
91 {
92         static BufferParams buffer_params;
93         buffer_params.width = options.width;
94         buffer_params.height = options.height;
95         buffer_params.full_width = options.width;
96         buffer_params.full_height = options.height;
97
98         return buffer_params;
99 }
100
101 static void session_init()
102 {
103         options.session = new Session(options.session_params);
104         options.session->reset(session_buffer_params(), options.session_params.samples);
105         options.session->scene = options.scene;
106
107         if(options.session_params.background && !options.quiet)
108                 options.session->progress.set_update_callback(function_bind(&session_print_status));
109 #ifdef WITH_CYCLES_STANDALONE_GUI
110         else
111                 options.session->progress.set_update_callback(function_bind(&view_redraw));
112 #endif
113
114         options.session->start();
115
116         options.scene = NULL;
117 }
118
119 static void scene_init()
120 {
121         options.scene = new Scene(options.scene_params, options.session_params.device);
122
123         /* Read XML */
124         xml_read_file(options.scene, options.filepath.c_str());
125
126         /* Camera width/height override? */
127         if(!(options.width == 0 || options.height == 0)) {
128                 options.scene->camera->width = options.width;
129                 options.scene->camera->height = options.height;
130         }
131         else {
132                 options.width = options.scene->camera->width;
133                 options.height = options.scene->camera->height;
134         }
135
136         /* Calculate Viewplane */
137         options.scene->camera->compute_auto_viewplane();
138 }
139
140 static void session_exit()
141 {
142         if(options.session) {
143                 delete options.session;
144                 options.session = NULL;
145         }
146         if(options.scene) {
147                 delete options.scene;
148                 options.scene = NULL;
149         }
150
151         if(options.session_params.background && !options.quiet) {
152                 session_print("Finished Rendering.");
153                 printf("\n");
154         }
155 }
156
157 #ifdef WITH_CYCLES_STANDALONE_GUI
158 static void display_info(Progress& progress)
159 {
160         static double latency = 0.0;
161         static double last = 0;
162         double elapsed = time_dt();
163         string str, interactive;
164
165         latency = (elapsed - last);
166         last = elapsed;
167
168         int sample, tile;
169         double total_time, sample_time, render_time;
170         string status, substatus;
171
172         sample = progress.get_sample();
173         progress.get_tile(tile, total_time, sample_time, render_time);
174         progress.get_status(status, substatus);
175
176         if(substatus != "")
177                 status += ": " + substatus;
178
179         interactive = options.interactive? "On":"Off";
180
181         str = string_printf(
182                 "%s"
183                 "        Time: %.2f"
184                 "        Latency: %.4f"
185                 "        Sample: %d"
186                 "        Average: %.4f"
187                 "        Interactive: %s",
188                 status.c_str(), total_time, latency, sample, sample_time, interactive.c_str());
189
190         view_display_info(str.c_str());
191
192         if(options.show_help)
193                 view_display_help();
194 }
195
196 static void display()
197 {
198         static DeviceDrawParams draw_params = DeviceDrawParams();
199
200         options.session->draw(session_buffer_params(), draw_params);
201
202         display_info(options.session->progress);
203 }
204
205 static void motion(int x, int y, int button)
206 {
207         if(options.interactive) {
208                 Transform matrix = options.session->scene->camera->matrix;
209
210                 /* Translate */
211                 if(button == 0) {
212                         float3 translate = make_float3(x * 0.01f, -(y * 0.01f), 0.0f);
213                         matrix = matrix * transform_translate(translate);
214                 }
215
216                 /* Rotate */
217                 else if(button == 2) {
218                         float4 r1 = make_float4((float)x * 0.1f, 0.0f, 1.0f, 0.0f);
219                         matrix = matrix * transform_rotate(DEG2RADF(r1.x), make_float3(r1.y, r1.z, r1.w));
220
221                         float4 r2 = make_float4(y * 0.1f, 1.0f, 0.0f, 0.0f);
222                         matrix = matrix * transform_rotate(DEG2RADF(r2.x), make_float3(r2.y, r2.z, r2.w));
223                 }
224
225                 /* Update and Reset */
226                 options.session->scene->camera->matrix = matrix;
227                 options.session->scene->camera->need_update = true;
228                 options.session->scene->camera->need_device_update = true;
229
230                 options.session->reset(session_buffer_params(), options.session_params.samples);
231         }
232 }
233
234 static void resize(int width, int height)
235 {
236         options.width = width;
237         options.height = height;
238
239         if(options.session) {
240                 /* Update camera */
241                 options.session->scene->camera->width = width;
242                 options.session->scene->camera->height = height;
243                 options.session->scene->camera->compute_auto_viewplane();
244                 options.session->scene->camera->need_update = true;
245                 options.session->scene->camera->need_device_update = true;
246
247                 options.session->reset(session_buffer_params(), options.session_params.samples);
248         }
249 }
250
251 static void keyboard(unsigned char key)
252 {
253         /* Toggle help */
254         if(key == 'h')
255                 options.show_help = !(options.show_help);
256
257         /* Reset */
258         else if(key == 'r')
259                 options.session->reset(session_buffer_params(), options.session_params.samples);
260
261         /* Cancel */
262         else if(key == 27) // escape
263                 options.session->progress.set_cancel("Canceled");
264
265         /* Pause */
266         else if(key == 'p') {
267                 options.pause = !options.pause;
268                 options.session->set_pause(options.pause);
269         }
270
271         /* Interactive Mode */
272         else if(key == 'i')
273                 options.interactive = !(options.interactive);
274
275         else if(options.interactive && (key == 'w' || key == 'a' || key == 's' || key == 'd')) {
276                 Transform matrix = options.session->scene->camera->matrix;
277                 float3 translate;
278
279                 if(key == 'w')
280                         translate = make_float3(0.0f, 0.0f, 0.1f);
281                 else if(key == 's')
282                         translate = make_float3(0.0f, 0.0f, -0.1f);
283                 else if(key == 'a')
284                         translate = make_float3(-0.1f, 0.0f, 0.0f);
285                 else if(key == 'd')
286                         translate = make_float3(0.1f, 0.0f, 0.0f);
287
288                 matrix = matrix * transform_translate(translate);
289
290                 /* Update and Reset */
291                 options.session->scene->camera->matrix = matrix;
292                 options.session->scene->camera->need_update = true;
293                 options.session->scene->camera->need_device_update = true;
294
295                 options.session->reset(session_buffer_params(), options.session_params.samples);
296         }
297 }
298 #endif
299
300 static int files_parse(int argc, const char *argv[])
301 {
302         if(argc > 0)
303                 options.filepath = argv[0];
304
305         return 0;
306 }
307
308 static void options_parse(int argc, const char **argv)
309 {
310         options.width = 0;
311         options.height = 0;
312         options.filepath = "";
313         options.session = NULL;
314         options.quiet = false;
315
316         /* device names */
317         string device_names = "";
318         string devicename = "cpu";
319         bool list = false;
320
321         vector<DeviceType>& types = Device::available_types();
322
323         /* TODO(sergey): Here's a feedback loop happens: on the one hand we want
324          * the device list to be printed in help message, on the other hand logging
325          * is not initialized yet so we wouldn't have debug log happening in the
326          * device initialization.
327          */
328         foreach(DeviceType type, types) {
329                 if(device_names != "")
330                         device_names += ", ";
331
332                 device_names += Device::string_from_type(type);
333         }
334
335         /* shading system */
336         string ssname = "svm";
337
338         /* parse options */
339         ArgParse ap;
340         bool help = false, debug = false;
341         int verbosity = 1;
342
343         ap.options ("Usage: cycles [options] file.xml",
344                 "%*", files_parse, "",
345                 "--device %s", &devicename, ("Devices to use: " + device_names).c_str(),
346 #ifdef WITH_OSL
347                 "--shadingsys %s", &ssname, "Shading system to use: svm, osl",
348 #endif
349                 "--background", &options.session_params.background, "Render in background, without user interface",
350                 "--quiet", &options.quiet, "In background mode, don't print progress messages",
351                 "--samples %d", &options.session_params.samples, "Number of samples to render",
352                 "--output %s", &options.session_params.output_path, "File path to write output image",
353                 "--threads %d", &options.session_params.threads, "CPU Rendering Threads",
354                 "--width  %d", &options.width, "Window width in pixel",
355                 "--height %d", &options.height, "Window height in pixel",
356                 "--list-devices", &list, "List information about all available devices",
357 #ifdef WITH_CYCLES_LOGGING
358                 "--debug", &debug, "Enable debug logging",
359                 "--verbose %d", &verbosity, "Set verbosity of the logger",
360 #endif
361                 "--help", &help, "Print help message",
362                 NULL);
363
364         if(ap.parse(argc, argv) < 0) {
365                 fprintf(stderr, "%s\n", ap.geterror().c_str());
366                 ap.usage();
367                 exit(EXIT_FAILURE);
368         }
369
370         if(debug) {
371                 util_logging_start();
372                 util_logging_verbosity_set(verbosity);
373         }
374
375         if(list) {
376                 vector<DeviceInfo>& devices = Device::available_devices();
377                 printf("Devices:\n");
378
379                 foreach(DeviceInfo& info, devices) {
380                         printf("    %s%s\n",
381                                 info.description.c_str(),
382                                 (info.display_device)? " (display)": "");
383                 }
384
385                 exit(EXIT_SUCCESS);
386         }
387         else if(help || options.filepath == "") {
388                 ap.usage();
389                 exit(EXIT_SUCCESS);
390         }
391
392         if(ssname == "osl")
393                 options.scene_params.shadingsystem = SHADINGSYSTEM_OSL;
394         else if(ssname == "svm")
395                 options.scene_params.shadingsystem = SHADINGSYSTEM_SVM;
396
397 #ifndef WITH_CYCLES_STANDALONE_GUI
398         options.session_params.background = true;
399 #endif
400
401         /* Use progressive rendering */
402         options.session_params.progressive = true;
403
404         /* find matching device */
405         DeviceType device_type = Device::type_from_string(devicename.c_str());
406         vector<DeviceInfo>& devices = Device::available_devices();
407         DeviceInfo device_info;
408         bool device_available = false;
409
410         foreach(DeviceInfo& device, devices) {
411                 if(device_type == device.type) {
412                         options.session_params.device = device;
413                         device_available = true;
414                         break;
415                 }
416         }
417
418         /* handle invalid configurations */
419         if(options.session_params.device.type == DEVICE_NONE || !device_available) {
420                 fprintf(stderr, "Unknown device: %s\n", devicename.c_str());
421                 exit(EXIT_FAILURE);
422         }
423 #ifdef WITH_OSL
424         else if(!(ssname == "osl" || ssname == "svm")) {
425                 fprintf(stderr, "Unknown shading system: %s\n", ssname.c_str());
426                 exit(EXIT_FAILURE);
427         }
428         else if(options.scene_params.shadingsystem == SHADINGSYSTEM_OSL && options.session_params.device.type != DEVICE_CPU) {
429                 fprintf(stderr, "OSL shading system only works with CPU device\n");
430                 exit(EXIT_FAILURE);
431         }
432 #endif
433         else if(options.session_params.samples < 0) {
434                 fprintf(stderr, "Invalid number of samples: %d\n", options.session_params.samples);
435                 exit(EXIT_FAILURE);
436         }
437         else if(options.filepath == "") {
438                 fprintf(stderr, "No file path specified\n");
439                 exit(EXIT_FAILURE);
440         }
441
442         /* For smoother Viewport */
443         options.session_params.start_resolution = 64;
444
445         /* load scene */
446         scene_init();
447 }
448
449 CCL_NAMESPACE_END
450
451 using namespace ccl;
452
453 int main(int argc, const char **argv)
454 {
455         util_logging_init(argv[0]);
456         path_init();
457         options_parse(argc, argv);
458
459 #ifdef WITH_CYCLES_STANDALONE_GUI
460         if(options.session_params.background) {
461 #endif
462                 session_init();
463                 options.session->wait();
464                 session_exit();
465 #ifdef WITH_CYCLES_STANDALONE_GUI
466         }
467         else {
468                 string title = "Cycles: " + path_filename(options.filepath);
469
470                 /* init/exit are callback so they run while GL is initialized */
471                 view_main_loop(title.c_str(), options.width, options.height,
472                         session_init, session_exit, resize, display, keyboard, motion);
473         }
474 #endif
475
476         return 0;
477 }
478