From d36a34edb77e93d501fd18fb7a255cc14e246dab Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Wed, 10 Jan 2024 16:08:25 -0600 Subject: [PATCH] Misc changes to the GLTF module before audio PR --- modules/gltf/doc_classes/GLTFAccessor.xml | 5 ++++ modules/gltf/doc_classes/GLTFBufferView.xml | 18 ++++++++++++ .../doc_classes/GLTFDocumentExtension.xml | 4 +-- modules/gltf/doc_classes/GLTFState.xml | 8 ++++++ .../extensions/gltf_document_extension.cpp | 1 - modules/gltf/gltf_document.cpp | 20 ++++++++----- modules/gltf/gltf_state.cpp | 28 +++++++++++++++++++ modules/gltf/gltf_state.h | 1 + modules/gltf/register_types.cpp | 1 + modules/gltf/structures/gltf_buffer_view.cpp | 13 +++++++++ modules/gltf/structures/gltf_buffer_view.h | 3 +- 11 files changed, 91 insertions(+), 11 deletions(-) diff --git a/modules/gltf/doc_classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml index f678a11319ee..ba7323b7cde6 100644 --- a/modules/gltf/doc_classes/GLTFAccessor.xml +++ b/modules/gltf/doc_classes/GLTFAccessor.xml @@ -1,14 +1,19 @@ + Represents a GLTF accessor. + GLTFAccessor is a data structure representing GLTF a [code]accessor[/code] that would be found in the [code]"accessors"[/code] array. A buffer is a blob of binary data. A buffer view is a slice of a buffer. An accessor is a typed interpretation of the data in a buffer view. + Most custom data stored in GLTF does not need accessors, only buffer views (see [GLTFBufferView]). Accessors are for more advanced use cases such as interleaved mesh data encoded for the GPU. + https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md $DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html + The index of the buffer view this accessor is referencing. If [code]-1[/code], this accessor is not referencing any buffer view. diff --git a/modules/gltf/doc_classes/GLTFBufferView.xml b/modules/gltf/doc_classes/GLTFBufferView.xml index d0f76a9af31e..11d58bda7284 100644 --- a/modules/gltf/doc_classes/GLTFBufferView.xml +++ b/modules/gltf/doc_classes/GLTFBufferView.xml @@ -1,22 +1,40 @@ + Represents a GLTF buffer view. + GLTFBufferView is a data structure representing GLTF a [code]bufferView[/code] that would be found in the [code]"bufferViews"[/code] array. A buffer is a blob of binary data. A buffer view is a slice of a buffer that can be used to identify and extract data from the buffer. + Most custom uses of buffers only need to use the [member buffer], [member byte_length], and [member byte_offset]. The [member byte_stride] and [member indices] properties are for more advanced use cases such as interleaved mesh data encoded for the GPU. + https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md $DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html + + + + + + Loads the buffer view data from the buffer referenced by this buffer view in the given [GLTFState]. Interleaved data with a byte stride is not yet supported by this method. The data is returned as a [PackedByteArray]. + + + + The index of the buffer this buffer view is referencing. If [code]-1[/code], this buffer view is not referencing any buffer. + The length, in bytes, of this buffer view. If [code]0[/code], this buffer view is empty. + The offset, in bytes, from the start of the buffer to the start of this buffer view. + The stride, in bytes, between interleaved data. If [code]-1[/code], this buffer view is not interleaved. + True if the GLTFBufferView's OpenGL GPU buffer type is an [code]ELEMENT_ARRAY_BUFFER[/code] used for vertex indices (integer constant [code]34963[/code]). False if the buffer type is [code]ARRAY_BUFFER[/code] used for vertex attributes (integer constant [code]34962[/code]) or when any other value. See [url=https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md]Buffers, BufferViews, and Accessors[/url] for possible values. This property is set but never used, setting this property will do nothing. diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml index aaa55e772a18..0eabcb5022e8 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml @@ -30,7 +30,7 @@ Part of the export process. This method is run after [method _get_saveable_image_formats] and before [method _export_post]. If this [GLTFDocumentExtension] is used for exporting images, this runs after [method _serialize_texture_json]. - This method can be used to modify the final JSON of each node. + This method can be used to modify the final JSON of each node. Data should be primarily stored in [param gltf_node] prior to serializing the JSON, but the original Godot [param node] is also provided if available. The node may be null if not available, such as when exporting GLTF data not generated from a Godot scene. @@ -114,7 +114,7 @@ Part of the import process. This method is run after [method _parse_node_extensions] and before [method _generate_scene_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. + This method can be used to modify any of the data imported so far after parsing, before generating the nodes and then running the final per-node import step. diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index e2560417377f..100750f40005 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -20,6 +20,14 @@ 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. + + + + + + Appends the given byte array data to the buffers and creates a [GLTFBufferView] for it. The index of the destination [GLTFBufferView] is returned. If [param deduplication] is true, the buffers will first be searched for duplicate data, otherwise new bytes will always be appended. + + diff --git a/modules/gltf/extensions/gltf_document_extension.cpp b/modules/gltf/extensions/gltf_document_extension.cpp index 582bcf466b5c..9fdd6034a949 100644 --- a/modules/gltf/extensions/gltf_document_extension.cpp +++ b/modules/gltf/extensions/gltf_document_extension.cpp @@ -185,7 +185,6 @@ Error GLTFDocumentExtension::serialize_texture_json(Ref p_state, Dict Error GLTFDocumentExtension::export_node(Ref p_state, Ref 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); Error err = OK; GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err); return err; diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 8a60df85cf92..c840889f5e4a 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -405,6 +405,7 @@ static Vector _xform_to_array(const Transform3D p_transform) { Error GLTFDocument::_serialize_nodes(Ref p_state) { Array nodes; + const int scene_node_count = p_state->scene_nodes.size(); for (int i = 0; i < p_state->nodes.size(); i++) { Dictionary node; Ref gltf_node = p_state->nodes[i]; @@ -452,10 +453,13 @@ Error GLTFDocument::_serialize_nodes(Ref p_state) { node["children"] = children; } + Node *scene_node = nullptr; + if (i < scene_node_count) { + scene_node = p_state->scene_nodes[i]; + } for (Ref ext : document_extensions) { ERR_CONTINUE(ext.is_null()); - ERR_CONTINUE(!p_state->scene_nodes.find(i)); - Error err = ext->export_node(p_state, gltf_node, node, p_state->scene_nodes[i]); + Error err = ext->export_node(p_state, gltf_node, node, scene_node); ERR_CONTINUE(err != OK); } @@ -7471,11 +7475,13 @@ Node *GLTFDocument::generate_scene(Ref p_state, float p_bake_fps, boo ERR_CONTINUE(!E.value); for (Ref ext : document_extensions) { ERR_CONTINUE(ext.is_null()); - 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]; + Dictionary node_json; + if (p_state->json.has("nodes")) { + Array nodes = p_state->json["nodes"]; + if (0 <= E.key && E.key < nodes.size()) { + node_json = nodes[E.key]; + } + } Ref gltf_node = p_state->nodes[E.key]; err = ext->import_node(p_state, gltf_node, node_json, E.value); ERR_CONTINUE(err != OK); diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index 766fe4125785..0c47d5777c71 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -34,6 +34,8 @@ void GLTFState::_bind_methods() { ClassDB::bind_method(D_METHOD("add_used_extension", "extension_name", "required"), &GLTFState::add_used_extension); + ClassDB::bind_method(D_METHOD("append_data_to_buffers", "data", "deduplication"), &GLTFState::append_data_to_buffers); + 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); @@ -399,3 +401,29 @@ Variant GLTFState::get_additional_data(const StringName &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; } + +GLTFBufferViewIndex GLTFState::append_data_to_buffers(const Vector &p_data, const bool p_deduplication = false) { + if (p_deduplication) { + for (int i = 0; i < buffer_views.size(); i++) { + Ref buffer_view = buffer_views[i]; + Vector buffer_view_data = buffer_view->load_buffer_view_data(this); + if (buffer_view_data == p_data) { + return i; + } + } + } + // Append the given data to a buffer and create a buffer view for it. + if (unlikely(buffers.is_empty())) { + buffers.push_back(Vector()); + } + Vector &destination_buffer = buffers.write[0]; + Ref buffer_view; + buffer_view.instantiate(); + buffer_view->set_buffer(0); + buffer_view->set_byte_offset(destination_buffer.size()); + buffer_view->set_byte_length(p_data.size()); + destination_buffer.append_array(p_data); + const int new_index = buffer_views.size(); + buffer_views.push_back(buffer_view); + return new_index; +} diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index 1ed8ce36290d..3edf9a722fc8 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -105,6 +105,7 @@ class GLTFState : public Resource { public: void add_used_extension(const String &p_extension, bool p_required = false); + GLTFBufferViewIndex append_data_to_buffers(const Vector &p_data, const bool p_deduplication); enum GLTFHandleBinary { HANDLE_BINARY_DISCARD_TEXTURES = 0, diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index 0bf02cf89079..94c9d66f78e1 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -118,6 +118,7 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(GLTFTexture); GDREGISTER_CLASS(GLTFTextureSampler); // Register GLTFDocumentExtension classes with GLTFDocument. + // Ensure physics is first in this list so that physics nodes are created before other nodes. GLTF_REGISTER_DOCUMENT_EXTENSION(GLTFDocumentExtensionPhysics); GLTF_REGISTER_DOCUMENT_EXTENSION(GLTFDocumentExtensionTextureKTX); GLTF_REGISTER_DOCUMENT_EXTENSION(GLTFDocumentExtensionTextureWebP); diff --git a/modules/gltf/structures/gltf_buffer_view.cpp b/modules/gltf/structures/gltf_buffer_view.cpp index 7678f23f5704..d40ed69915a7 100644 --- a/modules/gltf/structures/gltf_buffer_view.cpp +++ b/modules/gltf/structures/gltf_buffer_view.cpp @@ -30,7 +30,11 @@ #include "gltf_buffer_view.h" +#include "../gltf_state.h" + void GLTFBufferView::_bind_methods() { + ClassDB::bind_method(D_METHOD("load_buffer_view_data", "state"), &GLTFBufferView::load_buffer_view_data); + ClassDB::bind_method(D_METHOD("get_buffer"), &GLTFBufferView::get_buffer); ClassDB::bind_method(D_METHOD("set_buffer", "buffer"), &GLTFBufferView::set_buffer); ClassDB::bind_method(D_METHOD("get_byte_offset"), &GLTFBufferView::get_byte_offset); @@ -88,3 +92,12 @@ bool GLTFBufferView::get_indices() { void GLTFBufferView::set_indices(bool p_indices) { indices = p_indices; } + +Vector GLTFBufferView::load_buffer_view_data(const Ref p_state) const { + ERR_FAIL_COND_V_MSG(byte_stride > 0, Vector(), "Buffer views with byte stride are not yet supported by this method."); + const TypedArray> &buffers = p_state->get_buffers(); + ERR_FAIL_INDEX_V(buffer, buffers.size(), Vector()); + const PackedByteArray &buffer_data = buffers[buffer]; + const int64_t byte_end = byte_offset + byte_length; + return buffer_data.slice(byte_offset, byte_end); +} diff --git a/modules/gltf/structures/gltf_buffer_view.h b/modules/gltf/structures/gltf_buffer_view.h index 6d138dbf11ad..e4b716813010 100644 --- a/modules/gltf/structures/gltf_buffer_view.h +++ b/modules/gltf/structures/gltf_buffer_view.h @@ -64,7 +64,8 @@ class GLTFBufferView : public Resource { bool get_indices(); void set_indices(bool p_indices); - // matrices need to be transformed to this + + Vector load_buffer_view_data(const Ref p_state) const; }; #endif // GLTF_BUFFER_VIEW_H