diff --git a/modules/fbx/editor/editor_scene_importer_ufbx.cpp b/modules/fbx/editor/editor_scene_importer_ufbx.cpp index 07273d99d1d..706fb2e7291 100644 --- a/modules/fbx/editor/editor_scene_importer_ufbx.cpp +++ b/modules/fbx/editor/editor_scene_importer_ufbx.cpp @@ -68,8 +68,8 @@ Node *EditorSceneFormatImporterUFBX::import_scene(const String &p_path, uint32_t state->set_allow_geometry_helper_nodes(allow_geometry_helper_nodes); } if (p_options.has("fbx/embedded_image_handling")) { - int32_t enum_option = p_options["fbx/embedded_image_handling"]; - state->set_handle_binary_image(enum_option); + const int32_t enum_option = p_options["fbx/embedded_image_handling"]; + state->set_handle_binary_image_mode((GLTFState::HandleBinaryImageMode)enum_option); } if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) { state->set_import_as_skeleton_bones(true); @@ -97,7 +97,7 @@ void EditorSceneFormatImporterUFBX::get_import_options(const String &p_path, if (p_path.is_empty() || p_path.has_extension("fbx")) { r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/importer", PROPERTY_HINT_ENUM, "ufbx,FBX2glTF"), FBX_IMPORTER_UFBX)); r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::BOOL, "fbx/allow_geometry_helper_nodes"), false)); - r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), FBXState::HANDLE_BINARY_EXTRACT_TEXTURES)); + r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), FBXState::HANDLE_BINARY_IMAGE_MODE_EXTRACT_TEXTURES)); r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/naming_version", PROPERTY_HINT_ENUM, "Godot 4.0 or 4.1,Godot 4.2 to 4.4,Godot 4.5 or later"), 2)); } } diff --git a/modules/fbx/fbx_document.cpp b/modules/fbx/fbx_document.cpp index f04cd984379..f89d8dc311c 100644 --- a/modules/fbx/fbx_document.cpp +++ b/modules/fbx/fbx_document.cpp @@ -943,8 +943,8 @@ Ref FBXDocument::_parse_image_bytes_into_image(Ref p_state, con } GLTFImageIndex FBXDocument::_parse_image_save_image(Ref p_state, const Vector &p_bytes, const String &p_file_extension, int p_index, Ref p_image) { - FBXState::GLTFHandleBinary handling = FBXState::GLTFHandleBinary(p_state->handle_binary_image); - if (p_image->is_empty() || handling == FBXState::GLTFHandleBinary::HANDLE_BINARY_DISCARD_TEXTURES) { + FBXState::HandleBinaryImageMode handling = FBXState::HandleBinaryImageMode(p_state->handle_binary_image_mode); + if (p_image->is_empty() || handling == FBXState::HandleBinaryImageMode::HANDLE_BINARY_IMAGE_MODE_DISCARD_TEXTURES) { if (p_index < 0) { return -1; } @@ -953,7 +953,7 @@ GLTFImageIndex FBXDocument::_parse_image_save_image(Ref p_state, const return p_state->images.size() - 1; } #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint() && handling == FBXState::GLTFHandleBinary::HANDLE_BINARY_EXTRACT_TEXTURES) { + if (Engine::get_singleton()->is_editor_hint() && handling == FBXState::HandleBinaryImageMode::HANDLE_BINARY_IMAGE_MODE_EXTRACT_TEXTURES) { if (p_state->base_path.is_empty()) { if (p_index < 0) { return -1; @@ -1030,7 +1030,7 @@ GLTFImageIndex FBXDocument::_parse_image_save_image(Ref p_state, const return p_state->images.size() - 1; } #endif // TOOLS_ENABLED - if (handling == FBXState::HANDLE_BINARY_EMBED_AS_BASISU) { + if (handling == FBXState::HANDLE_BINARY_IMAGE_MODE_EMBED_AS_BASISU) { Ref tex; tex.instantiate(); tex->set_name(p_image->get_name()); @@ -1040,8 +1040,8 @@ GLTFImageIndex FBXDocument::_parse_image_save_image(Ref p_state, const p_state->source_images.push_back(p_image); return p_state->images.size() - 1; } - // This handles the case of HANDLE_BINARY_EMBED_AS_UNCOMPRESSED, and it also serves - // as a fallback for HANDLE_BINARY_EXTRACT_TEXTURES when this is not the editor. + // This handles the case of HANDLE_BINARY_IMAGE_MODE_EMBED_AS_UNCOMPRESSED, and it also serves + // as a fallback for HANDLE_BINARY_IMAGE_MODE_EXTRACT_TEXTURES when this is not the editor. Ref tex; tex.instantiate(); tex->set_name(p_image->get_name()); @@ -1112,7 +1112,7 @@ Ref FBXDocument::_get_texture(Ref p_state, const GLTFTextur ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref()); const GLTFImageIndex image = p_state->textures[p_texture]->get_src_image(); ERR_FAIL_INDEX_V(image, p_state->images.size(), Ref()); - if (FBXState::GLTFHandleBinary(p_state->handle_binary_image) == FBXState::HANDLE_BINARY_EMBED_AS_BASISU) { + if (FBXState::HandleBinaryImageMode(p_state->handle_binary_image_mode) == FBXState::HANDLE_BINARY_IMAGE_MODE_EMBED_AS_BASISU) { ERR_FAIL_INDEX_V(image, p_state->source_images.size(), Ref()); Ref portable_texture; portable_texture.instantiate(); diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index 5d19d336e2c..693784f13a0 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -83,9 +83,10 @@ Returns an array of all [GLTFCamera]s in the glTF file. These are the cameras that the [member GLTFNode.camera] index refers to. - + + Deprecated untyped alias for [member handle_binary_image_mode]. When importing a glTF file with unimported raw binary images embedded inside of binary blob buffers, in data URIs, or separate files not imported by Godot, this controls how the images are handled. @@ -203,10 +204,11 @@ Sets the [GLTFCamera]s in the state. These are the cameras that the [member GLTFNode.camera] index refers to. - + + Deprecated untyped alias for [member handle_binary_image_mode]. When importing a glTF file with unimported raw binary images embedded inside of binary blob buffers, in data URIs, or separate files not imported by Godot, this controls how the images are handled. @@ -305,6 +307,10 @@ The binary buffer attached to a .glb file. + + When importing a glTF file with unimported raw binary images embedded inside of binary blob buffers, in data URIs, or separate files not imported by Godot, this controls how the images are handled. Images can be discarded, saved as separate files, or embedded in the scene lossily or losslessly. See [enum HandleBinaryImageMode] for options. + This property does nothing for image files in the [code]res://[/code] folder imported by Godot, as those are handled by Godot's image importer directly, and then the Godot scene generated from the glTF file will use the images as Godot imported them. + If [code]true[/code], forces all GLTFNodes in the document to be bones of a single [Skeleton3D] Godot node. @@ -325,16 +331,30 @@ - + + When importing a glTF file with embedded binary images, discards all images and uses untextured materials in their place. Images stored as separate files in the [code]res://[/code] folder are not affected by this; those will be used as Godot imported them. + + + When importing a glTF file with embedded binary images, extracts them and saves them to their own files. This allows the image to be imported by Godot's image importer, which can then have their import options customized by the user, including optionally compressing the image to VRAM texture formats. + This will save the images's bytes exactly as-is, without recompression. For image formats supplied by glTF extensions, the file will have a filename ending with the file extension supplied by [method GLTFDocumentExtension._get_image_file_extension] of the extension class. + [b]Note:[/b] This option is editor-only. At runtime, this acts the same as [constant HANDLE_BINARY_IMAGE_MODE_EMBED_AS_UNCOMPRESSED]. + + + When importing a glTF file with embedded binary images, embeds textures VRAM compressed with Basis Universal into the generated scene. Images stored as separate files in the [code]res://[/code] folder are not affected by this; those will be used as Godot imported them. + + + When importing a glTF file with embedded binary images, embeds textures compressed losslessly into the generated scene. Images stored as separate files in the [code]res://[/code] folder are not affected by this; those will be used as Godot imported them. + + Discards all embedded textures and uses untextured materials. - + Extracts embedded textures to be reimported and compressed. Editor only. Acts as uncompressed at runtime. - + Embeds textures VRAM compressed with Basis Universal into the generated scene. - + Embeds textures compressed losslessly into the generated scene, matching old behavior. diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp index ef173ef4556..f8c6d775a17 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp @@ -51,7 +51,7 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t } if (p_options.has("gltf/embedded_image_handling")) { int32_t enum_option = p_options["gltf/embedded_image_handling"]; - state->set_handle_binary_image(enum_option); + state->set_handle_binary_image_mode((GLTFState::HandleBinaryImageMode)enum_option); } if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) { state->set_import_as_skeleton_bones(true); @@ -85,7 +85,7 @@ void EditorSceneFormatImporterGLTF::get_import_options(const String &p_path, // Returns all the options when path is empty because that means it's for the Project Settings. if (p_path.is_empty() || file_extension == "gltf" || file_extension == "glb") { r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/naming_version", PROPERTY_HINT_ENUM, "Godot 4.0 or 4.1,Godot 4.2 to 4.4,Godot 4.5 or later"), 2)); - r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES)); + r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_IMAGE_MODE_EXTRACT_TEXTURES)); } } diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 40b256c128a..9ad18f017d3 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -3909,14 +3909,14 @@ Ref GLTFDocument::_parse_image_bytes_into_image(Ref p_state, c } void GLTFDocument::_parse_image_save_image(Ref p_state, const Vector &p_bytes, const String &p_resource_uri, const String &p_file_extension, int p_index, Ref p_image) { - GLTFState::GLTFHandleBinary handling = GLTFState::GLTFHandleBinary(p_state->handle_binary_image); - if (p_image->is_empty() || handling == GLTFState::GLTFHandleBinary::HANDLE_BINARY_DISCARD_TEXTURES) { + GLTFState::HandleBinaryImageMode handling = GLTFState::HandleBinaryImageMode(p_state->handle_binary_image_mode); + if (p_image->is_empty() || handling == GLTFState::HandleBinaryImageMode::HANDLE_BINARY_IMAGE_MODE_DISCARD_TEXTURES) { p_state->images.push_back(Ref()); p_state->source_images.push_back(Ref()); return; } #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint() && handling == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EXTRACT_TEXTURES) { + if (Engine::get_singleton()->is_editor_hint() && handling == GLTFState::HandleBinaryImageMode::HANDLE_BINARY_IMAGE_MODE_EXTRACT_TEXTURES) { if (p_state->extract_path.is_empty()) { WARN_PRINT("glTF: Couldn't extract image because the base and extract paths are empty. It will be loaded directly instead, uncompressed."); } else if (p_state->extract_path.begins_with("res://.godot/imported")) { @@ -3999,7 +3999,7 @@ void GLTFDocument::_parse_image_save_image(Ref p_state, const Vector< } } #endif // TOOLS_ENABLED - if (handling == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EMBED_AS_BASISU) { + if (handling == GLTFState::HandleBinaryImageMode::HANDLE_BINARY_IMAGE_MODE_EMBED_AS_BASISU) { Ref tex; tex.instantiate(); tex->set_name(p_image->get_name()); @@ -4009,8 +4009,8 @@ void GLTFDocument::_parse_image_save_image(Ref p_state, const Vector< p_state->source_images.push_back(p_image); return; } - // This handles the case of HANDLE_BINARY_EMBED_AS_UNCOMPRESSED, and it also serves - // as a fallback for HANDLE_BINARY_EXTRACT_TEXTURES when this is not the editor. + // This handles the case of HANDLE_BINARY_IMAGE_MODE_EMBED_AS_UNCOMPRESSED, and it also serves + // as a fallback for HANDLE_BINARY_IMAGE_MODE_EXTRACT_TEXTURES when this is not the editor. Ref tex; tex.instantiate(); tex->set_name(p_image->get_name()); @@ -4243,7 +4243,7 @@ Ref GLTFDocument::_get_texture(Ref p_state, const GLTFText ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref()); const GLTFImageIndex image = p_state->textures[p_texture]->get_src_image(); ERR_FAIL_INDEX_V(image, p_state->images.size(), Ref()); - if (GLTFState::GLTFHandleBinary(p_state->handle_binary_image) == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EMBED_AS_BASISU) { + if (GLTFState::HandleBinaryImageMode(p_state->handle_binary_image_mode) == GLTFState::HandleBinaryImageMode::HANDLE_BINARY_IMAGE_MODE_EMBED_AS_BASISU) { ERR_FAIL_INDEX_V(image, p_state->source_images.size(), Ref()); Ref portable_texture; portable_texture.instantiate(); diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index 8fbfc8513d1..3dc32a830e6 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -99,8 +99,8 @@ void GLTFState::_bind_methods() { ClassDB::bind_method(D_METHOD("get_node_index", "scene_node"), &GLTFState::get_node_index); ClassDB::bind_method(D_METHOD("get_additional_data", "extension_name"), &GLTFState::get_additional_data); ClassDB::bind_method(D_METHOD("set_additional_data", "extension_name", "additional_data"), &GLTFState::set_additional_data); - ClassDB::bind_method(D_METHOD("get_handle_binary_image"), &GLTFState::get_handle_binary_image); - ClassDB::bind_method(D_METHOD("set_handle_binary_image", "method"), &GLTFState::set_handle_binary_image); + ClassDB::bind_method(D_METHOD("get_handle_binary_image_mode"), &GLTFState::get_handle_binary_image_mode); + ClassDB::bind_method(D_METHOD("set_handle_binary_image_mode", "method"), &GLTFState::set_handle_binary_image_mode); ClassDB::bind_method(D_METHOD("set_bake_fps", "value"), &GLTFState::set_bake_fps); ClassDB::bind_method(D_METHOD("get_bake_fps"), &GLTFState::get_bake_fps); @@ -132,9 +132,18 @@ void GLTFState::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "create_animations"), "set_create_animations", "get_create_animations"); // bool ADD_PROPERTY(PropertyInfo(Variant::BOOL, "import_as_skeleton_bones"), "set_import_as_skeleton_bones", "get_import_as_skeleton_bones"); // bool ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector> - ADD_PROPERTY(PropertyInfo(Variant::INT, "handle_binary_image", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_handle_binary_image", "get_handle_binary_image"); // enum + ADD_PROPERTY(PropertyInfo(Variant::INT, "handle_binary_image_mode", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed"), "set_handle_binary_image_mode", "get_handle_binary_image_mode"); // enum ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_fps", PROPERTY_HINT_RANGE, "0.001,120,0.0001,or_greater"), "set_bake_fps", "get_bake_fps"); + BIND_ENUM_CONSTANT(HANDLE_BINARY_IMAGE_MODE_DISCARD_TEXTURES); + BIND_ENUM_CONSTANT(HANDLE_BINARY_IMAGE_MODE_EXTRACT_TEXTURES); + BIND_ENUM_CONSTANT(HANDLE_BINARY_IMAGE_MODE_EMBED_AS_BASISU); + BIND_ENUM_CONSTANT(HANDLE_BINARY_IMAGE_MODE_EMBED_AS_UNCOMPRESSED); + + // Deprecated non-type-safe versions for backward compatibility, remove in Godot 5.0. + ClassDB::bind_method(D_METHOD("get_handle_binary_image"), &GLTFState::get_handle_binary_image); + ClassDB::bind_method(D_METHOD("set_handle_binary_image", "method"), &GLTFState::set_handle_binary_image); + ADD_PROPERTY(PropertyInfo(Variant::INT, "handle_binary_image", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_INTERNAL), "set_handle_binary_image", "get_handle_binary_image"); // enum as int BIND_CONSTANT(HANDLE_BINARY_DISCARD_TEXTURES); BIND_CONSTANT(HANDLE_BINARY_EXTRACT_TEXTURES); BIND_CONSTANT(HANDLE_BINARY_EMBED_AS_BASISU); diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index 1c75a7609e9..6bb8523a429 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -51,6 +51,14 @@ class GLTFState : public Resource { friend class GLTFDocument; friend class GLTFNode; +public: + enum HandleBinaryImageMode { + HANDLE_BINARY_IMAGE_MODE_DISCARD_TEXTURES = 0, + HANDLE_BINARY_IMAGE_MODE_EXTRACT_TEXTURES, + HANDLE_BINARY_IMAGE_MODE_EMBED_AS_BASISU, + HANDLE_BINARY_IMAGE_MODE_EMBED_AS_UNCOMPRESSED, // If this value changes from 3, ResourceImporterScene::pre_import must be changed as well. + }; + protected: String base_path; String extract_path; @@ -71,7 +79,7 @@ protected: bool force_disable_compression = false; bool import_as_skeleton_bones = false; - int handle_binary_image = HANDLE_BINARY_EXTRACT_TEXTURES; + HandleBinaryImageMode handle_binary_image_mode = HANDLE_BINARY_IMAGE_MODE_EXTRACT_TEXTURES; Vector> nodes; Vector> buffers; @@ -133,11 +141,13 @@ public: HANDLE_BINARY_EMBED_AS_UNCOMPRESSED, // If this value changes from 3, ResourceImporterScene::pre_import must be changed as well. }; int32_t get_handle_binary_image() { - return handle_binary_image; + return handle_binary_image_mode; } void set_handle_binary_image(int32_t p_handle_binary_image) { - handle_binary_image = p_handle_binary_image; + handle_binary_image_mode = (HandleBinaryImageMode)p_handle_binary_image; } + HandleBinaryImageMode get_handle_binary_image_mode() { return handle_binary_image_mode; } + void set_handle_binary_image_mode(HandleBinaryImageMode p_handle_binary_image) { handle_binary_image_mode = p_handle_binary_image; } Dictionary get_json(); void set_json(Dictionary p_json); @@ -251,3 +261,5 @@ public: Variant get_additional_data(const StringName &p_extension_name); void set_additional_data(const StringName &p_extension_name, Variant p_additional_data); }; + +VARIANT_ENUM_CAST(GLTFState::HandleBinaryImageMode); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index f74aaf04eb7..afa944f8eb9 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -2789,6 +2789,8 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte if (p_iprop.is_hidden) { p_output.append(MEMBER_BEGIN "[EditorBrowsable(EditorBrowsableState.Never)]"); + // Deprecated PROPERTY_USAGE_INTERNAL properties appear as hidden to C# and may call deprecated getter/setter functions. + p_output.append("\n#pragma warning disable CS0618 // Type or member is obsolete."); } p_output.append(MEMBER_BEGIN "public "); @@ -2847,6 +2849,10 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.append(CLOSE_BLOCK_L1); + if (p_iprop.is_hidden) { + p_output.append("#pragma warning restore CS0618 // Type or member is obsolete.\n"); + } + return OK; }