/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. */ /** \file \ingroup creator */ #include #include #ifdef WIN32 # if defined(_MSC_VER) && defined(_M_X64) # include /* needed for _set_FMA3_enable */ # endif # include # include "utfconv.h" #endif #include "MEM_guardedalloc.h" #include "CLG_log.h" #include "DNA_genfile.h" #include "BLI_args.h" #include "BLI_threads.h" #include "BLI_utildefines.h" #include "BLI_callbacks.h" #include "BLI_string.h" #include "BLI_system.h" /* mostly init functions */ #include "BKE_appdir.h" #include "BKE_blender.h" #include "BKE_brush.h" #include "BKE_cachefile.h" #include "BKE_context.h" #include "BKE_font.h" #include "BKE_global.h" #include "BKE_material.h" #include "BKE_modifier.h" #include "BKE_gpencil_modifier.h" #include "BKE_node.h" #include "BKE_shader_fx.h" #include "BKE_sound.h" #include "BKE_image.h" #include "BKE_particle.h" #include "DEG_depsgraph.h" #include "IMB_imbuf.h" /* for IMB_init */ #include "RE_engine.h" #include "RE_render_ext.h" #include "ED_datafiles.h" #include "WM_api.h" #include "WM_toolsystem.h" #include "RNA_define.h" #ifdef WITH_FREESTYLE # include "FRS_freestyle.h" #endif #include #ifdef __FreeBSD__ # include #endif #ifdef WITH_BINRELOC # include "binreloc.h" #endif #ifdef WITH_LIBMV # include "libmv-capi.h" #endif #ifdef WITH_CYCLES_LOGGING # include "CCL_api.h" #endif #ifdef WITH_SDL_DYNLOAD # include "sdlew.h" #endif #include "creator_intern.h" /* own include */ /* Local Function prototypes */ #ifdef WITH_PYTHON_MODULE int main_python_enter(int argc, const char **argv); void main_python_exit(void); #endif /* written to by 'creator_args.c' */ struct ApplicationState app_state = { .signal = { .use_crash_handler = true, .use_abort_handler = true, }, .exit_code_on_error = { .python = 0, }, }; /* -------------------------------------------------------------------- */ /** \name Application Level Callbacks * * Initialize callbacks for the modules that need them. * * \{ */ static void callback_mem_error(const char *errorStr) { fputs(errorStr, stderr); fflush(stderr); } static void main_callback_setup(void) { /* Error output from the alloc routines: */ MEM_set_error_callback(callback_mem_error); } /* free data on early exit (if Python calls 'sys.exit()' while parsing args for eg). */ struct CreatorAtExitData { bArgs *ba; #ifdef WIN32 const char **argv; int argv_num; #endif }; static void callback_main_atexit(void *user_data) { struct CreatorAtExitData *app_init_data = user_data; if (app_init_data->ba) { BLI_argsFree(app_init_data->ba); app_init_data->ba = NULL; } #ifdef WIN32 if (app_init_data->argv) { while (app_init_data->argv_num) { free((void *)app_init_data->argv[--app_init_data->argv_num]); } free((void *)app_init_data->argv); app_init_data->argv = NULL; } #endif } static void callback_clg_fatal(void *fp) { BLI_system_backtrace(fp); } /** \} */ /* -------------------------------------------------------------------- */ /** \name Main Function * \{ */ #ifdef WITH_PYTHON_MODULE /* allow python module to call main */ # define main main_python_enter static void *evil_C = NULL; # ifdef __APPLE__ /* environ is not available in mac shared libraries */ # include char **environ = NULL; # endif #endif /** * Blender's main function responsibilities are: * - setup subsystems. * - handle arguments. * - run #WM_main() event loop, * or exit immediately when running in background mode. */ int main( int argc, #ifdef WIN32 const char **UNUSED(argv_c) #else const char **argv #endif ) { bContext *C; #ifndef WITH_PYTHON_MODULE bArgs *ba; #endif #ifdef WIN32 char **argv; int argv_num; #endif /* --- end declarations --- */ /* ensure we free data on early-exit */ struct CreatorAtExitData app_init_data = {NULL}; BKE_blender_atexit_register(callback_main_atexit, &app_init_data); /* Unbuffered stdout makes stdout and stderr better synchronized, and helps * when stepping through code in a debugger (prints are immediately * visible). */ setvbuf(stdout, NULL, _IONBF, 0); #ifdef WIN32 /* We delay loading of openmp so we can set the policy here. */ # if defined(_MSC_VER) _putenv_s("OMP_WAIT_POLICY", "PASSIVE"); # endif /* FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM * (fixed in SP1). Just disable it. */ # if defined(_MSC_VER) && defined(_M_X64) _set_FMA3_enable(0); # endif /* Win32 Unicode Args */ /* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized * (it depends on the args passed in, which is what we're getting here!) */ { wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc); argv = malloc(argc * sizeof(char *)); for (argv_num = 0; argv_num < argc; argv_num++) { argv[argv_num] = alloc_utf_8_from_16(argv_16[argv_num], 0); } LocalFree(argv_16); /* free on early-exit */ app_init_data.argv = argv; app_init_data.argv_num = argv_num; } #endif /* WIN32 */ /* NOTE: Special exception for guarded allocator type switch: * we need to perform switch from lock-free to fully * guarded allocator before any allocation happened. */ { int i; for (i = 0; i < argc; i++) { if (STREQ(argv[i], "--debug") || STREQ(argv[i], "-d") || STREQ(argv[i], "--debug-memory") || STREQ(argv[i], "--debug-all")) { printf("Switching to fully guarded memory allocator.\n"); MEM_use_guarded_allocator(); break; } else if (STREQ(argv[i], "--")) { break; } } } #ifdef BUILD_DATE { time_t temp_time = build_commit_timestamp; struct tm *tm = gmtime(&temp_time); if (LIKELY(tm)) { strftime(build_commit_date, sizeof(build_commit_date), "%Y-%m-%d", tm); strftime(build_commit_time, sizeof(build_commit_time), "%H:%M", tm); } else { const char *unknown = "date-unknown"; BLI_strncpy(build_commit_date, unknown, sizeof(build_commit_date)); BLI_strncpy(build_commit_time, unknown, sizeof(build_commit_time)); } } #endif #ifdef WITH_SDL_DYNLOAD sdlewInit(); #endif /* Initialize logging */ CLG_init(); CLG_fatal_fn_set(callback_clg_fatal); C = CTX_create(); #ifdef WITH_PYTHON_MODULE #ifdef __APPLE__ environ = *_NSGetEnviron(); #endif #undef main evil_C = C; #endif #ifdef WITH_BINRELOC br_init(NULL); #endif #ifdef WITH_LIBMV libmv_initLogging(argv[0]); #elif defined(WITH_CYCLES_LOGGING) CCL_init_logging(argv[0]); #endif main_callback_setup(); #if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE) /* patch to ignore argument finder gives us (pid?) */ if (argc == 2 && STREQLEN(argv[1], "-psn_", 5)) { extern int GHOST_HACK_getFirstFile(char buf[]); static char firstfilebuf[512]; argc = 1; if (GHOST_HACK_getFirstFile(firstfilebuf)) { argc = 2; argv[1] = firstfilebuf; } } #endif #ifdef __FreeBSD__ fpsetmask(0); #endif /* initialize path to executable */ BKE_appdir_program_path_init(argv[0]); BLI_threadapi_init(); BLI_thread_put_process_on_fast_node(); DNA_sdna_current_init(); BKE_blender_globals_init(); /* blender.c */ IMB_init(); BKE_cachefiles_init(); BKE_images_init(); BKE_modifier_init(); BKE_gpencil_modifier_init(); BKE_shaderfx_init(); DEG_register_node_types(); BKE_brush_system_init(); RE_texture_rng_init(); BLI_callback_global_init(); /* first test for background */ #ifndef WITH_PYTHON_MODULE ba = BLI_argsInit(argc, (const char **)argv); /* skip binary path */ /* ensure we free on early exit */ app_init_data.ba = ba; main_args_setup(C, ba); BLI_argsParse(ba, 1, NULL, NULL); main_signal_setup(); #else /* using preferences or user startup makes no sense for py-as-module */ G.factory_startup = true; #endif #ifdef WITH_FFMPEG IMB_ffmpeg_init(); #endif /* after level 1 args, this is so playanim skips RNA init */ RNA_init(); RE_engines_init(); init_nodesystem(); psys_init_rng(); /* end second init */ #if defined(WITH_PYTHON_MODULE) || defined(WITH_HEADLESS) G.background = true; /* python module mode ALWAYS runs in background mode (for now) */ #else if (G.background) { main_signal_setup_background(); } #endif /* background render uses this font too */ BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size); /* Initialize ffmpeg if built in, also needed for bg mode if videos are * rendered via ffmpeg */ BKE_sound_init_once(); init_def_material(); if (G.background == 0) { #ifndef WITH_PYTHON_MODULE BLI_argsParse(ba, 2, NULL, NULL); BLI_argsParse(ba, 3, NULL, NULL); #endif WM_init(C, argc, (const char **)argv); /* this is properly initialized with user defs, but this is default */ /* call after loading the startup.blend so we can read U.tempdir */ BKE_tempdir_init(U.tempdir); } else { #ifndef WITH_PYTHON_MODULE BLI_argsParse(ba, 3, NULL, NULL); #endif WM_init(C, argc, (const char **)argv); /* don't use user preferences temp dir */ BKE_tempdir_init(NULL); } #ifdef WITH_PYTHON /** * NOTE: the U.pythondir string is NULL until WM_init() is executed, * so we provide the BPY_ function below to append the user defined * python-dir to Python's sys.path at this point. Simply putting * WM_init() before #BPY_python_start() crashes Blender at startup. */ /* TODO - U.pythondir */ #else printf("\n* WARNING * - Blender compiled without Python!\nthis is not intended for typical usage\n\n"); #endif CTX_py_init_set(C, 1); WM_keyconfig_init(C); #ifdef WITH_FREESTYLE /* initialize Freestyle */ FRS_initialize(); FRS_set_context(C); #endif /* OK we are ready for it */ #ifndef WITH_PYTHON_MODULE main_args_setup_post(C, ba); #endif /* Explicitly free data allocated for argument parsing: * - 'ba' * - 'argv' on WIN32. */ callback_main_atexit(&app_init_data); BKE_blender_atexit_unregister(callback_main_atexit, &app_init_data); /* paranoid, avoid accidental re-use */ #ifndef WITH_PYTHON_MODULE ba = NULL; (void)ba; #endif #ifdef WIN32 argv = NULL; (void)argv; #endif #ifdef WITH_PYTHON_MODULE return 0; /* keep blender in background mode running */ #endif if (G.background) { /* Using window-manager API in background mode is a bit odd, but works fine. */ WM_exit(C); } else { if (!G.file_loaded) { WM_init_splash(C); } } WM_main(C); return 0; } /* end of int main(argc, argv) */ #ifdef WITH_PYTHON_MODULE void main_python_exit(void) { WM_exit_ext((bContext *)evil_C, true); evil_C = NULL; } #endif /** \} */