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