diff options
Diffstat (limited to 'modules/gltf')
44 files changed, 2390 insertions, 1690 deletions
diff --git a/modules/gltf/SCsub b/modules/gltf/SCsub index 71f3ba58d9..d1f337715f 100644 --- a/modules/gltf/SCsub +++ b/modules/gltf/SCsub @@ -7,7 +7,7 @@ env_gltf = env_modules.Clone() # Godot source files env_gltf.add_source_files(env.modules_sources, "*.cpp") -env_gltf.add_source_files(env.modules_sources, "extensions/*.cpp") env_gltf.add_source_files(env.modules_sources, "structures/*.cpp") -if env["tools"]: +SConscript("extensions/SCsub") +if env.editor_build: env_gltf.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/modules/gltf/config.py b/modules/gltf/config.py index 189b5a831a..130c06d264 100644 --- a/modules/gltf/config.py +++ b/modules/gltf/config.py @@ -26,6 +26,7 @@ def get_doc_classes(): "GLTFSpecGloss", "GLTFState", "GLTFTexture", + "GLTFTextureSampler", ] diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml index 3cd0f5c0f9..f313f4b28f 100644 --- a/modules/gltf/doc_classes/GLTFDocument.xml +++ b/modules/gltf/doc_classes/GLTFDocument.xml @@ -14,8 +14,9 @@ <param index="1" name="base_path" type="String" /> <param index="2" name="state" type="GLTFState" /> <param index="3" name="flags" type="int" default="0" /> - <param index="4" name="bake_fps" type="int" default="30" /> <description> + Takes a [PackedByteArray] defining a gLTF and returns a [GLTFState] object through the [param state] parameter. + [b]Note:[/b] The [param base_path] tells [method append_from_buffer] where to find dependencies and can be empty. </description> </method> <method name="append_from_file"> @@ -23,9 +24,10 @@ <param index="0" name="path" type="String" /> <param index="1" name="state" type="GLTFState" /> <param index="2" name="flags" type="int" default="0" /> - <param index="3" name="bake_fps" type="int" default="30" /> - <param index="4" name="base_path" type="String" default="""" /> + <param index="3" name="base_path" type="String" default="""" /> <description> + Takes a path to a gLTF file and returns a [GLTFState] object through the [param state] parameter. + [b]Note:[/b] The [param base_path] tells [method append_from_file] where to find dependencies and can be empty. </description> </method> <method name="append_from_scene"> @@ -33,21 +35,40 @@ <param index="0" name="node" type="Node" /> <param index="1" name="state" type="GLTFState" /> <param index="2" name="flags" type="int" default="0" /> - <param index="3" name="bake_fps" type="int" default="30" /> <description> + Takes a Godot Engine scene node and returns a [GLTFState] object through the [param state] parameter. </description> </method> <method name="generate_buffer"> <return type="PackedByteArray" /> <param index="0" name="state" type="GLTFState" /> <description> + Takes a [GLTFState] object through the [param state] parameter and returns a gLTF [PackedByteArray]. </description> </method> <method name="generate_scene"> <return type="Node" /> <param index="0" name="state" type="GLTFState" /> - <param index="1" name="bake_fps" type="int" default="30" /> + <param index="1" name="bake_fps" type="float" default="30" /> + <param index="2" name="trimming" type="bool" default="false" /> <description> + Takes a [GLTFState] object through the [param state] parameter and returns a Godot Engine scene node. + </description> + </method> + <method name="register_gltf_document_extension" qualifiers="static"> + <return type="void" /> + <param index="0" name="extension" type="GLTFDocumentExtension" /> + <param index="1" name="first_priority" type="bool" default="false" /> + <description> + Registers the given [GLTFDocumentExtension] instance with GLTFDocument. If [param first_priority] is true, this extension will be run first. Otherwise, it will be run last. + [b]Note:[/b] Like GLTFDocument itself, all GLTFDocumentExtension classes must be stateless in order to function properly. If you need to store data, use the [code]set_additional_data[/code] and [code]get_additional_data[/code] methods in [GLTFState] or [GLTFNode]. + </description> + </method> + <method name="unregister_gltf_document_extension" qualifiers="static"> + <return type="void" /> + <param index="0" name="extension" type="GLTFDocumentExtension" /> + <description> + Unregisters the given [GLTFDocumentExtension] instance. </description> </method> <method name="write_to_filesystem"> @@ -55,11 +76,9 @@ <param index="0" name="state" type="GLTFState" /> <param index="1" name="path" type="String" /> <description> + Takes a [GLTFState] object through the [param state] parameter and writes a glTF file to the filesystem. + [b]Note:[/b] The extension of the glTF file determines if it is a .glb binary file or a .gltf file. </description> </method> </methods> - <members> - <member name="extensions" type="GLTFDocumentExtension[]" setter="set_extensions" getter="get_extensions" default="[]"> - </member> - </members> </class> diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml index d2a9022445..6004de32f1 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml @@ -1,12 +1,26 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="GLTFDocumentExtension" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> + [GLTFDocument] extension class. </brief_description> <description> + Extends the functionality of the [GLTFDocument] class by allowing you to run arbitrary code at various stages of GLTF import or export. + To use, make a new class extending GLTFDocumentExtension, override any methods you need, make an instance of your class, and register it using [method GLTFDocument.register_gltf_document_extension]. + [b]Note:[/b] Like GLTFDocument itself, all GLTFDocumentExtension classes must be stateless in order to function properly. If you need to store data, use the [code]set_additional_data[/code] and [code]get_additional_data[/code] methods in [GLTFState] or [GLTFNode]. </description> <tutorials> </tutorials> <methods> + <method name="_convert_scene_node" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="state" type="GLTFState" /> + <param index="1" name="gltf_node" type="GLTFNode" /> + <param index="2" name="scene_node" type="Node" /> + <description> + Part of the export process. This method is run after [method _export_preflight] and before [method _export_node]. + Runs when converting the data from a Godot scene node. This method can be used to process the Godot scene node data into a format that can be used by [method _export_node]. + </description> + </method> <method name="_export_node" qualifiers="virtual"> <return type="int" /> <param index="0" name="state" type="GLTFState" /> @@ -14,18 +28,42 @@ <param index="2" name="json" type="Dictionary" /> <param index="3" name="node" type="Node" /> <description> + Part of the export process. This method is run after [method _convert_scene_node] and before [method _export_post]. + This method can be used to modify the final JSON of each node. </description> </method> <method name="_export_post" qualifiers="virtual"> <return type="int" /> <param index="0" name="state" type="GLTFState" /> <description> + Part of the export process. This method is run last, after all other parts of the export process. + This method can be used to modify the final JSON of the generated GLTF file. </description> </method> <method name="_export_preflight" qualifiers="virtual"> <return type="int" /> - <param index="0" name="root" type="Node" /> + <param index="0" name="state" type="GLTFState" /> + <param index="1" name="root" type="Node" /> <description> + Part of the export process. This method is run first, before all other parts of the export process. + The return value is used to determine if this [GLTFDocumentExtension] instance should be used for exporting a given GLTF file. If [constant OK], the export will use this [GLTFDocumentExtension] instance. If not overridden, [constant OK] is returned. + </description> + </method> + <method name="_generate_scene_node" qualifiers="virtual"> + <return type="Node3D" /> + <param index="0" name="state" type="GLTFState" /> + <param index="1" name="gltf_node" type="GLTFNode" /> + <param index="2" name="scene_parent" type="Node" /> + <description> + Part of the import process. This method is run after [method _parse_node_extensions] and before [method _import_post_parse]. + Runs when generating a Godot scene node from a GLTFNode. The returned node will be added to the scene tree. Multiple nodes can be generated in this step if they are added as a child of the returned node. + </description> + </method> + <method name="_get_supported_extensions" qualifiers="virtual"> + <return type="PackedStringArray" /> + <description> + Part of the import process. This method is run after [method _import_preflight] and before [method _parse_node_extensions]. + Returns an array of the GLTF extensions supported by this GLTFDocumentExtension class. This is used to validate if a GLTF file with required extensions can be loaded. </description> </method> <method name="_import_node" qualifiers="virtual"> @@ -35,6 +73,8 @@ <param index="2" name="json" type="Dictionary" /> <param index="3" name="node" type="Node" /> <description> + Part of the import process. This method is run after [method _import_post_parse] and before [method _import_post]. + This method can be used to make modifications to each of the generated Godot scene nodes. </description> </method> <method name="_import_post" qualifiers="virtual"> @@ -42,18 +82,35 @@ <param index="0" name="state" type="GLTFState" /> <param index="1" name="root" type="Node" /> <description> + Part of the import process. This method is run last, after all other parts of the import process. + This method can be used to modify the final Godot scene generated by the import process. </description> </method> <method name="_import_post_parse" qualifiers="virtual"> <return type="int" /> <param index="0" name="state" type="GLTFState" /> <description> + Part of the import process. This method is run after [method _generate_scene_node] and before [method _import_node]. + This method can be used to modify any of the data imported so far, including any scene nodes, before running the final per-node import step. </description> </method> <method name="_import_preflight" qualifiers="virtual"> <return type="int" /> <param index="0" name="state" type="GLTFState" /> + <param index="1" name="extensions" type="PackedStringArray" /> + <description> + Part of the import process. This method is run first, before all other parts of the import process. + The return value is used to determine if this [GLTFDocumentExtension] instance should be used for importing a given GLTF file. If [constant OK], the import will use this [GLTFDocumentExtension] instance. If not overridden, [constant OK] is returned. + </description> + </method> + <method name="_parse_node_extensions" qualifiers="virtual"> + <return type="int" /> + <param index="0" name="state" type="GLTFState" /> + <param index="1" name="gltf_node" type="GLTFNode" /> + <param index="2" name="extensions" type="Dictionary" /> <description> + Part of the import process. This method is run after [method _get_supported_extensions] and before [method _generate_scene_node]. + Runs when parsing the node extensions of a GLTFNode. This method can be used to process the extension JSON data into a format that can be used by [method _generate_scene_node]. The return value should be a member of the [enum Error] enum. </description> </method> </methods> diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml index e933e6046a..8e48066623 100644 --- a/modules/gltf/doc_classes/GLTFNode.xml +++ b/modules/gltf/doc_classes/GLTFNode.xml @@ -1,11 +1,33 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="GLTFNode" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> + GLTF node class. </brief_description> <description> + Represents a GLTF node. GLTF nodes may have names, transforms, children (other GLTF nodes), and more specialized properties (represented by their own classes). </description> <tutorials> + <link title="GLTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link> </tutorials> + <methods> + <method name="get_additional_data"> + <return type="Variant" /> + <param index="0" name="extension_name" type="StringName" /> + <description> + Gets additional arbitrary data in this [GLTFNode] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless. + The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the return value can be anything you set. If nothing was set, the return value is null. + </description> + </method> + <method name="set_additional_data"> + <return type="void" /> + <param index="0" name="extension_name" type="StringName" /> + <param index="1" name="additional_data" type="Variant" /> + <description> + Sets additional arbitrary data in this [GLTFNode] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless. + The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want. + </description> + </method> + </methods> <members> <member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1"> </member> diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index 1dbd89aed8..9a554a0d49 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -7,11 +7,27 @@ <tutorials> </tutorials> <methods> + <method name="add_used_extension"> + <return type="void" /> + <param index="0" name="extension_name" type="String" /> + <param index="1" name="required" type="bool" /> + <description> + Appends an extension to the list of extensions used by this GLTF file during serialization. If [param required] is true, the extension will also be added to the list of required extensions. Do not run this in [method GLTFDocumentExtension._export_post], as that stage is too late to add extensions. The final list is sorted alphabetically. + </description> + </method> <method name="get_accessors"> <return type="GLTFAccessor[]" /> <description> </description> </method> + <method name="get_additional_data"> + <return type="Variant" /> + <param index="0" name="extension_name" type="StringName" /> + <description> + Gets additional arbitrary data in this [GLTFState] instance. This can be used to keep per-file state data in [GLTFDocumentExtension] classes, which is important because they are stateless. + The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the return value can be anything you set. If nothing was set, the return value is null. + </description> + </method> <method name="get_animation_player"> <return type="AnimationPlayer" /> <param index="0" name="idx" type="int" /> @@ -50,7 +66,7 @@ </description> </method> <method name="get_materials"> - <return type="BaseMaterial3D[]" /> + <return type="Material[]" /> <description> </description> </method> @@ -85,6 +101,12 @@ <description> </description> </method> + <method name="get_texture_samplers"> + <return type="GLTFTextureSampler[]" /> + <description> + Retrieves the array of texture samplers that are used by the textures contained in the GLTF. + </description> + </method> <method name="get_textures"> <return type="GLTFTexture[]" /> <description> @@ -106,6 +128,15 @@ <description> </description> </method> + <method name="set_additional_data"> + <return type="void" /> + <param index="0" name="extension_name" type="StringName" /> + <param index="1" name="additional_data" type="Variant" /> + <description> + Sets additional arbitrary data in this [GLTFState] instance. This can be used to keep per-file state data in [GLTFDocumentExtension] classes, which is important because they are stateless. + The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want. + </description> + </method> <method name="set_animations"> <return type="void" /> <param index="0" name="animations" type="GLTFAnimation[]" /> @@ -138,7 +169,7 @@ </method> <method name="set_materials"> <return type="void" /> - <param index="0" name="materials" type="BaseMaterial3D[]" /> + <param index="0" name="materials" type="Material[]" /> <description> </description> </method> @@ -172,6 +203,13 @@ <description> </description> </method> + <method name="set_texture_samplers"> + <return type="void" /> + <param index="0" name="texture_samplers" type="GLTFTextureSampler[]" /> + <description> + Sets the array of texture samplers that are used by the textures contained in the GLTF. + </description> + </method> <method name="set_textures"> <return type="void" /> <param index="0" name="textures" type="GLTFTexture[]" /> diff --git a/modules/gltf/doc_classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml index c0bc424168..f4486fd504 100644 --- a/modules/gltf/doc_classes/GLTFTexture.xml +++ b/modules/gltf/doc_classes/GLTFTexture.xml @@ -7,6 +7,9 @@ <tutorials> </tutorials> <members> + <member name="sampler" type="int" setter="set_sampler" getter="get_sampler" default="-1"> + ID of the texture sampler to use when sampling the image. If -1, then the default texture sampler is used (linear filtering, and repeat wrapping in both axes). + </member> <member name="src_image" type="int" setter="set_src_image" getter="get_src_image" default="0"> </member> </members> diff --git a/modules/gltf/doc_classes/GLTFTextureSampler.xml b/modules/gltf/doc_classes/GLTFTextureSampler.xml new file mode 100644 index 0000000000..1cc69bfe73 --- /dev/null +++ b/modules/gltf/doc_classes/GLTFTextureSampler.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="GLTFTextureSampler" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> + <brief_description> + Represents a GLTF texture sampler + </brief_description> + <description> + Represents a texture sampler as defined by the base GLTF spec. Texture samplers in GLTF specify how to sample data from the texture's base image, when rendering the texture on an object. + </description> + <tutorials> + </tutorials> + <members> + <member name="mag_filter" type="int" setter="set_mag_filter" getter="get_mag_filter" default="9729"> + Texture's magnification filter, used when texture appears larger on screen than the source image. + </member> + <member name="min_filter" type="int" setter="set_min_filter" getter="get_min_filter" default="9987"> + Texture's minification filter, used when the texture appears smaller on screen than the source image. + </member> + <member name="wrap_s" type="int" setter="set_wrap_s" getter="get_wrap_s" default="10497"> + Wrapping mode to use for S-axis (horizontal) texture coordinates. + </member> + <member name="wrap_t" type="int" setter="set_wrap_t" getter="get_wrap_t" default="10497"> + Wrapping mode to use for T-axis (vertical) texture coordinates. + </member> + </members> +</class> diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp index 95db1c0965..fe63afcc56 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp +++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp @@ -33,18 +33,10 @@ #include "editor_scene_exporter_gltf_plugin.h" #include "../gltf_document.h" -#include "../gltf_state.h" -#include "core/config/project_settings.h" -#include "core/error/error_list.h" -#include "core/object/object.h" -#include "core/templates/vector.h" #include "editor/editor_file_dialog.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/gui/check_box.h" -#include "scene/main/node.h" String SceneExporterGLTFPlugin::get_name() const { return "ConvertGLTF2"; @@ -85,7 +77,7 @@ void SceneExporterGLTFPlugin::_gltf2_dialog_action(String p_file) { state.instantiate(); int32_t flags = 0; flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; - Error err = doc->append_from_scene(root, state, flags, 30.0f); + Error err = doc->append_from_scene(root, state, flags); if (err != OK) { ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err))); } diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h index 5af46bc752..66fd27b449 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h +++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h @@ -36,6 +36,8 @@ #include "editor/editor_plugin.h" #include "editor_scene_importer_gltf.h" +class EditorFileDialog; + class SceneExporterGLTFPlugin : public EditorPlugin { GDCLASS(SceneExporterGLTFPlugin, EditorPlugin); diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index ab52761e17..4dafa746bc 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -33,7 +33,6 @@ #ifdef TOOLS_ENABLED #include "../gltf_document.h" -#include "../gltf_state.h" #include "core/config/project_settings.h" #include "editor/editor_file_dialog.h" @@ -41,8 +40,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "main/main.h" -#include "scene/main/node.h" -#include "scene/resources/animation.h" +#include "scene/gui/line_edit.h" #ifdef WINDOWS_ENABLED // Code by Pedro Estebanez (https://github.com/godotengine/godot/pull/59766) @@ -58,7 +56,7 @@ void EditorSceneFormatImporterBlend::get_extensions(List<String> *r_extensions) } Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { // Get global paths for source and sink. @@ -77,20 +75,19 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ } else { parameters_arg += "export_extras=False,"; } - if (p_options.has(SNAME("blender/meshes/skins")) && p_options[SNAME("blender/meshes/skins")]) { + if (p_options.has(SNAME("blender/meshes/skins"))) { int32_t skins = p_options["blender/meshes/skins"]; if (skins == BLEND_BONE_INFLUENCES_NONE) { - parameters_arg += "export_all_influences=False,"; + parameters_arg += "export_skins=False,"; } else if (skins == BLEND_BONE_INFLUENCES_COMPATIBLE) { - parameters_arg += "export_all_influences=False,"; + parameters_arg += "export_all_influences=False,export_skins=True,"; } else if (skins == BLEND_BONE_INFLUENCES_ALL) { - parameters_arg += "export_all_influences=True,"; + parameters_arg += "export_all_influences=True,export_skins=True,"; } - parameters_arg += "export_skins=True,"; } else { parameters_arg += "export_skins=False,"; } - if (p_options.has(SNAME("blender/materials/export_materials")) && p_options[SNAME("blender/materials/export_materials")]) { + if (p_options.has(SNAME("blender/materials/export_materials"))) { int32_t exports = p_options["blender/materials/export_materials"]; if (exports == BLEND_MATERIAL_EXPORT_PLACEHOLDER) { parameters_arg += "export_materials='PLACEHOLDER',"; @@ -115,7 +112,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ } else { parameters_arg += "export_colors=False,"; } - if (p_options.has(SNAME("blender/nodes/visible")) && p_options[SNAME("blender/nodes/visible")]) { + if (p_options.has(SNAME("blender/nodes/visible"))) { int32_t visible = p_options["blender/nodes/visible"]; if (visible == BLEND_VISIBLE_VISIBLE_ONLY) { parameters_arg += "use_visible=True,"; @@ -180,13 +177,13 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ "export_format='GLTF_SEPARATE'," "export_yup=True," + parameters_arg; - String script = + String export_script = String("import bpy, sys;") + "print('Blender 3.0 or higher is required.', file=sys.stderr) if bpy.app.version < (3, 0, 0) else None;" + vformat("bpy.ops.wm.open_mainfile(filepath='%s');", source_global) + unpack_all + vformat("bpy.ops.export_scene.gltf(export_keep_originals=True,%s);", common_args); - print_verbose(script); + print_verbose(export_script); // Run script with configured Blender binary. @@ -201,7 +198,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ List<String> args; args.push_back("--background"); args.push_back("--python-expr"); - args.push_back(script); + args.push_back(export_script); String standard_out; int ret; @@ -228,14 +225,14 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ if (p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")]) { base_dir = sink.get_base_dir(); } - Error err = gltf->append_from_file(sink.get_basename() + ".gltf", state, p_flags, p_bake_fps, base_dir); + Error err = gltf->append_from_file(sink.get_basename() + ".gltf", state, p_flags, base_dir); if (err != OK) { if (r_err) { *r_err = FAILED; } return nullptr; } - return gltf->generate_scene(state, p_bake_fps); + return gltf->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"]); } Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, @@ -261,7 +258,7 @@ void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, Li #define ADD_OPTION_ENUM(PATH, ENUM_HINT, VALUE) \ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, SNAME(PATH), PROPERTY_HINT_ENUM, ENUM_HINT), VALUE)); - ADD_OPTION_ENUM("blender/nodes/visible", "Visible Only,Renderable,All", BLEND_VISIBLE_ALL); + ADD_OPTION_ENUM("blender/nodes/visible", "All,Visible Only,Renderable", BLEND_VISIBLE_ALL); ADD_OPTION_BOOL("blender/nodes/punctual_lights", true); ADD_OPTION_BOOL("blender/nodes/cameras", true); ADD_OPTION_BOOL("blender/nodes/custom_properties", true); @@ -350,9 +347,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"); - String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path"); - - if (blend_enabled && !_test_blender_path(blender_path)) { + if (blend_enabled && !_test_blender_path(EDITOR_GET("filesystem/import/blender/blender3_path").operator String())) { // Intending to import Blender, but blend not configured. return true; } diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h index dd1c1b9889..fe687f19fc 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.h +++ b/modules/gltf/editor/editor_scene_importer_blend.h @@ -45,9 +45,9 @@ class EditorSceneFormatImporterBlend : public EditorSceneFormatImporter { public: enum { + BLEND_VISIBLE_ALL, BLEND_VISIBLE_VISIBLE_ONLY, - BLEND_VISIBLE_RENDERABLE, - BLEND_VISIBLE_ALL + BLEND_VISIBLE_RENDERABLE }; enum { BLEND_BONE_INFLUENCES_NONE, @@ -66,7 +66,7 @@ public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; virtual Node *import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override; virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) override; diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp index 017a44cccf..27e0052c1a 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.cpp +++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp @@ -33,12 +33,10 @@ #ifdef TOOLS_ENABLED #include "../gltf_document.h" -#include "../gltf_state.h" #include "core/config/project_settings.h" #include "editor/editor_settings.h" -#include "scene/main/node.h" -#include "scene/resources/animation.h" +#include "main/main.h" uint32_t EditorSceneFormatImporterFBX::get_import_flags() const { return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION; @@ -49,7 +47,7 @@ void EditorSceneFormatImporterFBX::get_extensions(List<String> *r_extensions) co } Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { // Get global paths for source and sink. @@ -95,14 +93,14 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t Ref<GLTFState> state; state.instantiate(); print_verbose(vformat("glTF path: %s", sink)); - Error err = gltf->append_from_file(sink, state, p_flags, p_bake_fps); + Error err = gltf->append_from_file(sink, state, p_flags); if (err != OK) { if (r_err) { *r_err = FAILED; } return nullptr; } - return gltf->generate_scene(state, p_bake_fps); + return gltf->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"]); } Variant EditorSceneFormatImporterFBX::get_option_visibility(const String &p_path, bool p_for_animation, @@ -114,4 +112,30 @@ void EditorSceneFormatImporterFBX::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) { } +bool EditorFileSystemImportFormatSupportQueryFBX::is_active() const { + String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path"); + return !FileAccess::exists(fbx2gltf_path); +} + +Vector<String> EditorFileSystemImportFormatSupportQueryFBX::get_file_extensions() const { + Vector<String> ret; + ret.push_back("fbx"); + return ret; +} + +bool EditorFileSystemImportFormatSupportQueryFBX::query() { + FBXImporterManager::get_singleton()->show_dialog(true); + + while (true) { + OS::get_singleton()->delay_usec(1); + DisplayServer::get_singleton()->process_events(); + Main::iteration(); + if (!FBXImporterManager::get_singleton()->is_visible()) { + break; + } + } + + return false; +} + #endif // TOOLS_ENABLED diff --git a/modules/gltf/editor/editor_scene_importer_fbx.h b/modules/gltf/editor/editor_scene_importer_fbx.h index b0039b1c8f..82179cc460 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.h +++ b/modules/gltf/editor/editor_scene_importer_fbx.h @@ -33,6 +33,8 @@ #ifdef TOOLS_ENABLED +#include "editor/editor_file_system.h" +#include "editor/fbx_importer_manager.h" #include "editor/import/resource_importer_scene.h" class Animation; @@ -45,7 +47,7 @@ public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; virtual Node *import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override; virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) override; @@ -53,6 +55,15 @@ public: const HashMap<StringName, Variant> &p_options) override; }; +class EditorFileSystemImportFormatSupportQueryFBX : public EditorFileSystemImportFormatSupportQuery { + GDCLASS(EditorFileSystemImportFormatSupportQueryFBX, EditorFileSystemImportFormatSupportQuery); + +public: + virtual bool is_active() const override; + virtual Vector<String> get_file_extensions() const override; + virtual bool query() override; +}; + #endif // TOOLS_ENABLED #endif // EDITOR_SCENE_IMPORTER_FBX_H diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp index 161808aade..bd1ba85abf 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp @@ -33,9 +33,6 @@ #include "editor_scene_importer_gltf.h" #include "../gltf_document.h" -#include "../gltf_state.h" - -#include "scene/resources/animation.h" uint32_t EditorSceneFormatImporterGLTF::get_import_flags() const { return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION; @@ -47,13 +44,13 @@ void EditorSceneFormatImporterGLTF::get_extensions(List<String> *r_extensions) c } Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { Ref<GLTFDocument> doc; doc.instantiate(); Ref<GLTFState> state; state.instantiate(); - Error err = doc->append_from_file(p_path, state, p_flags, p_bake_fps); + Error err = doc->append_from_file(p_path, state, p_flags); if (err != OK) { if (r_err) { *r_err = err; @@ -63,7 +60,12 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t if (p_options.has("animation/import")) { state->set_create_animations(bool(p_options["animation/import"])); } - return doc->generate_scene(state, p_bake_fps); + + if (p_options.has("animation/trimming")) { + return doc->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"]); + } else { + return doc->generate_scene(state, (float)p_options["animation/fps"], false); + } } #endif // TOOLS_ENABLED diff --git a/modules/gltf/editor/editor_scene_importer_gltf.h b/modules/gltf/editor/editor_scene_importer_gltf.h index b17a1e4eaa..c0582b26c1 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.h +++ b/modules/gltf/editor/editor_scene_importer_gltf.h @@ -33,9 +33,6 @@ #ifdef TOOLS_ENABLED -#include "../gltf_document_extension.h" -#include "../gltf_state.h" - #include "editor/import/resource_importer_scene.h" class Animation; @@ -48,7 +45,7 @@ public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; virtual Node *import_scene(const String &p_path, uint32_t p_flags, - const HashMap<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override; }; diff --git a/modules/gltf/extensions/SCsub b/modules/gltf/extensions/SCsub new file mode 100644 index 0000000000..ad214bb79c --- /dev/null +++ b/modules/gltf/extensions/SCsub @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_gltf = env_modules.Clone() + +# Godot source files +env_gltf.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/gltf/gltf_document_extension.cpp b/modules/gltf/extensions/gltf_document_extension.cpp index d0bd7651e0..630a62ba5c 100644 --- a/modules/gltf/gltf_document_extension.cpp +++ b/modules/gltf/extensions/gltf_document_extension.cpp @@ -31,78 +31,103 @@ #include "gltf_document_extension.h" void GLTFDocumentExtension::_bind_methods() { - GDVIRTUAL_BIND(_import_preflight, "state"); + // Import process. + GDVIRTUAL_BIND(_import_preflight, "state", "extensions"); + GDVIRTUAL_BIND(_get_supported_extensions); + GDVIRTUAL_BIND(_parse_node_extensions, "state", "gltf_node", "extensions"); + GDVIRTUAL_BIND(_generate_scene_node, "state", "gltf_node", "scene_parent"); GDVIRTUAL_BIND(_import_post_parse, "state"); GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node"); GDVIRTUAL_BIND(_import_post, "state", "root"); - GDVIRTUAL_BIND(_export_preflight, "root"); + // Export process. + GDVIRTUAL_BIND(_export_preflight, "state", "root"); + GDVIRTUAL_BIND(_convert_scene_node, "state", "gltf_node", "scene_node"); GDVIRTUAL_BIND(_export_node, "state", "gltf_node", "json", "node"); GDVIRTUAL_BIND(_export_post, "state"); } -Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) { - ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER); +// Import process. +Error GLTFDocumentExtension::import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions) { ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); int err = OK; - if (GDVIRTUAL_CALL(_import_post, p_state, p_root, err)) { - return Error(err); - } - return OK; + GDVIRTUAL_CALL(_import_preflight, p_state, p_extensions, err); + return Error(err); +} + +Vector<String> GLTFDocumentExtension::get_supported_extensions() { + Vector<String> ret; + GDVIRTUAL_CALL(_get_supported_extensions, ret); + return ret; } -Error GLTFDocumentExtension::import_preflight(Ref<GLTFState> p_state) { +Error GLTFDocumentExtension::parse_node_extensions(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &p_extensions) { ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER); int err = OK; - if (GDVIRTUAL_CALL(_import_preflight, p_state, err)) { - return Error(err); - } - return OK; + GDVIRTUAL_CALL(_parse_node_extensions, p_state, p_gltf_node, p_extensions, err); + return Error(err); +} + +Node3D *GLTFDocumentExtension::generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) { + ERR_FAIL_NULL_V(p_state, nullptr); + ERR_FAIL_NULL_V(p_gltf_node, nullptr); + ERR_FAIL_NULL_V(p_scene_parent, nullptr); + Node3D *ret_node = nullptr; + GDVIRTUAL_CALL(_generate_scene_node, p_state, p_gltf_node, p_scene_parent, ret_node); + return ret_node; } Error GLTFDocumentExtension::import_post_parse(Ref<GLTFState> p_state) { ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); int err = OK; - if (GDVIRTUAL_CALL(_import_post_parse, p_state, err)) { - return Error(err); - } - return OK; + GDVIRTUAL_CALL(_import_post_parse, p_state, err); + return Error(err); } -Error GLTFDocumentExtension::export_post(Ref<GLTFState> p_state) { +Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) { + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER); + int err = OK; + GDVIRTUAL_CALL(_import_node, p_state, p_gltf_node, r_dict, p_node, err); + return Error(err); +} + +Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) { + ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER); ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); int err = OK; - if (GDVIRTUAL_CALL(_export_post, p_state, err)) { - return Error(err); - } - return OK; + GDVIRTUAL_CALL(_import_post, p_state, p_root, err); + return Error(err); } -Error GLTFDocumentExtension::export_preflight(Node *p_root) { + +// Export process. +Error GLTFDocumentExtension::export_preflight(Ref<GLTFState> p_state, Node *p_root) { ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER); int err = OK; - if (GDVIRTUAL_CALL(_export_preflight, p_root, err)) { - return Error(err); - } - return OK; + GDVIRTUAL_CALL(_export_preflight, p_state, p_root, err); + return Error(err); } -Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) { +void GLTFDocumentExtension::convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node) { + ERR_FAIL_NULL(p_state); + ERR_FAIL_NULL(p_gltf_node); + ERR_FAIL_NULL(p_scene_node); + GDVIRTUAL_CALL(_convert_scene_node, p_state, p_gltf_node, p_scene_node); +} + +Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) { ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER); ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER); int err = OK; - if (GDVIRTUAL_CALL(_import_node, p_state, p_gltf_node, r_dict, p_node, err)) { - return Error(err); - } - return OK; + GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err); + return Error(err); } -Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) { +Error GLTFDocumentExtension::export_post(Ref<GLTFState> p_state) { ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); - ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER); - ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER); int err = OK; - if (GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err)) { - return Error(err); - } - return OK; + GDVIRTUAL_CALL(_export_post, p_state, err); + return Error(err); } diff --git a/modules/gltf/gltf_document_extension.h b/modules/gltf/extensions/gltf_document_extension.h index 0ef9109584..66cb9a3c33 100644 --- a/modules/gltf/gltf_document_extension.h +++ b/modules/gltf/extensions/gltf_document_extension.h @@ -31,8 +31,7 @@ #ifndef GLTF_DOCUMENT_EXTENSION_H #define GLTF_DOCUMENT_EXTENSION_H -#include "gltf_state.h" -#include "structures/gltf_node.h" +#include "../gltf_state.h" class GLTFDocumentExtension : public Resource { GDCLASS(GLTFDocumentExtension, Resource); @@ -41,18 +40,31 @@ protected: static void _bind_methods(); public: - virtual Error import_preflight(Ref<GLTFState> p_state); + // Import process. + virtual Error import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions); + virtual Vector<String> get_supported_extensions(); + virtual Error parse_node_extensions(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &p_extensions); + virtual Node3D *generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent); virtual Error import_post_parse(Ref<GLTFState> p_state); - virtual Error export_post(Ref<GLTFState> p_state); - virtual Error import_post(Ref<GLTFState> p_state, Node *p_node); - virtual Error export_preflight(Node *p_state); virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node); + virtual Error import_post(Ref<GLTFState> p_state, Node *p_node); + // Export process. + virtual Error export_preflight(Ref<GLTFState> p_state, Node *p_root); + virtual void convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node); virtual Error export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node); - GDVIRTUAL1R(int, _import_preflight, Ref<GLTFState>); + virtual Error export_post(Ref<GLTFState> p_state); + + // Import process. + GDVIRTUAL2R(int, _import_preflight, Ref<GLTFState>, Vector<String>); + GDVIRTUAL0R(Vector<String>, _get_supported_extensions); + GDVIRTUAL3R(int, _parse_node_extensions, Ref<GLTFState>, Ref<GLTFNode>, Dictionary); + GDVIRTUAL3R(Node3D *, _generate_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *); GDVIRTUAL1R(int, _import_post_parse, Ref<GLTFState>); GDVIRTUAL4R(int, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *); GDVIRTUAL2R(int, _import_post, Ref<GLTFState>, Node *); - GDVIRTUAL1R(int, _export_preflight, Node *); + // Export process. + GDVIRTUAL2R(int, _export_preflight, Ref<GLTFState>, Node *); + GDVIRTUAL3(_convert_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *); GDVIRTUAL4R(int, _export_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *); GDVIRTUAL1R(int, _export_post, Ref<GLTFState>); }; diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp index 1620900a04..cfa498af65 100644 --- a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp +++ b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp @@ -30,9 +30,7 @@ #include "gltf_document_extension_convert_importer_mesh.h" -#include "gltf_state.h" - -#include "core/error/error_macros.h" +#include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/resources/importer_mesh.h" diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.h b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.h index 00e664e73f..4fbfa0e066 100644 --- a/modules/gltf/gltf_document_extension_convert_importer_mesh.h +++ b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.h @@ -33,10 +33,6 @@ #include "gltf_document_extension.h" -#include "scene/3d/importer_mesh_instance_3d.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/resources/importer_mesh.h" - class GLTFDocumentExtensionConvertImporterMesh : public GLTFDocumentExtension { GDCLASS(GLTFDocumentExtensionConvertImporterMesh, GLTFDocumentExtension); diff --git a/modules/gltf/extensions/gltf_light.cpp b/modules/gltf/extensions/gltf_light.cpp index 6923c765cb..0379c62c9d 100644 --- a/modules/gltf/extensions/gltf_light.cpp +++ b/modules/gltf/extensions/gltf_light.cpp @@ -30,6 +30,8 @@ #include "gltf_light.h" +#include "scene/3d/light_3d.h" + void GLTFLight::_bind_methods() { ClassDB::bind_static_method("GLTFLight", D_METHOD("from_node", "light_node"), &GLTFLight::from_node); ClassDB::bind_method(D_METHOD("to_node"), &GLTFLight::to_node); @@ -142,18 +144,17 @@ Light3D *GLTFLight::to_node() const { light->set_color(color); return light; } - const float range = CLAMP(this->range, 0, 4096); if (light_type == "point") { OmniLight3D *light = memnew(OmniLight3D); light->set_param(OmniLight3D::PARAM_ENERGY, intensity); - light->set_param(OmniLight3D::PARAM_RANGE, range); + light->set_param(OmniLight3D::PARAM_RANGE, CLAMP(range, 0, 4096)); light->set_color(color); return light; } if (light_type == "spot") { SpotLight3D *light = memnew(SpotLight3D); light->set_param(SpotLight3D::PARAM_ENERGY, intensity); - light->set_param(SpotLight3D::PARAM_RANGE, range); + light->set_param(SpotLight3D::PARAM_RANGE, CLAMP(range, 0, 4096)); light->set_param(SpotLight3D::PARAM_SPOT_ANGLE, Math::rad_to_deg(outer_cone_angle)); light->set_color(color); // Line of best fit derived from guessing, see https://www.desmos.com/calculator/biiflubp8b diff --git a/modules/gltf/extensions/gltf_light.h b/modules/gltf/extensions/gltf_light.h index 04980e144c..85284f1d0e 100644 --- a/modules/gltf/extensions/gltf_light.h +++ b/modules/gltf/extensions/gltf_light.h @@ -31,9 +31,9 @@ #ifndef GLTF_LIGHT_H #define GLTF_LIGHT_H -#include "core/config/engine.h" #include "core/io/resource.h" -#include "scene/3d/light_3d.h" + +class Light3D; // https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual diff --git a/modules/gltf/extensions/gltf_spec_gloss.cpp b/modules/gltf/extensions/gltf_spec_gloss.cpp index 83af91bfcc..0645f31e01 100644 --- a/modules/gltf/extensions/gltf_spec_gloss.cpp +++ b/modules/gltf/extensions/gltf_spec_gloss.cpp @@ -30,6 +30,8 @@ #include "gltf_spec_gloss.h" +#include "core/io/image.h" + void GLTFSpecGloss::_bind_methods() { ClassDB::bind_method(D_METHOD("get_diffuse_img"), &GLTFSpecGloss::get_diffuse_img); ClassDB::bind_method(D_METHOD("set_diffuse_img", "diffuse_img"), &GLTFSpecGloss::set_diffuse_img); diff --git a/modules/gltf/extensions/gltf_spec_gloss.h b/modules/gltf/extensions/gltf_spec_gloss.h index 2b4d3ee609..56474acd03 100644 --- a/modules/gltf/extensions/gltf_spec_gloss.h +++ b/modules/gltf/extensions/gltf_spec_gloss.h @@ -31,9 +31,10 @@ #ifndef GLTF_SPEC_GLOSS_H #define GLTF_SPEC_GLOSS_H -#include "core/io/image.h" #include "core/io/resource.h" +class Image; + // KHR_materials_pbrSpecularGlossiness is an archived GLTF extension. // This means that it is deprecated and not recommended for new files. // However, it is still supported for loading old files. diff --git a/modules/gltf/gltf_defines.h b/modules/gltf/gltf_defines.h index c20c87f798..7b990e6573 100644 --- a/modules/gltf/gltf_defines.h +++ b/modules/gltf/gltf_defines.h @@ -36,9 +36,10 @@ // Godot classes used by GLTF headers. class BoneAttachment3D; class CSGShape3D; -class DirectionalLight3D; class GridMap; +class ImporterMeshInstance3D; class Light3D; +class MeshInstance3D; class MultiMeshInstance3D; class Skeleton3D; class Skin; @@ -58,6 +59,7 @@ class GLTFSkin; class GLTFSpecGloss; class GLTFState; class GLTFTexture; +class GLTFTextureSampler; // GLTF index aliases. using GLTFAccessorIndex = int; @@ -66,13 +68,14 @@ using GLTFBufferIndex = int; using GLTFBufferViewIndex = int; using GLTFCameraIndex = int; using GLTFImageIndex = int; +using GLTFLightIndex = int; using GLTFMaterialIndex = int; using GLTFMeshIndex = int; -using GLTFLightIndex = int; using GLTFNodeIndex = int; using GLTFSkeletonIndex = int; using GLTFSkinIndex = int; using GLTFTextureIndex = int; +using GLTFTextureSamplerIndex = int; enum GLTFType { TYPE_SCALAR, diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 61af58bda7..d858f76b28 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -31,33 +31,23 @@ #include "gltf_document.h" #include "extensions/gltf_spec_gloss.h" -#include "gltf_document_extension.h" -#include "gltf_document_extension_convert_importer_mesh.h" -#include "gltf_state.h" #include "core/crypto/crypto_core.h" -#include "core/error/error_macros.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" #include "core/io/file_access_memory.h" #include "core/io/json.h" #include "core/io/stream_peer.h" #include "core/math/disjoint_set.h" -#include "core/math/vector2.h" -#include "core/variant/dictionary.h" -#include "core/variant/typed_array.h" -#include "core/variant/variant.h" #include "core/version.h" #include "drivers/png/png_driver_common.h" -#include "scene/2d/node_2d.h" +#include "scene/3d/bone_attachment_3d.h" +#include "scene/3d/camera_3d.h" +#include "scene/3d/importer_mesh_instance_3d.h" +#include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/multimesh_instance_3d.h" -#include "scene/3d/node_3d.h" -#include "scene/animation/animation_player.h" -#include "scene/resources/importer_mesh.h" -#include "scene/resources/material.h" -#include "scene/resources/mesh.h" -#include "scene/resources/multimesh.h" +#include "scene/resources/skin.h" #include "scene/resources/surface_tool.h" #include "modules/modules_enabled.gen.h" // For csg, gridmap. @@ -113,140 +103,147 @@ static Ref<ImporterMesh> _mesh_to_importer_mesh(Ref<Mesh> p_mesh) { return importer_mesh; } -Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { - if (!state->buffers.size()) { - state->buffers.push_back(Vector<uint8_t>()); +Error GLTFDocument::_serialize(Ref<GLTFState> p_state, const String &p_path) { + if (!p_state->buffers.size()) { + p_state->buffers.push_back(Vector<uint8_t>()); } /* STEP CONVERT MESH INSTANCES */ - _convert_mesh_instances(state); + _convert_mesh_instances(p_state); /* STEP SERIALIZE CAMERAS */ - Error err = _serialize_cameras(state); + Error err = _serialize_cameras(p_state); if (err != OK) { return Error::FAILED; } /* STEP 3 CREATE SKINS */ - err = _serialize_skins(state); + err = _serialize_skins(p_state); if (err != OK) { return Error::FAILED; } /* STEP SERIALIZE MESHES (we have enough info now) */ - err = _serialize_meshes(state); + err = _serialize_meshes(p_state); if (err != OK) { return Error::FAILED; } /* STEP SERIALIZE TEXTURES */ - err = _serialize_materials(state); + err = _serialize_materials(p_state); + if (err != OK) { + return Error::FAILED; + } + + /* STEP SERIALIZE TEXTURE SAMPLERS */ + err = _serialize_texture_samplers(p_state); if (err != OK) { return Error::FAILED; } /* STEP SERIALIZE ANIMATIONS */ - err = _serialize_animations(state); + err = _serialize_animations(p_state); if (err != OK) { return Error::FAILED; } /* STEP SERIALIZE ACCESSORS */ - err = _encode_accessors(state); + err = _encode_accessors(p_state); if (err != OK) { return Error::FAILED; } /* STEP SERIALIZE IMAGES */ - err = _serialize_images(state, p_path); + err = _serialize_images(p_state, p_path); if (err != OK) { return Error::FAILED; } /* STEP SERIALIZE TEXTURES */ - err = _serialize_textures(state); + err = _serialize_textures(p_state); if (err != OK) { return Error::FAILED; } - for (GLTFBufferViewIndex i = 0; i < state->buffer_views.size(); i++) { - state->buffer_views.write[i]->buffer = 0; + for (GLTFBufferViewIndex i = 0; i < p_state->buffer_views.size(); i++) { + p_state->buffer_views.write[i]->buffer = 0; } /* STEP SERIALIZE BUFFER VIEWS */ - err = _encode_buffer_views(state); + err = _encode_buffer_views(p_state); if (err != OK) { return Error::FAILED; } /* STEP SERIALIZE NODES */ - err = _serialize_nodes(state); + err = _serialize_nodes(p_state); if (err != OK) { return Error::FAILED; } /* STEP SERIALIZE SCENE */ - err = _serialize_scenes(state); + err = _serialize_scenes(p_state); if (err != OK) { return Error::FAILED; } - /* STEP SERIALIZE SCENE */ - err = _serialize_lights(state); + /* STEP SERIALIZE LIGHTS */ + err = _serialize_lights(p_state); if (err != OK) { return Error::FAILED; } /* STEP SERIALIZE EXTENSIONS */ - err = _serialize_extensions(state); + err = _serialize_gltf_extensions(p_state); if (err != OK) { return Error::FAILED; } /* STEP SERIALIZE VERSION */ - err = _serialize_version(state); + err = _serialize_version(p_state); if (err != OK) { return Error::FAILED; } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); - err = ext->export_post(state); + err = ext->export_post(p_state); ERR_FAIL_COND_V(err != OK, err); } return OK; } -Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const { - Array extensions_used; - Array extensions_required; - if (!state->lights.is_empty()) { +Error GLTFDocument::_serialize_gltf_extensions(Ref<GLTFState> p_state) const { + Vector<String> extensions_used = p_state->extensions_used; + Vector<String> extensions_required = p_state->extensions_required; + if (!p_state->lights.is_empty()) { extensions_used.push_back("KHR_lights_punctual"); } - if (state->use_khr_texture_transform) { + if (p_state->use_khr_texture_transform) { extensions_used.push_back("KHR_texture_transform"); extensions_required.push_back("KHR_texture_transform"); } if (!extensions_used.is_empty()) { - state->json["extensionsUsed"] = extensions_used; + extensions_used.sort(); + p_state->json["extensionsUsed"] = extensions_used; } if (!extensions_required.is_empty()) { - state->json["extensionsRequired"] = extensions_required; + extensions_required.sort(); + p_state->json["extensionsRequired"] = extensions_required; } return OK; } -Error GLTFDocument::_serialize_scenes(Ref<GLTFState> state) { +Error GLTFDocument::_serialize_scenes(Ref<GLTFState> p_state) { Array scenes; const int loaded_scene = 0; - state->json["scene"] = loaded_scene; + p_state->json["scene"] = loaded_scene; - if (state->nodes.size()) { + if (p_state->nodes.size()) { Dictionary s; - if (!state->scene_name.is_empty()) { - s["name"] = state->scene_name; + if (!p_state->scene_name.is_empty()) { + s["name"] = p_state->scene_name; } Array nodes; @@ -254,21 +251,21 @@ Error GLTFDocument::_serialize_scenes(Ref<GLTFState> state) { s["nodes"] = nodes; scenes.push_back(s); } - state->json["scenes"] = scenes; + p_state->json["scenes"] = scenes; return OK; } -Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { +Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> p_state) { Error err; - Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); - if (f.is_null()) { + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err); + if (file.is_null()) { return err; } Vector<uint8_t> array; - array.resize(f->get_length()); - f->get_buffer(array.ptrw(), array.size()); + array.resize(file->get_length()); + file->get_buffer(array.ptrw(), array.size()); String text; text.parse_utf8((const char *)array.ptr(), array.size()); @@ -278,26 +275,26 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); return err; } - state->json = json.get_data(); + p_state->json = json.get_data(); return OK; } -Error GLTFDocument::_parse_glb(Ref<FileAccess> f, Ref<GLTFState> state) { - ERR_FAIL_NULL_V(f, ERR_INVALID_PARAMETER); - ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(f->get_position() != 0, ERR_FILE_CANT_READ); - uint32_t magic = f->get_32(); +Error GLTFDocument::_parse_glb(Ref<FileAccess> p_file, Ref<GLTFState> p_state) { + ERR_FAIL_NULL_V(p_file, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_file->get_position() != 0, ERR_FILE_CANT_READ); + uint32_t magic = p_file->get_32(); ERR_FAIL_COND_V(magic != 0x46546C67, ERR_FILE_UNRECOGNIZED); //glTF - f->get_32(); // version - f->get_32(); // length - uint32_t chunk_length = f->get_32(); - uint32_t chunk_type = f->get_32(); + p_file->get_32(); // version + p_file->get_32(); // length + uint32_t chunk_length = p_file->get_32(); + uint32_t chunk_type = p_file->get_32(); ERR_FAIL_COND_V(chunk_type != 0x4E4F534A, ERR_PARSE_ERROR); //JSON Vector<uint8_t> json_data; json_data.resize(chunk_length); - uint32_t len = f->get_buffer(json_data.ptrw(), chunk_length); + uint32_t len = p_file->get_buffer(json_data.ptrw(), chunk_length); ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT); String text; @@ -310,21 +307,21 @@ Error GLTFDocument::_parse_glb(Ref<FileAccess> f, Ref<GLTFState> state) { return err; } - state->json = json.get_data(); + p_state->json = json.get_data(); //data? - chunk_length = f->get_32(); - chunk_type = f->get_32(); + chunk_length = p_file->get_32(); + chunk_type = p_file->get_32(); - if (f->eof_reached()) { + if (p_file->eof_reached()) { return OK; //all good } ERR_FAIL_COND_V(chunk_type != 0x004E4942, ERR_PARSE_ERROR); //BIN - state->glb_data.resize(chunk_length); - len = f->get_buffer(state->glb_data.ptrw(), chunk_length); + p_state->glb_data.resize(chunk_length); + len = p_file->get_buffer(p_state->glb_data.ptrw(), chunk_length); ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT); return OK; @@ -397,89 +394,88 @@ static Vector<real_t> _xform_to_array(const Transform3D p_transform) { return array; } -Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) { +Error GLTFDocument::_serialize_nodes(Ref<GLTFState> p_state) { Array nodes; - for (int i = 0; i < state->nodes.size(); i++) { + for (int i = 0; i < p_state->nodes.size(); i++) { Dictionary node; - Ref<GLTFNode> n = state->nodes[i]; + Ref<GLTFNode> gltf_node = p_state->nodes[i]; Dictionary extensions; node["extensions"] = extensions; - if (!n->get_name().is_empty()) { - node["name"] = n->get_name(); + if (!gltf_node->get_name().is_empty()) { + node["name"] = gltf_node->get_name(); } - if (n->camera != -1) { - node["camera"] = n->camera; + if (gltf_node->camera != -1) { + node["camera"] = gltf_node->camera; } - if (n->light != -1) { + if (gltf_node->light != -1) { Dictionary lights_punctual; extensions["KHR_lights_punctual"] = lights_punctual; - lights_punctual["light"] = n->light; + lights_punctual["light"] = gltf_node->light; } - if (n->mesh != -1) { - node["mesh"] = n->mesh; + if (gltf_node->mesh != -1) { + node["mesh"] = gltf_node->mesh; } - if (n->skin != -1) { - node["skin"] = n->skin; + if (gltf_node->skin != -1) { + node["skin"] = gltf_node->skin; } - if (n->skeleton != -1 && n->skin < 0) { + if (gltf_node->skeleton != -1 && gltf_node->skin < 0) { } - if (n->xform != Transform3D()) { - node["matrix"] = _xform_to_array(n->xform); + if (gltf_node->xform != Transform3D()) { + node["matrix"] = _xform_to_array(gltf_node->xform); } - if (!n->rotation.is_equal_approx(Quaternion())) { - node["rotation"] = _quaternion_to_array(n->rotation); + if (!gltf_node->rotation.is_equal_approx(Quaternion())) { + node["rotation"] = _quaternion_to_array(gltf_node->rotation); } - if (!n->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) { - node["scale"] = _vec3_to_arr(n->scale); + if (!gltf_node->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) { + node["scale"] = _vec3_to_arr(gltf_node->scale); } - if (!n->position.is_zero_approx()) { - node["translation"] = _vec3_to_arr(n->position); + if (!gltf_node->position.is_zero_approx()) { + node["translation"] = _vec3_to_arr(gltf_node->position); } - if (n->children.size()) { + if (gltf_node->children.size()) { Array children; - for (int j = 0; j < n->children.size(); j++) { - children.push_back(n->children[j]); + for (int j = 0; j < gltf_node->children.size(); j++) { + children.push_back(gltf_node->children[j]); } node["children"] = children; } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); - ERR_CONTINUE(!state->scene_nodes.find(i)); - Error err = ext->export_node(state, n, state->json, state->scene_nodes[i]); + ERR_CONTINUE(!p_state->scene_nodes.find(i)); + Error err = ext->export_node(p_state, gltf_node, node, p_state->scene_nodes[i]); ERR_CONTINUE(err != OK); } nodes.push_back(node); } - state->json["nodes"] = nodes; + p_state->json["nodes"] = nodes; return OK; } -String GLTFDocument::_gen_unique_name(Ref<GLTFState> state, const String &p_name) { +String GLTFDocument::_gen_unique_name(Ref<GLTFState> p_state, const String &p_name) { const String s_name = p_name.validate_node_name(); - String name; + String u_name; int index = 1; while (true) { - name = s_name; + u_name = s_name; if (index > 1) { - name += itos(index); + u_name += itos(index); } - if (!state->unique_names.has(name)) { + if (!p_state->unique_names.has(u_name)) { break; } index++; } - state->unique_names.insert(name); + p_state->unique_names.insert(u_name); - return name; + return u_name; } String GLTFDocument::_sanitize_animation_name(const String &p_name) { @@ -487,71 +483,71 @@ String GLTFDocument::_sanitize_animation_name(const String &p_name) { // (See animation/animation_player.cpp::add_animation) // TODO: Consider adding invalid_characters or a validate_animation_name to animation_player to mirror Node. - String name = p_name.validate_node_name(); - name = name.replace(",", ""); - name = name.replace("[", ""); - return name; + String anim_name = p_name.validate_node_name(); + anim_name = anim_name.replace(",", ""); + anim_name = anim_name.replace("[", ""); + return anim_name; } -String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> state, const String &p_name) { +String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> p_state, const String &p_name) { const String s_name = _sanitize_animation_name(p_name); - String name; + String u_name; int index = 1; while (true) { - name = s_name; + u_name = s_name; if (index > 1) { - name += itos(index); + u_name += itos(index); } - if (!state->unique_animation_names.has(name)) { + if (!p_state->unique_animation_names.has(u_name)) { break; } index++; } - state->unique_animation_names.insert(name); + p_state->unique_animation_names.insert(u_name); - return name; + return u_name; } String GLTFDocument::_sanitize_bone_name(const String &p_name) { - String name = p_name; - name = name.replace(":", "_"); - name = name.replace("/", "_"); - return name; + String bone_name = p_name; + bone_name = bone_name.replace(":", "_"); + bone_name = bone_name.replace("/", "_"); + return bone_name; } -String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> state, const GLTFSkeletonIndex skel_i, const String &p_name) { +String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> p_state, const GLTFSkeletonIndex p_skel_i, const String &p_name) { String s_name = _sanitize_bone_name(p_name); if (s_name.is_empty()) { s_name = "bone"; } - String name; + String u_name; int index = 1; while (true) { - name = s_name; + u_name = s_name; if (index > 1) { - name += "_" + itos(index); + u_name += "_" + itos(index); } - if (!state->skeletons[skel_i]->unique_names.has(name)) { + if (!p_state->skeletons[p_skel_i]->unique_names.has(u_name)) { break; } index++; } - state->skeletons.write[skel_i]->unique_names.insert(name); + p_state->skeletons.write[p_skel_i]->unique_names.insert(u_name); - return name; + return u_name; } -Error GLTFDocument::_parse_scenes(Ref<GLTFState> state) { - ERR_FAIL_COND_V(!state->json.has("scenes"), ERR_FILE_CORRUPT); - const Array &scenes = state->json["scenes"]; +Error GLTFDocument::_parse_scenes(Ref<GLTFState> p_state) { + ERR_FAIL_COND_V(!p_state->json.has("scenes"), ERR_FILE_CORRUPT); + const Array &scenes = p_state->json["scenes"]; int loaded_scene = 0; - if (state->json.has("scene")) { - loaded_scene = state->json["scene"]; + if (p_state->json.has("scene")) { + loaded_scene = p_state->json["scene"]; } else { WARN_PRINT("The load-time scene is not defined in the glTF2 file. Picking the first scene."); } @@ -562,22 +558,22 @@ Error GLTFDocument::_parse_scenes(Ref<GLTFState> state) { ERR_FAIL_COND_V(!s.has("nodes"), ERR_UNAVAILABLE); const Array &nodes = s["nodes"]; for (int j = 0; j < nodes.size(); j++) { - state->root_nodes.push_back(nodes[j]); + p_state->root_nodes.push_back(nodes[j]); } if (s.has("name") && !String(s["name"]).is_empty() && !((String)s["name"]).begins_with("Scene")) { - state->scene_name = _gen_unique_name(state, s["name"]); + p_state->scene_name = _gen_unique_name(p_state, s["name"]); } else { - state->scene_name = _gen_unique_name(state, state->filename); + p_state->scene_name = _gen_unique_name(p_state, p_state->filename); } } return OK; } -Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) { - ERR_FAIL_COND_V(!state->json.has("nodes"), ERR_FILE_CORRUPT); - const Array &nodes = state->json["nodes"]; +Error GLTFDocument::_parse_nodes(Ref<GLTFState> p_state) { + ERR_FAIL_COND_V(!p_state->json.has("nodes"), ERR_FILE_CORRUPT); + const Array &nodes = p_state->json["nodes"]; for (int i = 0; i < nodes.size(); i++) { Ref<GLTFNode> node; node.instantiate(); @@ -621,6 +617,11 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) { node->light = light; } } + for (Ref<GLTFDocumentExtension> ext : document_extensions) { + ERR_CONTINUE(ext.is_null()); + Error err = ext->parse_node_extensions(p_state, node, extensions); + ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error " + itos(err) + " when parsing node extensions for node " + node->get_name() + " in file " + p_state->filename + ". Continuing."); + } } if (n.has("children")) { @@ -630,35 +631,35 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) { } } - state->nodes.push_back(node); + p_state->nodes.push_back(node); } // build the hierarchy - for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) { - for (int j = 0; j < state->nodes[node_i]->children.size(); j++) { - GLTFNodeIndex child_i = state->nodes[node_i]->children[j]; + for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) { + for (int j = 0; j < p_state->nodes[node_i]->children.size(); j++) { + GLTFNodeIndex child_i = p_state->nodes[node_i]->children[j]; - ERR_FAIL_INDEX_V(child_i, state->nodes.size(), ERR_FILE_CORRUPT); - ERR_CONTINUE(state->nodes[child_i]->parent != -1); //node already has a parent, wtf. + ERR_FAIL_INDEX_V(child_i, p_state->nodes.size(), ERR_FILE_CORRUPT); + ERR_CONTINUE(p_state->nodes[child_i]->parent != -1); //node already has a parent, wtf. - state->nodes.write[child_i]->parent = node_i; + p_state->nodes.write[child_i]->parent = node_i; } } - _compute_node_heights(state); + _compute_node_heights(p_state); return OK; } -void GLTFDocument::_compute_node_heights(Ref<GLTFState> state) { - state->root_nodes.clear(); - for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); ++node_i) { - Ref<GLTFNode> node = state->nodes[node_i]; +void GLTFDocument::_compute_node_heights(Ref<GLTFState> p_state) { + p_state->root_nodes.clear(); + for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); ++node_i) { + Ref<GLTFNode> node = p_state->nodes[node_i]; node->height = 0; GLTFNodeIndex current_i = node_i; while (current_i >= 0) { - const GLTFNodeIndex parent_i = state->nodes[current_i]->parent; + const GLTFNodeIndex parent_i = p_state->nodes[current_i]->parent; if (parent_i >= 0) { ++node->height; } @@ -666,7 +667,7 @@ void GLTFDocument::_compute_node_heights(Ref<GLTFState> state) { } if (node->height == 0) { - state->root_nodes.push_back(node_i); + p_state->root_nodes.push_back(node_i); } } } @@ -689,86 +690,86 @@ static Vector<uint8_t> _parse_base64_uri(const String &uri) { return buf; } -Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_path) { - print_verbose("glTF: Total buffers: " + itos(state->buffers.size())); +Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> p_state, const String &p_path) { + print_verbose("glTF: Total buffers: " + itos(p_state->buffers.size())); - if (!state->buffers.size()) { + if (!p_state->buffers.size()) { return OK; } Array buffers; - if (state->buffers.size()) { - Vector<uint8_t> buffer_data = state->buffers[0]; + if (p_state->buffers.size()) { + Vector<uint8_t> buffer_data = p_state->buffers[0]; Dictionary gltf_buffer; gltf_buffer["byteLength"] = buffer_data.size(); buffers.push_back(gltf_buffer); } - for (GLTFBufferIndex i = 1; i < state->buffers.size() - 1; i++) { - Vector<uint8_t> buffer_data = state->buffers[i]; + for (GLTFBufferIndex i = 1; i < p_state->buffers.size() - 1; i++) { + Vector<uint8_t> buffer_data = p_state->buffers[i]; Dictionary gltf_buffer; String filename = p_path.get_basename().get_file() + itos(i) + ".bin"; String path = p_path.get_base_dir() + "/" + filename; Error err; - Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err); - if (f.is_null()) { + Ref<FileAccess> file = FileAccess::open(path, FileAccess::WRITE, &err); + if (file.is_null()) { return err; } if (buffer_data.size() == 0) { return OK; } - f->create(FileAccess::ACCESS_RESOURCES); - f->store_buffer(buffer_data.ptr(), buffer_data.size()); + file->create(FileAccess::ACCESS_RESOURCES); + file->store_buffer(buffer_data.ptr(), buffer_data.size()); gltf_buffer["uri"] = filename; gltf_buffer["byteLength"] = buffer_data.size(); buffers.push_back(gltf_buffer); } - state->json["buffers"] = buffers; + p_state->json["buffers"] = buffers; return OK; } -Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_path) { - print_verbose("glTF: Total buffers: " + itos(state->buffers.size())); +Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> p_state, const String &p_path) { + print_verbose("glTF: Total buffers: " + itos(p_state->buffers.size())); - if (!state->buffers.size()) { + if (!p_state->buffers.size()) { return OK; } Array buffers; - for (GLTFBufferIndex i = 0; i < state->buffers.size(); i++) { - Vector<uint8_t> buffer_data = state->buffers[i]; + for (GLTFBufferIndex i = 0; i < p_state->buffers.size(); i++) { + Vector<uint8_t> buffer_data = p_state->buffers[i]; Dictionary gltf_buffer; String filename = p_path.get_basename().get_file() + itos(i) + ".bin"; String path = p_path.get_base_dir() + "/" + filename; Error err; - Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err); - if (f.is_null()) { + Ref<FileAccess> file = FileAccess::open(path, FileAccess::WRITE, &err); + if (file.is_null()) { return err; } if (buffer_data.size() == 0) { return OK; } - f->create(FileAccess::ACCESS_RESOURCES); - f->store_buffer(buffer_data.ptr(), buffer_data.size()); + file->create(FileAccess::ACCESS_RESOURCES); + file->store_buffer(buffer_data.ptr(), buffer_data.size()); gltf_buffer["uri"] = filename; gltf_buffer["byteLength"] = buffer_data.size(); buffers.push_back(gltf_buffer); } - state->json["buffers"] = buffers; + p_state->json["buffers"] = buffers; return OK; } -Error GLTFDocument::_parse_buffers(Ref<GLTFState> state, const String &p_base_path) { - if (!state->json.has("buffers")) { +Error GLTFDocument::_parse_buffers(Ref<GLTFState> p_state, const String &p_base_path) { + if (!p_state->json.has("buffers")) { return OK; } - const Array &buffers = state->json["buffers"]; + const Array &buffers = p_state->json["buffers"]; for (GLTFBufferIndex i = 0; i < buffers.size(); i++) { - if (i == 0 && state->glb_data.size()) { - state->buffers.push_back(state->glb_data); + if (i == 0 && p_state->glb_data.size()) { + p_state->buffers.push_back(p_state->glb_data); } else { const Dictionary &buffer = buffers[i]; @@ -787,29 +788,29 @@ Error GLTFDocument::_parse_buffers(Ref<GLTFState> state, const String &p_base_pa ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); uri = uri.uri_decode(); uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows. - buffer_data = FileAccess::get_file_as_array(uri); + buffer_data = FileAccess::get_file_as_bytes(uri); ERR_FAIL_COND_V_MSG(buffer.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri); } ERR_FAIL_COND_V(!buffer.has("byteLength"), ERR_PARSE_ERROR); int byteLength = buffer["byteLength"]; ERR_FAIL_COND_V(byteLength < buffer_data.size(), ERR_PARSE_ERROR); - state->buffers.push_back(buffer_data); + p_state->buffers.push_back(buffer_data); } } } - print_verbose("glTF: Total buffers: " + itos(state->buffers.size())); + print_verbose("glTF: Total buffers: " + itos(p_state->buffers.size())); return OK; } -Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> state) { +Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> p_state) { Array buffers; - for (GLTFBufferViewIndex i = 0; i < state->buffer_views.size(); i++) { + for (GLTFBufferViewIndex i = 0; i < p_state->buffer_views.size(); i++) { Dictionary d; - Ref<GLTFBufferView> buffer_view = state->buffer_views[i]; + Ref<GLTFBufferView> buffer_view = p_state->buffer_views[i]; d["buffer"] = buffer_view->buffer; d["byteLength"] = buffer_view->byte_length; @@ -827,19 +828,19 @@ Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> state) { ERR_FAIL_COND_V(!d.has("byteLength"), ERR_INVALID_DATA); buffers.push_back(d); } - print_verbose("glTF: Total buffer views: " + itos(state->buffer_views.size())); + print_verbose("glTF: Total buffer views: " + itos(p_state->buffer_views.size())); if (!buffers.size()) { return OK; } - state->json["bufferViews"] = buffers; + p_state->json["bufferViews"] = buffers; return OK; } -Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> state) { - if (!state->json.has("bufferViews")) { +Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> p_state) { + if (!p_state->json.has("bufferViews")) { return OK; } - const Array &buffers = state->json["bufferViews"]; + const Array &buffers = p_state->json["bufferViews"]; for (GLTFBufferViewIndex i = 0; i < buffers.size(); i++) { const Dictionary &d = buffers[i]; @@ -864,20 +865,20 @@ Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> state) { buffer_view->indices = target == GLTFDocument::ELEMENT_ARRAY_BUFFER; } - state->buffer_views.push_back(buffer_view); + p_state->buffer_views.push_back(buffer_view); } - print_verbose("glTF: Total buffer views: " + itos(state->buffer_views.size())); + print_verbose("glTF: Total buffer views: " + itos(p_state->buffer_views.size())); return OK; } -Error GLTFDocument::_encode_accessors(Ref<GLTFState> state) { +Error GLTFDocument::_encode_accessors(Ref<GLTFState> p_state) { Array accessors; - for (GLTFAccessorIndex i = 0; i < state->accessors.size(); i++) { + for (GLTFAccessorIndex i = 0; i < p_state->accessors.size(); i++) { Dictionary d; - Ref<GLTFAccessor> accessor = state->accessors[i]; + Ref<GLTFAccessor> accessor = p_state->accessors[i]; d["componentType"] = accessor->component_type; d["count"] = accessor->count; d["type"] = _get_accessor_type_name(accessor->type); @@ -923,9 +924,9 @@ Error GLTFDocument::_encode_accessors(Ref<GLTFState> state) { if (!accessors.size()) { return OK; } - state->json["accessors"] = accessors; - ERR_FAIL_COND_V(!state->json.has("accessors"), ERR_FILE_CORRUPT); - print_verbose("glTF: Total accessors: " + itos(state->accessors.size())); + p_state->json["accessors"] = accessors; + ERR_FAIL_COND_V(!p_state->json.has("accessors"), ERR_FILE_CORRUPT); + print_verbose("glTF: Total accessors: " + itos(p_state->accessors.size())); return OK; } @@ -984,11 +985,11 @@ GLTFType GLTFDocument::_get_type_from_str(const String &p_string) { ERR_FAIL_V(GLTFType::TYPE_SCALAR); } -Error GLTFDocument::_parse_accessors(Ref<GLTFState> state) { - if (!state->json.has("accessors")) { +Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) { + if (!p_state->json.has("accessors")) { return OK; } - const Array &accessors = state->json["accessors"]; + const Array &accessors = p_state->json["accessors"]; for (GLTFAccessorIndex i = 0; i < accessors.size(); i++) { const Dictionary &d = accessors[i]; @@ -1051,10 +1052,10 @@ Error GLTFDocument::_parse_accessors(Ref<GLTFState> state) { } } - state->accessors.push_back(accessor); + p_state->accessors.push_back(accessor); } - print_verbose("glTF: Total accessors: " + itos(state->accessors.size())); + print_verbose("glTF: Total accessors: " + itos(p_state->accessors.size())); return OK; } @@ -1099,33 +1100,33 @@ String GLTFDocument::_get_type_name(const GLTFType p_component) { return names[p_component]; } -Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, const int count, const GLTFType type, const int component_type, const bool normalized, const int byte_offset, const bool for_vertex, GLTFBufferViewIndex &r_accessor) { +Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_src, const int p_count, const GLTFType p_type, const int p_component_type, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex, GLTFBufferViewIndex &r_accessor) { const int component_count_for_type[7] = { 1, 2, 3, 4, 4, 9, 16 }; - const int component_count = component_count_for_type[type]; - const int component_size = _get_component_type_size(component_type); + const int component_count = component_count_for_type[p_type]; + const int component_size = _get_component_type_size(p_component_type); ERR_FAIL_COND_V(component_size == 0, FAILED); int skip_every = 0; int skip_bytes = 0; //special case of alignments, as described in spec - switch (component_type) { + switch (p_component_type) { case COMPONENT_TYPE_BYTE: case COMPONENT_TYPE_UNSIGNED_BYTE: { - if (type == TYPE_MAT2) { + if (p_type == TYPE_MAT2) { skip_every = 2; skip_bytes = 2; } - if (type == TYPE_MAT3) { + if (p_type == TYPE_MAT3) { skip_every = 3; skip_bytes = 1; } } break; case COMPONENT_TYPE_SHORT: case COMPONENT_TYPE_UNSIGNED_SHORT: { - if (type == TYPE_MAT3) { + if (p_type == TYPE_MAT3) { skip_every = 6; skip_bytes = 4; } @@ -1136,39 +1137,39 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, Ref<GLTFBufferView> bv; bv.instantiate(); - const uint32_t offset = bv->byte_offset = byte_offset; - Vector<uint8_t> &gltf_buffer = state->buffers.write[0]; + const uint32_t offset = bv->byte_offset = p_byte_offset; + Vector<uint8_t> &gltf_buffer = p_state->buffers.write[0]; - int stride = _get_component_type_size(component_type); - if (for_vertex && stride % 4) { + int stride = _get_component_type_size(p_component_type); + if (p_for_vertex && stride % 4) { stride += 4 - (stride % 4); //according to spec must be multiple of 4 } //use to debug - print_verbose("glTF: encoding type " + _get_type_name(type) + " component type: " + _get_component_type_name(component_type) + " stride: " + itos(stride) + " amount " + itos(count)); + print_verbose("glTF: encoding type " + _get_type_name(p_type) + " component type: " + _get_component_type_name(p_component_type) + " stride: " + itos(stride) + " amount " + itos(p_count)); - print_verbose("glTF: encoding accessor offset " + itos(byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(gltf_buffer.size()) + " view len " + itos(bv->byte_length)); + print_verbose("glTF: encoding accessor offset " + itos(p_byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(gltf_buffer.size()) + " view len " + itos(bv->byte_length)); - const int buffer_end = (stride * (count - 1)) + _get_component_type_size(component_type); + const int buffer_end = (stride * (p_count - 1)) + _get_component_type_size(p_component_type); // TODO define bv->byte_stride bv->byte_offset = gltf_buffer.size(); - switch (component_type) { + switch (p_component_type) { case COMPONENT_TYPE_BYTE: { Vector<int8_t> buffer; - buffer.resize(count * component_count); + buffer.resize(p_count * component_count); int32_t dst_i = 0; - for (int i = 0; i < count; i++) { + for (int i = 0; i < p_count; i++) { for (int j = 0; j < component_count; j++) { if (skip_every && j > 0 && (j % skip_every) == 0) { dst_i += skip_bytes; } - double d = *src; - if (normalized) { + double d = *p_src; + if (p_normalized) { buffer.write[dst_i] = d * 128.0; } else { buffer.write[dst_i] = d; } - src++; + p_src++; dst_i++; } } @@ -1179,20 +1180,20 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } break; case COMPONENT_TYPE_UNSIGNED_BYTE: { Vector<uint8_t> buffer; - buffer.resize(count * component_count); + buffer.resize(p_count * component_count); int32_t dst_i = 0; - for (int i = 0; i < count; i++) { + for (int i = 0; i < p_count; i++) { for (int j = 0; j < component_count; j++) { if (skip_every && j > 0 && (j % skip_every) == 0) { dst_i += skip_bytes; } - double d = *src; - if (normalized) { + double d = *p_src; + if (p_normalized) { buffer.write[dst_i] = d * 255.0; } else { buffer.write[dst_i] = d; } - src++; + p_src++; dst_i++; } } @@ -1201,20 +1202,20 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } break; case COMPONENT_TYPE_SHORT: { Vector<int16_t> buffer; - buffer.resize(count * component_count); + buffer.resize(p_count * component_count); int32_t dst_i = 0; - for (int i = 0; i < count; i++) { + for (int i = 0; i < p_count; i++) { for (int j = 0; j < component_count; j++) { if (skip_every && j > 0 && (j % skip_every) == 0) { dst_i += skip_bytes; } - double d = *src; - if (normalized) { + double d = *p_src; + if (p_normalized) { buffer.write[dst_i] = d * 32768.0; } else { buffer.write[dst_i] = d; } - src++; + p_src++; dst_i++; } } @@ -1225,20 +1226,20 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } break; case COMPONENT_TYPE_UNSIGNED_SHORT: { Vector<uint16_t> buffer; - buffer.resize(count * component_count); + buffer.resize(p_count * component_count); int32_t dst_i = 0; - for (int i = 0; i < count; i++) { + for (int i = 0; i < p_count; i++) { for (int j = 0; j < component_count; j++) { if (skip_every && j > 0 && (j % skip_every) == 0) { dst_i += skip_bytes; } - double d = *src; - if (normalized) { + double d = *p_src; + if (p_normalized) { buffer.write[dst_i] = d * 65535.0; } else { buffer.write[dst_i] = d; } - src++; + p_src++; dst_i++; } } @@ -1249,16 +1250,16 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } break; case COMPONENT_TYPE_INT: { Vector<int> buffer; - buffer.resize(count * component_count); + buffer.resize(p_count * component_count); int32_t dst_i = 0; - for (int i = 0; i < count; i++) { + for (int i = 0; i < p_count; i++) { for (int j = 0; j < component_count; j++) { if (skip_every && j > 0 && (j % skip_every) == 0) { dst_i += skip_bytes; } - double d = *src; + double d = *p_src; buffer.write[dst_i] = d; - src++; + p_src++; dst_i++; } } @@ -1269,16 +1270,16 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } break; case COMPONENT_TYPE_FLOAT: { Vector<float> buffer; - buffer.resize(count * component_count); + buffer.resize(p_count * component_count); int32_t dst_i = 0; - for (int i = 0; i < count; i++) { + for (int i = 0; i < p_count; i++) { for (int j = 0; j < component_count; j++) { if (skip_every && j > 0 && (j % skip_every) == 0) { dst_i += skip_bytes; } - double d = *src; + double d = *p_src; buffer.write[dst_i] = d; - src++; + p_src++; dst_i++; } } @@ -1291,53 +1292,53 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_INVALID_DATA); ERR_FAIL_COND_V((int)(offset + buffer_end) > gltf_buffer.size(), ERR_INVALID_DATA); - r_accessor = bv->buffer = state->buffer_views.size(); - state->buffer_views.push_back(bv); + r_accessor = bv->buffer = p_state->buffer_views.size(); + p_state->buffer_views.push_back(bv); return OK; } -Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> state, double *dst, const GLTFBufferViewIndex p_buffer_view, const int skip_every, const int skip_bytes, const int element_size, const int count, const GLTFType type, const int component_count, const int component_type, const int component_size, const bool normalized, const int byte_offset, const bool for_vertex) { - const Ref<GLTFBufferView> bv = state->buffer_views[p_buffer_view]; +Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> p_state, double *p_dst, const GLTFBufferViewIndex p_buffer_view, const int p_skip_every, const int p_skip_bytes, const int p_element_size, const int p_count, const GLTFType p_type, const int p_component_count, const int p_component_type, const int p_component_size, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex) { + const Ref<GLTFBufferView> bv = p_state->buffer_views[p_buffer_view]; - int stride = element_size; + int stride = p_element_size; if (bv->byte_stride != -1) { stride = bv->byte_stride; } - if (for_vertex && stride % 4) { + if (p_for_vertex && stride % 4) { stride += 4 - (stride % 4); //according to spec must be multiple of 4 } - ERR_FAIL_INDEX_V(bv->buffer, state->buffers.size(), ERR_PARSE_ERROR); + ERR_FAIL_INDEX_V(bv->buffer, p_state->buffers.size(), ERR_PARSE_ERROR); - const uint32_t offset = bv->byte_offset + byte_offset; - Vector<uint8_t> buffer = state->buffers[bv->buffer]; //copy on write, so no performance hit + const uint32_t offset = bv->byte_offset + p_byte_offset; + Vector<uint8_t> buffer = p_state->buffers[bv->buffer]; //copy on write, so no performance hit const uint8_t *bufptr = buffer.ptr(); //use to debug - print_verbose("glTF: type " + _get_type_name(type) + " component type: " + _get_component_type_name(component_type) + " stride: " + itos(stride) + " amount " + itos(count)); - print_verbose("glTF: accessor offset " + itos(byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(buffer.size()) + " view len " + itos(bv->byte_length)); + print_verbose("glTF: type " + _get_type_name(p_type) + " component type: " + _get_component_type_name(p_component_type) + " stride: " + itos(stride) + " amount " + itos(p_count)); + print_verbose("glTF: accessor offset " + itos(p_byte_offset) + " view offset: " + itos(bv->byte_offset) + " total buffer len: " + itos(buffer.size()) + " view len " + itos(bv->byte_length)); - const int buffer_end = (stride * (count - 1)) + element_size; + const int buffer_end = (stride * (p_count - 1)) + p_element_size; ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_PARSE_ERROR); ERR_FAIL_COND_V((int)(offset + buffer_end) > buffer.size(), ERR_PARSE_ERROR); //fill everything as doubles - for (int i = 0; i < count; i++) { + for (int i = 0; i < p_count; i++) { const uint8_t *src = &bufptr[offset + i * stride]; - for (int j = 0; j < component_count; j++) { - if (skip_every && j > 0 && (j % skip_every) == 0) { - src += skip_bytes; + for (int j = 0; j < p_component_count; j++) { + if (p_skip_every && j > 0 && (j % p_skip_every) == 0) { + src += p_skip_bytes; } double d = 0; - switch (component_type) { + switch (p_component_type) { case COMPONENT_TYPE_BYTE: { int8_t b = int8_t(*src); - if (normalized) { + if (p_normalized) { d = (double(b) / 128.0); } else { d = double(b); @@ -1345,7 +1346,7 @@ Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> state, double *dst, const } break; case COMPONENT_TYPE_UNSIGNED_BYTE: { uint8_t b = *src; - if (normalized) { + if (p_normalized) { d = (double(b) / 255.0); } else { d = double(b); @@ -1353,7 +1354,7 @@ Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> state, double *dst, const } break; case COMPONENT_TYPE_SHORT: { int16_t s = *(int16_t *)src; - if (normalized) { + if (p_normalized) { d = (double(s) / 32768.0); } else { d = double(s); @@ -1361,7 +1362,7 @@ Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> state, double *dst, const } break; case COMPONENT_TYPE_UNSIGNED_SHORT: { uint16_t s = *(uint16_t *)src; - if (normalized) { + if (p_normalized) { d = (double(s) / 65535.0); } else { d = double(s); @@ -1375,16 +1376,16 @@ Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> state, double *dst, const } break; } - *dst++ = d; - src += component_size; + *p_dst++ = d; + src += p_component_size; } } return OK; } -int GLTFDocument::_get_component_type_size(const int component_type) { - switch (component_type) { +int GLTFDocument::_get_component_type_size(const int p_component_type) { + switch (p_component_type) { case COMPONENT_TYPE_BYTE: case COMPONENT_TYPE_UNSIGNED_BYTE: return 1; @@ -1404,13 +1405,13 @@ int GLTFDocument::_get_component_type_size(const int component_type) { return 0; } -Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { +Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { //spec, for reference: //https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment - ERR_FAIL_INDEX_V(p_accessor, state->accessors.size(), Vector<double>()); + ERR_FAIL_INDEX_V(p_accessor, p_state->accessors.size(), Vector<double>()); - const Ref<GLTFAccessor> a = state->accessors[p_accessor]; + const Ref<GLTFAccessor> a = p_state->accessors[p_accessor]; const int component_count_for_type[7] = { 1, 2, 3, 4, 4, 9, 16 @@ -1455,9 +1456,9 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc double *dst = dst_buffer.ptrw(); if (a->buffer_view >= 0) { - ERR_FAIL_INDEX_V(a->buffer_view, state->buffer_views.size(), Vector<double>()); + ERR_FAIL_INDEX_V(a->buffer_view, p_state->buffer_views.size(), Vector<double>()); - const Error err = _decode_buffer_view(state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex); + const Error err = _decode_buffer_view(p_state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex); if (err != OK) { return Vector<double>(); } @@ -1474,14 +1475,14 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc indices.resize(a->sparse_count); const int indices_component_size = _get_component_type_size(a->sparse_indices_component_type); - Error err = _decode_buffer_view(state, indices.ptrw(), a->sparse_indices_buffer_view, 0, 0, indices_component_size, a->sparse_count, TYPE_SCALAR, 1, a->sparse_indices_component_type, indices_component_size, false, a->sparse_indices_byte_offset, false); + Error err = _decode_buffer_view(p_state, indices.ptrw(), a->sparse_indices_buffer_view, 0, 0, indices_component_size, a->sparse_count, TYPE_SCALAR, 1, a->sparse_indices_component_type, indices_component_size, false, a->sparse_indices_byte_offset, false); if (err != OK) { return Vector<double>(); } Vector<double> data; data.resize(component_count * a->sparse_count); - err = _decode_buffer_view(state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex); + err = _decode_buffer_view(p_state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex); if (err != OK) { return Vector<double>(); } @@ -1498,7 +1499,7 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc return dst_buffer; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> state, const Vector<int32_t> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> p_state, const Vector<int32_t> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1531,7 +1532,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> state, c Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; - int64_t size = state->buffers[0].size(); + int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_SCALAR; const int component_type = GLTFDocument::COMPONENT_TYPE_INT; @@ -1542,17 +1543,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> state, c accessor->type = type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } accessor->buffer_view = buffer_view_i; - state->accessors.push_back(accessor); - return state->accessors.size() - 1; + p_state->accessors.push_back(accessor); + return p_state->accessors.size() - 1; } -Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); +Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { + const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); Vector<int> ret; if (attribs.size() == 0) { @@ -1570,8 +1571,8 @@ Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> state, const G return ret; } -Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); +Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { + const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); Vector<float> ret; if (attribs.size() == 0) { @@ -1589,7 +1590,7 @@ Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> state, con return ret; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> state, const Vector<Vector2> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> p_state, const Vector<Vector2> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1615,7 +1616,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> state, c Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; - int64_t size = state->buffers[0].size(); + int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC2; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -1626,16 +1627,16 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> state, c accessor->type = type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } accessor->buffer_view = buffer_view_i; - state->accessors.push_back(accessor); - return state->accessors.size() - 1; + p_state->accessors.push_back(accessor); + return p_state->accessors.size() - 1; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> state, const Vector<Color> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1664,7 +1665,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> state, Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; - int64_t size = state->buffers[0].size(); + int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -1675,31 +1676,31 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> state, accessor->type = type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } accessor->buffer_view = buffer_view_i; - state->accessors.push_back(accessor); - return state->accessors.size() - 1; + p_state->accessors.push_back(accessor); + return p_state->accessors.size() - 1; } -void GLTFDocument::_calc_accessor_min_max(int i, const int element_count, Vector<double> &type_max, Vector<double> attribs, Vector<double> &type_min) { - if (i == 0) { - for (int32_t type_i = 0; type_i < element_count; type_i++) { - type_max.write[type_i] = attribs[(i * element_count) + type_i]; - type_min.write[type_i] = attribs[(i * element_count) + type_i]; +void GLTFDocument::_calc_accessor_min_max(int p_i, const int p_element_count, Vector<double> &p_type_max, Vector<double> p_attribs, Vector<double> &p_type_min) { + if (p_i == 0) { + for (int32_t type_i = 0; type_i < p_element_count; type_i++) { + p_type_max.write[type_i] = p_attribs[(p_i * p_element_count) + type_i]; + p_type_min.write[type_i] = p_attribs[(p_i * p_element_count) + type_i]; } } - for (int32_t type_i = 0; type_i < element_count; type_i++) { - type_max.write[type_i] = MAX(attribs[(i * element_count) + type_i], type_max[type_i]); - type_min.write[type_i] = MIN(attribs[(i * element_count) + type_i], type_min[type_i]); - type_max.write[type_i] = _filter_number(type_max.write[type_i]); - type_min.write[type_i] = _filter_number(type_min.write[type_i]); + for (int32_t type_i = 0; type_i < p_element_count; type_i++) { + p_type_max.write[type_i] = MAX(p_attribs[(p_i * p_element_count) + type_i], p_type_max[type_i]); + p_type_min.write[type_i] = MIN(p_attribs[(p_i * p_element_count) + type_i], p_type_min[type_i]); + p_type_max.write[type_i] = _filter_number(p_type_max.write[type_i]); + p_type_min.write[type_i] = _filter_number(p_type_min.write[type_i]); } } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> state, const Vector<Color> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1729,7 +1730,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> state Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; - int64_t size = state->buffers[0].size(); + int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -1740,16 +1741,16 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> state accessor->type = type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } accessor->buffer_view = buffer_view_i; - state->accessors.push_back(accessor); - return state->accessors.size() - 1; + p_state->accessors.push_back(accessor); + return p_state->accessors.size() - 1; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state, const Vector<Color> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1776,7 +1777,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state, Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; - int64_t size = state->buffers[0].size(); + int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT; @@ -1787,16 +1788,16 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state, accessor->type = type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } accessor->buffer_view = buffer_view_i; - state->accessors.push_back(accessor); - return state->accessors.size() - 1; + p_state->accessors.push_back(accessor); + return p_state->accessors.size() - 1; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> state, const Vector<Quaternion> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> p_state, const Vector<Quaternion> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1825,7 +1826,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> s Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; - int64_t size = state->buffers[0].size(); + int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -1836,17 +1837,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> s accessor->type = type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } accessor->buffer_view = buffer_view_i; - state->accessors.push_back(accessor); - return state->accessors.size() - 1; + p_state->accessors.push_back(accessor); + return p_state->accessors.size() - 1; } -Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); +Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { + const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); Vector<Vector2> ret; if (attribs.size() == 0) { @@ -1865,7 +1866,7 @@ Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> state, con return ret; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> state, const Vector<real_t> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> p_state, const Vector<real_t> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1890,7 +1891,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> state, Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; - int64_t size = state->buffers[0].size(); + int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_SCALAR; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -1901,16 +1902,16 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> state, accessor->type = type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } accessor->buffer_view = buffer_view_i; - state->accessors.push_back(accessor); - return state->accessors.size() - 1; + p_state->accessors.push_back(accessor); + return p_state->accessors.size() - 1; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, const Vector<Vector3> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> p_state, const Vector<Vector3> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1936,7 +1937,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, c Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; - int64_t size = state->buffers[0].size(); + int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_VEC3; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -1947,16 +1948,16 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, c accessor->type = type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } accessor->buffer_view = buffer_view_i; - state->accessors.push_back(accessor); - return state->accessors.size() - 1; + p_state->accessors.push_back(accessor); + return p_state->accessors.size() - 1; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, const Vector<Transform3D> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> p_state, const Vector<Transform3D> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -2004,7 +2005,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, Ref<GLTFAccessor> accessor; accessor.instantiate(); GLTFBufferIndex buffer_view_i; - int64_t size = state->buffers[0].size(); + int64_t size = p_state->buffers[0].size(); const GLTFType type = GLTFType::TYPE_MAT4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; @@ -2015,17 +2016,17 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, accessor->type = type; accessor->component_type = component_type; accessor->byte_offset = 0; - Error err = _encode_buffer_view(state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); + Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); if (err != OK) { return -1; } accessor->buffer_view = buffer_view_i; - state->accessors.push_back(accessor); - return state->accessors.size() - 1; + p_state->accessors.push_back(accessor); + return p_state->accessors.size() - 1; } -Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); +Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { + const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); Vector<Vector3> ret; if (attribs.size() == 0) { @@ -2044,15 +2045,15 @@ Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> state, con return ret; } -Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); +Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { + const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); Vector<Color> ret; if (attribs.size() == 0) { return ret; } - const int type = state->accessors[p_accessor]->type; + const int type = p_state->accessors[p_accessor]->type; ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret); int vec_len = 3; if (type == TYPE_VEC4) { @@ -2070,8 +2071,8 @@ Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> state, cons } return ret; } -Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); +Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { + const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); Vector<Quaternion> ret; if (attribs.size() == 0) { @@ -2089,8 +2090,8 @@ Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(Ref<GLTFState> s } return ret; } -Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); +Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { + const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); Vector<Transform2D> ret; if (attribs.size() == 0) { @@ -2106,8 +2107,8 @@ Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> sta return ret; } -Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); +Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { + const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); Vector<Basis> ret; if (attribs.size() == 0) { @@ -2124,8 +2125,8 @@ Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, cons return ret; } -Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); +Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { + const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); Vector<Transform3D> ret; if (attribs.size() == 0) { @@ -2143,15 +2144,15 @@ Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state return ret; } -Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { +Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) { Array meshes; - for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < state->meshes.size(); gltf_mesh_i++) { + for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < p_state->meshes.size(); gltf_mesh_i++) { print_verbose("glTF: Serializing mesh: " + itos(gltf_mesh_i)); - Ref<ImporterMesh> import_mesh = state->meshes.write[gltf_mesh_i]->get_mesh(); + Ref<ImporterMesh> import_mesh = p_state->meshes.write[gltf_mesh_i]->get_mesh(); if (import_mesh.is_null()) { continue; } - Array instance_materials = state->meshes.write[gltf_mesh_i]->get_instance_materials(); + Array instance_materials = p_state->meshes.write[gltf_mesh_i]->get_instance_materials(); Array primitives; Dictionary gltf_mesh; Array target_names; @@ -2204,7 +2205,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { { Vector<Vector3> a = array[Mesh::ARRAY_VERTEX]; ERR_FAIL_COND_V(!a.size(), ERR_INVALID_DATA); - attributes["POSITION"] = _encode_accessor_as_vec3(state, a, true); + attributes["POSITION"] = _encode_accessor_as_vec3(p_state, a, true); vertex_num = a.size(); } { @@ -2221,7 +2222,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { out.a = a[(i * 4) + 3]; attribs.write[i] = out; } - attributes["TANGENT"] = _encode_accessor_as_color(state, attribs, true); + attributes["TANGENT"] = _encode_accessor_as_color(p_state, attribs, true); } } { @@ -2233,19 +2234,19 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { for (int i = 0; i < ret_size; i++) { attribs.write[i] = Vector3(a[i]).normalized(); } - attributes["NORMAL"] = _encode_accessor_as_vec3(state, attribs, true); + attributes["NORMAL"] = _encode_accessor_as_vec3(p_state, attribs, true); } } { Vector<Vector2> a = array[Mesh::ARRAY_TEX_UV]; if (a.size()) { - attributes["TEXCOORD_0"] = _encode_accessor_as_vec2(state, a, true); + attributes["TEXCOORD_0"] = _encode_accessor_as_vec2(p_state, a, true); } } { Vector<Vector2> a = array[Mesh::ARRAY_TEX_UV2]; if (a.size()) { - attributes["TEXCOORD_1"] = _encode_accessor_as_vec2(state, a, true); + attributes["TEXCOORD_1"] = _encode_accessor_as_vec2(p_state, a, true); } } for (int custom_i = 0; custom_i < 3; custom_i++) { @@ -2274,7 +2275,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { if (!attributes.has(gltf_texcoord_key)) { Vector<Vector2> empty; empty.resize(vertex_num); - attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(state, empty, true); + attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, empty, true); } } @@ -2295,25 +2296,25 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { } } gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i); - attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(state, first_channel, true); + attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, first_channel, true); gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i + 1); - attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(state, second_channel, true); + attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, second_channel, true); } } { Vector<Color> a = array[Mesh::ARRAY_COLOR]; if (a.size()) { - attributes["COLOR_0"] = _encode_accessor_as_color(state, a, true); + attributes["COLOR_0"] = _encode_accessor_as_color(p_state, a, true); } } HashMap<int, int> joint_i_to_bone_i; - for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) { + for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) { GLTFSkinIndex skin_i = -1; - if (state->nodes[node_i]->mesh == gltf_mesh_i) { - skin_i = state->nodes[node_i]->skin; + if (p_state->nodes[node_i]->mesh == gltf_mesh_i) { + skin_i = p_state->nodes[node_i]->skin; } if (skin_i != -1) { - joint_i_to_bone_i = state->skins[skin_i]->joint_i_to_bone_i; + joint_i_to_bone_i = p_state->skins[skin_i]->joint_i_to_bone_i; break; } } @@ -2333,7 +2334,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { attribs.write[array_i] = Color(joint_0, joint_1, joint_2, joint_3); } } - attributes["JOINTS_0"] = _encode_accessor_as_joints(state, attribs, true); + attributes["JOINTS_0"] = _encode_accessor_as_joints(p_state, attribs, true); } else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) { Vector<Color> joints_0; joints_0.resize(vertex_num); @@ -2354,8 +2355,8 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { joint_1.a = a[vertex_i * weights_8_count + 7]; joints_1.write[vertex_i] = joint_1; } - attributes["JOINTS_0"] = _encode_accessor_as_joints(state, joints_0, true); - attributes["JOINTS_1"] = _encode_accessor_as_joints(state, joints_1, true); + attributes["JOINTS_0"] = _encode_accessor_as_joints(p_state, joints_0, true); + attributes["JOINTS_1"] = _encode_accessor_as_joints(p_state, joints_1, true); } } { @@ -2368,7 +2369,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { for (int i = 0; i < vertex_count; i++) { attribs.write[i] = Color(a[(i * JOINT_GROUP_SIZE) + 0], a[(i * JOINT_GROUP_SIZE) + 1], a[(i * JOINT_GROUP_SIZE) + 2], a[(i * JOINT_GROUP_SIZE) + 3]); } - attributes["WEIGHTS_0"] = _encode_accessor_as_weights(state, attribs, true); + attributes["WEIGHTS_0"] = _encode_accessor_as_weights(p_state, attribs, true); } else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) { Vector<Color> weights_0; weights_0.resize(vertex_num); @@ -2389,8 +2390,8 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { weight_1.a = a[vertex_i * weights_8_count + 7]; weights_1.write[vertex_i] = weight_1; } - attributes["WEIGHTS_0"] = _encode_accessor_as_weights(state, weights_0, true); - attributes["WEIGHTS_1"] = _encode_accessor_as_weights(state, weights_1, true); + attributes["WEIGHTS_0"] = _encode_accessor_as_weights(p_state, weights_0, true); + attributes["WEIGHTS_1"] = _encode_accessor_as_weights(p_state, weights_1, true); } } { @@ -2403,7 +2404,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { SWAP(mesh_indices.write[k + 0], mesh_indices.write[k + 2]); } } - primitive["indices"] = _encode_accessor_as_ints(state, mesh_indices, true); + primitive["indices"] = _encode_accessor_as_ints(p_state, mesh_indices, true); } else { if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) { //generate indices because they need to be swapped for CW/CCW @@ -2422,7 +2423,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { generated_indices.write[k + 2] = k + 1; } } - primitive["indices"] = _encode_accessor_as_ints(state, generated_indices, true); + primitive["indices"] = _encode_accessor_as_ints(p_state, generated_indices, true); } } } @@ -2447,12 +2448,12 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { } } - t["POSITION"] = _encode_accessor_as_vec3(state, varr, true); + t["POSITION"] = _encode_accessor_as_vec3(p_state, varr, true); } Vector<Vector3> narr = array_morph[Mesh::ARRAY_NORMAL]; if (narr.size()) { - t["NORMAL"] = _encode_accessor_as_vec3(state, narr, true); + t["NORMAL"] = _encode_accessor_as_vec3(p_state, narr, true); } Vector<real_t> tarr = array_morph[Mesh::ARRAY_TANGENT]; if (tarr.size()) { @@ -2465,7 +2466,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { vec3.y = tarr[(i * 4) + 1]; vec3.z = tarr[(i * 4) + 2]; } - t["TANGENT"] = _encode_accessor_as_vec3(state, attribs, true); + t["TANGENT"] = _encode_accessor_as_vec3(p_state, attribs, true); } targets.push_back(t); } @@ -2475,19 +2476,19 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { if (surface_i < instance_materials.size()) { v = instance_materials.get(surface_i); } - Ref<BaseMaterial3D> mat = v; + Ref<Material> mat = v; if (!mat.is_valid()) { mat = import_mesh->get_surface_material(surface_i); } if (mat.is_valid()) { - HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex>::Iterator material_cache_i = state->material_cache.find(mat); + HashMap<Ref<Material>, GLTFMaterialIndex>::Iterator material_cache_i = p_state->material_cache.find(mat); if (material_cache_i && material_cache_i->value != -1) { primitive["material"] = material_cache_i->value; } else { - GLTFMaterialIndex mat_i = state->materials.size(); - state->materials.push_back(mat); + GLTFMaterialIndex mat_i = p_state->materials.size(); + p_state->materials.push_back(mat); primitive["material"] = mat_i; - state->material_cache.insert(mat, mat_i); + p_state->material_cache.insert(mat, mat_i); } } @@ -2504,8 +2505,8 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { weights.resize(target_names.size()); for (int name_i = 0; name_i < target_names.size(); name_i++) { real_t weight = 0.0; - if (name_i < state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) { - weight = state->meshes.write[gltf_mesh_i]->get_blend_weights()[name_i]; + if (name_i < p_state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) { + weight = p_state->meshes.write[gltf_mesh_i]->get_blend_weights()[name_i]; } weights[name_i] = weight; } @@ -2525,18 +2526,18 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { if (!meshes.size()) { return OK; } - state->json["meshes"] = meshes; + p_state->json["meshes"] = meshes; print_verbose("glTF: Total meshes: " + itos(meshes.size())); return OK; } -Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { - if (!state->json.has("meshes")) { +Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { + if (!p_state->json.has("meshes")) { return OK; } - Array meshes = state->json["meshes"]; + Array meshes = p_state->json["meshes"]; for (GLTFMeshIndex i = 0; i < meshes.size(); i++) { print_verbose("glTF: Parsing mesh: " + itos(i)); Dictionary d = meshes[i]; @@ -2555,7 +2556,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { if (d.has("name") && !String(d["name"]).is_empty()) { mesh_name = d["name"]; } - import_mesh->set_name(_gen_unique_name(state, vformat("%s_%s", state->scene_name, mesh_name))); + import_mesh->set_name(_gen_unique_name(p_state, vformat("%s_%s", p_state->scene_name, mesh_name))); for (int j = 0; j < primitives.size(); j++) { uint32_t flags = 0; @@ -2582,10 +2583,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { Mesh::PRIMITIVE_TRIANGLES, // 4 TRIANGLES Mesh::PRIMITIVE_TRIANGLE_STRIP, // 5 TRIANGLE_STRIP Mesh::PRIMITIVE_TRIANGLES, // 6 TRIANGLE_FAN fan not supported, should be converted -#ifndef _MSC_VER -#warning line loop and triangle fan are not supported and need to be converted to lines and triangles -#endif - + // TODO: Line loop and triangle fan are not supported and need to be converted to lines and triangles. }; primitive = primitives2[mode]; @@ -2594,21 +2592,21 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { ERR_FAIL_COND_V(!a.has("POSITION"), ERR_PARSE_ERROR); int32_t vertex_num = 0; if (a.has("POSITION")) { - PackedVector3Array vertices = _decode_accessor_as_vec3(state, a["POSITION"], true); + PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION"], true); array[Mesh::ARRAY_VERTEX] = vertices; vertex_num = vertices.size(); } if (a.has("NORMAL")) { - array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(state, a["NORMAL"], true); + array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(p_state, a["NORMAL"], true); } if (a.has("TANGENT")) { - array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(state, a["TANGENT"], true); + array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(p_state, a["TANGENT"], true); } if (a.has("TEXCOORD_0")) { - array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(state, a["TEXCOORD_0"], true); + array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_0"], true); } if (a.has("TEXCOORD_1")) { - array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(state, a["TEXCOORD_1"], true); + array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_1"], true); } for (int custom_i = 0; custom_i < 3; custom_i++) { Vector<float> cur_custom; @@ -2619,12 +2617,12 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { String gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i); int num_channels = 0; if (a.has(gltf_texcoord_key)) { - texcoord_first = _decode_accessor_as_vec2(state, a[gltf_texcoord_key], true); + texcoord_first = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true); num_channels = 2; } gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i + 1); if (a.has(gltf_texcoord_key)) { - texcoord_second = _decode_accessor_as_vec2(state, a[gltf_texcoord_key], true); + texcoord_second = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true); num_channels = 4; } if (!num_channels) { @@ -2665,15 +2663,15 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } } if (a.has("COLOR_0")) { - array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(state, a["COLOR_0"], true); + array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(p_state, a["COLOR_0"], true); has_vertex_color = true; } if (a.has("JOINTS_0") && !a.has("JOINTS_1")) { - array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(state, a["JOINTS_0"], true); + array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true); } else if (a.has("JOINTS_0") && a.has("JOINTS_1")) { - PackedInt32Array joints_0 = _decode_accessor_as_ints(state, a["JOINTS_0"], true); - PackedInt32Array joints_1 = _decode_accessor_as_ints(state, a["JOINTS_1"], true); - ERR_FAIL_COND_V(joints_0.size() != joints_0.size(), ERR_INVALID_DATA); + PackedInt32Array joints_0 = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true); + PackedInt32Array joints_1 = _decode_accessor_as_ints(p_state, a["JOINTS_1"], true); + ERR_FAIL_COND_V(joints_0.size() != joints_1.size(), ERR_INVALID_DATA); int32_t weight_8_count = JOINT_GROUP_SIZE * 2; Vector<int> joints; joints.resize(vertex_num * weight_8_count); @@ -2690,7 +2688,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { array[Mesh::ARRAY_BONES] = joints; } if (a.has("WEIGHTS_0") && !a.has("WEIGHTS_1")) { - Vector<float> weights = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true); + Vector<float> weights = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true); { //gltf does not seem to normalize the weights for some reason.. int wc = weights.size(); float *w = weights.ptrw(); @@ -2711,8 +2709,8 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } array[Mesh::ARRAY_WEIGHTS] = weights; } else if (a.has("WEIGHTS_0") && a.has("WEIGHTS_1")) { - Vector<float> weights_0 = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true); - Vector<float> weights_1 = _decode_accessor_as_floats(state, a["WEIGHTS_1"], true); + Vector<float> weights_0 = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true); + Vector<float> weights_1 = _decode_accessor_as_floats(p_state, a["WEIGHTS_1"], true); Vector<float> weights; ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA); int32_t weight_8_count = JOINT_GROUP_SIZE * 2; @@ -2757,7 +2755,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } if (p.has("indices")) { - Vector<int> indices = _decode_accessor_as_ints(state, p["indices"], false); + Vector<int> indices = _decode_accessor_as_ints(p_state, p["indices"], false); if (primitive == Mesh::PRIMITIVE_TRIANGLES) { //swap around indices, convert ccw to cw for front face @@ -2816,8 +2814,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { if (j == 0) { const Array &target_names = extras.has("targetNames") ? (Array)extras["targetNames"] : Array(); for (int k = 0; k < targets.size(); k++) { - const String name = k < target_names.size() ? (String)target_names[k] : String("morph_") + itos(k); - import_mesh->add_blend_shape(name); + import_mesh->add_blend_shape(k < target_names.size() ? (String)target_names[k] : String("morph_") + itos(k)); } } @@ -2832,7 +2829,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } if (t.has("POSITION")) { - Vector<Vector3> varr = _decode_accessor_as_vec3(state, t["POSITION"], true); + Vector<Vector3> varr = _decode_accessor_as_vec3(p_state, t["POSITION"], true); const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX]; const int size = src_varr.size(); ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR); @@ -2854,7 +2851,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { array_copy[Mesh::ARRAY_VERTEX] = varr; } if (t.has("NORMAL")) { - Vector<Vector3> narr = _decode_accessor_as_vec3(state, t["NORMAL"], true); + Vector<Vector3> narr = _decode_accessor_as_vec3(p_state, t["NORMAL"], true); const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL]; int size = src_narr.size(); ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR); @@ -2876,7 +2873,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { array_copy[Mesh::ARRAY_NORMAL] = narr; } if (t.has("TANGENT")) { - const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(state, t["TANGENT"], true); + const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(p_state, t["TANGENT"], true); const Vector<float> src_tangents = array[Mesh::ARRAY_TANGENT]; ERR_FAIL_COND_V(src_tangents.size() == 0, ERR_PARSE_ERROR); @@ -2932,16 +2929,18 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } } - Ref<BaseMaterial3D> mat; + Ref<Material> mat; String mat_name; - if (!state->discard_meshes_and_materials) { + if (!p_state->discard_meshes_and_materials) { if (p.has("material")) { const int material = p["material"]; - ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT); - Ref<BaseMaterial3D> mat3d = state->materials[material]; + ERR_FAIL_INDEX_V(material, p_state->materials.size(), ERR_FILE_CORRUPT); + Ref<Material> mat3d = p_state->materials[material]; ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT); - if (has_vertex_color) { - mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + + Ref<BaseMaterial3D> base_material = mat3d; + if (has_vertex_color && base_material.is_valid()) { + base_material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); } mat = mat3d; @@ -2949,7 +2948,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { Ref<StandardMaterial3D> mat3d; mat3d.instantiate(); if (has_vertex_color) { - mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); } mat = mat3d; } @@ -2978,22 +2977,22 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { mesh->set_blend_weights(blend_weights); mesh->set_mesh(import_mesh); - state->meshes.push_back(mesh); + p_state->meshes.push_back(mesh); } - print_verbose("glTF: Total meshes: " + itos(state->meshes.size())); + print_verbose("glTF: Total meshes: " + itos(p_state->meshes.size())); return OK; } -Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path) { +Error GLTFDocument::_serialize_images(Ref<GLTFState> p_state, const String &p_path) { Array images; - for (int i = 0; i < state->images.size(); i++) { + for (int i = 0; i < p_state->images.size(); i++) { Dictionary d; - ERR_CONTINUE(state->images[i].is_null()); + ERR_CONTINUE(p_state->images[i].is_null()); - Ref<Image> image = state->images[i]->get_image(); + Ref<Image> image = p_state->images[i]->get_image(); ERR_CONTINUE(image.is_null()); if (p_path.to_lower().ends_with("glb") || p_path.is_empty()) { @@ -3004,8 +3003,8 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path const GLTFBufferIndex bi = 0; bv->buffer = bi; - bv->byte_offset = state->buffers[bi].size(); - ERR_FAIL_INDEX_V(bi, state->buffers.size(), ERR_PARAMETER_RANGE_ERROR); + bv->byte_offset = p_state->buffers[bi].size(); + ERR_FAIL_INDEX_V(bi, p_state->buffers.size(), ERR_PARAMETER_RANGE_ERROR); Vector<uint8_t> buffer; Ref<ImageTexture> img_tex = image; @@ -3016,22 +3015,22 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path ERR_FAIL_COND_V_MSG(err, err, "Can't convert image to PNG."); bv->byte_length = buffer.size(); - state->buffers.write[bi].resize(state->buffers[bi].size() + bv->byte_length); - memcpy(&state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size()); - ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > state->buffers[bi].size(), ERR_FILE_CORRUPT); + p_state->buffers.write[bi].resize(p_state->buffers[bi].size() + bv->byte_length); + memcpy(&p_state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size()); + ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > p_state->buffers[bi].size(), ERR_FILE_CORRUPT); - state->buffer_views.push_back(bv); - bvi = state->buffer_views.size() - 1; + p_state->buffer_views.push_back(bv); + bvi = p_state->buffer_views.size() - 1; d["bufferView"] = bvi; d["mimeType"] = "image/png"; } else { ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER); - String name = state->images[i]->get_name(); - if (name.is_empty()) { - name = itos(i); + String img_name = p_state->images[i]->get_name(); + if (img_name.is_empty()) { + img_name = itos(i); } - name = _gen_unique_name(state, name); - name = name.pad_zeros(3) + ".png"; + img_name = _gen_unique_name(p_state, img_name); + img_name = img_name.pad_zeros(3) + ".png"; String texture_dir = "textures"; String path = p_path.get_base_dir(); String new_texture_dir = path + "/" + texture_dir; @@ -3039,31 +3038,31 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path if (!da->dir_exists(new_texture_dir)) { da->make_dir(new_texture_dir); } - image->save_png(new_texture_dir.path_join(name)); - d["uri"] = texture_dir.path_join(name).uri_encode(); + image->save_png(new_texture_dir.path_join(img_name)); + d["uri"] = texture_dir.path_join(img_name).uri_encode(); } images.push_back(d); } - print_verbose("Total images: " + itos(state->images.size())); + print_verbose("Total images: " + itos(p_state->images.size())); if (!images.size()) { return OK; } - state->json["images"] = images; + p_state->json["images"] = images; return OK; } -Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_path) { - ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER); - if (!state->json.has("images")) { +Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_path) { + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + if (!p_state->json.has("images")) { return OK; } // Ref: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#images - const Array &images = state->json["images"]; + const Array &images = p_state->json["images"]; for (int i = 0; i < images.size(); i++) { const Dictionary &d = images[i]; @@ -3101,7 +3100,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat !uri.begins_with("data:image/png;base64") && !uri.begins_with("data:image/jpeg;base64")) { WARN_PRINT(vformat("glTF: Image index '%d' uses an unsupported URI data type: %s. Skipping it.", i, uri)); - state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count. + p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count. continue; } data = _parse_base64_uri(uri); @@ -3126,23 +3125,23 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat // the material), so we do this only as fallback. Ref<Texture2D> texture = ResourceLoader::load(uri); if (texture.is_valid()) { - state->images.push_back(texture); + p_state->images.push_back(texture); continue; } else if (mimetype == "image/png" || mimetype == "image/jpeg") { // Fallback to loading as byte array. // This enables us to support the spec's requirement that we honor mimetype // regardless of file URI. - data = FileAccess::get_file_as_array(uri); + data = FileAccess::get_file_as_bytes(uri); if (data.size() == 0) { WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded as a buffer of MIME type '%s' from URI: %s. Skipping it.", i, mimetype, uri)); - state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count. + p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count. continue; } data_ptr = data.ptr(); data_size = data.size(); } else { WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded from URI: %s. Skipping it.", i, uri)); - state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count. + p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count. continue; } } @@ -3153,16 +3152,16 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat const GLTFBufferViewIndex bvi = d["bufferView"]; - ERR_FAIL_INDEX_V(bvi, state->buffer_views.size(), ERR_PARAMETER_RANGE_ERROR); + ERR_FAIL_INDEX_V(bvi, p_state->buffer_views.size(), ERR_PARAMETER_RANGE_ERROR); - Ref<GLTFBufferView> bv = state->buffer_views[bvi]; + Ref<GLTFBufferView> bv = p_state->buffer_views[bvi]; const GLTFBufferIndex bi = bv->buffer; - ERR_FAIL_INDEX_V(bi, state->buffers.size(), ERR_PARAMETER_RANGE_ERROR); + ERR_FAIL_INDEX_V(bi, p_state->buffers.size(), ERR_PARAMETER_RANGE_ERROR); - ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > state->buffers[bi].size(), ERR_FILE_CORRUPT); + ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > p_state->buffers[bi].size(), ERR_FILE_CORRUPT); - data_ptr = &state->buffers[bi][bv->byte_offset]; + data_ptr = &p_state->buffers[bi][bv->byte_offset]; data_size = bv->byte_length; } @@ -3195,41 +3194,46 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat // Now we've done our best, fix your scenes. if (img.is_null()) { ERR_PRINT(vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s.", i, mimetype)); - state->images.push_back(Ref<Texture2D>()); + p_state->images.push_back(Ref<Texture2D>()); continue; } - state->images.push_back(ImageTexture::create_from_image(img)); + p_state->images.push_back(ImageTexture::create_from_image(img)); } - print_verbose("glTF: Total images: " + itos(state->images.size())); + print_verbose("glTF: Total images: " + itos(p_state->images.size())); return OK; } -Error GLTFDocument::_serialize_textures(Ref<GLTFState> state) { - if (!state->textures.size()) { +Error GLTFDocument::_serialize_textures(Ref<GLTFState> p_state) { + if (!p_state->textures.size()) { return OK; } Array textures; - for (int32_t i = 0; i < state->textures.size(); i++) { + for (int32_t i = 0; i < p_state->textures.size(); i++) { Dictionary d; - Ref<GLTFTexture> t = state->textures[i]; + Ref<GLTFTexture> t = p_state->textures[i]; ERR_CONTINUE(t->get_src_image() == -1); d["source"] = t->get_src_image(); + + GLTFTextureSamplerIndex sampler_index = t->get_sampler(); + if (sampler_index != -1) { + d["sampler"] = sampler_index; + } textures.push_back(d); } - state->json["textures"] = textures; + p_state->json["textures"] = textures; return OK; } -Error GLTFDocument::_parse_textures(Ref<GLTFState> state) { - if (!state->json.has("textures")) { +Error GLTFDocument::_parse_textures(Ref<GLTFState> p_state) { + if (!p_state->json.has("textures")) { return OK; } - const Array &textures = state->json["textures"]; + const Array &textures = p_state->json["textures"]; for (GLTFTextureIndex i = 0; i < textures.size(); i++) { const Dictionary &d = textures[i]; @@ -3238,221 +3242,327 @@ Error GLTFDocument::_parse_textures(Ref<GLTFState> state) { Ref<GLTFTexture> t; t.instantiate(); t->set_src_image(d["source"]); - state->textures.push_back(t); + if (d.has("sampler")) { + t->set_sampler(d["sampler"]); + } else { + t->set_sampler(-1); + } + p_state->textures.push_back(t); } return OK; } -GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture) { +GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> p_state, Ref<Texture2D> p_texture, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) { ERR_FAIL_COND_V(p_texture.is_null(), -1); Ref<GLTFTexture> gltf_texture; gltf_texture.instantiate(); ERR_FAIL_COND_V(p_texture->get_image().is_null(), -1); - GLTFImageIndex gltf_src_image_i = state->images.size(); - state->images.push_back(p_texture); + GLTFImageIndex gltf_src_image_i = p_state->images.size(); + p_state->images.push_back(p_texture); gltf_texture->set_src_image(gltf_src_image_i); - GLTFTextureIndex gltf_texture_i = state->textures.size(); - state->textures.push_back(gltf_texture); + gltf_texture->set_sampler(_set_sampler_for_mode(p_state, p_filter_mode, p_repeats)); + GLTFTextureIndex gltf_texture_i = p_state->textures.size(); + p_state->textures.push_back(gltf_texture); return gltf_texture_i; } -Ref<Texture2D> GLTFDocument::_get_texture(Ref<GLTFState> state, const GLTFTextureIndex p_texture) { - ERR_FAIL_INDEX_V(p_texture, state->textures.size(), Ref<Texture2D>()); - const GLTFImageIndex image = state->textures[p_texture]->get_src_image(); +Ref<Texture2D> GLTFDocument::_get_texture(Ref<GLTFState> p_state, const GLTFTextureIndex p_texture) { + ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref<Texture2D>()); + const GLTFImageIndex image = p_state->textures[p_texture]->get_src_image(); - ERR_FAIL_INDEX_V(image, state->images.size(), Ref<Texture2D>()); + ERR_FAIL_INDEX_V(image, p_state->images.size(), Ref<Texture2D>()); - return state->images[image]; + return p_state->images[image]; } -Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { - Array materials; - for (int32_t i = 0; i < state->materials.size(); i++) { +GLTFTextureSamplerIndex GLTFDocument::_set_sampler_for_mode(Ref<GLTFState> p_state, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) { + for (int i = 0; i < p_state->texture_samplers.size(); ++i) { + if (p_state->texture_samplers[i]->get_filter_mode() == p_filter_mode) { + return i; + } + } + + GLTFTextureSamplerIndex gltf_sampler_i = p_state->texture_samplers.size(); + Ref<GLTFTextureSampler> gltf_sampler; + gltf_sampler.instantiate(); + gltf_sampler->set_filter_mode(p_filter_mode); + gltf_sampler->set_wrap_mode(p_repeats); + p_state->texture_samplers.push_back(gltf_sampler); + return gltf_sampler_i; +} + +Ref<GLTFTextureSampler> GLTFDocument::_get_sampler_for_texture(Ref<GLTFState> p_state, const GLTFTextureIndex p_texture) { + ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref<Texture2D>()); + const GLTFTextureSamplerIndex sampler = p_state->textures[p_texture]->get_sampler(); + + if (sampler == -1) { + return p_state->default_texture_sampler; + } else { + ERR_FAIL_INDEX_V(sampler, p_state->texture_samplers.size(), Ref<GLTFTextureSampler>()); + + return p_state->texture_samplers[sampler]; + } +} + +Error GLTFDocument::_serialize_texture_samplers(Ref<GLTFState> p_state) { + if (!p_state->texture_samplers.size()) { + return OK; + } + + Array samplers; + for (int32_t i = 0; i < p_state->texture_samplers.size(); ++i) { Dictionary d; + Ref<GLTFTextureSampler> s = p_state->texture_samplers[i]; + d["magFilter"] = s->get_mag_filter(); + d["minFilter"] = s->get_min_filter(); + d["wrapS"] = s->get_wrap_s(); + d["wrapT"] = s->get_wrap_t(); + samplers.push_back(d); + } + p_state->json["samplers"] = samplers; + + return OK; +} + +Error GLTFDocument::_parse_texture_samplers(Ref<GLTFState> p_state) { + p_state->default_texture_sampler.instantiate(); + p_state->default_texture_sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR); + p_state->default_texture_sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR); + p_state->default_texture_sampler->set_wrap_s(GLTFTextureSampler::WrapMode::REPEAT); + p_state->default_texture_sampler->set_wrap_t(GLTFTextureSampler::WrapMode::REPEAT); + + if (!p_state->json.has("samplers")) { + return OK; + } + + const Array &samplers = p_state->json["samplers"]; + for (int i = 0; i < samplers.size(); ++i) { + const Dictionary &d = samplers[i]; + + Ref<GLTFTextureSampler> sampler; + sampler.instantiate(); + + if (d.has("minFilter")) { + sampler->set_min_filter(d["minFilter"]); + } else { + sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR); + } + if (d.has("magFilter")) { + sampler->set_mag_filter(d["magFilter"]); + } else { + sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR); + } + + if (d.has("wrapS")) { + sampler->set_wrap_s(d["wrapS"]); + } else { + sampler->set_wrap_s(GLTFTextureSampler::WrapMode::DEFAULT); + } + + if (d.has("wrapT")) { + sampler->set_wrap_t(d["wrapT"]); + } else { + sampler->set_wrap_t(GLTFTextureSampler::WrapMode::DEFAULT); + } + + p_state->texture_samplers.push_back(sampler); + } + + return OK; +} - Ref<BaseMaterial3D> material = state->materials[i]; +Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { + Array materials; + for (int32_t i = 0; i < p_state->materials.size(); i++) { + Dictionary d; + Ref<Material> material = p_state->materials[i]; if (material.is_null()) { materials.push_back(d); continue; } if (!material->get_name().is_empty()) { - d["name"] = _gen_unique_name(state, material->get_name()); + d["name"] = _gen_unique_name(p_state, material->get_name()); } + + Ref<BaseMaterial3D> base_material = material; + if (base_material.is_null()) { + materials.push_back(d); + continue; + } + + Dictionary mr; { - Dictionary mr; - { - Array arr; - const Color c = material->get_albedo().srgb_to_linear(); - arr.push_back(c.r); - arr.push_back(c.g); - arr.push_back(c.b); - arr.push_back(c.a); - mr["baseColorFactor"] = arr; - } - { - Dictionary bct; - Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - GLTFTextureIndex gltf_texture_index = -1; + Array arr; + const Color c = base_material->get_albedo().srgb_to_linear(); + arr.push_back(c.r); + arr.push_back(c.g); + arr.push_back(c.b); + arr.push_back(c.a); + mr["baseColorFactor"] = arr; + } + { + Dictionary bct; + Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); + GLTFTextureIndex gltf_texture_index = -1; - if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { - albedo_texture->set_name(material->get_name() + "_albedo"); - gltf_texture_index = _set_texture(state, albedo_texture); - } - if (gltf_texture_index != -1) { - bct["index"] = gltf_texture_index; - Dictionary extensions = _serialize_texture_transform_uv1(material); - if (!extensions.is_empty()) { - bct["extensions"] = extensions; - state->use_khr_texture_transform = true; - } - mr["baseColorTexture"] = bct; - } + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { + albedo_texture->set_name(material->get_name() + "_albedo"); + gltf_texture_index = _set_texture(p_state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } - - mr["metallicFactor"] = material->get_metallic(); - mr["roughnessFactor"] = material->get_roughness(); - bool has_roughness = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); - bool has_ao = material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); - bool has_metalness = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); - if (has_ao || has_roughness || has_metalness) { - Dictionary mrt; - Ref<Texture2D> roughness_texture = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); - BaseMaterial3D::TextureChannel roughness_channel = material->get_roughness_texture_channel(); - Ref<Texture2D> metallic_texture = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); - BaseMaterial3D::TextureChannel metalness_channel = material->get_metallic_texture_channel(); - Ref<Texture2D> ao_texture = material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); - BaseMaterial3D::TextureChannel ao_channel = material->get_ao_texture_channel(); - Ref<ImageTexture> orm_texture; - orm_texture.instantiate(); - Ref<Image> orm_image; - orm_image.instantiate(); - int32_t height = 0; - int32_t width = 0; - Ref<Image> ao_image; - if (has_ao) { - height = ao_texture->get_height(); - width = ao_texture->get_width(); - ao_image = ao_texture->get_image(); - Ref<ImageTexture> img_tex = ao_image; - if (img_tex.is_valid()) { - ao_image = img_tex->get_image(); - } - if (ao_image->is_compressed()) { - ao_image->decompress(); - } + if (gltf_texture_index != -1) { + bct["index"] = gltf_texture_index; + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + bct["extensions"] = extensions; + p_state->use_khr_texture_transform = true; } - Ref<Image> roughness_image; - if (has_roughness) { - height = roughness_texture->get_height(); - width = roughness_texture->get_width(); - roughness_image = roughness_texture->get_image(); - Ref<ImageTexture> img_tex = roughness_image; - if (img_tex.is_valid()) { - roughness_image = img_tex->get_image(); - } - if (roughness_image->is_compressed()) { - roughness_image->decompress(); - } + mr["baseColorTexture"] = bct; + } + } + + mr["metallicFactor"] = base_material->get_metallic(); + mr["roughnessFactor"] = base_material->get_roughness(); + bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); + bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); + bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); + if (has_ao || has_roughness || has_metalness) { + Dictionary mrt; + Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); + BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); + Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); + BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); + Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); + BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); + Ref<ImageTexture> orm_texture; + orm_texture.instantiate(); + Ref<Image> orm_image; + orm_image.instantiate(); + int32_t height = 0; + int32_t width = 0; + Ref<Image> ao_image; + if (has_ao) { + height = ao_texture->get_height(); + width = ao_texture->get_width(); + ao_image = ao_texture->get_image(); + Ref<ImageTexture> img_tex = ao_image; + if (img_tex.is_valid()) { + ao_image = img_tex->get_image(); } - Ref<Image> metallness_image; - if (has_metalness) { - height = metallic_texture->get_height(); - width = metallic_texture->get_width(); - metallness_image = metallic_texture->get_image(); - Ref<ImageTexture> img_tex = metallness_image; - if (img_tex.is_valid()) { - metallness_image = img_tex->get_image(); - } - if (metallness_image->is_compressed()) { - metallness_image->decompress(); - } + if (ao_image->is_compressed()) { + ao_image->decompress(); } - Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { - height = albedo_texture->get_height(); - width = albedo_texture->get_width(); + } + Ref<Image> roughness_image; + if (has_roughness) { + height = roughness_texture->get_height(); + width = roughness_texture->get_width(); + roughness_image = roughness_texture->get_image(); + Ref<ImageTexture> img_tex = roughness_image; + if (img_tex.is_valid()) { + roughness_image = img_tex->get_image(); } - orm_image->create(width, height, false, Image::FORMAT_RGBA8); - if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { - ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + if (roughness_image->is_compressed()) { + roughness_image->decompress(); } - if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { - roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + Ref<Image> metallness_image; + if (has_metalness) { + height = metallic_texture->get_height(); + width = metallic_texture->get_width(); + metallness_image = metallic_texture->get_image(); + Ref<ImageTexture> img_tex = metallness_image; + if (img_tex.is_valid()) { + metallness_image = img_tex->get_image(); } - if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { - metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + if (metallness_image->is_compressed()) { + metallness_image->decompress(); } - for (int32_t h = 0; h < height; h++) { - for (int32_t w = 0; w < width; w++) { - Color c = Color(1.0f, 1.0f, 1.0f); - if (has_ao) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { - c.r = ao_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { - c.r = ao_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { - c.r = ao_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { - c.r = ao_image->get_pixel(w, h).a; - } + } + Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { + height = albedo_texture->get_height(); + width = albedo_texture->get_width(); + } + orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); + if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { + ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { + roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { + metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + for (int32_t h = 0; h < height; h++) { + for (int32_t w = 0; w < width; w++) { + Color c = Color(1.0f, 1.0f, 1.0f); + if (has_ao) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { + c.r = ao_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { + c.r = ao_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { + c.r = ao_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { + c.r = ao_image->get_pixel(w, h).a; } - if (has_roughness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).a; - } + } + if (has_roughness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).a; } - if (has_metalness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).a; - } + } + if (has_metalness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).a; } - orm_image->set_pixel(w, h, c); } + orm_image->set_pixel(w, h, c); } - orm_image->generate_mipmaps(); - orm_texture->set_image(orm_image); - GLTFTextureIndex orm_texture_index = -1; - if (has_ao || has_roughness || has_metalness) { - orm_texture->set_name(material->get_name() + "_orm"); - orm_texture_index = _set_texture(state, orm_texture); - } - if (has_ao) { - Dictionary occt; - occt["index"] = orm_texture_index; - d["occlusionTexture"] = occt; - } - if (has_roughness || has_metalness) { - mrt["index"] = orm_texture_index; - Dictionary extensions = _serialize_texture_transform_uv1(material); - if (!extensions.is_empty()) { - mrt["extensions"] = extensions; - state->use_khr_texture_transform = true; - } - mr["metallicRoughnessTexture"] = mrt; + } + orm_image->generate_mipmaps(); + orm_texture->set_image(orm_image); + GLTFTextureIndex orm_texture_index = -1; + if (has_ao || has_roughness || has_metalness) { + orm_texture->set_name(material->get_name() + "_orm"); + orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + } + if (has_ao) { + Dictionary occt; + occt["index"] = orm_texture_index; + d["occlusionTexture"] = occt; + } + if (has_roughness || has_metalness) { + mrt["index"] = orm_texture_index; + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + mrt["extensions"] = extensions; + p_state->use_khr_texture_transform = true; } + mr["metallicRoughnessTexture"] = mrt; } - d["pbrMetallicRoughness"] = mr; } - if (material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { + d["pbrMetallicRoughness"] = mr; + if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { Dictionary nt; Ref<ImageTexture> tex; tex.instantiate(); { - Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); + Ref<Texture2D> normal_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); if (normal_texture.is_valid()) { // Code for uncompressing RG normal maps Ref<Image> img = normal_texture->get_image(); @@ -3482,30 +3592,31 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { GLTFTextureIndex gltf_texture_index = -1; if (tex.is_valid() && tex->get_image().is_valid()) { tex->set_name(material->get_name() + "_normal"); - gltf_texture_index = _set_texture(state, tex); + gltf_texture_index = _set_texture(p_state, tex, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } - nt["scale"] = material->get_normal_scale(); + nt["scale"] = base_material->get_normal_scale(); if (gltf_texture_index != -1) { nt["index"] = gltf_texture_index; d["normalTexture"] = nt; } } - if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { - const Color c = material->get_emission().linear_to_srgb(); + if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { + const Color c = base_material->get_emission().linear_to_srgb(); Array arr; arr.push_back(c.r); arr.push_back(c.g); arr.push_back(c.b); d["emissiveFactor"] = arr; } - if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { + + if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { Dictionary et; - Ref<Texture2D> emission_texture = material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); + Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); GLTFTextureIndex gltf_texture_index = -1; if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) { emission_texture->set_name(material->get_name() + "_emission"); - gltf_texture_index = _set_texture(state, emission_texture); + gltf_texture_index = _set_texture(p_state, emission_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } if (gltf_texture_index != -1) { @@ -3513,33 +3624,36 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { d["emissiveTexture"] = et; } } - const bool ds = material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED; + + const bool ds = base_material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED; if (ds) { d["doubleSided"] = ds; } - if (material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) { + + if (base_material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) { d["alphaMode"] = "MASK"; - d["alphaCutoff"] = material->get_alpha_scissor_threshold(); - } else if (material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) { + d["alphaCutoff"] = base_material->get_alpha_scissor_threshold(); + } else if (base_material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) { d["alphaMode"] = "BLEND"; } + materials.push_back(d); } if (!materials.size()) { return OK; } - state->json["materials"] = materials; - print_verbose("Total materials: " + itos(state->materials.size())); + p_state->json["materials"] = materials; + print_verbose("Total materials: " + itos(p_state->materials.size())); return OK; } -Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { - if (!state->json.has("materials")) { +Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) { + if (!p_state->json.has("materials")) { return OK; } - const Array &materials = state->json["materials"]; + const Array &materials = p_state->json["materials"]; for (GLTFMaterialIndex i = 0; i < materials.size(); i++) { const Dictionary &d = materials[i]; @@ -3564,7 +3678,12 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (sgm.has("diffuseTexture")) { const Dictionary &diffuse_texture_dict = sgm["diffuseTexture"]; if (diffuse_texture_dict.has("index")) { - Ref<Texture2D> diffuse_texture = _get_texture(state, diffuse_texture_dict["index"]); + Ref<GLTFTextureSampler> diffuse_sampler = _get_sampler_for_texture(p_state, diffuse_texture_dict["index"]); + if (diffuse_sampler.is_valid()) { + material->set_texture_filter(diffuse_sampler->get_filter_mode()); + material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, diffuse_sampler->get_wrap_mode()); + } + Ref<Texture2D> diffuse_texture = _get_texture(p_state, diffuse_texture_dict["index"]); if (diffuse_texture.is_valid()) { spec_gloss->diffuse_img = diffuse_texture->get_image(); material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_texture); @@ -3592,7 +3711,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (sgm.has("specularGlossinessTexture")) { const Dictionary &spec_gloss_texture = sgm["specularGlossinessTexture"]; if (spec_gloss_texture.has("index")) { - const Ref<Texture2D> orig_texture = _get_texture(state, spec_gloss_texture["index"]); + const Ref<Texture2D> orig_texture = _get_texture(p_state, spec_gloss_texture["index"]); if (orig_texture.is_valid()) { spec_gloss->spec_gloss_img = orig_texture->get_image(); } @@ -3612,7 +3731,10 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (mr.has("baseColorTexture")) { const Dictionary &bct = mr["baseColorTexture"]; if (bct.has("index")) { - material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, _get_texture(state, bct["index"])); + Ref<GLTFTextureSampler> bct_sampler = _get_sampler_for_texture(p_state, bct["index"]); + material->set_texture_filter(bct_sampler->get_filter_mode()); + material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, bct_sampler->get_wrap_mode()); + material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, _get_texture(p_state, bct["index"])); } if (!mr.has("baseColorFactor")) { material->set_albedo(Color(1, 1, 1)); @@ -3635,7 +3757,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (mr.has("metallicRoughnessTexture")) { const Dictionary &bct = mr["metallicRoughnessTexture"]; if (bct.has("index")) { - const Ref<Texture2D> t = _get_texture(state, bct["index"]); + const Ref<Texture2D> t = _get_texture(p_state, bct["index"]); material->set_texture(BaseMaterial3D::TEXTURE_METALLIC, t); material->set_metallic_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_BLUE); material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, t); @@ -3653,7 +3775,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (d.has("normalTexture")) { const Dictionary &bct = d["normalTexture"]; if (bct.has("index")) { - material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(state, bct["index"])); + material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(p_state, bct["index"])); material->set_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING, true); } if (bct.has("scale")) { @@ -3663,7 +3785,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (d.has("occlusionTexture")) { const Dictionary &bct = d["occlusionTexture"]; if (bct.has("index")) { - material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(state, bct["index"])); + material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(p_state, bct["index"])); material->set_ao_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_RED); material->set_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION, true); } @@ -3681,7 +3803,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { if (d.has("emissiveTexture")) { const Dictionary &bct = d["emissiveTexture"]; if (bct.has("index")) { - material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(state, bct["index"])); + material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(p_state, bct["index"])); material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true); material->set_emission(Color(0, 0, 0)); } @@ -3706,48 +3828,54 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { } } } - state->materials.push_back(material); + p_state->materials.push_back(material); } - print_verbose("Total materials: " + itos(state->materials.size())); + print_verbose("Total materials: " + itos(p_state->materials.size())); return OK; } -void GLTFDocument::_set_texture_transform_uv1(const Dictionary &d, Ref<BaseMaterial3D> material) { - if (d.has("extensions")) { - const Dictionary &extensions = d["extensions"]; +void GLTFDocument::_set_texture_transform_uv1(const Dictionary &p_dict, Ref<BaseMaterial3D> p_material) { + if (p_dict.has("extensions")) { + const Dictionary &extensions = p_dict["extensions"]; if (extensions.has("KHR_texture_transform")) { - const Dictionary &texture_transform = extensions["KHR_texture_transform"]; - const Array &offset_arr = texture_transform["offset"]; - if (offset_arr.size() == 2) { - const Vector3 offset_vector3 = Vector3(offset_arr[0], offset_arr[1], 0.0f); - material->set_uv1_offset(offset_vector3); - } + if (p_material.is_valid()) { + const Dictionary &texture_transform = extensions["KHR_texture_transform"]; + const Array &offset_arr = texture_transform["offset"]; + if (offset_arr.size() == 2) { + const Vector3 offset_vector3 = Vector3(offset_arr[0], offset_arr[1], 0.0f); + p_material->set_uv1_offset(offset_vector3); + } - const Array &scale_arr = texture_transform["scale"]; - if (scale_arr.size() == 2) { - const Vector3 scale_vector3 = Vector3(scale_arr[0], scale_arr[1], 1.0f); - material->set_uv1_scale(scale_vector3); + const Array &scale_arr = texture_transform["scale"]; + if (scale_arr.size() == 2) { + const Vector3 scale_vector3 = Vector3(scale_arr[0], scale_arr[1], 1.0f); + p_material->set_uv1_scale(scale_vector3); + } } } } } void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Ref<BaseMaterial3D> p_material) { + if (r_spec_gloss.is_null()) { + return; + } if (r_spec_gloss->spec_gloss_img.is_null()) { return; } if (r_spec_gloss->diffuse_img.is_null()) { return; } - Ref<Image> rm_img; - rm_img.instantiate(); + if (p_material.is_null()) { + return; + } bool has_roughness = false; bool has_metal = false; p_material->set_roughness(1.0f); p_material->set_metallic(1.0f); - rm_img->create(r_spec_gloss->spec_gloss_img->get_width(), r_spec_gloss->spec_gloss_img->get_height(), false, Image::FORMAT_RGBA8); + Ref<Image> rm_img = Image::create_empty(r_spec_gloss->spec_gloss_img->get_width(), r_spec_gloss->spec_gloss_img->get_height(), false, Image::FORMAT_RGBA8); r_spec_gloss->spec_gloss_img->decompress(); if (r_spec_gloss->diffuse_img.is_valid()) { r_spec_gloss->diffuse_img->decompress(); @@ -3814,13 +3942,13 @@ void GLTFDocument::spec_gloss_to_metal_base_color(const Color &p_specular_factor r_base_color = r_base_color.clamp(); } -GLTFNodeIndex GLTFDocument::_find_highest_node(Ref<GLTFState> state, const Vector<GLTFNodeIndex> &subset) { +GLTFNodeIndex GLTFDocument::_find_highest_node(Ref<GLTFState> p_state, const Vector<GLTFNodeIndex> &p_subset) { int highest = -1; GLTFNodeIndex best_node = -1; - for (int i = 0; i < subset.size(); ++i) { - const GLTFNodeIndex node_i = subset[i]; - const Ref<GLTFNode> node = state->nodes[node_i]; + for (int i = 0; i < p_subset.size(); ++i) { + const GLTFNodeIndex node_i = p_subset[i]; + const Ref<GLTFNode> node = p_state->nodes[node_i]; if (highest == -1 || node->height < highest) { highest = node->height; @@ -3831,38 +3959,38 @@ GLTFNodeIndex GLTFDocument::_find_highest_node(Ref<GLTFState> state, const Vecto return best_node; } -bool GLTFDocument::_capture_nodes_in_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin, const GLTFNodeIndex node_index) { +bool GLTFDocument::_capture_nodes_in_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin, const GLTFNodeIndex p_node_index) { bool found_joint = false; - for (int i = 0; i < state->nodes[node_index]->children.size(); ++i) { - found_joint |= _capture_nodes_in_skin(state, skin, state->nodes[node_index]->children[i]); + for (int i = 0; i < p_state->nodes[p_node_index]->children.size(); ++i) { + found_joint |= _capture_nodes_in_skin(p_state, p_skin, p_state->nodes[p_node_index]->children[i]); } if (found_joint) { // Mark it if we happen to find another skins joint... - if (state->nodes[node_index]->joint && skin->joints.find(node_index) < 0) { - skin->joints.push_back(node_index); - } else if (skin->non_joints.find(node_index) < 0) { - skin->non_joints.push_back(node_index); + if (p_state->nodes[p_node_index]->joint && p_skin->joints.find(p_node_index) < 0) { + p_skin->joints.push_back(p_node_index); + } else if (p_skin->non_joints.find(p_node_index) < 0) { + p_skin->non_joints.push_back(p_node_index); } } - if (skin->joints.find(node_index) > 0) { + if (p_skin->joints.find(p_node_index) > 0) { return true; } return false; } -void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) { +void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) { DisjointSet<GLTFNodeIndex> disjoint_set; - for (int i = 0; i < skin->joints.size(); ++i) { - const GLTFNodeIndex node_index = skin->joints[i]; - const GLTFNodeIndex parent = state->nodes[node_index]->parent; + for (int i = 0; i < p_skin->joints.size(); ++i) { + const GLTFNodeIndex node_index = p_skin->joints[i]; + const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; disjoint_set.insert(node_index); - if (skin->joints.find(parent) >= 0) { + if (p_skin->joints.find(parent) >= 0) { disjoint_set.create_union(parent, node_index); } } @@ -3880,8 +4008,8 @@ void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref for (int i = 0; i < roots.size(); ++i) { const GLTFNodeIndex root = roots[i]; - if (maxHeight == -1 || state->nodes[root]->height < maxHeight) { - maxHeight = state->nodes[root]->height; + if (maxHeight == -1 || p_state->nodes[root]->height < maxHeight) { + maxHeight = p_state->nodes[root]->height; } } @@ -3889,13 +4017,13 @@ void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref // This sucks, but 99% of all game engines (not just Godot) would have this same issue. for (int i = 0; i < roots.size(); ++i) { GLTFNodeIndex current_node = roots[i]; - while (state->nodes[current_node]->height > maxHeight) { - GLTFNodeIndex parent = state->nodes[current_node]->parent; + while (p_state->nodes[current_node]->height > maxHeight) { + GLTFNodeIndex parent = p_state->nodes[current_node]->parent; - if (state->nodes[parent]->joint && skin->joints.find(parent) < 0) { - skin->joints.push_back(parent); - } else if (skin->non_joints.find(parent) < 0) { - skin->non_joints.push_back(parent); + if (p_state->nodes[parent]->joint && p_skin->joints.find(parent) < 0) { + p_skin->joints.push_back(parent); + } else if (p_skin->non_joints.find(parent) < 0) { + p_skin->non_joints.push_back(parent); } current_node = parent; @@ -3910,21 +4038,21 @@ void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref do { all_same = true; - const GLTFNodeIndex first_parent = state->nodes[roots[0]]->parent; + const GLTFNodeIndex first_parent = p_state->nodes[roots[0]]->parent; for (int i = 1; i < roots.size(); ++i) { - all_same &= (first_parent == state->nodes[roots[i]]->parent); + all_same &= (first_parent == p_state->nodes[roots[i]]->parent); } if (!all_same) { for (int i = 0; i < roots.size(); ++i) { const GLTFNodeIndex current_node = roots[i]; - const GLTFNodeIndex parent = state->nodes[current_node]->parent; + const GLTFNodeIndex parent = p_state->nodes[current_node]->parent; - if (state->nodes[parent]->joint && skin->joints.find(parent) < 0) { - skin->joints.push_back(parent); - } else if (skin->non_joints.find(parent) < 0) { - skin->non_joints.push_back(parent); + if (p_state->nodes[parent]->joint && p_skin->joints.find(parent) < 0) { + p_skin->joints.push_back(parent); + } else if (p_skin->non_joints.find(parent) < 0) { + p_skin->non_joints.push_back(parent); } roots.write[i] = parent; @@ -3934,19 +4062,19 @@ void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref } while (!all_same); } -Error GLTFDocument::_expand_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) { - _capture_nodes_for_multirooted_skin(state, skin); +Error GLTFDocument::_expand_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) { + _capture_nodes_for_multirooted_skin(p_state, p_skin); // Grab all nodes that lay in between skin joints/nodes DisjointSet<GLTFNodeIndex> disjoint_set; Vector<GLTFNodeIndex> all_skin_nodes; - all_skin_nodes.append_array(skin->joints); - all_skin_nodes.append_array(skin->non_joints); + all_skin_nodes.append_array(p_skin->joints); + all_skin_nodes.append_array(p_skin->non_joints); for (int i = 0; i < all_skin_nodes.size(); ++i) { const GLTFNodeIndex node_index = all_skin_nodes[i]; - const GLTFNodeIndex parent = state->nodes[node_index]->parent; + const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; disjoint_set.insert(node_index); if (all_skin_nodes.find(parent) >= 0) { @@ -3963,7 +4091,7 @@ Error GLTFDocument::_expand_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) { Vector<GLTFNodeIndex> set; disjoint_set.get_members(set, out_owners[i]); - const GLTFNodeIndex root = _find_highest_node(state, set); + const GLTFNodeIndex root = _find_highest_node(p_state, set); ERR_FAIL_COND_V(root < 0, FAILED); out_roots.push_back(root); } @@ -3971,15 +4099,15 @@ Error GLTFDocument::_expand_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) { out_roots.sort(); for (int i = 0; i < out_roots.size(); ++i) { - _capture_nodes_in_skin(state, skin, out_roots[i]); + _capture_nodes_in_skin(p_state, p_skin, out_roots[i]); } - skin->roots = out_roots; + p_skin->roots = out_roots; return OK; } -Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) { +Error GLTFDocument::_verify_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) { // This may seem duplicated from expand_skins, but this is really a sanity check! (so it kinda is) // In case additional interpolating logic is added to the skins, this will help ensure that you // do not cause it to self implode into a fiery blaze @@ -3991,12 +4119,12 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) { DisjointSet<GLTFNodeIndex> disjoint_set; Vector<GLTFNodeIndex> all_skin_nodes; - all_skin_nodes.append_array(skin->joints); - all_skin_nodes.append_array(skin->non_joints); + all_skin_nodes.append_array(p_skin->joints); + all_skin_nodes.append_array(p_skin->non_joints); for (int i = 0; i < all_skin_nodes.size(); ++i) { const GLTFNodeIndex node_index = all_skin_nodes[i]; - const GLTFNodeIndex parent = state->nodes[node_index]->parent; + const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; disjoint_set.insert(node_index); if (all_skin_nodes.find(parent) >= 0) { @@ -4013,7 +4141,7 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) { Vector<GLTFNodeIndex> set; disjoint_set.get_members(set, out_owners[i]); - const GLTFNodeIndex root = _find_highest_node(state, set); + const GLTFNodeIndex root = _find_highest_node(p_state, set); ERR_FAIL_COND_V(root < 0, FAILED); out_roots.push_back(root); } @@ -4023,9 +4151,9 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) { ERR_FAIL_COND_V(out_roots.size() == 0, FAILED); // Make sure the roots are the exact same (they better be) - ERR_FAIL_COND_V(out_roots.size() != skin->roots.size(), FAILED); + ERR_FAIL_COND_V(out_roots.size() != p_skin->roots.size(), FAILED); for (int i = 0; i < out_roots.size(); ++i) { - ERR_FAIL_COND_V(out_roots[i] != skin->roots[i], FAILED); + ERR_FAIL_COND_V(out_roots[i] != p_skin->roots[i], FAILED); } // Single rooted skin? Perfectly ok! @@ -4034,9 +4162,9 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) { } // Make sure all parents of a multi-rooted skin are the SAME - const GLTFNodeIndex parent = state->nodes[out_roots[0]]->parent; + const GLTFNodeIndex parent = p_state->nodes[out_roots[0]]->parent; for (int i = 1; i < out_roots.size(); ++i) { - if (state->nodes[out_roots[i]]->parent != parent) { + if (p_state->nodes[out_roots[i]]->parent != parent) { return FAILED; } } @@ -4044,12 +4172,12 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) { return OK; } -Error GLTFDocument::_parse_skins(Ref<GLTFState> state) { - if (!state->json.has("skins")) { +Error GLTFDocument::_parse_skins(Ref<GLTFState> p_state) { + if (!p_state->json.has("skins")) { return OK; } - const Array &skins = state->json["skins"]; + const Array &skins = p_state->json["skins"]; // Create the base skins, and mark nodes that are joints for (int i = 0; i < skins.size(); i++) { @@ -4063,18 +4191,18 @@ Error GLTFDocument::_parse_skins(Ref<GLTFState> state) { const Array &joints = d["joints"]; if (d.has("inverseBindMatrices")) { - skin->inverse_binds = _decode_accessor_as_xform(state, d["inverseBindMatrices"], false); + skin->inverse_binds = _decode_accessor_as_xform(p_state, d["inverseBindMatrices"], false); ERR_FAIL_COND_V(skin->inverse_binds.size() != joints.size(), ERR_PARSE_ERROR); } for (int j = 0; j < joints.size(); j++) { const GLTFNodeIndex node = joints[j]; - ERR_FAIL_INDEX_V(node, state->nodes.size(), ERR_PARSE_ERROR); + ERR_FAIL_INDEX_V(node, p_state->nodes.size(), ERR_PARSE_ERROR); skin->joints.push_back(node); skin->joints_original.push_back(node); - state->nodes.write[node]->joint = true; + p_state->nodes.write[node]->joint = true; } if (d.has("name") && !String(d["name"]).is_empty()) { @@ -4087,32 +4215,32 @@ Error GLTFDocument::_parse_skins(Ref<GLTFState> state) { skin->skin_root = d["skeleton"]; } - state->skins.push_back(skin); + p_state->skins.push_back(skin); } - for (GLTFSkinIndex i = 0; i < state->skins.size(); ++i) { - Ref<GLTFSkin> skin = state->skins.write[i]; + for (GLTFSkinIndex i = 0; i < p_state->skins.size(); ++i) { + Ref<GLTFSkin> skin = p_state->skins.write[i]; // Expand the skin to capture all the extra non-joints that lie in between the actual joints, // and expand the hierarchy to ensure multi-rooted trees lie on the same height level - ERR_FAIL_COND_V(_expand_skin(state, skin), ERR_PARSE_ERROR); - ERR_FAIL_COND_V(_verify_skin(state, skin), ERR_PARSE_ERROR); + ERR_FAIL_COND_V(_expand_skin(p_state, skin), ERR_PARSE_ERROR); + ERR_FAIL_COND_V(_verify_skin(p_state, skin), ERR_PARSE_ERROR); } - print_verbose("glTF: Total skins: " + itos(state->skins.size())); + print_verbose("glTF: Total skins: " + itos(p_state->skins.size())); return OK; } -Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) { +Error GLTFDocument::_determine_skeletons(Ref<GLTFState> p_state) { // Using a disjoint set, we are going to potentially combine all skins that are actually branches // of a main skeleton, or treat skins defining the same set of nodes as ONE skeleton. // This is another unclear issue caused by the current glTF specification. DisjointSet<GLTFNodeIndex> skeleton_sets; - for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) { - const Ref<GLTFSkin> skin = state->skins[skin_i]; + for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { + const Ref<GLTFSkin> skin = p_state->skins[skin_i]; Vector<GLTFNodeIndex> all_skin_nodes; all_skin_nodes.append_array(skin->joints); @@ -4120,7 +4248,7 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) { for (int i = 0; i < all_skin_nodes.size(); ++i) { const GLTFNodeIndex node_index = all_skin_nodes[i]; - const GLTFNodeIndex parent = state->nodes[node_index]->parent; + const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; skeleton_sets.insert(node_index); if (all_skin_nodes.find(parent) >= 0) { @@ -4144,7 +4272,7 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) { for (int i = 0; i < groups_representatives.size(); ++i) { Vector<GLTFNodeIndex> group; skeleton_sets.get_members(group, groups_representatives[i]); - highest_group_members.push_back(_find_highest_node(state, group)); + highest_group_members.push_back(_find_highest_node(p_state, group)); groups.push_back(group); } @@ -4156,13 +4284,13 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) { const GLTFNodeIndex node_j = highest_group_members[j]; // Even if they are siblings under the root! :) - if (state->nodes[node_i]->parent == state->nodes[node_j]->parent) { + if (p_state->nodes[node_i]->parent == p_state->nodes[node_j]->parent) { skeleton_sets.create_union(node_i, node_j); } } // Attach any parenting going on together (we need to do this n^2 times) - const GLTFNodeIndex node_i_parent = state->nodes[node_i]->parent; + const GLTFNodeIndex node_i_parent = p_state->nodes[node_i]->parent; if (node_i_parent >= 0) { for (int j = 0; j < groups.size() && i != j; ++j) { const Vector<GLTFNodeIndex> &group = groups[j]; @@ -4189,8 +4317,8 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) { Vector<GLTFNodeIndex> skeleton_nodes; skeleton_sets.get_members(skeleton_nodes, skeleton_owner); - for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) { - Ref<GLTFSkin> skin = state->skins.write[skin_i]; + for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { + Ref<GLTFSkin> skin = p_state->skins.write[skin_i]; // If any of the the skeletons nodes exist in a skin, that skin now maps to the skeleton for (int i = 0; i < skeleton_nodes.size(); ++i) { @@ -4206,37 +4334,37 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) { for (int i = 0; i < skeleton_nodes.size(); ++i) { const GLTFNodeIndex node_i = skeleton_nodes[i]; - if (state->nodes[node_i]->joint) { + if (p_state->nodes[node_i]->joint) { skeleton->joints.push_back(node_i); } else { non_joints.push_back(node_i); } } - state->skeletons.push_back(skeleton); + p_state->skeletons.push_back(skeleton); - _reparent_non_joint_skeleton_subtrees(state, state->skeletons.write[skel_i], non_joints); + _reparent_non_joint_skeleton_subtrees(p_state, p_state->skeletons.write[skel_i], non_joints); } - for (GLTFSkeletonIndex skel_i = 0; skel_i < state->skeletons.size(); ++skel_i) { - Ref<GLTFSkeleton> skeleton = state->skeletons.write[skel_i]; + for (GLTFSkeletonIndex skel_i = 0; skel_i < p_state->skeletons.size(); ++skel_i) { + Ref<GLTFSkeleton> skeleton = p_state->skeletons.write[skel_i]; for (int i = 0; i < skeleton->joints.size(); ++i) { const GLTFNodeIndex node_i = skeleton->joints[i]; - Ref<GLTFNode> node = state->nodes[node_i]; + Ref<GLTFNode> node = p_state->nodes[node_i]; ERR_FAIL_COND_V(!node->joint, ERR_PARSE_ERROR); ERR_FAIL_COND_V(node->skeleton >= 0, ERR_PARSE_ERROR); node->skeleton = skel_i; } - ERR_FAIL_COND_V(_determine_skeleton_roots(state, skel_i), ERR_PARSE_ERROR); + ERR_FAIL_COND_V(_determine_skeleton_roots(p_state, skel_i), ERR_PARSE_ERROR); } return OK; } -Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton, const Vector<GLTFNodeIndex> &non_joints) { +Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> p_state, Ref<GLTFSkeleton> p_skeleton, const Vector<GLTFNodeIndex> &p_non_joints) { DisjointSet<GLTFNodeIndex> subtree_set; // Populate the disjoint set with ONLY non joints that are in the skeleton hierarchy (non_joints vector) @@ -4247,13 +4375,13 @@ Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> state, // skinD depicted here explains this issue: // https://github.com/KhronosGroup/glTF-Asset-Generator/blob/master/Output/Positive/Animation_Skin - for (int i = 0; i < non_joints.size(); ++i) { - const GLTFNodeIndex node_i = non_joints[i]; + for (int i = 0; i < p_non_joints.size(); ++i) { + const GLTFNodeIndex node_i = p_non_joints[i]; subtree_set.insert(node_i); - const GLTFNodeIndex parent_i = state->nodes[node_i]->parent; - if (parent_i >= 0 && non_joints.find(parent_i) >= 0 && !state->nodes[parent_i]->joint) { + const GLTFNodeIndex parent_i = p_state->nodes[node_i]->parent; + if (parent_i >= 0 && p_non_joints.find(parent_i) >= 0 && !p_state->nodes[parent_i]->joint) { subtree_set.create_union(parent_i, node_i); } } @@ -4270,44 +4398,44 @@ Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> state, subtree_set.get_members(subtree_nodes, subtree_root); for (int subtree_i = 0; subtree_i < subtree_nodes.size(); ++subtree_i) { - Ref<GLTFNode> node = state->nodes[subtree_nodes[subtree_i]]; + Ref<GLTFNode> node = p_state->nodes[subtree_nodes[subtree_i]]; node->joint = true; // Add the joint to the skeletons joints - skeleton->joints.push_back(subtree_nodes[subtree_i]); + p_skeleton->joints.push_back(subtree_nodes[subtree_i]); } } return OK; } -Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> state, const GLTFSkeletonIndex skel_i) { +Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> p_state, const GLTFSkeletonIndex p_skel_i) { DisjointSet<GLTFNodeIndex> disjoint_set; - for (GLTFNodeIndex i = 0; i < state->nodes.size(); ++i) { - const Ref<GLTFNode> node = state->nodes[i]; + for (GLTFNodeIndex i = 0; i < p_state->nodes.size(); ++i) { + const Ref<GLTFNode> node = p_state->nodes[i]; - if (node->skeleton != skel_i) { + if (node->skeleton != p_skel_i) { continue; } disjoint_set.insert(i); - if (node->parent >= 0 && state->nodes[node->parent]->skeleton == skel_i) { + if (node->parent >= 0 && p_state->nodes[node->parent]->skeleton == p_skel_i) { disjoint_set.create_union(node->parent, i); } } - Ref<GLTFSkeleton> skeleton = state->skeletons.write[skel_i]; + Ref<GLTFSkeleton> skeleton = p_state->skeletons.write[p_skel_i]; - Vector<GLTFNodeIndex> owners; - disjoint_set.get_representatives(owners); + Vector<GLTFNodeIndex> representatives; + disjoint_set.get_representatives(representatives); Vector<GLTFNodeIndex> roots; - for (int i = 0; i < owners.size(); ++i) { + for (int i = 0; i < representatives.size(); ++i) { Vector<GLTFNodeIndex> set; - disjoint_set.get_members(set, owners[i]); - const GLTFNodeIndex root = _find_highest_node(state, set); + disjoint_set.get_members(set, representatives[i]); + const GLTFNodeIndex root = _find_highest_node(p_state, set); ERR_FAIL_COND_V(root < 0, FAILED); roots.push_back(root); } @@ -4323,9 +4451,9 @@ Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> state, const GLTFSk } // Check that the subtrees have the same parent root - const GLTFNodeIndex parent = state->nodes[roots[0]]->parent; + const GLTFNodeIndex parent = p_state->nodes[roots[0]]->parent; for (int i = 1; i < roots.size(); ++i) { - if (state->nodes[roots[i]]->parent != parent) { + if (p_state->nodes[roots[i]]->parent != parent) { return FAILED; } } @@ -4333,16 +4461,16 @@ Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> state, const GLTFSk return OK; } -Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) { - for (GLTFSkeletonIndex skel_i = 0; skel_i < state->skeletons.size(); ++skel_i) { - Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i]; +Error GLTFDocument::_create_skeletons(Ref<GLTFState> p_state) { + for (GLTFSkeletonIndex skel_i = 0; skel_i < p_state->skeletons.size(); ++skel_i) { + Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_i]; Skeleton3D *skeleton = memnew(Skeleton3D); gltf_skeleton->godot_skeleton = skeleton; - state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skel_i; + p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skel_i; // Make a unique name, no gltf node represents this skeleton - skeleton->set_name(_gen_unique_name(state, "Skeleton3D")); + skeleton->set_name(_gen_unique_name(p_state, "Skeleton3D")); List<GLTFNodeIndex> bones; @@ -4358,14 +4486,14 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) { const GLTFNodeIndex node_i = bones.front()->get(); bones.pop_front(); - Ref<GLTFNode> node = state->nodes[node_i]; + Ref<GLTFNode> node = p_state->nodes[node_i]; ERR_FAIL_COND_V(node->skeleton != skel_i, FAILED); { // Add all child nodes to the stack (deterministically) Vector<GLTFNodeIndex> child_nodes; for (int i = 0; i < node->children.size(); ++i) { const GLTFNodeIndex child_i = node->children[i]; - if (state->nodes[child_i]->skeleton == skel_i) { + if (p_state->nodes[child_i]->skeleton == skel_i) { child_nodes.push_back(child_i); } } @@ -4383,7 +4511,7 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) { node->set_name("bone"); } - node->set_name(_gen_unique_bone_name(state, skel_i, node->get_name())); + node->set_name(_gen_unique_bone_name(p_state, skel_i, node->get_name())); skeleton->add_bone(node->get_name()); skeleton->set_bone_rest(bone_index, node->xform); @@ -4391,30 +4519,30 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) { skeleton->set_bone_pose_rotation(bone_index, node->rotation.normalized()); skeleton->set_bone_pose_scale(bone_index, node->scale); - if (node->parent >= 0 && state->nodes[node->parent]->skeleton == skel_i) { - const int bone_parent = skeleton->find_bone(state->nodes[node->parent]->get_name()); + if (node->parent >= 0 && p_state->nodes[node->parent]->skeleton == skel_i) { + const int bone_parent = skeleton->find_bone(p_state->nodes[node->parent]->get_name()); ERR_FAIL_COND_V(bone_parent < 0, FAILED); - skeleton->set_bone_parent(bone_index, skeleton->find_bone(state->nodes[node->parent]->get_name())); + skeleton->set_bone_parent(bone_index, skeleton->find_bone(p_state->nodes[node->parent]->get_name())); } - state->scene_nodes.insert(node_i, skeleton); + p_state->scene_nodes.insert(node_i, skeleton); } } - ERR_FAIL_COND_V(_map_skin_joints_indices_to_skeleton_bone_indices(state), ERR_PARSE_ERROR); + ERR_FAIL_COND_V(_map_skin_joints_indices_to_skeleton_bone_indices(p_state), ERR_PARSE_ERROR); return OK; } -Error GLTFDocument::_map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> state) { - for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) { - Ref<GLTFSkin> skin = state->skins.write[skin_i]; +Error GLTFDocument::_map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> p_state) { + for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { + Ref<GLTFSkin> skin = p_state->skins.write[skin_i]; - Ref<GLTFSkeleton> skeleton = state->skeletons[skin->skeleton]; + Ref<GLTFSkeleton> skeleton = p_state->skeletons[skin->skeleton]; for (int joint_index = 0; joint_index < skin->joints_original.size(); ++joint_index) { const GLTFNodeIndex node_i = skin->joints_original[joint_index]; - const Ref<GLTFNode> node = state->nodes[node_i]; + const Ref<GLTFNode> node = p_state->nodes[node_i]; const int bone_index = skeleton->godot_skeleton->find_bone(node->get_name()); ERR_FAIL_COND_V(bone_index < 0, FAILED); @@ -4426,28 +4554,28 @@ Error GLTFDocument::_map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFSt return OK; } -Error GLTFDocument::_serialize_skins(Ref<GLTFState> state) { - _remove_duplicate_skins(state); +Error GLTFDocument::_serialize_skins(Ref<GLTFState> p_state) { + _remove_duplicate_skins(p_state); Array json_skins; - for (int skin_i = 0; skin_i < state->skins.size(); skin_i++) { - Ref<GLTFSkin> gltf_skin = state->skins[skin_i]; + for (int skin_i = 0; skin_i < p_state->skins.size(); skin_i++) { + Ref<GLTFSkin> gltf_skin = p_state->skins[skin_i]; Dictionary json_skin; - json_skin["inverseBindMatrices"] = _encode_accessor_as_xform(state, gltf_skin->inverse_binds, false); + json_skin["inverseBindMatrices"] = _encode_accessor_as_xform(p_state, gltf_skin->inverse_binds, false); json_skin["joints"] = gltf_skin->get_joints(); json_skin["name"] = gltf_skin->get_name(); json_skins.push_back(json_skin); } - if (!state->skins.size()) { + if (!p_state->skins.size()) { return OK; } - state->json["skins"] = json_skins; + p_state->json["skins"] = json_skins; return OK; } -Error GLTFDocument::_create_skins(Ref<GLTFState> state) { - for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) { - Ref<GLTFSkin> gltf_skin = state->skins.write[skin_i]; +Error GLTFDocument::_create_skins(Ref<GLTFState> p_state) { + for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { + Ref<GLTFSkin> gltf_skin = p_state->skins.write[skin_i]; Ref<Skin> skin; skin.instantiate(); @@ -4457,14 +4585,14 @@ Error GLTFDocument::_create_skins(Ref<GLTFState> state) { for (int joint_i = 0; joint_i < gltf_skin->joints_original.size(); ++joint_i) { GLTFNodeIndex node = gltf_skin->joints_original[joint_i]; - String bone_name = state->nodes[node]->get_name(); + String bone_name = p_state->nodes[node]->get_name(); Transform3D xform; if (has_ibms) { xform = gltf_skin->inverse_binds[joint_i]; } - if (state->use_named_skin_binds) { + if (p_state->use_named_skin_binds) { skin->add_named_bind(bone_name, xform); } else { int32_t bone_i = gltf_skin->joint_i_to_bone_i[joint_i]; @@ -4476,35 +4604,35 @@ Error GLTFDocument::_create_skins(Ref<GLTFState> state) { } // Purge the duplicates! - _remove_duplicate_skins(state); + _remove_duplicate_skins(p_state); // Create unique names now, after removing duplicates - for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) { - Ref<Skin> skin = state->skins.write[skin_i]->godot_skin; + for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { + Ref<Skin> skin = p_state->skins.write[skin_i]->godot_skin; if (skin->get_name().is_empty()) { // Make a unique name, no gltf node represents this skin - skin->set_name(_gen_unique_name(state, "Skin")); + skin->set_name(_gen_unique_name(p_state, "Skin")); } } return OK; } -bool GLTFDocument::_skins_are_same(const Ref<Skin> skin_a, const Ref<Skin> skin_b) { - if (skin_a->get_bind_count() != skin_b->get_bind_count()) { +bool GLTFDocument::_skins_are_same(const Ref<Skin> p_skin_a, const Ref<Skin> p_skin_b) { + if (p_skin_a->get_bind_count() != p_skin_b->get_bind_count()) { return false; } - for (int i = 0; i < skin_a->get_bind_count(); ++i) { - if (skin_a->get_bind_bone(i) != skin_b->get_bind_bone(i)) { + for (int i = 0; i < p_skin_a->get_bind_count(); ++i) { + if (p_skin_a->get_bind_bone(i) != p_skin_b->get_bind_bone(i)) { return false; } - if (skin_a->get_bind_name(i) != skin_b->get_bind_name(i)) { + if (p_skin_a->get_bind_name(i) != p_skin_b->get_bind_name(i)) { return false; } - Transform3D a_xform = skin_a->get_bind_pose(i); - Transform3D b_xform = skin_b->get_bind_pose(i); + Transform3D a_xform = p_skin_a->get_bind_pose(i); + Transform3D b_xform = p_skin_b->get_bind_pose(i); if (a_xform != b_xform) { return false; @@ -4514,67 +4642,67 @@ bool GLTFDocument::_skins_are_same(const Ref<Skin> skin_a, const Ref<Skin> skin_ return true; } -void GLTFDocument::_remove_duplicate_skins(Ref<GLTFState> state) { - for (int i = 0; i < state->skins.size(); ++i) { - for (int j = i + 1; j < state->skins.size(); ++j) { - const Ref<Skin> skin_i = state->skins[i]->godot_skin; - const Ref<Skin> skin_j = state->skins[j]->godot_skin; +void GLTFDocument::_remove_duplicate_skins(Ref<GLTFState> p_state) { + for (int i = 0; i < p_state->skins.size(); ++i) { + for (int j = i + 1; j < p_state->skins.size(); ++j) { + const Ref<Skin> skin_i = p_state->skins[i]->godot_skin; + const Ref<Skin> skin_j = p_state->skins[j]->godot_skin; if (_skins_are_same(skin_i, skin_j)) { // replace it and delete the old - state->skins.write[j]->godot_skin = skin_i; + p_state->skins.write[j]->godot_skin = skin_i; } } } } -Error GLTFDocument::_serialize_lights(Ref<GLTFState> state) { - if (state->lights.is_empty()) { +Error GLTFDocument::_serialize_lights(Ref<GLTFState> p_state) { + if (p_state->lights.is_empty()) { return OK; } Array lights; - for (GLTFLightIndex i = 0; i < state->lights.size(); i++) { - lights.push_back(state->lights[i]->to_dictionary()); + for (GLTFLightIndex i = 0; i < p_state->lights.size(); i++) { + lights.push_back(p_state->lights[i]->to_dictionary()); } Dictionary extensions; - if (state->json.has("extensions")) { - extensions = state->json["extensions"]; + if (p_state->json.has("extensions")) { + extensions = p_state->json["extensions"]; } else { - state->json["extensions"] = extensions; + p_state->json["extensions"] = extensions; } Dictionary lights_punctual; extensions["KHR_lights_punctual"] = lights_punctual; lights_punctual["lights"] = lights; - print_verbose("glTF: Total lights: " + itos(state->lights.size())); + print_verbose("glTF: Total lights: " + itos(p_state->lights.size())); return OK; } -Error GLTFDocument::_serialize_cameras(Ref<GLTFState> state) { +Error GLTFDocument::_serialize_cameras(Ref<GLTFState> p_state) { Array cameras; - cameras.resize(state->cameras.size()); - for (GLTFCameraIndex i = 0; i < state->cameras.size(); i++) { - cameras[i] = state->cameras[i]->to_dictionary(); + cameras.resize(p_state->cameras.size()); + for (GLTFCameraIndex i = 0; i < p_state->cameras.size(); i++) { + cameras[i] = p_state->cameras[i]->to_dictionary(); } - if (!state->cameras.size()) { + if (!p_state->cameras.size()) { return OK; } - state->json["cameras"] = cameras; + p_state->json["cameras"] = cameras; - print_verbose("glTF: Total cameras: " + itos(state->cameras.size())); + print_verbose("glTF: Total cameras: " + itos(p_state->cameras.size())); return OK; } -Error GLTFDocument::_parse_lights(Ref<GLTFState> state) { - if (!state->json.has("extensions")) { +Error GLTFDocument::_parse_lights(Ref<GLTFState> p_state) { + if (!p_state->json.has("extensions")) { return OK; } - Dictionary extensions = state->json["extensions"]; + Dictionary extensions = p_state->json["extensions"]; if (!extensions.has("KHR_lights_punctual")) { return OK; } @@ -4590,26 +4718,26 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) { if (light.is_null()) { return Error::ERR_PARSE_ERROR; } - state->lights.push_back(light); + p_state->lights.push_back(light); } - print_verbose("glTF: Total lights: " + itos(state->lights.size())); + print_verbose("glTF: Total lights: " + itos(p_state->lights.size())); return OK; } -Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) { - if (!state->json.has("cameras")) { +Error GLTFDocument::_parse_cameras(Ref<GLTFState> p_state) { + if (!p_state->json.has("cameras")) { return OK; } - const Array cameras = state->json["cameras"]; + const Array cameras = p_state->json["cameras"]; for (GLTFCameraIndex i = 0; i < cameras.size(); i++) { - state->cameras.push_back(GLTFCamera::from_dictionary(cameras[i])); + p_state->cameras.push_back(GLTFCamera::from_dictionary(cameras[i])); } - print_verbose("glTF: Total cameras: " + itos(state->cameras.size())); + print_verbose("glTF: Total cameras: " + itos(p_state->cameras.size())); return OK; } @@ -4629,24 +4757,24 @@ String GLTFDocument::interpolation_to_string(const GLTFAnimation::Interpolation return interp; } -Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) { - if (!state->animation_players.size()) { +Error GLTFDocument::_serialize_animations(Ref<GLTFState> p_state) { + if (!p_state->animation_players.size()) { return OK; } - for (int32_t player_i = 0; player_i < state->animation_players.size(); player_i++) { + for (int32_t player_i = 0; player_i < p_state->animation_players.size(); player_i++) { List<StringName> animation_names; - AnimationPlayer *animation_player = state->animation_players[player_i]; + AnimationPlayer *animation_player = p_state->animation_players[player_i]; animation_player->get_animation_list(&animation_names); if (animation_names.size()) { for (int animation_name_i = 0; animation_name_i < animation_names.size(); animation_name_i++) { - _convert_animation(state, animation_player, animation_names[animation_name_i]); + _convert_animation(p_state, animation_player, animation_names[animation_name_i]); } } } Array animations; - for (GLTFAnimationIndex animation_i = 0; animation_i < state->animations.size(); animation_i++) { + for (GLTFAnimationIndex animation_i = 0; animation_i < p_state->animations.size(); animation_i++) { Dictionary d; - Ref<GLTFAnimation> gltf_animation = state->animations[animation_i]; + Ref<GLTFAnimation> gltf_animation = p_state->animations[animation_i]; if (!gltf_animation->get_tracks().size()) { continue; } @@ -4666,9 +4794,9 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) { s["interpolation"] = interpolation_to_string(track.position_track.interpolation); Vector<real_t> times = Variant(track.position_track.times); - s["input"] = _encode_accessor_as_floats(state, times, false); + s["input"] = _encode_accessor_as_floats(p_state, times, false); Vector<Vector3> values = Variant(track.position_track.values); - s["output"] = _encode_accessor_as_vec3(state, values, false); + s["output"] = _encode_accessor_as_vec3(p_state, values, false); samplers.push_back(s); @@ -4686,9 +4814,9 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) { s["interpolation"] = interpolation_to_string(track.rotation_track.interpolation); Vector<real_t> times = Variant(track.rotation_track.times); - s["input"] = _encode_accessor_as_floats(state, times, false); + s["input"] = _encode_accessor_as_floats(p_state, times, false); Vector<Quaternion> values = track.rotation_track.values; - s["output"] = _encode_accessor_as_quaternions(state, values, false); + s["output"] = _encode_accessor_as_quaternions(p_state, values, false); samplers.push_back(s); @@ -4706,9 +4834,9 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) { s["interpolation"] = interpolation_to_string(track.scale_track.interpolation); Vector<real_t> times = Variant(track.scale_track.times); - s["input"] = _encode_accessor_as_floats(state, times, false); + s["input"] = _encode_accessor_as_floats(p_state, times, false); Vector<Vector3> values = Variant(track.scale_track.values); - s["output"] = _encode_accessor_as_vec3(state, values, false); + s["output"] = _encode_accessor_as_vec3(p_state, values, false); samplers.push_back(s); @@ -4786,8 +4914,8 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) { } s["interpolation"] = interpolation_to_string(track.weight_tracks[track.weight_tracks.size() - 1].interpolation); - s["input"] = _encode_accessor_as_floats(state, all_track_times, false); - s["output"] = _encode_accessor_as_floats(state, all_track_values, false); + s["input"] = _encode_accessor_as_floats(p_state, all_track_times, false); + s["output"] = _encode_accessor_as_floats(p_state, all_track_values, false); samplers.push_back(s); @@ -4809,19 +4937,19 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) { if (!animations.size()) { return OK; } - state->json["animations"] = animations; + p_state->json["animations"] = animations; - print_verbose("glTF: Total animations '" + itos(state->animations.size()) + "'."); + print_verbose("glTF: Total animations '" + itos(p_state->animations.size()) + "'."); return OK; } -Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { - if (!state->json.has("animations")) { +Error GLTFDocument::_parse_animations(Ref<GLTFState> p_state) { + if (!p_state->json.has("animations")) { return OK; } - const Array &animations = state->json["animations"]; + const Array &animations = p_state->json["animations"]; for (GLTFAnimationIndex i = 0; i < animations.size(); i++) { const Dictionary &d = animations[i]; @@ -4837,12 +4965,12 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { Array samplers = d["samplers"]; if (d.has("name")) { - const String name = d["name"]; - const String name_lower = name.to_lower(); - if (name_lower.begins_with("loop") || name_lower.ends_with("loop") || name_lower.begins_with("cycle") || name_lower.ends_with("cycle")) { + const String anim_name = d["name"]; + const String anim_name_lower = anim_name.to_lower(); + if (anim_name_lower.begins_with("loop") || anim_name_lower.ends_with("loop") || anim_name_lower.begins_with("cycle") || anim_name_lower.ends_with("cycle")) { animation->set_loop(true); } - animation->set_name(_gen_unique_animation_name(state, name)); + animation->set_name(_gen_unique_animation_name(p_state, anim_name)); } for (int j = 0; j < channels.size(); j++) { @@ -4863,7 +4991,7 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { GLTFNodeIndex node = t["node"]; String path = t["path"]; - ERR_FAIL_INDEX_V(node, state->nodes.size(), ERR_PARSE_ERROR); + ERR_FAIL_INDEX_V(node, p_state->nodes.size(), ERR_PARSE_ERROR); GLTFAnimation::Track *track = nullptr; @@ -4898,27 +5026,27 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { } } - const Vector<float> times = _decode_accessor_as_floats(state, input, false); + const Vector<float> times = _decode_accessor_as_floats(p_state, input, false); if (path == "translation") { - const Vector<Vector3> positions = _decode_accessor_as_vec3(state, output, false); + const Vector<Vector3> positions = _decode_accessor_as_vec3(p_state, output, false); track->position_track.interpolation = interp; track->position_track.times = Variant(times); //convert via variant track->position_track.values = Variant(positions); //convert via variant } else if (path == "rotation") { - const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(state, output, false); + const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(p_state, output, false); track->rotation_track.interpolation = interp; track->rotation_track.times = Variant(times); //convert via variant track->rotation_track.values = rotations; } else if (path == "scale") { - const Vector<Vector3> scales = _decode_accessor_as_vec3(state, output, false); + const Vector<Vector3> scales = _decode_accessor_as_vec3(p_state, output, false); track->scale_track.interpolation = interp; track->scale_track.times = Variant(times); //convert via variant track->scale_track.values = Variant(scales); //convert via variant } else if (path == "weights") { - const Vector<float> weights = _decode_accessor_as_floats(state, output, false); + const Vector<float> weights = _decode_accessor_as_floats(p_state, output, false); - ERR_FAIL_INDEX_V(state->nodes[node]->mesh, state->meshes.size(), ERR_PARSE_ERROR); - Ref<GLTFMesh> mesh = state->meshes[state->nodes[node]->mesh]; + ERR_FAIL_INDEX_V(p_state->nodes[node]->mesh, p_state->meshes.size(), ERR_PARSE_ERROR); + Ref<GLTFMesh> mesh = p_state->meshes[p_state->nodes[node]->mesh]; ERR_CONTINUE(!mesh->get_blend_weights().size()); const int wc = mesh->get_blend_weights().size(); @@ -4946,17 +5074,17 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { } } - state->animations.push_back(animation); + p_state->animations.push_back(animation); } - print_verbose("glTF: Total animations '" + itos(state->animations.size()) + "'."); + print_verbose("glTF: Total animations '" + itos(p_state->animations.size()) + "'."); return OK; } -void GLTFDocument::_assign_scene_names(Ref<GLTFState> state) { - for (int i = 0; i < state->nodes.size(); i++) { - Ref<GLTFNode> n = state->nodes[i]; +void GLTFDocument::_assign_scene_names(Ref<GLTFState> p_state) { + for (int i = 0; i < p_state->nodes.size(); i++) { + Ref<GLTFNode> n = p_state->nodes[i]; // Any joints get unique names generated when the skeleton is made, unique to the skeleton if (n->skeleton >= 0) { @@ -4965,21 +5093,21 @@ void GLTFDocument::_assign_scene_names(Ref<GLTFState> state) { if (n->get_name().is_empty()) { if (n->mesh >= 0) { - n->set_name(_gen_unique_name(state, "Mesh")); + n->set_name(_gen_unique_name(p_state, "Mesh")); } else if (n->camera >= 0) { - n->set_name(_gen_unique_name(state, "Camera3D")); + n->set_name(_gen_unique_name(p_state, "Camera3D")); } else { - n->set_name(_gen_unique_name(state, "Node")); + n->set_name(_gen_unique_name(p_state, "Node")); } } - n->set_name(_gen_unique_name(state, n->get_name())); + n->set_name(_gen_unique_name(p_state, n->get_name())); } } -BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> state, Skeleton3D *skeleton, const GLTFNodeIndex node_index, const GLTFNodeIndex bone_index) { - Ref<GLTFNode> gltf_node = state->nodes[node_index]; - Ref<GLTFNode> bone_node = state->nodes[bone_index]; +BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> p_state, Skeleton3D *p_skeleton, const GLTFNodeIndex p_node_index, const GLTFNodeIndex p_bone_index) { + Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; + Ref<GLTFNode> bone_node = p_state->nodes[p_bone_index]; BoneAttachment3D *bone_attachment = memnew(BoneAttachment3D); print_verbose("glTF: Creating bone attachment for: " + gltf_node->get_name()); @@ -4990,7 +5118,7 @@ BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> state, return bone_attachment; } -GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInstance3D *p_mesh_instance) { +GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> p_state, MeshInstance3D *p_mesh_instance) { ERR_FAIL_NULL_V(p_mesh_instance, -1); if (p_mesh_instance->get_mesh().is_null()) { return -1; @@ -5021,20 +5149,20 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst gltf_mesh->set_instance_materials(instance_materials); gltf_mesh->set_mesh(current_mesh); gltf_mesh->set_blend_weights(blend_weights); - GLTFMeshIndex mesh_i = state->meshes.size(); - state->meshes.push_back(gltf_mesh); + GLTFMeshIndex mesh_i = p_state->meshes.size(); + p_state->meshes.push_back(gltf_mesh); return mesh_i; } -ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index) { - Ref<GLTFNode> gltf_node = state->nodes[node_index]; +ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { + Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; - ERR_FAIL_INDEX_V(gltf_node->mesh, state->meshes.size(), nullptr); + ERR_FAIL_INDEX_V(gltf_node->mesh, p_state->meshes.size(), nullptr); ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D); print_verbose("glTF: Creating mesh for: " + gltf_node->get_name()); - Ref<GLTFMesh> mesh = state->meshes.write[gltf_node->mesh]; + Ref<GLTFMesh> mesh = p_state->meshes.write[gltf_node->mesh]; if (mesh.is_null()) { return mi; } @@ -5046,63 +5174,64 @@ ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> sta return mi; } -Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index) { - Ref<GLTFNode> gltf_node = state->nodes[node_index]; +Light3D *GLTFDocument::_generate_light(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { + Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; - ERR_FAIL_INDEX_V(gltf_node->light, state->lights.size(), nullptr); + ERR_FAIL_INDEX_V(gltf_node->light, p_state->lights.size(), nullptr); print_verbose("glTF: Creating light for: " + gltf_node->get_name()); - Ref<GLTFLight> l = state->lights[gltf_node->light]; + Ref<GLTFLight> l = p_state->lights[gltf_node->light]; return l->to_node(); } -Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index) { - Ref<GLTFNode> gltf_node = state->nodes[node_index]; +Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { + Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; - ERR_FAIL_INDEX_V(gltf_node->camera, state->cameras.size(), nullptr); + ERR_FAIL_INDEX_V(gltf_node->camera, p_state->cameras.size(), nullptr); print_verbose("glTF: Creating camera for: " + gltf_node->get_name()); - Ref<GLTFCamera> c = state->cameras[gltf_node->camera]; + Ref<GLTFCamera> c = p_state->cameras[gltf_node->camera]; return c->to_node(); } -GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_camera) { +GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> p_state, Camera3D *p_camera) { print_verbose("glTF: Converting camera: " + p_camera->get_name()); Ref<GLTFCamera> c = GLTFCamera::from_node(p_camera); - GLTFCameraIndex camera_index = state->cameras.size(); - state->cameras.push_back(c); + GLTFCameraIndex camera_index = p_state->cameras.size(); + p_state->cameras.push_back(c); return camera_index; } -GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_light) { +GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> p_state, Light3D *p_light) { print_verbose("glTF: Converting light: " + p_light->get_name()); Ref<GLTFLight> l = GLTFLight::from_node(p_light); - GLTFLightIndex light_index = state->lights.size(); - state->lights.push_back(l); + GLTFLightIndex light_index = p_state->lights.size(); + p_state->lights.push_back(l); return light_index; } -void GLTFDocument::_convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node) { +void GLTFDocument::_convert_spatial(Ref<GLTFState> p_state, Node3D *p_spatial, Ref<GLTFNode> p_node) { Transform3D xform = p_spatial->get_transform(); p_node->scale = xform.basis.get_scale(); p_node->rotation = xform.basis.get_rotation_quaternion(); p_node->position = xform.origin; } -Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index) { - Ref<GLTFNode> gltf_node = state->nodes[node_index]; +Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { + Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; Node3D *spatial = memnew(Node3D); print_verbose("glTF: Converting spatial: " + gltf_node->get_name()); return spatial; } -void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) { + +void GLTFDocument::_convert_scene_node(Ref<GLTFState> p_state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) { bool retflag = true; _check_visibility(p_current, retflag); if (retflag) { @@ -5110,64 +5239,68 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, co } Ref<GLTFNode> gltf_node; gltf_node.instantiate(); - gltf_node->set_name(_gen_unique_name(state, p_current->get_name())); + gltf_node->set_name(_gen_unique_name(p_state, p_current->get_name())); if (cast_to<Node3D>(p_current)) { Node3D *spatial = cast_to<Node3D>(p_current); - _convert_spatial(state, spatial, gltf_node); + _convert_spatial(p_state, spatial, gltf_node); } if (cast_to<MeshInstance3D>(p_current)) { MeshInstance3D *mi = cast_to<MeshInstance3D>(p_current); - _convert_mesh_instance_to_gltf(mi, state, gltf_node); + _convert_mesh_instance_to_gltf(mi, p_state, gltf_node); } else if (cast_to<BoneAttachment3D>(p_current)) { BoneAttachment3D *bone = cast_to<BoneAttachment3D>(p_current); - _convert_bone_attachment_to_gltf(bone, state, p_gltf_parent, p_gltf_root, gltf_node); + _convert_bone_attachment_to_gltf(bone, p_state, p_gltf_parent, p_gltf_root, gltf_node); return; } else if (cast_to<Skeleton3D>(p_current)) { Skeleton3D *skel = cast_to<Skeleton3D>(p_current); - _convert_skeleton_to_gltf(skel, state, p_gltf_parent, p_gltf_root, gltf_node); + _convert_skeleton_to_gltf(skel, p_state, p_gltf_parent, p_gltf_root, gltf_node); // We ignore the Godot Engine node that is the skeleton. return; } else if (cast_to<MultiMeshInstance3D>(p_current)) { MultiMeshInstance3D *multi = cast_to<MultiMeshInstance3D>(p_current); - _convert_multi_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, state); + _convert_multi_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, p_state); #ifdef MODULE_CSG_ENABLED } else if (cast_to<CSGShape3D>(p_current)) { CSGShape3D *shape = cast_to<CSGShape3D>(p_current); if (shape->get_parent() && shape->is_root_shape()) { - _convert_csg_shape_to_gltf(shape, p_gltf_parent, gltf_node, state); + _convert_csg_shape_to_gltf(shape, p_gltf_parent, gltf_node, p_state); } #endif // MODULE_CSG_ENABLED #ifdef MODULE_GRIDMAP_ENABLED } else if (cast_to<GridMap>(p_current)) { GridMap *gridmap = Object::cast_to<GridMap>(p_current); - _convert_grid_map_to_gltf(gridmap, p_gltf_parent, p_gltf_root, gltf_node, state); + _convert_grid_map_to_gltf(gridmap, p_gltf_parent, p_gltf_root, gltf_node, p_state); #endif // MODULE_GRIDMAP_ENABLED } else if (cast_to<Camera3D>(p_current)) { Camera3D *camera = Object::cast_to<Camera3D>(p_current); - _convert_camera_to_gltf(camera, state, gltf_node); + _convert_camera_to_gltf(camera, p_state, gltf_node); } else if (cast_to<Light3D>(p_current)) { Light3D *light = Object::cast_to<Light3D>(p_current); - _convert_light_to_gltf(light, state, gltf_node); + _convert_light_to_gltf(light, p_state, gltf_node); } else if (cast_to<AnimationPlayer>(p_current)) { AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_current); - _convert_animation_player_to_gltf(animation_player, state, p_gltf_parent, p_gltf_root, gltf_node, p_current); + _convert_animation_player_to_gltf(animation_player, p_state, p_gltf_parent, p_gltf_root, gltf_node, p_current); + } + for (Ref<GLTFDocumentExtension> ext : document_extensions) { + ERR_CONTINUE(ext.is_null()); + ext->convert_scene_node(p_state, gltf_node, p_current); } - GLTFNodeIndex current_node_i = state->nodes.size(); + GLTFNodeIndex current_node_i = p_state->nodes.size(); GLTFNodeIndex gltf_root = p_gltf_root; if (gltf_root == -1) { gltf_root = current_node_i; Array scenes; scenes.push_back(gltf_root); - state->json["scene"] = scenes; + p_state->json["scene"] = scenes; } - _create_gltf_node(state, p_current, current_node_i, p_gltf_parent, gltf_root, gltf_node); + _create_gltf_node(p_state, p_current, current_node_i, p_gltf_parent, gltf_root, gltf_node); for (int node_i = 0; node_i < p_current->get_child_count(); node_i++) { - _convert_scene_node(state, p_current->get_child(node_i), current_node_i, gltf_root); + _convert_scene_node(p_state, p_current->get_child(node_i), current_node_i, gltf_root); } } #ifdef MODULE_CSG_ENABLED -void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) { +void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) { CSGShape3D *csg = p_current; csg->call("_update_shape"); Array meshes = csg->get_meshes(); @@ -5199,34 +5332,34 @@ void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeInd Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); gltf_mesh->set_mesh(mesh); - GLTFMeshIndex mesh_i = state->meshes.size(); - state->meshes.push_back(gltf_mesh); - gltf_node->mesh = mesh_i; - gltf_node->xform = csg->get_meshes()[0]; - gltf_node->set_name(_gen_unique_name(state, csg->get_name())); + GLTFMeshIndex mesh_i = p_state->meshes.size(); + p_state->meshes.push_back(gltf_mesh); + p_gltf_node->mesh = mesh_i; + p_gltf_node->xform = csg->get_meshes()[0]; + p_gltf_node->set_name(_gen_unique_name(p_state, csg->get_name())); } #endif // MODULE_CSG_ENABLED -void GLTFDocument::_create_gltf_node(Ref<GLTFState> state, Node *p_scene_parent, GLTFNodeIndex current_node_i, - GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, Ref<GLTFNode> gltf_node) { - state->scene_nodes.insert(current_node_i, p_scene_parent); - state->nodes.push_back(gltf_node); - ERR_FAIL_COND(current_node_i == p_parent_node_index); - state->nodes.write[current_node_i]->parent = p_parent_node_index; +void GLTFDocument::_create_gltf_node(Ref<GLTFState> p_state, Node *p_scene_parent, GLTFNodeIndex p_current_node_i, + GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, Ref<GLTFNode> p_gltf_node) { + p_state->scene_nodes.insert(p_current_node_i, p_scene_parent); + p_state->nodes.push_back(p_gltf_node); + ERR_FAIL_COND(p_current_node_i == p_parent_node_index); + p_state->nodes.write[p_current_node_i]->parent = p_parent_node_index; if (p_parent_node_index == -1) { return; } - state->nodes.write[p_parent_node_index]->children.push_back(current_node_i); + p_state->nodes.write[p_parent_node_index]->children.push_back(p_current_node_i); } -void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *animation_player, Ref<GLTFState> state, GLTFNodeIndex p_gltf_current, GLTFNodeIndex p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) { - ERR_FAIL_COND(!animation_player); - state->animation_players.push_back(animation_player); - print_verbose(String("glTF: Converting animation player: ") + animation_player->get_name()); +void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *p_animation_player, Ref<GLTFState> p_state, GLTFNodeIndex p_gltf_current, GLTFNodeIndex p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) { + ERR_FAIL_COND(!p_animation_player); + p_state->animation_players.push_back(p_animation_player); + print_verbose(String("glTF: Converting animation player: ") + p_animation_player->get_name()); } -void GLTFDocument::_check_visibility(Node *p_node, bool &retflag) { - retflag = true; +void GLTFDocument::_check_visibility(Node *p_node, bool &r_retflag) { + r_retflag = true; Node3D *spatial = Object::cast_to<Node3D>(p_node); Node2D *node_2d = Object::cast_to<Node2D>(p_node); if (node_2d && !node_2d->is_visible()) { @@ -5235,32 +5368,32 @@ void GLTFDocument::_check_visibility(Node *p_node, bool &retflag) { if (spatial && !spatial->is_visible()) { return; } - retflag = false; + r_retflag = false; } -void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> state, Ref<GLTFNode> gltf_node) { +void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) { ERR_FAIL_COND(!camera); - GLTFCameraIndex camera_index = _convert_camera(state, camera); + GLTFCameraIndex camera_index = _convert_camera(p_state, camera); if (camera_index != -1) { - gltf_node->camera = camera_index; + p_gltf_node->camera = camera_index; } } -void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Ref<GLTFNode> gltf_node) { +void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) { ERR_FAIL_COND(!light); - GLTFLightIndex light_index = _convert_light(state, light); + GLTFLightIndex light_index = _convert_light(p_state, light); if (light_index != -1) { - gltf_node->light = light_index; + p_gltf_node->light = light_index; } } #ifdef MODULE_GRIDMAP_ENABLED -void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) { +void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) { Array cells = p_grid_map->get_used_cells(); for (int32_t k = 0; k < cells.size(); k++) { GLTFNode *new_gltf_node = memnew(GLTFNode); - gltf_node->children.push_back(state->nodes.size()); - state->nodes.push_back(new_gltf_node); + p_gltf_node->children.push_back(p_state->nodes.size()); + p_state->nodes.push_back(new_gltf_node); Vector3 cell_location = cells[k]; int32_t cell = p_grid_map->get_cell_item( Vector3(cell_location.x, cell_location.y, cell_location.z)); @@ -5271,15 +5404,15 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex cell_xform.basis.scale(Vector3(p_grid_map->get_cell_scale(), p_grid_map->get_cell_scale(), p_grid_map->get_cell_scale())); - cell_xform.set_origin(p_grid_map->map_to_world( + cell_xform.set_origin(p_grid_map->map_to_local( Vector3(cell_location.x, cell_location.y, cell_location.z))); Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); gltf_mesh->set_mesh(_mesh_to_importer_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell))); - new_gltf_node->mesh = state->meshes.size(); - state->meshes.push_back(gltf_mesh); + new_gltf_node->mesh = p_state->meshes.size(); + p_state->meshes.push_back(gltf_mesh); new_gltf_node->xform = cell_xform * p_grid_map->get_transform(); - new_gltf_node->set_name(_gen_unique_name(state, p_grid_map->get_mesh_library()->get_item_name(cell))); + new_gltf_node->set_name(_gen_unique_name(p_state, p_grid_map->get_mesh_library()->get_item_name(cell))); } } #endif // MODULE_GRIDMAP_ENABLED @@ -5288,7 +5421,7 @@ void GLTFDocument::_convert_multi_mesh_instance_to_gltf( MultiMeshInstance3D *p_multi_mesh_instance, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, - Ref<GLTFNode> gltf_node, Ref<GLTFState> state) { + Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) { ERR_FAIL_COND(!p_multi_mesh_instance); Ref<MultiMesh> multi_mesh = p_multi_mesh_instance->get_multimesh(); if (multi_mesh.is_null()) { @@ -5324,8 +5457,8 @@ void GLTFDocument::_convert_multi_mesh_instance_to_gltf( blend_arrays, mesh->surface_get_lods(surface_i), mat, material_name, mesh->surface_get_format(surface_i)); } gltf_mesh->set_mesh(importer_mesh); - GLTFMeshIndex mesh_index = state->meshes.size(); - state->meshes.push_back(gltf_mesh); + GLTFMeshIndex mesh_index = p_state->meshes.size(); + p_state->meshes.push_back(gltf_mesh); for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count(); instance_i++) { Transform3D transform; @@ -5347,22 +5480,22 @@ void GLTFDocument::_convert_multi_mesh_instance_to_gltf( new_gltf_node.instantiate(); new_gltf_node->mesh = mesh_index; new_gltf_node->xform = transform; - new_gltf_node->set_name(_gen_unique_name(state, p_multi_mesh_instance->get_name())); - gltf_node->children.push_back(state->nodes.size()); - state->nodes.push_back(new_gltf_node); + new_gltf_node->set_name(_gen_unique_name(p_state, p_multi_mesh_instance->get_name())); + p_gltf_node->children.push_back(p_state->nodes.size()); + p_state->nodes.push_back(new_gltf_node); } } -void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFState> state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node) { +void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFState> p_state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node) { Skeleton3D *skeleton = p_skeleton3d; Ref<GLTFSkeleton> gltf_skeleton; gltf_skeleton.instantiate(); - // GLTFSkeleton is only used to hold internal state data. It will not be written to the document. + // GLTFSkeleton is only used to hold internal p_state data. It will not be written to the document. // gltf_skeleton->godot_skeleton = skeleton; - GLTFSkeletonIndex skeleton_i = state->skeletons.size(); - state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skeleton_i; - state->skeletons.push_back(gltf_skeleton); + GLTFSkeletonIndex skeleton_i = p_state->skeletons.size(); + p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skeleton_i; + p_state->skeletons.push_back(gltf_skeleton); BoneId bone_count = skeleton->get_bone_count(); for (BoneId bone_i = 0; bone_i < bone_count; bone_i++) { @@ -5370,15 +5503,15 @@ void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFS joint_node.instantiate(); // Note that we cannot use _gen_unique_bone_name here, because glTF spec requires all node // names to be unique regardless of whether or not they are used as joints. - joint_node->set_name(_gen_unique_name(state, skeleton->get_bone_name(bone_i))); + joint_node->set_name(_gen_unique_name(p_state, skeleton->get_bone_name(bone_i))); Transform3D xform = skeleton->get_bone_pose(bone_i); joint_node->scale = xform.basis.get_scale(); joint_node->rotation = xform.basis.get_rotation_quaternion(); joint_node->position = xform.origin; joint_node->joint = true; - GLTFNodeIndex current_node_i = state->nodes.size(); - state->scene_nodes.insert(current_node_i, skeleton); - state->nodes.push_back(joint_node); + GLTFNodeIndex current_node_i = p_state->nodes.size(); + p_state->scene_nodes.insert(current_node_i, skeleton); + p_state->nodes.push_back(joint_node); gltf_skeleton->joints.push_back(current_node_i); if (skeleton->get_bone_parent(bone_i) == -1) { @@ -5391,23 +5524,23 @@ void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFS BoneId parent_bone_id = skeleton->get_bone_parent(bone_i); if (parent_bone_id == -1) { if (p_parent_node_index != -1) { - state->nodes.write[current_node_i]->parent = p_parent_node_index; - state->nodes.write[p_parent_node_index]->children.push_back(current_node_i); + p_state->nodes.write[current_node_i]->parent = p_parent_node_index; + p_state->nodes.write[p_parent_node_index]->children.push_back(current_node_i); } } else { GLTFNodeIndex parent_node_i = gltf_skeleton->godot_bone_node[parent_bone_id]; - state->nodes.write[current_node_i]->parent = parent_node_i; - state->nodes.write[parent_node_i]->children.push_back(current_node_i); + p_state->nodes.write[current_node_i]->parent = parent_node_i; + p_state->nodes.write[parent_node_i]->children.push_back(current_node_i); } } // Remove placeholder skeleton3d node by not creating the gltf node // Skins are per mesh for (int node_i = 0; node_i < skeleton->get_child_count(); node_i++) { - _convert_scene_node(state, skeleton->get_child(node_i), p_parent_node_index, p_root_node_index); + _convert_scene_node(p_state, skeleton->get_child(node_i), p_parent_node_index, p_root_node_index); } } -void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment, Ref<GLTFState> state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node) { +void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment, Ref<GLTFState> p_state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node) { Skeleton3D *skeleton; // Note that relative transforms to external skeletons and pose overrides are not supported. if (p_bone_attachment->get_use_external_skeleton()) { @@ -5416,8 +5549,8 @@ void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_att skeleton = cast_to<Skeleton3D>(p_bone_attachment->get_parent()); } GLTFSkeletonIndex skel_gltf_i = -1; - if (skeleton != nullptr && state->skeleton3d_to_gltf_skeleton.has(skeleton->get_instance_id())) { - skel_gltf_i = state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()]; + if (skeleton != nullptr && p_state->skeleton3d_to_gltf_skeleton.has(skeleton->get_instance_id())) { + skel_gltf_i = p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()]; } int bone_idx = -1; if (skeleton != nullptr) { @@ -5428,28 +5561,28 @@ void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_att } GLTFNodeIndex par_node_index = p_parent_node_index; if (skeleton != nullptr && bone_idx != -1 && skel_gltf_i != -1) { - Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_gltf_i]; + Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_gltf_i]; gltf_skeleton->bone_attachments.push_back(p_bone_attachment); par_node_index = gltf_skeleton->joints[bone_idx]; } for (int node_i = 0; node_i < p_bone_attachment->get_child_count(); node_i++) { - _convert_scene_node(state, p_bone_attachment->get_child(node_i), par_node_index, p_root_node_index); + _convert_scene_node(p_state, p_bone_attachment->get_child(node_i), par_node_index, p_root_node_index); } } -void GLTFDocument::_convert_mesh_instance_to_gltf(MeshInstance3D *p_scene_parent, Ref<GLTFState> state, Ref<GLTFNode> gltf_node) { - GLTFMeshIndex gltf_mesh_index = _convert_mesh_to_gltf(state, p_scene_parent); +void GLTFDocument::_convert_mesh_instance_to_gltf(MeshInstance3D *p_scene_parent, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) { + GLTFMeshIndex gltf_mesh_index = _convert_mesh_to_gltf(p_state, p_scene_parent); if (gltf_mesh_index != -1) { - gltf_node->mesh = gltf_mesh_index; + p_gltf_node->mesh = gltf_mesh_index; } } -void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) { - Ref<GLTFNode> gltf_node = state->nodes[node_index]; +void GLTFDocument::_generate_scene_node(Ref<GLTFState> p_state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) { + Ref<GLTFNode> gltf_node = p_state->nodes[node_index]; if (gltf_node->skeleton >= 0) { - _generate_skeleton_bone_node(state, scene_parent, scene_root, node_index); + _generate_skeleton_bone_node(p_state, scene_parent, scene_root, node_index); return; } @@ -5463,76 +5596,87 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent // skinned meshes must not be placed in a bone attachment. if (non_bone_parented_to_skeleton && gltf_node->skin < 0) { // Bone Attachment - Parent Case - BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent); + BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, node_index, gltf_node->parent); scene_parent->add_child(bone_attachment, true); bone_attachment->set_owner(scene_root); // There is no gltf_node that represent this, so just directly create a unique name - bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment3D")); + bone_attachment->set_name(_gen_unique_name(p_state, "BoneAttachment3D")); // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node // and attach it to the bone_attachment scene_parent = bone_attachment; } - if (gltf_node->mesh >= 0) { - current_node = _generate_mesh_instance(state, node_index); - } else if (gltf_node->camera >= 0) { - current_node = _generate_camera(state, node_index); - } else if (gltf_node->light >= 0) { - current_node = _generate_light(state, node_index); + // Check if any GLTFDocumentExtension classes want to generate a node for us. + for (Ref<GLTFDocumentExtension> ext : document_extensions) { + ERR_CONTINUE(ext.is_null()); + current_node = ext->generate_scene_node(p_state, gltf_node, scene_parent); + if (current_node) { + break; + } } - - // We still have not managed to make a node. + // If none of our GLTFDocumentExtension classes generated us a node, we generate one. if (!current_node) { - current_node = _generate_spatial(state, node_index); + if (gltf_node->mesh >= 0) { + current_node = _generate_mesh_instance(p_state, node_index); + } else if (gltf_node->camera >= 0) { + current_node = _generate_camera(p_state, node_index); + } else if (gltf_node->light >= 0) { + current_node = _generate_light(p_state, node_index); + } else { + current_node = _generate_spatial(p_state, node_index); + } } + // Add the node we generated and set the owner to the scene root. scene_parent->add_child(current_node, true); if (current_node != scene_root) { - current_node->set_owner(scene_root); + Array args; + args.append(scene_root); + current_node->propagate_call(StringName("set_owner"), args); } current_node->set_transform(gltf_node->xform); current_node->set_name(gltf_node->get_name()); - state->scene_nodes.insert(node_index, current_node); + p_state->scene_nodes.insert(node_index, current_node); for (int i = 0; i < gltf_node->children.size(); ++i) { - _generate_scene_node(state, current_node, scene_root, gltf_node->children[i]); + _generate_scene_node(p_state, current_node, scene_root, gltf_node->children[i]); } } -void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) { - Ref<GLTFNode> gltf_node = state->nodes[node_index]; +void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> p_state, Node *p_scene_parent, Node3D *p_scene_root, const GLTFNodeIndex p_node_index) { + Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; Node3D *current_node = nullptr; - Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton; + Skeleton3D *skeleton = p_state->skeletons[gltf_node->skeleton]->godot_skeleton; // In this case, this node is already a bone in skeleton. const bool is_skinned_mesh = (gltf_node->skin >= 0 && gltf_node->mesh >= 0); const bool requires_extra_node = (gltf_node->mesh >= 0 || gltf_node->camera >= 0 || gltf_node->light >= 0); - Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(scene_parent); + Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(p_scene_parent); if (active_skeleton != skeleton) { if (active_skeleton) { // Bone Attachment - Direct Parented Skeleton Case - BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent); + BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, gltf_node->parent); - scene_parent->add_child(bone_attachment, true); - bone_attachment->set_owner(scene_root); + p_scene_parent->add_child(bone_attachment, true); + bone_attachment->set_owner(p_scene_root); // There is no gltf_node that represent this, so just directly create a unique name - bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment3D")); + bone_attachment->set_name(_gen_unique_name(p_state, "BoneAttachment3D")); // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node // and attach it to the bone_attachment - scene_parent = bone_attachment; - WARN_PRINT(vformat("glTF: Generating scene detected direct parented Skeletons at node %d", node_index)); + p_scene_parent = bone_attachment; + WARN_PRINT(vformat("glTF: Generating scene detected direct parented Skeletons at node %d", p_node_index)); } // Add it to the scene if it has not already been added if (skeleton->get_parent() == nullptr) { - scene_parent->add_child(skeleton, true); - skeleton->set_owner(scene_root); + p_scene_parent->add_child(skeleton, true); + skeleton->set_owner(p_scene_root); } } @@ -5543,40 +5687,53 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen // skinned meshes must not be placed in a bone attachment. if (!is_skinned_mesh) { // Bone Attachment - Same Node Case - BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, node_index); + BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, p_node_index); - scene_parent->add_child(bone_attachment, true); - bone_attachment->set_owner(scene_root); + p_scene_parent->add_child(bone_attachment, true); + bone_attachment->set_owner(p_scene_root); // There is no gltf_node that represent this, so just directly create a unique name - bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment3D")); + bone_attachment->set_name(_gen_unique_name(p_state, "BoneAttachment3D")); // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node // and attach it to the bone_attachment - scene_parent = bone_attachment; + p_scene_parent = bone_attachment; } - - // We still have not managed to make a node - if (gltf_node->mesh >= 0) { - current_node = _generate_mesh_instance(state, node_index); - } else if (gltf_node->camera >= 0) { - current_node = _generate_camera(state, node_index); - } else if (gltf_node->light >= 0) { - current_node = _generate_light(state, node_index); + // Check if any GLTFDocumentExtension classes want to generate a node for us. + for (Ref<GLTFDocumentExtension> ext : document_extensions) { + ERR_CONTINUE(ext.is_null()); + current_node = ext->generate_scene_node(p_state, gltf_node, p_scene_parent); + if (current_node) { + break; + } + } + // If none of our GLTFDocumentExtension classes generated us a node, we generate one. + if (!current_node) { + if (gltf_node->mesh >= 0) { + current_node = _generate_mesh_instance(p_state, p_node_index); + } else if (gltf_node->camera >= 0) { + current_node = _generate_camera(p_state, p_node_index); + } else if (gltf_node->light >= 0) { + current_node = _generate_light(p_state, p_node_index); + } else { + current_node = _generate_spatial(p_state, p_node_index); + } } - - scene_parent->add_child(current_node, true); - if (current_node != scene_root) { - current_node->set_owner(scene_root); + // Add the node we generated and set the owner to the scene root. + p_scene_parent->add_child(current_node, true); + if (current_node != p_scene_root) { + Array args; + args.append(p_scene_root); + current_node->propagate_call(StringName("set_owner"), args); } // Do not set transform here. Transform is already applied to our bone. current_node->set_name(gltf_node->get_name()); } - state->scene_nodes.insert(node_index, current_node); + p_state->scene_nodes.insert(p_node_index, current_node); for (int i = 0; i < gltf_node->children.size(); ++i) { - _generate_scene_node(state, active_skeleton, scene_root, gltf_node->children[i]); + _generate_scene_node(p_state, active_skeleton, p_scene_root, gltf_node->children[i]); } } @@ -5701,24 +5858,25 @@ T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T ERR_FAIL_V(p_values[0]); } -void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, const GLTFAnimationIndex index, const int bake_fps) { - Ref<GLTFAnimation> anim = state->animations[index]; +void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, const GLTFAnimationIndex p_index, const float p_bake_fps, const bool p_trimming) { + Ref<GLTFAnimation> anim = p_state->animations[p_index]; - String name = anim->get_name(); - if (name.is_empty()) { + String anim_name = anim->get_name(); + if (anim_name.is_empty()) { // No node represent these, and they are not in the hierarchy, so just make a unique name - name = _gen_unique_name(state, "Animation"); + anim_name = _gen_unique_name(p_state, "Animation"); } Ref<Animation> animation; animation.instantiate(); - animation->set_name(name); + animation->set_name(anim_name); if (anim->get_loop()) { animation->set_loop_mode(Animation::LOOP_LINEAR); } - float length = 0.0; + double anim_start = p_trimming ? INFINITY : 0.0; + double anim_end = 0.0; for (const KeyValue<int, GLTFAnimation::Track> &track_i : anim->get_tracks()) { const GLTFAnimation::Track &track = track_i.value; @@ -5729,38 +5887,59 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, GLTFNodeIndex node_index = track_i.key; - const Ref<GLTFNode> gltf_node = state->nodes[track_i.key]; + const Ref<GLTFNode> gltf_node = p_state->nodes[track_i.key]; - Node *root = ap->get_parent(); + Node *root = p_animation_player->get_parent(); ERR_FAIL_COND(root == nullptr); - HashMap<GLTFNodeIndex, Node *>::Iterator node_element = state->scene_nodes.find(node_index); + HashMap<GLTFNodeIndex, Node *>::Iterator node_element = p_state->scene_nodes.find(node_index); ERR_CONTINUE_MSG(!node_element, vformat("Unable to find node %d for animation", node_index)); node_path = root->get_path_to(node_element->value); if (gltf_node->skeleton >= 0) { - const Skeleton3D *sk = state->skeletons[gltf_node->skeleton]->godot_skeleton; + const Skeleton3D *sk = p_state->skeletons[gltf_node->skeleton]->godot_skeleton; ERR_FAIL_COND(sk == nullptr); - const String path = ap->get_parent()->get_path_to(sk); + const String path = p_animation_player->get_parent()->get_path_to(sk); const String bone = gltf_node->get_name(); transform_node_path = path + ":" + bone; } else { transform_node_path = node_path; } - for (int i = 0; i < track.rotation_track.times.size(); i++) { - length = MAX(length, track.rotation_track.times[i]); - } - for (int i = 0; i < track.position_track.times.size(); i++) { - length = MAX(length, track.position_track.times[i]); - } - for (int i = 0; i < track.scale_track.times.size(); i++) { - length = MAX(length, track.scale_track.times[i]); - } - - for (int i = 0; i < track.weight_tracks.size(); i++) { - for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { - length = MAX(length, track.weight_tracks[i].times[j]); + if (p_trimming) { + for (int i = 0; i < track.rotation_track.times.size(); i++) { + anim_start = MIN(anim_start, track.rotation_track.times[i]); + anim_end = MAX(anim_end, track.rotation_track.times[i]); + } + for (int i = 0; i < track.position_track.times.size(); i++) { + anim_start = MIN(anim_start, track.position_track.times[i]); + anim_end = MAX(anim_end, track.position_track.times[i]); + } + for (int i = 0; i < track.scale_track.times.size(); i++) { + anim_start = MIN(anim_start, track.scale_track.times[i]); + anim_end = MAX(anim_end, track.scale_track.times[i]); + } + for (int i = 0; i < track.weight_tracks.size(); i++) { + for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { + anim_start = MIN(anim_start, track.weight_tracks[i].times[j]); + anim_end = MAX(anim_end, track.weight_tracks[i].times[j]); + } + } + } else { + // If you don't use trimming and the first key time is not at 0.0, fake keys will be inserted. + for (int i = 0; i < track.rotation_track.times.size(); i++) { + anim_end = MAX(anim_end, track.rotation_track.times[i]); + } + for (int i = 0; i < track.position_track.times.size(); i++) { + anim_end = MAX(anim_end, track.position_track.times[i]); + } + for (int i = 0; i < track.scale_track.times.size(); i++) { + anim_end = MAX(anim_end, track.scale_track.times[i]); + } + for (int i = 0; i < track.weight_tracks.size(); i++) { + for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { + anim_end = MAX(anim_end, track.weight_tracks[i].times[j]); + } } } @@ -5774,7 +5953,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, int scale_idx = -1; if (track.position_track.values.size()) { - Vector3 base_pos = state->nodes[track_i.key]->position; + Vector3 base_pos = p_state->nodes[track_i.key]->position; bool not_default = false; //discard the track if all it contains is default values for (int i = 0; i < track.position_track.times.size(); i++) { Vector3 value = track.position_track.values[track.position_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i]; @@ -5793,7 +5972,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } if (track.rotation_track.values.size()) { - Quaternion base_rot = state->nodes[track_i.key]->rotation.normalized(); + Quaternion base_rot = p_state->nodes[track_i.key]->rotation.normalized(); bool not_default = false; //discard the track if all it contains is default values for (int i = 0; i < track.rotation_track.times.size(); i++) { Quaternion value = track.rotation_track.values[track.rotation_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i].normalized(); @@ -5811,7 +5990,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } if (track.scale_track.values.size()) { - Vector3 base_scale = state->nodes[track_i.key]->scale; + Vector3 base_scale = p_state->nodes[track_i.key]->scale; bool not_default = false; //discard the track if all it contains is default values for (int i = 0; i < track.scale_track.times.size(); i++) { Vector3 value = track.scale_track.values[track.scale_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i]; @@ -5829,25 +6008,23 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } - //first determine animation length - - const double increment = 1.0 / bake_fps; - double time = 0.0; + const double increment = 1.0 / p_bake_fps; + double time = anim_start; Vector3 base_pos; Quaternion base_rot; Vector3 base_scale = Vector3(1, 1, 1); if (rotation_idx == -1) { - base_rot = state->nodes[track_i.key]->rotation.normalized(); + base_rot = p_state->nodes[track_i.key]->rotation.normalized(); } if (position_idx == -1) { - base_pos = state->nodes[track_i.key]->position; + base_pos = p_state->nodes[track_i.key]->position; } if (scale_idx == -1) { - base_scale = state->nodes[track_i.key]->scale; + base_scale = p_state->nodes[track_i.key]->scale; } bool last = false; @@ -5858,33 +6035,33 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (position_idx >= 0) { pos = _interpolate_track<Vector3>(track.position_track.times, track.position_track.values, time, track.position_track.interpolation); - animation->position_track_insert_key(position_idx, time, pos); + animation->position_track_insert_key(position_idx, time - anim_start, pos); } if (rotation_idx >= 0) { rot = _interpolate_track<Quaternion>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation); - animation->rotation_track_insert_key(rotation_idx, time, rot); + animation->rotation_track_insert_key(rotation_idx, time - anim_start, rot); } if (scale_idx >= 0) { scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation); - animation->scale_track_insert_key(scale_idx, time, scale); + animation->scale_track_insert_key(scale_idx, time - anim_start, scale); } if (last) { break; } time += increment; - if (time >= length) { + if (time >= anim_end) { last = true; - time = length; + time = anim_end; } } } for (int i = 0; i < track.weight_tracks.size(); i++) { - ERR_CONTINUE(gltf_node->mesh < 0 || gltf_node->mesh >= state->meshes.size()); - Ref<GLTFMesh> mesh = state->meshes[gltf_node->mesh]; + ERR_CONTINUE(gltf_node->mesh < 0 || gltf_node->mesh >= p_state->meshes.size()); + Ref<GLTFMesh> mesh = p_state->meshes[gltf_node->mesh]; ERR_CONTINUE(mesh.is_null()); ERR_CONTINUE(mesh->get_mesh().is_null()); ERR_CONTINUE(mesh->get_mesh()->get_mesh().is_null()); @@ -5907,45 +6084,45 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } else { // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. - const double increment = 1.0 / bake_fps; + const double increment = 1.0 / p_bake_fps; double time = 0.0; bool last = false; while (true) { real_t blend = _interpolate_track<real_t>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, gltf_interp); - animation->blend_shape_track_insert_key(track_idx, time, blend); + animation->blend_shape_track_insert_key(track_idx, time - anim_start, blend); if (last) { break; } time += increment; - if (time >= length) { + if (time >= anim_end) { last = true; - time = length; + time = anim_end; } } } } } - animation->set_length(length); + animation->set_length(anim_end - anim_start); Ref<AnimationLibrary> library; - if (!ap->has_animation_library("")) { + if (!p_animation_player->has_animation_library("")) { library.instantiate(); - ap->add_animation_library("", library); + p_animation_player->add_animation_library("", library); } else { - library = ap->get_animation_library(""); + library = p_animation_player->get_animation_library(""); } - library->add_animation(name, animation); + library->add_animation(anim_name, animation); } -void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { - for (GLTFNodeIndex mi_node_i = 0; mi_node_i < state->nodes.size(); ++mi_node_i) { - Ref<GLTFNode> node = state->nodes[mi_node_i]; +void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> p_state) { + for (GLTFNodeIndex mi_node_i = 0; mi_node_i < p_state->nodes.size(); ++mi_node_i) { + Ref<GLTFNode> node = p_state->nodes[mi_node_i]; if (node->mesh < 0) { continue; } - HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = state->scene_nodes.find(mi_node_i); + HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = p_state->scene_nodes.find(mi_node_i); if (!mi_element) { continue; } @@ -5976,10 +6153,10 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { if (skel_node != nullptr) { godot_skeleton = cast_to<Skeleton3D>(skel_node); } - if (godot_skeleton != nullptr && state->skeleton3d_to_gltf_skeleton.has(godot_skeleton->get_instance_id())) { + if (godot_skeleton != nullptr && p_state->skeleton3d_to_gltf_skeleton.has(godot_skeleton->get_instance_id())) { // This is a skinned mesh. If the mesh has no ARRAY_WEIGHTS or ARRAY_BONES, it will be invisible. - const GLTFSkeletonIndex skeleton_gltf_i = state->skeleton3d_to_gltf_skeleton[godot_skeleton->get_instance_id()]; - Ref<GLTFSkeleton> gltf_skeleton = state->skeletons[skeleton_gltf_i]; + const GLTFSkeletonIndex skeleton_gltf_i = p_state->skeleton3d_to_gltf_skeleton[godot_skeleton->get_instance_id()]; + Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons[skeleton_gltf_i]; int bone_cnt = skeleton->get_bone_count(); ERR_FAIL_COND(bone_cnt != gltf_skeleton->joints.size()); @@ -5993,8 +6170,8 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { if (!gltf_skeleton->roots.is_empty()) { root_gltf_i = gltf_skeleton->roots[0]; } - if (state->skin_and_skeleton3d_to_gltf_skin.has(gltf_skin_key) && state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key].has(gltf_skel_key)) { - skin_gltf_i = state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key]; + if (p_state->skin_and_skeleton3d_to_gltf_skin.has(gltf_skin_key) && p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key].has(gltf_skel_key)) { + skin_gltf_i = p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key]; } else { if (skin.is_null()) { // Note that gltf_skin_key should remain null, so these can share a reference. @@ -6031,9 +6208,9 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { gltf_skin->joint_i_to_bone_i[bind_i] = bone_i; gltf_skin->joint_i_to_name[bind_i] = bind_name; } - skin_gltf_i = state->skins.size(); - state->skins.push_back(gltf_skin); - state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key] = skin_gltf_i; + skin_gltf_i = p_state->skins.size(); + p_state->skins.push_back(gltf_skin); + p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key] = skin_gltf_i; } node->skin = skin_gltf_i; node->skeleton = skeleton_gltf_i; @@ -6041,14 +6218,14 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { } } -float GLTFDocument::solve_metallic(float p_dielectric_specular, float diffuse, float specular, float p_one_minus_specular_strength) { - if (specular <= p_dielectric_specular) { +float GLTFDocument::solve_metallic(float p_dielectric_specular, float p_diffuse, float p_specular, float p_one_minus_specular_strength) { + if (p_specular <= p_dielectric_specular) { return 0.0f; } const float a = p_dielectric_specular; - const float b = diffuse * p_one_minus_specular_strength / (1.0f - p_dielectric_specular) + specular - 2.0f * p_dielectric_specular; - const float c = p_dielectric_specular - specular; + const float b = p_diffuse * p_one_minus_specular_strength / (1.0f - p_dielectric_specular) + p_specular - 2.0f * p_dielectric_specular; + const float c = p_dielectric_specular - p_specular; const float D = b * b - 4.0f * a * c; return CLAMP((-b + Math::sqrt(D)) / (2.0f * a), 0.0f, 1.0f); } @@ -6072,21 +6249,21 @@ float GLTFDocument::get_max_component(const Color &p_color) { return MAX(MAX(r, g), b); } -void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_root) { - for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); ++node_i) { - Ref<GLTFNode> node = state->nodes[node_i]; +void GLTFDocument::_process_mesh_instances(Ref<GLTFState> p_state, Node *p_scene_root) { + for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); ++node_i) { + Ref<GLTFNode> node = p_state->nodes[node_i]; if (node->skin >= 0 && node->mesh >= 0) { const GLTFSkinIndex skin_i = node->skin; - HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = state->scene_nodes.find(node_i); + HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = p_state->scene_nodes.find(node_i); ERR_CONTINUE_MSG(!mi_element, vformat("Unable to find node %d", node_i)); ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(mi_element->value); ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D", node_i, mi_element->value->get_class_name())); - const GLTFSkeletonIndex skel_i = state->skins.write[node->skin]->skeleton; - Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i]; + const GLTFSkeletonIndex skel_i = p_state->skins.write[node->skin]->skeleton; + Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_i]; Skeleton3D *skeleton = gltf_skeleton->godot_skeleton; ERR_CONTINUE_MSG(skeleton == nullptr, vformat("Unable to find Skeleton for node %d skin %d", node_i, skin_i)); @@ -6094,14 +6271,14 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo skeleton->add_child(mi, true); mi->set_owner(skeleton->get_owner()); - mi->set_skin(state->skins.write[skin_i]->godot_skin); + mi->set_skin(p_state->skins.write[skin_i]->godot_skin); mi->set_skeleton_path(mi->get_path_to(skeleton)); mi->set_transform(Transform3D()); } } } -GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, int32_t p_track_i, GLTFNodeIndex p_node_i) { +GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> p_state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, int32_t p_track_i, GLTFNodeIndex p_node_i) { Animation::InterpolationType interpolation = p_animation->track_get_interpolation_type(p_track_i); GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR; @@ -6171,7 +6348,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state for (int32_t key_i = 0; key_i < key_count; key_i++) { Vector3 rotation_radian = p_animation->track_get_key_value(p_track_i, key_i); - p_track.rotation_track.values.write[key_i] = Quaternion(rotation_radian); + p_track.rotation_track.values.write[key_i] = Quaternion::from_euler(rotation_radian); } } else if (path.contains(":scale")) { p_track.scale_track.times = times; @@ -6247,11 +6424,11 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state return p_track; } -void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, String p_animation_track_name) { - Ref<Animation> animation = ap->get_animation(p_animation_track_name); +void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, String p_animation_track_name) { + Ref<Animation> animation = p_animation_player->get_animation(p_animation_track_name); Ref<GLTFAnimation> gltf_animation; gltf_animation.instantiate(); - gltf_animation->set_name(_gen_unique_name(state, p_animation_track_name)); + gltf_animation->set_name(_gen_unique_name(p_state, p_animation_track_name)); for (int32_t track_i = 0; track_i < animation->get_track_count(); track_i++) { if (!animation->track_is_enabled(track_i)) { @@ -6261,8 +6438,8 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (String(orig_track_path).contains(":position")) { const Vector<String> node_suffix = String(orig_track_path).split(":position"); const NodePath path = node_suffix[0]; - const Node *node = ap->get_parent()->get_node_or_null(path); - for (const KeyValue<GLTFNodeIndex, Node *> &position_scene_node_i : state->scene_nodes) { + const Node *node = p_animation_player->get_parent()->get_node_or_null(path); + for (const KeyValue<GLTFNodeIndex, Node *> &position_scene_node_i : p_state->scene_nodes) { if (position_scene_node_i.value == node) { GLTFNodeIndex node_index = position_scene_node_i.key; HashMap<int, GLTFAnimation::Track>::Iterator position_track_i = gltf_animation->get_tracks().find(node_index); @@ -6270,15 +6447,15 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (position_track_i) { track = position_track_i->value; } - track = _convert_animation_track(state, track, animation, track_i, node_index); + track = _convert_animation_track(p_state, track, animation, track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } } else if (String(orig_track_path).contains(":rotation_degrees")) { const Vector<String> node_suffix = String(orig_track_path).split(":rotation_degrees"); const NodePath path = node_suffix[0]; - const Node *node = ap->get_parent()->get_node_or_null(path); - for (const KeyValue<GLTFNodeIndex, Node *> &rotation_degree_scene_node_i : state->scene_nodes) { + const Node *node = p_animation_player->get_parent()->get_node_or_null(path); + for (const KeyValue<GLTFNodeIndex, Node *> &rotation_degree_scene_node_i : p_state->scene_nodes) { if (rotation_degree_scene_node_i.value == node) { GLTFNodeIndex node_index = rotation_degree_scene_node_i.key; HashMap<int, GLTFAnimation::Track>::Iterator rotation_degree_track_i = gltf_animation->get_tracks().find(node_index); @@ -6286,15 +6463,15 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (rotation_degree_track_i) { track = rotation_degree_track_i->value; } - track = _convert_animation_track(state, track, animation, track_i, node_index); + track = _convert_animation_track(p_state, track, animation, track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } } else if (String(orig_track_path).contains(":scale")) { const Vector<String> node_suffix = String(orig_track_path).split(":scale"); const NodePath path = node_suffix[0]; - const Node *node = ap->get_parent()->get_node_or_null(path); - for (const KeyValue<GLTFNodeIndex, Node *> &scale_scene_node_i : state->scene_nodes) { + const Node *node = p_animation_player->get_parent()->get_node_or_null(path); + for (const KeyValue<GLTFNodeIndex, Node *> &scale_scene_node_i : p_state->scene_nodes) { if (scale_scene_node_i.value == node) { GLTFNodeIndex node_index = scale_scene_node_i.key; HashMap<int, GLTFAnimation::Track>::Iterator scale_track_i = gltf_animation->get_tracks().find(node_index); @@ -6302,18 +6479,18 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (scale_track_i) { track = scale_track_i->value; } - track = _convert_animation_track(state, track, animation, track_i, node_index); + track = _convert_animation_track(p_state, track, animation, track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } } else if (String(orig_track_path).contains(":transform")) { const Vector<String> node_suffix = String(orig_track_path).split(":transform"); const NodePath path = node_suffix[0]; - const Node *node = ap->get_parent()->get_node_or_null(path); - for (const KeyValue<GLTFNodeIndex, Node *> &transform_track_i : state->scene_nodes) { + const Node *node = p_animation_player->get_parent()->get_node_or_null(path); + for (const KeyValue<GLTFNodeIndex, Node *> &transform_track_i : p_state->scene_nodes) { if (transform_track_i.value == node) { GLTFAnimation::Track track; - track = _convert_animation_track(state, track, animation, track_i, transform_track_i.key); + track = _convert_animation_track(p_state, track, animation, track_i, transform_track_i.key); gltf_animation->get_tracks().insert(transform_track_i.key, track); } } @@ -6321,12 +6498,12 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, const Vector<String> node_suffix = String(orig_track_path).split(":"); const NodePath path = node_suffix[0]; const String suffix = node_suffix[1]; - Node *node = ap->get_parent()->get_node_or_null(path); + Node *node = p_animation_player->get_parent()->get_node_or_null(path); MeshInstance3D *mi = cast_to<MeshInstance3D>(node); Ref<Mesh> mesh = mi->get_mesh(); ERR_CONTINUE(mesh.is_null()); int32_t mesh_index = -1; - for (const KeyValue<GLTFNodeIndex, Node *> &mesh_track_i : state->scene_nodes) { + for (const KeyValue<GLTFNodeIndex, Node *> &mesh_track_i : p_state->scene_nodes) { if (mesh_track_i.value == node) { mesh_index = mesh_track_i.key; } @@ -6379,15 +6556,15 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, const String node = node_suffix[0]; const NodePath node_path = node; const String suffix = node_suffix[1]; - Node *godot_node = ap->get_parent()->get_node_or_null(node_path); + Node *godot_node = p_animation_player->get_parent()->get_node_or_null(node_path); Skeleton3D *skeleton = nullptr; GLTFSkeletonIndex skeleton_gltf_i = -1; - for (GLTFSkeletonIndex skeleton_i = 0; skeleton_i < state->skeletons.size(); skeleton_i++) { - if (state->skeletons[skeleton_i]->godot_skeleton == cast_to<Skeleton3D>(godot_node)) { - skeleton = state->skeletons[skeleton_i]->godot_skeleton; + for (GLTFSkeletonIndex skeleton_i = 0; skeleton_i < p_state->skeletons.size(); skeleton_i++) { + if (p_state->skeletons[skeleton_i]->godot_skeleton == cast_to<Skeleton3D>(godot_node)) { + skeleton = p_state->skeletons[skeleton_i]->godot_skeleton; skeleton_gltf_i = skeleton_i; ERR_CONTINUE(!skeleton); - Ref<GLTFSkeleton> skeleton_gltf = state->skeletons[skeleton_gltf_i]; + Ref<GLTFSkeleton> skeleton_gltf = p_state->skeletons[skeleton_gltf_i]; int32_t bone = skeleton->find_bone(suffix); ERR_CONTINUE(bone == -1); if (!skeleton_gltf->godot_bone_node.has(bone)) { @@ -6399,14 +6576,14 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (property_track_i) { track = property_track_i->value; } - track = _convert_animation_track(state, track, animation, track_i, node_i); + track = _convert_animation_track(p_state, track, animation, track_i, node_i); gltf_animation->get_tracks()[node_i] = track; } } } else if (!String(orig_track_path).contains(":")) { - ERR_CONTINUE(!ap->get_parent()); - Node *godot_node = ap->get_parent()->get_node_or_null(orig_track_path); - for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : state->scene_nodes) { + ERR_CONTINUE(!p_animation_player->get_parent()); + Node *godot_node = p_animation_player->get_parent()->get_node_or_null(orig_track_path); + for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : p_state->scene_nodes) { if (scene_node_i.value == godot_node) { GLTFNodeIndex node_i = scene_node_i.key; HashMap<int, GLTFAnimation::Track>::Iterator node_track_i = gltf_animation->get_tracks().find(node_i); @@ -6414,7 +6591,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (node_track_i) { track = node_track_i->value; } - track = _convert_animation_track(state, track, animation, track_i, node_i); + track = _convert_animation_track(p_state, track, animation, track_i, node_i); gltf_animation->get_tracks()[node_i] = track; break; } @@ -6422,42 +6599,42 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } if (gltf_animation->get_tracks().size()) { - state->animations.push_back(gltf_animation); + p_state->animations.push_back(gltf_animation); } } -Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps) { +Error GLTFDocument::_parse(Ref<GLTFState> p_state, String p_path, Ref<FileAccess> p_file) { Error err; - if (f.is_null()) { + if (p_file.is_null()) { return FAILED; } - f->seek(0); - uint32_t magic = f->get_32(); + p_file->seek(0); + uint32_t magic = p_file->get_32(); if (magic == 0x46546C67) { //binary file //text file - f->seek(0); - err = _parse_glb(f, state); + p_file->seek(0); + err = _parse_glb(p_file, p_state); if (err != OK) { return err; } } else { - f->seek(0); - String text = f->get_as_utf8_string(); + p_file->seek(0); + String text = p_file->get_as_utf8_string(); JSON json; err = json.parse(text); if (err != OK) { _err_print_error("", "", json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); } ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); - state->json = json.get_data(); + p_state->json = json.get_data(); } - if (!state->json.has("asset")) { + if (!p_state->json.has("asset")) { return ERR_PARSE_ERROR; } - Dictionary asset = state->json["asset"]; + Dictionary asset = p_state->json["asset"]; if (!asset.has("version")) { return ERR_PARSE_ERROR; @@ -6465,17 +6642,21 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> String version = asset["version"]; - state->major_version = version.get_slice(".", 0).to_int(); - state->minor_version = version.get_slice(".", 1).to_int(); + p_state->major_version = version.get_slice(".", 0).to_int(); + p_state->minor_version = version.get_slice(".", 1).to_int(); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + document_extensions.clear(); + for (Ref<GLTFDocumentExtension> ext : all_document_extensions) { ERR_CONTINUE(ext.is_null()); - err = ext->import_preflight(state); - ERR_FAIL_COND_V(err != OK, err); + err = ext->import_preflight(p_state, p_state->json["extensionsUsed"]); + if (err == OK) { + document_extensions.push_back(ext); + } } - err = _parse_gltf_state(state, p_path, p_bake_fps); + + err = _parse_gltf_state(p_state, p_path); ERR_FAIL_COND_V(err != OK, err); + return OK; } @@ -6506,47 +6687,43 @@ Dictionary _serialize_texture_transform_uv(Vector2 p_offset, Vector2 p_scale) { } Dictionary GLTFDocument::_serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material) { - if (p_material.is_valid()) { - Vector3 offset = p_material->get_uv1_offset(); - Vector3 scale = p_material->get_uv1_scale(); - return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); - } - return Dictionary(); + ERR_FAIL_NULL_V(p_material, Dictionary()); + Vector3 offset = p_material->get_uv1_offset(); + Vector3 scale = p_material->get_uv1_scale(); + return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); } Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) { - if (p_material.is_valid()) { - Vector3 offset = p_material->get_uv2_offset(); - Vector3 scale = p_material->get_uv2_scale(); - return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); - } - return Dictionary(); + ERR_FAIL_NULL_V(p_material, Dictionary()); + Vector3 offset = p_material->get_uv2_offset(); + Vector3 scale = p_material->get_uv2_scale(); + return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); } -Error GLTFDocument::_serialize_version(Ref<GLTFState> state) { +Error GLTFDocument::_serialize_version(Ref<GLTFState> p_state) { const String version = "2.0"; - state->major_version = version.get_slice(".", 0).to_int(); - state->minor_version = version.get_slice(".", 1).to_int(); + p_state->major_version = version.get_slice(".", 0).to_int(); + p_state->minor_version = version.get_slice(".", 1).to_int(); Dictionary asset; asset["version"] = version; String hash = String(VERSION_HASH); asset["generator"] = String(VERSION_FULL_NAME) + String("@") + (hash.is_empty() ? String("unknown") : hash); - state->json["asset"] = asset; + p_state->json["asset"] = asset; ERR_FAIL_COND_V(!asset.has("version"), Error::FAILED); - ERR_FAIL_COND_V(!state->json.has("asset"), Error::FAILED); + ERR_FAIL_COND_V(!p_state->json.has("asset"), Error::FAILED); return OK; } -Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { +Error GLTFDocument::_serialize_file(Ref<GLTFState> p_state, const String p_path) { Error err = FAILED; if (p_path.to_lower().ends_with("glb")) { - err = _encode_buffer_glb(state, p_path); + err = _encode_buffer_glb(p_state, p_path); ERR_FAIL_COND_V(err != OK, err); - Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V(f.is_null(), FAILED); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V(file.is_null(), FAILED); - String json = Variant(state->json).to_json_string(); + String json = Variant(p_state->json).to_json_string(); const uint32_t magic = 0x46546C67; // GLTF const int32_t header_size = 12; @@ -6557,106 +6734,104 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { const uint32_t text_chunk_type = 0x4E4F534A; //JSON uint32_t binary_data_length = 0; - if (state->buffers.size()) { - binary_data_length = state->buffers[0].size(); + if (p_state->buffers.size()) { + binary_data_length = p_state->buffers[0].size(); } const uint32_t binary_chunk_length = ((binary_data_length + 3) & (~3)); const uint32_t binary_chunk_type = 0x004E4942; //BIN - f->create(FileAccess::ACCESS_RESOURCES); - f->store_32(magic); - f->store_32(state->major_version); // version - f->store_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_chunk_length); // length - f->store_32(text_chunk_length); - f->store_32(text_chunk_type); - f->store_buffer((uint8_t *)&cs[0], cs.length()); + file->create(FileAccess::ACCESS_RESOURCES); + file->store_32(magic); + file->store_32(p_state->major_version); // version + file->store_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_chunk_length); // length + file->store_32(text_chunk_length); + file->store_32(text_chunk_type); + file->store_buffer((uint8_t *)&cs[0], cs.length()); for (uint32_t pad_i = text_data_length; pad_i < text_chunk_length; pad_i++) { - f->store_8(' '); + file->store_8(' '); } if (binary_chunk_length) { - f->store_32(binary_chunk_length); - f->store_32(binary_chunk_type); - f->store_buffer(state->buffers[0].ptr(), binary_data_length); + file->store_32(binary_chunk_length); + file->store_32(binary_chunk_type); + file->store_buffer(p_state->buffers[0].ptr(), binary_data_length); } for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) { - f->store_8(0); + file->store_8(0); } } else { - err = _encode_buffer_bins(state, p_path); + err = _encode_buffer_bins(p_state, p_path); ERR_FAIL_COND_V(err != OK, err); - Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V(f.is_null(), FAILED); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V(file.is_null(), FAILED); - f->create(FileAccess::ACCESS_RESOURCES); - String json = Variant(state->json).to_json_string(); - f->store_string(json); + file->create(FileAccess::ACCESS_RESOURCES); + String json = Variant(p_state->json).to_json_string(); + file->store_string(json); } return err; } void GLTFDocument::_bind_methods() { - ClassDB::bind_method(D_METHOD("append_from_file", "path", "state", "flags", "bake_fps", "base_path"), - &GLTFDocument::append_from_file, DEFVAL(0), DEFVAL(30), DEFVAL(String())); - ClassDB::bind_method(D_METHOD("append_from_buffer", "bytes", "base_path", "state", "flags", "bake_fps"), - &GLTFDocument::append_from_buffer, DEFVAL(0), DEFVAL(30)); - ClassDB::bind_method(D_METHOD("append_from_scene", "node", "state", "flags", "bake_fps"), - &GLTFDocument::append_from_scene, DEFVAL(0), DEFVAL(30)); - ClassDB::bind_method(D_METHOD("generate_scene", "state", "bake_fps"), - &GLTFDocument::generate_scene, DEFVAL(30)); + ClassDB::bind_method(D_METHOD("append_from_file", "path", "state", "flags", "base_path"), + &GLTFDocument::append_from_file, DEFVAL(0), DEFVAL(String())); + ClassDB::bind_method(D_METHOD("append_from_buffer", "bytes", "base_path", "state", "flags"), + &GLTFDocument::append_from_buffer, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("append_from_scene", "node", "state", "flags"), + &GLTFDocument::append_from_scene, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("generate_scene", "state", "bake_fps", "trimming"), + &GLTFDocument::generate_scene, DEFVAL(30), DEFVAL(false)); ClassDB::bind_method(D_METHOD("generate_buffer", "state"), &GLTFDocument::generate_buffer); ClassDB::bind_method(D_METHOD("write_to_filesystem", "state", "path"), &GLTFDocument::write_to_filesystem); - ClassDB::bind_method(D_METHOD("set_extensions", "extensions"), - &GLTFDocument::set_extensions); - ClassDB::bind_method(D_METHOD("get_extensions"), - &GLTFDocument::get_extensions); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "extensions", PROPERTY_HINT_ARRAY_TYPE, - vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "GLTFDocumentExtension"), - PROPERTY_USAGE_DEFAULT), - "set_extensions", "get_extensions"); + ClassDB::bind_static_method("GLTFDocument", D_METHOD("register_gltf_document_extension", "extension", "first_priority"), + &GLTFDocument::register_gltf_document_extension, DEFVAL(false)); + ClassDB::bind_static_method("GLTFDocument", D_METHOD("unregister_gltf_document_extension", "extension"), + &GLTFDocument::unregister_gltf_document_extension); } -void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> state) { +void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> p_state) { // build the hierarchy - for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) { - for (int j = 0; j < state->nodes[node_i]->children.size(); j++) { - GLTFNodeIndex child_i = state->nodes[node_i]->children[j]; - ERR_FAIL_INDEX(child_i, state->nodes.size()); - if (state->nodes.write[child_i]->parent != -1) { + for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) { + for (int j = 0; j < p_state->nodes[node_i]->children.size(); j++) { + GLTFNodeIndex child_i = p_state->nodes[node_i]->children[j]; + ERR_FAIL_INDEX(child_i, p_state->nodes.size()); + if (p_state->nodes.write[child_i]->parent != -1) { continue; } - state->nodes.write[child_i]->parent = node_i; + p_state->nodes.write[child_i]->parent = node_i; } } } -void GLTFDocument::set_extensions(TypedArray<GLTFDocumentExtension> p_extensions) { - document_extensions = p_extensions; +Vector<Ref<GLTFDocumentExtension>> GLTFDocument::all_document_extensions; + +void GLTFDocument::register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority) { + if (all_document_extensions.find(p_extension) == -1) { + if (p_first_priority) { + all_document_extensions.insert(0, p_extension); + } else { + all_document_extensions.push_back(p_extension); + } + } } -TypedArray<GLTFDocumentExtension> GLTFDocument::get_extensions() const { - return document_extensions; +void GLTFDocument::unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension) { + all_document_extensions.erase(p_extension); } -GLTFDocument::GLTFDocument() { - bool is_editor = ::Engine::get_singleton()->is_editor_hint(); - if (is_editor) { - return; - } - Ref<GLTFDocumentExtensionConvertImporterMesh> extension_editor; - extension_editor.instantiate(); - document_extensions.push_back(extension_editor); +void GLTFDocument::unregister_all_gltf_document_extensions() { + all_document_extensions.clear(); } -PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> state, Error *r_err) { - Error err = _encode_buffer_glb(state, ""); +PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err) { + Error err = _encode_buffer_glb(p_state, ""); if (r_err) { *r_err = err; } ERR_FAIL_COND_V(err != OK, PackedByteArray()); - String json = Variant(state->json).to_json_string(); + String json = Variant(p_state->json).to_json_string(); const uint32_t magic = 0x46546C67; // GLTF const int32_t header_size = 12; @@ -6670,8 +6845,8 @@ PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> state, Error const uint32_t text_chunk_type = 0x4E4F534A; //JSON int32_t binary_data_length = 0; - if (state->buffers.size()) { - binary_data_length = state->buffers[0].size(); + if (p_state->buffers.size()) { + binary_data_length = p_state->buffers[0].size(); } const int32_t binary_chunk_length = binary_data_length; const int32_t binary_chunk_type = 0x004E4942; //BIN @@ -6679,7 +6854,7 @@ PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> state, Error Ref<StreamPeerBuffer> buffer; buffer.instantiate(); buffer->put_32(magic); - buffer->put_32(state->major_version); // version + buffer->put_32(p_state->major_version); // version buffer->put_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_data_length); // length buffer->put_32(text_chunk_length); buffer->put_32(text_chunk_type); @@ -6687,206 +6862,210 @@ PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> state, Error if (binary_chunk_length) { buffer->put_32(binary_chunk_length); buffer->put_32(binary_chunk_type); - buffer->put_data(state->buffers[0].ptr(), binary_data_length); + buffer->put_data(p_state->buffers[0].ptr(), binary_data_length); } return buffer->get_data_array(); } -PackedByteArray GLTFDocument::generate_buffer(Ref<GLTFState> state) { - ERR_FAIL_NULL_V(state, PackedByteArray()); - Error err = _serialize(state, ""); +PackedByteArray GLTFDocument::generate_buffer(Ref<GLTFState> p_state) { + ERR_FAIL_NULL_V(p_state, PackedByteArray()); + Error err = _serialize(p_state, ""); ERR_FAIL_COND_V(err != OK, PackedByteArray()); - PackedByteArray bytes = _serialize_glb_buffer(state, &err); + PackedByteArray bytes = _serialize_glb_buffer(p_state, &err); return bytes; } -Error GLTFDocument::write_to_filesystem(Ref<GLTFState> state, const String &p_path) { - ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER); - Error err = _serialize(state, p_path); +Error GLTFDocument::write_to_filesystem(Ref<GLTFState> p_state, const String &p_path) { + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + Error err = _serialize(p_state, p_path); if (err != OK) { return err; } - err = _serialize_file(state, p_path); + err = _serialize_file(p_state, p_path); if (err != OK) { return Error::FAILED; } return OK; } -Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) { - ERR_FAIL_NULL_V(state, nullptr); - ERR_FAIL_INDEX_V(0, state->root_nodes.size(), nullptr); +Node *GLTFDocument::generate_scene(Ref<GLTFState> p_state, float p_bake_fps, bool p_trimming) { + ERR_FAIL_NULL_V(p_state, nullptr); + ERR_FAIL_INDEX_V(0, p_state->root_nodes.size(), nullptr); Error err = OK; - GLTFNodeIndex gltf_root = state->root_nodes.write[0]; - Node *gltf_root_node = state->get_scene_node(gltf_root); + GLTFNodeIndex gltf_root = p_state->root_nodes.write[0]; + Node *gltf_root_node = p_state->get_scene_node(gltf_root); Node *root = gltf_root_node->get_parent(); ERR_FAIL_NULL_V(root, nullptr); - _process_mesh_instances(state, root); - if (state->get_create_animations() && state->animations.size()) { + _process_mesh_instances(p_state, root); + if (p_state->get_create_animations() && p_state->animations.size()) { AnimationPlayer *ap = memnew(AnimationPlayer); root->add_child(ap, true); ap->set_owner(root); - for (int i = 0; i < state->animations.size(); i++) { - _import_animation(state, ap, i, p_bake_fps); + for (int i = 0; i < p_state->animations.size(); i++) { + _import_animation(p_state, ap, i, p_bake_fps, p_trimming); } } - for (KeyValue<GLTFNodeIndex, Node *> E : state->scene_nodes) { + for (KeyValue<GLTFNodeIndex, Node *> E : p_state->scene_nodes) { ERR_CONTINUE(!E.value); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); - ERR_CONTINUE(!state->json.has("nodes")); - Array nodes = state->json["nodes"]; + ERR_CONTINUE(!p_state->json.has("nodes")); + Array nodes = p_state->json["nodes"]; ERR_CONTINUE(E.key >= nodes.size()); ERR_CONTINUE(E.key < 0); Dictionary node_json = nodes[E.key]; - Ref<GLTFNode> gltf_node = state->nodes[E.key]; - err = ext->import_node(state, gltf_node, node_json, E.value); + Ref<GLTFNode> gltf_node = p_state->nodes[E.key]; + err = ext->import_node(p_state, gltf_node, node_json, E.value); ERR_CONTINUE(err != OK); } } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); - err = ext->import_post(state, root); + err = ext->import_post(p_state, root); ERR_CONTINUE(err != OK); } ERR_FAIL_NULL_V(root, nullptr); return root; } -Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) { - ERR_FAIL_COND_V(state.is_null(), FAILED); - state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; - state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; +Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint32_t p_flags) { + ERR_FAIL_COND_V(p_state.is_null(), FAILED); + p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; + p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + document_extensions.clear(); + for (Ref<GLTFDocumentExtension> ext : all_document_extensions) { ERR_CONTINUE(ext.is_null()); - Error err = ext->export_preflight(p_node); - ERR_FAIL_COND_V(err != OK, FAILED); + Error err = ext->export_preflight(p_state, p_node); + if (err == OK) { + document_extensions.push_back(ext); + } } - _convert_scene_node(state, p_node, -1, -1); - if (!state->buffers.size()) { - state->buffers.push_back(Vector<uint8_t>()); + _convert_scene_node(p_state, p_node, -1, -1); + if (!p_state->buffers.size()) { + p_state->buffers.push_back(Vector<uint8_t>()); } return OK; } -Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) { - ERR_FAIL_COND_V(state.is_null(), FAILED); +Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> p_state, uint32_t p_flags) { + ERR_FAIL_COND_V(p_state.is_null(), FAILED); // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire Error err = FAILED; - state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; - state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; + p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; + p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; Ref<FileAccessMemory> file_access; file_access.instantiate(); file_access->open_custom(p_bytes.ptr(), p_bytes.size()); - state->base_path = p_base_path.get_base_dir(); - err = _parse(state, state->base_path, file_access, p_bake_fps); + p_state->base_path = p_base_path.get_base_dir(); + err = _parse(p_state, p_state->base_path, file_access); ERR_FAIL_COND_V(err != OK, err); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); - err = ext->import_post_parse(state); + err = ext->import_post_parse(p_state); ERR_FAIL_COND_V(err != OK, err); } return OK; } -Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_search_path, float p_bake_fps) { +Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> p_state, const String &p_search_path) { Error err; /* PARSE EXTENSIONS */ - err = _parse_gltf_extensions(state); + err = _parse_gltf_extensions(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE SCENE */ - err = _parse_scenes(state); + err = _parse_scenes(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE NODES */ - err = _parse_nodes(state); + err = _parse_nodes(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE BUFFERS */ - err = _parse_buffers(state, p_search_path); + err = _parse_buffers(p_state, p_search_path); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE BUFFER VIEWS */ - err = _parse_buffer_views(state); + err = _parse_buffer_views(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE ACCESSORS */ - err = _parse_accessors(state); + err = _parse_accessors(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); - if (!state->discard_meshes_and_materials) { + if (!p_state->discard_meshes_and_materials) { /* PARSE IMAGES */ - err = _parse_images(state, p_search_path); + err = _parse_images(p_state, p_search_path); + + ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); + + /* PARSE TEXTURE SAMPLERS */ + err = _parse_texture_samplers(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE TEXTURES */ - err = _parse_textures(state); + err = _parse_textures(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE TEXTURES */ - err = _parse_materials(state); + err = _parse_materials(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); } /* PARSE SKINS */ - err = _parse_skins(state); + err = _parse_skins(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* DETERMINE SKELETONS */ - err = _determine_skeletons(state); + err = _determine_skeletons(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* CREATE SKELETONS */ - err = _create_skeletons(state); + err = _create_skeletons(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* CREATE SKINS */ - err = _create_skins(state); + err = _create_skins(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE MESHES (we have enough info now) */ - err = _parse_meshes(state); + err = _parse_meshes(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE LIGHTS */ - err = _parse_lights(state); + err = _parse_lights(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE CAMERAS */ - err = _parse_cameras(state); + err = _parse_cameras(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE ANIMATIONS */ - err = _parse_animations(state); + err = _parse_animations(p_state); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* ASSIGN SCENE NAMES */ - _assign_scene_names(state); + _assign_scene_names(p_state); Node3D *root = memnew(Node3D); - for (int32_t root_i = 0; root_i < state->root_nodes.size(); root_i++) { - _generate_scene_node(state, root, root, state->root_nodes[root_i]); + for (int32_t root_i = 0; root_i < p_state->root_nodes.size(); root_i++) { + _generate_scene_node(p_state, root, root, p_state->root_nodes[root_i]); } return OK; } -Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags, int32_t p_bake_fps, String p_base_path) { +Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags, String p_base_path) { // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire if (r_state == Ref<GLTFState>()) { r_state.instantiate(); @@ -6895,18 +7074,17 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint r_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; r_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; Error err; - Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN); - ERR_FAIL_NULL_V(f, ERR_FILE_CANT_OPEN); + ERR_FAIL_NULL_V(file, ERR_FILE_CANT_OPEN); String base_path = p_base_path; if (base_path.is_empty()) { base_path = p_path.get_base_dir(); } r_state->base_path = base_path; - err = _parse(r_state, base_path, f, p_bake_fps); + err = _parse(r_state, base_path, file); ERR_FAIL_COND_V(err != OK, err); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); err = ext->import_post_parse(r_state); ERR_FAIL_COND_V(err != OK, err); @@ -6914,14 +7092,33 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint return OK; } -Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) { - ERR_FAIL_NULL_V(state, ERR_PARSE_ERROR); - if (state->json.has("extensionsRequired") && state->json["extensionsRequired"].get_type() == Variant::ARRAY) { - Array extensions_required = state->json["extensionsRequired"]; - if (extensions_required.find("KHR_draco_mesh_compression") != -1) { - ERR_PRINT("glTF2 extension KHR_draco_mesh_compression is not supported."); - return ERR_UNAVAILABLE; +Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> p_state) { + ERR_FAIL_NULL_V(p_state, ERR_PARSE_ERROR); + if (p_state->json.has("extensionsUsed")) { + Vector<String> ext_array = p_state->json["extensionsUsed"]; + p_state->extensions_used = ext_array; + } + if (p_state->json.has("extensionsRequired")) { + Vector<String> ext_array = p_state->json["extensionsRequired"]; + p_state->extensions_required = ext_array; + } + HashSet<String> supported_extensions; + supported_extensions.insert("KHR_lights_punctual"); + supported_extensions.insert("KHR_materials_pbrSpecularGlossiness"); + supported_extensions.insert("KHR_texture_transform"); + for (Ref<GLTFDocumentExtension> ext : document_extensions) { + ERR_CONTINUE(ext.is_null()); + Vector<String> ext_supported_extensions = ext->get_supported_extensions(); + for (int i = 0; i < ext_supported_extensions.size(); ++i) { + supported_extensions.insert(ext_supported_extensions[i]); } } - return OK; + Error ret = Error::OK; + for (int i = 0; i < p_state->extensions_required.size(); i++) { + if (!supported_extensions.has(p_state->extensions_required[i])) { + ERR_PRINT("GLTF: Can't import file '" + p_state->filename + "', required extension '" + String(p_state->extensions_required[i]) + "' is not supported. Are you missing a GLTFDocumentExtension plugin?"); + ret = ERR_UNAVAILABLE; + } + } + return ret; } diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 36a2f94a4e..6e2d0e2fd4 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -31,26 +31,19 @@ #ifndef GLTF_DOCUMENT_H #define GLTF_DOCUMENT_H -#include "gltf_defines.h" -#include "structures/gltf_animation.h" - -#include "scene/3d/bone_attachment_3d.h" -#include "scene/3d/importer_mesh_instance_3d.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/animation/animation_player.h" -#include "scene/resources/material.h" +#include "extensions/gltf_document_extension.h" #include "modules/modules_enabled.gen.h" // For csg, gridmap. class GLTFDocument : public Resource { GDCLASS(GLTFDocument, Resource); - TypedArray<GLTFDocumentExtension> document_extensions; + static Vector<Ref<GLTFDocumentExtension>> all_document_extensions; + Vector<Ref<GLTFDocumentExtension>> document_extensions; private: const float BAKE_FPS = 30.0f; public: - GLTFDocument(); const int32_t JOINT_GROUP_SIZE = 4; enum { @@ -76,196 +69,204 @@ protected: static void _bind_methods(); public: - void set_extensions(TypedArray<GLTFDocumentExtension> p_extensions); - TypedArray<GLTFDocumentExtension> get_extensions() const; + static void register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority = false); + static void unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension); + static void unregister_all_gltf_document_extensions(); private: - void _build_parent_hierachy(Ref<GLTFState> state); + void _build_parent_hierachy(Ref<GLTFState> p_state); double _filter_number(double p_float); String _get_component_type_name(const uint32_t p_component); - int _get_component_type_size(const int component_type); - Error _parse_scenes(Ref<GLTFState> state); - Error _parse_nodes(Ref<GLTFState> state); + int _get_component_type_size(const int p_component_type); + Error _parse_scenes(Ref<GLTFState> p_state); + Error _parse_nodes(Ref<GLTFState> p_state); String _get_type_name(const GLTFType p_component); String _get_accessor_type_name(const GLTFType p_type); - String _gen_unique_name(Ref<GLTFState> state, const String &p_name); - String _sanitize_animation_name(const String &name); - String _gen_unique_animation_name(Ref<GLTFState> state, const String &p_name); - String _sanitize_bone_name(const String &name); - String _gen_unique_bone_name(Ref<GLTFState> state, - const GLTFSkeletonIndex skel_i, + String _gen_unique_name(Ref<GLTFState> p_state, const String &p_name); + String _sanitize_animation_name(const String &p_name); + String _gen_unique_animation_name(Ref<GLTFState> p_state, const String &p_name); + String _sanitize_bone_name(const String &p_name); + String _gen_unique_bone_name(Ref<GLTFState> p_state, + const GLTFSkeletonIndex p_skel_i, const String &p_name); - GLTFTextureIndex _set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture); - Ref<Texture2D> _get_texture(Ref<GLTFState> state, + GLTFTextureIndex _set_texture(Ref<GLTFState> p_state, Ref<Texture2D> p_texture, + StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats); + Ref<Texture2D> _get_texture(Ref<GLTFState> p_state, + const GLTFTextureIndex p_texture); + GLTFTextureSamplerIndex _set_sampler_for_mode(Ref<GLTFState> p_state, + StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats); + Ref<GLTFTextureSampler> _get_sampler_for_texture(Ref<GLTFState> p_state, const GLTFTextureIndex p_texture); - Error _parse_json(const String &p_path, Ref<GLTFState> state); - Error _parse_glb(Ref<FileAccess> f, Ref<GLTFState> state); - void _compute_node_heights(Ref<GLTFState> state); - Error _parse_buffers(Ref<GLTFState> state, const String &p_base_path); - Error _parse_buffer_views(Ref<GLTFState> state); + Error _parse_json(const String &p_path, Ref<GLTFState> p_state); + Error _parse_glb(Ref<FileAccess> p_file, Ref<GLTFState> p_state); + void _compute_node_heights(Ref<GLTFState> p_state); + Error _parse_buffers(Ref<GLTFState> p_state, const String &p_base_path); + Error _parse_buffer_views(Ref<GLTFState> p_state); GLTFType _get_type_from_str(const String &p_string); - Error _parse_accessors(Ref<GLTFState> state); - Error _decode_buffer_view(Ref<GLTFState> state, double *dst, + Error _parse_accessors(Ref<GLTFState> p_state); + Error _decode_buffer_view(Ref<GLTFState> p_state, double *p_dst, const GLTFBufferViewIndex p_buffer_view, - const int skip_every, const int skip_bytes, - const int element_size, const int count, - const GLTFType type, const int component_count, - const int component_type, const int component_size, - const bool normalized, const int byte_offset, - const bool for_vertex); - Vector<double> _decode_accessor(Ref<GLTFState> state, + const int p_skip_every, const int p_skip_bytes, + const int p_element_size, const int p_count, + const GLTFType p_type, const int p_component_count, + const int p_component_type, const int p_component_size, + const bool p_normalized, const int p_byte_offset, + const bool p_for_vertex); + Vector<double> _decode_accessor(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<float> _decode_accessor_as_floats(Ref<GLTFState> state, + Vector<float> _decode_accessor_as_floats(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<int> _decode_accessor_as_ints(Ref<GLTFState> state, + Vector<int> _decode_accessor_as_ints(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Vector2> _decode_accessor_as_vec2(Ref<GLTFState> state, + Vector<Vector2> _decode_accessor_as_vec2(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Vector3> _decode_accessor_as_vec3(Ref<GLTFState> state, + Vector<Vector3> _decode_accessor_as_vec3(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Color> _decode_accessor_as_color(Ref<GLTFState> state, + Vector<Color> _decode_accessor_as_color(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Quaternion> _decode_accessor_as_quaternion(Ref<GLTFState> state, + Vector<Quaternion> _decode_accessor_as_quaternion(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Transform2D> _decode_accessor_as_xform2d(Ref<GLTFState> state, + Vector<Transform2D> _decode_accessor_as_xform2d(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Basis> _decode_accessor_as_basis(Ref<GLTFState> state, + Vector<Basis> _decode_accessor_as_basis(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Transform3D> _decode_accessor_as_xform(Ref<GLTFState> state, + Vector<Transform3D> _decode_accessor_as_xform(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Error _parse_meshes(Ref<GLTFState> state); - Error _serialize_textures(Ref<GLTFState> state); - Error _serialize_images(Ref<GLTFState> state, const String &p_path); - Error _serialize_lights(Ref<GLTFState> state); - Error _parse_images(Ref<GLTFState> state, const String &p_base_path); - Error _parse_textures(Ref<GLTFState> state); - Error _parse_materials(Ref<GLTFState> state); - void _set_texture_transform_uv1(const Dictionary &d, Ref<BaseMaterial3D> material); + Error _parse_meshes(Ref<GLTFState> p_state); + Error _serialize_textures(Ref<GLTFState> p_state); + Error _serialize_texture_samplers(Ref<GLTFState> p_state); + Error _serialize_images(Ref<GLTFState> p_state, const String &p_path); + Error _serialize_lights(Ref<GLTFState> p_state); + Error _parse_images(Ref<GLTFState> p_state, const String &p_base_path); + Error _parse_textures(Ref<GLTFState> p_state); + Error _parse_texture_samplers(Ref<GLTFState> p_state); + Error _parse_materials(Ref<GLTFState> p_state); + void _set_texture_transform_uv1(const Dictionary &d, Ref<BaseMaterial3D> p_material); void spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Ref<BaseMaterial3D> p_material); static void spec_gloss_to_metal_base_color(const Color &p_specular_factor, const Color &p_diffuse, Color &r_base_color, float &r_metallic); - GLTFNodeIndex _find_highest_node(Ref<GLTFState> state, - const Vector<GLTFNodeIndex> &subset); - bool _capture_nodes_in_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin, - const GLTFNodeIndex node_index); - void _capture_nodes_for_multirooted_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin); - Error _expand_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin); - Error _verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin); - Error _parse_skins(Ref<GLTFState> state); - Error _determine_skeletons(Ref<GLTFState> state); + GLTFNodeIndex _find_highest_node(Ref<GLTFState> p_state, + const Vector<GLTFNodeIndex> &p_subset); + bool _capture_nodes_in_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin, + const GLTFNodeIndex p_node_index); + void _capture_nodes_for_multirooted_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin); + Error _expand_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin); + Error _verify_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin); + Error _parse_skins(Ref<GLTFState> p_state); + Error _determine_skeletons(Ref<GLTFState> p_state); Error _reparent_non_joint_skeleton_subtrees( - Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton, - const Vector<GLTFNodeIndex> &non_joints); - Error _determine_skeleton_roots(Ref<GLTFState> state, - const GLTFSkeletonIndex skel_i); - Error _create_skeletons(Ref<GLTFState> state); - Error _map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> state); - Error _serialize_skins(Ref<GLTFState> state); - Error _create_skins(Ref<GLTFState> state); - bool _skins_are_same(const Ref<Skin> skin_a, const Ref<Skin> skin_b); - void _remove_duplicate_skins(Ref<GLTFState> state); - Error _serialize_cameras(Ref<GLTFState> state); - Error _parse_cameras(Ref<GLTFState> state); - Error _parse_lights(Ref<GLTFState> state); - Error _parse_animations(Ref<GLTFState> state); - Error _serialize_animations(Ref<GLTFState> state); - BoneAttachment3D *_generate_bone_attachment(Ref<GLTFState> state, - Skeleton3D *skeleton, - const GLTFNodeIndex node_index, - const GLTFNodeIndex bone_index); - ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, const GLTFNodeIndex node_index); - Camera3D *_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index); - Node3D *_generate_light(Ref<GLTFState> state, const GLTFNodeIndex node_index); - Node3D *_generate_spatial(Ref<GLTFState> state, const GLTFNodeIndex node_index); - void _assign_scene_names(Ref<GLTFState> state); + Ref<GLTFState> p_state, Ref<GLTFSkeleton> p_skeleton, + const Vector<GLTFNodeIndex> &p_non_joints); + Error _determine_skeleton_roots(Ref<GLTFState> p_state, + const GLTFSkeletonIndex p_skel_i); + Error _create_skeletons(Ref<GLTFState> p_state); + Error _map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> p_state); + Error _serialize_skins(Ref<GLTFState> p_state); + Error _create_skins(Ref<GLTFState> p_state); + bool _skins_are_same(const Ref<Skin> p_skin_a, const Ref<Skin> p_skin_b); + void _remove_duplicate_skins(Ref<GLTFState> p_state); + Error _serialize_cameras(Ref<GLTFState> p_state); + Error _parse_cameras(Ref<GLTFState> p_state); + Error _parse_lights(Ref<GLTFState> p_state); + Error _parse_animations(Ref<GLTFState> p_state); + Error _serialize_animations(Ref<GLTFState> p_state); + BoneAttachment3D *_generate_bone_attachment(Ref<GLTFState> p_state, + Skeleton3D *p_skeleton, + const GLTFNodeIndex p_node_index, + const GLTFNodeIndex p_bone_index); + ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index); + Camera3D *_generate_camera(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index); + Light3D *_generate_light(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index); + Node3D *_generate_spatial(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index); + void _assign_scene_names(Ref<GLTFState> p_state); template <class T> T _interpolate_track(const Vector<real_t> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp); - GLTFAccessorIndex _encode_accessor_as_quaternions(Ref<GLTFState> state, + GLTFAccessorIndex _encode_accessor_as_quaternions(Ref<GLTFState> p_state, const Vector<Quaternion> p_attribs, const bool p_for_vertex); - GLTFAccessorIndex _encode_accessor_as_weights(Ref<GLTFState> state, + GLTFAccessorIndex _encode_accessor_as_weights(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex); - GLTFAccessorIndex _encode_accessor_as_joints(Ref<GLTFState> state, + GLTFAccessorIndex _encode_accessor_as_joints(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex); - GLTFAccessorIndex _encode_accessor_as_floats(Ref<GLTFState> state, + GLTFAccessorIndex _encode_accessor_as_floats(Ref<GLTFState> p_state, const Vector<real_t> p_attribs, const bool p_for_vertex); - GLTFAccessorIndex _encode_accessor_as_vec2(Ref<GLTFState> state, + GLTFAccessorIndex _encode_accessor_as_vec2(Ref<GLTFState> p_state, const Vector<Vector2> p_attribs, const bool p_for_vertex); - void _calc_accessor_vec2_min_max(int i, const int element_count, Vector<double> &type_max, Vector2 attribs, Vector<double> &type_min) { - if (i == 0) { - for (int32_t type_i = 0; type_i < element_count; type_i++) { - type_max.write[type_i] = attribs[(i * element_count) + type_i]; - type_min.write[type_i] = attribs[(i * element_count) + type_i]; + void _calc_accessor_vec2_min_max(int p_i, const int p_element_count, Vector<double> &p_type_max, Vector2 p_attribs, Vector<double> &p_type_min) { + if (p_i == 0) { + for (int32_t type_i = 0; type_i < p_element_count; type_i++) { + p_type_max.write[type_i] = p_attribs[(p_i * p_element_count) + type_i]; + p_type_min.write[type_i] = p_attribs[(p_i * p_element_count) + type_i]; } } - for (int32_t type_i = 0; type_i < element_count; type_i++) { - type_max.write[type_i] = MAX(attribs[(i * element_count) + type_i], type_max[type_i]); - type_min.write[type_i] = MIN(attribs[(i * element_count) + type_i], type_min[type_i]); - type_max.write[type_i] = _filter_number(type_max.write[type_i]); - type_min.write[type_i] = _filter_number(type_min.write[type_i]); + for (int32_t type_i = 0; type_i < p_element_count; type_i++) { + p_type_max.write[type_i] = MAX(p_attribs[(p_i * p_element_count) + type_i], p_type_max[type_i]); + p_type_min.write[type_i] = MIN(p_attribs[(p_i * p_element_count) + type_i], p_type_min[type_i]); + p_type_max.write[type_i] = _filter_number(p_type_max.write[type_i]); + p_type_min.write[type_i] = _filter_number(p_type_min.write[type_i]); } } - GLTFAccessorIndex _encode_accessor_as_vec3(Ref<GLTFState> state, + GLTFAccessorIndex _encode_accessor_as_vec3(Ref<GLTFState> p_state, const Vector<Vector3> p_attribs, const bool p_for_vertex); - GLTFAccessorIndex _encode_accessor_as_color(Ref<GLTFState> state, + GLTFAccessorIndex _encode_accessor_as_color(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex); void _calc_accessor_min_max(int p_i, const int p_element_count, Vector<double> &p_type_max, Vector<double> p_attribs, Vector<double> &p_type_min); - GLTFAccessorIndex _encode_accessor_as_ints(Ref<GLTFState> state, + GLTFAccessorIndex _encode_accessor_as_ints(Ref<GLTFState> p_state, const Vector<int32_t> p_attribs, const bool p_for_vertex); - GLTFAccessorIndex _encode_accessor_as_xform(Ref<GLTFState> state, + GLTFAccessorIndex _encode_accessor_as_xform(Ref<GLTFState> p_state, const Vector<Transform3D> p_attribs, const bool p_for_vertex); - Error _encode_buffer_view(Ref<GLTFState> state, const double *src, - const int count, const GLTFType type, - const int component_type, const bool normalized, - const int byte_offset, const bool for_vertex, + Error _encode_buffer_view(Ref<GLTFState> p_state, const double *p_src, + const int p_count, const GLTFType p_type, + const int p_component_type, const bool p_normalized, + const int p_byte_offset, const bool p_for_vertex, GLTFBufferViewIndex &r_accessor); - Error _encode_accessors(Ref<GLTFState> state); - Error _encode_buffer_views(Ref<GLTFState> state); - Error _serialize_materials(Ref<GLTFState> state); - Error _serialize_meshes(Ref<GLTFState> state); - Error _serialize_nodes(Ref<GLTFState> state); - Error _serialize_scenes(Ref<GLTFState> state); + Error _encode_accessors(Ref<GLTFState> p_state); + Error _encode_buffer_views(Ref<GLTFState> p_state); + Error _serialize_materials(Ref<GLTFState> p_state); + Error _serialize_meshes(Ref<GLTFState> p_state); + Error _serialize_nodes(Ref<GLTFState> p_state); + Error _serialize_scenes(Ref<GLTFState> p_state); String interpolation_to_string(const GLTFAnimation::Interpolation p_interp); - GLTFAnimation::Track _convert_animation_track(Ref<GLTFState> state, + GLTFAnimation::Track _convert_animation_track(Ref<GLTFState> p_state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, int32_t p_track_i, GLTFNodeIndex p_node_i); - Error _encode_buffer_bins(Ref<GLTFState> state, const String &p_path); - Error _encode_buffer_glb(Ref<GLTFState> state, const String &p_path); - PackedByteArray _serialize_glb_buffer(Ref<GLTFState> state, Error *r_err); + Error _encode_buffer_bins(Ref<GLTFState> p_state, const String &p_path); + Error _encode_buffer_glb(Ref<GLTFState> p_state, const String &p_path); + PackedByteArray _serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err); Dictionary _serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material); Dictionary _serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material); - Error _serialize_version(Ref<GLTFState> state); - Error _serialize_file(Ref<GLTFState> state, const String p_path); - Error _serialize_extensions(Ref<GLTFState> state) const; + Error _serialize_version(Ref<GLTFState> p_state); + Error _serialize_file(Ref<GLTFState> p_state, const String p_path); + Error _serialize_gltf_extensions(Ref<GLTFState> p_state) const; public: // https://www.itu.int/rec/R-REC-BT.601 @@ -277,90 +278,90 @@ public: private: // https://github.com/microsoft/glTF-SDK/blob/master/GLTFSDK/Source/PBRUtils.cpp#L9 // https://bghgary.github.io/glTF/convert-between-workflows-bjs/js/babylon.pbrUtilities.js - static float solve_metallic(float p_dielectric_specular, float diffuse, - float specular, + static float solve_metallic(float p_dielectric_specular, float p_diffuse, + float p_specular, float p_one_minus_specular_strength); static float get_perceived_brightness(const Color p_color); static float get_max_component(const Color &p_color); public: - Error append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30, String p_base_path = String()); - Error append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30); - Error append_from_scene(Node *p_node, Ref<GLTFState> r_state, uint32_t p_flags = 0, int32_t p_bake_fps = 30); + Error append_from_file(String p_path, Ref<GLTFState> r_state, uint32_t p_flags = 0, String p_base_path = String()); + Error append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> r_state, uint32_t p_flags = 0); + Error append_from_scene(Node *p_node, Ref<GLTFState> r_state, uint32_t p_flags = 0); public: - Node *generate_scene(Ref<GLTFState> state, int32_t p_bake_fps = 30.0f); - PackedByteArray generate_buffer(Ref<GLTFState> state); - Error write_to_filesystem(Ref<GLTFState> state, const String &p_path); + Node *generate_scene(Ref<GLTFState> p_state, float p_bake_fps = 30.0f, bool p_trimming = false); + PackedByteArray generate_buffer(Ref<GLTFState> p_state); + Error write_to_filesystem(Ref<GLTFState> p_state, const String &p_path); public: - Error _parse_gltf_state(Ref<GLTFState> state, const String &p_search_path, float p_bake_fps); - Error _parse_gltf_extensions(Ref<GLTFState> state); - void _process_mesh_instances(Ref<GLTFState> state, Node *scene_root); - void _generate_scene_node(Ref<GLTFState> state, Node *scene_parent, - Node3D *scene_root, - const GLTFNodeIndex node_index); - void _generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index); - void _import_animation(Ref<GLTFState> state, AnimationPlayer *ap, - const GLTFAnimationIndex index, const int bake_fps); - void _convert_mesh_instances(Ref<GLTFState> state); - GLTFCameraIndex _convert_camera(Ref<GLTFState> state, Camera3D *p_camera); - void _convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Ref<GLTFNode> gltf_node); - GLTFLightIndex _convert_light(Ref<GLTFState> state, Light3D *p_light); - void _convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node); - void _convert_scene_node(Ref<GLTFState> state, Node *p_current, + Error _parse_gltf_state(Ref<GLTFState> p_state, const String &p_search_path); + Error _parse_gltf_extensions(Ref<GLTFState> p_state); + void _process_mesh_instances(Ref<GLTFState> p_state, Node *p_scene_root); + void _generate_scene_node(Ref<GLTFState> p_state, Node *p_scene_parent, + Node3D *p_scene_root, + const GLTFNodeIndex p_node_index); + void _generate_skeleton_bone_node(Ref<GLTFState> p_state, Node *p_scene_parent, Node3D *p_scene_root, const GLTFNodeIndex p_node_index); + void _import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, + const GLTFAnimationIndex p_index, const float p_bake_fps, const bool p_trimming); + void _convert_mesh_instances(Ref<GLTFState> p_state); + GLTFCameraIndex _convert_camera(Ref<GLTFState> p_state, Camera3D *p_camera); + void _convert_light_to_gltf(Light3D *p_light, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node); + GLTFLightIndex _convert_light(Ref<GLTFState> p_state, Light3D *p_light); + void _convert_spatial(Ref<GLTFState> p_state, Node3D *p_spatial, Ref<GLTFNode> p_node); + void _convert_scene_node(Ref<GLTFState> p_state, Node *p_current, const GLTFNodeIndex p_gltf_current, const GLTFNodeIndex p_gltf_root); #ifdef MODULE_CSG_ENABLED - void _convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state); + void _convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state); #endif // MODULE_CSG_ENABLED - void _create_gltf_node(Ref<GLTFState> state, + void _create_gltf_node(Ref<GLTFState> p_state, Node *p_scene_parent, - GLTFNodeIndex current_node_i, + GLTFNodeIndex p_current_node_i, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, - Ref<GLTFNode> gltf_node); + Ref<GLTFNode> p_gltf_node); void _convert_animation_player_to_gltf( - AnimationPlayer *animation_player, Ref<GLTFState> state, + AnimationPlayer *p_animation_player, Ref<GLTFState> p_state, GLTFNodeIndex p_gltf_current, GLTFNodeIndex p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent); - void _check_visibility(Node *p_node, bool &retflag); - void _convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> state, - Ref<GLTFNode> gltf_node); + void _check_visibility(Node *p_node, bool &r_retflag); + void _convert_camera_to_gltf(Camera3D *p_camera, Ref<GLTFState> p_state, + Ref<GLTFNode> p_gltf_node); #ifdef MODULE_GRIDMAP_ENABLED void _convert_grid_map_to_gltf( GridMap *p_grid_map, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, - Ref<GLTFNode> gltf_node, Ref<GLTFState> state); + Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state); #endif // MODULE_GRIDMAP_ENABLED void _convert_multi_mesh_instance_to_gltf( MultiMeshInstance3D *p_multi_mesh_instance, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, - Ref<GLTFNode> gltf_node, Ref<GLTFState> state); + Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state); void _convert_skeleton_to_gltf( - Skeleton3D *p_scene_parent, Ref<GLTFState> state, + Skeleton3D *p_scene_parent, Ref<GLTFState> p_state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, - Ref<GLTFNode> gltf_node); + Ref<GLTFNode> p_gltf_node); void _convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment, - Ref<GLTFState> state, + Ref<GLTFState> p_state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, - Ref<GLTFNode> gltf_node); + Ref<GLTFNode> p_gltf_node); void _convert_mesh_instance_to_gltf(MeshInstance3D *p_mesh_instance, - Ref<GLTFState> state, - Ref<GLTFNode> gltf_node); - GLTFMeshIndex _convert_mesh_to_gltf(Ref<GLTFState> state, + Ref<GLTFState> p_state, + Ref<GLTFNode> p_gltf_node); + GLTFMeshIndex _convert_mesh_to_gltf(Ref<GLTFState> p_state, MeshInstance3D *p_mesh_instance); - void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, + void _convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, String p_animation_track_name); - Error _serialize(Ref<GLTFState> state, const String &p_path); - Error _parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps); + Error _serialize(Ref<GLTFState> p_state, const String &p_path); + Error _parse(Ref<GLTFState> p_state, String p_path, Ref<FileAccess> p_file); }; #endif // GLTF_DOCUMENT_H diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index 85bac446cc..9f6cb20935 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -30,7 +30,10 @@ #include "gltf_state.h" +#include "gltf_template_convert.h" + void GLTFState::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_used_extension", "extension_name", "required"), &GLTFState::add_used_extension); ClassDB::bind_method(D_METHOD("get_json"), &GLTFState::get_json); ClassDB::bind_method(D_METHOD("set_json", "json"), &GLTFState::set_json); ClassDB::bind_method(D_METHOD("get_major_version"), &GLTFState::get_major_version); @@ -63,6 +66,8 @@ void GLTFState::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_nodes", "root_nodes"), &GLTFState::set_root_nodes); ClassDB::bind_method(D_METHOD("get_textures"), &GLTFState::get_textures); ClassDB::bind_method(D_METHOD("set_textures", "textures"), &GLTFState::set_textures); + ClassDB::bind_method(D_METHOD("get_texture_samplers"), &GLTFState::get_texture_samplers); + ClassDB::bind_method(D_METHOD("set_texture_samplers", "texture_samplers"), &GLTFState::set_texture_samplers); ClassDB::bind_method(D_METHOD("get_images"), &GLTFState::get_images); ClassDB::bind_method(D_METHOD("set_images", "images"), &GLTFState::set_images); ClassDB::bind_method(D_METHOD("get_skins"), &GLTFState::get_skins); @@ -84,6 +89,8 @@ void GLTFState::_bind_methods() { ClassDB::bind_method(D_METHOD("get_animations"), &GLTFState::get_animations); ClassDB::bind_method(D_METHOD("set_animations", "animations"), &GLTFState::set_animations); ClassDB::bind_method(D_METHOD("get_scene_node", "idx"), &GLTFState::get_scene_node); + 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); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "json"), "set_json", "get_json"); // Dictionary ADD_PROPERTY(PropertyInfo(Variant::INT, "major_version"), "set_major_version", "get_major_version"); // int @@ -100,6 +107,7 @@ void GLTFState::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_path"), "set_base_path", "get_base_path"); // String ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "root_nodes"), "set_root_nodes", "get_root_nodes"); // Vector<int> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_textures", "get_textures"); // Vector<Ref<GLTFTexture>> + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "texture_samplers", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_texture_samplers", "get_texture_samplers"); //Vector<Ref<GLTFTextureSampler>> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "images", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_images", "get_images"); // Vector<Ref<Texture> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skins", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skins", "get_skins"); // Vector<Ref<GLTFSkin>> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "cameras", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_cameras", "get_cameras"); // Vector<Ref<GLTFCamera>> @@ -112,6 +120,17 @@ void GLTFState::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>> } +void GLTFState::add_used_extension(const String &p_extension_name, bool p_required) { + if (!extensions_used.has(p_extension_name)) { + extensions_used.push_back(p_extension_name); + } + if (p_required) { + if (!extensions_required.has(p_extension_name)) { + extensions_required.push_back(p_extension_name); + } + } +} + Dictionary GLTFState::get_json() { return json; } @@ -192,11 +211,11 @@ void GLTFState::set_meshes(TypedArray<GLTFMesh> p_meshes) { GLTFTemplateConvert::set_from_array(meshes, p_meshes); } -TypedArray<BaseMaterial3D> GLTFState::get_materials() { +TypedArray<Material> GLTFState::get_materials() { return GLTFTemplateConvert::to_array(materials); } -void GLTFState::set_materials(TypedArray<BaseMaterial3D> p_materials) { +void GLTFState::set_materials(TypedArray<Material> p_materials) { GLTFTemplateConvert::set_from_array(materials, p_materials); } @@ -224,6 +243,14 @@ void GLTFState::set_textures(TypedArray<GLTFTexture> p_textures) { GLTFTemplateConvert::set_from_array(textures, p_textures); } +TypedArray<GLTFTextureSampler> GLTFState::get_texture_samplers() { + return GLTFTemplateConvert::to_array(texture_samplers); +} + +void GLTFState::set_texture_samplers(TypedArray<GLTFTextureSampler> p_texture_samplers) { + GLTFTemplateConvert::set_from_array(texture_samplers, p_texture_samplers); +} + TypedArray<Texture2D> GLTFState::get_images() { return GLTFTemplateConvert::to_array(images); } @@ -335,3 +362,11 @@ String GLTFState::get_base_path() { void GLTFState::set_base_path(String p_base_path) { base_path = p_base_path; } + +Variant GLTFState::get_additional_data(const StringName &p_extension_name) { + return additional_data[p_extension_name]; +} + +void GLTFState::set_additional_data(const StringName &p_extension_name, Variant p_additional_data) { + additional_data[p_extension_name] = p_additional_data; +} diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index 6b2d1ca228..e264da69e0 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -32,7 +32,6 @@ #define GLTF_STATE_H #include "extensions/gltf_light.h" -#include "gltf_template_convert.h" #include "structures/gltf_accessor.h" #include "structures/gltf_animation.h" #include "structures/gltf_buffer_view.h" @@ -42,10 +41,7 @@ #include "structures/gltf_skeleton.h" #include "structures/gltf_skin.h" #include "structures/gltf_texture.h" - -#include "core/templates/rb_map.h" -#include "scene/animation/animation_player.h" -#include "scene/resources/texture.h" +#include "structures/gltf_texture_sampler.h" class GLTFState : public Resource { GDCLASS(GLTFState, Resource); @@ -71,13 +67,17 @@ class GLTFState : public Resource { Vector<Ref<GLTFMesh>> meshes; // meshes are loaded directly, no reason not to. Vector<AnimationPlayer *> animation_players; - HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex> material_cache; - Vector<Ref<BaseMaterial3D>> materials; + HashMap<Ref<Material>, GLTFMaterialIndex> material_cache; + Vector<Ref<Material>> materials; String scene_name; Vector<int> root_nodes; Vector<Ref<GLTFTexture>> textures; + Vector<Ref<GLTFTextureSampler>> texture_samplers; + Ref<GLTFTextureSampler> default_texture_sampler; Vector<Ref<Texture2D>> images; + Vector<String> extensions_used; + Vector<String> extensions_required; Vector<Ref<GLTFSkin>> skins; Vector<Ref<GLTFCamera>> cameras; @@ -92,11 +92,14 @@ class GLTFState : public Resource { HashMap<ObjectID, GLTFSkeletonIndex> skeleton3d_to_gltf_skeleton; HashMap<ObjectID, HashMap<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_gltf_skin; + Dictionary additional_data; protected: static void _bind_methods(); public: + void add_used_extension(const String &p_extension, bool p_required = false); + Dictionary get_json(); void set_json(Dictionary p_json); @@ -130,8 +133,8 @@ public: TypedArray<GLTFMesh> get_meshes(); void set_meshes(TypedArray<GLTFMesh> p_meshes); - TypedArray<BaseMaterial3D> get_materials(); - void set_materials(TypedArray<BaseMaterial3D> p_materials); + TypedArray<Material> get_materials(); + void set_materials(TypedArray<Material> p_materials); String get_scene_name(); void set_scene_name(String p_scene_name); @@ -145,6 +148,9 @@ public: TypedArray<GLTFTexture> get_textures(); void set_textures(TypedArray<GLTFTexture> p_textures); + TypedArray<GLTFTextureSampler> get_texture_samplers(); + void set_texture_samplers(TypedArray<GLTFTextureSampler> p_texture_samplers); + TypedArray<Texture2D> get_images(); void set_images(TypedArray<Texture2D> p_images); @@ -181,20 +187,8 @@ public: AnimationPlayer *get_animation_player(int idx); - //void set_scene_nodes(RBMap<GLTFNodeIndex, Node *> p_scene_nodes) { - // this->scene_nodes = p_scene_nodes; - //} - - //void set_animation_players(Vector<AnimationPlayer *> p_animation_players) { - // this->animation_players = p_animation_players; - //} - - //RBMap<Ref<Material>, GLTFMaterialIndex> get_material_cache() { - // return this->material_cache; - //} - //void set_material_cache(RBMap<Ref<Material>, GLTFMaterialIndex> p_material_cache) { - // this->material_cache = p_material_cache; - //} + Variant get_additional_data(const StringName &p_extension_name); + void set_additional_data(const StringName &p_extension_name, Variant p_additional_data); }; #endif // GLTF_STATE_H diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index dbbccc9bcc..2322e13ae2 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -30,23 +30,9 @@ #include "register_types.h" -#ifndef _3D_DISABLED - -#include "extensions/gltf_light.h" +#include "extensions/gltf_document_extension_convert_importer_mesh.h" #include "extensions/gltf_spec_gloss.h" #include "gltf_document.h" -#include "gltf_document_extension.h" -#include "gltf_document_extension_convert_importer_mesh.h" -#include "gltf_state.h" -#include "structures/gltf_accessor.h" -#include "structures/gltf_animation.h" -#include "structures/gltf_buffer_view.h" -#include "structures/gltf_camera.h" -#include "structures/gltf_mesh.h" -#include "structures/gltf_node.h" -#include "structures/gltf_skeleton.h" -#include "structures/gltf_skin.h" -#include "structures/gltf_texture.h" #ifdef TOOLS_ENABLED #include "core/config/project_settings.h" @@ -94,20 +80,22 @@ static void _editor_init() { EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "filesystem/import/fbx/fbx2gltf_path", PROPERTY_HINT_GLOBAL_FILE)); if (fbx_enabled) { - Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (fbx2gltf_path.is_empty()) { - WARN_PRINT("FBX file import is enabled in the project settings, but no FBX2glTF path is configured in the editor settings. FBX files will not be imported."); - } else if (!da->file_exists(fbx2gltf_path)) { - WARN_PRINT("FBX file import is enabled, but the FBX2glTF path doesn't point to an accessible file. FBX files will not be imported."); - } else { - Ref<EditorSceneFormatImporterFBX> importer; - importer.instantiate(); - ResourceImporterScene::add_importer(importer); - } + Ref<EditorSceneFormatImporterFBX> importer; + importer.instantiate(); + ResourceImporterScene::get_scene_singleton()->add_importer(importer); + + Ref<EditorFileSystemImportFormatSupportQueryFBX> fbx_import_query; + fbx_import_query.instantiate(); + EditorFileSystem::get_singleton()->add_import_format_support_query(fbx_import_query); } } #endif // TOOLS_ENABLED +#define GLTF_REGISTER_DOCUMENT_EXTENSION(m_doc_ext_class) \ + Ref<m_doc_ext_class> extension_##m_doc_ext_class; \ + extension_##m_doc_ext_class.instantiate(); \ + GLTFDocument::register_gltf_document_extension(extension_##m_doc_ext_class); + void initialize_gltf_module(ModuleInitializationLevel p_level) { if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) { // glTF API available at runtime. @@ -126,6 +114,12 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(GLTFSpecGloss); GDREGISTER_CLASS(GLTFState); GDREGISTER_CLASS(GLTFTexture); + GDREGISTER_CLASS(GLTFTextureSampler); + // Register GLTFDocumentExtension classes with GLTFDocument. + bool is_editor = ::Engine::get_singleton()->is_editor_hint(); + if (!is_editor) { + GLTF_REGISTER_DOCUMENT_EXTENSION(GLTFDocumentExtensionConvertImporterMesh); + } } #ifdef TOOLS_ENABLED @@ -142,6 +136,11 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) { GLOBAL_DEF_RST("filesystem/import/fbx/enabled", true); GDREGISTER_CLASS(EditorSceneFormatImporterBlend); GDREGISTER_CLASS(EditorSceneFormatImporterFBX); + // Can't (a priori) run external app on these platforms. + GLOBAL_DEF_RST("filesystem/import/blender/enabled.android", false); + GLOBAL_DEF_RST("filesystem/import/blender/enabled.web", false); + GLOBAL_DEF_RST("filesystem/import/fbx/enabled.android", false); + GLOBAL_DEF_RST("filesystem/import/fbx/enabled.web", false); ClassDB::set_current_api(prev_api); EditorNode::add_init_callback(_editor_init); @@ -154,6 +153,5 @@ void uninitialize_gltf_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } + GLTFDocument::unregister_all_gltf_document_extensions(); } - -#endif // _3D_DISABLED diff --git a/modules/gltf/register_types.h b/modules/gltf/register_types.h index 90b9a83c88..bf2730d2ef 100644 --- a/modules/gltf/register_types.h +++ b/modules/gltf/register_types.h @@ -28,7 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef GLTF_REGISTER_TYPES_H +#define GLTF_REGISTER_TYPES_H + #include "modules/register_module_types.h" void initialize_gltf_module(ModuleInitializationLevel p_level); void uninitialize_gltf_module(ModuleInitializationLevel p_level); + +#endif // GLTF_REGISTER_TYPES_H diff --git a/modules/gltf/structures/gltf_accessor.h b/modules/gltf/structures/gltf_accessor.h index bfb71d57fe..8e4bb2d3f9 100644 --- a/modules/gltf/structures/gltf_accessor.h +++ b/modules/gltf/structures/gltf_accessor.h @@ -31,9 +31,8 @@ #ifndef GLTF_ACCESSOR_H #define GLTF_ACCESSOR_H -#include "core/io/resource.h" - #include "../gltf_defines.h" +#include "core/io/resource.h" struct GLTFAccessor : public Resource { GDCLASS(GLTFAccessor, Resource); diff --git a/modules/gltf/structures/gltf_animation.h b/modules/gltf/structures/gltf_animation.h index 3777f579f6..fc535631bb 100644 --- a/modules/gltf/structures/gltf_animation.h +++ b/modules/gltf/structures/gltf_animation.h @@ -31,7 +31,7 @@ #ifndef GLTF_ANIMATION_H #define GLTF_ANIMATION_H -#include "core/io/resource.h" +#include "scene/animation/animation_player.h" class GLTFAnimation : public Resource { GDCLASS(GLTFAnimation, Resource); diff --git a/modules/gltf/structures/gltf_buffer_view.cpp b/modules/gltf/structures/gltf_buffer_view.cpp index ba19ed8628..a15141225b 100644 --- a/modules/gltf/structures/gltf_buffer_view.cpp +++ b/modules/gltf/structures/gltf_buffer_view.cpp @@ -30,8 +30,6 @@ #include "gltf_buffer_view.h" -#include "../gltf_document_extension.h" - void GLTFBufferView::_bind_methods() { ClassDB::bind_method(D_METHOD("get_buffer"), &GLTFBufferView::get_buffer); ClassDB::bind_method(D_METHOD("set_buffer", "buffer"), &GLTFBufferView::set_buffer); diff --git a/modules/gltf/structures/gltf_camera.cpp b/modules/gltf/structures/gltf_camera.cpp index 212b9b80c8..7a5ab2763c 100644 --- a/modules/gltf/structures/gltf_camera.cpp +++ b/modules/gltf/structures/gltf_camera.cpp @@ -30,6 +30,8 @@ #include "gltf_camera.h" +#include "scene/3d/camera_3d.h" + void GLTFCamera::_bind_methods() { ClassDB::bind_static_method("GLTFCamera", D_METHOD("from_node", "camera_node"), &GLTFCamera::from_node); ClassDB::bind_method(D_METHOD("to_node"), &GLTFCamera::to_node); diff --git a/modules/gltf/structures/gltf_camera.h b/modules/gltf/structures/gltf_camera.h index 50ae10e17a..5e8a1da5f7 100644 --- a/modules/gltf/structures/gltf_camera.h +++ b/modules/gltf/structures/gltf_camera.h @@ -32,7 +32,8 @@ #define GLTF_CAMERA_H #include "core/io/resource.h" -#include "scene/3d/camera_3d.h" + +class Camera3D; // Reference and test file: // https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_015_SimpleCameras.md @@ -64,7 +65,7 @@ public: real_t get_depth_near() const { return depth_near; } void set_depth_near(real_t p_val) { depth_near = p_val; } - static Ref<GLTFCamera> from_node(const Camera3D *p_light); + static Ref<GLTFCamera> from_node(const Camera3D *p_camera); Camera3D *to_node() const; static Ref<GLTFCamera> from_dictionary(const Dictionary p_dictionary); diff --git a/modules/gltf/structures/gltf_mesh.h b/modules/gltf/structures/gltf_mesh.h index 2fa37fd727..92722ce75c 100644 --- a/modules/gltf/structures/gltf_mesh.h +++ b/modules/gltf/structures/gltf_mesh.h @@ -31,10 +31,8 @@ #ifndef GLTF_MESH_H #define GLTF_MESH_H -#include "core/io/resource.h" -#include "scene/3d/importer_mesh_instance_3d.h" +#include "../gltf_defines.h" #include "scene/resources/importer_mesh.h" -#include "scene/resources/mesh.h" class GLTFMesh : public Resource { GDCLASS(GLTFMesh, Resource); diff --git a/modules/gltf/structures/gltf_node.cpp b/modules/gltf/structures/gltf_node.cpp index 86280603fa..6fd36f93b7 100644 --- a/modules/gltf/structures/gltf_node.cpp +++ b/modules/gltf/structures/gltf_node.cpp @@ -57,6 +57,8 @@ void GLTFNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_children", "children"), &GLTFNode::set_children); ClassDB::bind_method(D_METHOD("get_light"), &GLTFNode::get_light); ClassDB::bind_method(D_METHOD("set_light", "light"), &GLTFNode::set_light); + ClassDB::bind_method(D_METHOD("get_additional_data", "extension_name"), &GLTFNode::get_additional_data); + ClassDB::bind_method(D_METHOD("set_additional_data", "extension_name", "additional_data"), &GLTFNode::set_additional_data); ADD_PROPERTY(PropertyInfo(Variant::INT, "parent"), "set_parent", "get_parent"); // GLTFNodeIndex ADD_PROPERTY(PropertyInfo(Variant::INT, "height"), "set_height", "get_height"); // int @@ -176,3 +178,11 @@ GLTFLightIndex GLTFNode::get_light() { void GLTFNode::set_light(GLTFLightIndex p_light) { light = p_light; } + +Variant GLTFNode::get_additional_data(const StringName &p_extension_name) { + return additional_data[p_extension_name]; +} + +void GLTFNode::set_additional_data(const StringName &p_extension_name, Variant p_additional_data) { + additional_data[p_extension_name] = p_additional_data; +} diff --git a/modules/gltf/structures/gltf_node.h b/modules/gltf/structures/gltf_node.h index 1a57ea32e2..90a4fa99ed 100644 --- a/modules/gltf/structures/gltf_node.h +++ b/modules/gltf/structures/gltf_node.h @@ -53,6 +53,7 @@ private: Vector3 scale = Vector3(1, 1, 1); Vector<int> children; GLTFLightIndex light = -1; + Dictionary additional_data; protected: static void _bind_methods(); @@ -96,6 +97,9 @@ public: GLTFLightIndex get_light(); void set_light(GLTFLightIndex p_light); + + Variant get_additional_data(const StringName &p_extension_name); + void set_additional_data(const StringName &p_extension_name, Variant p_additional_data); }; #endif // GLTF_NODE_H diff --git a/modules/gltf/structures/gltf_texture.cpp b/modules/gltf/structures/gltf_texture.cpp index 2a21cb3df8..5cc96e3221 100644 --- a/modules/gltf/structures/gltf_texture.cpp +++ b/modules/gltf/structures/gltf_texture.cpp @@ -33,8 +33,11 @@ void GLTFTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("get_src_image"), &GLTFTexture::get_src_image); ClassDB::bind_method(D_METHOD("set_src_image", "src_image"), &GLTFTexture::set_src_image); + ClassDB::bind_method(D_METHOD("get_sampler"), &GLTFTexture::get_sampler); + ClassDB::bind_method(D_METHOD("set_sampler", "sampler"), &GLTFTexture::set_sampler); ADD_PROPERTY(PropertyInfo(Variant::INT, "src_image"), "set_src_image", "get_src_image"); // int + ADD_PROPERTY(PropertyInfo(Variant::INT, "sampler"), "set_sampler", "get_sampler"); // int } GLTFImageIndex GLTFTexture::get_src_image() const { @@ -44,3 +47,11 @@ GLTFImageIndex GLTFTexture::get_src_image() const { void GLTFTexture::set_src_image(GLTFImageIndex val) { src_image = val; } + +GLTFTextureSamplerIndex GLTFTexture::get_sampler() const { + return sampler; +} + +void GLTFTexture::set_sampler(GLTFTextureSamplerIndex val) { + sampler = val; +} diff --git a/modules/gltf/structures/gltf_texture.h b/modules/gltf/structures/gltf_texture.h index b1d12dddfa..b26c8a7b07 100644 --- a/modules/gltf/structures/gltf_texture.h +++ b/modules/gltf/structures/gltf_texture.h @@ -39,6 +39,7 @@ class GLTFTexture : public Resource { private: GLTFImageIndex src_image = 0; + GLTFTextureSamplerIndex sampler = -1; protected: static void _bind_methods(); @@ -46,6 +47,8 @@ protected: public: GLTFImageIndex get_src_image() const; void set_src_image(GLTFImageIndex val); + GLTFTextureSamplerIndex get_sampler() const; + void set_sampler(GLTFTextureSamplerIndex val); }; #endif // GLTF_TEXTURE_H diff --git a/modules/gltf/structures/gltf_texture_sampler.cpp b/modules/gltf/structures/gltf_texture_sampler.cpp new file mode 100644 index 0000000000..6cf615b6cc --- /dev/null +++ b/modules/gltf/structures/gltf_texture_sampler.cpp @@ -0,0 +1,47 @@ +/*************************************************************************/ +/* gltf_texture_sampler.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "gltf_texture_sampler.h" + +void GLTFTextureSampler::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_mag_filter"), &GLTFTextureSampler::get_mag_filter); + ClassDB::bind_method(D_METHOD("set_mag_filter", "filter_mode"), &GLTFTextureSampler::set_mag_filter); + ClassDB::bind_method(D_METHOD("get_min_filter"), &GLTFTextureSampler::get_min_filter); + ClassDB::bind_method(D_METHOD("set_min_filter", "filter_mode"), &GLTFTextureSampler::set_min_filter); + ClassDB::bind_method(D_METHOD("get_wrap_s"), &GLTFTextureSampler::get_wrap_s); + ClassDB::bind_method(D_METHOD("set_wrap_s", "wrap_mode"), &GLTFTextureSampler::set_wrap_s); + ClassDB::bind_method(D_METHOD("get_wrap_t"), &GLTFTextureSampler::get_wrap_t); + ClassDB::bind_method(D_METHOD("set_wrap_t", "wrap_mode"), &GLTFTextureSampler::set_wrap_t); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "mag_filter"), "set_mag_filter", "get_mag_filter"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "min_filter"), "set_min_filter", "get_min_filter"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_s"), "set_wrap_s", "get_wrap_s"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_t"), "set_wrap_t", "get_wrap_t"); +} diff --git a/modules/gltf/structures/gltf_texture_sampler.h b/modules/gltf/structures/gltf_texture_sampler.h new file mode 100644 index 0000000000..7bb7cd62e3 --- /dev/null +++ b/modules/gltf/structures/gltf_texture_sampler.h @@ -0,0 +1,162 @@ +/*************************************************************************/ +/* gltf_texture_sampler.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GLTF_TEXTURE_SAMPLER_H +#define GLTF_TEXTURE_SAMPLER_H + +#include "scene/resources/material.h" + +class GLTFTextureSampler : public Resource { + GDCLASS(GLTFTextureSampler, Resource); + +public: + enum FilterMode { + NEAREST = 9728, + LINEAR = 9729, + NEAREST_MIPMAP_NEAREST = 9984, + LINEAR_MIPMAP_NEAREST = 9985, + NEAREST_MIPMAP_LINEAR = 9986, + LINEAR_MIPMAP_LINEAR = 9987 + }; + + enum WrapMode { + CLAMP_TO_EDGE = 33071, + MIRRORED_REPEAT = 33648, + REPEAT = 10497, + DEFAULT = REPEAT + }; + + int get_mag_filter() const { + return mag_filter; + } + + void set_mag_filter(const int filter_mode) { + mag_filter = (FilterMode)filter_mode; + } + + int get_min_filter() const { + return min_filter; + } + + void set_min_filter(const int filter_mode) { + min_filter = (FilterMode)filter_mode; + } + + int get_wrap_s() const { + return wrap_s; + } + + void set_wrap_s(const int wrap_mode) { + wrap_s = (WrapMode)wrap_mode; + } + + int get_wrap_t() const { + return wrap_t; + } + + void set_wrap_t(const int wrap_mode) { + wrap_s = (WrapMode)wrap_mode; + } + + StandardMaterial3D::TextureFilter get_filter_mode() const { + using TextureFilter = StandardMaterial3D::TextureFilter; + + switch (min_filter) { + case NEAREST: + return TextureFilter::TEXTURE_FILTER_NEAREST; + case LINEAR: + return TextureFilter::TEXTURE_FILTER_LINEAR; + case NEAREST_MIPMAP_NEAREST: + case NEAREST_MIPMAP_LINEAR: + return TextureFilter::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS; + case LINEAR_MIPMAP_NEAREST: + case LINEAR_MIPMAP_LINEAR: + default: + return TextureFilter::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; + } + } + + void set_filter_mode(StandardMaterial3D::TextureFilter mode) { + using TextureFilter = StandardMaterial3D::TextureFilter; + + switch (mode) { + case TextureFilter::TEXTURE_FILTER_NEAREST: + min_filter = FilterMode::NEAREST; + mag_filter = FilterMode::NEAREST; + break; + case TextureFilter::TEXTURE_FILTER_LINEAR: + min_filter = FilterMode::LINEAR; + mag_filter = FilterMode::LINEAR; + break; + case TextureFilter::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: + case TextureFilter::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: + min_filter = FilterMode::NEAREST_MIPMAP_LINEAR; + mag_filter = FilterMode::NEAREST; + break; + case TextureFilter::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: + case TextureFilter::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: + default: + min_filter = FilterMode::LINEAR_MIPMAP_LINEAR; + mag_filter = FilterMode::LINEAR; + break; + } + } + + bool get_wrap_mode() const { + // BaseMaterial3D presents wrapping as a boolean property. Either the texture is repeated + // in both dimensions, non-mirrored, or it isn't repeated at all. This will cause oddities + // when people import models having other wrapping mode combinations. + return (wrap_s == WrapMode::REPEAT) && (wrap_t == WrapMode::REPEAT); + } + + void set_wrap_mode(bool mat_repeats) { + if (mat_repeats) { + wrap_s = WrapMode::REPEAT; + wrap_t = WrapMode::REPEAT; + } else { + wrap_s = WrapMode::CLAMP_TO_EDGE; + wrap_t = WrapMode::CLAMP_TO_EDGE; + } + } + +protected: + static void _bind_methods(); + +private: + FilterMode mag_filter = FilterMode::LINEAR; + FilterMode min_filter = FilterMode::LINEAR_MIPMAP_LINEAR; + WrapMode wrap_s = WrapMode::REPEAT; + WrapMode wrap_t = WrapMode::REPEAT; +}; + +VARIANT_ENUM_CAST(GLTFTextureSampler::FilterMode); +VARIANT_ENUM_CAST(GLTFTextureSampler::WrapMode); + +#endif // GLTF_TEXTURE_SAMPLER_H |