1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup creator
19  */
20 
21 #ifndef WITH_PYTHON_MODULE
22 
23 #  include <errno.h>
24 #  include <stdlib.h>
25 #  include <string.h>
26 
27 #  include "MEM_guardedalloc.h"
28 
29 #  include "CLG_log.h"
30 
31 #  ifdef WIN32
32 #    include "BLI_winstuff.h"
33 #  endif
34 
35 #  include "BLI_args.h"
36 #  include "BLI_fileops.h"
37 #  include "BLI_listbase.h"
38 #  include "BLI_mempool.h"
39 #  include "BLI_path_util.h"
40 #  include "BLI_string.h"
41 #  include "BLI_string_utf8.h"
42 #  include "BLI_system.h"
43 #  include "BLI_threads.h"
44 #  include "BLI_utildefines.h"
45 
46 #  include "BLO_readfile.h" /* only for BLO_has_bfile_extension */
47 
48 #  include "BKE_blender_version.h"
49 #  include "BKE_context.h"
50 
51 #  include "BKE_appdir.h"
52 #  include "BKE_global.h"
53 #  include "BKE_image.h"
54 #  include "BKE_lib_id.h"
55 #  include "BKE_main.h"
56 #  include "BKE_report.h"
57 #  include "BKE_scene.h"
58 #  include "BKE_sound.h"
59 
60 #  include "IMB_imbuf.h"
61 
62 #  ifdef WITH_PYTHON
63 #    include "BPY_extern_python.h"
64 #    include "BPY_extern_run.h"
65 #  endif
66 
67 #  include "RE_engine.h"
68 #  include "RE_pipeline.h"
69 
70 #  include "ED_datafiles.h"
71 
72 #  include "WM_api.h"
73 
74 #  ifdef WITH_LIBMV
75 #    include "libmv-capi.h"
76 #  endif
77 
78 #  ifdef WITH_CYCLES_LOGGING
79 #    include "CCL_api.h"
80 #  endif
81 
82 #  include "DEG_depsgraph.h"
83 #  include "DEG_depsgraph_build.h"
84 #  include "DEG_depsgraph_debug.h"
85 
86 #  include "creator_intern.h" /* own include */
87 
88 /* -------------------------------------------------------------------- */
89 /** \name Utility String Parsing
90  * \{ */
91 
parse_int_relative(const char * str,const char * str_end_test,int pos,int neg,int * r_value,const char ** r_err_msg)92 static bool parse_int_relative(const char *str,
93                                const char *str_end_test,
94                                int pos,
95                                int neg,
96                                int *r_value,
97                                const char **r_err_msg)
98 {
99   char *str_end = NULL;
100   long value;
101 
102   errno = 0;
103 
104   switch (*str) {
105     case '+':
106       value = pos + strtol(str + 1, &str_end, 10);
107       break;
108     case '-':
109       value = (neg - strtol(str + 1, &str_end, 10)) + 1;
110       break;
111     default:
112       value = strtol(str, &str_end, 10);
113       break;
114   }
115 
116   if (*str_end != '\0' && (str_end != str_end_test)) {
117     static const char *msg = "not a number";
118     *r_err_msg = msg;
119     return false;
120   }
121   else if ((errno == ERANGE) || ((value < INT_MIN || value > INT_MAX))) {
122     static const char *msg = "exceeds range";
123     *r_err_msg = msg;
124     return false;
125   }
126   else {
127     *r_value = (int)value;
128     return true;
129   }
130 }
131 
parse_int_range_sep_search(const char * str,const char * str_end_test)132 static const char *parse_int_range_sep_search(const char *str, const char *str_end_test)
133 {
134   const char *str_end_range = NULL;
135   if (str_end_test) {
136     str_end_range = memchr(str, '.', (str_end_test - str) - 1);
137     if (str_end_range && (str_end_range[1] != '.')) {
138       str_end_range = NULL;
139     }
140   }
141   else {
142     str_end_range = strstr(str, "..");
143     if (str_end_range && (str_end_range[2] == '\0')) {
144       str_end_range = NULL;
145     }
146   }
147   return str_end_range;
148 }
149 
150 /**
151  * Parse a number as a range, eg: `1..4`.
152  *
153  * The \a str_end_range argument is a result of #parse_int_range_sep_search.
154  */
parse_int_range_relative(const char * str,const char * str_end_range,const char * str_end_test,int pos,int neg,int r_value_range[2],const char ** r_err_msg)155 static bool parse_int_range_relative(const char *str,
156                                      const char *str_end_range,
157                                      const char *str_end_test,
158                                      int pos,
159                                      int neg,
160                                      int r_value_range[2],
161                                      const char **r_err_msg)
162 {
163   if (parse_int_relative(str, str_end_range, pos, neg, &r_value_range[0], r_err_msg) &&
164       parse_int_relative(
165           str_end_range + 2, str_end_test, pos, neg, &r_value_range[1], r_err_msg)) {
166     return true;
167   }
168   else {
169     return false;
170   }
171 }
172 
parse_int_relative_clamp(const char * str,const char * str_end_test,int pos,int neg,int min,int max,int * r_value,const char ** r_err_msg)173 static bool parse_int_relative_clamp(const char *str,
174                                      const char *str_end_test,
175                                      int pos,
176                                      int neg,
177                                      int min,
178                                      int max,
179                                      int *r_value,
180                                      const char **r_err_msg)
181 {
182   if (parse_int_relative(str, str_end_test, pos, neg, r_value, r_err_msg)) {
183     CLAMP(*r_value, min, max);
184     return true;
185   }
186   else {
187     return false;
188   }
189 }
190 
parse_int_range_relative_clamp(const char * str,const char * str_end_range,const char * str_end_test,int pos,int neg,int min,int max,int r_value_range[2],const char ** r_err_msg)191 static bool parse_int_range_relative_clamp(const char *str,
192                                            const char *str_end_range,
193                                            const char *str_end_test,
194                                            int pos,
195                                            int neg,
196                                            int min,
197                                            int max,
198                                            int r_value_range[2],
199                                            const char **r_err_msg)
200 {
201   if (parse_int_range_relative(
202           str, str_end_range, str_end_test, pos, neg, r_value_range, r_err_msg)) {
203     CLAMP(r_value_range[0], min, max);
204     CLAMP(r_value_range[1], min, max);
205     return true;
206   }
207   else {
208     return false;
209   }
210 }
211 
212 /**
213  * No clamping, fails with any number outside the range.
214  */
parse_int_strict_range(const char * str,const char * str_end_test,const int min,const int max,int * r_value,const char ** r_err_msg)215 static bool parse_int_strict_range(const char *str,
216                                    const char *str_end_test,
217                                    const int min,
218                                    const int max,
219                                    int *r_value,
220                                    const char **r_err_msg)
221 {
222   char *str_end = NULL;
223   long value;
224 
225   errno = 0;
226   value = strtol(str, &str_end, 10);
227 
228   if (*str_end != '\0' && (str_end != str_end_test)) {
229     static const char *msg = "not a number";
230     *r_err_msg = msg;
231     return false;
232   }
233   else if ((errno == ERANGE) || ((value < min || value > max))) {
234     static const char *msg = "exceeds range";
235     *r_err_msg = msg;
236     return false;
237   }
238   else {
239     *r_value = (int)value;
240     return true;
241   }
242 }
243 
parse_int(const char * str,const char * str_end_test,int * r_value,const char ** r_err_msg)244 static bool parse_int(const char *str,
245                       const char *str_end_test,
246                       int *r_value,
247                       const char **r_err_msg)
248 {
249   return parse_int_strict_range(str, str_end_test, INT_MIN, INT_MAX, r_value, r_err_msg);
250 }
251 
parse_int_clamp(const char * str,const char * str_end_test,int min,int max,int * r_value,const char ** r_err_msg)252 static bool parse_int_clamp(const char *str,
253                             const char *str_end_test,
254                             int min,
255                             int max,
256                             int *r_value,
257                             const char **r_err_msg)
258 {
259   if (parse_int(str, str_end_test, r_value, r_err_msg)) {
260     CLAMP(*r_value, min, max);
261     return true;
262   }
263   else {
264     return false;
265   }
266 }
267 
268 #  if 0
269 /**
270  * Version of #parse_int_relative_clamp
271  * that parses a comma separated list of numbers.
272  */
273 static int *parse_int_relative_clamp_n(
274     const char *str, int pos, int neg, int min, int max, int *r_value_len, const char **r_err_msg)
275 {
276   const char sep = ',';
277   int len = 1;
278   for (int i = 0; str[i]; i++) {
279     if (str[i] == sep) {
280       len++;
281     }
282   }
283 
284   int *values = MEM_mallocN(sizeof(*values) * len, __func__);
285   int i = 0;
286   while (true) {
287     const char *str_end = strchr(str, sep);
288     if ((*str == sep) || (*str == '\0')) {
289       static const char *msg = "incorrect comma use";
290       *r_err_msg = msg;
291       goto fail;
292     }
293     else if (parse_int_relative_clamp(str, str_end, pos, neg, min, max, &values[i], r_err_msg)) {
294       i++;
295     }
296     else {
297       goto fail; /* error message already set */
298     }
299 
300     if (str_end) { /* next */
301       str = str_end + 1;
302     }
303     else { /* finished */
304       break;
305     }
306   }
307 
308   *r_value_len = i;
309   return values;
310 
311 fail:
312   MEM_freeN(values);
313   return NULL;
314 }
315 
316 #  endif
317 
318 /**
319  * Version of #parse_int_relative_clamp & #parse_int_range_relative_clamp
320  * that parses a comma separated list of numbers.
321  *
322  * \note single values are evaluated as a range with matching start/end.
323  */
parse_int_range_relative_clamp_n(const char * str,int pos,int neg,int min,int max,int * r_value_len,const char ** r_err_msg)324 static int (*parse_int_range_relative_clamp_n(const char *str,
325                                               int pos,
326                                               int neg,
327                                               int min,
328                                               int max,
329                                               int *r_value_len,
330                                               const char **r_err_msg))[2]
331 {
332   const char sep = ',';
333   int len = 1;
334   for (int i = 0; str[i]; i++) {
335     if (str[i] == sep) {
336       len++;
337     }
338   }
339 
340   int(*values)[2] = MEM_mallocN(sizeof(*values) * len, __func__);
341   int i = 0;
342   while (true) {
343     const char *str_end_range;
344     const char *str_end = strchr(str, sep);
345     if ((*str == sep) || (*str == '\0')) {
346       static const char *msg = "incorrect comma use";
347       *r_err_msg = msg;
348       goto fail;
349     }
350     else if ((str_end_range = parse_int_range_sep_search(str, str_end)) ?
351                  parse_int_range_relative_clamp(
352                      str, str_end_range, str_end, pos, neg, min, max, values[i], r_err_msg) :
353                  parse_int_relative_clamp(
354                      str, str_end, pos, neg, min, max, &values[i][0], r_err_msg)) {
355       if (str_end_range == NULL) {
356         values[i][1] = values[i][0];
357       }
358       i++;
359     }
360     else {
361       goto fail; /* error message already set */
362     }
363 
364     if (str_end) { /* next */
365       str = str_end + 1;
366     }
367     else { /* finished */
368       break;
369     }
370   }
371 
372   *r_value_len = i;
373   return values;
374 
375 fail:
376   MEM_freeN(values);
377   return NULL;
378 }
379 
380 /** \} */
381 
382 /* -------------------------------------------------------------------- */
383 /** \name Utilities Python Context Macro (#BPY_CTX_SETUP)
384  * \{ */
385 
386 #  ifdef WITH_PYTHON
387 
388 struct BlendePyContextStore {
389   wmWindowManager *wm;
390   Scene *scene;
391   wmWindow *win;
392   bool has_win;
393 };
394 
arg_py_context_backup(bContext * C,struct BlendePyContextStore * c_py,const char * script_id)395 static void arg_py_context_backup(bContext *C,
396                                   struct BlendePyContextStore *c_py,
397                                   const char *script_id)
398 {
399   c_py->wm = CTX_wm_manager(C);
400   c_py->scene = CTX_data_scene(C);
401   c_py->has_win = !BLI_listbase_is_empty(&c_py->wm->windows);
402   if (c_py->has_win) {
403     c_py->win = CTX_wm_window(C);
404     CTX_wm_window_set(C, c_py->wm->windows.first);
405   }
406   else {
407     c_py->win = NULL;
408     fprintf(stderr,
409             "Python script \"%s\" "
410             "running with missing context data.\n",
411             script_id);
412   }
413 }
414 
arg_py_context_restore(bContext * C,struct BlendePyContextStore * c_py)415 static void arg_py_context_restore(bContext *C, struct BlendePyContextStore *c_py)
416 {
417   /* script may load a file, check old data is valid before using */
418   if (c_py->has_win) {
419     if ((c_py->win == NULL) || ((BLI_findindex(&G_MAIN->wm, c_py->wm) != -1) &&
420                                 (BLI_findindex(&c_py->wm->windows, c_py->win) != -1))) {
421       CTX_wm_window_set(C, c_py->win);
422     }
423   }
424 
425   if ((c_py->scene == NULL) || BLI_findindex(&G_MAIN->scenes, c_py->scene) != -1) {
426     CTX_data_scene_set(C, c_py->scene);
427   }
428 }
429 
430 /* macro for context setup/reset */
431 #    define BPY_CTX_SETUP(_cmd) \
432       { \
433         struct BlendePyContextStore py_c; \
434         arg_py_context_backup(C, &py_c, argv[1]); \
435         { \
436           _cmd; \
437         } \
438         arg_py_context_restore(C, &py_c); \
439       } \
440       ((void)0)
441 
442 #  endif /* WITH_PYTHON */
443 
444 /** \} */
445 
446 /* -------------------------------------------------------------------- */
447 /** \name Handle Argument Callbacks
448  *
449  * \note Doc strings here are used in differently:
450  *
451  * - The `--help` message.
452  * - The man page (for Unix systems),
453  *   see: `doc/manpage/blender.1.py`
454  * - Parsed and extracted for the manual,
455  *   which converts our ad-hoc formatting to reStructuredText.
456  *   see: https://docs.blender.org/manual/en/dev/advanced/command_line.html
457  *
458  * \{ */
459 
print_version_full(void)460 static void print_version_full(void)
461 {
462   printf("Blender %s\n", BKE_blender_version_string());
463 #  ifdef BUILD_DATE
464   printf("\tbuild date: %s\n", build_date);
465   printf("\tbuild time: %s\n", build_time);
466   printf("\tbuild commit date: %s\n", build_commit_date);
467   printf("\tbuild commit time: %s\n", build_commit_time);
468   printf("\tbuild hash: %s\n", build_hash);
469   printf("\tbuild platform: %s\n", build_platform);
470   printf("\tbuild type: %s\n", build_type);
471   printf("\tbuild c flags: %s\n", build_cflags);
472   printf("\tbuild c++ flags: %s\n", build_cxxflags);
473   printf("\tbuild link flags: %s\n", build_linkflags);
474   printf("\tbuild system: %s\n", build_system);
475 #  endif
476 }
477 
print_version_short(void)478 static void print_version_short(void)
479 {
480 #  ifdef BUILD_DATE
481   /* NOTE: We include built time since sometimes we need to tell broken from
482    * working built of the same hash. */
483   printf("Blender %s (hash %s built %s %s)\n",
484          BKE_blender_version_string(),
485          build_hash,
486          build_date,
487          build_time);
488 #  else
489   printf("Blender %s\n", BKE_blender_version_string());
490 #  endif
491 }
492 
493 static const char arg_handle_print_version_doc[] =
494     "\n\t"
495     "Print Blender version and exit.";
arg_handle_print_version(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))496 static int arg_handle_print_version(int UNUSED(argc),
497                                     const char **UNUSED(argv),
498                                     void *UNUSED(data))
499 {
500   print_version_full();
501   exit(0);
502   return 0;
503 }
504 
505 static const char arg_handle_print_help_doc[] =
506     "\n\t"
507     "Print this help text and exit.";
508 static const char arg_handle_print_help_doc_win32[] =
509     "\n\t"
510     "Print this help text and exit (windows only).";
arg_handle_print_help(int UNUSED (argc),const char ** UNUSED (argv),void * data)511 static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), void *data)
512 {
513   bArgs *ba = (bArgs *)data;
514 
515   printf("Blender %s\n", BKE_blender_version_string());
516   printf("Usage: blender [args ...] [file] [args ...]\n\n");
517 
518   printf("Render Options:\n");
519   BLI_argsPrintArgDoc(ba, "--background");
520   BLI_argsPrintArgDoc(ba, "--render-anim");
521   BLI_argsPrintArgDoc(ba, "--scene");
522   BLI_argsPrintArgDoc(ba, "--render-frame");
523   BLI_argsPrintArgDoc(ba, "--frame-start");
524   BLI_argsPrintArgDoc(ba, "--frame-end");
525   BLI_argsPrintArgDoc(ba, "--frame-jump");
526   BLI_argsPrintArgDoc(ba, "--render-output");
527   BLI_argsPrintArgDoc(ba, "--engine");
528   BLI_argsPrintArgDoc(ba, "--threads");
529 
530   printf("\n");
531   printf("Format Options:\n");
532   BLI_argsPrintArgDoc(ba, "--render-format");
533   BLI_argsPrintArgDoc(ba, "--use-extension");
534 
535   printf("\n");
536   printf("Animation Playback Options:\n");
537   BLI_argsPrintArgDoc(ba, "-a");
538 
539   printf("\n");
540   printf("Window Options:\n");
541   BLI_argsPrintArgDoc(ba, "--window-border");
542   BLI_argsPrintArgDoc(ba, "--window-fullscreen");
543   BLI_argsPrintArgDoc(ba, "--window-geometry");
544   BLI_argsPrintArgDoc(ba, "--window-maximized");
545   BLI_argsPrintArgDoc(ba, "--start-console");
546   BLI_argsPrintArgDoc(ba, "--no-native-pixels");
547   BLI_argsPrintArgDoc(ba, "--no-window-focus");
548 
549   printf("\n");
550   printf("Python Options:\n");
551   BLI_argsPrintArgDoc(ba, "--enable-autoexec");
552   BLI_argsPrintArgDoc(ba, "--disable-autoexec");
553 
554   printf("\n");
555 
556   BLI_argsPrintArgDoc(ba, "--python");
557   BLI_argsPrintArgDoc(ba, "--python-text");
558   BLI_argsPrintArgDoc(ba, "--python-expr");
559   BLI_argsPrintArgDoc(ba, "--python-console");
560   BLI_argsPrintArgDoc(ba, "--python-exit-code");
561   BLI_argsPrintArgDoc(ba, "--python-use-system-env");
562   BLI_argsPrintArgDoc(ba, "--addons");
563 
564   printf("\n");
565   printf("Logging Options:\n");
566   BLI_argsPrintArgDoc(ba, "--log");
567   BLI_argsPrintArgDoc(ba, "--log-level");
568   BLI_argsPrintArgDoc(ba, "--log-show-basename");
569   BLI_argsPrintArgDoc(ba, "--log-show-backtrace");
570   BLI_argsPrintArgDoc(ba, "--log-show-timestamp");
571   BLI_argsPrintArgDoc(ba, "--log-file");
572 
573   printf("\n");
574   printf("Debug Options:\n");
575   BLI_argsPrintArgDoc(ba, "--debug");
576   BLI_argsPrintArgDoc(ba, "--debug-value");
577 
578   printf("\n");
579   BLI_argsPrintArgDoc(ba, "--debug-events");
580 #  ifdef WITH_FFMPEG
581   BLI_argsPrintArgDoc(ba, "--debug-ffmpeg");
582 #  endif
583   BLI_argsPrintArgDoc(ba, "--debug-handlers");
584 #  ifdef WITH_LIBMV
585   BLI_argsPrintArgDoc(ba, "--debug-libmv");
586 #  endif
587 #  ifdef WITH_CYCLES_LOGGING
588   BLI_argsPrintArgDoc(ba, "--debug-cycles");
589 #  endif
590   BLI_argsPrintArgDoc(ba, "--debug-memory");
591   BLI_argsPrintArgDoc(ba, "--debug-jobs");
592   BLI_argsPrintArgDoc(ba, "--debug-python");
593   BLI_argsPrintArgDoc(ba, "--debug-depsgraph");
594   BLI_argsPrintArgDoc(ba, "--debug-depsgraph-eval");
595   BLI_argsPrintArgDoc(ba, "--debug-depsgraph-build");
596   BLI_argsPrintArgDoc(ba, "--debug-depsgraph-tag");
597   BLI_argsPrintArgDoc(ba, "--debug-depsgraph-no-threads");
598   BLI_argsPrintArgDoc(ba, "--debug-depsgraph-time");
599   BLI_argsPrintArgDoc(ba, "--debug-depsgraph-pretty");
600   BLI_argsPrintArgDoc(ba, "--debug-gpu");
601   BLI_argsPrintArgDoc(ba, "--debug-gpumem");
602   BLI_argsPrintArgDoc(ba, "--debug-gpu-shaders");
603   BLI_argsPrintArgDoc(ba, "--debug-gpu-force-workarounds");
604   BLI_argsPrintArgDoc(ba, "--debug-wm");
605 #  ifdef WITH_XR_OPENXR
606   BLI_argsPrintArgDoc(ba, "--debug-xr");
607   BLI_argsPrintArgDoc(ba, "--debug-xr-time");
608 #  endif
609   BLI_argsPrintArgDoc(ba, "--debug-all");
610   BLI_argsPrintArgDoc(ba, "--debug-io");
611 
612   printf("\n");
613   BLI_argsPrintArgDoc(ba, "--debug-fpe");
614   BLI_argsPrintArgDoc(ba, "--disable-crash-handler");
615   BLI_argsPrintArgDoc(ba, "--disable-abort-handler");
616 
617   printf("\n");
618   printf("Misc Options:\n");
619   BLI_argsPrintArgDoc(ba, "--app-template");
620   BLI_argsPrintArgDoc(ba, "--factory-startup");
621   BLI_argsPrintArgDoc(ba, "--enable-event-simulate");
622   printf("\n");
623   BLI_argsPrintArgDoc(ba, "--env-system-datafiles");
624   BLI_argsPrintArgDoc(ba, "--env-system-scripts");
625   BLI_argsPrintArgDoc(ba, "--env-system-python");
626   printf("\n");
627   BLI_argsPrintArgDoc(ba, "-noaudio");
628   BLI_argsPrintArgDoc(ba, "-setaudio");
629 
630   printf("\n");
631 
632   BLI_argsPrintArgDoc(ba, "--help");
633 
634   /* WIN32 only (ignored for non-win32) */
635   BLI_argsPrintArgDoc(ba, "-R");
636   BLI_argsPrintArgDoc(ba, "-r");
637 
638   BLI_argsPrintArgDoc(ba, "--version");
639 
640   BLI_argsPrintArgDoc(ba, "--");
641 
642   // printf("\n");
643   // printf("Experimental Features:\n");
644 
645   /* Other options _must_ be last (anything not handled will show here) */
646   printf("\n");
647   printf("Other Options:\n");
648   BLI_argsPrintOtherDoc(ba);
649 
650   printf("\n");
651   printf("Argument Parsing:\n");
652   printf("\tArguments must be separated by white space, eg:\n");
653   printf("\t# blender -ba test.blend\n");
654   printf("\t...will exit since '-ba' is an unknown argument.\n");
655 
656   printf("Argument Order:\n");
657   printf("\tArguments are executed in the order they are given. eg:\n");
658   printf("\t# blender --background test.blend --render-frame 1 --render-output '/tmp'\n");
659   printf(
660       "\t...will not render to '/tmp' because '--render-frame 1' renders before the output path "
661       "is set.\n");
662   printf("\t# blender --background --render-output /tmp test.blend --render-frame 1\n");
663   printf(
664       "\t...will not render to '/tmp' because loading the blend-file overwrites the render output "
665       "that was set.\n");
666   printf("\t# blender --background test.blend --render-output /tmp --render-frame 1\n");
667   printf("\t...works as expected.\n\n");
668 
669   printf("Environment Variables:\n");
670   printf("  $BLENDER_USER_CONFIG      Directory for user configuration files.\n");
671   printf("  $BLENDER_USER_SCRIPTS     Directory for user scripts.\n");
672   printf("  $BLENDER_SYSTEM_SCRIPTS   Directory for system wide scripts.\n");
673   printf("  $BLENDER_USER_DATAFILES   Directory for user data files (icons, translations, ..).\n");
674   printf("  $BLENDER_SYSTEM_DATAFILES Directory for system wide data files.\n");
675   printf("  $BLENDER_SYSTEM_PYTHON    Directory for system Python libraries.\n");
676 #  ifdef WIN32
677   printf("  $TEMP                     Store temporary files here.\n");
678 #  else
679   printf("  $TMP or $TMPDIR           Store temporary files here.\n");
680 #  endif
681 #  ifdef WITH_SDL
682   printf("  $SDL_AUDIODRIVER          LibSDL audio driver - alsa, esd, dma.\n");
683 #  endif
684 
685   exit(0);
686 
687   return 0;
688 }
689 
690 static const char arg_handle_arguments_end_doc[] =
691     "\n\t"
692     "End option processing, following arguments passed unchanged. Access via Python's "
693     "'sys.argv'.";
arg_handle_arguments_end(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))694 static int arg_handle_arguments_end(int UNUSED(argc),
695                                     const char **UNUSED(argv),
696                                     void *UNUSED(data))
697 {
698   return -1;
699 }
700 
701 /* only to give help message */
702 #  ifndef WITH_PYTHON_SECURITY /* default */
703 #    define PY_ENABLE_AUTO ", (default)"
704 #    define PY_DISABLE_AUTO ""
705 #  else
706 #    define PY_ENABLE_AUTO ""
707 #    define PY_DISABLE_AUTO ", (compiled as non-standard default)"
708 #  endif
709 
710 static const char arg_handle_python_set_doc_enable[] =
711     "\n\t"
712     "Enable automatic Python script execution" PY_ENABLE_AUTO ".";
713 static const char arg_handle_python_set_doc_disable[] =
714     "\n\t"
715     "Disable automatic Python script execution (pydrivers & startup scripts)" PY_DISABLE_AUTO ".";
716 #  undef PY_ENABLE_AUTO
717 #  undef PY_DISABLE_AUTO
718 
arg_handle_python_set(int UNUSED (argc),const char ** UNUSED (argv),void * data)719 static int arg_handle_python_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
720 {
721   if ((bool)data) {
722     G.f |= G_FLAG_SCRIPT_AUTOEXEC;
723   }
724   else {
725     G.f &= ~G_FLAG_SCRIPT_AUTOEXEC;
726   }
727   G.f |= G_FLAG_SCRIPT_OVERRIDE_PREF;
728   return 0;
729 }
730 
731 static const char arg_handle_crash_handler_disable_doc[] =
732     "\n\t"
733     "Disable the crash handler.";
arg_handle_crash_handler_disable(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))734 static int arg_handle_crash_handler_disable(int UNUSED(argc),
735                                             const char **UNUSED(argv),
736                                             void *UNUSED(data))
737 {
738   app_state.signal.use_crash_handler = false;
739   return 0;
740 }
741 
742 static const char arg_handle_abort_handler_disable_doc[] =
743     "\n\t"
744     "Disable the abort handler.";
arg_handle_abort_handler_disable(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))745 static int arg_handle_abort_handler_disable(int UNUSED(argc),
746                                             const char **UNUSED(argv),
747                                             void *UNUSED(data))
748 {
749   app_state.signal.use_abort_handler = false;
750   return 0;
751 }
752 
clog_abort_on_error_callback(void * fp)753 static void clog_abort_on_error_callback(void *fp)
754 {
755   BLI_system_backtrace(fp);
756   fflush(fp);
757   abort();
758 }
759 
760 static const char arg_handle_debug_exit_on_error_doc[] =
761     "\n\t"
762     "Immediately exit when internal errors are detected.";
arg_handle_debug_exit_on_error(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))763 static int arg_handle_debug_exit_on_error(int UNUSED(argc),
764                                           const char **UNUSED(argv),
765                                           void *UNUSED(data))
766 {
767   MEM_enable_fail_on_memleak();
768   CLG_error_fn_set(clog_abort_on_error_callback);
769   return 0;
770 }
771 
772 static const char arg_handle_background_mode_set_doc[] =
773     "\n\t"
774     "Run in background (often used for UI-less rendering).";
arg_handle_background_mode_set(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))775 static int arg_handle_background_mode_set(int UNUSED(argc),
776                                           const char **UNUSED(argv),
777                                           void *UNUSED(data))
778 {
779   print_version_short();
780   G.background = 1;
781   return 0;
782 }
783 
784 static const char arg_handle_log_level_set_doc[] =
785     "<level>\n"
786     "\tSet the logging verbosity level (higher for more details) defaults to 1,\n"
787     "\tuse -1 to log all levels.";
arg_handle_log_level_set(int argc,const char ** argv,void * UNUSED (data))788 static int arg_handle_log_level_set(int argc, const char **argv, void *UNUSED(data))
789 {
790   const char *arg_id = "--log-level";
791   if (argc > 1) {
792     const char *err_msg = NULL;
793     if (!parse_int_clamp(argv[1], NULL, -1, INT_MAX, &G.log.level, &err_msg)) {
794       printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
795     }
796     else {
797       if (G.log.level == -1) {
798         G.log.level = INT_MAX;
799       }
800       CLG_level_set(G.log.level);
801     }
802     return 1;
803   }
804   else {
805     printf("\nError: '%s' no args given.\n", arg_id);
806     return 0;
807   }
808 }
809 
810 static const char arg_handle_log_show_basename_set_doc[] =
811     "\n\t"
812     "Only show file name in output (not the leading path).";
arg_handle_log_show_basename_set(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))813 static int arg_handle_log_show_basename_set(int UNUSED(argc),
814                                             const char **UNUSED(argv),
815                                             void *UNUSED(data))
816 {
817   CLG_output_use_basename_set(true);
818   return 0;
819 }
820 
821 static const char arg_handle_log_show_backtrace_set_doc[] =
822     "\n\t"
823     "Show a back trace for each log message (debug builds only).";
arg_handle_log_show_backtrace_set(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))824 static int arg_handle_log_show_backtrace_set(int UNUSED(argc),
825                                              const char **UNUSED(argv),
826                                              void *UNUSED(data))
827 {
828   /* Ensure types don't become incompatible. */
829   void (*fn)(FILE * fp) = BLI_system_backtrace;
830   CLG_backtrace_fn_set((void (*)(void *))fn);
831   return 0;
832 }
833 
834 static const char arg_handle_log_show_timestamp_set_doc[] =
835     "\n\t"
836     "Show a timestamp for each log message in seconds since start.";
arg_handle_log_show_timestamp_set(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))837 static int arg_handle_log_show_timestamp_set(int UNUSED(argc),
838                                              const char **UNUSED(argv),
839                                              void *UNUSED(data))
840 {
841   CLG_output_use_timestamp_set(true);
842   return 0;
843 }
844 
845 static const char arg_handle_log_file_set_doc[] =
846     "<filename>\n"
847     "\tSet a file to output the log to.";
arg_handle_log_file_set(int argc,const char ** argv,void * UNUSED (data))848 static int arg_handle_log_file_set(int argc, const char **argv, void *UNUSED(data))
849 {
850   const char *arg_id = "--log-file";
851   if (argc > 1) {
852     errno = 0;
853     FILE *fp = BLI_fopen(argv[1], "w");
854     if (fp == NULL) {
855       const char *err_msg = errno ? strerror(errno) : "unknown";
856       printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
857     }
858     else {
859       if (UNLIKELY(G.log.file != NULL)) {
860         fclose(G.log.file);
861       }
862       G.log.file = fp;
863       CLG_output_set(G.log.file);
864     }
865     return 1;
866   }
867   else {
868     printf("\nError: '%s' no args given.\n", arg_id);
869     return 0;
870   }
871 }
872 
873 static const char arg_handle_log_set_doc[] =
874     "<match>\n"
875     "\tEnable logging categories, taking a single comma separated argument.\n"
876     "\tMultiple categories can be matched using a '.*' suffix,\n"
877     "\tso '--log \"wm.*\"' logs every kind of window-manager message.\n"
878     "\tUse \"^\" prefix to ignore, so '--log \"*,^wm.operator.*\"' logs all except for "
879     "'wm.operators.*'\n"
880     "\tUse \"*\" to log everything.";
arg_handle_log_set(int argc,const char ** argv,void * UNUSED (data))881 static int arg_handle_log_set(int argc, const char **argv, void *UNUSED(data))
882 {
883   const char *arg_id = "--log";
884   if (argc > 1) {
885     const char *str_step = argv[1];
886     while (*str_step) {
887       const char *str_step_end = strchr(str_step, ',');
888       int str_step_len = str_step_end ? (str_step_end - str_step) : strlen(str_step);
889 
890       if (str_step[0] == '^') {
891         CLG_type_filter_exclude(str_step + 1, str_step_len - 1);
892       }
893       else {
894         CLG_type_filter_include(str_step, str_step_len);
895       }
896 
897       if (str_step_end) {
898         /* Typically only be one, but don't fail on multiple. */
899         while (*str_step_end == ',') {
900           str_step_end++;
901         }
902         str_step = str_step_end;
903       }
904       else {
905         break;
906       }
907     }
908     return 1;
909   }
910   else {
911     printf("\nError: '%s' no args given.\n", arg_id);
912     return 0;
913   }
914 }
915 
916 static const char arg_handle_debug_mode_set_doc[] =
917     "\n"
918     "\tTurn debugging on.\n"
919     "\n"
920     "\t* Enables memory error detection\n"
921     "\t* Disables mouse grab (to interact with a debugger in some cases)\n"
922     "\t* Keeps Python's 'sys.stdin' rather than setting it to None";
arg_handle_debug_mode_set(int UNUSED (argc),const char ** UNUSED (argv),void * data)923 static int arg_handle_debug_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
924 {
925   G.debug |= G_DEBUG; /* std output printf's */
926   printf("Blender %s\n", BKE_blender_version_string());
927   MEM_set_memory_debug();
928 #  ifndef NDEBUG
929   BLI_mempool_set_memory_debug();
930 #  endif
931 
932 #  ifdef WITH_BUILDINFO
933   printf("Build: %s %s %s %s\n", build_date, build_time, build_platform, build_type);
934 #  endif
935 
936   BLI_argsPrint(data);
937   return 0;
938 }
939 
940 #  ifdef WITH_FFMPEG
941 static const char arg_handle_debug_mode_generic_set_doc_ffmpeg[] =
942     "\n\t"
943     "Enable debug messages from FFmpeg library.";
944 #  endif
945 #  ifdef WITH_FREESTYLE
946 static const char arg_handle_debug_mode_generic_set_doc_freestyle[] =
947     "\n\t"
948     "Enable debug messages for Freestyle.";
949 #  endif
950 static const char arg_handle_debug_mode_generic_set_doc_python[] =
951     "\n\t"
952     "Enable debug messages for Python.";
953 static const char arg_handle_debug_mode_generic_set_doc_events[] =
954     "\n\t"
955     "Enable debug messages for the event system.";
956 static const char arg_handle_debug_mode_generic_set_doc_handlers[] =
957     "\n\t"
958     "Enable debug messages for event handling.";
959 static const char arg_handle_debug_mode_generic_set_doc_wm[] =
960     "\n\t"
961     "Enable debug messages for the window manager, shows all operators in search, shows "
962     "keymap errors.";
963 #  ifdef WITH_XR_OPENXR
964 static const char arg_handle_debug_mode_generic_set_doc_xr[] =
965     "\n\t"
966     "Enable debug messages for virtual reality contexts.\n"
967     "\tEnables the OpenXR API validation layer, (OpenXR) debug messages and general information "
968     "prints.";
969 static const char arg_handle_debug_mode_generic_set_doc_xr_time[] =
970     "\n\t"
971     "Enable debug messages for virtual reality frame rendering times.";
972 #  endif
973 static const char arg_handle_debug_mode_generic_set_doc_jobs[] =
974     "\n\t"
975     "Enable time profiling for background jobs.";
976 static const char arg_handle_debug_mode_generic_set_doc_gpu[] =
977     "\n\t"
978     "Enable GPU debug context and information for OpenGL 4.3+.";
979 static const char arg_handle_debug_mode_generic_set_doc_depsgraph[] =
980     "\n\t"
981     "Enable all debug messages from dependency graph.";
982 static const char arg_handle_debug_mode_generic_set_doc_depsgraph_build[] =
983     "\n\t"
984     "Enable debug messages from dependency graph related on graph construction.";
985 static const char arg_handle_debug_mode_generic_set_doc_depsgraph_tag[] =
986     "\n\t"
987     "Enable debug messages from dependency graph related on tagging.";
988 static const char arg_handle_debug_mode_generic_set_doc_depsgraph_time[] =
989     "\n\t"
990     "Enable debug messages from dependency graph related on timing.";
991 static const char arg_handle_debug_mode_generic_set_doc_depsgraph_eval[] =
992     "\n\t"
993     "Enable debug messages from dependency graph related on evaluation.";
994 static const char arg_handle_debug_mode_generic_set_doc_depsgraph_no_threads[] =
995     "\n\t"
996     "Switch dependency graph to a single threaded evaluation.";
997 static const char arg_handle_debug_mode_generic_set_doc_depsgraph_pretty[] =
998     "\n\t"
999     "Enable colors for dependency graph debug messages.";
1000 static const char arg_handle_debug_mode_generic_set_doc_gpumem[] =
1001     "\n\t"
1002     "Enable GPU memory stats in status bar.";
1003 
arg_handle_debug_mode_generic_set(int UNUSED (argc),const char ** UNUSED (argv),void * data)1004 static int arg_handle_debug_mode_generic_set(int UNUSED(argc),
1005                                              const char **UNUSED(argv),
1006                                              void *data)
1007 {
1008   G.debug |= POINTER_AS_INT(data);
1009   return 0;
1010 }
1011 
1012 static const char arg_handle_debug_mode_io_doc[] =
1013     "\n\t"
1014     "Enable debug messages for I/O (Collada, ...).";
arg_handle_debug_mode_io(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1015 static int arg_handle_debug_mode_io(int UNUSED(argc),
1016                                     const char **UNUSED(argv),
1017                                     void *UNUSED(data))
1018 {
1019   G.debug |= G_DEBUG_IO;
1020   return 0;
1021 }
1022 
1023 static const char arg_handle_debug_mode_all_doc[] =
1024     "\n\t"
1025     "Enable all debug messages.";
arg_handle_debug_mode_all(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1026 static int arg_handle_debug_mode_all(int UNUSED(argc),
1027                                      const char **UNUSED(argv),
1028                                      void *UNUSED(data))
1029 {
1030   G.debug |= G_DEBUG_ALL;
1031 #  ifdef WITH_LIBMV
1032   libmv_startDebugLogging();
1033 #  endif
1034 #  ifdef WITH_CYCLES_LOGGING
1035   CCL_start_debug_logging();
1036 #  endif
1037   return 0;
1038 }
1039 
1040 #  ifdef WITH_LIBMV
1041 static const char arg_handle_debug_mode_libmv_doc[] =
1042     "\n\t"
1043     "Enable debug messages from libmv library.";
arg_handle_debug_mode_libmv(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1044 static int arg_handle_debug_mode_libmv(int UNUSED(argc),
1045                                        const char **UNUSED(argv),
1046                                        void *UNUSED(data))
1047 {
1048   libmv_startDebugLogging();
1049 
1050   return 0;
1051 }
1052 #  endif
1053 
1054 #  ifdef WITH_CYCLES_LOGGING
1055 static const char arg_handle_debug_mode_cycles_doc[] =
1056     "\n\t"
1057     "Enable debug messages from Cycles.";
arg_handle_debug_mode_cycles(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1058 static int arg_handle_debug_mode_cycles(int UNUSED(argc),
1059                                         const char **UNUSED(argv),
1060                                         void *UNUSED(data))
1061 {
1062   CCL_start_debug_logging();
1063   return 0;
1064 }
1065 #  endif
1066 
1067 static const char arg_handle_debug_mode_memory_set_doc[] =
1068     "\n\t"
1069     "Enable fully guarded memory allocation and debugging.";
arg_handle_debug_mode_memory_set(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1070 static int arg_handle_debug_mode_memory_set(int UNUSED(argc),
1071                                             const char **UNUSED(argv),
1072                                             void *UNUSED(data))
1073 {
1074   MEM_set_memory_debug();
1075   return 0;
1076 }
1077 
1078 static const char arg_handle_debug_value_set_doc[] =
1079     "<value>\n"
1080     "\tSet debug value of <value> on startup.";
arg_handle_debug_value_set(int argc,const char ** argv,void * UNUSED (data))1081 static int arg_handle_debug_value_set(int argc, const char **argv, void *UNUSED(data))
1082 {
1083   const char *arg_id = "--debug-value";
1084   if (argc > 1) {
1085     const char *err_msg = NULL;
1086     int value;
1087     if (!parse_int(argv[1], NULL, &value, &err_msg)) {
1088       printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1089       return 1;
1090     }
1091 
1092     G.debug_value = value;
1093 
1094     return 1;
1095   }
1096   else {
1097     printf("\nError: you must specify debug value to set.\n");
1098     return 0;
1099   }
1100 }
1101 
1102 static const char arg_handle_debug_fpe_set_doc[] =
1103     "\n\t"
1104     "Enable floating point exceptions.";
arg_handle_debug_fpe_set(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1105 static int arg_handle_debug_fpe_set(int UNUSED(argc),
1106                                     const char **UNUSED(argv),
1107                                     void *UNUSED(data))
1108 {
1109   main_signal_setup_fpe();
1110   return 0;
1111 }
1112 
1113 static const char arg_handle_app_template_doc[] =
1114     "<template>\n"
1115     "\tSet the application template (matching the directory name), use 'default' for none.";
arg_handle_app_template(int argc,const char ** argv,void * UNUSED (data))1116 static int arg_handle_app_template(int argc, const char **argv, void *UNUSED(data))
1117 {
1118   if (argc > 1) {
1119     const char *app_template = STREQ(argv[1], "default") ? "" : argv[1];
1120     WM_init_state_app_template_set(app_template);
1121     return 1;
1122   }
1123   else {
1124     printf("\nError: App template must follow '--app-template'.\n");
1125     return 0;
1126   }
1127 }
1128 
1129 static const char arg_handle_factory_startup_set_doc[] =
1130     "\n\t"
1131     "Skip reading the " STRINGIFY(BLENDER_STARTUP_FILE) " in the users home directory.";
arg_handle_factory_startup_set(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1132 static int arg_handle_factory_startup_set(int UNUSED(argc),
1133                                           const char **UNUSED(argv),
1134                                           void *UNUSED(data))
1135 {
1136   G.factory_startup = 1;
1137   G.f |= G_FLAG_USERPREF_NO_SAVE_ON_EXIT;
1138   return 0;
1139 }
1140 
1141 static const char arg_handle_enable_event_simulate_doc[] =
1142     "\n\t"
1143     "Enable event simulation testing feature 'bpy.types.Window.event_simulate'.";
arg_handle_enable_event_simulate(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1144 static int arg_handle_enable_event_simulate(int UNUSED(argc),
1145                                             const char **UNUSED(argv),
1146                                             void *UNUSED(data))
1147 {
1148   G.f |= G_FLAG_EVENT_SIMULATE;
1149   return 0;
1150 }
1151 
1152 static const char arg_handle_env_system_set_doc_datafiles[] =
1153     "\n\t"
1154     "Set the " STRINGIFY_ARG(BLENDER_SYSTEM_DATAFILES) " environment variable.";
1155 static const char arg_handle_env_system_set_doc_scripts[] =
1156     "\n\t"
1157     "Set the " STRINGIFY_ARG(BLENDER_SYSTEM_SCRIPTS) " environment variable.";
1158 static const char arg_handle_env_system_set_doc_python[] =
1159     "\n\t"
1160     "Set the " STRINGIFY_ARG(BLENDER_SYSTEM_PYTHON) " environment variable.";
1161 
arg_handle_env_system_set(int argc,const char ** argv,void * UNUSED (data))1162 static int arg_handle_env_system_set(int argc, const char **argv, void *UNUSED(data))
1163 {
1164   /* "--env-system-scripts" --> "BLENDER_SYSTEM_SCRIPTS" */
1165 
1166   char env[64] = "BLENDER";
1167   char *ch_dst = env + 7;           /* skip BLENDER */
1168   const char *ch_src = argv[0] + 5; /* skip --env */
1169 
1170   if (argc < 2) {
1171     printf("%s requires one argument\n", argv[0]);
1172     exit(1);
1173   }
1174 
1175   for (; *ch_src; ch_src++, ch_dst++) {
1176     *ch_dst = (*ch_src == '-') ? '_' : (*ch_src) - 32; /* toupper() */
1177   }
1178 
1179   *ch_dst = '\0';
1180   BLI_setenv(env, argv[1]);
1181   return 1;
1182 }
1183 
1184 static const char arg_handle_playback_mode_doc[] =
1185     "<options> <file(s)>\n"
1186     "\tInstead of showing Blender's user interface, this runs Blender as an animation player,\n"
1187     "\tto view movies and image sequences rendered in Blender (ignored if '-b' is set).\n"
1188     "\n"
1189     "\tPlayback Arguments:\n"
1190     "\n"
1191     "\t-p <sx> <sy>\n"
1192     "\t\tOpen with lower left corner at <sx>, <sy>.\n"
1193     "\t-m\n"
1194     "\t\tRead from disk (Do not buffer).\n"
1195     "\t-f <fps> <fps-base>\n"
1196     "\t\tSpecify FPS to start with.\n"
1197     "\t-j <frame>\n"
1198     "\t\tSet frame step to <frame>.\n"
1199     "\t-s <frame>\n"
1200     "\t\tPlay from <frame>.\n"
1201     "\t-e <frame>\n"
1202     "\t\tPlay until <frame>.";
arg_handle_playback_mode(int argc,const char ** argv,void * UNUSED (data))1203 static int arg_handle_playback_mode(int argc, const char **argv, void *UNUSED(data))
1204 {
1205   /* not if -b was given first */
1206   if (G.background == 0) {
1207     BKE_appdir_init();
1208     IMB_init();
1209 #  ifdef WITH_FFMPEG
1210     /* Setup FFmpeg with current debug flags. */
1211     IMB_ffmpeg_init();
1212 #  endif
1213 
1214     WM_main_playanim(argc, argv); /* not the same argc and argv as before */
1215     exit(0);                      /* 2.4x didn't do this */
1216   }
1217 
1218   return -2;
1219 }
1220 
1221 static const char arg_handle_window_geometry_doc[] =
1222     "<sx> <sy> <w> <h>\n"
1223     "\tOpen with lower left corner at <sx>, <sy> and width and height as <w>, <h>.";
arg_handle_window_geometry(int argc,const char ** argv,void * UNUSED (data))1224 static int arg_handle_window_geometry(int argc, const char **argv, void *UNUSED(data))
1225 {
1226   const char *arg_id = "-p / --window-geometry";
1227   int params[4], i;
1228 
1229   if (argc < 5) {
1230     fprintf(stderr, "Error: requires four arguments '%s'\n", arg_id);
1231     exit(1);
1232   }
1233 
1234   for (i = 0; i < 4; i++) {
1235     const char *err_msg = NULL;
1236     if (!parse_int(argv[i + 1], NULL, &params[i], &err_msg)) {
1237       printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1238       exit(1);
1239     }
1240   }
1241 
1242   WM_init_state_size_set(UNPACK4(params));
1243 
1244   return 4;
1245 }
1246 
1247 static const char arg_handle_native_pixels_set_doc[] =
1248     "\n\t"
1249     "Do not use native pixel size, for high resolution displays (MacBook 'Retina').";
arg_handle_native_pixels_set(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1250 static int arg_handle_native_pixels_set(int UNUSED(argc),
1251                                         const char **UNUSED(argv),
1252                                         void *UNUSED(data))
1253 {
1254   WM_init_native_pixels(false);
1255   return 0;
1256 }
1257 
1258 static const char arg_handle_with_borders_doc[] =
1259     "\n\t"
1260     "Force opening with borders.";
arg_handle_with_borders(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1261 static int arg_handle_with_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
1262 {
1263   WM_init_state_normal_set();
1264   return 0;
1265 }
1266 
1267 static const char arg_handle_without_borders_doc[] =
1268     "\n\t"
1269     "Force opening in fullscreen mode.";
arg_handle_without_borders(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1270 static int arg_handle_without_borders(int UNUSED(argc),
1271                                       const char **UNUSED(argv),
1272                                       void *UNUSED(data))
1273 {
1274   WM_init_state_fullscreen_set();
1275   return 0;
1276 }
1277 
1278 static const char arg_handle_window_maximized_doc[] =
1279     "\n\t"
1280     "Force opening maximized.";
arg_handle_window_maximized(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1281 static int arg_handle_window_maximized(int UNUSED(argc),
1282                                        const char **UNUSED(argv),
1283                                        void *UNUSED(data))
1284 {
1285   WM_init_state_maximized_set();
1286   return 0;
1287 }
1288 
1289 static const char arg_handle_no_window_focus_doc[] =
1290     "\n\t"
1291     "Open behind other windows and without taking focus.";
arg_handle_no_window_focus(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1292 static int arg_handle_no_window_focus(int UNUSED(argc),
1293                                       const char **UNUSED(argv),
1294                                       void *UNUSED(data))
1295 {
1296   WM_init_window_focus_set(false);
1297   return 0;
1298 }
1299 
1300 static const char arg_handle_start_with_console_doc[] =
1301     "\n\t"
1302     "Start with the console window open (ignored if '-b' is set), (Windows only).";
arg_handle_start_with_console(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1303 static int arg_handle_start_with_console(int UNUSED(argc),
1304                                          const char **UNUSED(argv),
1305                                          void *UNUSED(data))
1306 {
1307   WM_init_state_start_with_console_set(true);
1308   return 0;
1309 }
1310 
1311 static const char arg_handle_register_extension_doc[] =
1312     "\n\t"
1313     "Register blend-file extension, then exit (Windows only).";
1314 static const char arg_handle_register_extension_doc_silent[] =
1315     "\n\t"
1316     "Silently register blend-file extension, then exit (Windows only).";
arg_handle_register_extension(int UNUSED (argc),const char ** UNUSED (argv),void * data)1317 static int arg_handle_register_extension(int UNUSED(argc), const char **UNUSED(argv), void *data)
1318 {
1319 #  ifdef WIN32
1320   if (data) {
1321     G.background = 1;
1322   }
1323   BLI_windows_register_blend_extension(G.background);
1324 #  else
1325   (void)data; /* unused */
1326 #  endif
1327   return 0;
1328 }
1329 
1330 static const char arg_handle_audio_disable_doc[] =
1331     "\n\t"
1332     "Force sound system to None.";
arg_handle_audio_disable(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1333 static int arg_handle_audio_disable(int UNUSED(argc),
1334                                     const char **UNUSED(argv),
1335                                     void *UNUSED(data))
1336 {
1337   BKE_sound_force_device("Null");
1338   return 0;
1339 }
1340 
1341 static const char arg_handle_audio_set_doc[] =
1342     "\n\t"
1343     "Force sound system to a specific device."
1344     "\n\t"
1345     "'NULL' 'SDL' 'OPENAL' 'JACK'.";
arg_handle_audio_set(int argc,const char ** argv,void * UNUSED (data))1346 static int arg_handle_audio_set(int argc, const char **argv, void *UNUSED(data))
1347 {
1348   if (argc < 1) {
1349     fprintf(stderr, "-setaudio require one argument\n");
1350     exit(1);
1351   }
1352 
1353   BKE_sound_force_device(argv[1]);
1354   return 1;
1355 }
1356 
1357 static const char arg_handle_output_set_doc[] =
1358     "<path>\n"
1359     "\tSet the render path and file name.\n"
1360     "\tUse '//' at the start of the path to render relative to the blend-file.\n"
1361     "\n"
1362     "\tThe '#' characters are replaced by the frame number, and used to define zero padding.\n"
1363     "\n"
1364     "\t* 'animation_##_test.png' becomes 'animation_01_test.png'\n"
1365     "\t* 'test-######.png' becomes 'test-000001.png'\n"
1366     "\n"
1367     "\tWhen the filename does not contain '#', The suffix '####' is added to the filename.\n"
1368     "\n"
1369     "\tThe frame number will be added at the end of the filename, eg:\n"
1370     "\t# blender -b animation.blend -o //render_ -F PNG -x 1 -a\n"
1371     "\t'//render_' becomes '//render_####', writing frames as '//render_0001.png'";
arg_handle_output_set(int argc,const char ** argv,void * data)1372 static int arg_handle_output_set(int argc, const char **argv, void *data)
1373 {
1374   bContext *C = data;
1375   if (argc > 1) {
1376     Scene *scene = CTX_data_scene(C);
1377     if (scene) {
1378       BLI_strncpy(scene->r.pic, argv[1], sizeof(scene->r.pic));
1379       DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
1380     }
1381     else {
1382       printf("\nError: no blend loaded. cannot use '-o / --render-output'.\n");
1383     }
1384     return 1;
1385   }
1386   else {
1387     printf("\nError: you must specify a path after '-o  / --render-output'.\n");
1388     return 0;
1389   }
1390 }
1391 
1392 static const char arg_handle_engine_set_doc[] =
1393     "<engine>\n"
1394     "\tSpecify the render engine.\n"
1395     "\tUse '-E help' to list available engines.";
arg_handle_engine_set(int argc,const char ** argv,void * data)1396 static int arg_handle_engine_set(int argc, const char **argv, void *data)
1397 {
1398   bContext *C = data;
1399   if (argc >= 2) {
1400     if (STREQ(argv[1], "help")) {
1401       RenderEngineType *type = NULL;
1402       printf("Blender Engine Listing:\n");
1403       for (type = R_engines.first; type; type = type->next) {
1404         printf("\t%s\n", type->idname);
1405       }
1406       exit(0);
1407     }
1408     else {
1409       Scene *scene = CTX_data_scene(C);
1410       if (scene) {
1411         if (BLI_findstring(&R_engines, argv[1], offsetof(RenderEngineType, idname))) {
1412           BLI_strncpy_utf8(scene->r.engine, argv[1], sizeof(scene->r.engine));
1413           DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
1414         }
1415         else {
1416           printf("\nError: engine not found '%s'\n", argv[1]);
1417           exit(1);
1418         }
1419       }
1420       else {
1421         printf(
1422             "\nError: no blend loaded. "
1423             "order the arguments so '-E / --engine' is after a blend is loaded.\n");
1424       }
1425     }
1426 
1427     return 1;
1428   }
1429   else {
1430     printf("\nEngine not specified, give 'help' for a list of available engines.\n");
1431     return 0;
1432   }
1433 }
1434 
1435 static const char arg_handle_image_type_set_doc[] =
1436     "<format>\n"
1437     "\tSet the render format.\n"
1438     "\tValid options are:\n"
1439     "\t'TGA' 'RAWTGA' 'JPEG' 'IRIS' 'IRIZ' 'AVIRAW' 'AVIJPEG' 'PNG' 'BMP'\n"
1440     "\n"
1441     "\tFormats that can be compiled into Blender, not available on all systems:\n"
1442     "\t'HDR' 'TIFF' 'OPEN_EXR' 'OPEN_EXR_MULTILAYER' 'MPEG' 'CINEON' 'DPX' 'DDS' 'JP2'";
arg_handle_image_type_set(int argc,const char ** argv,void * data)1443 static int arg_handle_image_type_set(int argc, const char **argv, void *data)
1444 {
1445   bContext *C = data;
1446   if (argc > 1) {
1447     const char *imtype = argv[1];
1448     Scene *scene = CTX_data_scene(C);
1449     if (scene) {
1450       const char imtype_new = BKE_imtype_from_arg(imtype);
1451 
1452       if (imtype_new == R_IMF_IMTYPE_INVALID) {
1453         printf(
1454             "\nError: Format from '-F / --render-format' not known or not compiled in this "
1455             "release.\n");
1456       }
1457       else {
1458         scene->r.im_format.imtype = imtype_new;
1459         DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
1460       }
1461     }
1462     else {
1463       printf(
1464           "\nError: no blend loaded. "
1465           "order the arguments so '-F  / --render-format' is after the blend is loaded.\n");
1466     }
1467     return 1;
1468   }
1469   else {
1470     printf("\nError: you must specify a format after '-F  / --render-format'.\n");
1471     return 0;
1472   }
1473 }
1474 
1475 static const char arg_handle_threads_set_doc[] =
1476     "<threads>\n"
1477     "\tUse amount of <threads> for rendering and other operations\n"
1478     "\t[1-" STRINGIFY(BLENDER_MAX_THREADS) "], 0 for systems processor count.";
arg_handle_threads_set(int argc,const char ** argv,void * UNUSED (data))1479 static int arg_handle_threads_set(int argc, const char **argv, void *UNUSED(data))
1480 {
1481   const char *arg_id = "-t / --threads";
1482   const int min = 0, max = BLENDER_MAX_THREADS;
1483   if (argc > 1) {
1484     const char *err_msg = NULL;
1485     int threads;
1486     if (!parse_int_strict_range(argv[1], NULL, min, max, &threads, &err_msg)) {
1487       printf("\nError: %s '%s %s', expected number in [%d..%d].\n",
1488              err_msg,
1489              arg_id,
1490              argv[1],
1491              min,
1492              max);
1493       return 1;
1494     }
1495 
1496     BLI_system_num_threads_override_set(threads);
1497     return 1;
1498   }
1499   else {
1500     printf("\nError: you must specify a number of threads in [%d..%d] '%s'.\n", min, max, arg_id);
1501     return 0;
1502   }
1503 }
1504 
1505 static const char arg_handle_verbosity_set_doc[] =
1506     "<verbose>\n"
1507     "\tSet the logging verbosity level for debug messages that support it.";
arg_handle_verbosity_set(int argc,const char ** argv,void * UNUSED (data))1508 static int arg_handle_verbosity_set(int argc, const char **argv, void *UNUSED(data))
1509 {
1510   const char *arg_id = "--verbose";
1511   if (argc > 1) {
1512     const char *err_msg = NULL;
1513     int level;
1514     if (!parse_int(argv[1], NULL, &level, &err_msg)) {
1515       printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1516     }
1517 
1518 #  ifdef WITH_LIBMV
1519     libmv_setLoggingVerbosity(level);
1520 #  elif defined(WITH_CYCLES_LOGGING)
1521     CCL_logging_verbosity_set(level);
1522 #  else
1523     (void)level;
1524 #  endif
1525 
1526     return 1;
1527   }
1528   else {
1529     printf("\nError: you must specify a verbosity level.\n");
1530     return 0;
1531   }
1532 }
1533 
1534 static const char arg_handle_extension_set_doc[] =
1535     "<bool>\n"
1536     "\tSet option to add the file extension to the end of the file.";
arg_handle_extension_set(int argc,const char ** argv,void * data)1537 static int arg_handle_extension_set(int argc, const char **argv, void *data)
1538 {
1539   bContext *C = data;
1540   if (argc > 1) {
1541     Scene *scene = CTX_data_scene(C);
1542     if (scene) {
1543       if (argv[1][0] == '0') {
1544         scene->r.scemode &= ~R_EXTENSION;
1545         DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
1546       }
1547       else if (argv[1][0] == '1') {
1548         scene->r.scemode |= R_EXTENSION;
1549         DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
1550       }
1551       else {
1552         printf("\nError: Use '-x 1 / -x 0' To set the extension option or '--use-extension'\n");
1553       }
1554     }
1555     else {
1556       printf(
1557           "\nError: no blend loaded. "
1558           "order the arguments so '-o ' is after '-x '.\n");
1559     }
1560     return 1;
1561   }
1562   else {
1563     printf("\nError: you must specify a path after '- '.\n");
1564     return 0;
1565   }
1566 }
1567 
1568 static const char arg_handle_render_frame_doc[] =
1569     "<frame>\n"
1570     "\tRender frame <frame> and save it.\n"
1571     "\n"
1572     "\t* +<frame> start frame relative, -<frame> end frame relative.\n"
1573     "\t* A comma separated list of frames can also be used (no spaces).\n"
1574     "\t* A range of frames can be expressed using '..' separator between the first and last "
1575     "frames (inclusive).\n";
arg_handle_render_frame(int argc,const char ** argv,void * data)1576 static int arg_handle_render_frame(int argc, const char **argv, void *data)
1577 {
1578   const char *arg_id = "-f / --render-frame";
1579   bContext *C = data;
1580   Scene *scene = CTX_data_scene(C);
1581   if (scene) {
1582     Main *bmain = CTX_data_main(C);
1583 
1584     if (argc > 1) {
1585       const char *err_msg = NULL;
1586       Render *re;
1587       ReportList reports;
1588 
1589       int(*frame_range_arr)[2], frames_range_len;
1590       if ((frame_range_arr = parse_int_range_relative_clamp_n(argv[1],
1591                                                               scene->r.sfra,
1592                                                               scene->r.efra,
1593                                                               MINAFRAME,
1594                                                               MAXFRAME,
1595                                                               &frames_range_len,
1596                                                               &err_msg)) == NULL) {
1597         printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1598         return 1;
1599       }
1600 
1601       re = RE_NewSceneRender(scene);
1602       BKE_reports_init(&reports, RPT_STORE);
1603       RE_SetReports(re, &reports);
1604       for (int i = 0; i < frames_range_len; i++) {
1605         /* We could pass in frame ranges,
1606          * but prefer having exact behavior as passing in multiple frames */
1607         if ((frame_range_arr[i][0] <= frame_range_arr[i][1]) == 0) {
1608           printf("\nWarning: negative range ignored '%s %s'.\n", arg_id, argv[1]);
1609         }
1610 
1611         for (int frame = frame_range_arr[i][0]; frame <= frame_range_arr[i][1]; frame++) {
1612           RE_RenderAnim(re, bmain, scene, NULL, NULL, frame, frame, scene->r.frame_step);
1613         }
1614       }
1615       RE_SetReports(re, NULL);
1616       BKE_reports_clear(&reports);
1617       MEM_freeN(frame_range_arr);
1618       return 1;
1619     }
1620     else {
1621       printf("\nError: frame number must follow '%s'.\n", arg_id);
1622       return 0;
1623     }
1624   }
1625   else {
1626     printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1627     return 0;
1628   }
1629 }
1630 
1631 static const char arg_handle_render_animation_doc[] =
1632     "\n\t"
1633     "Render frames from start to end (inclusive).";
arg_handle_render_animation(int UNUSED (argc),const char ** UNUSED (argv),void * data)1634 static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(argv), void *data)
1635 {
1636   bContext *C = data;
1637   Scene *scene = CTX_data_scene(C);
1638   if (scene) {
1639     Main *bmain = CTX_data_main(C);
1640     Render *re = RE_NewSceneRender(scene);
1641     ReportList reports;
1642     BKE_reports_init(&reports, RPT_STORE);
1643     RE_SetReports(re, &reports);
1644     RE_RenderAnim(re, bmain, scene, NULL, NULL, scene->r.sfra, scene->r.efra, scene->r.frame_step);
1645     RE_SetReports(re, NULL);
1646     BKE_reports_clear(&reports);
1647   }
1648   else {
1649     printf("\nError: no blend loaded. cannot use '-a'.\n");
1650   }
1651   return 0;
1652 }
1653 
1654 static const char arg_handle_scene_set_doc[] =
1655     "<name>\n"
1656     "\tSet the active scene <name> for rendering.";
arg_handle_scene_set(int argc,const char ** argv,void * data)1657 static int arg_handle_scene_set(int argc, const char **argv, void *data)
1658 {
1659   if (argc > 1) {
1660     bContext *C = data;
1661     Scene *scene = BKE_scene_set_name(CTX_data_main(C), argv[1]);
1662     if (scene) {
1663       CTX_data_scene_set(C, scene);
1664 
1665       /* Set the scene of the first window, see: T55991,
1666        * otherwise scrips that run later won't get this scene back from the context. */
1667       wmWindow *win = CTX_wm_window(C);
1668       if (win == NULL) {
1669         win = CTX_wm_manager(C)->windows.first;
1670       }
1671       if (win != NULL) {
1672         WM_window_set_active_scene(CTX_data_main(C), C, win, scene);
1673       }
1674     }
1675     return 1;
1676   }
1677   else {
1678     printf("\nError: Scene name must follow '-S / --scene'.\n");
1679     return 0;
1680   }
1681 }
1682 
1683 static const char arg_handle_frame_start_set_doc[] =
1684     "<frame>\n"
1685     "\tSet start to frame <frame>, supports +/- for relative frames too.";
arg_handle_frame_start_set(int argc,const char ** argv,void * data)1686 static int arg_handle_frame_start_set(int argc, const char **argv, void *data)
1687 {
1688   const char *arg_id = "-s / --frame-start";
1689   bContext *C = data;
1690   Scene *scene = CTX_data_scene(C);
1691   if (scene) {
1692     if (argc > 1) {
1693       const char *err_msg = NULL;
1694       if (!parse_int_relative_clamp(argv[1],
1695                                     NULL,
1696                                     scene->r.sfra,
1697                                     scene->r.sfra - 1,
1698                                     MINAFRAME,
1699                                     MAXFRAME,
1700                                     &scene->r.sfra,
1701                                     &err_msg)) {
1702         printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1703       }
1704       else {
1705         DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
1706       }
1707       return 1;
1708     }
1709     else {
1710       printf("\nError: frame number must follow '%s'.\n", arg_id);
1711       return 0;
1712     }
1713   }
1714   else {
1715     printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1716     return 0;
1717   }
1718 }
1719 
1720 static const char arg_handle_frame_end_set_doc[] =
1721     "<frame>\n"
1722     "\tSet end to frame <frame>, supports +/- for relative frames too.";
arg_handle_frame_end_set(int argc,const char ** argv,void * data)1723 static int arg_handle_frame_end_set(int argc, const char **argv, void *data)
1724 {
1725   const char *arg_id = "-e / --frame-end";
1726   bContext *C = data;
1727   Scene *scene = CTX_data_scene(C);
1728   if (scene) {
1729     if (argc > 1) {
1730       const char *err_msg = NULL;
1731       if (!parse_int_relative_clamp(argv[1],
1732                                     NULL,
1733                                     scene->r.efra,
1734                                     scene->r.efra - 1,
1735                                     MINAFRAME,
1736                                     MAXFRAME,
1737                                     &scene->r.efra,
1738                                     &err_msg)) {
1739         printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1740       }
1741       else {
1742         DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
1743       }
1744       return 1;
1745     }
1746     else {
1747       printf("\nError: frame number must follow '%s'.\n", arg_id);
1748       return 0;
1749     }
1750   }
1751   else {
1752     printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1753     return 0;
1754   }
1755 }
1756 
1757 static const char arg_handle_frame_skip_set_doc[] =
1758     "<frames>\n"
1759     "\tSet number of frames to step forward after each rendered frame.";
arg_handle_frame_skip_set(int argc,const char ** argv,void * data)1760 static int arg_handle_frame_skip_set(int argc, const char **argv, void *data)
1761 {
1762   const char *arg_id = "-j / --frame-jump";
1763   bContext *C = data;
1764   Scene *scene = CTX_data_scene(C);
1765   if (scene) {
1766     if (argc > 1) {
1767       const char *err_msg = NULL;
1768       if (!parse_int_clamp(argv[1], NULL, 1, MAXFRAME, &scene->r.frame_step, &err_msg)) {
1769         printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
1770       }
1771       else {
1772         DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
1773       }
1774       return 1;
1775     }
1776     else {
1777       printf("\nError: number of frames to step must follow '%s'.\n", arg_id);
1778       return 0;
1779     }
1780   }
1781   else {
1782     printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
1783     return 0;
1784   }
1785 }
1786 
1787 static const char arg_handle_python_file_run_doc[] =
1788     "<filename>\n"
1789     "\tRun the given Python script file.";
arg_handle_python_file_run(int argc,const char ** argv,void * data)1790 static int arg_handle_python_file_run(int argc, const char **argv, void *data)
1791 {
1792 #  ifdef WITH_PYTHON
1793   bContext *C = data;
1794 
1795   /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1796   if (argc > 1) {
1797     /* Make the path absolute because its needed for relative linked blends to be found */
1798     char filename[FILE_MAX];
1799     BLI_strncpy(filename, argv[1], sizeof(filename));
1800     BLI_path_abs_from_cwd(filename, sizeof(filename));
1801 
1802     bool ok;
1803     BPY_CTX_SETUP(ok = BPY_run_filepath(C, filename, NULL));
1804     if (!ok && app_state.exit_code_on_error.python) {
1805       printf("\nError: script failed, file: '%s', exiting.\n", argv[1]);
1806       BPY_python_end();
1807       exit(app_state.exit_code_on_error.python);
1808     }
1809     return 1;
1810   }
1811   else {
1812     printf("\nError: you must specify a filepath after '%s'.\n", argv[0]);
1813     return 0;
1814   }
1815 #  else
1816   UNUSED_VARS(argc, argv, data);
1817   printf("This Blender was built without Python support\n");
1818   return 0;
1819 #  endif /* WITH_PYTHON */
1820 }
1821 
1822 static const char arg_handle_python_text_run_doc[] =
1823     "<name>\n"
1824     "\tRun the given Python script text block.";
arg_handle_python_text_run(int argc,const char ** argv,void * data)1825 static int arg_handle_python_text_run(int argc, const char **argv, void *data)
1826 {
1827 #  ifdef WITH_PYTHON
1828   bContext *C = data;
1829 
1830   /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1831   if (argc > 1) {
1832     Main *bmain = CTX_data_main(C);
1833     /* Make the path absolute because its needed for relative linked blends to be found */
1834     struct Text *text = (struct Text *)BKE_libblock_find_name(bmain, ID_TXT, argv[1]);
1835     bool ok;
1836 
1837     if (text) {
1838       BPY_CTX_SETUP(ok = BPY_run_text(C, text, NULL, false));
1839     }
1840     else {
1841       printf("\nError: text block not found %s.\n", argv[1]);
1842       ok = false;
1843     }
1844 
1845     if (!ok && app_state.exit_code_on_error.python) {
1846       printf("\nError: script failed, text: '%s', exiting.\n", argv[1]);
1847       BPY_python_end();
1848       exit(app_state.exit_code_on_error.python);
1849     }
1850 
1851     return 1;
1852   }
1853   else {
1854     printf("\nError: you must specify a text block after '%s'.\n", argv[0]);
1855     return 0;
1856   }
1857 #  else
1858   UNUSED_VARS(argc, argv, data);
1859   printf("This Blender was built without Python support\n");
1860   return 0;
1861 #  endif /* WITH_PYTHON */
1862 }
1863 
1864 static const char arg_handle_python_expr_run_doc[] =
1865     "<expression>\n"
1866     "\tRun the given expression as a Python script.";
arg_handle_python_expr_run(int argc,const char ** argv,void * data)1867 static int arg_handle_python_expr_run(int argc, const char **argv, void *data)
1868 {
1869 #  ifdef WITH_PYTHON
1870   bContext *C = data;
1871 
1872   /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1873   if (argc > 1) {
1874     bool ok;
1875     BPY_CTX_SETUP(ok = BPY_run_string_exec(C, NULL, argv[1]));
1876     if (!ok && app_state.exit_code_on_error.python) {
1877       printf("\nError: script failed, expr: '%s', exiting.\n", argv[1]);
1878       BPY_python_end();
1879       exit(app_state.exit_code_on_error.python);
1880     }
1881     return 1;
1882   }
1883   else {
1884     printf("\nError: you must specify a Python expression after '%s'.\n", argv[0]);
1885     return 0;
1886   }
1887 #  else
1888   UNUSED_VARS(argc, argv, data);
1889   printf("This Blender was built without Python support\n");
1890   return 0;
1891 #  endif /* WITH_PYTHON */
1892 }
1893 
1894 static const char arg_handle_python_console_run_doc[] =
1895     "\n\t"
1896     "Run Blender with an interactive console.";
arg_handle_python_console_run(int UNUSED (argc),const char ** argv,void * data)1897 static int arg_handle_python_console_run(int UNUSED(argc), const char **argv, void *data)
1898 {
1899 #  ifdef WITH_PYTHON
1900   bContext *C = data;
1901 
1902   BPY_CTX_SETUP(BPY_run_string_eval(C, (const char *[]){"code", NULL}, "code.interact()"));
1903 
1904   return 0;
1905 #  else
1906   UNUSED_VARS(argv, data);
1907   printf("This Blender was built without python support\n");
1908   return 0;
1909 #  endif /* WITH_PYTHON */
1910 }
1911 
1912 static const char arg_handle_python_exit_code_set_doc[] =
1913     "<code>\n"
1914     "\tSet the exit-code in [0..255] to exit if a Python exception is raised\n"
1915     "\t(only for scripts executed from the command line), zero disables.";
arg_handle_python_exit_code_set(int argc,const char ** argv,void * UNUSED (data))1916 static int arg_handle_python_exit_code_set(int argc, const char **argv, void *UNUSED(data))
1917 {
1918   const char *arg_id = "--python-exit-code";
1919   if (argc > 1) {
1920     const char *err_msg = NULL;
1921     const int min = 0, max = 255;
1922     int exit_code;
1923     if (!parse_int_strict_range(argv[1], NULL, min, max, &exit_code, &err_msg)) {
1924       printf("\nError: %s '%s %s', expected number in [%d..%d].\n",
1925              err_msg,
1926              arg_id,
1927              argv[1],
1928              min,
1929              max);
1930       return 1;
1931     }
1932 
1933     app_state.exit_code_on_error.python = (unsigned char)exit_code;
1934     return 1;
1935   }
1936   else {
1937     printf("\nError: you must specify an exit code number '%s'.\n", arg_id);
1938     return 0;
1939   }
1940 }
1941 
1942 static const char arg_handle_python_use_system_env_set_doc[] =
1943     "\n\t"
1944     "Allow Python to use system environment variables such as 'PYTHONPATH' and the user "
1945     "site-packages directory.";
arg_handle_python_use_system_env_set(int UNUSED (argc),const char ** UNUSED (argv),void * UNUSED (data))1946 static int arg_handle_python_use_system_env_set(int UNUSED(argc),
1947                                                 const char **UNUSED(argv),
1948                                                 void *UNUSED(data))
1949 {
1950 #  ifdef WITH_PYTHON
1951   BPY_python_use_system_env();
1952 #  endif
1953   return 0;
1954 }
1955 
1956 static const char arg_handle_addons_set_doc[] =
1957     "<addon(s)>\n"
1958     "\tComma separated list of add-ons (no spaces).";
arg_handle_addons_set(int argc,const char ** argv,void * data)1959 static int arg_handle_addons_set(int argc, const char **argv, void *data)
1960 {
1961   /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
1962   if (argc > 1) {
1963 #  ifdef WITH_PYTHON
1964     const char script_str[] =
1965         "from addon_utils import check, enable\n"
1966         "for m in '%s'.split(','):\n"
1967         "    if check(m)[1] is False:\n"
1968         "        enable(m, persistent=True)";
1969     const int slen = strlen(argv[1]) + (sizeof(script_str) - 2);
1970     char *str = malloc(slen);
1971     bContext *C = data;
1972     BLI_snprintf(str, slen, script_str, argv[1]);
1973 
1974     BLI_assert(strlen(str) + 1 == slen);
1975     BPY_CTX_SETUP(BPY_run_string_exec(C, NULL, str));
1976     free(str);
1977 #  else
1978     UNUSED_VARS(argv, data);
1979 #  endif /* WITH_PYTHON */
1980     return 1;
1981   }
1982   else {
1983     printf("\nError: you must specify a comma separated list after '--addons'.\n");
1984     return 0;
1985   }
1986 }
1987 
arg_handle_load_file(int UNUSED (argc),const char ** argv,void * data)1988 static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data)
1989 {
1990   bContext *C = data;
1991   ReportList reports;
1992   bool success;
1993 
1994   /* Make the path absolute because its needed for relative linked blends to be found */
1995   char filename[FILE_MAX];
1996 
1997   /* note, we could skip these, but so far we always tried to load these files */
1998   if (argv[0][0] == '-') {
1999     fprintf(stderr, "unknown argument, loading as file: %s\n", argv[0]);
2000   }
2001 
2002   BLI_strncpy(filename, argv[0], sizeof(filename));
2003   BLI_path_abs_from_cwd(filename, sizeof(filename));
2004 
2005   /* load the file */
2006   BKE_reports_init(&reports, RPT_PRINT);
2007   WM_file_autoexec_init(filename);
2008   success = WM_file_read(C, filename, &reports);
2009   BKE_reports_clear(&reports);
2010 
2011   if (success) {
2012     if (G.background) {
2013       /* ensuer we use 'C->data.scene' for background render */
2014       CTX_wm_window_set(C, NULL);
2015     }
2016   }
2017   else {
2018     /* failed to load file, stop processing arguments if running in background mode */
2019     if (G.background) {
2020       /* Set is_break if running in the background mode so
2021        * blender will return non-zero exit code which then
2022        * could be used in automated script to control how
2023        * good or bad things are.
2024        */
2025       G.is_break = true;
2026       return -1;
2027     }
2028 
2029     if (BLO_has_bfile_extension(filename)) {
2030       /* Just pretend a file was loaded, so the user can press Save and it'll
2031        * save at the filename from the CLI. */
2032       BLI_strncpy(G_MAIN->name, filename, FILE_MAX);
2033       G.relbase_valid = true;
2034       G.save_over = true;
2035       printf("... opened default scene instead; saving will write to: %s\n", filename);
2036     }
2037     else {
2038       printf(
2039           "Error: argument has no '.blend' file extension, not using as new file, exiting! %s\n",
2040           filename);
2041       G.is_break = true;
2042       WM_exit(C);
2043     }
2044   }
2045 
2046   G.file_loaded = 1;
2047 
2048   return 0;
2049 }
2050 
main_args_setup(bContext * C,bArgs * ba)2051 void main_args_setup(bContext *C, bArgs *ba)
2052 {
2053 
2054 #  define CB(a) a##_doc, a
2055 #  define CB_EX(a, b) a##_doc_##b, a
2056 
2057   // BLI_argsAdd(ba, pass, short_arg, long_arg, doc, cb, C);
2058 
2059   /* end argument processing after -- */
2060   BLI_argsAdd(ba, -1, "--", NULL, CB(arg_handle_arguments_end), NULL);
2061 
2062   /* first pass: background mode, disable python and commands that exit after usage */
2063   BLI_argsAdd(ba, 1, "-h", "--help", CB(arg_handle_print_help), ba);
2064   /* Windows only */
2065   BLI_argsAdd(ba, 1, "/?", NULL, CB_EX(arg_handle_print_help, win32), ba);
2066 
2067   BLI_argsAdd(ba, 1, "-v", "--version", CB(arg_handle_print_version), NULL);
2068 
2069   BLI_argsAdd(
2070       ba, 1, "-y", "--enable-autoexec", CB_EX(arg_handle_python_set, enable), (void *)true);
2071   BLI_argsAdd(
2072       ba, 1, "-Y", "--disable-autoexec", CB_EX(arg_handle_python_set, disable), (void *)false);
2073 
2074   BLI_argsAdd(ba, 1, NULL, "--disable-crash-handler", CB(arg_handle_crash_handler_disable), NULL);
2075   BLI_argsAdd(ba, 1, NULL, "--disable-abort-handler", CB(arg_handle_abort_handler_disable), NULL);
2076 
2077   BLI_argsAdd(ba, 1, "-b", "--background", CB(arg_handle_background_mode_set), NULL);
2078 
2079   BLI_argsAdd(ba, 1, "-a", NULL, CB(arg_handle_playback_mode), NULL);
2080 
2081   BLI_argsAdd(ba, 1, NULL, "--log", CB(arg_handle_log_set), ba);
2082   BLI_argsAdd(ba, 1, NULL, "--log-level", CB(arg_handle_log_level_set), ba);
2083   BLI_argsAdd(ba, 1, NULL, "--log-show-basename", CB(arg_handle_log_show_basename_set), ba);
2084   BLI_argsAdd(ba, 1, NULL, "--log-show-backtrace", CB(arg_handle_log_show_backtrace_set), ba);
2085   BLI_argsAdd(ba, 1, NULL, "--log-show-timestamp", CB(arg_handle_log_show_timestamp_set), ba);
2086   BLI_argsAdd(ba, 1, NULL, "--log-file", CB(arg_handle_log_file_set), ba);
2087 
2088   BLI_argsAdd(ba, 1, "-d", "--debug", CB(arg_handle_debug_mode_set), ba);
2089 
2090 #  ifdef WITH_FFMPEG
2091   BLI_argsAdd(ba,
2092               1,
2093               NULL,
2094               "--debug-ffmpeg",
2095               CB_EX(arg_handle_debug_mode_generic_set, ffmpeg),
2096               (void *)G_DEBUG_FFMPEG);
2097 #  endif
2098 
2099 #  ifdef WITH_FREESTYLE
2100   BLI_argsAdd(ba,
2101               1,
2102               NULL,
2103               "--debug-freestyle",
2104               CB_EX(arg_handle_debug_mode_generic_set, freestyle),
2105               (void *)G_DEBUG_FREESTYLE);
2106 #  endif
2107 
2108   BLI_argsAdd(ba,
2109               1,
2110               NULL,
2111               "--debug-python",
2112               CB_EX(arg_handle_debug_mode_generic_set, python),
2113               (void *)G_DEBUG_PYTHON);
2114   BLI_argsAdd(ba,
2115               1,
2116               NULL,
2117               "--debug-events",
2118               CB_EX(arg_handle_debug_mode_generic_set, events),
2119               (void *)G_DEBUG_EVENTS);
2120   BLI_argsAdd(ba,
2121               1,
2122               NULL,
2123               "--debug-handlers",
2124               CB_EX(arg_handle_debug_mode_generic_set, handlers),
2125               (void *)G_DEBUG_HANDLERS);
2126   BLI_argsAdd(
2127       ba, 1, NULL, "--debug-wm", CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM);
2128 #  ifdef WITH_XR_OPENXR
2129   BLI_argsAdd(
2130       ba, 1, NULL, "--debug-xr", CB_EX(arg_handle_debug_mode_generic_set, xr), (void *)G_DEBUG_XR);
2131   BLI_argsAdd(ba,
2132               1,
2133               NULL,
2134               "--debug-xr-time",
2135               CB_EX(arg_handle_debug_mode_generic_set, xr_time),
2136               (void *)G_DEBUG_XR_TIME);
2137 #  endif
2138   BLI_argsAdd(ba,
2139               1,
2140               NULL,
2141               "--debug-ghost",
2142               CB_EX(arg_handle_debug_mode_generic_set, handlers),
2143               (void *)G_DEBUG_GHOST);
2144   BLI_argsAdd(ba, 1, NULL, "--debug-all", CB(arg_handle_debug_mode_all), NULL);
2145 
2146   BLI_argsAdd(ba, 1, NULL, "--debug-io", CB(arg_handle_debug_mode_io), NULL);
2147 
2148   BLI_argsAdd(ba, 1, NULL, "--debug-fpe", CB(arg_handle_debug_fpe_set), NULL);
2149 
2150 #  ifdef WITH_LIBMV
2151   BLI_argsAdd(ba, 1, NULL, "--debug-libmv", CB(arg_handle_debug_mode_libmv), NULL);
2152 #  endif
2153 #  ifdef WITH_CYCLES_LOGGING
2154   BLI_argsAdd(ba, 1, NULL, "--debug-cycles", CB(arg_handle_debug_mode_cycles), NULL);
2155 #  endif
2156   BLI_argsAdd(ba, 1, NULL, "--debug-memory", CB(arg_handle_debug_mode_memory_set), NULL);
2157 
2158   BLI_argsAdd(ba, 1, NULL, "--debug-value", CB(arg_handle_debug_value_set), NULL);
2159   BLI_argsAdd(ba,
2160               1,
2161               NULL,
2162               "--debug-jobs",
2163               CB_EX(arg_handle_debug_mode_generic_set, jobs),
2164               (void *)G_DEBUG_JOBS);
2165   BLI_argsAdd(ba,
2166               1,
2167               NULL,
2168               "--debug-gpu",
2169               CB_EX(arg_handle_debug_mode_generic_set, gpu),
2170               (void *)G_DEBUG_GPU);
2171   BLI_argsAdd(ba,
2172               1,
2173               NULL,
2174               "--debug-depsgraph",
2175               CB_EX(arg_handle_debug_mode_generic_set, depsgraph),
2176               (void *)G_DEBUG_DEPSGRAPH);
2177   BLI_argsAdd(ba,
2178               1,
2179               NULL,
2180               "--debug-depsgraph-build",
2181               CB_EX(arg_handle_debug_mode_generic_set, depsgraph_build),
2182               (void *)G_DEBUG_DEPSGRAPH_BUILD);
2183   BLI_argsAdd(ba,
2184               1,
2185               NULL,
2186               "--debug-depsgraph-eval",
2187               CB_EX(arg_handle_debug_mode_generic_set, depsgraph_eval),
2188               (void *)G_DEBUG_DEPSGRAPH_EVAL);
2189   BLI_argsAdd(ba,
2190               1,
2191               NULL,
2192               "--debug-depsgraph-tag",
2193               CB_EX(arg_handle_debug_mode_generic_set, depsgraph_tag),
2194               (void *)G_DEBUG_DEPSGRAPH_TAG);
2195   BLI_argsAdd(ba,
2196               1,
2197               NULL,
2198               "--debug-depsgraph-time",
2199               CB_EX(arg_handle_debug_mode_generic_set, depsgraph_time),
2200               (void *)G_DEBUG_DEPSGRAPH_TIME);
2201   BLI_argsAdd(ba,
2202               1,
2203               NULL,
2204               "--debug-depsgraph-no-threads",
2205               CB_EX(arg_handle_debug_mode_generic_set, depsgraph_no_threads),
2206               (void *)G_DEBUG_DEPSGRAPH_NO_THREADS);
2207   BLI_argsAdd(ba,
2208               1,
2209               NULL,
2210               "--debug-depsgraph-pretty",
2211               CB_EX(arg_handle_debug_mode_generic_set, depsgraph_pretty),
2212               (void *)G_DEBUG_DEPSGRAPH_PRETTY);
2213   BLI_argsAdd(ba,
2214               1,
2215               NULL,
2216               "--debug-depsgraph-uuid",
2217               CB_EX(arg_handle_debug_mode_generic_set, depsgraph_build),
2218               (void *)G_DEBUG_DEPSGRAPH_UUID);
2219   BLI_argsAdd(ba,
2220               1,
2221               NULL,
2222               "--debug-gpumem",
2223               CB_EX(arg_handle_debug_mode_generic_set, gpumem),
2224               (void *)G_DEBUG_GPU_MEM);
2225   BLI_argsAdd(ba,
2226               1,
2227               NULL,
2228               "--debug-gpu-shaders",
2229               CB_EX(arg_handle_debug_mode_generic_set, gpumem),
2230               (void *)G_DEBUG_GPU_SHADERS);
2231   BLI_argsAdd(ba,
2232               1,
2233               NULL,
2234               "--debug-gpu-force-workarounds",
2235               CB_EX(arg_handle_debug_mode_generic_set, gpumem),
2236               (void *)G_DEBUG_GPU_FORCE_WORKAROUNDS);
2237   BLI_argsAdd(ba, 1, NULL, "--debug-exit-on-error", CB(arg_handle_debug_exit_on_error), NULL);
2238 
2239   BLI_argsAdd(ba, 1, NULL, "--verbose", CB(arg_handle_verbosity_set), NULL);
2240 
2241   BLI_argsAdd(ba, 1, NULL, "--app-template", CB(arg_handle_app_template), NULL);
2242   BLI_argsAdd(ba, 1, NULL, "--factory-startup", CB(arg_handle_factory_startup_set), NULL);
2243   BLI_argsAdd(ba, 1, NULL, "--enable-event-simulate", CB(arg_handle_enable_event_simulate), NULL);
2244 
2245   /* TODO, add user env vars? */
2246   BLI_argsAdd(
2247       ba, 1, NULL, "--env-system-datafiles", CB_EX(arg_handle_env_system_set, datafiles), NULL);
2248   BLI_argsAdd(
2249       ba, 1, NULL, "--env-system-scripts", CB_EX(arg_handle_env_system_set, scripts), NULL);
2250   BLI_argsAdd(ba, 1, NULL, "--env-system-python", CB_EX(arg_handle_env_system_set, python), NULL);
2251 
2252   BLI_argsAdd(
2253       ba, 1, NULL, "--python-use-system-env", CB(arg_handle_python_use_system_env_set), NULL);
2254 
2255   /* second pass: custom window stuff */
2256   BLI_argsAdd(ba, 2, "-p", "--window-geometry", CB(arg_handle_window_geometry), NULL);
2257   BLI_argsAdd(ba, 2, "-w", "--window-border", CB(arg_handle_with_borders), NULL);
2258   BLI_argsAdd(ba, 2, "-W", "--window-fullscreen", CB(arg_handle_without_borders), NULL);
2259   BLI_argsAdd(ba, 2, "-M", "--window-maximized", CB(arg_handle_window_maximized), NULL);
2260   BLI_argsAdd(ba, 2, NULL, "--no-window-focus", CB(arg_handle_no_window_focus), NULL);
2261   BLI_argsAdd(ba, 2, "-con", "--start-console", CB(arg_handle_start_with_console), NULL);
2262   BLI_argsAdd(ba, 2, "-R", NULL, CB(arg_handle_register_extension), NULL);
2263   BLI_argsAdd(ba, 2, "-r", NULL, CB_EX(arg_handle_register_extension, silent), ba);
2264   BLI_argsAdd(ba, 2, NULL, "--no-native-pixels", CB(arg_handle_native_pixels_set), ba);
2265 
2266   /* third pass: disabling things and forcing settings */
2267   BLI_argsAddCase(ba, 3, "-noaudio", 1, NULL, 0, CB(arg_handle_audio_disable), NULL);
2268   BLI_argsAddCase(ba, 3, "-setaudio", 1, NULL, 0, CB(arg_handle_audio_set), NULL);
2269 
2270   /* fourth pass: processing arguments */
2271   BLI_argsAdd(ba, 4, "-f", "--render-frame", CB(arg_handle_render_frame), C);
2272   BLI_argsAdd(ba, 4, "-a", "--render-anim", CB(arg_handle_render_animation), C);
2273   BLI_argsAdd(ba, 4, "-S", "--scene", CB(arg_handle_scene_set), C);
2274   BLI_argsAdd(ba, 4, "-s", "--frame-start", CB(arg_handle_frame_start_set), C);
2275   BLI_argsAdd(ba, 4, "-e", "--frame-end", CB(arg_handle_frame_end_set), C);
2276   BLI_argsAdd(ba, 4, "-j", "--frame-jump", CB(arg_handle_frame_skip_set), C);
2277   BLI_argsAdd(ba, 4, "-P", "--python", CB(arg_handle_python_file_run), C);
2278   BLI_argsAdd(ba, 4, NULL, "--python-text", CB(arg_handle_python_text_run), C);
2279   BLI_argsAdd(ba, 4, NULL, "--python-expr", CB(arg_handle_python_expr_run), C);
2280   BLI_argsAdd(ba, 4, NULL, "--python-console", CB(arg_handle_python_console_run), C);
2281   BLI_argsAdd(ba, 4, NULL, "--python-exit-code", CB(arg_handle_python_exit_code_set), NULL);
2282   BLI_argsAdd(ba, 4, NULL, "--addons", CB(arg_handle_addons_set), C);
2283 
2284   BLI_argsAdd(ba, 4, "-o", "--render-output", CB(arg_handle_output_set), C);
2285   BLI_argsAdd(ba, 4, "-E", "--engine", CB(arg_handle_engine_set), C);
2286 
2287   BLI_argsAdd(ba, 4, "-F", "--render-format", CB(arg_handle_image_type_set), C);
2288   BLI_argsAdd(ba, 1, "-t", "--threads", CB(arg_handle_threads_set), NULL);
2289   BLI_argsAdd(ba, 4, "-x", "--use-extension", CB(arg_handle_extension_set), C);
2290 
2291 #  undef CB
2292 #  undef CB_EX
2293 }
2294 
2295 /**
2296  * Needs to be added separately.
2297  */
main_args_setup_post(bContext * C,bArgs * ba)2298 void main_args_setup_post(bContext *C, bArgs *ba)
2299 {
2300   BLI_argsParse(ba, 4, arg_handle_load_file, C);
2301 }
2302 
2303 /** \} */
2304 
2305 #endif /* WITH_PYTHON_MODULE */
2306