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