D2830 - 2.8: Fix crash when creating new action
[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-wm");
552         BLI_argsPrintArgDoc(ba, "--debug-all");
553         BLI_argsPrintArgDoc(ba, "--debug-io");
554
555         printf("\n");
556         BLI_argsPrintArgDoc(ba, "--debug-fpe");
557         BLI_argsPrintArgDoc(ba, "--disable-crash-handler");
558
559         printf("\n");
560         printf("Misc Options:\n");
561         BLI_argsPrintArgDoc(ba, "--factory-startup");
562         printf("\n");
563         BLI_argsPrintArgDoc(ba, "--env-system-datafiles");
564         BLI_argsPrintArgDoc(ba, "--env-system-scripts");
565         BLI_argsPrintArgDoc(ba, "--env-system-python");
566         printf("\n");
567         BLI_argsPrintArgDoc(ba, "-nojoystick");
568         BLI_argsPrintArgDoc(ba, "-noaudio");
569         BLI_argsPrintArgDoc(ba, "-setaudio");
570
571         printf("\n");
572
573         BLI_argsPrintArgDoc(ba, "--help");
574
575 #ifdef WIN32
576         BLI_argsPrintArgDoc(ba, "-R");
577         BLI_argsPrintArgDoc(ba, "-r");
578 #endif
579         BLI_argsPrintArgDoc(ba, "--version");
580
581         BLI_argsPrintArgDoc(ba, "--");
582
583         printf("\n");
584         printf("Experimental Features:\n");
585
586         /* Other options _must_ be last (anything not handled will show here) */
587         printf("\n");
588         printf("Other Options:\n");
589         BLI_argsPrintOtherDoc(ba);
590
591         printf("\n");
592         printf("Argument Parsing:\n");
593         printf("\tArguments must be separated by white space, eg:\n");
594         printf("\t# blender -ba test.blend\n");
595         printf("\t...will ignore the 'a'\n");
596         printf("\t# blender -b test.blend -f8\n");
597         printf("\t...will ignore '8' because there is no space between the '-f' and the frame value\n\n");
598
599         printf("Argument Order:\n");
600         printf("\tArguments are executed in the order they are given. eg:\n");
601         printf("\t# blender --background test.blend --render-frame 1 --render-output '/tmp'\n");
602         printf("\t...will not render to '/tmp' because '--render-frame 1' renders before the output path is set\n");
603         printf("\t# blender --background --render-output /tmp test.blend --render-frame 1\n");
604         printf("\t...will not render to '/tmp' because loading the blend-file overwrites the render output that was set\n");
605         printf("\t# blender --background test.blend --render-output /tmp --render-frame 1\n");
606         printf("\t...works as expected.\n\n");
607
608         printf("Environment Variables:\n");
609         printf("  $BLENDER_USER_CONFIG      Directory for user configuration files.\n");
610         printf("  $BLENDER_USER_SCRIPTS     Directory for user scripts.\n");
611         printf("  $BLENDER_SYSTEM_SCRIPTS   Directory for system wide scripts.\n");
612         printf("  $BLENDER_USER_DATAFILES   Directory for user data files (icons, translations, ..).\n");
613         printf("  $BLENDER_SYSTEM_DATAFILES Directory for system wide data files.\n");
614         printf("  $BLENDER_SYSTEM_PYTHON    Directory for system python libraries.\n");
615 #ifdef WIN32
616         printf("  $TEMP                     Store temporary files here.\n");
617 #else
618         printf("  $TMP or $TMPDIR           Store temporary files here.\n");
619 #endif
620 #ifdef WITH_SDL
621         printf("  $SDL_AUDIODRIVER          LibSDL audio driver - alsa, esd, dma.\n");
622 #endif
623         printf("  $PYTHONHOME               Path to the python directory, eg. /usr/lib/python.\n\n");
624
625         exit(0);
626
627         return 0;
628 }
629
630 static const char arg_handle_arguments_end_doc[] =
631 "\n\tEnds option processing, following arguments passed unchanged. Access via Python's 'sys.argv'"
632 ;
633 static int arg_handle_arguments_end(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
634 {
635         return -1;
636 }
637
638 /* only to give help message */
639 #ifndef WITH_PYTHON_SECURITY /* default */
640 #  define   PY_ENABLE_AUTO ", (default)"
641 #  define   PY_DISABLE_AUTO ""
642 #else
643 #  define   PY_ENABLE_AUTO ""
644 #  define   PY_DISABLE_AUTO ", (compiled as non-standard default)"
645 #endif
646
647 static const char arg_handle_python_set_doc_enable[] =
648 "\n\tEnable automatic Python script execution" PY_ENABLE_AUTO
649 ;
650 static const char arg_handle_python_set_doc_disable[] =
651 "\n\tDisable automatic Python script execution (pydrivers & startup scripts)" PY_DISABLE_AUTO
652 ;
653 #undef PY_ENABLE_AUTO
654 #undef PY_DISABLE_AUTO
655
656 static int arg_handle_python_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
657 {
658         if ((bool)data) {
659                 G.f |= G_SCRIPT_AUTOEXEC;
660         }
661         else {
662                 G.f &= ~G_SCRIPT_AUTOEXEC;
663         }
664         G.f |= G_SCRIPT_OVERRIDE_PREF;
665         return 0;
666 }
667
668 static const char arg_handle_crash_handler_disable_doc[] =
669 "\n\tDisable the crash handler"
670 ;
671 static int arg_handle_crash_handler_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
672 {
673         app_state.signal.use_crash_handler = false;
674         return 0;
675 }
676
677 static const char arg_handle_abort_handler_disable_doc[] =
678 "\n\tDisable the abort handler"
679 ;
680 static int arg_handle_abort_handler_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
681 {
682         app_state.signal.use_abort_handler = false;
683         return 0;
684 }
685
686 static const char arg_handle_background_mode_set_doc[] =
687 "\n\tRun in background (often used for UI-less rendering)"
688 ;
689 static int arg_handle_background_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
690 {
691         G.background = 1;
692         return 0;
693 }
694
695 static const char arg_handle_debug_mode_set_doc[] =
696 "\n"
697 "\tTurn debugging on\n"
698 "\n"
699 "\t* Enables memory error detection\n"
700 "\t* Disables mouse grab (to interact with a debugger in some cases)\n"
701 "\t* Keeps Python's 'sys.stdin' rather than setting it to None"
702 ;
703 static int arg_handle_debug_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
704 {
705         G.debug |= G_DEBUG;  /* std output printf's */
706         printf(BLEND_VERSION_STRING_FMT);
707         MEM_set_memory_debug();
708 #ifndef NDEBUG
709         BLI_mempool_set_memory_debug();
710 #endif
711
712 #ifdef WITH_BUILDINFO
713         printf("Build: %s %s %s %s\n", build_date, build_time, build_platform, build_type);
714 #endif
715
716         BLI_argsPrint(data);
717         return 0;
718 }
719
720 #ifdef WITH_FFMPEG
721 static const char arg_handle_debug_mode_generic_set_doc_ffmpeg[] =
722 "\n\tEnable debug messages from FFmpeg library";
723 #endif
724 #ifdef WITH_FREESTYLE
725 static const char arg_handle_debug_mode_generic_set_doc_freestyle[] =
726 "\n\tEnable debug messages for FreeStyle";
727 #endif
728 static const char arg_handle_debug_mode_generic_set_doc_python[] =
729 "\n\tEnable debug messages for Python";
730 static const char arg_handle_debug_mode_generic_set_doc_events[] =
731 "\n\tEnable debug messages for the event system";
732 static const char arg_handle_debug_mode_generic_set_doc_handlers[] =
733 "\n\tEnable debug messages for event handling";
734 static const char arg_handle_debug_mode_generic_set_doc_wm[] =
735 "\n\tEnable debug messages for the window manager, also prints every operator call";
736 static const char arg_handle_debug_mode_generic_set_doc_jobs[] =
737 "\n\tEnable time profiling for background jobs.";
738 static const char arg_handle_debug_mode_generic_set_doc_gpu[] =
739 "\n\tEnable gpu debug context and information for OpenGL 4.3+.";
740 static const char arg_handle_debug_mode_generic_set_doc_depsgraph[] =
741 "\n\tEnable debug messages from dependency graph";
742 static const char arg_handle_debug_mode_generic_set_doc_depsgraph_no_threads[] =
743 "\n\tSwitch dependency graph to a single threaded evaluation";
744 static const char arg_handle_debug_mode_generic_set_doc_gpumem[] =
745 "\n\tEnable GPU memory stats in status bar";
746
747 static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
748 {
749         G.debug |= GET_INT_FROM_POINTER(data);
750         return 0;
751 }
752
753 static const char arg_handle_debug_mode_io_doc[] =
754 "\n\tEnable debug messages for I/O (collada, ...)";
755 static int arg_handle_debug_mode_io(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
756 {
757         G.debug |= G_DEBUG_IO;
758         return 0;
759 }
760
761 static const char arg_handle_debug_mode_all_doc[] =
762 "\n\tEnable all debug messages";
763 static int arg_handle_debug_mode_all(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
764 {
765         G.debug |= G_DEBUG_ALL;
766 #ifdef WITH_LIBMV
767         libmv_startDebugLogging();
768 #endif
769 #ifdef WITH_CYCLES_LOGGING
770         CCL_start_debug_logging();
771 #endif
772         return 0;
773 }
774
775 #ifdef WITH_LIBMV
776 static const char arg_handle_debug_mode_libmv_doc[] =
777 "\n\tEnable debug messages from libmv library"
778 ;
779 static int arg_handle_debug_mode_libmv(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
780 {
781         libmv_startDebugLogging();
782
783         return 0;
784 }
785 #endif
786
787 #ifdef WITH_CYCLES_LOGGING
788 static const char arg_handle_debug_mode_cycles_doc[] =
789 "\n\tEnable debug messages from Cycles"
790 ;
791 static int arg_handle_debug_mode_cycles(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
792 {
793         CCL_start_debug_logging();
794         return 0;
795 }
796 #endif
797
798 static const char arg_handle_debug_mode_memory_set_doc[] =
799 "\n\tEnable fully guarded memory allocation and debugging"
800 ;
801 static int arg_handle_debug_mode_memory_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
802 {
803         MEM_set_memory_debug();
804         return 0;
805 }
806
807 static const char arg_handle_debug_value_set_doc[] =
808 "<value>\n"
809 "\tSet debug value of <value> on startup\n"
810 ;
811 static int arg_handle_debug_value_set(int argc, const char **argv, void *UNUSED(data))
812 {
813         const char *arg_id = "--debug-value";
814         if (argc > 1) {
815                 const char *err_msg = NULL;
816                 int value;
817                 if (!parse_int(argv[1], NULL, &value, &err_msg)) {
818                         printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
819                         return 1;
820                 }
821
822                 G.debug_value = value;
823
824                 return 1;
825         }
826         else {
827                 printf("\nError: you must specify debug value to set.\n");
828                 return 0;
829         }
830 }
831
832 static const char arg_handle_debug_fpe_set_doc[] =
833 "\n\tEnable floating point exceptions"
834 ;
835 static int arg_handle_debug_fpe_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
836 {
837         main_signal_setup_fpe();
838         return 0;
839 }
840
841 static const char arg_handle_factory_startup_set_doc[] =
842 "\n\tSkip reading the " STRINGIFY(BLENDER_STARTUP_FILE) " in the users home directory"
843 ;
844 static int arg_handle_factory_startup_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
845 {
846         G.factory_startup = 1;
847         return 0;
848 }
849
850 static const char arg_handle_env_system_set_doc_datafiles[] =
851 "\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_DATAFILES)" environment variable";
852 static const char arg_handle_env_system_set_doc_scripts[] =
853 "\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_SCRIPTS)" environment variable";
854 static const char arg_handle_env_system_set_doc_python[] =
855 "\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_PYTHON)" environment variable";
856
857 static int arg_handle_env_system_set(int argc, const char **argv, void *UNUSED(data))
858 {
859         /* "--env-system-scripts" --> "BLENDER_SYSTEM_SCRIPTS" */
860
861         char env[64] = "BLENDER";
862         char *ch_dst = env + 7; /* skip BLENDER */
863         const char *ch_src = argv[0] + 5; /* skip --env */
864
865         if (argc < 2) {
866                 printf("%s requires one argument\n", argv[0]);
867                 exit(1);
868         }
869
870         for (; *ch_src; ch_src++, ch_dst++) {
871                 *ch_dst = (*ch_src == '-') ? '_' : (*ch_src) - 32; /* toupper() */
872         }
873
874         *ch_dst = '\0';
875         BLI_setenv(env, argv[1]);
876         return 1;
877 }
878
879 static const char arg_handle_playback_mode_doc[] =
880 "<options> <file(s)>\n"
881 "\tPlayback <file(s)>, only operates this way when not running in background.\n"
882 "\t\t-p <sx> <sy>\tOpen with lower left corner at <sx>, <sy>\n"
883 "\t\t-m\t\tRead from disk (Do not buffer)\n"
884 "\t\t-f <fps> <fps-base>\t\tSpecify FPS to start with\n"
885 "\t\t-j <frame>\tSet frame step to <frame>\n"
886 "\t\t-s <frame>\tPlay from <frame>\n"
887 "\t\t-e <frame>\tPlay until <frame>"
888 ;
889 static int arg_handle_playback_mode(int argc, const char **argv, void *UNUSED(data))
890 {
891         /* not if -b was given first */
892         if (G.background == 0) {
893 #ifdef WITH_FFMPEG
894                 /* Setup FFmpeg with current debug flags. */
895                 IMB_ffmpeg_init();
896 #endif
897
898                 WM_main_playanim(argc, argv); /* not the same argc and argv as before */
899                 exit(0); /* 2.4x didn't do this */
900         }
901
902         return -2;
903 }
904
905 static const char arg_handle_window_geometry_doc[] =
906 "<sx> <sy> <w> <h>\n"
907 "\tOpen with lower left corner at <sx>, <sy> and width and height as <w>, <h>"
908 ;
909 static int arg_handle_window_geometry(int argc, const char **argv, void *UNUSED(data))
910 {
911         const char *arg_id = "-p / --window-geometry";
912         int params[4], i;
913
914         if (argc < 5) {
915                 fprintf(stderr, "Error: requires four arguments '%s'\n", arg_id);
916                 exit(1);
917         }
918
919         for (i = 0; i < 4; i++) {
920                 const char *err_msg = NULL;
921                 if (!parse_int(argv[i + 1], NULL, &params[i], &err_msg)) {
922                         printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
923                         exit(1);
924                 }
925         }
926
927         WM_init_state_size_set(UNPACK4(params));
928
929         return 4;
930 }
931
932 static const char arg_handle_native_pixels_set_doc[] =
933 "\n\tDo not use native pixel size, for high resolution displays (MacBook 'Retina')"
934 ;
935 static int arg_handle_native_pixels_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
936 {
937         WM_init_native_pixels(false);
938         return 0;
939 }
940
941 static const char arg_handle_with_borders_doc[] =
942 "\n\tForce opening with borders"
943 ;
944 static int arg_handle_with_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
945 {
946         WM_init_state_normal_set();
947         return 0;
948 }
949
950 static const char arg_handle_without_borders_doc[] =
951 "\n\tForce opening without borders"
952 ;
953 static int arg_handle_without_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
954 {
955         WM_init_state_fullscreen_set();
956         return 0;
957 }
958
959 extern bool wm_start_with_console; /* wm_init_exit.c */
960
961 static const char arg_handle_start_with_console_doc[] =
962 "\n\tStart with the console window open (ignored if -b is set), (Windows only)"
963 ;
964 static int arg_handle_start_with_console(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
965 {
966         wm_start_with_console = true;
967         return 0;
968 }
969
970 static const char arg_handle_register_extension_doc[] =
971 "\n\tRegister blend-file extension, then exit (Windows only)"
972 ;
973 static const char arg_handle_register_extension_doc_silent[] =
974 "\n\tSilently register blend-file extension, then exit (Windows only)"
975 ;
976 static int arg_handle_register_extension(int UNUSED(argc), const char **UNUSED(argv), void *data)
977 {
978 #ifdef WIN32
979         if (data)
980                 G.background = 1;
981         RegisterBlendExtension();
982 #else
983         (void)data; /* unused */
984 #endif
985         return 0;
986 }
987
988 static const char arg_handle_joystick_disable_doc[] =
989 "\n\tDisable joystick support"
990 ;
991 static int arg_handle_joystick_disable(int UNUSED(argc), const char **UNUSED(argv), void *data)
992 {
993 #ifndef WITH_GAMEENGINE
994         (void)data;
995 #else
996         SYS_SystemHandle *syshandle = data;
997
998         /**
999          * don't initialize joysticks if user doesn't want to use joysticks
1000          * failed joystick initialization delays over 5 seconds, before game engine start
1001          */
1002         SYS_WriteCommandLineInt(*syshandle, "nojoystick", 1);
1003         if (G.debug & G_DEBUG) printf("disabling nojoystick\n");
1004 #endif
1005
1006         return 0;
1007 }
1008
1009 static const char arg_handle_audio_disable_doc[] =
1010 "\n\tForce sound system to None"
1011 ;
1012 static int arg_handle_audio_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
1013 {
1014         BKE_sound_force_device("Null");
1015         return 0;
1016 }
1017
1018 static const char arg_handle_audio_set_doc[] =
1019 "\n\tForce sound system to a specific device\n\tThe name is the same as found in the user preferences, e.g. OpenAL."
1020 ;
1021 static int arg_handle_audio_set(int argc, const char **argv, void *UNUSED(data))
1022 {
1023         if (argc < 1) {
1024                 fprintf(stderr, "-setaudio require one argument\n");
1025                 exit(1);
1026         }
1027
1028         BKE_sound_force_device(argv[1]);
1029         return 1;
1030 }
1031
1032 static const char arg_handle_output_set_doc[] =
1033 "<path>\n"
1034 "\tSet the render path and file name.\n"
1035 "\tUse '//' at the start of the path to render relative to the blend-file.\n"
1036 "\n"
1037 "\tThe '#' characters are replaced by the frame number, and used to define zero padding.\n"
1038 "\n"
1039 "\t* 'ani_##_test.png' becomes 'ani_01_test.png'\n"
1040 "\t* 'test-######.png' becomes 'test-000001.png'\n"
1041 "\n"
1042 "\tWhen the filename does not contain '#', The suffix '####' is added to the filename.\n"
1043 "\n"
1044 "\tThe frame number will be added at the end of the filename, eg:\n"
1045 "\t# blender -b foobar.blend -o //render_ -F PNG -x 1 -a\n"
1046 "\t'//render_' becomes '//render_####', writing frames as '//render_0001.png'"
1047 ;
1048 static int arg_handle_output_set(int argc, const char **argv, void *data)
1049 {
1050         bContext *C = data;
1051         if (argc > 1) {
1052                 Scene *scene = CTX_data_scene(C);
1053                 if (scene) {
1054                         BLI_strncpy(scene->r.pic, argv[1], sizeof(scene->r.pic));
1055                 }
1056                 else {
1057                         printf("\nError: no blend loaded. cannot use '-o / --render-output'.\n");
1058                 }
1059                 return 1;
1060         }
1061         else {
1062                 printf("\nError: you must specify a path after '-o  / --render-output'.\n");
1063                 return 0;
1064         }
1065 }
1066
1067 static const char arg_handle_engine_set_doc[] =
1068 "<engine>\n"
1069 "\tSpecify the render engine\n\tuse -E help to list available engines"
1070 ;
1071 static int arg_handle_engine_set(int argc, const char **argv, void *data)
1072 {
1073         bContext *C = data;
1074         if (argc >= 2) {
1075                 if (STREQ(argv[1], "help")) {
1076                         RenderEngineType *type = NULL;
1077                         printf("Blender Engine Listing:\n");
1078                         for (type = R_engines.first; type; type = type->next) {
1079                                 printf("\t%s\n", type->idname);
1080                         }
1081                         exit(0);
1082                 }
1083                 else {
1084                         Scene *scene = CTX_data_scene(C);
1085                         if (scene) {
1086                                 RenderData *rd = &scene->r;
1087
1088                                 if (BLI_findstring(&R_engines, argv[1], offsetof(RenderEngineType, idname))) {
1089                                         BLI_strncpy_utf8(rd->engine, argv[1], sizeof(rd->engine));
1090                                 }
1091                                 else {
1092                                         printf("\nError: engine not found '%s'\n", argv[1]);
1093                                         exit(1);
1094                                 }
1095                         }
1096                         else {
1097                                 printf("\nError: no blend loaded. "
1098                                        "order the arguments so '-E  / --engine ' is after a blend is loaded.\n");
1099                         }
1100                 }
1101
1102                 return 1;
1103         }
1104         else {
1105                 printf("\nEngine not specified, give 'help' for a list of available engines.\n");
1106                 return 0;
1107         }
1108 }
1109
1110 static const char arg_handle_image_type_set_doc[] =
1111 "<format>\n"
1112 "\tSet the render format, Valid options are...\n"
1113 "\t\tTGA RAWTGA JPEG IRIS IRIZ\n"
1114 "\t\tAVIRAW AVIJPEG PNG BMP\n"
1115 "\t(formats that can be compiled into blender, not available on all systems)\n"
1116 "\t\tHDR TIFF EXR MULTILAYER MPEG FRAMESERVER CINEON DPX DDS JP2"
1117 ;
1118 static int arg_handle_image_type_set(int argc, const char **argv, void *data)
1119 {
1120         bContext *C = data;
1121         if (argc > 1) {
1122                 const char *imtype = argv[1];
1123                 Scene *scene = CTX_data_scene(C);
1124                 if (scene) {
1125                         const char imtype_new = BKE_imtype_from_arg(imtype);
1126
1127                         if (imtype_new == R_IMF_IMTYPE_INVALID) {
1128                                 printf("\nError: Format from '-F / --render-format' not known or not compiled in this release.\n");
1129                         }
1130                         else {
1131                                 scene->r.im_format.imtype = imtype_new;
1132                         }
1133                 }
1134                 else {
1135                         printf("\nError: no blend loaded. "
1136                                "order the arguments so '-F  / --render-format' is after the blend is loaded.\n");
1137                 }
1138                 return 1;
1139         }
1140         else {
1141                 printf("\nError: you must specify a format after '-F  / --render-foramt'.\n");
1142                 return 0;
1143         }
1144 }
1145
1146 static const char arg_handle_threads_set_doc[] =
1147 "<threads>\n"
1148 "\tUse amount of <threads> for rendering and other operations\n"
1149 "\t[1-" STRINGIFY(BLENDER_MAX_THREADS) "], 0 for systems processor count."
1150 ;
1151 static int arg_handle_threads_set(int argc, const char **argv, void *UNUSED(data))
1152 {
1153         const char *arg_id = "-t / --threads";
1154         const int min = 0, max = BLENDER_MAX_THREADS;
1155         if (argc > 1) {
1156                 const char *err_msg = NULL;
1157                 int threads;
1158                 if (!parse_int_strict_range(argv[1], NULL, min, max, &threads, &err_msg)) {
1159                         printf("\nError: %s '%s %s', expected number in [%d..%d].\n", err_msg, arg_id, argv[1], min, max);
1160                         return 1;
1161                 }
1162
1163                 BLI_system_num_threads_override_set(threads);
1164                 return 1;
1165         }
1166         else {
1167                 printf("\nError: you must specify a number of threads in [%d..%d] '%s'.\n", min, max, arg_id);
1168                 return 0;
1169         }
1170 }
1171
1172 static const char arg_handle_verbosity_set_doc[] =
1173 "<verbose>\n"
1174 "\tSet logging verbosity level."
1175 ;
1176 static int arg_handle_verbosity_set(int argc, const char **argv, void *UNUSED(data))
1177 {
1178         const char *arg_id = "--verbose";
1179         if (argc > 1) {
1180                 const char *err_msg = NULL;
1181                 int level;
1182                 if (!parse_int(argv[1], NULL, &level, &err_msg)) {
1183                         printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1184                 }
1185
1186 #ifdef WITH_LIBMV
1187                 libmv_setLoggingVerbosity(level);
1188 #elif defined(WITH_CYCLES_LOGGING)
1189                 CCL_logging_verbosity_set(level);
1190 #else
1191                 (void)level;
1192 #endif
1193
1194                 return 1;
1195         }
1196         else {
1197                 printf("\nError: you must specify a verbosity level.\n");
1198                 return 0;
1199         }
1200 }
1201
1202 static const char arg_handle_extension_set_doc[] =
1203 "<bool>\n"
1204 "\tSet option to add the file extension to the end of the file"
1205 ;
1206 static int arg_handle_extension_set(int argc, const char **argv, void *data)
1207 {
1208         bContext *C = data;
1209         if (argc > 1) {
1210                 Scene *scene = CTX_data_scene(C);
1211                 if (scene) {
1212                         if (argv[1][0] == '0') {
1213                                 scene->r.scemode &= ~R_EXTENSION;
1214                         }
1215                         else if (argv[1][0] == '1') {
1216                                 scene->r.scemode |= R_EXTENSION;
1217                         }
1218                         else {
1219                                 printf("\nError: Use '-x 1 / -x 0' To set the extension option or '--use-extension'\n");
1220                         }
1221                 }
1222                 else {
1223                         printf("\nError: no blend loaded. "
1224                                "order the arguments so '-o ' is after '-x '.\n");
1225                 }
1226                 return 1;
1227         }
1228         else {
1229                 printf("\nError: you must specify a path after '- '.\n");
1230                 return 0;
1231         }
1232 }
1233
1234 static const char arg_handle_ge_parameters_set_doc[] =
1235 "Game Engine specific options\n"
1236 "\t-g fixedtime\t\tRun on 50 hertz without dropping frames\n"
1237 "\t-g vertexarrays\t\tUse Vertex Arrays for rendering (usually faster)\n"
1238 "\t-g nomipmap\t\tNo Texture Mipmapping\n"
1239 "\t-g linearmipmap\t\tLinear Texture Mipmapping instead of Nearest (default)"
1240 ;
1241 static int arg_handle_ge_parameters_set(int argc, const char **argv, void *data)
1242 {
1243         int a = 0;
1244 #ifdef WITH_GAMEENGINE
1245         SYS_SystemHandle syshandle = *(SYS_SystemHandle *)data;
1246 #else
1247         (void)data;
1248 #endif
1249
1250         /**
1251          * gameengine parameters are automatically put into system
1252          * -g [paramname = value]
1253          * -g [boolparamname]
1254          * example:
1255          * -g novertexarrays
1256          * -g maxvertexarraysize = 512
1257          */
1258
1259         if (argc >= 1) {
1260                 const char *paramname = argv[a];
1261                 /* check for single value versus assignment */
1262                 if (a + 1 < argc && (*(argv[a + 1]) == '=')) {
1263                         a++;
1264                         if (a + 1 < argc) {
1265                                 a++;
1266                                 /* assignment */
1267 #ifdef WITH_GAMEENGINE
1268                                 SYS_WriteCommandLineString(syshandle, paramname, argv[a]);
1269 #endif
1270                         }
1271                         else {
1272                                 printf("error: argument assignment (%s) without value.\n", paramname);
1273                                 return 0;
1274                         }
1275                         /* name arg eaten */
1276
1277                 }
1278                 else {
1279 #ifdef WITH_GAMEENGINE
1280                         SYS_WriteCommandLineInt(syshandle, argv[a], 1);
1281 #endif
1282                         /* doMipMap */
1283                         if (STREQ(argv[a], "nomipmap")) {
1284                                 GPU_set_mipmap(0); //doMipMap = 0;
1285                         }
1286                         /* linearMipMap */
1287                         if (STREQ(argv[a], "linearmipmap")) {
1288                                 GPU_set_mipmap(1);
1289                                 GPU_set_linear_mipmap(1); //linearMipMap = 1;
1290                         }
1291
1292
1293                 } /* if (*(argv[a + 1]) == '=') */
1294         }
1295
1296         return a;
1297 }
1298
1299 static const char arg_handle_render_frame_doc[] =
1300 "<frame>\n"
1301 "\tRender frame <frame> and save it.\n"
1302 "\n"
1303 "\t* +<frame> start frame relative, -<frame> end frame relative.\n"
1304 "\t* A comma separated list of frames can also be used (no spaces).\n"
1305 "\t* A range of frames can be expressed using '..' seperator between the first and last frames (inclusive).\n"
1306 ;
1307 static int arg_handle_render_frame(int argc, const char **argv, void *data)
1308 {
1309         const char *arg_id = "-f / --render-frame";
1310         bContext *C = data;
1311         Scene *scene = CTX_data_scene(C);
1312         if (scene) {
1313                 Main *bmain = CTX_data_main(C);
1314
1315                 if (argc > 1) {
1316                         const char *err_msg = NULL;
1317                         Render *re;
1318                         ReportList reports;
1319
1320                         int (*frame_range_arr)[2], frames_range_len;
1321                         if ((frame_range_arr = parse_int_range_relative_clamp_n(
1322                                  argv[1], scene->r.sfra, scene->r.efra, MINAFRAME, MAXFRAME,
1323                                  &frames_range_len, &err_msg)) == NULL)
1324                         {
1325                                 printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1326                                 return 1;
1327                         }
1328
1329                         re = RE_NewSceneRender(scene);
1330                         BLI_begin_threaded_malloc();
1331                         BKE_reports_init(&reports, RPT_STORE);
1332
1333                         RE_SetReports(re, &reports);
1334                         for (int i = 0; i < frames_range_len; i++) {
1335                                 /* We could pass in frame ranges,
1336                                  * but prefer having exact behavior as passing in multiple frames */
1337                                 if ((frame_range_arr[i][0] <= frame_range_arr[i][1]) == 0) {
1338                                         printf("\nWarning: negative range ignored '%s %s'.\n", arg_id, argv[1]);
1339                                 }
1340
1341                                 for (int frame = frame_range_arr[i][0]; frame <= frame_range_arr[i][1]; frame++) {
1342                                         RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, frame, frame, scene->r.frame_step);
1343                                 }
1344                         }
1345                         RE_SetReports(re, NULL);
1346                         BKE_reports_clear(&reports);
1347                         BLI_end_threaded_malloc();
1348                         MEM_freeN(frame_range_arr);
1349                         return 1;
1350                 }
1351                 else {
1352                         printf("\nError: frame number must follow '%s'.\n", arg_id);
1353                         return 0;
1354                 }
1355         }
1356         else {
1357                 printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1358                 return 0;
1359         }
1360 }
1361
1362 static const char arg_handle_render_animation_doc[] =
1363 "\n\tRender frames from start to end (inclusive)"
1364 ;
1365 static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(argv), void *data)
1366 {
1367         bContext *C = data;
1368         Scene *scene = CTX_data_scene(C);
1369         if (scene) {
1370                 Main *bmain = CTX_data_main(C);
1371                 Render *re = RE_NewSceneRender(scene);
1372                 ReportList reports;
1373                 BLI_begin_threaded_malloc();
1374                 BKE_reports_init(&reports, RPT_STORE);
1375                 RE_SetReports(re, &reports);
1376                 RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, scene->r.sfra, scene->r.efra, scene->r.frame_step);
1377                 RE_SetReports(re, NULL);
1378                 BKE_reports_clear(&reports);
1379                 BLI_end_threaded_malloc();
1380         }
1381         else {
1382                 printf("\nError: no blend loaded. cannot use '-a'.\n");
1383         }
1384         return 0;
1385 }
1386
1387 static const char arg_handle_scene_set_doc[] =
1388 "<name>\n"
1389 "\tSet the active scene <name> for rendering"
1390 ;
1391 static int arg_handle_scene_set(int argc, const char **argv, void *data)
1392 {
1393         if (argc > 1) {
1394                 bContext *C = data;
1395                 Scene *scene = BKE_scene_set_name(CTX_data_main(C), argv[1]);
1396                 if (scene) {
1397                         CTX_data_scene_set(C, scene);
1398                 }
1399                 return 1;
1400         }
1401         else {
1402                 printf("\nError: Scene name must follow '-S / --scene'.\n");
1403                 return 0;
1404         }
1405 }
1406
1407 static const char arg_handle_frame_start_set_doc[] =
1408 "<frame>\n"
1409 "\tSet start to frame <frame>, supports +/- for relative frames too."
1410 ;
1411 static int arg_handle_frame_start_set(int argc, const char **argv, void *data)
1412 {
1413         const char *arg_id = "-s / --frame-start";
1414         bContext *C = data;
1415         Scene *scene = CTX_data_scene(C);
1416         if (scene) {
1417                 if (argc > 1) {
1418                         const char *err_msg = NULL;
1419                         if (!parse_int_relative_clamp(
1420                                 argv[1], NULL, scene->r.sfra, scene->r.sfra - 1, MINAFRAME, MAXFRAME,
1421                                 &scene->r.sfra, &err_msg))
1422                         {
1423                                 printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1424                         }
1425                         return 1;
1426                 }
1427                 else {
1428                         printf("\nError: frame number must follow '%s'.\n", arg_id);
1429                         return 0;
1430                 }
1431         }
1432         else {
1433                 printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1434                 return 0;
1435         }
1436 }
1437
1438 static const char arg_handle_frame_end_set_doc[] =
1439 "<frame>\n"
1440 "\tSet end to frame <frame>, supports +/- for relative frames too."
1441 ;
1442 static int arg_handle_frame_end_set(int argc, const char **argv, void *data)
1443 {
1444         const char *arg_id = "-e / --frame-end";
1445         bContext *C = data;
1446         Scene *scene = CTX_data_scene(C);
1447         if (scene) {
1448                 if (argc > 1) {
1449                         const char *err_msg = NULL;
1450                         if (!parse_int_relative_clamp(
1451                                 argv[1], NULL, scene->r.efra, scene->r.efra - 1, MINAFRAME, MAXFRAME,
1452                                 &scene->r.efra, &err_msg))
1453                         {
1454                                 printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1455                         }
1456                         return 1;
1457                 }
1458                 else {
1459                         printf("\nError: frame number must follow '%s'.\n", arg_id);
1460                         return 0;
1461                 }
1462         }
1463         else {
1464                 printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1465                 return 0;
1466         }
1467 }
1468
1469 static const char arg_handle_frame_skip_set_doc[] =
1470 "<frames>\n"
1471 "\tSet number of frames to step forward after each rendered frame"
1472 ;
1473 static int arg_handle_frame_skip_set(int argc, const char **argv, void *data)
1474 {
1475         const char *arg_id = "-j / --frame-jump";
1476         bContext *C = data;
1477         Scene *scene = CTX_data_scene(C);
1478         if (scene) {
1479                 if (argc > 1) {
1480                         const char *err_msg = NULL;
1481                         if (!parse_int_clamp(argv[1], NULL, 1, MAXFRAME, &scene->r.frame_step, &err_msg)) {
1482                                 printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1483                         }
1484                         return 1;
1485                 }
1486                 else {
1487                         printf("\nError: number of frames to step must follow '%s'.\n", arg_id);
1488                         return 0;
1489                 }
1490         }
1491         else {
1492                 printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1493                 return 0;
1494         }
1495 }
1496
1497 static const char arg_handle_python_file_run_doc[] =
1498 "<filename>\n"
1499 "\tRun the given Python script file"
1500 ;
1501 static int arg_handle_python_file_run(int argc, const char **argv, void *data)
1502 {
1503 #ifdef WITH_PYTHON
1504         bContext *C = data;
1505
1506         /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1507         if (argc > 1) {
1508                 /* Make the path absolute because its needed for relative linked blends to be found */
1509                 char filename[FILE_MAX];
1510                 BLI_strncpy(filename, argv[1], sizeof(filename));
1511                 BLI_path_cwd(filename, sizeof(filename));
1512
1513                 bool ok;
1514                 BPY_CTX_SETUP(ok = BPY_execute_filepath(C, filename, NULL));
1515                 if (!ok && app_state.exit_code_on_error.python) {
1516                         printf("\nError: script failed, file: '%s', exiting.\n", argv[1]);
1517                         exit(app_state.exit_code_on_error.python);
1518                 }
1519                 return 1;
1520         }
1521         else {
1522                 printf("\nError: you must specify a filepath after '%s'.\n", argv[0]);
1523                 return 0;
1524         }
1525 #else
1526         UNUSED_VARS(argc, argv, data);
1527         printf("This blender was built without python support\n");
1528         return 0;
1529 #endif /* WITH_PYTHON */
1530 }
1531
1532 static const char arg_handle_python_text_run_doc[] =
1533 "<name>\n"
1534 "\tRun the given Python script text block"
1535 ;
1536 static int arg_handle_python_text_run(int argc, const char **argv, void *data)
1537 {
1538 #ifdef WITH_PYTHON
1539         bContext *C = data;
1540
1541         /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1542         if (argc > 1) {
1543                 /* Make the path absolute because its needed for relative linked blends to be found */
1544                 struct Text *text = (struct Text *)BKE_libblock_find_name(ID_TXT, argv[1]);
1545                 bool ok;
1546
1547                 if (text) {
1548                         BPY_CTX_SETUP(ok = BPY_execute_text(C, text, NULL, false));
1549                 }
1550                 else {
1551                         printf("\nError: text block not found %s.\n", argv[1]);
1552                         ok = false;
1553                 }
1554
1555                 if (!ok && app_state.exit_code_on_error.python) {
1556                         printf("\nError: script failed, text: '%s', exiting.\n", argv[1]);
1557                         exit(app_state.exit_code_on_error.python);
1558                 }
1559
1560                 return 1;
1561         }
1562         else {
1563                 printf("\nError: you must specify a text block after '%s'.\n", argv[0]);
1564                 return 0;
1565         }
1566 #else
1567         UNUSED_VARS(argc, argv, data);
1568         printf("This blender was built without python support\n");
1569         return 0;
1570 #endif /* WITH_PYTHON */
1571 }
1572
1573 static const char arg_handle_python_expr_run_doc[] =
1574 "<expression>\n"
1575 "\tRun the given expression as a Python script"
1576 ;
1577 static int arg_handle_python_expr_run(int argc, const char **argv, void *data)
1578 {
1579 #ifdef WITH_PYTHON
1580         bContext *C = data;
1581
1582         /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1583         if (argc > 1) {
1584                 bool ok;
1585                 BPY_CTX_SETUP(ok = BPY_execute_string_ex(C, argv[1], false));
1586                 if (!ok && app_state.exit_code_on_error.python) {
1587                         printf("\nError: script failed, expr: '%s', exiting.\n", argv[1]);
1588                         exit(app_state.exit_code_on_error.python);
1589                 }
1590                 return 1;
1591         }
1592         else {
1593                 printf("\nError: you must specify a Python expression after '%s'.\n", argv[0]);
1594                 return 0;
1595         }
1596 #else
1597         UNUSED_VARS(argc, argv, data);
1598         printf("This blender was built without python support\n");
1599         return 0;
1600 #endif /* WITH_PYTHON */
1601 }
1602
1603 static const char arg_handle_python_console_run_doc[] =
1604 "\n\tRun blender with an interactive console"
1605 ;
1606 static int arg_handle_python_console_run(int UNUSED(argc), const char **argv, void *data)
1607 {
1608 #ifdef WITH_PYTHON
1609         bContext *C = data;
1610
1611         BPY_CTX_SETUP(BPY_execute_string(C, "__import__('code').interact()"));
1612
1613         return 0;
1614 #else
1615         UNUSED_VARS(argv, data);
1616         printf("This blender was built without python support\n");
1617         return 0;
1618 #endif /* WITH_PYTHON */
1619 }
1620
1621 static const char arg_handle_python_exit_code_set_doc[] =
1622 "\n"
1623 "\tSet the exit-code in [0..255] to exit if a Python exception is raised\n"
1624 "\t(only for scripts executed from the command line), zero disables."
1625 ;
1626 static int arg_handle_python_exit_code_set(int argc, const char **argv, void *UNUSED(data))
1627 {
1628         const char *arg_id = "--python-exit-code";
1629         if (argc > 1) {
1630                 const char *err_msg = NULL;
1631                 const int min = 0, max = 255;
1632                 int exit_code;
1633                 if (!parse_int_strict_range(argv[1], NULL, min, max, &exit_code, &err_msg)) {
1634                         printf("\nError: %s '%s %s', expected number in [%d..%d].\n", err_msg, arg_id, argv[1], min, max);
1635                         return 1;
1636                 }
1637
1638                 app_state.exit_code_on_error.python = (unsigned char)exit_code;
1639                 return 1;
1640         }
1641         else {
1642                 printf("\nError: you must specify an exit code number '%s'.\n", arg_id);
1643                 return 0;
1644         }
1645 }
1646
1647 static const char arg_handle_addons_set_doc[] =
1648 "\n\tComma separated list of add-ons (no spaces)"
1649 ;
1650 static int arg_handle_addons_set(int argc, const char **argv, void *data)
1651 {
1652         /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1653         if (argc > 1) {
1654 #ifdef WITH_PYTHON
1655                 const char script_str[] =
1656                         "from addon_utils import check, enable\n"
1657                         "for m in '%s'.split(','):\n"
1658                         "    if check(m)[1] is False:\n"
1659                         "        enable(m, persistent=True)";
1660                 const int slen = strlen(argv[1]) + (sizeof(script_str) - 2);
1661                 char *str = malloc(slen);
1662                 bContext *C = data;
1663                 BLI_snprintf(str, slen, script_str, argv[1]);
1664
1665                 BLI_assert(strlen(str) + 1 == slen);
1666                 BPY_CTX_SETUP(BPY_execute_string_ex(C, str, false));
1667                 free(str);
1668 #else
1669                 UNUSED_VARS(argv, data);
1670 #endif /* WITH_PYTHON */
1671                 return 1;
1672         }
1673         else {
1674                 printf("\nError: you must specify a comma separated list after '--addons'.\n");
1675                 return 0;
1676         }
1677 }
1678
1679 static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data)
1680 {
1681         bContext *C = data;
1682         ReportList reports;
1683         bool success;
1684
1685         /* Make the path absolute because its needed for relative linked blends to be found */
1686         char filename[FILE_MAX];
1687
1688         /* note, we could skip these, but so far we always tried to load these files */
1689         if (argv[0][0] == '-') {
1690                 fprintf(stderr, "unknown argument, loading as file: %s\n", argv[0]);
1691         }
1692
1693         BLI_strncpy(filename, argv[0], sizeof(filename));
1694         BLI_path_cwd(filename, sizeof(filename));
1695
1696         /* load the file */
1697         BKE_reports_init(&reports, RPT_PRINT);
1698         WM_file_autoexec_init(filename);
1699         success = WM_file_read(C, filename, &reports);
1700         BKE_reports_clear(&reports);
1701
1702         if (success) {
1703                 if (G.background) {
1704                         /* ensuer we use 'C->data.scene' for background render */
1705                         CTX_wm_window_set(C, NULL);
1706                 }
1707         }
1708         else {
1709                 /* failed to load file, stop processing arguments if running in background mode */
1710                 if (G.background) {
1711                         /* Set is_break if running in the background mode so
1712                          * blender will return non-zero exit code which then
1713                          * could be used in automated script to control how
1714                          * good or bad things are.
1715                          */
1716                         G.is_break = true;
1717                         return -1;
1718                 }
1719
1720                 /* Just pretend a file was loaded, so the user can press Save and it'll save at the filename from the CLI. */
1721                 BLI_strncpy(G.main->name, filename, FILE_MAX);
1722                 G.relbase_valid = true;
1723                 G.save_over = true;
1724                 printf("... opened default scene instead; saving will write to %s\n", filename);
1725         }
1726
1727         G.file_loaded = 1;
1728
1729         return 0;
1730 }
1731
1732
1733 void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
1734 {
1735
1736 #define CB(a) a##_doc, a
1737 #define CB_EX(a, b) a##_doc_##b, a
1738
1739         //BLI_argsAdd(ba, pass, short_arg, long_arg, doc, cb, C);
1740
1741         /* end argument processing after -- */
1742         BLI_argsAdd(ba, -1, "--", NULL, CB(arg_handle_arguments_end), NULL);
1743
1744         /* first pass: background mode, disable python and commands that exit after usage */
1745         BLI_argsAdd(ba, 1, "-h", "--help", CB(arg_handle_print_help), ba);
1746         /* Windows only */
1747         BLI_argsAdd(ba, 1, "/?", NULL, CB_EX(arg_handle_print_help, win32), ba);
1748
1749         BLI_argsAdd(ba, 1, "-v", "--version", CB(arg_handle_print_version), NULL);
1750
1751         BLI_argsAdd(ba, 1, "-y", "--enable-autoexec", CB_EX(arg_handle_python_set, enable), (void *)true);
1752         BLI_argsAdd(ba, 1, "-Y", "--disable-autoexec", CB_EX(arg_handle_python_set, disable), (void *)false);
1753
1754         BLI_argsAdd(ba, 1, NULL, "--disable-crash-handler", CB(arg_handle_crash_handler_disable), NULL);
1755         BLI_argsAdd(ba, 1, NULL, "--disable-abort-handler", CB(arg_handle_abort_handler_disable), NULL);
1756
1757         BLI_argsAdd(ba, 1, "-b", "--background", CB(arg_handle_background_mode_set), NULL);
1758
1759         BLI_argsAdd(ba, 1, "-a", NULL, CB(arg_handle_playback_mode), NULL);
1760
1761         BLI_argsAdd(ba, 1, "-d", "--debug", CB(arg_handle_debug_mode_set), ba);
1762
1763 #ifdef WITH_FFMPEG
1764         BLI_argsAdd(ba, 1, NULL, "--debug-ffmpeg",
1765                     CB_EX(arg_handle_debug_mode_generic_set, ffmpeg), (void *)G_DEBUG_FFMPEG);
1766 #endif
1767
1768 #ifdef WITH_FREESTYLE
1769         BLI_argsAdd(ba, 1, NULL, "--debug-freestyle",
1770                     CB_EX(arg_handle_debug_mode_generic_set, freestyle), (void *)G_DEBUG_FREESTYLE);
1771 #endif
1772
1773         BLI_argsAdd(ba, 1, NULL, "--debug-python",
1774                     CB_EX(arg_handle_debug_mode_generic_set, python), (void *)G_DEBUG_PYTHON);
1775         BLI_argsAdd(ba, 1, NULL, "--debug-events",
1776                     CB_EX(arg_handle_debug_mode_generic_set, events), (void *)G_DEBUG_EVENTS);
1777         BLI_argsAdd(ba, 1, NULL, "--debug-handlers",
1778                     CB_EX(arg_handle_debug_mode_generic_set, handlers), (void *)G_DEBUG_HANDLERS);
1779         BLI_argsAdd(ba, 1, NULL, "--debug-wm",
1780                     CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM);
1781         BLI_argsAdd(ba, 1, NULL, "--debug-all", CB(arg_handle_debug_mode_all), NULL);
1782
1783         BLI_argsAdd(ba, 1, NULL, "--debug-io", CB(arg_handle_debug_mode_io), NULL);
1784
1785         BLI_argsAdd(ba, 1, NULL, "--debug-fpe",
1786                     CB(arg_handle_debug_fpe_set), NULL);
1787
1788 #ifdef WITH_LIBMV
1789         BLI_argsAdd(ba, 1, NULL, "--debug-libmv", CB(arg_handle_debug_mode_libmv), NULL);
1790 #endif
1791 #ifdef WITH_CYCLES_LOGGING
1792         BLI_argsAdd(ba, 1, NULL, "--debug-cycles", CB(arg_handle_debug_mode_cycles), NULL);
1793 #endif
1794         BLI_argsAdd(ba, 1, NULL, "--debug-memory", CB(arg_handle_debug_mode_memory_set), NULL);
1795
1796         BLI_argsAdd(ba, 1, NULL, "--debug-value",
1797                     CB(arg_handle_debug_value_set), NULL);
1798         BLI_argsAdd(ba, 1, NULL, "--debug-jobs",
1799                     CB_EX(arg_handle_debug_mode_generic_set, jobs), (void *)G_DEBUG_JOBS);
1800         BLI_argsAdd(ba, 1, NULL, "--debug-gpu",
1801                     CB_EX(arg_handle_debug_mode_generic_set, gpu), (void *)G_DEBUG_GPU);
1802         BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph",
1803                     CB_EX(arg_handle_debug_mode_generic_set, depsgraph), (void *)G_DEBUG_DEPSGRAPH);
1804         BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-no-threads",
1805                     CB_EX(arg_handle_debug_mode_generic_set, depsgraph_no_threads), (void *)G_DEBUG_DEPSGRAPH_NO_THREADS);
1806         BLI_argsAdd(ba, 1, NULL, "--debug-gpumem",
1807                     CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM);
1808
1809         BLI_argsAdd(ba, 1, NULL, "--verbose", CB(arg_handle_verbosity_set), NULL);
1810
1811         BLI_argsAdd(ba, 1, NULL, "--factory-startup", CB(arg_handle_factory_startup_set), NULL);
1812
1813         /* TODO, add user env vars? */
1814         BLI_argsAdd(ba, 1, NULL, "--env-system-datafiles", CB_EX(arg_handle_env_system_set, datafiles), NULL);
1815         BLI_argsAdd(ba, 1, NULL, "--env-system-scripts", CB_EX(arg_handle_env_system_set, scripts), NULL);
1816         BLI_argsAdd(ba, 1, NULL, "--env-system-python", CB_EX(arg_handle_env_system_set, python), NULL);
1817
1818         /* second pass: custom window stuff */
1819         BLI_argsAdd(ba, 2, "-p", "--window-geometry", CB(arg_handle_window_geometry), NULL);
1820         BLI_argsAdd(ba, 2, "-w", "--window-border", CB(arg_handle_with_borders), NULL);
1821         BLI_argsAdd(ba, 2, "-W", "--window-borderless", CB(arg_handle_without_borders), NULL);
1822         BLI_argsAdd(ba, 2, "-con", "--start-console", CB(arg_handle_start_with_console), NULL);
1823         BLI_argsAdd(ba, 2, "-R", NULL, CB(arg_handle_register_extension), NULL);
1824         BLI_argsAdd(ba, 2, "-r", NULL, CB_EX(arg_handle_register_extension, silent), ba);
1825         BLI_argsAdd(ba, 2, NULL, "--no-native-pixels", CB(arg_handle_native_pixels_set), ba);
1826
1827         /* third pass: disabling things and forcing settings */
1828         BLI_argsAddCase(ba, 3, "-nojoystick", 1, NULL, 0, CB(arg_handle_joystick_disable), syshandle);
1829         BLI_argsAddCase(ba, 3, "-noaudio", 1, NULL, 0, CB(arg_handle_audio_disable), NULL);
1830         BLI_argsAddCase(ba, 3, "-setaudio", 1, NULL, 0, CB(arg_handle_audio_set), NULL);
1831
1832         /* fourth pass: processing arguments */
1833         BLI_argsAdd(ba, 4, "-g", NULL, CB(arg_handle_ge_parameters_set), syshandle);
1834         BLI_argsAdd(ba, 4, "-f", "--render-frame", CB(arg_handle_render_frame), C);
1835         BLI_argsAdd(ba, 4, "-a", "--render-anim", CB(arg_handle_render_animation), C);
1836         BLI_argsAdd(ba, 4, "-S", "--scene", CB(arg_handle_scene_set), C);
1837         BLI_argsAdd(ba, 4, "-s", "--frame-start", CB(arg_handle_frame_start_set), C);
1838         BLI_argsAdd(ba, 4, "-e", "--frame-end", CB(arg_handle_frame_end_set), C);
1839         BLI_argsAdd(ba, 4, "-j", "--frame-jump", CB(arg_handle_frame_skip_set), C);
1840         BLI_argsAdd(ba, 4, "-P", "--python", CB(arg_handle_python_file_run), C);
1841         BLI_argsAdd(ba, 4, NULL, "--python-text", CB(arg_handle_python_text_run), C);
1842         BLI_argsAdd(ba, 4, NULL, "--python-expr", CB(arg_handle_python_expr_run), C);
1843         BLI_argsAdd(ba, 4, NULL, "--python-console", CB(arg_handle_python_console_run), C);
1844         BLI_argsAdd(ba, 4, NULL, "--python-exit-code", CB(arg_handle_python_exit_code_set), NULL);
1845         BLI_argsAdd(ba, 4, NULL, "--addons", CB(arg_handle_addons_set), C);
1846
1847         BLI_argsAdd(ba, 4, "-o", "--render-output", CB(arg_handle_output_set), C);
1848         BLI_argsAdd(ba, 4, "-E", "--engine", CB(arg_handle_engine_set), C);
1849
1850         BLI_argsAdd(ba, 4, "-F", "--render-format", CB(arg_handle_image_type_set), C);
1851         BLI_argsAdd(ba, 1, "-t", "--threads", CB(arg_handle_threads_set), NULL);
1852         BLI_argsAdd(ba, 4, "-x", "--use-extension", CB(arg_handle_extension_set), C);
1853
1854 #undef CB
1855 #undef CB_EX
1856
1857 }
1858
1859 /**
1860  * Needs to be added separately.
1861  */
1862 void main_args_setup_post(bContext *C, bArgs *ba)
1863 {
1864         BLI_argsParse(ba, 4, arg_handle_load_file, C);
1865 }
1866
1867 /** \} */
1868
1869 #endif /* WITH_PYTHON_MODULE */