diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index b7f3ec9963d..ee13aa1cfc6 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -495,7 +495,7 @@ The thumbnail size to use in the editor's file dialogs (in pixels). See also [member docks/filesystem/thumbnail_size]. - + The path to the directory containing the Blender executable used for converting the Blender 3D scene files [code].blend[/code] to glTF 2.0 format during import. Blender 3.0 or later is required. To enable this feature for your specific project, use [member ProjectSettings.filesystem/import/blender/enabled]. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index cbd797273c1..0876261a315 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -943,7 +943,7 @@ If [code]true[/code], Blender 3D scene files with the [code].blend[/code] extension will be imported by converting them to glTF 2.0. - This requires configuring a path to a Blender executable in the editor settings at [code]filesystem/import/blender/blender3_path[/code]. Blender 3.0 or later is required. + This requires configuring a path to a Blender executable in the editor settings at [code]filesystem/import/blender/blender_path[/code]. Blender 3.0 or later is required. Override for [member filesystem/import/blender/enabled] on Android where Blender can't easily be accessed from Godot. diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 25510122f40..3b1a69459d4 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -520,7 +520,7 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/file_dialog/thumbnail_size", 64, "32,128,16") // Import (for glft module) - EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/import/blender/blender3_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) + EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/import/blender/blender_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/import/blender/rpc_port", 6011, "0,65535,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "filesystem/import/blender/rpc_server_uptime", 5, "0,300,1,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/import/fbx/fbx2gltf_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) diff --git a/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml b/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml index 24f6dbd887f..e3433e6e29a 100644 --- a/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml +++ b/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml @@ -5,7 +5,7 @@ Imports Blender scenes in the [code].blend[/code] file format through the glTF 2.0 3D import pipeline. This importer requires Blender to be installed by the user, so that it can be used to export the scene as glTF 2.0. - The location of the Blender binary is set via the [code]filesystem/import/blender/blender3_path[/code] editor setting. + The location of the Blender binary is set via the [code]filesystem/import/blender/blender_path[/code] editor setting. This importer is only used if [member ProjectSettings.filesystem/import/blender/enabled] is enabled, otherwise [code].blend[/code] files present in the project folder are not imported. Blend import requires Blender 3.0. Internally, the EditorSceneFormatImporterBlend uses the Blender glTF "Use Original" mode to reference external textures. diff --git a/modules/gltf/editor/editor_import_blend_runner.cpp b/modules/gltf/editor/editor_import_blend_runner.cpp index 659a60e6a1f..9f2dc757aac 100644 --- a/modules/gltf/editor/editor_import_blend_runner.cpp +++ b/modules/gltf/editor/editor_import_blend_runner.cpp @@ -153,13 +153,7 @@ String dict_to_xmlrpc(const Dictionary &p_dict) { } Error EditorImportBlendRunner::start_blender(const String &p_python_script, bool p_blocking) { - String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path"); - -#ifdef WINDOWS_ENABLED - blender_path = blender_path.path_join("blender.exe"); -#else - blender_path = blender_path.path_join("blender"); -#endif + String blender_path = EDITOR_GET("filesystem/import/blender/blender_path"); List args; args.push_back("--background"); diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 46367820635..a91856c4a14 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -55,20 +55,7 @@ #endif static bool _get_blender_version(const String &p_path, int &r_major, int &r_minor, String *r_err = nullptr) { - String path = p_path; -#ifdef WINDOWS_ENABLED - path = path.path_join("blender.exe"); -#else - path = path.path_join("blender"); -#endif - -#if defined(MACOS_ENABLED) - if (!FileAccess::exists(path)) { - path = p_path.path_join("Blender"); - } -#endif - - if (!FileAccess::exists(path)) { + if (!FileAccess::exists(p_path)) { if (r_err) { *r_err = TTR("Path does not contain a Blender installation."); } @@ -77,7 +64,7 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_mino List args; args.push_back("--version"); String pipe; - Error err = OS::get_singleton()->execute(path, args, &pipe); + Error err = OS::get_singleton()->execute(p_path, args, &pipe); if (err != OK) { if (r_err) { *r_err = TTR("Can't execute Blender binary."); @@ -87,7 +74,7 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_mino int bl = pipe.find("Blender "); if (bl == -1) { if (r_err) { - *r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s."), path); + *r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s."), p_path); } return false; } @@ -126,7 +113,7 @@ void EditorSceneFormatImporterBlend::get_extensions(List *r_extensions) Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags, const HashMap &p_options, List *r_missing_deps, Error *r_err) { - String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path"); + String blender_path = EDITOR_GET("filesystem/import/blender/blender_path"); if (blender_major_version == -1 || blender_minor_version == -1) { _get_blender_version(blender_path, blender_major_version, blender_minor_version, nullptr); @@ -369,7 +356,7 @@ static bool _test_blender_path(const String &p_path, String *r_err = nullptr) { bool EditorFileSystemImportFormatSupportQueryBlend::is_active() const { bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled"); - if (blend_enabled && !_test_blender_path(EDITOR_GET("filesystem/import/blender/blender3_path").operator String())) { + if (blend_enabled && !_test_blender_path(EDITOR_GET("filesystem/import/blender/blender_path").operator String())) { // Intending to import Blender, but blend not configured. return true; } @@ -409,11 +396,59 @@ void EditorFileSystemImportFormatSupportQueryBlend::_validate_path(String p_path } } -bool EditorFileSystemImportFormatSupportQueryBlend::_autodetect_path(String p_path) { - if (_test_blender_path(p_path)) { - auto_detected_path = p_path; - return true; +bool EditorFileSystemImportFormatSupportQueryBlend::_autodetect_path() { + // Autodetect + auto_detected_path = ""; + +#if defined(MACOS_ENABLED) + Vector find_paths = { + "/opt/homebrew/bin/blender", + "/opt/local/bin/blender", + "/usr/local/bin/blender", + "/usr/local/opt/blender", + "/Applications/Blender.app/Contents/MacOS/Blender", + }; + { + List mdfind_args; + mdfind_args.push_back("kMDItemCFBundleIdentifier=org.blenderfoundation.blender"); + + String output; + Error err = OS::get_singleton()->execute("mdfind", mdfind_args, &output); + if (err == OK) { + for (const String &find_path : output.split("\n")) { + find_paths.push_back(find_path.path_join("Contents/MacOS/Blender")); + } + } } +#elif defined(WINDOWS_ENABLED) + Vector find_paths = { + "C:\\Program Files\\Blender Foundation\\blender.exe", + "C:\\Program Files (x86)\\Blender Foundation\\blender.exe", + }; + { + char blender_opener_path[MAX_PATH]; + DWORD path_len = MAX_PATH; + HRESULT res = AssocQueryString(0, ASSOCSTR_EXECUTABLE, ".blend", "open", blender_opener_path, &path_len); + if (res == S_OK) { + find_paths.push_back(String(blender_opener_path).get_base_dir().path_join("blender.exe")); + } + } + +#elif defined(UNIX_ENABLED) + Vector find_paths = { + "/usr/bin/blender", + "/usr/local/bin/blender", + "/opt/blender/bin/blender", + }; +#endif + + for (const String &find_path : find_paths) { + if (_test_blender_path(find_path)) { + auto_detected_path = find_path; + return true; + } + } + return false; } @@ -427,7 +462,7 @@ void EditorFileSystemImportFormatSupportQueryBlend::_select_install(String p_pat } void EditorFileSystemImportFormatSupportQueryBlend::_browse_install() { if (blender_path->get_text() != String()) { - browse_dialog->set_current_dir(blender_path->get_text()); + browse_dialog->set_current_file(blender_path->get_text()); } browse_dialog->popup_centered_ratio(); @@ -479,76 +514,10 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() { EditorNode::get_singleton()->get_gui_base()->add_child(browse_dialog); } - String path = EDITOR_GET("filesystem/import/blender/blender3_path"); + String path = EDITOR_GET("filesystem/import/blender/blender_path"); - if (path == "") { - // Autodetect - auto_detected_path = ""; - -#if defined(MACOS_ENABLED) - - { - Vector mdfind_paths; - { - List mdfind_args; - mdfind_args.push_back("kMDItemCFBundleIdentifier=org.blenderfoundation.blender"); - - String output; - Error err = OS::get_singleton()->execute("mdfind", mdfind_args, &output); - if (err == OK) { - mdfind_paths = output.split("\n"); - } - } - - bool found = false; - for (const String &found_path : mdfind_paths) { - found = _autodetect_path(found_path.path_join("Contents/MacOS")); - if (found) { - break; - } - } - if (!found) { - found = _autodetect_path("/opt/homebrew/bin"); - } - if (!found) { - found = _autodetect_path("/opt/local/bin"); - } - if (!found) { - found = _autodetect_path("/usr/local/bin"); - } - if (!found) { - found = _autodetect_path("/usr/local/opt"); - } - if (!found) { - found = _autodetect_path("/Applications/Blender.app/Contents/MacOS"); - } - } -#elif defined(WINDOWS_ENABLED) - { - char blender_opener_path[MAX_PATH]; - DWORD path_len = MAX_PATH; - HRESULT res = AssocQueryString(0, ASSOCSTR_EXECUTABLE, ".blend", "open", blender_opener_path, &path_len); - if (res == S_OK && _autodetect_path(String(blender_opener_path).get_base_dir())) { - // Good. - } else if (_autodetect_path("C:\\Program Files\\Blender Foundation")) { - // Good. - } else { - _autodetect_path("C:\\Program Files (x86)\\Blender Foundation"); - } - } - -#elif defined(UNIX_ENABLED) - if (_autodetect_path("/usr/bin")) { - // Good. - } else if (_autodetect_path("/usr/local/bin")) { - // Good - } else { - _autodetect_path("/opt/blender/bin"); - } -#endif - if (auto_detected_path != "") { - path = auto_detected_path; - } + if (path.is_empty() && _autodetect_path()) { + path = auto_detected_path; } blender_path->set_text(path); @@ -569,7 +538,7 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() { if (confirmed) { // Can only confirm a valid path. - EditorSettings::get_singleton()->set("filesystem/import/blender/blender3_path", blender_path->get_text()); + EditorSettings::get_singleton()->set("filesystem/import/blender/blender_path", blender_path->get_text()); EditorSettings::get_singleton()->save(); } else { // Disable Blender import diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h index c1f4280170a..ed1b19eaf3b 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.h +++ b/modules/gltf/editor/editor_scene_importer_blend.h @@ -95,7 +95,7 @@ class EditorFileSystemImportFormatSupportQueryBlend : public EditorFileSystemImp String auto_detected_path; void _validate_path(String p_path); - bool _autodetect_path(String p_path); + bool _autodetect_path(); void _path_confirmed(); diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index 94c9d66f78e..216309abf19 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -55,23 +55,39 @@ static void _editor_init() { // Blend to glTF importer. - bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled"); - String blender3_path = EDITOR_GET("filesystem/import/blender/blender3_path"); - if (blend_enabled) { - Ref da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (blender3_path.is_empty()) { - WARN_PRINT(TTR("Blend file import is enabled in the project settings, but no Blender path is configured in the editor settings. Blend files will not be imported.")); - } else if (!da->dir_exists(blender3_path)) { - WARN_PRINT(TTR("Blend file import is enabled, but the Blender path doesn't point to an accessible directory. Blend files will not be imported.")); - } else { - Ref importer; - importer.instantiate(); - ResourceImporterScene::add_scene_importer(importer); + String blender_path = EDITOR_GET("filesystem/import/blender/blender_path"); + if (blender_path.is_empty() && EditorSettings::get_singleton()->has_setting("filesystem/import/blender/blender3_path")) { + blender_path = EditorSettings::get_singleton()->get("filesystem/import/blender/blender3_path"); - Ref blend_import_query; - blend_import_query.instantiate(); - EditorFileSystem::get_singleton()->add_import_format_support_query(blend_import_query); + if (!blender_path.is_empty()) { +#if defined(MACOS_ENABLED) + if (blender_path.contains(".app")) { + blender_path += "/Contents/MacOS/Blender"; + } else { + blender_path += "/blender"; + } +#elif defined(WINDOWS_ENABLED) + blender_path += "\\blender.exe"; +#elif defined(UNIX_ENABLED) + blender_path += "/blender"; +#endif + + EditorSettings::get_singleton()->set("filesystem/import/blender/blender_path", blender_path); } + + EditorSettings::get_singleton()->erase("filesystem/import/blender/blender3_path"); + EditorSettings::get_singleton()->save(); + } + + bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled"); + if (blend_enabled) { + Ref importer; + importer.instantiate(); + ResourceImporterScene::add_scene_importer(importer); + + Ref blend_import_query; + blend_import_query.instantiate(); + EditorFileSystem::get_singleton()->add_import_format_support_query(blend_import_query); } memnew(EditorImportBlendRunner); EditorNode::get_singleton()->add_child(EditorImportBlendRunner::get_singleton());