diff --git a/modules/gltf/doc_classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml index b0d4cc5d70..3e869e65d0 100644 --- a/modules/gltf/doc_classes/GLTFAccessor.xml +++ b/modules/gltf/doc_classes/GLTFAccessor.xml @@ -11,6 +11,21 @@ https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md $DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html + + + + + + Creates a new GLTFAccessor instance by parsing the given [Dictionary]. + + + + + + Serializes this GLTFAccessor instance into a [Dictionary]. + + + The glTF accessor type, as an enum. diff --git a/modules/gltf/doc_classes/GLTFBufferView.xml b/modules/gltf/doc_classes/GLTFBufferView.xml index 9c2ee3197f..d488b5bcfb 100644 --- a/modules/gltf/doc_classes/GLTFBufferView.xml +++ b/modules/gltf/doc_classes/GLTFBufferView.xml @@ -12,6 +12,13 @@ $DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html + + + + + Creates a new GLTFBufferView instance by parsing the given [Dictionary]. + + @@ -19,6 +26,12 @@ 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]. + + + + Serializes this GLTFBufferView instance into a [Dictionary]. + + diff --git a/modules/gltf/gltf_defines.h b/modules/gltf/gltf_defines.h index dda7249193..8d37e6bd69 100644 --- a/modules/gltf/gltf_defines.h +++ b/modules/gltf/gltf_defines.h @@ -33,7 +33,7 @@ // This file should only be included by other headers. // GLTF classes. -struct GLTFAccessor; +class GLTFAccessor; class GLTFAnimation; class GLTFBufferView; class GLTFCamera; diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 7ea1fec119..12a6f56cb2 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -848,30 +848,8 @@ Error GLTFDocument::_parse_buffers(Ref p_state, const String &p_base_ Error GLTFDocument::_encode_buffer_views(Ref p_state) { Array buffers; for (GLTFBufferViewIndex i = 0; i < p_state->buffer_views.size(); i++) { - Dictionary d; - - Ref buffer_view = p_state->buffer_views[i]; - - d["buffer"] = buffer_view->buffer; - d["byteLength"] = buffer_view->byte_length; - - if (buffer_view->byte_offset > 0) { - d["byteOffset"] = buffer_view->byte_offset; - } - - if (buffer_view->byte_stride != -1) { - d["byteStride"] = buffer_view->byte_stride; - } - - if (buffer_view->indices) { - d["target"] = GLTFDocument::ELEMENT_ARRAY_BUFFER; - } else if (buffer_view->vertex_attributes) { - d["target"] = GLTFDocument::ARRAY_BUFFER; - } - - ERR_FAIL_COND_V(!d.has("buffer"), ERR_INVALID_DATA); - ERR_FAIL_COND_V(!d.has("byteLength"), ERR_INVALID_DATA); - buffers.push_back(d); + const Ref buffer_view = p_state->buffer_views[i]; + buffers.push_back(buffer_view->to_dictionary()); } print_verbose("glTF: Total buffer views: " + itos(p_state->buffer_views.size())); if (!buffers.size()) { @@ -887,33 +865,11 @@ Error GLTFDocument::_parse_buffer_views(Ref p_state) { } const Array &buffers = p_state->json["bufferViews"]; for (GLTFBufferViewIndex i = 0; i < buffers.size(); i++) { - const Dictionary &d = buffers[i]; - - Ref buffer_view; - buffer_view.instantiate(); - - ERR_FAIL_COND_V(!d.has("buffer"), ERR_PARSE_ERROR); - buffer_view->buffer = d["buffer"]; - ERR_FAIL_COND_V(!d.has("byteLength"), ERR_PARSE_ERROR); - buffer_view->byte_length = d["byteLength"]; - - if (d.has("byteOffset")) { - buffer_view->byte_offset = d["byteOffset"]; - } - - if (d.has("byteStride")) { - buffer_view->byte_stride = d["byteStride"]; - if (buffer_view->byte_stride < 4 || buffer_view->byte_stride > 252 || buffer_view->byte_stride % 4 != 0) { - ERR_PRINT("glTF import: Invalid byte stride " + itos(buffer_view->byte_stride) + " for buffer view at index " + itos(i) + " while importing file '" + p_state->filename + "'. If defined, byte stride must be a multiple of 4 and between 4 and 252."); - } - } - - if (d.has("target")) { - const int target = d["target"]; - buffer_view->indices = target == GLTFDocument::ELEMENT_ARRAY_BUFFER; - buffer_view->vertex_attributes = target == GLTFDocument::ARRAY_BUFFER; - } - + const Dictionary &dict = buffers[i]; + // Both "buffer" and "byteLength" are required by the spec. + ERR_FAIL_COND_V(!dict.has("buffer"), ERR_PARSE_ERROR); + ERR_FAIL_COND_V(!dict.has("byteLength"), ERR_PARSE_ERROR); + Ref buffer_view = GLTFBufferView::from_dictionary(dict); p_state->buffer_views.push_back(buffer_view); } @@ -925,49 +881,8 @@ Error GLTFDocument::_parse_buffer_views(Ref p_state) { Error GLTFDocument::_encode_accessors(Ref p_state) { Array accessors; for (GLTFAccessorIndex i = 0; i < p_state->accessors.size(); i++) { - Dictionary d; - - Ref accessor = p_state->accessors[i]; - d["componentType"] = accessor->component_type; - d["count"] = accessor->count; - d["type"] = _get_accessor_type_name(accessor->accessor_type); - d["normalized"] = accessor->normalized; - d["max"] = accessor->max; - d["min"] = accessor->min; - if (accessor->buffer_view != -1) { - // bufferView may be omitted to zero-initialize the buffer. When this happens, byteOffset MUST also be omitted. - if (accessor->byte_offset > 0) { - d["byteOffset"] = accessor->byte_offset; - } - d["bufferView"] = accessor->buffer_view; - } - - if (accessor->sparse_count > 0) { - Dictionary s; - s["count"] = accessor->sparse_count; - - Dictionary si; - si["bufferView"] = accessor->sparse_indices_buffer_view; - si["componentType"] = accessor->sparse_indices_component_type; - if (accessor->sparse_indices_byte_offset > 0) { - si["byteOffset"] = accessor->sparse_indices_byte_offset; - } - ERR_FAIL_COND_V(!si.has("bufferView") || !si.has("componentType"), ERR_PARSE_ERROR); - s["indices"] = si; - - Dictionary sv; - sv["bufferView"] = accessor->sparse_values_buffer_view; - if (accessor->sparse_values_byte_offset > 0) { - sv["byteOffset"] = accessor->sparse_values_byte_offset; - } - ERR_FAIL_COND_V(!sv.has("bufferView"), ERR_PARSE_ERROR); - s["values"] = sv; - - ERR_FAIL_COND_V(!s.has("count") || !s.has("indices") || !s.has("values"), ERR_PARSE_ERROR); - d["sparse"] = s; - } - - accessors.push_back(d); + const Ref accessor = p_state->accessors[i]; + accessors.push_back(accessor->to_dictionary()); } if (!accessors.size()) { @@ -1040,68 +955,12 @@ Error GLTFDocument::_parse_accessors(Ref p_state) { } const Array &accessors = p_state->json["accessors"]; for (GLTFAccessorIndex i = 0; i < accessors.size(); i++) { - const Dictionary &d = accessors[i]; - - Ref accessor; - accessor.instantiate(); - - ERR_FAIL_COND_V(!d.has("componentType"), ERR_PARSE_ERROR); - accessor->component_type = (GLTFAccessor::GLTFComponentType)(int32_t)d["componentType"]; - ERR_FAIL_COND_V(!d.has("count"), ERR_PARSE_ERROR); - accessor->count = d["count"]; - if (accessor->count <= 0) { - ERR_PRINT("glTF import: Invalid accessor count " + itos(accessor->count) + " for accessor at index " + itos(i) + " while importing file '" + p_state->filename + "'. Accessor count must be greater than 0."); - } - ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); - accessor->accessor_type = _get_accessor_type_from_str(d["type"]); - - if (d.has("bufferView")) { - accessor->buffer_view = d["bufferView"]; //optional because it may be sparse... - } - - if (d.has("byteOffset")) { - accessor->byte_offset = d["byteOffset"]; - } - - if (d.has("normalized")) { - accessor->normalized = d["normalized"]; - } - - if (d.has("max")) { - accessor->max = d["max"]; - } - - if (d.has("min")) { - accessor->min = d["min"]; - } - - if (d.has("sparse")) { - const Dictionary &s = d["sparse"]; - - ERR_FAIL_COND_V(!s.has("count"), ERR_PARSE_ERROR); - accessor->sparse_count = s["count"]; - ERR_FAIL_COND_V(!s.has("indices"), ERR_PARSE_ERROR); - const Dictionary &si = s["indices"]; - - ERR_FAIL_COND_V(!si.has("bufferView"), ERR_PARSE_ERROR); - accessor->sparse_indices_buffer_view = si["bufferView"]; - ERR_FAIL_COND_V(!si.has("componentType"), ERR_PARSE_ERROR); - accessor->sparse_indices_component_type = (GLTFAccessor::GLTFComponentType)(int32_t)si["componentType"]; - - if (si.has("byteOffset")) { - accessor->sparse_indices_byte_offset = si["byteOffset"]; - } - - ERR_FAIL_COND_V(!s.has("values"), ERR_PARSE_ERROR); - const Dictionary &sv = s["values"]; - - ERR_FAIL_COND_V(!sv.has("bufferView"), ERR_PARSE_ERROR); - accessor->sparse_values_buffer_view = sv["bufferView"]; - if (sv.has("byteOffset")) { - accessor->sparse_values_byte_offset = sv["byteOffset"]; - } - } - + const Dictionary &dict = accessors[i]; + // All of these fields are required by the spec. + ERR_FAIL_COND_V(!dict.has("componentType"), ERR_PARSE_ERROR); + ERR_FAIL_COND_V(!dict.has("count"), ERR_PARSE_ERROR); + ERR_FAIL_COND_V(!dict.has("type"), ERR_PARSE_ERROR); + Ref accessor = GLTFAccessor::from_dictionary(dict); p_state->accessors.push_back(accessor); } diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index ecababcf42..80d5a7f0b6 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -47,10 +47,6 @@ class GLTFDocument : public Resource { public: const int32_t JOINT_GROUP_SIZE = 4; - enum { - ARRAY_BUFFER = 34962, - ELEMENT_ARRAY_BUFFER = 34963, - }; enum { TEXTURE_TYPE_GENERIC = 0, TEXTURE_TYPE_NORMAL = 1, diff --git a/modules/gltf/structures/gltf_accessor.cpp b/modules/gltf/structures/gltf_accessor.cpp index 414e649bd6..a508cea12e 100644 --- a/modules/gltf/structures/gltf_accessor.cpp +++ b/modules/gltf/structures/gltf_accessor.cpp @@ -31,6 +31,8 @@ #include "gltf_accessor.h" #include "gltf_accessor.compat.inc" +#include "../gltf_state.h" + void GLTFAccessor::_bind_methods() { BIND_ENUM_CONSTANT(TYPE_SCALAR); BIND_ENUM_CONSTANT(TYPE_VEC2); @@ -53,6 +55,9 @@ void GLTFAccessor::_bind_methods() { BIND_ENUM_CONSTANT(COMPONENT_TYPE_SIGNED_LONG); BIND_ENUM_CONSTANT(COMPONENT_TYPE_UNSIGNED_LONG); + ClassDB::bind_static_method("GLTFAccessor", D_METHOD("from_dictionary", "dictionary"), &GLTFAccessor::from_dictionary); + ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFAccessor::to_dictionary); + ClassDB::bind_method(D_METHOD("get_buffer_view"), &GLTFAccessor::get_buffer_view); ClassDB::bind_method(D_METHOD("set_buffer_view", "buffer_view"), &GLTFAccessor::set_buffer_view); ClassDB::bind_method(D_METHOD("get_byte_offset"), &GLTFAccessor::get_byte_offset); @@ -101,6 +106,8 @@ void GLTFAccessor::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "sparse_values_byte_offset"), "set_sparse_values_byte_offset", "get_sparse_values_byte_offset"); // int } +// Property getters and setters. + GLTFBufferViewIndex GLTFAccessor::get_buffer_view() const { return buffer_view; } @@ -220,3 +227,146 @@ int64_t GLTFAccessor::get_sparse_values_byte_offset() const { void GLTFAccessor::set_sparse_values_byte_offset(int64_t p_sparse_values_byte_offset) { sparse_values_byte_offset = p_sparse_values_byte_offset; } + +// Trivial helper functions. + +GLTFAccessor::GLTFAccessorType GLTFAccessor::_get_accessor_type_from_str(const String &p_string) { + if (p_string == "SCALAR") { + return GLTFAccessor::TYPE_SCALAR; + } + if (p_string == "VEC2") { + return GLTFAccessor::TYPE_VEC2; + } + if (p_string == "VEC3") { + return GLTFAccessor::TYPE_VEC3; + } + if (p_string == "VEC4") { + return GLTFAccessor::TYPE_VEC4; + } + if (p_string == "MAT2") { + return GLTFAccessor::TYPE_MAT2; + } + if (p_string == "MAT3") { + return GLTFAccessor::TYPE_MAT3; + } + if (p_string == "MAT4") { + return GLTFAccessor::TYPE_MAT4; + } + ERR_FAIL_V(GLTFAccessor::TYPE_SCALAR); +} + +String GLTFAccessor::_get_accessor_type_name() const { + switch (accessor_type) { + case GLTFAccessor::TYPE_SCALAR: + return "SCALAR"; + case GLTFAccessor::TYPE_VEC2: + return "VEC2"; + case GLTFAccessor::TYPE_VEC3: + return "VEC3"; + case GLTFAccessor::TYPE_VEC4: + return "VEC4"; + case GLTFAccessor::TYPE_MAT2: + return "MAT2"; + case GLTFAccessor::TYPE_MAT3: + return "MAT3"; + case GLTFAccessor::TYPE_MAT4: + return "MAT4"; + default: + break; + } + ERR_FAIL_V("SCALAR"); +} + +// Dictionary conversion. + +Ref GLTFAccessor::from_dictionary(const Dictionary &p_dict) { + // See https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/schema/accessor.schema.json + Ref accessor; + accessor.instantiate(); + if (p_dict.has("bufferView")) { + // bufferView is optional. If not present, the accessor is considered to be zero-initialized. + accessor->buffer_view = p_dict["bufferView"]; + } + if (p_dict.has("byteOffset")) { + accessor->byte_offset = p_dict["byteOffset"]; + } + if (p_dict.has("componentType")) { + accessor->component_type = (GLTFAccessor::GLTFComponentType)(int32_t)p_dict["componentType"]; + } + if (p_dict.has("count")) { + accessor->count = p_dict["count"]; + } + if (accessor->count <= 0) { + ERR_PRINT("glTF import: Invalid accessor count " + itos(accessor->count) + " for accessor. Accessor count must be greater than 0."); + } + if (p_dict.has("max")) { + accessor->max = p_dict["max"]; + } + if (p_dict.has("min")) { + accessor->min = p_dict["min"]; + } + if (p_dict.has("normalized")) { + accessor->normalized = p_dict["normalized"]; + } + if (p_dict.has("sparse")) { + // See https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/schema/accessor.sparse.schema.json + const Dictionary &sparse_dict = p_dict["sparse"]; + ERR_FAIL_COND_V(!sparse_dict.has("count"), accessor); + accessor->sparse_count = sparse_dict["count"]; + ERR_FAIL_COND_V(!sparse_dict.has("indices"), accessor); + const Dictionary &sparse_indices_dict = sparse_dict["indices"]; + ERR_FAIL_COND_V(!sparse_indices_dict.has("bufferView"), accessor); + accessor->sparse_indices_buffer_view = sparse_indices_dict["bufferView"]; + ERR_FAIL_COND_V(!sparse_indices_dict.has("componentType"), accessor); + accessor->sparse_indices_component_type = (GLTFAccessor::GLTFComponentType)(int32_t)sparse_indices_dict["componentType"]; + if (sparse_indices_dict.has("byteOffset")) { + accessor->sparse_indices_byte_offset = sparse_indices_dict["byteOffset"]; + } + ERR_FAIL_COND_V(!sparse_dict.has("values"), accessor); + const Dictionary &sparse_values_dict = sparse_dict["values"]; + ERR_FAIL_COND_V(!sparse_values_dict.has("bufferView"), accessor); + accessor->sparse_values_buffer_view = sparse_values_dict["bufferView"]; + if (sparse_values_dict.has("byteOffset")) { + accessor->sparse_values_byte_offset = sparse_values_dict["byteOffset"]; + } + } + accessor->accessor_type = _get_accessor_type_from_str(p_dict["type"]); + return accessor; +} + +Dictionary GLTFAccessor::to_dictionary() const { + Dictionary dict; + if (buffer_view != -1) { + // bufferView may be omitted to zero-initialize the buffer. When this happens, byteOffset MUST also be omitted. + if (byte_offset > 0) { + dict["byteOffset"] = byte_offset; + } + dict["bufferView"] = buffer_view; + } + dict["componentType"] = component_type; + dict["count"] = count; + dict["max"] = max; + dict["min"] = min; + dict["normalized"] = normalized; + dict["type"] = _get_accessor_type_name(); + + if (sparse_count > 0) { + Dictionary sparse_indices_dict; + sparse_indices_dict["bufferView"] = sparse_indices_buffer_view; + sparse_indices_dict["componentType"] = sparse_indices_component_type; + if (sparse_indices_byte_offset > 0) { + sparse_indices_dict["byteOffset"] = sparse_indices_byte_offset; + } + Dictionary sparse_values_dict; + sparse_values_dict["bufferView"] = sparse_values_buffer_view; + if (sparse_values_byte_offset > 0) { + sparse_values_dict["byteOffset"] = sparse_values_byte_offset; + } + Dictionary sparse_dict; + sparse_dict["count"] = sparse_count; + sparse_dict["indices"] = sparse_indices_dict; + sparse_dict["values"] = sparse_values_dict; + dict["sparse"] = sparse_dict; + } + return dict; +} diff --git a/modules/gltf/structures/gltf_accessor.h b/modules/gltf/structures/gltf_accessor.h index a5ff894fb2..2eb2aa3eba 100644 --- a/modules/gltf/structures/gltf_accessor.h +++ b/modules/gltf/structures/gltf_accessor.h @@ -32,9 +32,9 @@ #include "../gltf_defines.h" -#include "core/io/resource.h" +#include "gltf_buffer_view.h" -struct GLTFAccessor : public Resource { +class GLTFAccessor : public Resource { GDCLASS(GLTFAccessor, Resource); friend class GLTFDocument; @@ -80,6 +80,10 @@ private: GLTFBufferViewIndex sparse_values_buffer_view = 0; int64_t sparse_values_byte_offset = 0; + // Trivial helper functions. + static GLTFAccessor::GLTFAccessorType _get_accessor_type_from_str(const String &p_string); + String _get_accessor_type_name() const; + protected: static void _bind_methods(); @@ -106,6 +110,7 @@ protected: #endif // DISABLE_DEPRECATED public: + // Property getters and setters. GLTFBufferViewIndex get_buffer_view() const; void set_buffer_view(GLTFBufferViewIndex p_buffer_view); @@ -150,6 +155,10 @@ public: int64_t get_sparse_values_byte_offset() const; void set_sparse_values_byte_offset(int64_t p_sparse_values_byte_offset); + + // Dictionary conversion. + static Ref from_dictionary(const Dictionary &p_dict); + Dictionary to_dictionary() const; }; VARIANT_ENUM_CAST(GLTFAccessor::GLTFAccessorType); diff --git a/modules/gltf/structures/gltf_buffer_view.cpp b/modules/gltf/structures/gltf_buffer_view.cpp index 2b0ff7999c..782f77ac66 100644 --- a/modules/gltf/structures/gltf_buffer_view.cpp +++ b/modules/gltf/structures/gltf_buffer_view.cpp @@ -36,6 +36,9 @@ void GLTFBufferView::_bind_methods() { ClassDB::bind_method(D_METHOD("load_buffer_view_data", "state"), &GLTFBufferView::load_buffer_view_data); + ClassDB::bind_static_method("GLTFBufferView", D_METHOD("from_dictionary", "dictionary"), &GLTFBufferView::from_dictionary); + ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFBufferView::to_dictionary); + 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); @@ -105,12 +108,58 @@ void GLTFBufferView::set_vertex_attributes(bool p_attributes) { vertex_attributes = p_attributes; } -Vector GLTFBufferView::load_buffer_view_data(const Ref p_state) const { - ERR_FAIL_COND_V(p_state.is_null(), Vector()); +Vector GLTFBufferView::load_buffer_view_data(const Ref p_gltf_state) const { + ERR_FAIL_COND_V(p_gltf_state.is_null(), Vector()); 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(); + const TypedArray> &buffers = p_gltf_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); } + +Ref GLTFBufferView::from_dictionary(const Dictionary &p_dict) { + // See https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/schema/bufferView.schema.json + Ref buffer_view; + buffer_view.instantiate(); + if (p_dict.has("buffer")) { + buffer_view->set_buffer(p_dict["buffer"]); + } + if (p_dict.has("byteLength")) { + buffer_view->set_byte_length(p_dict["byteLength"]); + } + if (p_dict.has("byteOffset")) { + buffer_view->set_byte_offset(p_dict["byteOffset"]); + } + if (p_dict.has("byteStride")) { + buffer_view->byte_stride = p_dict["byteStride"]; + if (buffer_view->byte_stride < 4 || buffer_view->byte_stride > 252 || buffer_view->byte_stride % 4 != 0) { + ERR_PRINT("glTF import: Invalid byte stride " + itos(buffer_view->byte_stride) + " for buffer view. If defined, byte stride must be a multiple of 4 and between 4 and 252."); + } + } + if (p_dict.has("target")) { + const int target = p_dict["target"]; + buffer_view->indices = target == ArrayBufferTarget::TARGET_ELEMENT_ARRAY_BUFFER; + buffer_view->vertex_attributes = target == ArrayBufferTarget::TARGET_ARRAY_BUFFER; + } + return buffer_view; +} + +Dictionary GLTFBufferView::to_dictionary() const { + Dictionary dict; + ERR_FAIL_COND_V_MSG(buffer == -1, dict, "Buffer index must be set to a valid buffer before converting to Dictionary."); + dict["buffer"] = buffer; + dict["byteLength"] = byte_length; + if (byte_offset != 0) { + dict["byteOffset"] = byte_offset; + } + if (byte_stride != -1) { + dict["byteStride"] = byte_stride; + } + if (indices) { + dict["target"] = ArrayBufferTarget::TARGET_ELEMENT_ARRAY_BUFFER; + } else if (vertex_attributes) { + dict["target"] = ArrayBufferTarget::TARGET_ARRAY_BUFFER; + } + return dict; +} diff --git a/modules/gltf/structures/gltf_buffer_view.h b/modules/gltf/structures/gltf_buffer_view.h index dda2e57ff6..3d0c1b7eed 100644 --- a/modules/gltf/structures/gltf_buffer_view.h +++ b/modules/gltf/structures/gltf_buffer_view.h @@ -38,13 +38,24 @@ class GLTFBufferView : public Resource { GDCLASS(GLTFBufferView, Resource); friend class GLTFDocument; +public: + // When a buffer view is used by vertex indices or attribute accessors it SHOULD specify + // "target" with a value of ELEMENT_ARRAY_BUFFER (34963) or ARRAY_BUFFER (34962) respectively. + // This is only used for mesh data. For non-mesh buffer views, the target should be left blank. + // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#buffers-and-buffer-views-overview + enum ArrayBufferTarget { + TARGET_NONE = 0, + TARGET_ARRAY_BUFFER = 34962, + TARGET_ELEMENT_ARRAY_BUFFER = 34963, + }; + private: GLTFBufferIndex buffer = -1; int64_t byte_offset = 0; int64_t byte_length = 0; int64_t byte_stride = -1; - bool indices = false; - bool vertex_attributes = false; + bool indices = false; // True for TARGET_ELEMENT_ARRAY_BUFFER. + bool vertex_attributes = false; // True for TARGET_ARRAY_BUFFER. protected: static void _bind_methods(); @@ -78,5 +89,8 @@ public: bool get_vertex_attributes() const; void set_vertex_attributes(bool p_attributes); - Vector load_buffer_view_data(const Ref p_state) const; + Vector load_buffer_view_data(const Ref p_gltf_state) const; + + static Ref from_dictionary(const Dictionary &p_dict); + Dictionary to_dictionary() const; };