diff options
-rw-r--r-- | scene/resources/mesh.cpp | 184 |
1 files changed, 136 insertions, 48 deletions
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 1df40fc08e..d2d96b1f06 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -596,7 +596,7 @@ enum OldArrayFormat { OLD_ARRAY_FLAG_USE_2D_VERTICES = OLD_ARRAY_COMPRESS_INDEX << 1, OLD_ARRAY_FLAG_USE_16_BIT_BONES = OLD_ARRAY_COMPRESS_INDEX << 2, OLD_ARRAY_FLAG_USE_DYNAMIC_UPDATE = OLD_ARRAY_COMPRESS_INDEX << 3, - + OLD_ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION = OLD_ARRAY_COMPRESS_INDEX << 4, }; #ifndef DISABLE_DEPRECATED @@ -626,6 +626,27 @@ static Mesh::PrimitiveType _old_primitives[7] = { }; #endif // DISABLE_DEPRECATED +// Convert Octahedron-mapped normalized vector back to Cartesian +// Assumes normalized format (elements of v within range [-1, 1]) +Vector3 _oct_to_norm(const Vector2 v) { + Vector3 res(v.x, v.y, 1 - (Math::absf(v.x) + Math::absf(v.y))); + float t = MAX(-res.z, 0.0f); + res.x += t * -SIGN(res.x); + res.y += t * -SIGN(res.y); + return res.normalized(); +} + +// Convert Octahedron-mapped normalized tangent vector back to Cartesian +// out_sign provides the direction for the original cartesian tangent +// Assumes normalized format (elements of v within range [-1, 1]) +Vector3 _oct_to_tangent(const Vector2 v, float *out_sign) { + Vector2 v_decompressed = v; + v_decompressed.y = Math::absf(v_decompressed.y) * 2 - 1; + Vector3 res = _oct_to_norm(v_decompressed); + *out_sign = SIGN(v[1]); + return res; +} + void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_format, uint32_t p_new_format, uint32_t p_elements, Vector<uint8_t> &vertex_data, Vector<uint8_t> &attribute_data, Vector<uint8_t> &skin_data) { uint32_t dst_vertex_stride; uint32_t dst_attribute_stride; @@ -692,66 +713,133 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma } } break; case OLD_ARRAY_NORMAL: { - if (p_old_format & OLD_ARRAY_COMPRESS_NORMAL) { - const float multiplier = 1.f / 127.f * 1023.0f; + if (p_old_format & OLD_ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) { + if ((p_old_format & OLD_ARRAY_COMPRESS_NORMAL) && (p_old_format & OLD_ARRAY_FORMAT_TANGENT) && (p_old_format & OLD_ARRAY_COMPRESS_TANGENT)) { + for (uint32_t i = 0; i < p_elements; i++) { + const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f); + + const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + *dst = 0; + *dst |= CLAMP(int(res.x * 1023.0f), 0, 1023); + *dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10; + *dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20; + } + src_offset += sizeof(int8_t) * 2; + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f); + + const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + *dst = 0; + *dst |= CLAMP(int(res.x * 1023.0f), 0, 1023); + *dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10; + *dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20; + } + src_offset += sizeof(int16_t) * 2; + } + } else { // No Octahedral compression + if (p_old_format & OLD_ARRAY_COMPRESS_NORMAL) { + const float multiplier = 1.f / 127.f * 1023.0f; - for (uint32_t i = 0; i < p_elements; i++) { - const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + for (uint32_t i = 0; i < p_elements; i++) { + const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; - *dst = 0; - *dst |= CLAMP(int(src[0] * multiplier), 0, 1023); - *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10; - *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20; - } - src_offset += sizeof(uint32_t); - } else { - for (uint32_t i = 0; i < p_elements; i++) { - const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + *dst = 0; + *dst |= CLAMP(int(src[0] * multiplier), 0, 1023); + *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20; + } + src_offset += sizeof(uint32_t); + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; - *dst = 0; - *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023); - *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10; - *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20; + *dst = 0; + *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023); + *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20; + } + src_offset += sizeof(float) * 3; } - src_offset += sizeof(float) * 3; } } break; case OLD_ARRAY_TANGENT: { - if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { - const float multiplier = 1.f / 127.f * 1023.0f; - - for (uint32_t i = 0; i < p_elements; i++) { - const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; - - *dst = 0; - *dst |= CLAMP(int(src[0] * multiplier), 0, 1023); - *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10; - *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20; - if (src[3] > 0) { - *dst |= 3 << 30; + if (p_old_format & OLD_ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) { + if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8 + for (uint32_t i = 0; i < p_elements; i++) { + const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f); + float out_sign; + const Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + + *dst = 0; + *dst |= CLAMP(int(res.x * 1023.0), 0, 1023); + *dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10; + *dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20; + if (out_sign > 0) { + *dst |= 3 << 30; + } } + src_offset += sizeof(int8_t) * 2; + } else { // int16 + for (uint32_t i = 0; i < p_elements; i++) { + const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f); + float out_sign; + Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + + *dst = 0; + *dst |= CLAMP(int(res.x * 1023.0), 0, 1023); + *dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10; + *dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20; + if (out_sign > 0) { + *dst |= 3 << 30; + } + } + src_offset += sizeof(int16_t) * 2; } - src_offset += sizeof(uint32_t); - } else { - for (uint32_t i = 0; i < p_elements; i++) { - const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; - - *dst = 0; - *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023); - *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10; - *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20; - if (src[3] > 0) { - *dst |= 3 << 30; + } else { // No Octahedral compression + if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { + const float multiplier = 1.f / 127.f * 1023.0f; + + for (uint32_t i = 0; i < p_elements; i++) { + const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + + *dst = 0; + *dst |= CLAMP(int(src[0] * multiplier), 0, 1023); + *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20; + if (src[3] > 0) { + *dst |= 3 << 30; + } + } + src_offset += sizeof(uint32_t); + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + + *dst = 0; + *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023); + *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20; + if (src[3] > 0) { + *dst |= 3 << 30; + } } + src_offset += sizeof(float) * 4; } - src_offset += sizeof(float) * 4; } - } break; case OLD_ARRAY_COLOR: { if (p_old_format & OLD_ARRAY_COMPRESS_COLOR) { |