mirror of
https://github.com/godotengine/godot.git
synced 2025-12-08 06:09:55 +00:00
GLTF: Move accessor and buffer view Dictionary conversion into classes
This commit is contained in:
parent
fc7065d2b4
commit
02182b1087
9 changed files with 274 additions and 169 deletions
|
|
@ -11,6 +11,21 @@
|
||||||
<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="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>
|
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
|
<methods>
|
||||||
|
<method name="from_dictionary" qualifiers="static">
|
||||||
|
<return type="GLTFAccessor" />
|
||||||
|
<param index="0" name="dictionary" type="Dictionary" />
|
||||||
|
<description>
|
||||||
|
Creates a new GLTFAccessor instance by parsing the given [Dictionary].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="to_dictionary" qualifiers="const">
|
||||||
|
<return type="Dictionary" />
|
||||||
|
<description>
|
||||||
|
Serializes this GLTFAccessor instance into a [Dictionary].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
<member name="accessor_type" type="int" setter="set_accessor_type" getter="get_accessor_type" enum="GLTFAccessor.GLTFAccessorType" default="0">
|
<member name="accessor_type" type="int" setter="set_accessor_type" getter="get_accessor_type" enum="GLTFAccessor.GLTFAccessorType" default="0">
|
||||||
The glTF accessor type, as an enum.
|
The glTF accessor type, as an enum.
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,13 @@
|
||||||
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
<link title="Runtime file loading and saving">$DOCS_URL/tutorials/io/runtime_file_loading_and_saving.html</link>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
<methods>
|
<methods>
|
||||||
|
<method name="from_dictionary" qualifiers="static">
|
||||||
|
<return type="GLTFBufferView" />
|
||||||
|
<param index="0" name="dictionary" type="Dictionary" />
|
||||||
|
<description>
|
||||||
|
Creates a new GLTFBufferView instance by parsing the given [Dictionary].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="load_buffer_view_data" qualifiers="const">
|
<method name="load_buffer_view_data" qualifiers="const">
|
||||||
<return type="PackedByteArray" />
|
<return type="PackedByteArray" />
|
||||||
<param index="0" name="state" type="GLTFState" />
|
<param index="0" name="state" type="GLTFState" />
|
||||||
|
|
@ -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].
|
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>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="to_dictionary" qualifiers="const">
|
||||||
|
<return type="Dictionary" />
|
||||||
|
<description>
|
||||||
|
Serializes this GLTFBufferView instance into a [Dictionary].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
<member name="buffer" type="int" setter="set_buffer" getter="get_buffer" default="-1">
|
<member name="buffer" type="int" setter="set_buffer" getter="get_buffer" default="-1">
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
// This file should only be included by other headers.
|
// This file should only be included by other headers.
|
||||||
|
|
||||||
// GLTF classes.
|
// GLTF classes.
|
||||||
struct GLTFAccessor;
|
class GLTFAccessor;
|
||||||
class GLTFAnimation;
|
class GLTFAnimation;
|
||||||
class GLTFBufferView;
|
class GLTFBufferView;
|
||||||
class GLTFCamera;
|
class GLTFCamera;
|
||||||
|
|
|
||||||
|
|
@ -848,30 +848,8 @@ Error GLTFDocument::_parse_buffers(Ref<GLTFState> p_state, const String &p_base_
|
||||||
Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> p_state) {
|
Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> p_state) {
|
||||||
Array buffers;
|
Array buffers;
|
||||||
for (GLTFBufferViewIndex i = 0; i < p_state->buffer_views.size(); i++) {
|
for (GLTFBufferViewIndex i = 0; i < p_state->buffer_views.size(); i++) {
|
||||||
Dictionary d;
|
const Ref<GLTFBufferView> buffer_view = p_state->buffer_views[i];
|
||||||
|
buffers.push_back(buffer_view->to_dictionary());
|
||||||
Ref<GLTFBufferView> 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);
|
|
||||||
}
|
}
|
||||||
print_verbose("glTF: Total buffer views: " + itos(p_state->buffer_views.size()));
|
print_verbose("glTF: Total buffer views: " + itos(p_state->buffer_views.size()));
|
||||||
if (!buffers.size()) {
|
if (!buffers.size()) {
|
||||||
|
|
@ -887,33 +865,11 @@ Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> p_state) {
|
||||||
}
|
}
|
||||||
const Array &buffers = p_state->json["bufferViews"];
|
const Array &buffers = p_state->json["bufferViews"];
|
||||||
for (GLTFBufferViewIndex i = 0; i < buffers.size(); i++) {
|
for (GLTFBufferViewIndex i = 0; i < buffers.size(); i++) {
|
||||||
const Dictionary &d = buffers[i];
|
const Dictionary &dict = buffers[i];
|
||||||
|
// Both "buffer" and "byteLength" are required by the spec.
|
||||||
Ref<GLTFBufferView> buffer_view;
|
ERR_FAIL_COND_V(!dict.has("buffer"), ERR_PARSE_ERROR);
|
||||||
buffer_view.instantiate();
|
ERR_FAIL_COND_V(!dict.has("byteLength"), ERR_PARSE_ERROR);
|
||||||
|
Ref<GLTFBufferView> buffer_view = GLTFBufferView::from_dictionary(dict);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
p_state->buffer_views.push_back(buffer_view);
|
p_state->buffer_views.push_back(buffer_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -925,49 +881,8 @@ Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> p_state) {
|
||||||
Error GLTFDocument::_encode_accessors(Ref<GLTFState> p_state) {
|
Error GLTFDocument::_encode_accessors(Ref<GLTFState> p_state) {
|
||||||
Array accessors;
|
Array accessors;
|
||||||
for (GLTFAccessorIndex i = 0; i < p_state->accessors.size(); i++) {
|
for (GLTFAccessorIndex i = 0; i < p_state->accessors.size(); i++) {
|
||||||
Dictionary d;
|
const Ref<GLTFAccessor> accessor = p_state->accessors[i];
|
||||||
|
accessors.push_back(accessor->to_dictionary());
|
||||||
Ref<GLTFAccessor> 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!accessors.size()) {
|
if (!accessors.size()) {
|
||||||
|
|
@ -1040,68 +955,12 @@ Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) {
|
||||||
}
|
}
|
||||||
const Array &accessors = p_state->json["accessors"];
|
const Array &accessors = p_state->json["accessors"];
|
||||||
for (GLTFAccessorIndex i = 0; i < accessors.size(); i++) {
|
for (GLTFAccessorIndex i = 0; i < accessors.size(); i++) {
|
||||||
const Dictionary &d = accessors[i];
|
const Dictionary &dict = accessors[i];
|
||||||
|
// All of these fields are required by the spec.
|
||||||
Ref<GLTFAccessor> accessor;
|
ERR_FAIL_COND_V(!dict.has("componentType"), ERR_PARSE_ERROR);
|
||||||
accessor.instantiate();
|
ERR_FAIL_COND_V(!dict.has("count"), ERR_PARSE_ERROR);
|
||||||
|
ERR_FAIL_COND_V(!dict.has("type"), ERR_PARSE_ERROR);
|
||||||
ERR_FAIL_COND_V(!d.has("componentType"), ERR_PARSE_ERROR);
|
Ref<GLTFAccessor> accessor = GLTFAccessor::from_dictionary(dict);
|
||||||
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"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p_state->accessors.push_back(accessor);
|
p_state->accessors.push_back(accessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,6 @@ class GLTFDocument : public Resource {
|
||||||
public:
|
public:
|
||||||
const int32_t JOINT_GROUP_SIZE = 4;
|
const int32_t JOINT_GROUP_SIZE = 4;
|
||||||
|
|
||||||
enum {
|
|
||||||
ARRAY_BUFFER = 34962,
|
|
||||||
ELEMENT_ARRAY_BUFFER = 34963,
|
|
||||||
};
|
|
||||||
enum {
|
enum {
|
||||||
TEXTURE_TYPE_GENERIC = 0,
|
TEXTURE_TYPE_GENERIC = 0,
|
||||||
TEXTURE_TYPE_NORMAL = 1,
|
TEXTURE_TYPE_NORMAL = 1,
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@
|
||||||
#include "gltf_accessor.h"
|
#include "gltf_accessor.h"
|
||||||
#include "gltf_accessor.compat.inc"
|
#include "gltf_accessor.compat.inc"
|
||||||
|
|
||||||
|
#include "../gltf_state.h"
|
||||||
|
|
||||||
void GLTFAccessor::_bind_methods() {
|
void GLTFAccessor::_bind_methods() {
|
||||||
BIND_ENUM_CONSTANT(TYPE_SCALAR);
|
BIND_ENUM_CONSTANT(TYPE_SCALAR);
|
||||||
BIND_ENUM_CONSTANT(TYPE_VEC2);
|
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_SIGNED_LONG);
|
||||||
BIND_ENUM_CONSTANT(COMPONENT_TYPE_UNSIGNED_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("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("set_buffer_view", "buffer_view"), &GLTFAccessor::set_buffer_view);
|
||||||
ClassDB::bind_method(D_METHOD("get_byte_offset"), &GLTFAccessor::get_byte_offset);
|
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
|
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 {
|
GLTFBufferViewIndex GLTFAccessor::get_buffer_view() const {
|
||||||
return buffer_view;
|
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) {
|
void GLTFAccessor::set_sparse_values_byte_offset(int64_t p_sparse_values_byte_offset) {
|
||||||
sparse_values_byte_offset = 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> GLTFAccessor::from_dictionary(const Dictionary &p_dict) {
|
||||||
|
// See https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/schema/accessor.schema.json
|
||||||
|
Ref<GLTFAccessor> 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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,9 @@
|
||||||
|
|
||||||
#include "../gltf_defines.h"
|
#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);
|
GDCLASS(GLTFAccessor, Resource);
|
||||||
friend class GLTFDocument;
|
friend class GLTFDocument;
|
||||||
|
|
||||||
|
|
@ -80,6 +80,10 @@ private:
|
||||||
GLTFBufferViewIndex sparse_values_buffer_view = 0;
|
GLTFBufferViewIndex sparse_values_buffer_view = 0;
|
||||||
int64_t sparse_values_byte_offset = 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:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
|
|
@ -106,6 +110,7 @@ protected:
|
||||||
#endif // DISABLE_DEPRECATED
|
#endif // DISABLE_DEPRECATED
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// Property getters and setters.
|
||||||
GLTFBufferViewIndex get_buffer_view() const;
|
GLTFBufferViewIndex get_buffer_view() const;
|
||||||
void set_buffer_view(GLTFBufferViewIndex p_buffer_view);
|
void set_buffer_view(GLTFBufferViewIndex p_buffer_view);
|
||||||
|
|
||||||
|
|
@ -150,6 +155,10 @@ public:
|
||||||
|
|
||||||
int64_t get_sparse_values_byte_offset() const;
|
int64_t get_sparse_values_byte_offset() const;
|
||||||
void set_sparse_values_byte_offset(int64_t p_sparse_values_byte_offset);
|
void set_sparse_values_byte_offset(int64_t p_sparse_values_byte_offset);
|
||||||
|
|
||||||
|
// Dictionary conversion.
|
||||||
|
static Ref<GLTFAccessor> from_dictionary(const Dictionary &p_dict);
|
||||||
|
Dictionary to_dictionary() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
VARIANT_ENUM_CAST(GLTFAccessor::GLTFAccessorType);
|
VARIANT_ENUM_CAST(GLTFAccessor::GLTFAccessorType);
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@
|
||||||
void GLTFBufferView::_bind_methods() {
|
void GLTFBufferView::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("load_buffer_view_data", "state"), &GLTFBufferView::load_buffer_view_data);
|
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("get_buffer"), &GLTFBufferView::get_buffer);
|
||||||
ClassDB::bind_method(D_METHOD("set_buffer", "buffer"), &GLTFBufferView::set_buffer);
|
ClassDB::bind_method(D_METHOD("set_buffer", "buffer"), &GLTFBufferView::set_buffer);
|
||||||
ClassDB::bind_method(D_METHOD("get_byte_offset"), &GLTFBufferView::get_byte_offset);
|
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;
|
vertex_attributes = p_attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<uint8_t> GLTFBufferView::load_buffer_view_data(const Ref<GLTFState> p_state) const {
|
Vector<uint8_t> GLTFBufferView::load_buffer_view_data(const Ref<GLTFState> p_gltf_state) const {
|
||||||
ERR_FAIL_COND_V(p_state.is_null(), Vector<uint8_t>());
|
ERR_FAIL_COND_V(p_gltf_state.is_null(), Vector<uint8_t>());
|
||||||
ERR_FAIL_COND_V_MSG(byte_stride > 0, Vector<uint8_t>(), "Buffer views with byte stride are not yet supported by this method.");
|
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();
|
const TypedArray<Vector<uint8_t>> &buffers = p_gltf_state->get_buffers();
|
||||||
ERR_FAIL_INDEX_V(buffer, buffers.size(), Vector<uint8_t>());
|
ERR_FAIL_INDEX_V(buffer, buffers.size(), Vector<uint8_t>());
|
||||||
const PackedByteArray &buffer_data = buffers[buffer];
|
const PackedByteArray &buffer_data = buffers[buffer];
|
||||||
const int64_t byte_end = byte_offset + byte_length;
|
const int64_t byte_end = byte_offset + byte_length;
|
||||||
return buffer_data.slice(byte_offset, byte_end);
|
return buffer_data.slice(byte_offset, byte_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<GLTFBufferView> GLTFBufferView::from_dictionary(const Dictionary &p_dict) {
|
||||||
|
// See https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/schema/bufferView.schema.json
|
||||||
|
Ref<GLTFBufferView> 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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,24 @@ class GLTFBufferView : public Resource {
|
||||||
GDCLASS(GLTFBufferView, Resource);
|
GDCLASS(GLTFBufferView, Resource);
|
||||||
friend class GLTFDocument;
|
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:
|
private:
|
||||||
GLTFBufferIndex buffer = -1;
|
GLTFBufferIndex buffer = -1;
|
||||||
int64_t byte_offset = 0;
|
int64_t byte_offset = 0;
|
||||||
int64_t byte_length = 0;
|
int64_t byte_length = 0;
|
||||||
int64_t byte_stride = -1;
|
int64_t byte_stride = -1;
|
||||||
bool indices = false;
|
bool indices = false; // True for TARGET_ELEMENT_ARRAY_BUFFER.
|
||||||
bool vertex_attributes = false;
|
bool vertex_attributes = false; // True for TARGET_ARRAY_BUFFER.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
@ -78,5 +89,8 @@ public:
|
||||||
bool get_vertex_attributes() const;
|
bool get_vertex_attributes() const;
|
||||||
void set_vertex_attributes(bool p_attributes);
|
void set_vertex_attributes(bool p_attributes);
|
||||||
|
|
||||||
Vector<uint8_t> load_buffer_view_data(const Ref<GLTFState> p_state) const;
|
Vector<uint8_t> load_buffer_view_data(const Ref<GLTFState> p_gltf_state) const;
|
||||||
|
|
||||||
|
static Ref<GLTFBufferView> from_dictionary(const Dictionary &p_dict);
|
||||||
|
Dictionary to_dictionary() const;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue