mirror of
https://github.com/godotengine/godot.git
synced 2025-12-07 22:00:10 +00:00
GLTF: Move accessor decoding functions to GLTFAccessor
This commit is contained in:
parent
bd2ca13c6f
commit
9d0b391d6c
4 changed files with 733 additions and 734 deletions
|
|
@ -81,10 +81,6 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
constexpr int COMPONENT_COUNT_FOR_ACCESSOR_TYPE[7] = {
|
|
||||||
1, 2, 3, 4, 4, 9, 16
|
|
||||||
};
|
|
||||||
|
|
||||||
static void _attach_extras_to_meta(const Dictionary &p_extras, Ref<Resource> p_node) {
|
static void _attach_extras_to_meta(const Dictionary &p_extras, Ref<Resource> p_node) {
|
||||||
if (!p_extras.is_empty()) {
|
if (!p_extras.is_empty()) {
|
||||||
p_node->set_meta("extras", p_extras);
|
p_node->set_meta("extras", p_extras);
|
||||||
|
|
@ -908,32 +904,6 @@ Error GLTFDocument::_encode_accessors(Ref<GLTFState> p_state) {
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
String GLTFDocument::_get_accessor_type_name(const GLTFAccessor::GLTFAccessorType p_accessor_type) {
|
|
||||||
if (p_accessor_type == GLTFAccessor::TYPE_SCALAR) {
|
|
||||||
return "SCALAR";
|
|
||||||
}
|
|
||||||
if (p_accessor_type == GLTFAccessor::TYPE_VEC2) {
|
|
||||||
return "VEC2";
|
|
||||||
}
|
|
||||||
if (p_accessor_type == GLTFAccessor::TYPE_VEC3) {
|
|
||||||
return "VEC3";
|
|
||||||
}
|
|
||||||
if (p_accessor_type == GLTFAccessor::TYPE_VEC4) {
|
|
||||||
return "VEC4";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_accessor_type == GLTFAccessor::TYPE_MAT2) {
|
|
||||||
return "MAT2";
|
|
||||||
}
|
|
||||||
if (p_accessor_type == GLTFAccessor::TYPE_MAT3) {
|
|
||||||
return "MAT3";
|
|
||||||
}
|
|
||||||
if (p_accessor_type == GLTFAccessor::TYPE_MAT4) {
|
|
||||||
return "MAT4";
|
|
||||||
}
|
|
||||||
ERR_FAIL_V("SCALAR");
|
|
||||||
}
|
|
||||||
|
|
||||||
Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) {
|
Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) {
|
||||||
if (!p_state->json.has("accessors")) {
|
if (!p_state->json.has("accessors")) {
|
||||||
return OK;
|
return OK;
|
||||||
|
|
@ -954,647 +924,94 @@ Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) {
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
String GLTFDocument::_get_component_type_name(const GLTFAccessor::GLTFComponentType p_component) {
|
template <typename T>
|
||||||
switch (p_component) {
|
T GLTFDocument::_decode_unpack_indexed_data(const T &p_source, const PackedInt32Array &p_indices) {
|
||||||
case GLTFAccessor::COMPONENT_TYPE_NONE:
|
// Handle unpacking indexed data as if it was a regular array.
|
||||||
return "None";
|
// This isn't a feature of accessors, rather a feature of places using accessors like
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_BYTE:
|
// indexed meshes, but GLTFDocument needs it in several places when reading accessors.
|
||||||
return "Byte";
|
T ret;
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_BYTE:
|
const int64_t last_index = p_indices[p_indices.size() - 1];
|
||||||
return "UByte";
|
ERR_FAIL_COND_V(last_index >= p_source.size(), ret);
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_SHORT:
|
ret.resize(p_indices.size());
|
||||||
return "Short";
|
for (int64_t i = 0; i < p_indices.size(); i++) {
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_SHORT:
|
const int64_t source_index = p_indices[i];
|
||||||
return "UShort";
|
ret.set(i, p_source[source_index]);
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_INT:
|
|
||||||
return "Int";
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_INT:
|
|
||||||
return "UInt";
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SINGLE_FLOAT:
|
|
||||||
return "Float";
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_DOUBLE_FLOAT:
|
|
||||||
return "Double";
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_HALF_FLOAT:
|
|
||||||
return "Half";
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_LONG:
|
|
||||||
return "Long";
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_LONG:
|
|
||||||
return "ULong";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "<Error>";
|
|
||||||
}
|
|
||||||
|
|
||||||
Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> p_state, double *p_dst, const GLTFBufferViewIndex p_buffer_view, const int64_t p_skip_every, const int64_t p_skip_bytes, const int64_t p_element_size, const int64_t p_count, const GLTFAccessor::GLTFAccessorType p_accessor_type, const int64_t p_component_count, const GLTFAccessor::GLTFComponentType p_component_type, const int64_t p_component_size, const bool p_normalized, const int64_t p_byte_offset, const bool p_for_vertex) {
|
|
||||||
const Ref<GLTFBufferView> bv = p_state->buffer_views[p_buffer_view];
|
|
||||||
|
|
||||||
int64_t stride = p_element_size;
|
|
||||||
if (bv->byte_stride > 0) {
|
|
||||||
stride = bv->byte_stride;
|
|
||||||
}
|
|
||||||
if (p_for_vertex && stride % 4) {
|
|
||||||
stride += 4 - (stride % 4); //according to spec must be multiple of 4
|
|
||||||
}
|
|
||||||
|
|
||||||
ERR_FAIL_INDEX_V(bv->buffer, p_state->buffers.size(), ERR_PARSE_ERROR);
|
|
||||||
if (bv->byte_offset % p_component_size != 0) {
|
|
||||||
WARN_PRINT("glTF: Buffer view byte offset is not a multiple of accessor component size. This file is invalid per the glTF specification and will not load correctly in some glTF viewers, but Godot will try to load it anyway.");
|
|
||||||
}
|
|
||||||
if (p_byte_offset % p_component_size != 0) {
|
|
||||||
WARN_PRINT("glTF: Accessor byte offset is not a multiple of accessor component size. This file is invalid per the glTF specification and will not load correctly in some glTF viewers, but Godot will try to load it anyway.");
|
|
||||||
}
|
|
||||||
|
|
||||||
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: accessor type " + _get_accessor_type_name(p_accessor_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 int64_t 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 (int64_t i = 0; i < p_count; i++) {
|
|
||||||
const uint8_t *src = &bufptr[offset + i * stride];
|
|
||||||
|
|
||||||
for (int64_t 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;
|
|
||||||
// 3.11. Implementations MUST use following equations to decode real floating-point value f from a normalized integer c and vise-versa.
|
|
||||||
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#animations
|
|
||||||
switch (p_component_type) {
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_NONE: {
|
|
||||||
ERR_FAIL_V_MSG(ERR_INVALID_DATA, "glTF: Failed to decode buffer view, component type not set.");
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_BYTE: {
|
|
||||||
int8_t b = int8_t(*src);
|
|
||||||
if (p_normalized) {
|
|
||||||
d = MAX(double(b) / 127.0, -1.0);
|
|
||||||
} else {
|
|
||||||
d = double(b);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_BYTE: {
|
|
||||||
uint8_t b = *src;
|
|
||||||
if (p_normalized) {
|
|
||||||
d = (double(b) / 255.0);
|
|
||||||
} else {
|
|
||||||
d = double(b);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_SHORT: {
|
|
||||||
int16_t s = *(int16_t *)src;
|
|
||||||
if (p_normalized) {
|
|
||||||
d = MAX(double(s) / 32767.0, -1.0);
|
|
||||||
} else {
|
|
||||||
d = double(s);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_SHORT: {
|
|
||||||
uint16_t s = *(uint16_t *)src;
|
|
||||||
if (p_normalized) {
|
|
||||||
d = (double(s) / 65535.0);
|
|
||||||
} else {
|
|
||||||
d = double(s);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_INT: {
|
|
||||||
d = *(int32_t *)src;
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_INT: {
|
|
||||||
d = *(uint32_t *)src;
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SINGLE_FLOAT: {
|
|
||||||
d = *(float *)src;
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_DOUBLE_FLOAT: {
|
|
||||||
d = *(double *)src;
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_HALF_FLOAT: {
|
|
||||||
ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "glTF: Half float not supported yet.");
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_LONG: {
|
|
||||||
d = *(int64_t *)src;
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_LONG: {
|
|
||||||
d = *(uint64_t *)src;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
*p_dst++ = d;
|
|
||||||
src += p_component_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GLTFDocument::_get_component_type_size(const GLTFAccessor::GLTFComponentType p_component_type) {
|
|
||||||
switch (p_component_type) {
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_NONE:
|
|
||||||
ERR_FAIL_V(0);
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_BYTE:
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_BYTE:
|
|
||||||
return 1;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_SHORT:
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_SHORT:
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_HALF_FLOAT:
|
|
||||||
return 2;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_INT:
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_INT:
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SINGLE_FLOAT:
|
|
||||||
return 4;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_DOUBLE_FLOAT:
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_LONG:
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_LONG:
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
ERR_FAIL_V(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
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, p_state->accessors.size(), Vector<double>());
|
|
||||||
|
|
||||||
const Ref<GLTFAccessor> a = p_state->accessors[p_accessor];
|
|
||||||
|
|
||||||
const int component_count = COMPONENT_COUNT_FOR_ACCESSOR_TYPE[a->accessor_type];
|
|
||||||
const int component_size = _get_component_type_size(a->component_type);
|
|
||||||
ERR_FAIL_COND_V(component_size == 0, Vector<double>());
|
|
||||||
int element_size = component_count * component_size;
|
|
||||||
|
|
||||||
int64_t skip_every = 0;
|
|
||||||
int64_t skip_bytes = 0;
|
|
||||||
//special case of alignments, as described in spec
|
|
||||||
switch (a->component_type) {
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_BYTE:
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_BYTE: {
|
|
||||||
if (a->accessor_type == GLTFAccessor::TYPE_MAT2) {
|
|
||||||
skip_every = 2;
|
|
||||||
skip_bytes = 2;
|
|
||||||
element_size = 8; //override for this case
|
|
||||||
}
|
|
||||||
if (a->accessor_type == GLTFAccessor::TYPE_MAT3) {
|
|
||||||
skip_every = 3;
|
|
||||||
skip_bytes = 1;
|
|
||||||
element_size = 12; //override for this case
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_SIGNED_SHORT:
|
|
||||||
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_SHORT: {
|
|
||||||
if (a->accessor_type == GLTFAccessor::TYPE_MAT3) {
|
|
||||||
skip_every = 6;
|
|
||||||
skip_bytes = 2;
|
|
||||||
element_size = 16; //override for this case
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
default: {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<double> dst_buffer;
|
|
||||||
dst_buffer.resize(component_count * a->count);
|
|
||||||
double *dst = dst_buffer.ptrw();
|
|
||||||
|
|
||||||
if (a->buffer_view >= 0) {
|
|
||||||
ERR_FAIL_INDEX_V(a->buffer_view, p_state->buffer_views.size(), Vector<double>());
|
|
||||||
|
|
||||||
const Error err = _decode_buffer_view(p_state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->accessor_type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex);
|
|
||||||
if (err != OK) {
|
|
||||||
return Vector<double>();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//fill with zeros, as bufferview is not defined.
|
|
||||||
for (int64_t i = 0; i < (a->count * component_count); i++) {
|
|
||||||
dst_buffer.write[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a->sparse_count > 0) {
|
|
||||||
// I could not find any file using this, so this code is so far untested
|
|
||||||
Vector<double> indices;
|
|
||||||
indices.resize(a->sparse_count);
|
|
||||||
const int indices_component_size = _get_component_type_size(a->sparse_indices_component_type);
|
|
||||||
|
|
||||||
Error err = _decode_buffer_view(p_state, indices.ptrw(), a->sparse_indices_buffer_view, 0, 0, indices_component_size, a->sparse_count, GLTFAccessor::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(p_state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->accessor_type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex);
|
|
||||||
if (err != OK) {
|
|
||||||
return Vector<double>();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < indices.size(); i++) {
|
|
||||||
const int64_t write_offset = int(indices[i]) * component_count;
|
|
||||||
|
|
||||||
for (int j = 0; j < component_count; j++) {
|
|
||||||
dst[write_offset + j] = data[i * component_count + j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dst_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector<int> &p_packed_vertex_ids) {
|
|
||||||
const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
|
|
||||||
Vector<int> ret;
|
|
||||||
|
|
||||||
if (attribs.is_empty()) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
const double *attribs_ptr = attribs.ptr();
|
|
||||||
int64_t ret_size = attribs.size();
|
|
||||||
if (!p_packed_vertex_ids.is_empty()) {
|
|
||||||
ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret);
|
|
||||||
ret_size = p_packed_vertex_ids.size();
|
|
||||||
}
|
|
||||||
ret.resize(ret_size);
|
|
||||||
for (int64_t i = 0; i < ret_size; i++) {
|
|
||||||
int64_t src_i = i;
|
|
||||||
if (!p_packed_vertex_ids.is_empty()) {
|
|
||||||
src_i = p_packed_vertex_ids[i];
|
|
||||||
}
|
|
||||||
ret.write[i] = int(attribs_ptr[src_i]);
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector<int> &p_packed_vertex_ids) {
|
PackedFloat32Array GLTFDocument::_decode_accessor_as_float32s(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids) {
|
||||||
const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
|
ERR_FAIL_INDEX_V(p_accessor_index, p_gltf_state->accessors.size(), PackedFloat32Array());
|
||||||
Vector<float> ret;
|
Ref<GLTFAccessor> accessor = p_gltf_state->accessors[p_accessor_index];
|
||||||
|
PackedFloat32Array numbers = accessor->decode_as_float32s(p_gltf_state);
|
||||||
if (attribs.is_empty()) {
|
if (p_packed_vertex_ids.is_empty()) {
|
||||||
return ret;
|
return numbers;
|
||||||
}
|
}
|
||||||
|
return _decode_unpack_indexed_data<PackedFloat32Array>(numbers, p_packed_vertex_ids);
|
||||||
const double *attribs_ptr = attribs.ptr();
|
|
||||||
int64_t ret_size = attribs.size();
|
|
||||||
if (!p_packed_vertex_ids.is_empty()) {
|
|
||||||
ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret);
|
|
||||||
ret_size = p_packed_vertex_ids.size();
|
|
||||||
}
|
|
||||||
ret.resize(ret_size);
|
|
||||||
for (int64_t i = 0; i < ret_size; i++) {
|
|
||||||
int64_t src_i = i;
|
|
||||||
if (!p_packed_vertex_ids.is_empty()) {
|
|
||||||
src_i = p_packed_vertex_ids[i];
|
|
||||||
}
|
|
||||||
ret.write[i] = float(attribs_ptr[src_i]);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector<int> &p_packed_vertex_ids) {
|
PackedFloat64Array GLTFDocument::_decode_accessor_as_float64s(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids) {
|
||||||
const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
|
ERR_FAIL_INDEX_V(p_accessor_index, p_gltf_state->accessors.size(), PackedFloat64Array());
|
||||||
Vector<Vector2> ret;
|
Ref<GLTFAccessor> accessor = p_gltf_state->accessors[p_accessor_index];
|
||||||
|
PackedFloat64Array numbers = accessor->decode_as_float64s(p_gltf_state);
|
||||||
if (attribs.is_empty()) {
|
if (p_packed_vertex_ids.is_empty()) {
|
||||||
return ret;
|
return numbers;
|
||||||
}
|
}
|
||||||
|
return _decode_unpack_indexed_data<PackedFloat64Array>(numbers, p_packed_vertex_ids);
|
||||||
ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret);
|
|
||||||
const double *attribs_ptr = attribs.ptr();
|
|
||||||
int64_t ret_size = attribs.size() / 2;
|
|
||||||
if (!p_packed_vertex_ids.is_empty()) {
|
|
||||||
ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret);
|
|
||||||
ret_size = p_packed_vertex_ids.size();
|
|
||||||
}
|
|
||||||
ret.resize(ret_size);
|
|
||||||
for (int64_t i = 0; i < ret_size; i++) {
|
|
||||||
int64_t src_i = i;
|
|
||||||
if (!p_packed_vertex_ids.is_empty()) {
|
|
||||||
src_i = p_packed_vertex_ids[i];
|
|
||||||
}
|
|
||||||
ret.write[i] = Vector2(attribs_ptr[src_i * 2 + 0], attribs_ptr[src_i * 2 + 1]);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector<int> &p_packed_vertex_ids) {
|
PackedInt32Array GLTFDocument::_decode_accessor_as_int32s(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids) {
|
||||||
const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
|
ERR_FAIL_INDEX_V(p_accessor_index, p_gltf_state->accessors.size(), PackedInt32Array());
|
||||||
Vector<Vector3> ret;
|
Ref<GLTFAccessor> accessor = p_gltf_state->accessors[p_accessor_index];
|
||||||
|
PackedInt32Array numbers = accessor->decode_as_int32s(p_gltf_state);
|
||||||
if (attribs.is_empty()) {
|
if (p_packed_vertex_ids.is_empty()) {
|
||||||
return ret;
|
return numbers;
|
||||||
}
|
}
|
||||||
|
return _decode_unpack_indexed_data<PackedInt32Array>(numbers, p_packed_vertex_ids);
|
||||||
ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret);
|
|
||||||
const double *attribs_ptr = attribs.ptr();
|
|
||||||
int64_t ret_size = attribs.size() / 3;
|
|
||||||
if (!p_packed_vertex_ids.is_empty()) {
|
|
||||||
ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret);
|
|
||||||
ret_size = p_packed_vertex_ids.size();
|
|
||||||
}
|
|
||||||
ret.resize(ret_size);
|
|
||||||
for (int64_t i = 0; i < ret_size; i++) {
|
|
||||||
int64_t src_i = i;
|
|
||||||
if (!p_packed_vertex_ids.is_empty()) {
|
|
||||||
src_i = p_packed_vertex_ids[i];
|
|
||||||
}
|
|
||||||
ret.write[i] = Vector3(attribs_ptr[src_i * 3 + 0], attribs_ptr[src_i * 3 + 1], attribs_ptr[src_i * 3 + 2]);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex, const Vector<int> &p_packed_vertex_ids) {
|
PackedVector2Array GLTFDocument::_decode_accessor_as_vec2(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids) {
|
||||||
const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
|
ERR_FAIL_INDEX_V(p_accessor_index, p_gltf_state->accessors.size(), PackedVector2Array());
|
||||||
Vector<Color> ret;
|
Ref<GLTFAccessor> accessor = p_gltf_state->accessors[p_accessor_index];
|
||||||
|
PackedVector2Array vectors = accessor->decode_as_vector2s(p_gltf_state);
|
||||||
if (attribs.is_empty()) {
|
if (p_packed_vertex_ids.is_empty()) {
|
||||||
return ret;
|
return vectors;
|
||||||
}
|
}
|
||||||
|
return _decode_unpack_indexed_data<PackedVector2Array>(vectors, p_packed_vertex_ids);
|
||||||
const GLTFAccessor::GLTFAccessorType accessor_type = p_state->accessors[p_accessor]->accessor_type;
|
|
||||||
ERR_FAIL_COND_V(!(accessor_type == GLTFAccessor::TYPE_VEC3 || accessor_type == GLTFAccessor::TYPE_VEC4), ret);
|
|
||||||
int vec_len = 3;
|
|
||||||
if (accessor_type == GLTFAccessor::TYPE_VEC4) {
|
|
||||||
vec_len = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
ERR_FAIL_COND_V(attribs.size() % vec_len != 0, ret);
|
|
||||||
const double *attribs_ptr = attribs.ptr();
|
|
||||||
int64_t ret_size = attribs.size() / vec_len;
|
|
||||||
if (!p_packed_vertex_ids.is_empty()) {
|
|
||||||
ERR_FAIL_COND_V(p_packed_vertex_ids[p_packed_vertex_ids.size() - 1] >= ret_size, ret);
|
|
||||||
ret_size = p_packed_vertex_ids.size();
|
|
||||||
}
|
|
||||||
ret.resize(ret_size);
|
|
||||||
for (int64_t i = 0; i < ret_size; i++) {
|
|
||||||
int64_t src_i = i;
|
|
||||||
if (!p_packed_vertex_ids.is_empty()) {
|
|
||||||
src_i = p_packed_vertex_ids[i];
|
|
||||||
}
|
|
||||||
ret.write[i] = Color(attribs_ptr[src_i * vec_len + 0], attribs_ptr[src_i * vec_len + 1], attribs_ptr[src_i * vec_len + 2], vec_len == 4 ? attribs_ptr[src_i * 4 + 3] : 1.0);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
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.is_empty()) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
|
|
||||||
const double *attribs_ptr = attribs.ptr();
|
|
||||||
const int64_t ret_size = attribs.size() / 4;
|
|
||||||
ret.resize(ret_size);
|
|
||||||
{
|
|
||||||
for (int64_t i = 0; i < ret_size; i++) {
|
|
||||||
ret.write[i] = Quaternion(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]).normalized();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
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.is_empty()) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
|
|
||||||
ret.resize(attribs.size() / 4);
|
|
||||||
for (int64_t i = 0; i < ret.size(); i++) {
|
|
||||||
ret.write[i][0] = Vector2(attribs[i * 4 + 0], attribs[i * 4 + 1]);
|
|
||||||
ret.write[i][1] = Vector2(attribs[i * 4 + 2], attribs[i * 4 + 3]);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
|
PackedVector3Array GLTFDocument::_decode_accessor_as_vec3(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids) {
|
||||||
const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
|
ERR_FAIL_INDEX_V(p_accessor_index, p_gltf_state->accessors.size(), PackedVector3Array());
|
||||||
Vector<Basis> ret;
|
Ref<GLTFAccessor> accessor = p_gltf_state->accessors[p_accessor_index];
|
||||||
|
PackedVector3Array vectors = accessor->decode_as_vector3s(p_gltf_state);
|
||||||
if (attribs.is_empty()) {
|
if (p_packed_vertex_ids.is_empty()) {
|
||||||
return ret;
|
return vectors;
|
||||||
}
|
}
|
||||||
|
return _decode_unpack_indexed_data<PackedVector3Array>(vectors, p_packed_vertex_ids);
|
||||||
ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret);
|
|
||||||
ret.resize(attribs.size() / 9);
|
|
||||||
for (int64_t i = 0; i < ret.size(); i++) {
|
|
||||||
ret.write[i].set_column(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2]));
|
|
||||||
ret.write[i].set_column(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5]));
|
|
||||||
ret.write[i].set_column(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8]));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
|
PackedColorArray GLTFDocument::_decode_accessor_as_color(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids) {
|
||||||
const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex);
|
ERR_FAIL_INDEX_V(p_accessor_index, p_gltf_state->accessors.size(), PackedColorArray());
|
||||||
Vector<Transform3D> ret;
|
Ref<GLTFAccessor> accessor = p_gltf_state->accessors[p_accessor_index];
|
||||||
|
PackedColorArray colors = accessor->decode_as_colors(p_gltf_state);
|
||||||
if (attribs.is_empty()) {
|
if (p_packed_vertex_ids.is_empty()) {
|
||||||
return ret;
|
return colors;
|
||||||
}
|
}
|
||||||
|
return _decode_unpack_indexed_data<PackedColorArray>(colors, p_packed_vertex_ids);
|
||||||
ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret);
|
|
||||||
ret.resize(attribs.size() / 16);
|
|
||||||
for (int64_t i = 0; i < ret.size(); i++) {
|
|
||||||
ret.write[i].basis.set_column(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2]));
|
|
||||||
ret.write[i].basis.set_column(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6]));
|
|
||||||
ret.write[i].basis.set_column(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10]));
|
|
||||||
ret.write[i].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14]));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Variant> GLTFDocument::_decode_accessor_as_variant(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, Variant::Type p_variant_type, GLTFAccessor::GLTFAccessorType p_accessor_type) {
|
Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index) {
|
||||||
const Vector<double> attribs = _decode_accessor(p_state, p_accessor, false);
|
ERR_FAIL_INDEX_V(p_accessor_index, p_gltf_state->accessors.size(), Vector<Quaternion>());
|
||||||
Vector<Variant> ret;
|
Ref<GLTFAccessor> accessor = p_gltf_state->accessors[p_accessor_index];
|
||||||
ERR_FAIL_COND_V_MSG(attribs.is_empty(), ret, "glTF: The accessor was empty.");
|
Vector<Quaternion> quaternions = accessor->decode_as_quaternions(p_gltf_state);
|
||||||
const int component_count = COMPONENT_COUNT_FOR_ACCESSOR_TYPE[p_accessor_type];
|
return quaternions;
|
||||||
ERR_FAIL_COND_V_MSG(attribs.size() % component_count != 0, ret, "glTF: The accessor size was not a multiple of the component count.");
|
}
|
||||||
const int64_t ret_size = attribs.size() / component_count;
|
|
||||||
ret.resize(ret_size);
|
Array GLTFDocument::_decode_accessor_as_variants(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, Variant::Type p_variant_type) {
|
||||||
for (int64_t i = 0; i < ret_size; i++) {
|
ERR_FAIL_INDEX_V(p_accessor_index, p_gltf_state->accessors.size(), Array());
|
||||||
switch (p_variant_type) {
|
Ref<GLTFAccessor> accessor = p_gltf_state->accessors[p_accessor_index];
|
||||||
case Variant::BOOL: {
|
Array variants = accessor->decode_as_variants(p_gltf_state, p_variant_type);
|
||||||
ret.write[i] = attribs[i * component_count] != 0.0;
|
return variants;
|
||||||
} break;
|
|
||||||
case Variant::INT: {
|
|
||||||
ret.write[i] = (int64_t)attribs[i * component_count];
|
|
||||||
} break;
|
|
||||||
case Variant::FLOAT: {
|
|
||||||
ret.write[i] = attribs[i * component_count];
|
|
||||||
} break;
|
|
||||||
case Variant::VECTOR2:
|
|
||||||
case Variant::RECT2:
|
|
||||||
case Variant::VECTOR3:
|
|
||||||
case Variant::VECTOR4:
|
|
||||||
case Variant::PLANE:
|
|
||||||
case Variant::QUATERNION: {
|
|
||||||
// General-purpose code for importing glTF accessor data with any component count into structs up to 4 `real_t`s in size.
|
|
||||||
Variant v;
|
|
||||||
switch (component_count) {
|
|
||||||
case 1: {
|
|
||||||
v = Vector4(attribs[i * component_count], 0.0f, 0.0f, 0.0f);
|
|
||||||
} break;
|
|
||||||
case 2: {
|
|
||||||
v = Vector4(attribs[i * component_count], attribs[i * component_count + 1], 0.0f, 0.0f);
|
|
||||||
} break;
|
|
||||||
case 3: {
|
|
||||||
v = Vector4(attribs[i * component_count], attribs[i * component_count + 1], attribs[i * component_count + 2], 0.0f);
|
|
||||||
} break;
|
|
||||||
default: {
|
|
||||||
v = Vector4(attribs[i * component_count], attribs[i * component_count + 1], attribs[i * component_count + 2], attribs[i * component_count + 3]);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
// Evil hack that relies on the structure of Variant, but it's the
|
|
||||||
// only way to accomplish this without a ton of code duplication.
|
|
||||||
*(Variant::Type *)&v = p_variant_type;
|
|
||||||
ret.write[i] = v;
|
|
||||||
} break;
|
|
||||||
case Variant::VECTOR2I:
|
|
||||||
case Variant::RECT2I:
|
|
||||||
case Variant::VECTOR3I:
|
|
||||||
case Variant::VECTOR4I: {
|
|
||||||
// General-purpose code for importing glTF accessor data with any component count into structs up to 4 `int32_t`s in size.
|
|
||||||
Variant v;
|
|
||||||
switch (component_count) {
|
|
||||||
case 1: {
|
|
||||||
v = Vector4i((int32_t)attribs[i * component_count], 0, 0, 0);
|
|
||||||
} break;
|
|
||||||
case 2: {
|
|
||||||
v = Vector4i((int32_t)attribs[i * component_count], (int32_t)attribs[i * component_count + 1], 0, 0);
|
|
||||||
} break;
|
|
||||||
case 3: {
|
|
||||||
v = Vector4i((int32_t)attribs[i * component_count], (int32_t)attribs[i * component_count + 1], (int32_t)attribs[i * component_count + 2], 0);
|
|
||||||
} break;
|
|
||||||
default: {
|
|
||||||
v = Vector4i((int32_t)attribs[i * component_count], (int32_t)attribs[i * component_count + 1], (int32_t)attribs[i * component_count + 2], (int32_t)attribs[i * component_count + 3]);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
// Evil hack that relies on the structure of Variant, but it's the
|
|
||||||
// only way to accomplish this without a ton of code duplication.
|
|
||||||
*(Variant::Type *)&v = p_variant_type;
|
|
||||||
ret.write[i] = v;
|
|
||||||
} break;
|
|
||||||
// No more generalized hacks, each of the below types needs a lot of repetitive code.
|
|
||||||
case Variant::COLOR: {
|
|
||||||
Variant v;
|
|
||||||
switch (component_count) {
|
|
||||||
case 1: {
|
|
||||||
v = Color(attribs[i * component_count], 0.0f, 0.0f, 1.0f);
|
|
||||||
} break;
|
|
||||||
case 2: {
|
|
||||||
v = Color(attribs[i * component_count], attribs[i * component_count + 1], 0.0f, 1.0f);
|
|
||||||
} break;
|
|
||||||
case 3: {
|
|
||||||
v = Color(attribs[i * component_count], attribs[i * component_count + 1], attribs[i * component_count + 2], 1.0f);
|
|
||||||
} break;
|
|
||||||
default: {
|
|
||||||
v = Color(attribs[i * component_count], attribs[i * component_count + 1], attribs[i * component_count + 2], attribs[i * component_count + 3]);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
ret.write[i] = v;
|
|
||||||
} break;
|
|
||||||
case Variant::TRANSFORM2D: {
|
|
||||||
Transform2D t;
|
|
||||||
switch (component_count) {
|
|
||||||
case 4: {
|
|
||||||
t.columns[0] = Vector2(attribs[i * component_count + 0], attribs[i * component_count + 1]);
|
|
||||||
t.columns[1] = Vector2(attribs[i * component_count + 2], attribs[i * component_count + 3]);
|
|
||||||
} break;
|
|
||||||
case 9: {
|
|
||||||
t.columns[0] = Vector2(attribs[i * component_count + 0], attribs[i * component_count + 1]);
|
|
||||||
t.columns[1] = Vector2(attribs[i * component_count + 3], attribs[i * component_count + 4]);
|
|
||||||
t.columns[2] = Vector2(attribs[i * component_count + 6], attribs[i * component_count + 7]);
|
|
||||||
} break;
|
|
||||||
case 16: {
|
|
||||||
t.columns[0] = Vector2(attribs[i * component_count + 0], attribs[i * component_count + 1]);
|
|
||||||
t.columns[1] = Vector2(attribs[i * component_count + 4], attribs[i * component_count + 5]);
|
|
||||||
t.columns[2] = Vector2(attribs[i * component_count + 12], attribs[i * component_count + 13]);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
ret.write[i] = t;
|
|
||||||
} break;
|
|
||||||
case Variant::BASIS: {
|
|
||||||
Basis b;
|
|
||||||
switch (component_count) {
|
|
||||||
case 4: {
|
|
||||||
b.rows[0] = Vector3(attribs[i * component_count + 0], attribs[i * component_count + 2], 0.0f);
|
|
||||||
b.rows[1] = Vector3(attribs[i * component_count + 1], attribs[i * component_count + 3], 0.0f);
|
|
||||||
} break;
|
|
||||||
case 9: {
|
|
||||||
b.rows[0] = Vector3(attribs[i * component_count + 0], attribs[i * component_count + 3], attribs[i * component_count + 6]);
|
|
||||||
b.rows[1] = Vector3(attribs[i * component_count + 1], attribs[i * component_count + 4], attribs[i * component_count + 7]);
|
|
||||||
b.rows[2] = Vector3(attribs[i * component_count + 2], attribs[i * component_count + 5], attribs[i * component_count + 8]);
|
|
||||||
} break;
|
|
||||||
case 16: {
|
|
||||||
b.rows[0] = Vector3(attribs[i * component_count + 0], attribs[i * component_count + 4], attribs[i * component_count + 8]);
|
|
||||||
b.rows[1] = Vector3(attribs[i * component_count + 1], attribs[i * component_count + 5], attribs[i * component_count + 9]);
|
|
||||||
b.rows[2] = Vector3(attribs[i * component_count + 2], attribs[i * component_count + 6], attribs[i * component_count + 10]);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
ret.write[i] = b;
|
|
||||||
} break;
|
|
||||||
case Variant::TRANSFORM3D: {
|
|
||||||
Transform3D t;
|
|
||||||
switch (component_count) {
|
|
||||||
case 4: {
|
|
||||||
t.basis.rows[0] = Vector3(attribs[i * component_count + 0], attribs[i * component_count + 2], 0.0f);
|
|
||||||
t.basis.rows[1] = Vector3(attribs[i * component_count + 1], attribs[i * component_count + 3], 0.0f);
|
|
||||||
} break;
|
|
||||||
case 9: {
|
|
||||||
t.basis.rows[0] = Vector3(attribs[i * component_count + 0], attribs[i * component_count + 3], attribs[i * component_count + 6]);
|
|
||||||
t.basis.rows[1] = Vector3(attribs[i * component_count + 1], attribs[i * component_count + 4], attribs[i * component_count + 7]);
|
|
||||||
t.basis.rows[2] = Vector3(attribs[i * component_count + 2], attribs[i * component_count + 5], attribs[i * component_count + 8]);
|
|
||||||
} break;
|
|
||||||
case 16: {
|
|
||||||
t.basis.rows[0] = Vector3(attribs[i * component_count + 0], attribs[i * component_count + 4], attribs[i * component_count + 8]);
|
|
||||||
t.basis.rows[1] = Vector3(attribs[i * component_count + 1], attribs[i * component_count + 5], attribs[i * component_count + 9]);
|
|
||||||
t.basis.rows[2] = Vector3(attribs[i * component_count + 2], attribs[i * component_count + 6], attribs[i * component_count + 10]);
|
|
||||||
t.origin = Vector3(attribs[i * component_count + 12], attribs[i * component_count + 13], attribs[i * component_count + 14]);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
ret.write[i] = t;
|
|
||||||
} break;
|
|
||||||
case Variant::PROJECTION: {
|
|
||||||
Projection p;
|
|
||||||
switch (component_count) {
|
|
||||||
case 4: {
|
|
||||||
p.columns[0] = Vector4(attribs[i * component_count + 0], attribs[i * component_count + 1], 0.0f, 0.0f);
|
|
||||||
p.columns[1] = Vector4(attribs[i * component_count + 4], attribs[i * component_count + 5], 0.0f, 0.0f);
|
|
||||||
} break;
|
|
||||||
case 9: {
|
|
||||||
p.columns[0] = Vector4(attribs[i * component_count + 0], attribs[i * component_count + 1], attribs[i * component_count + 2], 0.0f);
|
|
||||||
p.columns[1] = Vector4(attribs[i * component_count + 4], attribs[i * component_count + 5], attribs[i * component_count + 6], 0.0f);
|
|
||||||
p.columns[2] = Vector4(attribs[i * component_count + 8], attribs[i * component_count + 9], attribs[i * component_count + 10], 0.0f);
|
|
||||||
} break;
|
|
||||||
case 16: {
|
|
||||||
p.columns[0] = Vector4(attribs[i * component_count + 0], attribs[i * component_count + 1], attribs[i * component_count + 2], attribs[i * component_count + 3]);
|
|
||||||
p.columns[1] = Vector4(attribs[i * component_count + 4], attribs[i * component_count + 5], attribs[i * component_count + 6], attribs[i * component_count + 7]);
|
|
||||||
p.columns[2] = Vector4(attribs[i * component_count + 8], attribs[i * component_count + 9], attribs[i * component_count + 10], attribs[i * component_count + 11]);
|
|
||||||
p.columns[3] = Vector4(attribs[i * component_count + 12], attribs[i * component_count + 13], attribs[i * component_count + 14], attribs[i * component_count + 15]);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
ret.write[i] = p;
|
|
||||||
} break;
|
|
||||||
default: {
|
|
||||||
ERR_FAIL_V_MSG(ret, "glTF: Cannot decode accessor as Variant of type " + Variant::get_type_name(p_variant_type) + ".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
|
Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
|
||||||
|
|
@ -2095,7 +1512,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
|
||||||
int32_t orig_vertex_num = 0;
|
int32_t orig_vertex_num = 0;
|
||||||
ERR_FAIL_COND_V(!a.has("POSITION"), ERR_PARSE_ERROR);
|
ERR_FAIL_COND_V(!a.has("POSITION"), ERR_PARSE_ERROR);
|
||||||
if (a.has("POSITION")) {
|
if (a.has("POSITION")) {
|
||||||
PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION"], true);
|
PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION"]);
|
||||||
array[Mesh::ARRAY_VERTEX] = vertices;
|
array[Mesh::ARRAY_VERTEX] = vertices;
|
||||||
orig_vertex_num = vertices.size();
|
orig_vertex_num = vertices.size();
|
||||||
}
|
}
|
||||||
|
|
@ -2106,7 +1523,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
|
||||||
Vector<int> indices_rev_mapping;
|
Vector<int> indices_rev_mapping;
|
||||||
Vector<int> indices_vec4_mapping;
|
Vector<int> indices_vec4_mapping;
|
||||||
if (mesh_prim.has("indices")) {
|
if (mesh_prim.has("indices")) {
|
||||||
indices = _decode_accessor_as_ints(p_state, mesh_prim["indices"], false);
|
indices = _decode_accessor_as_int32s(p_state, mesh_prim["indices"]);
|
||||||
const int index_count = indices.size();
|
const int index_count = indices.size();
|
||||||
|
|
||||||
if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
|
if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
|
||||||
|
|
@ -2145,20 +1562,20 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
|
||||||
ERR_FAIL_COND_V(vertex_num <= 0, ERR_INVALID_DECLARATION);
|
ERR_FAIL_COND_V(vertex_num <= 0, ERR_INVALID_DECLARATION);
|
||||||
|
|
||||||
if (a.has("POSITION")) {
|
if (a.has("POSITION")) {
|
||||||
PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION"], true, indices_mapping);
|
PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION"], indices_mapping);
|
||||||
array[Mesh::ARRAY_VERTEX] = vertices;
|
array[Mesh::ARRAY_VERTEX] = vertices;
|
||||||
}
|
}
|
||||||
if (a.has("NORMAL")) {
|
if (a.has("NORMAL")) {
|
||||||
array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(p_state, a["NORMAL"], true, indices_mapping);
|
array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(p_state, a["NORMAL"], indices_mapping);
|
||||||
}
|
}
|
||||||
if (a.has("TANGENT")) {
|
if (a.has("TANGENT")) {
|
||||||
array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(p_state, a["TANGENT"], true, indices_vec4_mapping);
|
array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_float32s(p_state, a["TANGENT"], indices_vec4_mapping);
|
||||||
}
|
}
|
||||||
if (a.has("TEXCOORD_0")) {
|
if (a.has("TEXCOORD_0")) {
|
||||||
array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_0"], true, indices_mapping);
|
array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_0"], indices_mapping);
|
||||||
}
|
}
|
||||||
if (a.has("TEXCOORD_1")) {
|
if (a.has("TEXCOORD_1")) {
|
||||||
array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_1"], true, indices_mapping);
|
array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_1"], indices_mapping);
|
||||||
}
|
}
|
||||||
for (int custom_i = 0; custom_i < 3; custom_i++) {
|
for (int custom_i = 0; custom_i < 3; custom_i++) {
|
||||||
Vector<float> cur_custom;
|
Vector<float> cur_custom;
|
||||||
|
|
@ -2169,12 +1586,12 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
|
||||||
String gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i);
|
String gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i);
|
||||||
int num_channels = 0;
|
int num_channels = 0;
|
||||||
if (a.has(gltf_texcoord_key)) {
|
if (a.has(gltf_texcoord_key)) {
|
||||||
texcoord_first = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true, indices_mapping);
|
texcoord_first = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], indices_mapping);
|
||||||
num_channels = 2;
|
num_channels = 2;
|
||||||
}
|
}
|
||||||
gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i + 1);
|
gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i + 1);
|
||||||
if (a.has(gltf_texcoord_key)) {
|
if (a.has(gltf_texcoord_key)) {
|
||||||
texcoord_second = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true, indices_mapping);
|
texcoord_second = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], indices_mapping);
|
||||||
num_channels = 4;
|
num_channels = 4;
|
||||||
}
|
}
|
||||||
if (!num_channels) {
|
if (!num_channels) {
|
||||||
|
|
@ -2215,16 +1632,16 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (a.has("COLOR_0")) {
|
if (a.has("COLOR_0")) {
|
||||||
array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(p_state, a["COLOR_0"], true, indices_mapping);
|
array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(p_state, a["COLOR_0"], indices_mapping);
|
||||||
has_vertex_color = true;
|
has_vertex_color = true;
|
||||||
}
|
}
|
||||||
if (a.has("JOINTS_0") && !a.has("JOINTS_1")) {
|
if (a.has("JOINTS_0") && !a.has("JOINTS_1")) {
|
||||||
PackedInt32Array joints_0 = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true, indices_vec4_mapping);
|
PackedInt32Array joints_0 = _decode_accessor_as_int32s(p_state, a["JOINTS_0"], indices_vec4_mapping);
|
||||||
ERR_FAIL_COND_V(joints_0.size() != 4 * vertex_num, ERR_INVALID_DATA);
|
ERR_FAIL_COND_V(joints_0.size() != 4 * vertex_num, ERR_INVALID_DATA);
|
||||||
array[Mesh::ARRAY_BONES] = joints_0;
|
array[Mesh::ARRAY_BONES] = joints_0;
|
||||||
} else if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
|
} else if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
|
||||||
PackedInt32Array joints_0 = _decode_accessor_as_ints(p_state, a["JOINTS_0"], true, indices_vec4_mapping);
|
PackedInt32Array joints_0 = _decode_accessor_as_int32s(p_state, a["JOINTS_0"], indices_vec4_mapping);
|
||||||
PackedInt32Array joints_1 = _decode_accessor_as_ints(p_state, a["JOINTS_1"], true, indices_vec4_mapping);
|
PackedInt32Array joints_1 = _decode_accessor_as_int32s(p_state, a["JOINTS_1"], indices_vec4_mapping);
|
||||||
ERR_FAIL_COND_V(joints_0.size() != joints_1.size(), ERR_INVALID_DATA);
|
ERR_FAIL_COND_V(joints_0.size() != joints_1.size(), ERR_INVALID_DATA);
|
||||||
ERR_FAIL_COND_V(joints_0.size() != 4 * vertex_num, ERR_INVALID_DATA);
|
ERR_FAIL_COND_V(joints_0.size() != 4 * vertex_num, ERR_INVALID_DATA);
|
||||||
int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
|
int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
|
||||||
|
|
@ -2246,7 +1663,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
|
||||||
// ArrayMesh uses a flat array of either 4 or 8 floats per vertex.
|
// ArrayMesh uses a flat array of either 4 or 8 floats per vertex.
|
||||||
// Therefore, decode up to two glTF VEC4 arrays as float arrays.
|
// Therefore, decode up to two glTF VEC4 arrays as float arrays.
|
||||||
if (a.has("WEIGHTS_0") && !a.has("WEIGHTS_1")) {
|
if (a.has("WEIGHTS_0") && !a.has("WEIGHTS_1")) {
|
||||||
Vector<float> weights = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true, indices_vec4_mapping);
|
Vector<float> weights = _decode_accessor_as_float32s(p_state, a["WEIGHTS_0"], indices_vec4_mapping);
|
||||||
ERR_FAIL_COND_V(weights.size() != 4 * vertex_num, ERR_INVALID_DATA);
|
ERR_FAIL_COND_V(weights.size() != 4 * vertex_num, ERR_INVALID_DATA);
|
||||||
{ // glTF does not seem to normalize the weights for some reason.
|
{ // glTF does not seem to normalize the weights for some reason.
|
||||||
int wc = weights.size();
|
int wc = weights.size();
|
||||||
|
|
@ -2268,8 +1685,8 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
|
||||||
}
|
}
|
||||||
array[Mesh::ARRAY_WEIGHTS] = weights;
|
array[Mesh::ARRAY_WEIGHTS] = weights;
|
||||||
} else if (a.has("WEIGHTS_0") && a.has("WEIGHTS_1")) {
|
} else if (a.has("WEIGHTS_0") && a.has("WEIGHTS_1")) {
|
||||||
Vector<float> weights_0 = _decode_accessor_as_floats(p_state, a["WEIGHTS_0"], true, indices_vec4_mapping);
|
Vector<float> weights_0 = _decode_accessor_as_float32s(p_state, a["WEIGHTS_0"], indices_vec4_mapping);
|
||||||
Vector<float> weights_1 = _decode_accessor_as_floats(p_state, a["WEIGHTS_1"], true, indices_vec4_mapping);
|
Vector<float> weights_1 = _decode_accessor_as_float32s(p_state, a["WEIGHTS_1"], indices_vec4_mapping);
|
||||||
Vector<float> weights;
|
Vector<float> weights;
|
||||||
ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA);
|
ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA);
|
||||||
ERR_FAIL_COND_V(weights_0.size() != 4 * vertex_num, ERR_INVALID_DATA);
|
ERR_FAIL_COND_V(weights_0.size() != 4 * vertex_num, ERR_INVALID_DATA);
|
||||||
|
|
@ -2437,7 +1854,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t.has("POSITION")) {
|
if (t.has("POSITION")) {
|
||||||
Vector<Vector3> varr = _decode_accessor_as_vec3(p_state, t["POSITION"], true, indices_mapping);
|
Vector<Vector3> varr = _decode_accessor_as_vec3(p_state, t["POSITION"], indices_mapping);
|
||||||
const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
|
const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
|
||||||
const int size = src_varr.size();
|
const int size = src_varr.size();
|
||||||
ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
|
ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
|
||||||
|
|
@ -2459,7 +1876,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
|
||||||
array_copy[Mesh::ARRAY_VERTEX] = varr;
|
array_copy[Mesh::ARRAY_VERTEX] = varr;
|
||||||
}
|
}
|
||||||
if (t.has("NORMAL")) {
|
if (t.has("NORMAL")) {
|
||||||
Vector<Vector3> narr = _decode_accessor_as_vec3(p_state, t["NORMAL"], true, indices_mapping);
|
Vector<Vector3> narr = _decode_accessor_as_vec3(p_state, t["NORMAL"], indices_mapping);
|
||||||
const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL];
|
const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL];
|
||||||
int size = src_narr.size();
|
int size = src_narr.size();
|
||||||
ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
|
ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
|
||||||
|
|
@ -2481,7 +1898,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
|
||||||
array_copy[Mesh::ARRAY_NORMAL] = narr;
|
array_copy[Mesh::ARRAY_NORMAL] = narr;
|
||||||
}
|
}
|
||||||
if (t.has("TANGENT")) {
|
if (t.has("TANGENT")) {
|
||||||
const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(p_state, t["TANGENT"], true, indices_mapping);
|
const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(p_state, t["TANGENT"], indices_mapping);
|
||||||
const Vector<float> src_tangents = array[Mesh::ARRAY_TANGENT];
|
const Vector<float> src_tangents = array[Mesh::ARRAY_TANGENT];
|
||||||
ERR_FAIL_COND_V(src_tangents.is_empty(), ERR_PARSE_ERROR);
|
ERR_FAIL_COND_V(src_tangents.is_empty(), ERR_PARSE_ERROR);
|
||||||
|
|
||||||
|
|
@ -3908,8 +3325,10 @@ Error GLTFDocument::_parse_skins(Ref<GLTFState> p_state) {
|
||||||
const Array &joints = d["joints"];
|
const Array &joints = d["joints"];
|
||||||
|
|
||||||
if (d.has("inverseBindMatrices")) {
|
if (d.has("inverseBindMatrices")) {
|
||||||
skin->inverse_binds = _decode_accessor_as_xform(p_state, d["inverseBindMatrices"], false);
|
const GLTFAccessorIndex inv_bind_accessor_index = d["inverseBindMatrices"];
|
||||||
ERR_FAIL_COND_V(skin->inverse_binds.size() != joints.size(), ERR_PARSE_ERROR);
|
Array inv_binds_arr = _decode_accessor_as_variants(p_state, inv_bind_accessor_index, Variant::TRANSFORM3D);
|
||||||
|
ERR_FAIL_COND_V(inv_binds_arr.size() != joints.size(), ERR_PARSE_ERROR);
|
||||||
|
GLTFTemplateConvert::set_from_array(skin->inverse_binds, inv_binds_arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < joints.size(); j++) {
|
for (int j = 0; j < joints.size(); j++) {
|
||||||
|
|
@ -4424,7 +3843,7 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> p_state) {
|
||||||
output_count = 3;
|
output_count = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const Vector<double> times = _decode_accessor(p_state, input_time_accessor_index, false);
|
const PackedFloat64Array times = _decode_accessor_as_float64s(p_state, input_time_accessor_index);
|
||||||
// Parse target.
|
// Parse target.
|
||||||
const Dictionary &anim_target = anim_channel["target"];
|
const Dictionary &anim_target = anim_channel["target"];
|
||||||
ERR_FAIL_COND_V_MSG(!anim_target.has("path"), ERR_PARSE_ERROR, "glTF: Animation channel target missing required 'path' property.");
|
ERR_FAIL_COND_V_MSG(!anim_target.has("path"), ERR_PARSE_ERROR, "glTF: Animation channel target missing required 'path' property.");
|
||||||
|
|
@ -4457,22 +3876,22 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> p_state) {
|
||||||
track = &animation->get_node_tracks()[node];
|
track = &animation->get_node_tracks()[node];
|
||||||
|
|
||||||
if (path == "translation") {
|
if (path == "translation") {
|
||||||
const Vector<Vector3> positions = _decode_accessor_as_vec3(p_state, output_value_accessor_index, false);
|
const Vector<Vector3> positions = _decode_accessor_as_vec3(p_state, output_value_accessor_index);
|
||||||
track->position_track.interpolation = interp;
|
track->position_track.interpolation = interp;
|
||||||
track->position_track.times = times;
|
track->position_track.times = times;
|
||||||
track->position_track.values = positions;
|
track->position_track.values = positions;
|
||||||
} else if (path == "rotation") {
|
} else if (path == "rotation") {
|
||||||
const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(p_state, output_value_accessor_index, false);
|
const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(p_state, output_value_accessor_index);
|
||||||
track->rotation_track.interpolation = interp;
|
track->rotation_track.interpolation = interp;
|
||||||
track->rotation_track.times = times;
|
track->rotation_track.times = times;
|
||||||
track->rotation_track.values = rotations;
|
track->rotation_track.values = rotations;
|
||||||
} else if (path == "scale") {
|
} else if (path == "scale") {
|
||||||
const Vector<Vector3> scales = _decode_accessor_as_vec3(p_state, output_value_accessor_index, false);
|
const Vector<Vector3> scales = _decode_accessor_as_vec3(p_state, output_value_accessor_index);
|
||||||
track->scale_track.interpolation = interp;
|
track->scale_track.interpolation = interp;
|
||||||
track->scale_track.times = times;
|
track->scale_track.times = times;
|
||||||
track->scale_track.values = scales;
|
track->scale_track.values = scales;
|
||||||
} else if (path == "weights") {
|
} else if (path == "weights") {
|
||||||
const Vector<float> weights = _decode_accessor_as_floats(p_state, output_value_accessor_index, false);
|
const Vector<float> weights = _decode_accessor_as_float32s(p_state, output_value_accessor_index);
|
||||||
|
|
||||||
ERR_FAIL_INDEX_V(p_state->nodes[node]->mesh, p_state->meshes.size(), ERR_PARSE_ERROR);
|
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];
|
Ref<GLTFMesh> mesh = p_state->meshes[p_state->nodes[node]->mesh];
|
||||||
|
|
@ -4528,22 +3947,22 @@ void GLTFDocument::_parse_animation_pointer(Ref<GLTFState> p_state, const String
|
||||||
}
|
}
|
||||||
GLTFAnimation::NodeTrack *track = &node_tracks[node_index];
|
GLTFAnimation::NodeTrack *track = &node_tracks[node_index];
|
||||||
if (split[2] == "translation") {
|
if (split[2] == "translation") {
|
||||||
const Vector<Vector3> positions = _decode_accessor_as_vec3(p_state, p_output_value_accessor_index, false);
|
const Vector<Vector3> positions = _decode_accessor_as_vec3(p_state, p_output_value_accessor_index);
|
||||||
track->position_track.interpolation = p_interp;
|
track->position_track.interpolation = p_interp;
|
||||||
track->position_track.times = p_times;
|
track->position_track.times = p_times;
|
||||||
track->position_track.values = positions;
|
track->position_track.values = positions;
|
||||||
} else if (split[2] == "rotation") {
|
} else if (split[2] == "rotation") {
|
||||||
const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(p_state, p_output_value_accessor_index, false);
|
const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(p_state, p_output_value_accessor_index);
|
||||||
track->rotation_track.interpolation = p_interp;
|
track->rotation_track.interpolation = p_interp;
|
||||||
track->rotation_track.times = p_times;
|
track->rotation_track.times = p_times;
|
||||||
track->rotation_track.values = rotations;
|
track->rotation_track.values = rotations;
|
||||||
} else if (split[2] == "scale") {
|
} else if (split[2] == "scale") {
|
||||||
const Vector<Vector3> scales = _decode_accessor_as_vec3(p_state, p_output_value_accessor_index, false);
|
const Vector<Vector3> scales = _decode_accessor_as_vec3(p_state, p_output_value_accessor_index);
|
||||||
track->scale_track.interpolation = p_interp;
|
track->scale_track.interpolation = p_interp;
|
||||||
track->scale_track.times = p_times;
|
track->scale_track.times = p_times;
|
||||||
track->scale_track.values = scales;
|
track->scale_track.values = scales;
|
||||||
} else if (split[2] == "matrix") {
|
} else if (split[2] == "matrix") {
|
||||||
const Vector<Transform3D> transforms = _decode_accessor_as_xform(p_state, p_output_value_accessor_index, false);
|
Array transforms = _decode_accessor_as_variants(p_state, p_output_value_accessor_index, Variant::TRANSFORM3D);
|
||||||
track->position_track.interpolation = p_interp;
|
track->position_track.interpolation = p_interp;
|
||||||
track->position_track.times = p_times;
|
track->position_track.times = p_times;
|
||||||
track->position_track.values.resize(transforms.size());
|
track->position_track.values.resize(transforms.size());
|
||||||
|
|
@ -4554,12 +3973,13 @@ void GLTFDocument::_parse_animation_pointer(Ref<GLTFState> p_state, const String
|
||||||
track->scale_track.times = p_times;
|
track->scale_track.times = p_times;
|
||||||
track->scale_track.values.resize(transforms.size());
|
track->scale_track.values.resize(transforms.size());
|
||||||
for (int i = 0; i < transforms.size(); i++) {
|
for (int i = 0; i < transforms.size(); i++) {
|
||||||
track->position_track.values.write[i] = transforms[i].get_origin();
|
Transform3D transform = transforms[i];
|
||||||
track->rotation_track.values.write[i] = transforms[i].basis.get_rotation_quaternion();
|
track->position_track.values.write[i] = transform.get_origin();
|
||||||
track->scale_track.values.write[i] = transforms[i].basis.get_scale();
|
track->rotation_track.values.write[i] = transform.basis.get_rotation_quaternion();
|
||||||
|
track->scale_track.values.write[i] = transform.basis.get_scale();
|
||||||
}
|
}
|
||||||
} else { // if (split[2] == "weights")
|
} else { // if (split[2] == "weights")
|
||||||
const Vector<float> accessor_weights = _decode_accessor_as_floats(p_state, p_output_value_accessor_index, false);
|
const Vector<float> accessor_weights = _decode_accessor_as_float32s(p_state, p_output_value_accessor_index);
|
||||||
const GLTFMeshIndex mesh_index = p_state->nodes[node_index]->mesh;
|
const GLTFMeshIndex mesh_index = p_state->nodes[node_index]->mesh;
|
||||||
ERR_FAIL_INDEX(mesh_index, p_state->meshes.size());
|
ERR_FAIL_INDEX(mesh_index, p_state->meshes.size());
|
||||||
const Ref<GLTFMesh> gltf_mesh = p_state->meshes[mesh_index];
|
const Ref<GLTFMesh> gltf_mesh = p_state->meshes[mesh_index];
|
||||||
|
|
@ -4598,7 +4018,9 @@ void GLTFDocument::_parse_animation_pointer(Ref<GLTFState> p_state, const String
|
||||||
GLTFAnimation::Channel<Variant> channel;
|
GLTFAnimation::Channel<Variant> channel;
|
||||||
channel.interpolation = p_interp;
|
channel.interpolation = p_interp;
|
||||||
channel.times = p_times;
|
channel.times = p_times;
|
||||||
channel.values = _decode_accessor_as_variant(p_state, p_output_value_accessor_index, obj_model_prop->get_variant_type(), obj_model_prop->get_accessor_type());
|
Array values_arr = _decode_accessor_as_variants(p_state, p_output_value_accessor_index, obj_model_prop->get_variant_type());
|
||||||
|
// TODO: This can be made faster after this pull request is merged: https://github.com/godotengine/godot/pull/109003
|
||||||
|
GLTFTemplateConvert::set_from_array(channel.values, values_arr);
|
||||||
anim_ptr_map[p_animation_json_pointer] = channel;
|
anim_ptr_map[p_animation_json_pointer] = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,11 +108,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _build_parent_hierarchy(Ref<GLTFState> p_state);
|
void _build_parent_hierarchy(Ref<GLTFState> p_state);
|
||||||
String _get_component_type_name(const GLTFAccessor::GLTFComponentType p_component_type);
|
|
||||||
int _get_component_type_size(const GLTFAccessor::GLTFComponentType p_component_type);
|
|
||||||
Error _parse_scenes(Ref<GLTFState> p_state);
|
Error _parse_scenes(Ref<GLTFState> p_state);
|
||||||
Error _parse_nodes(Ref<GLTFState> p_state);
|
Error _parse_nodes(Ref<GLTFState> p_state);
|
||||||
String _get_accessor_type_name(const GLTFAccessor::GLTFAccessorType p_accessor_type);
|
|
||||||
String _sanitize_animation_name(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 _gen_unique_animation_name(Ref<GLTFState> p_state, const String &p_name);
|
||||||
String _sanitize_bone_name(const String &p_name);
|
String _sanitize_bone_name(const String &p_name);
|
||||||
|
|
@ -133,53 +130,16 @@ private:
|
||||||
Error _parse_buffers(Ref<GLTFState> p_state, const String &p_base_path);
|
Error _parse_buffers(Ref<GLTFState> p_state, const String &p_base_path);
|
||||||
Error _parse_buffer_views(Ref<GLTFState> p_state);
|
Error _parse_buffer_views(Ref<GLTFState> p_state);
|
||||||
Error _parse_accessors(Ref<GLTFState> p_state);
|
Error _parse_accessors(Ref<GLTFState> p_state);
|
||||||
Error _decode_buffer_view(Ref<GLTFState> p_state, double *p_dst,
|
template <typename T>
|
||||||
const GLTFBufferViewIndex p_buffer_view,
|
static T _decode_unpack_indexed_data(const T &p_source, const PackedInt32Array &p_indices);
|
||||||
const int64_t p_skip_every, const int64_t p_skip_bytes,
|
PackedFloat32Array _decode_accessor_as_float32s(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids = PackedInt32Array());
|
||||||
const int64_t p_element_size, const int64_t p_count,
|
PackedFloat64Array _decode_accessor_as_float64s(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids = PackedInt32Array());
|
||||||
const GLTFAccessor::GLTFAccessorType p_accessor_type, const int64_t p_component_count,
|
PackedInt32Array _decode_accessor_as_int32s(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids = PackedInt32Array());
|
||||||
const GLTFAccessor::GLTFComponentType p_component_type, const int64_t p_component_size,
|
PackedVector2Array _decode_accessor_as_vec2(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids = PackedInt32Array());
|
||||||
const bool p_normalized, const int64_t p_byte_offset,
|
PackedVector3Array _decode_accessor_as_vec3(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids = PackedInt32Array());
|
||||||
const bool p_for_vertex);
|
PackedColorArray _decode_accessor_as_color(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, const PackedInt32Array &p_packed_vertex_ids = PackedInt32Array());
|
||||||
Vector<double> _decode_accessor(Ref<GLTFState> p_state,
|
Vector<Quaternion> _decode_accessor_as_quaternion(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index);
|
||||||
const GLTFAccessorIndex p_accessor,
|
Array _decode_accessor_as_variants(const Ref<GLTFState> p_gltf_state, GLTFAccessorIndex p_accessor_index, Variant::Type p_variant_type);
|
||||||
const bool p_for_vertex);
|
|
||||||
Vector<float> _decode_accessor_as_floats(Ref<GLTFState> p_state,
|
|
||||||
const GLTFAccessorIndex p_accessor,
|
|
||||||
const bool p_for_vertex,
|
|
||||||
const Vector<int> &p_packed_vertex_ids = Vector<int>());
|
|
||||||
Vector<int> _decode_accessor_as_ints(Ref<GLTFState> p_state,
|
|
||||||
const GLTFAccessorIndex p_accessor,
|
|
||||||
const bool p_for_vertex,
|
|
||||||
const Vector<int> &p_packed_vertex_ids = Vector<int>());
|
|
||||||
Vector<Vector2> _decode_accessor_as_vec2(Ref<GLTFState> p_state,
|
|
||||||
const GLTFAccessorIndex p_accessor,
|
|
||||||
const bool p_for_vertex,
|
|
||||||
const Vector<int> &p_packed_vertex_ids = Vector<int>());
|
|
||||||
Vector<Vector3> _decode_accessor_as_vec3(Ref<GLTFState> p_state,
|
|
||||||
const GLTFAccessorIndex p_accessor,
|
|
||||||
const bool p_for_vertex,
|
|
||||||
const Vector<int> &p_packed_vertex_ids = Vector<int>());
|
|
||||||
Vector<Color> _decode_accessor_as_color(Ref<GLTFState> p_state,
|
|
||||||
const GLTFAccessorIndex p_accessor,
|
|
||||||
const bool p_for_vertex,
|
|
||||||
const Vector<int> &p_packed_vertex_ids = Vector<int>());
|
|
||||||
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> p_state,
|
|
||||||
const GLTFAccessorIndex p_accessor,
|
|
||||||
const bool p_for_vertex);
|
|
||||||
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> p_state,
|
|
||||||
const GLTFAccessorIndex p_accessor,
|
|
||||||
const bool p_for_vertex);
|
|
||||||
Vector<Variant> _decode_accessor_as_variant(Ref<GLTFState> p_state,
|
|
||||||
const GLTFAccessorIndex p_accessor,
|
|
||||||
Variant::Type p_variant_type,
|
|
||||||
GLTFAccessor::GLTFAccessorType p_accessor_type);
|
|
||||||
Error _parse_meshes(Ref<GLTFState> p_state);
|
Error _parse_meshes(Ref<GLTFState> p_state);
|
||||||
Error _serialize_textures(Ref<GLTFState> p_state);
|
Error _serialize_textures(Ref<GLTFState> p_state);
|
||||||
Error _serialize_texture_samplers(Ref<GLTFState> p_state);
|
Error _serialize_texture_samplers(Ref<GLTFState> p_state);
|
||||||
|
|
|
||||||
|
|
@ -443,6 +443,63 @@ int64_t GLTFAccessor::_get_vector_size() const {
|
||||||
ERR_FAIL_V(0);
|
ERR_FAIL_V(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t GLTFAccessor::_get_numbers_per_variant_for_gltf(Variant::Type p_variant_type) {
|
||||||
|
// Note that these numbers are used to determine the size of the glTF accessor appropriate for the type (see `_get_vector_size`).
|
||||||
|
// Therefore, the only valid values this can return are 1 (SCALAR), 2 (VEC2), 3 (VEC3), 4 (VEC4/MAT2), 9 (MAT3), and 16 (MAT4).
|
||||||
|
// The value 0 indicates the Variant type can't map to glTF accessors, and INT64_MAX indicates it needs special handling.
|
||||||
|
switch (p_variant_type) {
|
||||||
|
case Variant::NIL:
|
||||||
|
case Variant::STRING:
|
||||||
|
case Variant::STRING_NAME:
|
||||||
|
case Variant::NODE_PATH:
|
||||||
|
case Variant::RID:
|
||||||
|
case Variant::OBJECT:
|
||||||
|
case Variant::CALLABLE:
|
||||||
|
case Variant::SIGNAL:
|
||||||
|
case Variant::DICTIONARY:
|
||||||
|
case Variant::ARRAY:
|
||||||
|
case Variant::PACKED_STRING_ARRAY:
|
||||||
|
case Variant::PACKED_VECTOR2_ARRAY:
|
||||||
|
case Variant::PACKED_VECTOR3_ARRAY:
|
||||||
|
case Variant::PACKED_COLOR_ARRAY:
|
||||||
|
case Variant::PACKED_VECTOR4_ARRAY:
|
||||||
|
case Variant::VARIANT_MAX:
|
||||||
|
return 0; // Not supported.
|
||||||
|
case Variant::BOOL:
|
||||||
|
case Variant::INT:
|
||||||
|
case Variant::FLOAT:
|
||||||
|
return 1;
|
||||||
|
case Variant::VECTOR2:
|
||||||
|
case Variant::VECTOR2I:
|
||||||
|
return 2;
|
||||||
|
case Variant::VECTOR3:
|
||||||
|
case Variant::VECTOR3I:
|
||||||
|
return 3;
|
||||||
|
case Variant::RECT2:
|
||||||
|
case Variant::RECT2I:
|
||||||
|
case Variant::VECTOR4:
|
||||||
|
case Variant::VECTOR4I:
|
||||||
|
case Variant::PLANE:
|
||||||
|
case Variant::QUATERNION:
|
||||||
|
case Variant::COLOR:
|
||||||
|
return 4;
|
||||||
|
case Variant::TRANSFORM2D:
|
||||||
|
case Variant::AABB:
|
||||||
|
case Variant::BASIS:
|
||||||
|
return 9;
|
||||||
|
case Variant::TRANSFORM3D:
|
||||||
|
case Variant::PROJECTION:
|
||||||
|
return 16;
|
||||||
|
case Variant::PACKED_BYTE_ARRAY:
|
||||||
|
case Variant::PACKED_INT32_ARRAY:
|
||||||
|
case Variant::PACKED_INT64_ARRAY:
|
||||||
|
case Variant::PACKED_FLOAT32_ARRAY:
|
||||||
|
case Variant::PACKED_FLOAT64_ARRAY:
|
||||||
|
return INT64_MAX; // Special, use `_get_vector_size()` only to determine size.
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t GLTFAccessor::_get_bytes_per_component(const GLTFComponentType p_component_type) {
|
int64_t GLTFAccessor::_get_bytes_per_component(const GLTFComponentType p_component_type) {
|
||||||
switch (p_component_type) {
|
switch (p_component_type) {
|
||||||
case GLTFAccessor::COMPONENT_TYPE_NONE:
|
case GLTFAccessor::COMPONENT_TYPE_NONE:
|
||||||
|
|
@ -491,6 +548,546 @@ bool GLTFAccessor::is_equal_exact(const Ref<GLTFAccessor> &p_other) const {
|
||||||
sparse_values_byte_offset == p_other->sparse_values_byte_offset);
|
sparse_values_byte_offset == p_other->sparse_values_byte_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Private decode functions.
|
||||||
|
|
||||||
|
PackedInt64Array GLTFAccessor::_decode_sparse_indices(const Ref<GLTFState> &p_gltf_state, const TypedArray<GLTFBufferView> &p_buffer_views) const {
|
||||||
|
const int64_t bytes_per_component = _get_bytes_per_component(sparse_indices_component_type);
|
||||||
|
PackedInt64Array numbers;
|
||||||
|
ERR_FAIL_INDEX_V(sparse_indices_buffer_view, p_buffer_views.size(), numbers);
|
||||||
|
const Ref<GLTFBufferView> actual_buffer_view = p_buffer_views[sparse_indices_buffer_view];
|
||||||
|
const PackedByteArray raw_bytes = actual_buffer_view->load_buffer_view_data(p_gltf_state);
|
||||||
|
const int64_t min_raw_byte_size = bytes_per_component * sparse_count + sparse_indices_byte_offset;
|
||||||
|
ERR_FAIL_COND_V_MSG(raw_bytes.size() < min_raw_byte_size, numbers, "glTF import: Sparse indices buffer view did not have enough bytes to read the expected number of indices. Returning an empty array.");
|
||||||
|
numbers.resize(sparse_count);
|
||||||
|
const uint8_t *raw_pointer = raw_bytes.ptr();
|
||||||
|
int64_t raw_read_offset = sparse_indices_byte_offset;
|
||||||
|
for (int64_t i = 0; i < sparse_count; i++) {
|
||||||
|
const uint8_t *raw_source = &raw_pointer[raw_read_offset];
|
||||||
|
int64_t number = 0;
|
||||||
|
switch (sparse_indices_component_type) {
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_BYTE: {
|
||||||
|
number = *(uint8_t *)raw_source;
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_SHORT: {
|
||||||
|
number = *(uint16_t *)raw_source;
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_INT: {
|
||||||
|
number = *(uint32_t *)raw_source;
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_LONG: {
|
||||||
|
number = *(uint64_t *)raw_source;
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
ERR_FAIL_V_MSG(PackedInt64Array(), "glTF import: Sparse indices must have an unsigned integer component type. Failed to decode, returning an empty array.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numbers.set(i, number);
|
||||||
|
raw_read_offset += bytes_per_component;
|
||||||
|
}
|
||||||
|
ERR_FAIL_COND_V_MSG(raw_read_offset != raw_bytes.size(), numbers, "glTF import: Sparse indices buffer view size did not exactly match the expected size.");
|
||||||
|
return numbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> GLTFAccessor::_decode_raw_numbers(const Ref<GLTFState> &p_gltf_state, const TypedArray<GLTFBufferView> &p_buffer_views, bool p_sparse_values) const {
|
||||||
|
const int64_t bytes_per_component = _get_bytes_per_component(component_type);
|
||||||
|
const int64_t bytes_per_vector = _get_bytes_per_vector();
|
||||||
|
const int64_t vector_size = _get_vector_size();
|
||||||
|
int64_t pad_skip_every = 0;
|
||||||
|
int64_t pad_skip_bytes = 0;
|
||||||
|
_determine_pad_skip(pad_skip_every, pad_skip_bytes);
|
||||||
|
int64_t raw_vector_count;
|
||||||
|
int64_t raw_buffer_view_index;
|
||||||
|
int64_t raw_read_offset_start;
|
||||||
|
if (p_sparse_values) {
|
||||||
|
raw_vector_count = sparse_count;
|
||||||
|
raw_buffer_view_index = sparse_values_buffer_view;
|
||||||
|
raw_read_offset_start = sparse_values_byte_offset;
|
||||||
|
} else {
|
||||||
|
raw_vector_count = count;
|
||||||
|
raw_buffer_view_index = buffer_view;
|
||||||
|
raw_read_offset_start = byte_offset;
|
||||||
|
}
|
||||||
|
const int64_t raw_number_count = raw_vector_count * vector_size;
|
||||||
|
Vector<T> ret_numbers;
|
||||||
|
if (raw_buffer_view_index == -1) {
|
||||||
|
ret_numbers.resize(raw_number_count);
|
||||||
|
// No buffer view, so fill with zeros.
|
||||||
|
for (int64_t i = 0; i < raw_number_count; i++) {
|
||||||
|
ret_numbers.set(i, T(0));
|
||||||
|
}
|
||||||
|
return ret_numbers;
|
||||||
|
}
|
||||||
|
ERR_FAIL_INDEX_V(raw_buffer_view_index, p_buffer_views.size(), ret_numbers);
|
||||||
|
const Ref<GLTFBufferView> raw_buffer_view = p_buffer_views[raw_buffer_view_index];
|
||||||
|
if (raw_buffer_view->get_byte_offset() % bytes_per_component != 0) {
|
||||||
|
WARN_PRINT("glTF import: Buffer view byte offset is not a multiple of accessor component size. This file is invalid per the glTF specification and will not load correctly in some glTF viewers, but Godot will try to load it anyway.");
|
||||||
|
}
|
||||||
|
if (byte_offset % bytes_per_component != 0) {
|
||||||
|
WARN_PRINT("glTF import: Accessor byte offset is not a multiple of accessor component size. This file is invalid per the glTF specification and will not load correctly in some glTF viewers, but Godot will try to load it anyway.");
|
||||||
|
}
|
||||||
|
int64_t declared_byte_stride = raw_buffer_view->get_byte_stride();
|
||||||
|
int64_t actual_byte_stride = bytes_per_vector;
|
||||||
|
int64_t stride_skip_every = 0;
|
||||||
|
int64_t stride_skip_bytes = 0;
|
||||||
|
if (declared_byte_stride != -1) {
|
||||||
|
ERR_FAIL_COND_V_MSG(declared_byte_stride % 4 != 0, ret_numbers, "glTF import: The declared buffer view byte stride " + itos(declared_byte_stride) + " was not a multiple of 4 as required by glTF. Returning an empty array.");
|
||||||
|
if (declared_byte_stride > bytes_per_vector) {
|
||||||
|
actual_byte_stride = declared_byte_stride;
|
||||||
|
stride_skip_every = vector_size;
|
||||||
|
stride_skip_bytes = declared_byte_stride - bytes_per_vector;
|
||||||
|
}
|
||||||
|
} else if (raw_buffer_view->get_vertex_attributes()) {
|
||||||
|
print_verbose("WARNING: glTF import: Buffer view byte stride should be declared for vertex attributes. Assuming packed data and reading anyway.");
|
||||||
|
}
|
||||||
|
const int64_t min_raw_byte_size = actual_byte_stride * (raw_vector_count - 1) + bytes_per_vector + raw_read_offset_start;
|
||||||
|
const PackedByteArray raw_bytes = raw_buffer_view->load_buffer_view_data(p_gltf_state);
|
||||||
|
ERR_FAIL_COND_V_MSG(raw_bytes.size() < min_raw_byte_size, ret_numbers, "glTF import: The buffer view size was smaller than the minimum required size for the accessor. Returning an empty array.");
|
||||||
|
ret_numbers.resize(raw_number_count);
|
||||||
|
const uint8_t *raw_pointer = raw_bytes.ptr();
|
||||||
|
int64_t raw_read_offset = raw_read_offset_start;
|
||||||
|
for (int64_t i = 0; i < raw_number_count; i++) {
|
||||||
|
const uint8_t *raw_source = &raw_pointer[raw_read_offset];
|
||||||
|
T number = 0;
|
||||||
|
// 3.11. Implementations MUST use following equations to decode real floating-point value f from a normalized integer c and vice-versa.
|
||||||
|
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#animations
|
||||||
|
switch (component_type) {
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_NONE: {
|
||||||
|
ERR_FAIL_V_MSG(Vector<T>(), "glTF import: Failed to decode buffer view, component type not set. Returning an empty array.");
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_SIGNED_BYTE: {
|
||||||
|
int8_t prim = *(int8_t *)raw_source;
|
||||||
|
if (normalized) {
|
||||||
|
number = T(MAX(double(prim) / 127.0, -1.0));
|
||||||
|
} else {
|
||||||
|
number = T(prim);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_BYTE: {
|
||||||
|
uint8_t prim = *(uint8_t *)raw_source;
|
||||||
|
if (normalized) {
|
||||||
|
number = T((double(prim) / 255.0));
|
||||||
|
} else {
|
||||||
|
number = T(prim);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_SIGNED_SHORT: {
|
||||||
|
int16_t prim = *(int16_t *)raw_source;
|
||||||
|
if (normalized) {
|
||||||
|
number = T(MAX(double(prim) / 32767.0, -1.0));
|
||||||
|
} else {
|
||||||
|
number = T(prim);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_SHORT: {
|
||||||
|
uint16_t prim = *(uint16_t *)raw_source;
|
||||||
|
if (normalized) {
|
||||||
|
number = T(double(prim) / 65535.0);
|
||||||
|
} else {
|
||||||
|
number = T(prim);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_SIGNED_INT: {
|
||||||
|
number = T(*(int32_t *)raw_source);
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_INT: {
|
||||||
|
number = T(*(uint32_t *)raw_source);
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_SINGLE_FLOAT: {
|
||||||
|
number = T(*(float *)raw_source);
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_DOUBLE_FLOAT: {
|
||||||
|
number = T(*(double *)raw_source);
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_HALF_FLOAT: {
|
||||||
|
number = Math::half_to_float(*(uint16_t *)raw_source);
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_SIGNED_LONG: {
|
||||||
|
number = T(*(int64_t *)raw_source);
|
||||||
|
} break;
|
||||||
|
case GLTFAccessor::COMPONENT_TYPE_UNSIGNED_LONG: {
|
||||||
|
number = T(*(uint64_t *)raw_source);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
ret_numbers.set(i, number);
|
||||||
|
raw_read_offset += bytes_per_component;
|
||||||
|
// Padding and stride skipping are distinct concepts that both need to be handled.
|
||||||
|
// For example, a 2-in-1 interleaved MAT3 bytes accessor has both, and would look like:
|
||||||
|
// AAA0 AAA0 AAA0 BBB0 BBB0 BBB0 AAA0 AAA0 AAA0 BBB0 BBB0 BBB0
|
||||||
|
// The "0" is skipped by the padding, and the "BBB0" is skipped by the stride.
|
||||||
|
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#data-alignment
|
||||||
|
if (unlikely(pad_skip_every > 0)) {
|
||||||
|
if ((i + 1) % pad_skip_every == 0) {
|
||||||
|
raw_read_offset += pad_skip_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unlikely(stride_skip_every > 0)) {
|
||||||
|
if ((i + 1) % stride_skip_every == 0) {
|
||||||
|
raw_read_offset += stride_skip_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret_numbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> GLTFAccessor::_decode_as_numbers(const Ref<GLTFState> &p_gltf_state) const {
|
||||||
|
const TypedArray<GLTFBufferView> &p_buffer_views = p_gltf_state->get_buffer_views();
|
||||||
|
Vector<T> ret_numbers = _decode_raw_numbers<T>(p_gltf_state, p_buffer_views, false);
|
||||||
|
if (sparse_count == 0) {
|
||||||
|
return ret_numbers;
|
||||||
|
}
|
||||||
|
// Handle sparse accessors.
|
||||||
|
PackedInt64Array sparse_indices = _decode_sparse_indices(p_gltf_state, p_buffer_views);
|
||||||
|
ERR_FAIL_COND_V_MSG(sparse_indices.size() != sparse_count, ret_numbers, "glTF import: Sparse indices size does not match the sparse count.");
|
||||||
|
const int64_t vector_size = _get_vector_size();
|
||||||
|
Vector<T> sparse_values = _decode_raw_numbers<T>(p_gltf_state, p_buffer_views, true);
|
||||||
|
ERR_FAIL_COND_V_MSG(sparse_values.size() != sparse_count * vector_size, ret_numbers, "glTF import: Sparse values size does not match the sparse count.");
|
||||||
|
for (int64_t in_sparse = 0; in_sparse < sparse_count; in_sparse++) {
|
||||||
|
const int64_t sparse_index = sparse_indices[in_sparse];
|
||||||
|
const int64_t array_offset = sparse_index * vector_size;
|
||||||
|
ERR_FAIL_INDEX_V_MSG(array_offset, ret_numbers.size(), ret_numbers, "glTF import: Sparse indices were out of bounds for the accessor.");
|
||||||
|
for (int64_t in_vec = 0; in_vec < vector_size; in_vec++) {
|
||||||
|
ret_numbers.set(array_offset + in_vec, sparse_values[in_sparse * vector_size + in_vec]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret_numbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// High-level decode functions.
|
||||||
|
|
||||||
|
PackedColorArray GLTFAccessor::decode_as_colors(const Ref<GLTFState> &p_gltf_state) const {
|
||||||
|
PackedColorArray ret;
|
||||||
|
PackedFloat32Array numbers = _decode_as_numbers<float>(p_gltf_state);
|
||||||
|
if (accessor_type == TYPE_VEC3) {
|
||||||
|
ERR_FAIL_COND_V_MSG(numbers.size() != count * 3, ret, "glTF import: The accessor does not have the expected amount of numbers for the given count and vector size.");
|
||||||
|
ret.resize(count);
|
||||||
|
for (int64_t i = 0; i < count; i++) {
|
||||||
|
const int64_t number_index = i * 3;
|
||||||
|
ret.set(i, Color(numbers[number_index], numbers[number_index + 1], numbers[number_index + 2], 1.0f));
|
||||||
|
}
|
||||||
|
} else if (accessor_type == TYPE_VEC4) {
|
||||||
|
ERR_FAIL_COND_V_MSG(numbers.size() != count * 4, ret, "glTF import: The accessor does not have the expected amount of numbers for the given count and vector size.");
|
||||||
|
ret.resize(count);
|
||||||
|
for (int64_t i = 0; i < count; i++) {
|
||||||
|
const int64_t number_index = i * 4;
|
||||||
|
ret.set(i, Color(numbers[number_index], numbers[number_index + 1], numbers[number_index + 2], numbers[number_index + 3]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ERR_FAIL_V_MSG(ret, "glTF import: The `decode_as_colors` function is designed to be fast and can only be used with accessors of type \"VEC3\" or \"VEC4\", but was called with type \"" + _get_accessor_type_name() + "\". Consider using `decode_as_variants` if you need more flexible behavior with support for any accessor type.");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackedFloat32Array GLTFAccessor::decode_as_float32s(const Ref<GLTFState> &p_gltf_state) const {
|
||||||
|
return _decode_as_numbers<float>(p_gltf_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
PackedFloat64Array GLTFAccessor::decode_as_float64s(const Ref<GLTFState> &p_gltf_state) const {
|
||||||
|
return _decode_as_numbers<double>(p_gltf_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
PackedInt32Array GLTFAccessor::decode_as_int32s(const Ref<GLTFState> &p_gltf_state) const {
|
||||||
|
return _decode_as_numbers<int32_t>(p_gltf_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
PackedInt64Array GLTFAccessor::decode_as_int64s(const Ref<GLTFState> &p_gltf_state) const {
|
||||||
|
return _decode_as_numbers<int64_t>(p_gltf_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Quaternion> GLTFAccessor::decode_as_quaternions(const Ref<GLTFState> &p_gltf_state) const {
|
||||||
|
Vector<Quaternion> ret;
|
||||||
|
ERR_FAIL_COND_V_MSG(accessor_type != TYPE_VEC4, ret, "glTF import: The `decode_as_quaternions` function is designed to be fast and can only be used with accessors of type \"VEC4\", but was called with type \"" + _get_accessor_type_name() + "\". Consider using `decode_as_variants` if you need more flexible behavior with support for any accessor type.");
|
||||||
|
PackedRealArray numbers = _decode_as_numbers<real_t>(p_gltf_state);
|
||||||
|
ERR_FAIL_COND_V_MSG(numbers.size() != count * 4, ret, "glTF import: The accessor does not have the expected amount of numbers for the given count and vector size.");
|
||||||
|
ret.resize(count);
|
||||||
|
for (int64_t i = 0; i < count; i++) {
|
||||||
|
const int64_t number_index = i * 4;
|
||||||
|
ret.set(i, Quaternion(numbers[number_index], numbers[number_index + 1], numbers[number_index + 2], numbers[number_index + 3]).normalized());
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Array GLTFAccessor::decode_as_variants(const Ref<GLTFState> &p_gltf_state, Variant::Type p_variant_type) const {
|
||||||
|
const int64_t numbers_per_variant = _get_numbers_per_variant_for_gltf(p_variant_type);
|
||||||
|
Array ret;
|
||||||
|
ERR_FAIL_COND_V_MSG(numbers_per_variant < 1, ret, "glTF import: The Variant type '" + Variant::get_type_name(p_variant_type) + "' is not supported. Returning an empty array.");
|
||||||
|
const PackedFloat64Array numbers = _decode_as_numbers<double>(p_gltf_state);
|
||||||
|
const int64_t vector_size = _get_vector_size();
|
||||||
|
ERR_FAIL_COND_V_MSG(vector_size < 1, ret, "glTF import: The accessor type '" + _get_accessor_type_name() + "' is not supported. Returning an empty array.");
|
||||||
|
const int64_t numbers_to_read = MIN(vector_size, numbers_per_variant);
|
||||||
|
ERR_FAIL_COND_V_MSG(numbers.size() != count * vector_size, ret, "glTF import: The accessor does not have the expected amount of numbers for the given count and vector size.");
|
||||||
|
ret.resize(count);
|
||||||
|
for (int64_t value_index = 0; value_index < count; value_index++) {
|
||||||
|
const int64_t number_index = value_index * vector_size;
|
||||||
|
switch (p_variant_type) {
|
||||||
|
case Variant::BOOL: {
|
||||||
|
ret[value_index] = numbers[number_index] != 0.0;
|
||||||
|
} break;
|
||||||
|
case Variant::INT: {
|
||||||
|
ret[value_index] = (int64_t)numbers[number_index];
|
||||||
|
} break;
|
||||||
|
case Variant::FLOAT: {
|
||||||
|
ret[value_index] = numbers[number_index];
|
||||||
|
} break;
|
||||||
|
case Variant::VECTOR2:
|
||||||
|
case Variant::RECT2:
|
||||||
|
case Variant::VECTOR3:
|
||||||
|
case Variant::VECTOR4:
|
||||||
|
case Variant::PLANE:
|
||||||
|
case Variant::QUATERNION: {
|
||||||
|
// General-purpose code for importing glTF accessor data with any component count into structs up to 4 `real_t`s in size.
|
||||||
|
Vector4 vec;
|
||||||
|
switch (numbers_to_read) {
|
||||||
|
case 1: {
|
||||||
|
vec = Vector4(numbers[number_index], 0.0f, 0.0f, 0.0f);
|
||||||
|
} break;
|
||||||
|
case 2: {
|
||||||
|
vec = Vector4(numbers[number_index], numbers[number_index + 1], 0.0f, 0.0f);
|
||||||
|
} break;
|
||||||
|
case 3: {
|
||||||
|
vec = Vector4(numbers[number_index], numbers[number_index + 1], numbers[number_index + 2], 0.0f);
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
vec = Vector4(numbers[number_index], numbers[number_index + 1], numbers[number_index + 2], numbers[number_index + 3]);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
if (p_variant_type == Variant::QUATERNION) {
|
||||||
|
vec.normalize();
|
||||||
|
}
|
||||||
|
// Evil hack that relies on the structure of Variant, but it's the
|
||||||
|
// only way to accomplish this without a ton of code duplication.
|
||||||
|
Variant variant = vec;
|
||||||
|
*(Variant::Type *)&variant = p_variant_type;
|
||||||
|
ret[value_index] = variant;
|
||||||
|
} break;
|
||||||
|
case Variant::VECTOR2I:
|
||||||
|
case Variant::RECT2I:
|
||||||
|
case Variant::VECTOR3I:
|
||||||
|
case Variant::VECTOR4I: {
|
||||||
|
// General-purpose code for importing glTF accessor data with any component count into structs up to 4 `int32_t`s in size.
|
||||||
|
Vector4i vec;
|
||||||
|
switch (numbers_to_read) {
|
||||||
|
case 1: {
|
||||||
|
vec = Vector4i((int32_t)numbers[number_index], 0, 0, 0);
|
||||||
|
} break;
|
||||||
|
case 2: {
|
||||||
|
vec = Vector4i((int32_t)numbers[number_index], (int32_t)numbers[number_index + 1], 0, 0);
|
||||||
|
} break;
|
||||||
|
case 3: {
|
||||||
|
vec = Vector4i((int32_t)numbers[number_index], (int32_t)numbers[number_index + 1], (int32_t)numbers[number_index + 2], 0);
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
vec = Vector4i((int32_t)numbers[number_index], (int32_t)numbers[number_index + 1], (int32_t)numbers[number_index + 2], (int32_t)numbers[number_index + 3]);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
// Evil hack that relies on the structure of Variant, but it's the
|
||||||
|
// only way to accomplish this without a ton of code duplication.
|
||||||
|
Variant variant = vec;
|
||||||
|
*(Variant::Type *)&variant = p_variant_type;
|
||||||
|
ret[value_index] = variant;
|
||||||
|
} break;
|
||||||
|
// No more generalized hacks, each of the below types needs a lot of repetitive code.
|
||||||
|
case Variant::COLOR: {
|
||||||
|
Color color;
|
||||||
|
switch (numbers_to_read) {
|
||||||
|
case 1: {
|
||||||
|
color = Color(numbers[number_index], 0.0f, 0.0f, 1.0f);
|
||||||
|
} break;
|
||||||
|
case 2: {
|
||||||
|
color = Color(numbers[number_index], numbers[number_index + 1], 0.0f, 1.0f);
|
||||||
|
} break;
|
||||||
|
case 3: {
|
||||||
|
color = Color(numbers[number_index], numbers[number_index + 1], numbers[number_index + 2], 1.0f);
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
color = Color(numbers[number_index], numbers[number_index + 1], numbers[number_index + 2], numbers[number_index + 3]);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
ret[value_index] = color;
|
||||||
|
} break;
|
||||||
|
case Variant::TRANSFORM2D: {
|
||||||
|
Transform2D t;
|
||||||
|
switch (numbers_to_read) {
|
||||||
|
case 4: {
|
||||||
|
t.columns[0] = Vector2(numbers[number_index + 0], numbers[number_index + 1]);
|
||||||
|
t.columns[1] = Vector2(numbers[number_index + 2], numbers[number_index + 3]);
|
||||||
|
} break;
|
||||||
|
case 9: {
|
||||||
|
t.columns[0] = Vector2(numbers[number_index + 0], numbers[number_index + 1]);
|
||||||
|
t.columns[1] = Vector2(numbers[number_index + 3], numbers[number_index + 4]);
|
||||||
|
t.columns[2] = Vector2(numbers[number_index + 6], numbers[number_index + 7]);
|
||||||
|
} break;
|
||||||
|
case 16: {
|
||||||
|
t.columns[0] = Vector2(numbers[number_index + 0], numbers[number_index + 1]);
|
||||||
|
t.columns[1] = Vector2(numbers[number_index + 4], numbers[number_index + 5]);
|
||||||
|
t.columns[2] = Vector2(numbers[number_index + 12], numbers[number_index + 13]);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
ret[value_index] = t;
|
||||||
|
} break;
|
||||||
|
case Variant::AABB: {
|
||||||
|
AABB aabb;
|
||||||
|
switch (numbers_to_read) {
|
||||||
|
case 4: {
|
||||||
|
aabb.position = Vector3(numbers[number_index + 0], numbers[number_index + 1], 0.0f);
|
||||||
|
aabb.size = Vector3(numbers[number_index + 2], numbers[number_index + 3], 0.0f);
|
||||||
|
} break;
|
||||||
|
case 9: {
|
||||||
|
aabb.position = Vector3(numbers[number_index + 0], numbers[number_index + 1], numbers[number_index + 2]);
|
||||||
|
aabb.size = Vector3(numbers[number_index + 3], numbers[number_index + 4], numbers[number_index + 5]);
|
||||||
|
} break;
|
||||||
|
case 16: {
|
||||||
|
aabb.position = Vector3(numbers[number_index + 0], numbers[number_index + 1], numbers[number_index + 2]);
|
||||||
|
aabb.size = Vector3(numbers[number_index + 4], numbers[number_index + 5], numbers[number_index + 6]);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
ret[value_index] = aabb;
|
||||||
|
} break;
|
||||||
|
case Variant::BASIS: {
|
||||||
|
Basis b;
|
||||||
|
switch (numbers_to_read) {
|
||||||
|
case 4: {
|
||||||
|
b.rows[0] = Vector3(numbers[number_index + 0], numbers[number_index + 2], 0.0f);
|
||||||
|
b.rows[1] = Vector3(numbers[number_index + 1], numbers[number_index + 3], 0.0f);
|
||||||
|
} break;
|
||||||
|
case 9: {
|
||||||
|
b.rows[0] = Vector3(numbers[number_index + 0], numbers[number_index + 3], numbers[number_index + 6]);
|
||||||
|
b.rows[1] = Vector3(numbers[number_index + 1], numbers[number_index + 4], numbers[number_index + 7]);
|
||||||
|
b.rows[2] = Vector3(numbers[number_index + 2], numbers[number_index + 5], numbers[number_index + 8]);
|
||||||
|
} break;
|
||||||
|
case 16: {
|
||||||
|
b.rows[0] = Vector3(numbers[number_index + 0], numbers[number_index + 4], numbers[number_index + 8]);
|
||||||
|
b.rows[1] = Vector3(numbers[number_index + 1], numbers[number_index + 5], numbers[number_index + 9]);
|
||||||
|
b.rows[2] = Vector3(numbers[number_index + 2], numbers[number_index + 6], numbers[number_index + 10]);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
ret[value_index] = b;
|
||||||
|
} break;
|
||||||
|
case Variant::TRANSFORM3D: {
|
||||||
|
Transform3D t;
|
||||||
|
switch (numbers_to_read) {
|
||||||
|
case 4: {
|
||||||
|
t.basis.rows[0] = Vector3(numbers[number_index + 0], numbers[number_index + 2], 0.0f);
|
||||||
|
t.basis.rows[1] = Vector3(numbers[number_index + 1], numbers[number_index + 3], 0.0f);
|
||||||
|
} break;
|
||||||
|
case 9: {
|
||||||
|
t.basis.rows[0] = Vector3(numbers[number_index + 0], numbers[number_index + 3], numbers[number_index + 6]);
|
||||||
|
t.basis.rows[1] = Vector3(numbers[number_index + 1], numbers[number_index + 4], numbers[number_index + 7]);
|
||||||
|
t.basis.rows[2] = Vector3(numbers[number_index + 2], numbers[number_index + 5], numbers[number_index + 8]);
|
||||||
|
} break;
|
||||||
|
case 16: {
|
||||||
|
t.basis.rows[0] = Vector3(numbers[number_index + 0], numbers[number_index + 4], numbers[number_index + 8]);
|
||||||
|
t.basis.rows[1] = Vector3(numbers[number_index + 1], numbers[number_index + 5], numbers[number_index + 9]);
|
||||||
|
t.basis.rows[2] = Vector3(numbers[number_index + 2], numbers[number_index + 6], numbers[number_index + 10]);
|
||||||
|
t.origin = Vector3(numbers[number_index + 12], numbers[number_index + 13], numbers[number_index + 14]);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
ret[value_index] = t;
|
||||||
|
} break;
|
||||||
|
case Variant::PROJECTION: {
|
||||||
|
Projection p;
|
||||||
|
switch (numbers_to_read) {
|
||||||
|
case 4: {
|
||||||
|
p.columns[0] = Vector4(numbers[number_index + 0], numbers[number_index + 1], 0.0f, 0.0f);
|
||||||
|
p.columns[1] = Vector4(numbers[number_index + 4], numbers[number_index + 5], 0.0f, 0.0f);
|
||||||
|
} break;
|
||||||
|
case 9: {
|
||||||
|
p.columns[0] = Vector4(numbers[number_index + 0], numbers[number_index + 1], numbers[number_index + 2], 0.0f);
|
||||||
|
p.columns[1] = Vector4(numbers[number_index + 4], numbers[number_index + 5], numbers[number_index + 6], 0.0f);
|
||||||
|
p.columns[2] = Vector4(numbers[number_index + 8], numbers[number_index + 9], numbers[number_index + 10], 0.0f);
|
||||||
|
} break;
|
||||||
|
case 16: {
|
||||||
|
p.columns[0] = Vector4(numbers[number_index + 0], numbers[number_index + 1], numbers[number_index + 2], numbers[number_index + 3]);
|
||||||
|
p.columns[1] = Vector4(numbers[number_index + 4], numbers[number_index + 5], numbers[number_index + 6], numbers[number_index + 7]);
|
||||||
|
p.columns[2] = Vector4(numbers[number_index + 8], numbers[number_index + 9], numbers[number_index + 10], numbers[number_index + 11]);
|
||||||
|
p.columns[3] = Vector4(numbers[number_index + 12], numbers[number_index + 13], numbers[number_index + 14], numbers[number_index + 15]);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
ret[value_index] = p;
|
||||||
|
} break;
|
||||||
|
case Variant::PACKED_BYTE_ARRAY: {
|
||||||
|
PackedByteArray packed_array;
|
||||||
|
packed_array.resize(numbers_to_read);
|
||||||
|
for (int64_t j = 0; j < numbers_to_read; j++) {
|
||||||
|
packed_array.set(value_index, numbers[number_index + j]);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Variant::PACKED_INT32_ARRAY: {
|
||||||
|
PackedInt32Array packed_array;
|
||||||
|
packed_array.resize(numbers_to_read);
|
||||||
|
for (int64_t j = 0; j < numbers_to_read; j++) {
|
||||||
|
packed_array.set(value_index, numbers[number_index + j]);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Variant::PACKED_INT64_ARRAY: {
|
||||||
|
PackedInt64Array packed_array;
|
||||||
|
packed_array.resize(numbers_to_read);
|
||||||
|
for (int64_t j = 0; j < numbers_to_read; j++) {
|
||||||
|
packed_array.set(value_index, numbers[number_index + j]);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Variant::PACKED_FLOAT32_ARRAY: {
|
||||||
|
PackedFloat32Array packed_array;
|
||||||
|
packed_array.resize(numbers_to_read);
|
||||||
|
for (int64_t j = 0; j < numbers_to_read; j++) {
|
||||||
|
packed_array.set(value_index, numbers[number_index + j]);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Variant::PACKED_FLOAT64_ARRAY: {
|
||||||
|
PackedFloat64Array packed_array;
|
||||||
|
packed_array.resize(numbers_to_read);
|
||||||
|
for (int64_t j = 0; j < numbers_to_read; j++) {
|
||||||
|
packed_array.set(value_index, numbers[number_index + j]);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
ERR_FAIL_V_MSG(ret, "glTF: Cannot decode accessor as Variant of type " + Variant::get_type_name(p_variant_type) + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackedVector2Array GLTFAccessor::decode_as_vector2s(const Ref<GLTFState> &p_gltf_state) const {
|
||||||
|
PackedVector2Array ret;
|
||||||
|
ERR_FAIL_COND_V_MSG(accessor_type != TYPE_VEC2, ret, "glTF import: The `decode_as_vector2s` function is designed to be fast and can only be used with accessors of type \"VEC2\", but was called with type \"" + _get_accessor_type_name() + "\". Consider using `decode_as_variants` if you need more flexible behavior with support for any accessor type.");
|
||||||
|
PackedRealArray numbers = _decode_as_numbers<real_t>(p_gltf_state);
|
||||||
|
ERR_FAIL_COND_V_MSG(numbers.size() != count * 2, ret, "glTF import: The accessor does not have the expected amount of numbers for the given count and vector size.");
|
||||||
|
ret.resize(count);
|
||||||
|
for (int64_t i = 0; i < count; i++) {
|
||||||
|
const int64_t number_index = i * 2;
|
||||||
|
ret.set(i, Vector2(numbers[number_index], numbers[number_index + 1]));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackedVector3Array GLTFAccessor::decode_as_vector3s(const Ref<GLTFState> &p_gltf_state) const {
|
||||||
|
PackedVector3Array ret;
|
||||||
|
ERR_FAIL_COND_V_MSG(accessor_type != TYPE_VEC3, ret, "glTF import: The `decode_as_vector3s` function is designed to be fast and can only be used with accessors of type \"VEC3\", but was called with type \"" + _get_accessor_type_name() + "\". Consider using `decode_as_variants` if you need more flexible behavior with support for any accessor type.");
|
||||||
|
PackedRealArray numbers = _decode_as_numbers<real_t>(p_gltf_state);
|
||||||
|
ERR_FAIL_COND_V_MSG(numbers.size() != count * 3, ret, "glTF import: The accessor does not have the expected amount of numbers for the given count and vector size.");
|
||||||
|
ret.resize(count);
|
||||||
|
for (int64_t i = 0; i < count; i++) {
|
||||||
|
const int64_t number_index = i * 3;
|
||||||
|
ret.set(i, Vector3(numbers[number_index], numbers[number_index + 1], numbers[number_index + 2]));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackedVector4Array GLTFAccessor::decode_as_vector4s(const Ref<GLTFState> &p_gltf_state) const {
|
||||||
|
PackedVector4Array ret;
|
||||||
|
ERR_FAIL_COND_V_MSG(accessor_type != TYPE_VEC4, ret, "glTF import: The `decode_as_vector4s` function is designed to be fast and can only be used with accessors of type \"VEC4\", but was called with type \"" + _get_accessor_type_name() + "\". Consider using `decode_as_variants` if you need more flexible behavior with support for any accessor type.");
|
||||||
|
PackedRealArray numbers = _decode_as_numbers<real_t>(p_gltf_state);
|
||||||
|
ERR_FAIL_COND_V_MSG(numbers.size() != count * 4, ret, "glTF import: The accessor does not have the expected amount of numbers for the given count and vector size.");
|
||||||
|
ret.resize(count);
|
||||||
|
for (int64_t i = 0; i < count; i++) {
|
||||||
|
const int64_t number_index = i * 4;
|
||||||
|
ret.set(i, Vector4(numbers[number_index], numbers[number_index + 1], numbers[number_index + 2], numbers[number_index + 3]));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// Private encode functions.
|
// Private encode functions.
|
||||||
|
|
||||||
PackedFloat64Array GLTFAccessor::_encode_variants_as_floats(const Array &p_input_data, Variant::Type p_variant_type) const {
|
PackedFloat64Array GLTFAccessor::_encode_variants_as_floats(const Array &p_input_data, Variant::Type p_variant_type) const {
|
||||||
|
|
|
||||||
|
|
@ -90,9 +90,17 @@ private:
|
||||||
static GLTFAccessorType _get_accessor_type_from_str(const String &p_string);
|
static GLTFAccessorType _get_accessor_type_from_str(const String &p_string);
|
||||||
String _get_accessor_type_name() const;
|
String _get_accessor_type_name() const;
|
||||||
int64_t _get_vector_size() const;
|
int64_t _get_vector_size() const;
|
||||||
|
static int64_t _get_numbers_per_variant_for_gltf(Variant::Type p_variant_type);
|
||||||
static int64_t _get_bytes_per_component(const GLTFComponentType p_component_type);
|
static int64_t _get_bytes_per_component(const GLTFComponentType p_component_type);
|
||||||
int64_t _get_bytes_per_vector() const;
|
int64_t _get_bytes_per_vector() const;
|
||||||
|
|
||||||
|
// Private decode functions.
|
||||||
|
PackedInt64Array _decode_sparse_indices(const Ref<GLTFState> &p_gltf_state, const TypedArray<GLTFBufferView> &p_buffer_views) const;
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> _decode_raw_numbers(const Ref<GLTFState> &p_gltf_state, const TypedArray<GLTFBufferView> &p_buffer_views, bool p_sparse_values) const;
|
||||||
|
template <typename T>
|
||||||
|
Vector<T> _decode_as_numbers(const Ref<GLTFState> &p_gltf_state) const;
|
||||||
|
|
||||||
// Private encode functions.
|
// Private encode functions.
|
||||||
PackedFloat64Array _encode_variants_as_floats(const Array &p_input_data, Variant::Type p_variant_type) const;
|
PackedFloat64Array _encode_variants_as_floats(const Array &p_input_data, Variant::Type p_variant_type) const;
|
||||||
void _store_sparse_indices_into_state(const Ref<GLTFState> &p_gltf_state, const PackedInt64Array &p_sparse_indices, const bool p_deduplicate = true);
|
void _store_sparse_indices_into_state(const Ref<GLTFState> &p_gltf_state, const PackedInt64Array &p_sparse_indices, const bool p_deduplicate = true);
|
||||||
|
|
@ -171,6 +179,18 @@ public:
|
||||||
|
|
||||||
bool is_equal_exact(const Ref<GLTFAccessor> &p_other) const;
|
bool is_equal_exact(const Ref<GLTFAccessor> &p_other) const;
|
||||||
|
|
||||||
|
// High-level decode functions.
|
||||||
|
PackedColorArray decode_as_colors(const Ref<GLTFState> &p_gltf_state) const;
|
||||||
|
PackedFloat32Array decode_as_float32s(const Ref<GLTFState> &p_gltf_state) const;
|
||||||
|
PackedFloat64Array decode_as_float64s(const Ref<GLTFState> &p_gltf_state) const;
|
||||||
|
PackedInt32Array decode_as_int32s(const Ref<GLTFState> &p_gltf_state) const;
|
||||||
|
PackedInt64Array decode_as_int64s(const Ref<GLTFState> &p_gltf_state) const;
|
||||||
|
Vector<Quaternion> decode_as_quaternions(const Ref<GLTFState> &p_gltf_state) const;
|
||||||
|
PackedVector2Array decode_as_vector2s(const Ref<GLTFState> &p_gltf_state) const;
|
||||||
|
PackedVector3Array decode_as_vector3s(const Ref<GLTFState> &p_gltf_state) const;
|
||||||
|
PackedVector4Array decode_as_vector4s(const Ref<GLTFState> &p_gltf_state) const;
|
||||||
|
Array decode_as_variants(const Ref<GLTFState> &p_gltf_state, Variant::Type p_variant_type) const;
|
||||||
|
|
||||||
// Low-level encode functions.
|
// Low-level encode functions.
|
||||||
static GLTFComponentType get_minimal_integer_component_type_from_ints(const PackedInt64Array &p_numbers);
|
static GLTFComponentType get_minimal_integer_component_type_from_ints(const PackedInt64Array &p_numbers);
|
||||||
PackedByteArray encode_floats_as_bytes(const PackedFloat64Array &p_input_numbers);
|
PackedByteArray encode_floats_as_bytes(const PackedFloat64Array &p_input_numbers);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue