Merge pull request #87063 from aaronfranke/gltf-misc-before-audio

Misc changes to the GLTF module before audio PR
This commit is contained in:
Rémi Verschelde 2024-01-15 13:27:50 +01:00
commit fb45210e2c
No known key found for this signature in database
GPG key ID: C3336907360768E1
11 changed files with 91 additions and 11 deletions

View file

@ -1,14 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFAccessor" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Represents a GLTF accessor.
</brief_description>
<description>
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.
</description>
<tutorials>
<link title="Buffers, BufferViews, and Accessors in Khronos glTF specification">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md</link>
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
</tutorials>
<members>
<member name="buffer_view" type="int" setter="set_buffer_view" getter="get_buffer_view" default="-1">
The index of the buffer view this accessor is referencing. If [code]-1[/code], this accessor is not referencing any buffer view.
</member>
<member name="byte_offset" type="int" setter="set_byte_offset" getter="get_byte_offset" default="0">
</member>

View file

@ -1,22 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFBufferView" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Represents a GLTF buffer view.
</brief_description>
<description>
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.
</description>
<tutorials>
<link title="Buffers, BufferViews, and Accessors in Khronos glTF specification">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md</link>
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
</tutorials>
<methods>
<method name="load_buffer_view_data" qualifiers="const">
<return type="PackedByteArray" />
<param index="0" name="state" type="GLTFState" />
<description>
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].
</description>
</method>
</methods>
<members>
<member name="buffer" type="int" setter="set_buffer" getter="get_buffer" default="-1">
The index of the buffer this buffer view is referencing. If [code]-1[/code], this buffer view is not referencing any buffer.
</member>
<member name="byte_length" type="int" setter="set_byte_length" getter="get_byte_length" default="0">
The length, in bytes, of this buffer view. If [code]0[/code], this buffer view is empty.
</member>
<member name="byte_offset" type="int" setter="set_byte_offset" getter="get_byte_offset" default="0">
The offset, in bytes, from the start of the buffer to the start of this buffer view.
</member>
<member name="byte_stride" type="int" setter="set_byte_stride" getter="get_byte_stride" default="-1">
The stride, in bytes, between interleaved data. If [code]-1[/code], this buffer view is not interleaved.
</member>
<member name="indices" type="bool" setter="set_indices" getter="get_indices" default="false">
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.
</member>
</members>
</class>

View file

@ -30,7 +30,7 @@
<param index="3" name="node" type="Node" />
<description>
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.
</description>
</method>
<method name="_export_post" qualifiers="virtual">
@ -114,7 +114,7 @@
<param index="0" name="state" type="GLTFState" />
<description>
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.
</description>
</method>
<method name="_import_preflight" qualifiers="virtual">

View file

@ -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.
</description>
</method>
<method name="append_data_to_buffers">
<return type="int" />
<param index="0" name="data" type="PackedByteArray" />
<param index="1" name="deduplication" type="bool" />
<description>
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.
</description>
</method>
<method name="get_accessors">
<return type="GLTFAccessor[]" />
<description>

View file

@ -185,7 +185,6 @@ Error GLTFDocumentExtension::serialize_texture_json(Ref<GLTFState> p_state, Dict
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);
Error err = OK;
GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err);
return err;

View file

@ -405,6 +405,7 @@ static Vector<real_t> _xform_to_array(const Transform3D p_transform) {
Error GLTFDocument::_serialize_nodes(Ref<GLTFState> 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<GLTFNode> gltf_node = p_state->nodes[i];
@ -452,10 +453,13 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> p_state) {
node["children"] = children;
}
Node *scene_node = nullptr;
if (i < scene_node_count) {
scene_node = p_state->scene_nodes[i];
}
for (Ref<GLTFDocumentExtension> 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<GLTFState> p_state, float p_bake_fps, boo
ERR_CONTINUE(!E.value);
for (Ref<GLTFDocumentExtension> 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<GLTFNode> gltf_node = p_state->nodes[E.key];
err = ext->import_node(p_state, gltf_node, node_json, E.value);
ERR_CONTINUE(err != OK);

View file

@ -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<uint8_t> &p_data, const bool p_deduplication = false) {
if (p_deduplication) {
for (int i = 0; i < buffer_views.size(); i++) {
Ref<GLTFBufferView> buffer_view = buffer_views[i];
Vector<uint8_t> 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<uint8_t>());
}
Vector<uint8_t> &destination_buffer = buffers.write[0];
Ref<GLTFBufferView> 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;
}

View file

@ -105,6 +105,7 @@ protected:
public:
void add_used_extension(const String &p_extension, bool p_required = false);
GLTFBufferViewIndex append_data_to_buffers(const Vector<uint8_t> &p_data, const bool p_deduplication);
enum GLTFHandleBinary {
HANDLE_BINARY_DISCARD_TEXTURES = 0,

View file

@ -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);

View file

@ -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<uint8_t> GLTFBufferView::load_buffer_view_data(const Ref<GLTFState> p_state) const {
ERR_FAIL_COND_V_MSG(byte_stride > 0, Vector<uint8_t>(), "Buffer views with byte stride are not yet supported by this method.");
const TypedArray<Vector<uint8_t>> &buffers = p_state->get_buffers();
ERR_FAIL_INDEX_V(buffer, buffers.size(), Vector<uint8_t>());
const PackedByteArray &buffer_data = buffers[buffer];
const int64_t byte_end = byte_offset + byte_length;
return buffer_data.slice(byte_offset, byte_end);
}

View file

@ -64,7 +64,8 @@ public:
bool get_indices();
void set_indices(bool p_indices);
// matrices need to be transformed to this
Vector<uint8_t> load_buffer_view_data(const Ref<GLTFState> p_state) const;
};
#endif // GLTF_BUFFER_VIEW_H