--debug-gpu-shader: Dump GLSL shaders to disk
[blender.git] / source / creator / creator_args.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
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  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file creator/creator_args.c
22  *  \ingroup creator
23  */
24
25 #ifndef WITH_PYTHON_MODULE
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #ifdef WIN32
34 #  include "BLI_winstuff.h"
35 #endif
36
37 #include "BLI_args.h"
38 #include "BLI_threads.h"
39 #include "BLI_utildefines.h"
40 #include "BLI_listbase.h"
41 #include "BLI_string.h"
42 #include "BLI_string_utf8.h"
43 #include "BLI_path_util.h"
44 #include "BLI_fileops.h"
45 #include "BLI_mempool.h"
46
47 #include "BKE_blender_version.h"
48 #include "BKE_context.h"
49
50 #include "BKE_global.h"
51 #include "BKE_library.h"
52 #include "BKE_main.h"
53 #include "BKE_scene.h"
54 #include "BKE_report.h"
55 #include "BKE_sound.h"
56 #include "BKE_image.h"
57
58 #ifdef WITH_FFMPEG
59 #include "IMB_imbuf.h"
60 #endif
61
62 #ifdef WITH_PYTHON
63 #include "BPY_extern.h"
64 #endif
65
66 #include "RE_engine.h"
67 #include "RE_pipeline.h"
68
69 #include "ED_datafiles.h"
70
71 #include "WM_api.h"
72
73 #include "GPU_draw.h"
74
75 /* for passing information between creator and gameengine */
76 #ifdef WITH_GAMEENGINE
77 #  include "BL_System.h"
78 #else /* dummy */
79 #  define SYS_SystemHandle int
80 #endif
81
82 #ifdef WITH_LIBMV
83 #  include "libmv-capi.h"
84 #endif
85
86 #ifdef WITH_CYCLES_LOGGING
87 #  include "CCL_api.h"
88 #endif
89
90 #include "creator_intern.h"  /* own include */
91
92
93 /* -------------------------------------------------------------------- */
94
95 /** \name Utility String Parsing
96  * \{ */
97
98 static bool parse_int_relative(
99         const char *str, const char *str_end_test, int pos, int neg,
100         int *r_value, const char **r_err_msg)
101 {
102         char *str_end = NULL;
103         long value;
104
105         errno = 0;
106
107         switch (*str) {
108                 case '+':
109                         value = pos + strtol(str + 1, &str_end, 10);
110                         break;
111                 case '-':
112                         value = (neg - strtol(str + 1, &str_end, 10)) + 1;
113                         break;
114                 default:
115                         value = strtol(str, &str_end, 10);
116                         break;
117         }
118
119
120         if (*str_end != '\0' && (str_end != str_end_test)) {
121                 static const char *msg = "not a number";
122                 *r_err_msg = msg;
123                 return false;
124         }
125         else if ((errno == ERANGE) || ((value < INT_MIN || value > INT_MAX))) {
126                 static const char *msg = "exceeds range";
127                 *r_err_msg = msg;
128                 return false;
129         }
130         else {
131                 *r_value = (int)value;
132                 return true;
133         }
134 }
135
136 static const char *parse_int_range_sep_search(const char *str, const char *str_end_test)
137 {
138         const char *str_end_range = NULL;
139         if (str_end_test) {
140                 str_end_range = memchr(str, '.', (str_end_test - str) - 1);
141                 if (str_end_range && (str_end_range[1] != '.')) {
142                         str_end_range = NULL;
143                 }
144         }
145         else {
146                 str_end_range = strstr(str, "..");
147                 if (str_end_range && (str_end_range[2] == '\0')) {
148                         str_end_range = NULL;
149                 }
150         }
151         return str_end_range;
152 }
153
154 /**
155  * Parse a number as a range, eg: `1..4`.
156  *
157  * The \a str_end_range argument is a result of #parse_int_range_sep_search.
158  */
159 static bool parse_int_range_relative(
160         const char *str, const char *str_end_range, const char *str_end_test, int pos, int neg,
161         int r_value_range[2], const char **r_err_msg)
162 {
163         if (parse_int_relative(str,               str_end_range, pos, neg, &r_value_range[0], r_err_msg) &&
164             parse_int_relative(str_end_range + 2, str_end_test,  pos, neg, &r_value_range[1], r_err_msg))
165         {
166                 return true;
167         }
168         else {
169                 return false;
170         }
171 }
172
173 static bool parse_int_relative_clamp(
174         const char *str, const char *str_end_test, int pos, int neg, int min, int max,
175         int *r_value, const char **r_err_msg)
176 {
177         if (parse_int_relative(str, str_end_test, pos, neg, r_value, r_err_msg)) {
178                 CLAMP(*r_value, min, max);
179                 return true;
180         }
181         else {
182                 return false;
183         }
184 }
185
186 static bool parse_int_range_relative_clamp(
187         const char *str, const char *str_end_range, const char *str_end_test, int pos, int neg, int min, int max,
188         int r_value_range[2], const char **r_err_msg)
189 {
190         if (parse_int_range_relative(str, str_end_range, str_end_test, pos, neg, r_value_range, r_err_msg)) {
191                 CLAMP(r_value_range[0], min, max);
192                 CLAMP(r_value_range[1], min, max);
193                 return true;
194         }
195         else {
196                 return false;
197         }
198 }
199
200 /**
201  * No clamping, fails with any number outside the range.
202  */
203 static bool parse_int_strict_range(
204         const char *str, const char *str_end_test, const int min, const int max,
205         int *r_value, const char **r_err_msg)
206 {
207         char *str_end = NULL;
208         long value;
209
210         errno = 0;
211         value = strtol(str, &str_end, 10);
212
213         if (*str_end != '\0' && (str_end != str_end_test)) {
214                 static const char *msg = "not a number";
215                 *r_err_msg = msg;
216                 return false;
217         }
218         else if ((errno == ERANGE) || ((value < min || value > max))) {
219                 static const char *msg = "exceeds range";
220                 *r_err_msg = msg;
221                 return false;
222         }
223         else {
224                 *r_value = (int)value;
225                 return true;
226         }
227 }
228
229 static bool parse_int(
230         const char *str, const char *str_end_test,
231         int *r_value, const char **r_err_msg)
232 {
233         return parse_int_strict_range(str, str_end_test, INT_MIN, INT_MAX, r_value, r_err_msg);
234 }
235
236 static bool parse_int_clamp(
237         const char *str, const char *str_end_test, int min, int max,
238         int *r_value, const char **r_err_msg)
239 {
240         if (parse_int(str, str_end_test, r_value, r_err_msg)) {
241                 CLAMP(*r_value, min, max);
242                 return true;
243         }
244         else {
245                 return false;
246         }
247 }
248
249 #if 0
250 /**
251  * Version of #parse_int_relative_clamp
252  * that parses a comma separated list of numbers.
253  */
254 static int *parse_int_relative_clamp_n(
255         const char *str, int pos, int neg, int min, int max,
256         int *r_value_len, const char **r_err_msg)
257 {
258         const char sep = ',';
259         int len = 1;
260         for (int i = 0; str[i]; i++) {
261                 if (str[i] == sep) {
262                         len++;
263                 }
264         }
265
266         int *values = MEM_mallocN(sizeof(*values) * len, __func__);
267         int i = 0;
268         while (true) {
269                 const char *str_end = strchr(str, sep);
270                 if ((*str == sep) || (*str == '\0')) {
271                         static const char *msg = "incorrect comma use";
272                         *r_err_msg = msg;
273                         goto fail;
274
275                 }
276                 else if (parse_int_relative_clamp(str, str_end, pos, neg, min, max, &values[i], r_err_msg)) {
277                         i++;
278                 }
279                 else {
280                         goto fail;  /* error message already set */
281                 }
282
283                 if (str_end) {  /* next */
284                         str = str_end + 1;
285                 }
286                 else {  /* finished */
287                         break;
288                 }
289         }
290
291         *r_value_len = i;
292         return values;
293
294 fail:
295         MEM_freeN(values);
296         return NULL;
297 }
298
299 #endif
300
301 /**
302  * Version of #parse_int_relative_clamp & #parse_int_range_relative_clamp
303  * that parses a comma separated list of numbers.
304  *
305  * \note single values are evaluated as a range with matching start/end.
306  */
307 static int (*parse_int_range_relative_clamp_n(
308         const char *str, int pos, int neg, int min, int max,
309         int *r_value_len, const char **r_err_msg))[2]
310 {
311         const char sep = ',';
312         int len = 1;
313         for (int i = 0; str[i]; i++) {
314                 if (str[i] == sep) {
315                         len++;
316                 }
317         }
318
319         int (*values)[2] = MEM_mallocN(sizeof(*values) * len, __func__);
320         int i = 0;
321         while (true) {
322                 const char *str_end_range;
323                 const char *str_end = strchr(str, sep);
324                 if ((*str == sep) || (*str == '\0')) {
325                         static const char *msg = "incorrect comma use";
326                         *r_err_msg = msg;
327                         goto fail;
328                 }
329                 else if ((str_end_range = parse_int_range_sep_search(str, str_end)) ?
330                          parse_int_range_relative_clamp(str, str_end_range, str_end, pos, neg, min, max, values[i], r_err_msg) :
331                          parse_int_relative_clamp(str, str_end, pos, neg, min, max, &values[i][0], r_err_msg))
332                 {
333                         if (str_end_range == NULL) {
334                                 values[i][1] = values[i][0];
335                         }
336                         i++;
337                 }
338                 else {
339                         goto fail;  /* error message already set */
340                 }
341
342                 if (str_end) {  /* next */
343                         str = str_end + 1;
344                 }
345                 else {  /* finished */
346                         break;
347                 }
348         }
349
350         *r_value_len = i;
351         return values;
352
353 fail:
354         MEM_freeN(values);
355         return NULL;
356 }
357
358 /** \} */
359
360
361 /* -------------------------------------------------------------------- */
362
363 #ifdef WITH_PYTHON
364
365 /** \name Utilities Python Context Macro (#BPY_CTX_SETUP)
366  * \{ */
367 struct BlendePyContextStore {
368         wmWindowManager *wm;
369         Scene *scene;
370         wmWindow *win;
371         bool has_win;
372 };
373
374 static void arg_py_context_backup(
375         bContext *C, struct BlendePyContextStore *c_py,
376         const char *script_id)
377 {
378         c_py->wm = CTX_wm_manager(C);
379         c_py->scene = CTX_data_scene(C);
380         c_py->has_win = !BLI_listbase_is_empty(&c_py->wm->windows);
381         if (c_py->has_win) {
382                 c_py->win = CTX_wm_window(C);
383                 CTX_wm_window_set(C, c_py->wm->windows.first);
384         }
385         else {
386                 c_py->win = NULL;
387                 fprintf(stderr, "Python script \"%s\" "
388                         "running with missing context data.\n", script_id);
389         }
390 }
391
392 static void arg_py_context_restore(
393         bContext *C, struct BlendePyContextStore *c_py)
394 {
395         /* script may load a file, check old data is valid before using */
396         if (c_py->has_win) {
397                 if ((c_py->win == NULL) ||
398                     ((BLI_findindex(&G.main->wm, c_py->wm) != -1) &&
399                      (BLI_findindex(&c_py->wm->windows, c_py->win) != -1)))
400                 {
401                         CTX_wm_window_set(C, c_py->win);
402                 }
403         }
404
405         if ((c_py->scene == NULL) ||
406             BLI_findindex(&G.main->scene, c_py->scene) != -1)
407         {
408                 CTX_data_scene_set(C, c_py->scene);
409         }
410 }
411
412 /* macro for context setup/reset */
413 #define BPY_CTX_SETUP(_cmd) \
414         { \
415                 struct BlendePyContextStore py_c; \
416                 arg_py_context_backup(C, &py_c, argv[1]); \
417                 { _cmd; } \
418                 arg_py_context_restore(C, &py_c); \
419         } ((void)0)
420
421 #endif /* WITH_PYTHON */
422
423 /** \} */
424
425
426 /* -------------------------------------------------------------------- */
427
428 /** \name Handle Argument Callbacks
429  *
430  * \note Doc strings here are used in differently:
431  *
432  * - The `--help` message.
433  * - The man page (for Unix systems),
434  *   see: `doc/manpage/blender.1.py`
435  * - Parsed and extracted for the manual,
436  *   which converts our ad-hoc formatting to reStructuredText.
437  *   see: https://docs.blender.org/manual/en/dev/advanced/command_line.html
438  *
439  * \{ */
440
441 static const char arg_handle_print_version_doc[] =
442 "\n\tPrint Blender version and exit"
443 ;
444 static int arg_handle_print_version(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
445 {
446         printf(BLEND_VERSION_STRING_FMT);
447 #ifdef BUILD_DATE
448         printf("\tbuild date: %s\n", build_date);
449         printf("\tbuild time: %s\n", build_time);
450         printf("\tbuild commit date: %s\n", build_commit_date);
451         printf("\tbuild commit time: %s\n", build_commit_time);
452         printf("\tbuild hash: %s\n", build_hash);
453         printf("\tbuild platform: %s\n", build_platform);
454         printf("\tbuild type: %s\n", build_type);
455         printf("\tbuild c flags: %s\n", build_cflags);
456         printf("\tbuild c++ flags: %s\n", build_cxxflags);
457         printf("\tbuild link flags: %s\n", build_linkflags);
458         printf("\tbuild system: %s\n", build_system);
459 #endif
460         exit(0);
461
462         return 0;
463 }
464
465 static const char arg_handle_print_help_doc[] =
466 "\n\tPrint this help text and exit"
467 ;
468 static const char arg_handle_print_help_doc_win32[] =
469 "\n\tPrint this help text and exit (windows only)"
470 ;
471 static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), void *data)
472 {
473         bArgs *ba = (bArgs *)data;
474
475         printf(BLEND_VERSION_STRING_FMT);
476         printf("Usage: blender [args ...] [file] [args ...]\n\n");
477
478         printf("Render Options:\n");
479         BLI_argsPrintArgDoc(ba, "--background");
480         BLI_argsPrintArgDoc(ba, "--render-anim");
481         BLI_argsPrintArgDoc(ba, "--scene");
482         BLI_argsPrintArgDoc(ba, "--render-frame");
483         BLI_argsPrintArgDoc(ba, "--frame-start");
484         BLI_argsPrintArgDoc(ba, "--frame-end");
485         BLI_argsPrintArgDoc(ba, "--frame-jump");
486         BLI_argsPrintArgDoc(ba, "--render-output");
487         BLI_argsPrintArgDoc(ba, "--engine");
488         BLI_argsPrintArgDoc(ba, "--threads");
489
490         printf("\n");
491         printf("Format Options:\n");
492         BLI_argsPrintArgDoc(ba, "--render-format");
493         BLI_argsPrintArgDoc(ba, "--use-extension");
494
495         printf("\n");
496         printf("Animation Playback Options:\n");
497         BLI_argsPrintArgDoc(ba, "-a");
498
499         printf("\n");
500         printf("Window Options:\n");
501         BLI_argsPrintArgDoc(ba, "--window-border");
502         BLI_argsPrintArgDoc(ba, "--window-borderless");
503         BLI_argsPrintArgDoc(ba, "--window-geometry");
504         BLI_argsPrintArgDoc(ba, "--start-console");
505         BLI_argsPrintArgDoc(ba, "--no-native-pixels");
506
507
508         printf("\n");
509         printf("Game Engine Specific Options:\n");
510         BLI_argsPrintArgDoc(ba, "-g");
511
512         printf("\n");
513         printf("Python Options:\n");
514         BLI_argsPrintArgDoc(ba, "--enable-autoexec");
515         BLI_argsPrintArgDoc(ba, "--disable-autoexec");
516
517         printf("\n");
518
519         BLI_argsPrintArgDoc(ba, "--python");
520         BLI_argsPrintArgDoc(ba, "--python-text");
521         BLI_argsPrintArgDoc(ba, "--python-expr");
522         BLI_argsPrintArgDoc(ba, "--python-console");
523         BLI_argsPrintArgDoc(ba, "--python-exit-code");
524         BLI_argsPrintArgDoc(ba, "--addons");
525
526
527         printf("\n");
528         printf("Debug Options:\n");
529         BLI_argsPrintArgDoc(ba, "--debug");
530         BLI_argsPrintArgDoc(ba, "--debug-value");
531
532         printf("\n");
533         BLI_argsPrintArgDoc(ba, "--debug-events");
534 #ifdef WITH_FFMPEG
535         BLI_argsPrintArgDoc(ba, "--debug-ffmpeg");
536 #endif
537         BLI_argsPrintArgDoc(ba, "--debug-handlers");
538 #ifdef WITH_LIBMV
539         BLI_argsPrintArgDoc(ba, "--debug-libmv");
540 #endif
541 #ifdef WITH_CYCLES_LOGGING
542         BLI_argsPrintArgDoc(ba, "--debug-cycles");
543 #endif
544         BLI_argsPrintArgDoc(ba, "--debug-memory");
545         BLI_argsPrintArgDoc(ba, "--debug-jobs");
546         BLI_argsPrintArgDoc(ba, "--debug-python");
547         BLI_argsPrintArgDoc(ba, "--debug-depsgraph");
548         BLI_argsPrintArgDoc(ba, "--debug-depsgraph-no-threads");
549
550         BLI_argsPrintArgDoc(ba, "--debug-gpumem");
551         BLI_argsPrintArgDoc(ba, "--debug-gpu-shaders");
552         BLI_argsPrintArgDoc(ba, "--debug-wm");
553         BLI_argsPrintArgDoc(ba, "--debug-all");
554         BLI_argsPrintArgDoc(ba, "--debug-io");
555
556         printf("\n");
557         BLI_argsPrintArgDoc(ba, "--debug-fpe");
558         BLI_argsPrintArgDoc(ba, "--disable-crash-handler");
559
560         printf("\n");
561         printf("Misc Options:\n");
562         BLI_argsPrintArgDoc(ba, "--factory-startup");
563         printf("\n");
564         BLI_argsPrintArgDoc(ba, "--env-system-datafiles");
565         BLI_argsPrintArgDoc(ba, "--env-system-scripts");
566         BLI_argsPrintArgDoc(ba, "--env-system-python");
567         printf("\n");
568         BLI_argsPrintArgDoc(ba, "-nojoystick");
569         BLI_argsPrintArgDoc(ba, "-noaudio");
570         BLI_argsPrintArgDoc(ba, "-setaudio");
571
572         printf("\n");
573
574         BLI_argsPrintArgDoc(ba, "--help");
575
576 #ifdef WIN32
577         BLI_argsPrintArgDoc(ba, "-R");
578         BLI_argsPrintArgDoc(ba, "-r");
579 #endif
580         BLI_argsPrintArgDoc(ba, "--version");
581
582         BLI_argsPrintArgDoc(ba, "--");
583
584         printf("\n");
585         printf("Experimental Features:\n");
586
587         /* Other options _must_ be last (anything not handled will show here) */
588         printf("\n");
589         printf("Other Options:\n");
590         BLI_argsPrintOtherDoc(ba);
591
592         printf("\n");
593         printf("Argument Parsing:\n");
594         printf("\tArguments must be separated by white space, eg:\n");
595         printf("\t# blender -ba test.blend\n");
596         printf("\t...will ignore the 'a'\n");
597         printf("\t# blender -b test.blend -f8\n");
598         printf("\t...will ignore '8' because there is no space between the '-f' and the frame value\n\n");
599
600         printf("Argument Order:\n");
601         printf("\tArguments are executed in the order they are given. eg:\n");
602         printf("\t# blender --background test.blend --render-frame 1 --render-output '/tmp'\n");
603         printf("\t...will not render to '/tmp' because '--render-frame 1' renders before the output path is set\n");
604         printf("\t# blender --background --render-output /tmp test.blend --render-frame 1\n");
605         printf("\t...will not render to '/tmp' because loading the blend-file overwrites the render output that was set\n");
606         printf("\t# blender --background test.blend --render-output /tmp --render-frame 1\n");
607         printf("\t...works as expected.\n\n");
608
609         printf("Environment Variables:\n");
610         printf("  $BLENDER_USER_CONFIG      Directory for user configuration files.\n");
611         printf("  $BLENDER_USER_SCRIPTS     Directory for user scripts.\n");
612         printf("  $BLENDER_SYSTEM_SCRIPTS   Directory for system wide scripts.\n");
613         printf("  $BLENDER_USER_DATAFILES   Directory for user data files (icons, translations, ..).\n");
614         printf("  $BLENDER_SYSTEM_DATAFILES Directory for system wide data files.\n");
615         printf("  $BLENDER_SYSTEM_PYTHON    Directory for system python libraries.\n");
616 #ifdef WIN32
617         printf("  $TEMP                     Store temporary files here.\n");
618 #else
619         printf("  $TMP or $TMPDIR           Store temporary files here.\n");
620 #endif
621 #ifdef WITH_SDL
622         printf("  $SDL_AUDIODRIVER          LibSDL audio driver - alsa, esd, dma.\n");
623 #endif
624         printf("  $PYTHONHOME               Path to the python directory, eg. /usr/lib/python.\n\n");
625
626         exit(0);
627
628         return 0;
629 }
630
631 static const char arg_handle_arguments_end_doc[] =
632 "\n\tEnds option processing, following arguments passed unchanged. Access via Python's 'sys.argv'"
633 ;
634 static int arg_handle_arguments_end(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
635 {
636         return -1;
637 }
638
639 /* only to give help message */
640 #ifndef WITH_PYTHON_SECURITY /* default */
641 #  define   PY_ENABLE_AUTO ", (default)"
642 #  define   PY_DISABLE_AUTO ""
643 #else
644 #  define   PY_ENABLE_AUTO ""
645 #  define   PY_DISABLE_AUTO ", (compiled as non-standard default)"
646 #endif
647
648 static const char arg_handle_python_set_doc_enable[] =
649 "\n\tEnable automatic Python script execution" PY_ENABLE_AUTO
650 ;
651 static const char arg_handle_python_set_doc_disable[] =
652 "\n\tDisable automatic Python script execution (pydrivers & startup scripts)" PY_DISABLE_AUTO
653 ;
654 #undef PY_ENABLE_AUTO
655 #undef PY_DISABLE_AUTO
656
657 static int arg_handle_python_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
658 {
659         if ((bool)data) {
660                 G.f |= G_SCRIPT_AUTOEXEC;
661         }
662         else {
663                 G.f &= ~G_SCRIPT_AUTOEXEC;
664         }
665         G.f |= G_SCRIPT_OVERRIDE_PREF;
666         return 0;
667 }
668
669 static const char arg_handle_crash_handler_disable_doc[] =
670 "\n\tDisable the crash handler"
671 ;
672 static int arg_handle_crash_handler_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
673 {
674         app_state.signal.use_crash_handler = false;
675         return 0;
676 }
677
678 static const char arg_handle_abort_handler_disable_doc[] =
679 "\n\tDisable the abort handler"
680 ;
681 static int arg_handle_abort_handler_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
682 {
683         app_state.signal.use_abort_handler = false;
684         return 0;
685 }
686
687 static const char arg_handle_background_mode_set_doc[] =
688 "\n\tRun in background (often used for UI-less rendering)"
689 ;
690 static int arg_handle_background_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
691 {
692         G.background = 1;
693         return 0;
694 }
695
696 static const char arg_handle_debug_mode_set_doc[] =
697 "\n"
698 "\tTurn debugging on\n"
699 "\n"
700 "\t* Enables memory error detection\n"
701 "\t* Disables mouse grab (to interact with a debugger in some cases)\n"
702 "\t* Keeps Python's 'sys.stdin' rather than setting it to None"
703 ;
704 static int arg_handle_debug_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
705 {
706         G.debug |= G_DEBUG;  /* std output printf's */
707         printf(BLEND_VERSION_STRING_FMT);
708         MEM_set_memory_debug();
709 #ifndef NDEBUG
710         BLI_mempool_set_memory_debug();
711 #endif
712
713 #ifdef WITH_BUILDINFO
714         printf("Build: %s %s %s %s\n", build_date, build_time, build_platform, build_type);
715 #endif
716
717         BLI_argsPrint(data);
718         return 0;
719 }
720
721 #ifdef WITH_FFMPEG
722 static const char arg_handle_debug_mode_generic_set_doc_ffmpeg[] =
723 "\n\tEnable debug messages from FFmpeg library";
724 #endif
725 #ifdef WITH_FREESTYLE
726 static const char arg_handle_debug_mode_generic_set_doc_freestyle[] =
727 "\n\tEnable debug messages for FreeStyle";
728 #endif
729 static const char arg_handle_debug_mode_generic_set_doc_python[] =
730 "\n\tEnable debug messages for Python";
731 static const char arg_handle_debug_mode_generic_set_doc_events[] =
732 "\n\tEnable debug messages for the event system";
733 static const char arg_handle_debug_mode_generic_set_doc_handlers[] =
734 "\n\tEnable debug messages for event handling";
735 static const char arg_handle_debug_mode_generic_set_doc_wm[] =
736 "\n\tEnable debug messages for the window manager, also prints every operator call";
737 static const char arg_handle_debug_mode_generic_set_doc_jobs[] =
738 "\n\tEnable time profiling for background jobs.";
739 static const char arg_handle_debug_mode_generic_set_doc_gpu[] =
740 "\n\tEnable gpu debug context and information for OpenGL 4.3+.";
741 static const char arg_handle_debug_mode_generic_set_doc_depsgraph[] =
742 "\n\tEnable debug messages from dependency graph";
743 static const char arg_handle_debug_mode_generic_set_doc_depsgraph_no_threads[] =
744 "\n\tSwitch dependency graph to a single threaded evaluation";
745 static const char arg_handle_debug_mode_generic_set_doc_gpumem[] =
746 "\n\tEnable GPU memory stats in status bar";
747
748 static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
749 {
750         G.debug |= GET_INT_FROM_POINTER(data);
751         return 0;
752 }
753
754 static const char arg_handle_debug_mode_io_doc[] =
755 "\n\tEnable debug messages for I/O (collada, ...)";
756 static int arg_handle_debug_mode_io(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
757 {
758         G.debug |= G_DEBUG_IO;
759         return 0;
760 }
761
762 static const char arg_handle_debug_mode_all_doc[] =
763 "\n\tEnable all debug messages";
764 static int arg_handle_debug_mode_all(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
765 {
766         G.debug |= G_DEBUG_ALL;
767 #ifdef WITH_LIBMV
768         libmv_startDebugLogging();
769 #endif
770 #ifdef WITH_CYCLES_LOGGING
771         CCL_start_debug_logging();
772 #endif
773         return 0;
774 }
775
776 #ifdef WITH_LIBMV
777 static const char arg_handle_debug_mode_libmv_doc[] =
778 "\n\tEnable debug messages from libmv library"
779 ;
780 static int arg_handle_debug_mode_libmv(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
781 {
782         libmv_startDebugLogging();
783
784         return 0;
785 }
786 #endif
787
788 #ifdef WITH_CYCLES_LOGGING
789 static const char arg_handle_debug_mode_cycles_doc[] =
790 "\n\tEnable debug messages from Cycles"
791 ;
792 static int arg_handle_debug_mode_cycles(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
793 {
794         CCL_start_debug_logging();
795         return 0;
796 }
797 #endif
798
799 static const char arg_handle_debug_mode_memory_set_doc[] =
800 "\n\tEnable fully guarded memory allocation and debugging"
801 ;
802 static int arg_handle_debug_mode_memory_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
803 {
804         MEM_set_memory_debug();
805         return 0;
806 }
807
808 static const char arg_handle_debug_value_set_doc[] =
809 "<value>\n"
810 "\tSet debug value of <value> on startup\n"
811 ;
812 static int arg_handle_debug_value_set(int argc, const char **argv, void *UNUSED(data))
813 {
814         const char *arg_id = "--debug-value";
815         if (argc > 1) {
816                 const char *err_msg = NULL;
817                 int value;
818                 if (!parse_int(argv[1], NULL, &value, &err_msg)) {
819                         printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
820                         return 1;
821                 }
822
823                 G.debug_value = value;
824
825                 return 1;
826         }
827         else {
828                 printf("\nError: you must specify debug value to set.\n");
829                 return 0;
830         }
831 }
832
833 static const char arg_handle_debug_fpe_set_doc[] =
834 "\n\tEnable floating point exceptions"
835 ;
836 static int arg_handle_debug_fpe_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
837 {
838         main_signal_setup_fpe();
839         return 0;
840 }
841
842 static const char arg_handle_factory_startup_set_doc[] =
843 "\n\tSkip reading the " STRINGIFY(BLENDER_STARTUP_FILE) " in the users home directory"
844 ;
845 static int arg_handle_factory_startup_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
846 {
847         G.factory_startup = 1;
848         return 0;
849 }
850
851 static const char arg_handle_env_system_set_doc_datafiles[] =
852 "\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_DATAFILES)" environment variable";
853 static const char arg_handle_env_system_set_doc_scripts[] =
854 "\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_SCRIPTS)" environment variable";
855 static const char arg_handle_env_system_set_doc_python[] =
856 "\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_PYTHON)" environment variable";
857
858 static int arg_handle_env_system_set(int argc, const char **argv, void *UNUSED(data))
859 {
860         /* "--env-system-scripts" --> "BLENDER_SYSTEM_SCRIPTS" */
861
862         char env[64] = "BLENDER";
863         char *ch_dst = env + 7; /* skip BLENDER */
864         const char *ch_src = argv[0] + 5; /* skip --env */
865
866         if (argc < 2) {
867                 printf("%s requires one argument\n", argv[0]);
868                 exit(1);
869         }
870
871         for (; *ch_src; ch_src++, ch_dst++) {
872                 *ch_dst = (*ch_src == '-') ? '_' : (*ch_src) - 32; /* toupper() */
873         }
874
875         *ch_dst = '\0';
876         BLI_setenv(env, argv[1]);
877         return 1;
878 }
879
880 static const char arg_handle_playback_mode_doc[] =
881 "<options> <file(s)>\n"
882 "\tPlayback <file(s)>, only operates this way when not running in background.\n"
883 "\t\t-p <sx> <sy>\tOpen with lower left corner at <sx>, <sy>\n"
884 "\t\t-m\t\tRead from disk (Do not buffer)\n"
885 "\t\t-f <fps> <fps-base>\t\tSpecify FPS to start with\n"
886 "\t\t-j <frame>\tSet frame step to <frame>\n"
887 "\t\t-s <frame>\tPlay from <frame>\n"
888 "\t\t-e <frame>\tPlay until <frame>"
889 ;
890 static int arg_handle_playback_mode(int argc, const char **argv, void *UNUSED(data))
891 {
892         /* not if -b was given first */
893         if (G.background == 0) {
894 #ifdef WITH_FFMPEG
895                 /* Setup FFmpeg with current debug flags. */
896                 IMB_ffmpeg_init();
897 #endif
898
899                 WM_main_playanim(argc, argv); /* not the same argc and argv as before */
900                 exit(0); /* 2.4x didn't do this */
901         }
902
903         return -2;
904 }
905
906 static const char arg_handle_window_geometry_doc[] =
907 "<sx> <sy> <w> <h>\n"
908 "\tOpen with lower left corner at <sx>, <sy> and width and height as <w>, <h>"
909 ;
910 static int arg_handle_window_geometry(int argc, const char **argv, void *UNUSED(data))
911 {
912         const char *arg_id = "-p / --window-geometry";
913         int params[4], i;
914
915         if (argc < 5) {
916                 fprintf(stderr, "Error: requires four arguments '%s'\n", arg_id);
917                 exit(1);
918         }
919
920         for (i = 0; i < 4; i++) {
921                 const char *err_msg = NULL;
922                 if (!parse_int(argv[i + 1], NULL, &params[i], &err_msg)) {
923                         printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
924                         exit(1);
925                 }
926         }
927
928         WM_init_state_size_set(UNPACK4(params));
929
930         return 4;
931 }
932
933 static const char arg_handle_native_pixels_set_doc[] =
934 "\n\tDo not use native pixel size, for high resolution displays (MacBook 'Retina')"
935 ;
936 static int arg_handle_native_pixels_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
937 {
938         WM_init_native_pixels(false);
939         return 0;
940 }
941
942 static const char arg_handle_with_borders_doc[] =
943 "\n\tForce opening with borders"
944 ;
945 static int arg_handle_with_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
946 {
947         WM_init_state_normal_set();
948         return 0;
949 }
950
951 static const char arg_handle_without_borders_doc[] =
952 "\n\tForce opening without borders"
953 ;
954 static int arg_handle_without_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
955 {
956         WM_init_state_fullscreen_set();
957         return 0;
958 }
959
960 extern bool wm_start_with_console; /* wm_init_exit.c */
961
962 static const char arg_handle_start_with_console_doc[] =
963 "\n\tStart with the console window open (ignored if -b is set), (Windows only)"
964 ;
965 static int arg_handle_start_with_console(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
966 {
967         wm_start_with_console = true;
968         return 0;
969 }
970
971 static const char arg_handle_register_extension_doc[] =
972 "\n\tRegister blend-file extension, then exit (Windows only)"
973 ;
974 static const char arg_handle_register_extension_doc_silent[] =
975 "\n\tSilently register blend-file extension, then exit (Windows only)"
976 ;
977 static int arg_handle_register_extension(int UNUSED(argc), const char **UNUSED(argv), void *data)
978 {
979 #ifdef WIN32
980         if (data)
981                 G.background = 1;
982         RegisterBlendExtension();
983 #else
984         (void)data; /* unused */
985 #endif
986         return 0;
987 }
988
989 static const char arg_handle_joystick_disable_doc[] =
990 "\n\tDisable joystick support"
991 ;
992 static int arg_handle_joystick_disable(int UNUSED(argc), const char **UNUSED(argv), void *data)
993 {
994 #ifndef WITH_GAMEENGINE
995         (void)data;
996 #else
997         SYS_SystemHandle *syshandle = data;
998
999         /**
1000          * don't initialize joysticks if user doesn't want to use joysticks
1001          * failed joystick initialization delays over 5 seconds, before game engine start
1002          */
1003         SYS_WriteCommandLineInt(*syshandle, "nojoystick", 1);
1004         if (G.debug & G_DEBUG) printf("disabling nojoystick\n");
1005 #endif
1006
1007         return 0;
1008 }
1009
1010 static const char arg_handle_audio_disable_doc[] =
1011 "\n\tForce sound system to None"
1012 ;
1013 static int arg_handle_audio_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
1014 {
1015         BKE_sound_force_device("Null");
1016         return 0;
1017 }
1018
1019 static const char arg_handle_audio_set_doc[] =
1020 "\n\tForce sound system to a specific device\n\tThe name is the same as found in the user preferences, e.g. OpenAL."
1021 ;
1022 static int arg_handle_audio_set(int argc, const char **argv, void *UNUSED(data))
1023 {
1024         if (argc < 1) {
1025                 fprintf(stderr, "-setaudio require one argument\n");
1026                 exit(1);
1027         }
1028
1029         BKE_sound_force_device(argv[1]);
1030         return 1;
1031 }
1032
1033 static const char arg_handle_output_set_doc[] =
1034 "<path>\n"
1035 "\tSet the render path and file name.\n"
1036 "\tUse '//' at the start of the path to render relative to the blend-file.\n"
1037 "\n"
1038 "\tThe '#' characters are replaced by the frame number, and used to define zero padding.\n"
1039 "\n"
1040 "\t* 'ani_##_test.png' becomes 'ani_01_test.png'\n"
1041 "\t* 'test-######.png' becomes 'test-000001.png'\n"
1042 "\n"
1043 "\tWhen the filename does not contain '#', The suffix '####' is added to the filename.\n"
1044 "\n"
1045 "\tThe frame number will be added at the end of the filename, eg:\n"
1046 "\t# blender -b foobar.blend -o //render_ -F PNG -x 1 -a\n"
1047 "\t'//render_' becomes '//render_####', writing frames as '//render_0001.png'"
1048 ;
1049 static int arg_handle_output_set(int argc, const char **argv, void *data)
1050 {
1051         bContext *C = data;
1052         if (argc > 1) {
1053                 Scene *scene = CTX_data_scene(C);
1054                 if (scene) {
1055                         BLI_strncpy(scene->r.pic, argv[1], sizeof(scene->r.pic));
1056                 }
1057                 else {
1058                         printf("\nError: no blend loaded. cannot use '-o / --render-output'.\n");
1059                 }
1060                 return 1;
1061         }
1062         else {
1063                 printf("\nError: you must specify a path after '-o  / --render-output'.\n");
1064                 return 0;
1065         }
1066 }
1067
1068 static const char arg_handle_engine_set_doc[] =
1069 "<engine>\n"
1070 "\tSpecify the render engine\n\tuse -E help to list available engines"
1071 ;
1072 static int arg_handle_engine_set(int argc, const char **argv, void *data)
1073 {
1074         bContext *C = data;
1075         if (argc >= 2) {
1076                 if (STREQ(argv[1], "help")) {
1077                         RenderEngineType *type = NULL;
1078                         printf("Blender Engine Listing:\n");
1079                         for (type = R_engines.first; type; type = type->next) {
1080                                 printf("\t%s\n", type->idname);
1081                         }
1082                         exit(0);
1083                 }
1084                 else {
1085                         Scene *scene = CTX_data_scene(C);
1086                         if (scene) {
1087                                 RenderData *rd = &scene->r;
1088
1089                                 if (BLI_findstring(&R_engines, argv[1], offsetof(RenderEngineType, idname))) {
1090                                         BLI_strncpy_utf8(rd->engine, argv[1], sizeof(rd->engine));
1091                                 }
1092                                 else {
1093                                         printf("\nError: engine not found '%s'\n", argv[1]);
1094                                         exit(1);
1095                                 }
1096                         }
1097                         else {
1098                                 printf("\nError: no blend loaded. "
1099                                        "order the arguments so '-E  / --engine ' is after a blend is loaded.\n");
1100                         }
1101                 }
1102
1103                 return 1;
1104         }
1105         else {
1106                 printf("\nEngine not specified, give 'help' for a list of available engines.\n");
1107                 return 0;
1108         }
1109 }
1110
1111 static const char arg_handle_image_type_set_doc[] =
1112 "<format>\n"
1113 "\tSet the render format, Valid options are...\n"
1114 "\t\tTGA RAWTGA JPEG IRIS IRIZ\n"
1115 "\t\tAVIRAW AVIJPEG PNG BMP\n"
1116 "\t(formats that can be compiled into blender, not available on all systems)\n"
1117 "\t\tHDR TIFF EXR MULTILAYER MPEG FRAMESERVER CINEON DPX DDS JP2"
1118 ;
1119 static int arg_handle_image_type_set(int argc, const char **argv, void *data)
1120 {
1121         bContext *C = data;
1122         if (argc > 1) {
1123                 const char *imtype = argv[1];
1124                 Scene *scene = CTX_data_scene(C);
1125                 if (scene) {
1126                         const char imtype_new = BKE_imtype_from_arg(imtype);
1127
1128                         if (imtype_new == R_IMF_IMTYPE_INVALID) {
1129                                 printf("\nError: Format from '-F / --render-format' not known or not compiled in this release.\n");
1130                         }
1131                         else {
1132                                 scene->r.im_format.imtype = imtype_new;
1133                         }
1134                 }
1135                 else {
1136                         printf("\nError: no blend loaded. "
1137                                "order the arguments so '-F  / --render-format' is after the blend is loaded.\n");
1138                 }
1139                 return 1;
1140         }
1141         else {
1142                 printf("\nError: you must specify a format after '-F  / --render-foramt'.\n");
1143                 return 0;
1144         }
1145 }
1146
1147 static const char arg_handle_threads_set_doc[] =
1148 "<threads>\n"
1149 "\tUse amount of <threads> for rendering and other operations\n"
1150 "\t[1-" STRINGIFY(BLENDER_MAX_THREADS) "], 0 for systems processor count."
1151 ;
1152 static int arg_handle_threads_set(int argc, const char **argv, void *UNUSED(data))
1153 {
1154         const char *arg_id = "-t / --threads";
1155         const int min = 0, max = BLENDER_MAX_THREADS;
1156         if (argc > 1) {
1157                 const char *err_msg = NULL;
1158                 int threads;
1159                 if (!parse_int_strict_range(argv[1], NULL, min, max, &threads, &err_msg)) {
1160                         printf("\nError: %s '%s %s', expected number in [%d..%d].\n", err_msg, arg_id, argv[1], min, max);
1161                         return 1;
1162                 }
1163
1164                 BLI_system_num_threads_override_set(threads);
1165                 return 1;
1166         }
1167         else {
1168                 printf("\nError: you must specify a number of threads in [%d..%d] '%s'.\n", min, max, arg_id);
1169                 return 0;
1170         }
1171 }
1172
1173 static const char arg_handle_verbosity_set_doc[] =
1174 "<verbose>\n"
1175 "\tSet logging verbosity level."
1176 ;
1177 static int arg_handle_verbosity_set(int argc, const char **argv, void *UNUSED(data))
1178 {
1179         const char *arg_id = "--verbose";
1180         if (argc > 1) {
1181                 const char *err_msg = NULL;
1182                 int level;
1183                 if (!parse_int(argv[1], NULL, &level, &err_msg)) {
1184                         printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1185                 }
1186
1187 #ifdef WITH_LIBMV
1188                 libmv_setLoggingVerbosity(level);
1189 #elif defined(WITH_CYCLES_LOGGING)
1190                 CCL_logging_verbosity_set(level);
1191 #else
1192                 (void)level;
1193 #endif
1194
1195                 return 1;
1196         }
1197         else {
1198                 printf("\nError: you must specify a verbosity level.\n");
1199                 return 0;
1200         }
1201 }
1202
1203 static const char arg_handle_extension_set_doc[] =
1204 "<bool>\n"
1205 "\tSet option to add the file extension to the end of the file"
1206 ;
1207 static int arg_handle_extension_set(int argc, const char **argv, void *data)
1208 {
1209         bContext *C = data;
1210         if (argc > 1) {
1211                 Scene *scene = CTX_data_scene(C);
1212                 if (scene) {
1213                         if (argv[1][0] == '0') {
1214                                 scene->r.scemode &= ~R_EXTENSION;
1215                         }
1216                         else if (argv[1][0] == '1') {
1217                                 scene->r.scemode |= R_EXTENSION;
1218                         }
1219                         else {
1220                                 printf("\nError: Use '-x 1 / -x 0' To set the extension option or '--use-extension'\n");
1221                         }
1222                 }
1223                 else {
1224                         printf("\nError: no blend loaded. "
1225                                "order the arguments so '-o ' is after '-x '.\n");
1226                 }
1227                 return 1;
1228         }
1229         else {
1230                 printf("\nError: you must specify a path after '- '.\n");
1231                 return 0;
1232         }
1233 }
1234
1235 static const char arg_handle_ge_parameters_set_doc[] =
1236 "Game Engine specific options\n"
1237 "\t-g fixedtime\t\tRun on 50 hertz without dropping frames\n"
1238 "\t-g vertexarrays\t\tUse Vertex Arrays for rendering (usually faster)\n"
1239 "\t-g nomipmap\t\tNo Texture Mipmapping\n"
1240 "\t-g linearmipmap\t\tLinear Texture Mipmapping instead of Nearest (default)"
1241 ;
1242 static int arg_handle_ge_parameters_set(int argc, const char **argv, void *data)
1243 {
1244         int a = 0;
1245 #ifdef WITH_GAMEENGINE
1246         SYS_SystemHandle syshandle = *(SYS_SystemHandle *)data;
1247 #else
1248         (void)data;
1249 #endif
1250
1251         /**
1252          * gameengine parameters are automatically put into system
1253          * -g [paramname = value]
1254          * -g [boolparamname]
1255          * example:
1256          * -g novertexarrays
1257          * -g maxvertexarraysize = 512
1258          */
1259
1260         if (argc >= 1) {
1261                 const char *paramname = argv[a];
1262                 /* check for single value versus assignment */
1263                 if (a + 1 < argc && (*(argv[a + 1]) == '=')) {
1264                         a++;
1265                         if (a + 1 < argc) {
1266                                 a++;
1267                                 /* assignment */
1268 #ifdef WITH_GAMEENGINE
1269                                 SYS_WriteCommandLineString(syshandle, paramname, argv[a]);
1270 #endif
1271                         }
1272                         else {
1273                                 printf("error: argument assignment (%s) without value.\n", paramname);
1274                                 return 0;
1275                         }
1276                         /* name arg eaten */
1277
1278                 }
1279                 else {
1280 #ifdef WITH_GAMEENGINE
1281                         SYS_WriteCommandLineInt(syshandle, argv[a], 1);
1282 #endif
1283                         /* doMipMap */
1284                         if (STREQ(argv[a], "nomipmap")) {
1285                                 GPU_set_mipmap(0); //doMipMap = 0;
1286                         }
1287                         /* linearMipMap */
1288                         if (STREQ(argv[a], "linearmipmap")) {
1289                                 GPU_set_mipmap(1);
1290                                 GPU_set_linear_mipmap(1); //linearMipMap = 1;
1291                         }
1292
1293
1294                 } /* if (*(argv[a + 1]) == '=') */
1295         }
1296
1297         return a;
1298 }
1299
1300 static const char arg_handle_render_frame_doc[] =
1301 "<frame>\n"
1302 "\tRender frame <frame> and save it.\n"
1303 "\n"
1304 "\t* +<frame> start frame relative, -<frame> end frame relative.\n"
1305 "\t* A comma separated list of frames can also be used (no spaces).\n"
1306 "\t* A range of frames can be expressed using '..' seperator between the first and last frames (inclusive).\n"
1307 ;
1308 static int arg_handle_render_frame(int argc, const char **argv, void *data)
1309 {
1310         const char *arg_id = "-f / --render-frame";
1311         bContext *C = data;
1312         Scene *scene = CTX_data_scene(C);
1313         if (scene) {
1314                 Main *bmain = CTX_data_main(C);
1315
1316                 if (argc > 1) {
1317                         const char *err_msg = NULL;
1318                         Render *re;
1319                         ReportList reports;
1320
1321                         int (*frame_range_arr)[2], frames_range_len;
1322                         if ((frame_range_arr = parse_int_range_relative_clamp_n(
1323                                  argv[1], scene->r.sfra, scene->r.efra, MINAFRAME, MAXFRAME,
1324                                  &frames_range_len, &err_msg)) == NULL)
1325                         {
1326                                 printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1327                                 return 1;
1328                         }
1329
1330                         re = RE_NewSceneRender(scene);
1331                         BLI_begin_threaded_malloc();
1332                         BKE_reports_init(&reports, RPT_STORE);
1333
1334                         RE_SetReports(re, &reports);
1335                         for (int i = 0; i < frames_range_len; i++) {
1336                                 /* We could pass in frame ranges,
1337                                  * but prefer having exact behavior as passing in multiple frames */
1338                                 if ((frame_range_arr[i][0] <= frame_range_arr[i][1]) == 0) {
1339                                         printf("\nWarning: negative range ignored '%s %s'.\n", arg_id, argv[1]);
1340                                 }
1341
1342                                 for (int frame = frame_range_arr[i][0]; frame <= frame_range_arr[i][1]; frame++) {
1343                                         RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, frame, frame, scene->r.frame_step);
1344                                 }
1345                         }
1346                         RE_SetReports(re, NULL);
1347                         BKE_reports_clear(&reports);
1348                         BLI_end_threaded_malloc();
1349                         MEM_freeN(frame_range_arr);
1350                         return 1;
1351                 }
1352                 else {
1353                         printf("\nError: frame number must follow '%s'.\n", arg_id);
1354                         return 0;
1355                 }
1356         }
1357         else {
1358                 printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1359                 return 0;
1360         }
1361 }
1362
1363 static const char arg_handle_render_animation_doc[] =
1364 "\n\tRender frames from start to end (inclusive)"
1365 ;
1366 static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(argv), void *data)
1367 {
1368         bContext *C = data;
1369         Scene *scene = CTX_data_scene(C);
1370         if (scene) {
1371                 Main *bmain = CTX_data_main(C);
1372                 Render *re = RE_NewSceneRender(scene);
1373                 ReportList reports;
1374                 BLI_begin_threaded_malloc();
1375                 BKE_reports_init(&reports, RPT_STORE);
1376                 RE_SetReports(re, &reports);
1377                 RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, scene->r.sfra, scene->r.efra, scene->r.frame_step);
1378                 RE_SetReports(re, NULL);
1379                 BKE_reports_clear(&reports);
1380                 BLI_end_threaded_malloc();
1381         }
1382         else {
1383                 printf("\nError: no blend loaded. cannot use '-a'.\n");
1384         }
1385         return 0;
1386 }
1387
1388 static const char arg_handle_scene_set_doc[] =
1389 "<name>\n"
1390 "\tSet the active scene <name> for rendering"
1391 ;
1392 static int arg_handle_scene_set(int argc, const char **argv, void *data)
1393 {
1394         if (argc > 1) {
1395                 bContext *C = data;
1396                 Scene *scene = BKE_scene_set_name(CTX_data_main(C), argv[1]);
1397                 if (scene) {
1398                         CTX_data_scene_set(C, scene);
1399                 }
1400                 return 1;
1401         }
1402         else {
1403                 printf("\nError: Scene name must follow '-S / --scene'.\n");
1404                 return 0;
1405         }
1406 }
1407
1408 static const char arg_handle_frame_start_set_doc[] =
1409 "<frame>\n"
1410 "\tSet start to frame <frame>, supports +/- for relative frames too."
1411 ;
1412 static int arg_handle_frame_start_set(int argc, const char **argv, void *data)
1413 {
1414         const char *arg_id = "-s / --frame-start";
1415         bContext *C = data;
1416         Scene *scene = CTX_data_scene(C);
1417         if (scene) {
1418                 if (argc > 1) {
1419                         const char *err_msg = NULL;
1420                         if (!parse_int_relative_clamp(
1421                                 argv[1], NULL, scene->r.sfra, scene->r.sfra - 1, MINAFRAME, MAXFRAME,
1422                                 &scene->r.sfra, &err_msg))
1423                         {
1424                                 printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1425                         }
1426                         return 1;
1427                 }
1428                 else {
1429                         printf("\nError: frame number must follow '%s'.\n", arg_id);
1430                         return 0;
1431                 }
1432         }
1433         else {
1434                 printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1435                 return 0;
1436         }
1437 }
1438
1439 static const char arg_handle_frame_end_set_doc[] =
1440 "<frame>\n"
1441 "\tSet end to frame <frame>, supports +/- for relative frames too."
1442 ;
1443 static int arg_handle_frame_end_set(int argc, const char **argv, void *data)
1444 {
1445         const char *arg_id = "-e / --frame-end";
1446         bContext *C = data;
1447         Scene *scene = CTX_data_scene(C);
1448         if (scene) {
1449                 if (argc > 1) {
1450                         const char *err_msg = NULL;
1451                         if (!parse_int_relative_clamp(
1452                                 argv[1], NULL, scene->r.efra, scene->r.efra - 1, MINAFRAME, MAXFRAME,
1453                                 &scene->r.efra, &err_msg))
1454                         {
1455                                 printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1456                         }
1457                         return 1;
1458                 }
1459                 else {
1460                         printf("\nError: frame number must follow '%s'.\n", arg_id);
1461                         return 0;
1462                 }
1463         }
1464         else {
1465                 printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1466                 return 0;
1467         }
1468 }
1469
1470 static const char arg_handle_frame_skip_set_doc[] =
1471 "<frames>\n"
1472 "\tSet number of frames to step forward after each rendered frame"
1473 ;
1474 static int arg_handle_frame_skip_set(int argc, const char **argv, void *data)
1475 {
1476         const char *arg_id = "-j / --frame-jump";
1477         bContext *C = data;
1478         Scene *scene = CTX_data_scene(C);
1479         if (scene) {
1480                 if (argc > 1) {
1481                         const char *err_msg = NULL;
1482                         if (!parse_int_clamp(argv[1], NULL, 1, MAXFRAME, &scene->r.frame_step, &err_msg)) {
1483                                 printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1484                         }
1485                         return 1;
1486                 }
1487                 else {
1488                         printf("\nError: number of frames to step must follow '%s'.\n", arg_id);
1489                         return 0;
1490                 }
1491         }
1492         else {
1493                 printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1494                 return 0;
1495         }
1496 }
1497
1498 static const char arg_handle_python_file_run_doc[] =
1499 "<filename>\n"
1500 "\tRun the given Python script file"
1501 ;
1502 static int arg_handle_python_file_run(int argc, const char **argv, void *data)
1503 {
1504 #ifdef WITH_PYTHON
1505         bContext *C = data;
1506
1507         /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1508         if (argc > 1) {
1509                 /* Make the path absolute because its needed for relative linked blends to be found */
1510                 char filename[FILE_MAX];
1511                 BLI_strncpy(filename, argv[1], sizeof(filename));
1512                 BLI_path_cwd(filename, sizeof(filename));
1513
1514                 bool ok;
1515                 BPY_CTX_SETUP(ok = BPY_execute_filepath(C, filename, NULL));
1516                 if (!ok && app_state.exit_code_on_error.python) {
1517                         printf("\nError: script failed, file: '%s', exiting.\n", argv[1]);
1518                         exit(app_state.exit_code_on_error.python);
1519                 }
1520                 return 1;
1521         }
1522         else {
1523                 printf("\nError: you must specify a filepath after '%s'.\n", argv[0]);
1524                 return 0;
1525         }
1526 #else
1527         UNUSED_VARS(argc, argv, data);
1528         printf("This blender was built without python support\n");
1529         return 0;
1530 #endif /* WITH_PYTHON */
1531 }
1532
1533 static const char arg_handle_python_text_run_doc[] =
1534 "<name>\n"
1535 "\tRun the given Python script text block"
1536 ;
1537 static int arg_handle_python_text_run(int argc, const char **argv, void *data)
1538 {
1539 #ifdef WITH_PYTHON
1540         bContext *C = data;
1541
1542         /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1543         if (argc > 1) {
1544                 /* Make the path absolute because its needed for relative linked blends to be found */
1545                 struct Text *text = (struct Text *)BKE_libblock_find_name(ID_TXT, argv[1]);
1546                 bool ok;
1547
1548                 if (text) {
1549                         BPY_CTX_SETUP(ok = BPY_execute_text(C, text, NULL, false));
1550                 }
1551                 else {
1552                         printf("\nError: text block not found %s.\n", argv[1]);
1553                         ok = false;
1554                 }
1555
1556                 if (!ok && app_state.exit_code_on_error.python) {
1557                         printf("\nError: script failed, text: '%s', exiting.\n", argv[1]);
1558                         exit(app_state.exit_code_on_error.python);
1559                 }
1560
1561                 return 1;
1562         }
1563         else {
1564                 printf("\nError: you must specify a text block after '%s'.\n", argv[0]);
1565                 return 0;
1566         }
1567 #else
1568         UNUSED_VARS(argc, argv, data);
1569         printf("This blender was built without python support\n");
1570         return 0;
1571 #endif /* WITH_PYTHON */
1572 }
1573
1574 static const char arg_handle_python_expr_run_doc[] =
1575 "<expression>\n"
1576 "\tRun the given expression as a Python script"
1577 ;
1578 static int arg_handle_python_expr_run(int argc, const char **argv, void *data)
1579 {
1580 #ifdef WITH_PYTHON
1581         bContext *C = data;
1582
1583         /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1584         if (argc > 1) {
1585                 bool ok;
1586                 BPY_CTX_SETUP(ok = BPY_execute_string_ex(C, argv[1], false));
1587                 if (!ok && app_state.exit_code_on_error.python) {
1588                         printf("\nError: script failed, expr: '%s', exiting.\n", argv[1]);
1589                         exit(app_state.exit_code_on_error.python);
1590                 }
1591                 return 1;
1592         }
1593         else {
1594                 printf("\nError: you must specify a Python expression after '%s'.\n", argv[0]);
1595                 return 0;
1596         }
1597 #else
1598         UNUSED_VARS(argc, argv, data);
1599         printf("This blender was built without python support\n");
1600         return 0;
1601 #endif /* WITH_PYTHON */
1602 }
1603
1604 static const char arg_handle_python_console_run_doc[] =
1605 "\n\tRun blender with an interactive console"
1606 ;
1607 static int arg_handle_python_console_run(int UNUSED(argc), const char **argv, void *data)
1608 {
1609 #ifdef WITH_PYTHON
1610         bContext *C = data;
1611
1612         BPY_CTX_SETUP(BPY_execute_string(C, "__import__('code').interact()"));
1613
1614         return 0;
1615 #else
1616         UNUSED_VARS(argv, data);
1617         printf("This blender was built without python support\n");
1618         return 0;
1619 #endif /* WITH_PYTHON */
1620 }
1621
1622 static const char arg_handle_python_exit_code_set_doc[] =
1623 "\n"
1624 "\tSet the exit-code in [0..255] to exit if a Python exception is raised\n"
1625 "\t(only for scripts executed from the command line), zero disables."
1626 ;
1627 static int arg_handle_python_exit_code_set(int argc, const char **argv, void *UNUSED(data))
1628 {
1629         const char *arg_id = "--python-exit-code";
1630         if (argc > 1) {
1631                 const char *err_msg = NULL;
1632                 const int min = 0, max = 255;
1633                 int exit_code;
1634                 if (!parse_int_strict_range(argv[1], NULL, min, max, &exit_code, &err_msg)) {
1635                         printf("\nError: %s '%s %s', expected number in [%d..%d].\n", err_msg, arg_id, argv[1], min, max);
1636                         return 1;
1637                 }
1638
1639                 app_state.exit_code_on_error.python = (unsigned char)exit_code;
1640                 return 1;
1641         }
1642         else {
1643                 printf("\nError: you must specify an exit code number '%s'.\n", arg_id);
1644                 return 0;
1645         }
1646 }
1647
1648 static const char arg_handle_addons_set_doc[] =
1649 "\n\tComma separated list of add-ons (no spaces)"
1650 ;
1651 static int arg_handle_addons_set(int argc, const char **argv, void *data)
1652 {
1653         /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1654         if (argc > 1) {
1655 #ifdef WITH_PYTHON
1656                 const char script_str[] =
1657                         "from addon_utils import check, enable\n"
1658                         "for m in '%s'.split(','):\n"
1659                         "    if check(m)[1] is False:\n"
1660                         "        enable(m, persistent=True)";
1661                 const int slen = strlen(argv[1]) + (sizeof(script_str) - 2);
1662                 char *str = malloc(slen);
1663                 bContext *C = data;
1664                 BLI_snprintf(str, slen, script_str, argv[1]);
1665
1666                 BLI_assert(strlen(str) + 1 == slen);
1667                 BPY_CTX_SETUP(BPY_execute_string_ex(C, str, false));
1668                 free(str);
1669 #else
1670                 UNUSED_VARS(argv, data);
1671 #endif /* WITH_PYTHON */
1672                 return 1;
1673         }
1674         else {
1675                 printf("\nError: you must specify a comma separated list after '--addons'.\n");
1676                 return 0;
1677         }
1678 }
1679
1680 static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data)
1681 {
1682         bContext *C = data;
1683         ReportList reports;
1684         bool success;
1685
1686         /* Make the path absolute because its needed for relative linked blends to be found */
1687         char filename[FILE_MAX];
1688
1689         /* note, we could skip these, but so far we always tried to load these files */
1690         if (argv[0][0] == '-') {
1691                 fprintf(stderr, "unknown argument, loading as file: %s\n", argv[0]);
1692         }
1693
1694         BLI_strncpy(filename, argv[0], sizeof(filename));
1695         BLI_path_cwd(filename, sizeof(filename));
1696
1697         /* load the file */
1698         BKE_reports_init(&reports, RPT_PRINT);
1699         WM_file_autoexec_init(filename);
1700         success = WM_file_read(C, filename, &reports);
1701         BKE_reports_clear(&reports);
1702
1703         if (success) {
1704                 if (G.background) {
1705                         /* ensuer we use 'C->data.scene' for background render */
1706                         CTX_wm_window_set(C, NULL);
1707                 }
1708         }
1709         else {
1710                 /* failed to load file, stop processing arguments if running in background mode */
1711                 if (G.background) {
1712                         /* Set is_break if running in the background mode so
1713                          * blender will return non-zero exit code which then
1714                          * could be used in automated script to control how
1715                          * good or bad things are.
1716                          */
1717                         G.is_break = true;
1718                         return -1;
1719                 }
1720
1721                 /* Just pretend a file was loaded, so the user can press Save and it'll save at the filename from the CLI. */
1722                 BLI_strncpy(G.main->name, filename, FILE_MAX);
1723                 G.relbase_valid = true;
1724                 G.save_over = true;
1725                 printf("... opened default scene instead; saving will write to %s\n", filename);
1726         }
1727
1728         G.file_loaded = 1;
1729
1730         return 0;
1731 }
1732
1733
1734 void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
1735 {
1736
1737 #define CB(a) a##_doc, a
1738 #define CB_EX(a, b) a##_doc_##b, a
1739
1740         //BLI_argsAdd(ba, pass, short_arg, long_arg, doc, cb, C);
1741
1742         /* end argument processing after -- */
1743         BLI_argsAdd(ba, -1, "--", NULL, CB(arg_handle_arguments_end), NULL);
1744
1745         /* first pass: background mode, disable python and commands that exit after usage */
1746         BLI_argsAdd(ba, 1, "-h", "--help", CB(arg_handle_print_help), ba);
1747         /* Windows only */
1748         BLI_argsAdd(ba, 1, "/?", NULL, CB_EX(arg_handle_print_help, win32), ba);
1749
1750         BLI_argsAdd(ba, 1, "-v", "--version", CB(arg_handle_print_version), NULL);
1751
1752         BLI_argsAdd(ba, 1, "-y", "--enable-autoexec", CB_EX(arg_handle_python_set, enable), (void *)true);
1753         BLI_argsAdd(ba, 1, "-Y", "--disable-autoexec", CB_EX(arg_handle_python_set, disable), (void *)false);
1754
1755         BLI_argsAdd(ba, 1, NULL, "--disable-crash-handler", CB(arg_handle_crash_handler_disable), NULL);
1756         BLI_argsAdd(ba, 1, NULL, "--disable-abort-handler", CB(arg_handle_abort_handler_disable), NULL);
1757
1758         BLI_argsAdd(ba, 1, "-b", "--background", CB(arg_handle_background_mode_set), NULL);
1759
1760         BLI_argsAdd(ba, 1, "-a", NULL, CB(arg_handle_playback_mode), NULL);
1761
1762         BLI_argsAdd(ba, 1, "-d", "--debug", CB(arg_handle_debug_mode_set), ba);
1763
1764 #ifdef WITH_FFMPEG
1765         BLI_argsAdd(ba, 1, NULL, "--debug-ffmpeg",
1766                     CB_EX(arg_handle_debug_mode_generic_set, ffmpeg), (void *)G_DEBUG_FFMPEG);
1767 #endif
1768
1769 #ifdef WITH_FREESTYLE
1770         BLI_argsAdd(ba, 1, NULL, "--debug-freestyle",
1771                     CB_EX(arg_handle_debug_mode_generic_set, freestyle), (void *)G_DEBUG_FREESTYLE);
1772 #endif
1773
1774         BLI_argsAdd(ba, 1, NULL, "--debug-python",
1775                     CB_EX(arg_handle_debug_mode_generic_set, python), (void *)G_DEBUG_PYTHON);
1776         BLI_argsAdd(ba, 1, NULL, "--debug-events",
1777                     CB_EX(arg_handle_debug_mode_generic_set, events), (void *)G_DEBUG_EVENTS);
1778         BLI_argsAdd(ba, 1, NULL, "--debug-handlers",
1779                     CB_EX(arg_handle_debug_mode_generic_set, handlers), (void *)G_DEBUG_HANDLERS);
1780         BLI_argsAdd(ba, 1, NULL, "--debug-wm",
1781                     CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM);
1782         BLI_argsAdd(ba, 1, NULL, "--debug-all", CB(arg_handle_debug_mode_all), NULL);
1783
1784         BLI_argsAdd(ba, 1, NULL, "--debug-io", CB(arg_handle_debug_mode_io), NULL);
1785
1786         BLI_argsAdd(ba, 1, NULL, "--debug-fpe",
1787                     CB(arg_handle_debug_fpe_set), NULL);
1788
1789 #ifdef WITH_LIBMV
1790         BLI_argsAdd(ba, 1, NULL, "--debug-libmv", CB(arg_handle_debug_mode_libmv), NULL);
1791 #endif
1792 #ifdef WITH_CYCLES_LOGGING
1793         BLI_argsAdd(ba, 1, NULL, "--debug-cycles", CB(arg_handle_debug_mode_cycles), NULL);
1794 #endif
1795         BLI_argsAdd(ba, 1, NULL, "--debug-memory", CB(arg_handle_debug_mode_memory_set), NULL);
1796
1797         BLI_argsAdd(ba, 1, NULL, "--debug-value",
1798                     CB(arg_handle_debug_value_set), NULL);
1799         BLI_argsAdd(ba, 1, NULL, "--debug-jobs",
1800                     CB_EX(arg_handle_debug_mode_generic_set, jobs), (void *)G_DEBUG_JOBS);
1801         BLI_argsAdd(ba, 1, NULL, "--debug-gpu",
1802                     CB_EX(arg_handle_debug_mode_generic_set, gpu), (void *)G_DEBUG_GPU);
1803         BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph",
1804                     CB_EX(arg_handle_debug_mode_generic_set, depsgraph), (void *)G_DEBUG_DEPSGRAPH);
1805         BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-no-threads",
1806                     CB_EX(arg_handle_debug_mode_generic_set, depsgraph_no_threads), (void *)G_DEBUG_DEPSGRAPH_NO_THREADS);
1807         BLI_argsAdd(ba, 1, NULL, "--debug-gpumem",
1808                     CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM);
1809         BLI_argsAdd(ba, 1, NULL, "--debug-gpu-shaders",
1810                     CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_SHADERS);
1811
1812         BLI_argsAdd(ba, 1, NULL, "--verbose", CB(arg_handle_verbosity_set), NULL);
1813
1814         BLI_argsAdd(ba, 1, NULL, "--factory-startup", CB(arg_handle_factory_startup_set), NULL);
1815
1816         /* TODO, add user env vars? */
1817         BLI_argsAdd(ba, 1, NULL, "--env-system-datafiles", CB_EX(arg_handle_env_system_set, datafiles), NULL);
1818         BLI_argsAdd(ba, 1, NULL, "--env-system-scripts", CB_EX(arg_handle_env_system_set, scripts), NULL);
1819         BLI_argsAdd(ba, 1, NULL, "--env-system-python", CB_EX(arg_handle_env_system_set, python), NULL);
1820
1821         /* second pass: custom window stuff */
1822         BLI_argsAdd(ba, 2, "-p", "--window-geometry", CB(arg_handle_window_geometry), NULL);
1823         BLI_argsAdd(ba, 2, "-w", "--window-border", CB(arg_handle_with_borders), NULL);
1824         BLI_argsAdd(ba, 2, "-W", "--window-borderless", CB(arg_handle_without_borders), NULL);
1825         BLI_argsAdd(ba, 2, "-con", "--start-console", CB(arg_handle_start_with_console), NULL);
1826         BLI_argsAdd(ba, 2, "-R", NULL, CB(arg_handle_register_extension), NULL);
1827         BLI_argsAdd(ba, 2, "-r", NULL, CB_EX(arg_handle_register_extension, silent), ba);
1828         BLI_argsAdd(ba, 2, NULL, "--no-native-pixels", CB(arg_handle_native_pixels_set), ba);
1829
1830         /* third pass: disabling things and forcing settings */
1831         BLI_argsAddCase(ba, 3, "-nojoystick", 1, NULL, 0, CB(arg_handle_joystick_disable), syshandle);
1832         BLI_argsAddCase(ba, 3, "-noaudio", 1, NULL, 0, CB(arg_handle_audio_disable), NULL);
1833         BLI_argsAddCase(ba, 3, "-setaudio", 1, NULL, 0, CB(arg_handle_audio_set), NULL);
1834
1835         /* fourth pass: processing arguments */
1836         BLI_argsAdd(ba, 4, "-g", NULL, CB(arg_handle_ge_parameters_set), syshandle);
1837         BLI_argsAdd(ba, 4, "-f", "--render-frame", CB(arg_handle_render_frame), C);
1838         BLI_argsAdd(ba, 4, "-a", "--render-anim", CB(arg_handle_render_animation), C);
1839         BLI_argsAdd(ba, 4, "-S", "--scene", CB(arg_handle_scene_set), C);
1840         BLI_argsAdd(ba, 4, "-s", "--frame-start", CB(arg_handle_frame_start_set), C);
1841         BLI_argsAdd(ba, 4, "-e", "--frame-end", CB(arg_handle_frame_end_set), C);
1842         BLI_argsAdd(ba, 4, "-j", "--frame-jump", CB(arg_handle_frame_skip_set), C);
1843         BLI_argsAdd(ba, 4, "-P", "--python", CB(arg_handle_python_file_run), C);
1844         BLI_argsAdd(ba, 4, NULL, "--python-text", CB(arg_handle_python_text_run), C);
1845         BLI_argsAdd(ba, 4, NULL, "--python-expr", CB(arg_handle_python_expr_run), C);
1846         BLI_argsAdd(ba, 4, NULL, "--python-console", CB(arg_handle_python_console_run), C);
1847         BLI_argsAdd(ba, 4, NULL, "--python-exit-code", CB(arg_handle_python_exit_code_set), NULL);
1848         BLI_argsAdd(ba, 4, NULL, "--addons", CB(arg_handle_addons_set), C);
1849
1850         BLI_argsAdd(ba, 4, "-o", "--render-output", CB(arg_handle_output_set), C);
1851         BLI_argsAdd(ba, 4, "-E", "--engine", CB(arg_handle_engine_set), C);
1852
1853         BLI_argsAdd(ba, 4, "-F", "--render-format", CB(arg_handle_image_type_set), C);
1854         BLI_argsAdd(ba, 1, "-t", "--threads", CB(arg_handle_threads_set), NULL);
1855         BLI_argsAdd(ba, 4, "-x", "--use-extension", CB(arg_handle_extension_set), C);
1856
1857 #undef CB
1858 #undef CB_EX
1859
1860 }
1861
1862 /**
1863  * Needs to be added separately.
1864  */
1865 void main_args_setup_post(bContext *C, bArgs *ba)
1866 {
1867         BLI_argsParse(ba, 4, arg_handle_load_file, C);
1868 }
1869
1870 /** \} */
1871
1872 #endif /* WITH_PYTHON_MODULE */