diff options
author | clayjohn <claynjohn@gmail.com> | 2023-08-29 21:04:32 +0200 |
---|---|---|
committer | clayjohn <claynjohn@gmail.com> | 2023-10-05 12:02:23 -0600 |
commit | 51ed3aef63c0fdfc7666c004cc6d94dd15322d81 (patch) | |
tree | de596e05a1319438fb08024f23be417d29446494 /servers/rendering_server.cpp | |
parent | d31794c4a26e5e10fc30c34a1ae9722fd9f50123 (diff) | |
download | redot-engine-51ed3aef63c0fdfc7666c004cc6d94dd15322d81.tar.gz |
Vertex and attribute compression to reduce the size of the vertex format.
This allows Godot to automatically compress meshes to save a lot of bandwidth.
In general, this requires no interaction from the user and should result in
no noticable quality loss.
This scheme is not backwards compatible, so we have provided an upgrade
mechanism, and a mesh versioning mechanism.
Existing meshes can still be used as a result, but users can get a
performance boost by reimporting assets.
Diffstat (limited to 'servers/rendering_server.cpp')
-rw-r--r-- | servers/rendering_server.cpp | 657 |
1 files changed, 542 insertions, 115 deletions
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 9a3b7b9f3c..94ff59f7e1 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -322,7 +322,40 @@ RID RenderingServer::get_white_texture() { return white_texture; } -Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) { +void _get_axis_angle(const Vector3 &p_normal, const Vector4 &p_tangent, float &r_angle, Vector3 &r_axis) { + Vector3 tangent = Vector3(p_tangent.x, p_tangent.y, p_tangent.z); + float d = p_tangent.w; + Vector3 binormal = p_normal.cross(tangent); + + r_angle = Math::acos((tangent.x + binormal.y + p_normal.z - 1.0) / 2.0); + float denom = 2.0 * Math::sin(r_angle); + r_axis.x = (p_normal.y - binormal.z) / denom; + r_axis.y = (tangent.z - p_normal.x) / denom; + r_axis.z = (binormal.x - tangent.y) / denom; + r_axis.normalize(); + + if (d < 0.0) { + r_angle = CLAMP((1.0 - r_angle / Math_PI) * 0.5, 0.0, 0.49999); + } else { + r_angle = (r_angle / Math_PI) * 0.5 + 0.5; + } +} + +// The inputs to this function should match the outputs of _get_axis_angle. I.e. p_axis is a normalized vector +// and p_angle includes the binormal direction. +void _get_tbn_from_axis_angle(const Vector3 &p_axis, float p_angle, Vector3 &r_normal, Vector4 &r_tangent) { + float binormal_sign = p_angle > 0.5 ? 1.0 : -1.0; + float angle = Math::abs(p_angle * 2.0 - 1.0) * Math_PI; + float c = cos(angle); + float s = sin(angle); + Vector3 omc_axis = (1.0 - c) * p_axis; + Vector3 s_axis = s * p_axis; + Vector3 tan = omc_axis.x * p_axis + Vector3(c, -s_axis.z, s_axis.y); + r_tangent = Vector4(tan.x, tan.y, tan.z, binormal_sign); + r_normal = omc_axis.z * p_axis + Vector3(-s_axis.y, s_axis.x, c); +} + +Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_normal_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb, Vector4 &r_uv_scale) { uint8_t *vw = r_vertex_array.ptrw(); uint8_t *aw = r_attrib_array.ptrw(); uint8_t *sw = r_skin_array.ptrw(); @@ -334,8 +367,44 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint int max_bone = 0; + // Preprocess UVs if compression is enabled + if (p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && ((p_format & RS::ARRAY_FORMAT_TEX_UV) || (p_format & RS::ARRAY_FORMAT_TEX_UV2))) { + const Vector2 *uv_src = nullptr; + if (p_format & RS::ARRAY_FORMAT_TEX_UV) { + Vector<Vector2> array = p_arrays[RS::ARRAY_TEX_UV]; + uv_src = array.ptr(); + } + + const Vector2 *uv2_src = nullptr; + if (p_format & RS::ARRAY_FORMAT_TEX_UV2) { + Vector<Vector2> array = p_arrays[RS::ARRAY_TEX_UV2]; + uv2_src = array.ptr(); + } + + Vector2 max_val = Vector2(0.0, 0.0); + Vector2 min_val = Vector2(0.0, 0.0); + Vector2 max_val2 = Vector2(0.0, 0.0); + Vector2 min_val2 = Vector2(0.0, 0.0); + + for (int i = 0; i < p_vertex_array_len; i++) { + if (p_format & RS::ARRAY_FORMAT_TEX_UV) { + max_val = max_val.max(uv_src[i]); + min_val = min_val.min(uv_src[i]); + } + if (p_format & RS::ARRAY_FORMAT_TEX_UV2) { + max_val2 = max_val2.max(uv2_src[i]); + min_val2 = min_val2.min(uv2_src[i]); + } + } + + max_val = max_val.abs().max(min_val.abs()); + max_val2 = max_val2.abs().max(min_val2.abs()); + + r_uv_scale = Vector4(max_val.x, max_val.y, max_val2.x, max_val2.y) * Vector4(2.0, 2.0, 2.0, 2.0); + } + for (int ai = 0; ai < RS::ARRAY_MAX; ai++) { - if (!(p_format & (1 << ai))) { // No array + if (!(p_format & (1ULL << ai))) { // No array continue; } @@ -375,7 +444,118 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint // Setting vertices means regenerating the AABB. AABB aabb; - { + if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + // First we need to generate the AABB for the entire surface. + for (int i = 0; i < p_vertex_array_len; i++) { + if (i == 0) { + aabb = AABB(src[i], SMALL_VEC3); + } else { + aabb.expand_to(src[i]); + } + } + + bool using_normals_tangents = (p_format & RS::ARRAY_FORMAT_NORMAL) && (p_format & RS::ARRAY_FORMAT_TANGENT); + + if (!using_normals_tangents) { + // Early out if we are only setting vertex positions. + for (int i = 0; i < p_vertex_array_len; i++) { + Vector3 pos = (src[i] - aabb.position) / aabb.size; + uint16_t vector[4] = { + (uint16_t)CLAMP(pos.x * 65535, 0, 65535), + (uint16_t)CLAMP(pos.y * 65535, 0, 65535), + (uint16_t)CLAMP(pos.z * 65535, 0, 65535), + (uint16_t)0 + }; + + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(uint16_t) * 4); + } + continue; + } + + // Validate normal and tangent arrays. + ERR_FAIL_COND_V(p_arrays[RS::ARRAY_NORMAL].get_type() != Variant::PACKED_VECTOR3_ARRAY, ERR_INVALID_PARAMETER); + Variant::Type tangent_type = p_arrays[RS::ARRAY_TANGENT].get_type(); + ERR_FAIL_COND_V(tangent_type != Variant::PACKED_FLOAT32_ARRAY && tangent_type != Variant::PACKED_FLOAT64_ARRAY, ERR_INVALID_PARAMETER); + + Vector<Vector3> normal_array = p_arrays[RS::ARRAY_NORMAL]; + ERR_FAIL_COND_V(normal_array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); + const Vector3 *normal_src = normal_array.ptr(); + + // We need a different version if using double precision tangents. + if (tangent_type == Variant::PACKED_FLOAT32_ARRAY) { + Vector<float> tangent_array = p_arrays[RS::ARRAY_TANGENT]; + ERR_FAIL_COND_V(tangent_array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); + const float *tangent_src = tangent_array.ptr(); + + // Set data for vertex, normal, and tangent. + for (int i = 0; i < p_vertex_array_len; i++) { + float angle = 0.0; + Vector3 axis; + Vector4 tangent = Vector4(tangent_src[i * 4 + 0], tangent_src[i * 4 + 1], tangent_src[i * 4 + 2], tangent_src[i * 4 + 3]); + _get_axis_angle(normal_src[i], tangent, angle, axis); + + // Store axis. + { + Vector2 res = axis.octahedron_encode(); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + memcpy(&vw[p_offsets[RS::ARRAY_NORMAL] + i * p_normal_stride], vector, 4); + } + + // Store vertex position + angle. + { + Vector3 pos = (src[i] - aabb.position) / aabb.size; + uint16_t vector[4] = { + (uint16_t)CLAMP(pos.x * 65535, 0, 65535), + (uint16_t)CLAMP(pos.y * 65535, 0, 65535), + (uint16_t)CLAMP(pos.z * 65535, 0, 65535), + (uint16_t)CLAMP(angle * 65535, 0, 65535) + }; + + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(uint16_t) * 4); + } + } + } else { // PACKED_FLOAT64_ARRAY + Vector<double> tangent_array = p_arrays[RS::ARRAY_TANGENT]; + ERR_FAIL_COND_V(tangent_array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); + const double *tangent_src = tangent_array.ptr(); + + // Set data for vertex, normal, and tangent. + for (int i = 0; i < p_vertex_array_len; i++) { + float angle; + Vector3 axis; + Vector4 tangent = Vector4(tangent_src[i * 4 + 0], tangent_src[i * 4 + 1], tangent_src[i * 4 + 2], tangent_src[i * 4 + 3]); + _get_axis_angle(normal_src[i], tangent, angle, axis); + + // Store axis. + { + Vector2 res = axis.octahedron_encode(); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + memcpy(&vw[p_offsets[RS::ARRAY_NORMAL] + i * p_normal_stride], vector, 4); + } + + // Store vertex position + angle. + { + Vector3 pos = (src[i] - aabb.position) / aabb.size; + uint16_t vector[4] = { + (uint16_t)CLAMP(pos.x * 65535, 0, 65535), + (uint16_t)CLAMP(pos.y * 65535, 0, 65535), + (uint16_t)CLAMP(pos.z * 65535, 0, 65535), + (uint16_t)CLAMP(angle * 65535, 0, 65535) + }; + + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(uint16_t) * 4); + } + } + } + } else { for (int i = 0; i < p_vertex_array_len; i++) { float vector[3] = { (float)src[i].x, (float)src[i].y, (float)src[i].z }; @@ -394,55 +574,61 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint } break; case RS::ARRAY_NORMAL: { - ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY, ERR_INVALID_PARAMETER); + // If using compression we store normal while storing vertices. + if (!(p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY, ERR_INVALID_PARAMETER); - Vector<Vector3> array = p_arrays[ai]; - ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); - - const Vector3 *src = array.ptr(); - for (int i = 0; i < p_vertex_array_len; i++) { - Vector2 res = src[i].octahedron_encode(); - uint16_t vector[2] = { - (uint16_t)CLAMP(res.x * 65535, 0, 65535), - (uint16_t)CLAMP(res.y * 65535, 0, 65535), - }; - - memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4); - } - } break; - - case RS::ARRAY_TANGENT: { - Variant::Type type = p_arrays[ai].get_type(); - ERR_FAIL_COND_V(type != Variant::PACKED_FLOAT32_ARRAY && type != Variant::PACKED_FLOAT64_ARRAY, ERR_INVALID_PARAMETER); - if (type == Variant::PACKED_FLOAT32_ARRAY) { - Vector<float> array = p_arrays[ai]; - ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); - const float *src_ptr = array.ptr(); + Vector<Vector3> array = p_arrays[ai]; + ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); + const Vector3 *src = array.ptr(); for (int i = 0; i < p_vertex_array_len; i++) { - const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]); - Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]); + Vector2 res = src[i].octahedron_encode(); uint16_t vector[2] = { (uint16_t)CLAMP(res.x * 65535, 0, 65535), (uint16_t)CLAMP(res.y * 65535, 0, 65535), }; - memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4); + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); } - } else { // PACKED_FLOAT64_ARRAY - Vector<double> array = p_arrays[ai]; - ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); - const double *src_ptr = array.ptr(); + } + } break; - for (int i = 0; i < p_vertex_array_len; i++) { - const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]); - Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]); - uint16_t vector[2] = { - (uint16_t)CLAMP(res.x * 65535, 0, 65535), - (uint16_t)CLAMP(res.y * 65535, 0, 65535), - }; + case RS::ARRAY_TANGENT: { + // If using compression we store tangent while storing vertices. + if (!(p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + Variant::Type type = p_arrays[ai].get_type(); + ERR_FAIL_COND_V(type != Variant::PACKED_FLOAT32_ARRAY && type != Variant::PACKED_FLOAT64_ARRAY, ERR_INVALID_PARAMETER); + if (type == Variant::PACKED_FLOAT32_ARRAY) { + Vector<float> array = p_arrays[ai]; + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); + const float *src_ptr = array.ptr(); + + for (int i = 0; i < p_vertex_array_len; i++) { + const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]); + Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); + } + } else { // PACKED_FLOAT64_ARRAY + Vector<double> array = p_arrays[ai]; + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); + const double *src_ptr = array.ptr(); - memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4); + for (int i = 0; i < p_vertex_array_len; i++) { + const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]); + Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); + } } } } break; @@ -472,13 +658,20 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); const Vector2 *src = array.ptr(); - - for (int i = 0; i < p_vertex_array_len; i++) { - float uv[2] = { (float)src[i].x, (float)src[i].y }; - - memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); + if (p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + for (int i = 0; i < p_vertex_array_len; i++) { + Vector2 vec = src[i]; + // Normalize into 0-1 from possible range -uv_scale - uv_scale. + vec = vec / (Vector2(r_uv_scale.x, r_uv_scale.y)) + Vector2(0.5, 0.5); + uint16_t uv[2] = { (uint16_t)CLAMP(vec.x * 65535, 0, 65535), (uint16_t)CLAMP(vec.y * 65535, 0, 65535) }; + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 4); + } + } else { + for (int i = 0; i < p_vertex_array_len; i++) { + float uv[2] = { (float)src[i].x, (float)src[i].y }; + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); + } } - } break; case RS::ARRAY_TEX_UV2: { @@ -490,9 +683,19 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const Vector2 *src = array.ptr(); - for (int i = 0; i < p_vertex_array_len; i++) { - float uv[2] = { (float)src[i].x, (float)src[i].y }; - memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); + if (p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + for (int i = 0; i < p_vertex_array_len; i++) { + Vector2 vec = src[i]; + // Normalize into 0-1 from possible range -uv_scale - uv_scale. + vec = vec / (Vector2(r_uv_scale.z, r_uv_scale.w)) + Vector2(0.5, 0.5); + uint16_t uv[2] = { (uint16_t)CLAMP(vec.x * 65535, 0, 65535), (uint16_t)CLAMP(vec.y * 65535, 0, 65535) }; + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 4); + } + } else { + for (int i = 0; i < p_vertex_array_len; i++) { + float uv[2] = { (float)src[i].x, (float)src[i].y }; + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); + } } } break; case RS::ARRAY_CUSTOM0: @@ -707,9 +910,10 @@ uint32_t RenderingServer::mesh_surface_get_format_offset(BitField<ArrayFormat> p p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; + uint32_t ntstr; uint32_t astr; uint32_t sstr; - mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, ntstr, astr, sstr); return offsets[p_array_index]; } @@ -717,32 +921,48 @@ uint32_t RenderingServer::mesh_surface_get_format_vertex_stride(BitField<ArrayFo p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; + uint32_t ntstr; uint32_t astr; uint32_t sstr; - mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, ntstr, astr, sstr); return vstr; } + +uint32_t RenderingServer::mesh_surface_get_format_normal_tangent_stride(BitField<ArrayFormat> p_format, int p_vertex_len) const { + p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; + uint32_t offsets[ARRAY_MAX]; + uint32_t vstr; + uint32_t ntstr; + uint32_t astr; + uint32_t sstr; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, ntstr, astr, sstr); + return vstr; +} + uint32_t RenderingServer::mesh_surface_get_format_attribute_stride(BitField<ArrayFormat> p_format, int p_vertex_len) const { p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; + uint32_t ntstr; uint32_t astr; uint32_t sstr; - mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, ntstr, astr, sstr); return astr; } uint32_t RenderingServer::mesh_surface_get_format_skin_stride(BitField<ArrayFormat> p_format, int p_vertex_len) const { p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; + uint32_t ntstr; uint32_t astr; uint32_t sstr; - mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, ntstr, astr, sstr); return sstr; } -void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const { +void RenderingServer::mesh_surface_make_offsets_from_format(uint64_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_normal_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const { r_vertex_element_size = 0; + r_normal_element_size = 0; r_attrib_element_size = 0; r_skin_element_size = 0; @@ -753,13 +973,15 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i if (i == RS::ARRAY_VERTEX) { size_accum = &r_vertex_element_size; + } else if (i == RS::ARRAY_NORMAL) { + size_accum = &r_normal_element_size; } else if (i == RS::ARRAY_COLOR) { size_accum = &r_attrib_element_size; } else if (i == RS::ARRAY_BONES) { size_accum = &r_skin_element_size; } - if (!(p_format & (1 << i))) { // No array + if (!(p_format & (1ULL << i))) { // No array continue; } @@ -770,7 +992,7 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i if (p_format & ARRAY_FLAG_USE_2D_VERTICES) { elem_size = 2; } else { - elem_size = 3; + elem_size = (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) ? 2 : 3; } elem_size *= sizeof(float); @@ -779,22 +1001,22 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i elem_size = 4; } break; case RS::ARRAY_TANGENT: { - elem_size = 4; + elem_size = (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) ? 0 : 4; } break; case RS::ARRAY_COLOR: { elem_size = 4; } break; case RS::ARRAY_TEX_UV: { - elem_size = 8; + elem_size = (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) ? 4 : 8; } break; case RS::ARRAY_TEX_UV2: { - elem_size = 8; + elem_size = (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) ? 4 : 8; } break; case RS::ARRAY_CUSTOM0: case RS::ARRAY_CUSTOM1: case RS::ARRAY_CUSTOM2: case RS::ARRAY_CUSTOM3: { - uint32_t format = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + (ARRAY_FORMAT_CUSTOM_BITS * (i - ARRAY_CUSTOM0)))) & ARRAY_FORMAT_CUSTOM_MASK; + uint64_t format = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + (ARRAY_FORMAT_CUSTOM_BITS * (i - ARRAY_CUSTOM0)))) & ARRAY_FORMAT_CUSTOM_MASK; switch (format) { case ARRAY_CUSTOM_RGBA8_UNORM: { elem_size = 4; @@ -852,6 +1074,9 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i if (size_accum != nullptr) { r_offsets[i] = (*size_accum); + if (i == RS::ARRAY_NORMAL || i == RS::ARRAY_TANGENT) { + r_offsets[i] += r_vertex_element_size * p_vertex_len; + } (*size_accum) += elem_size; } else { r_offsets[i] = 0; @@ -859,11 +1084,11 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i } } -Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_compress_format) { +Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint64_t p_compress_format) { ERR_FAIL_INDEX_V(p_primitive, RS::PRIMITIVE_MAX, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_arrays.size() != RS::ARRAY_MAX, ERR_INVALID_PARAMETER); - uint32_t format = 0; + uint64_t format = 0; // Validation int index_array_len = 0; @@ -874,7 +1099,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa continue; } - format |= (1 << i); + format |= (1ULL << i); if (i == RS::ARRAY_VERTEX) { switch (p_arrays[i].get_type()) { @@ -930,7 +1155,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa for (uint32_t i = 0; i < RS::ARRAY_CUSTOM_COUNT; ++i) { // Include custom array format type. - if (format & (1 << (ARRAY_CUSTOM0 + i))) { + if (format & (1ULL << (ARRAY_CUSTOM0 + i))) { format |= (RS::ARRAY_FORMAT_CUSTOM_MASK << (RS::ARRAY_FORMAT_CUSTOM_BASE + i * RS::ARRAY_FORMAT_CUSTOM_BITS)) & p_compress_format; } } @@ -938,21 +1163,33 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa uint32_t offsets[RS::ARRAY_MAX]; uint32_t vertex_element_size; + uint32_t normal_element_size; uint32_t attrib_element_size; uint32_t skin_element_size; - mesh_surface_make_offsets_from_format(format, array_len, index_array_len, offsets, vertex_element_size, attrib_element_size, skin_element_size); - - uint32_t mask = (1 << ARRAY_MAX) - 1; + uint64_t mask = (1ULL << ARRAY_MAX) - 1ULL; format |= (~mask) & p_compress_format; // Make the full format. + // Force version to the current version as this function will always return a surface with the current version. + format &= ~(ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); + format |= ARRAY_FLAG_FORMAT_CURRENT_VERSION & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); + + mesh_surface_make_offsets_from_format(format, array_len, index_array_len, offsets, vertex_element_size, normal_element_size, attrib_element_size, skin_element_size); + if ((format & RS::ARRAY_FORMAT_VERTEX) == 0 && !(format & RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY)) { ERR_PRINT("Mesh created without vertex array. This mesh will not be visible with the default shader. If using an empty vertex array is intentional, create the mesh with the ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY flag to silence this error."); // Set the flag here after warning to suppress errors down the pipeline. format |= RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY; } - int vertex_array_size = vertex_element_size * array_len; + if (format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && ((format & RS::ARRAY_FORMAT_NORMAL) || (format & RS::ARRAY_FORMAT_TANGENT))) { + // If using normals or tangents, then we need all three. + ERR_FAIL_COND_V_MSG(!(format & RS::ARRAY_FORMAT_VERTEX), ERR_INVALID_PARAMETER, "Can't use compression flag 'ARRAY_FLAG_COMPRESS_ATTRIBUTES' while using normals or tangents without vertex array."); + ERR_FAIL_COND_V_MSG(!(format & RS::ARRAY_FORMAT_NORMAL), ERR_INVALID_PARAMETER, "Can't use compression flag 'ARRAY_FLAG_COMPRESS_ATTRIBUTES' while using tangents without normal array."); + ERR_FAIL_COND_V_MSG(!(format & RS::ARRAY_FORMAT_TANGENT), ERR_INVALID_PARAMETER, "Can't use compression flag 'ARRAY_FLAG_COMPRESS_ATTRIBUTES' while using normals without tangent array."); + } + + int vertex_array_size = (vertex_element_size + normal_element_size) * array_len; int attrib_array_size = attrib_element_size * array_len; int skin_array_size = skin_element_size * array_len; int index_array_size = offsets[RS::ARRAY_INDEX] * index_array_len; @@ -972,7 +1209,9 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa AABB aabb; Vector<AABB> bone_aabb; - Error err = _surface_set_data(p_arrays, format, offsets, vertex_element_size, attrib_element_size, skin_element_size, vertex_array, attrib_array, skin_array, array_len, index_array, index_array_len, aabb, bone_aabb); + Vector4 uv_scale = Vector4(0.0, 0.0, 0.0, 0.0); + + Error err = _surface_set_data(p_arrays, format, offsets, vertex_element_size, normal_element_size, attrib_element_size, skin_element_size, vertex_array, attrib_array, skin_array, array_len, index_array, index_array_len, aabb, bone_aabb, uv_scale); ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Invalid array format for surface."); Vector<uint8_t> blend_shape_data; @@ -987,7 +1226,8 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa Vector<uint8_t> noskin; AABB laabb; - Error err2 = _surface_set_data(p_blend_shapes[i], bs_format, offsets, vertex_element_size, 0, 0, vertex_array_shape, noattrib, noskin, array_len, noindex, 0, laabb, bone_aabb); + Vector4 bone_uv_scale; // Not used. + Error err2 = _surface_set_data(p_blend_shapes[i], bs_format, offsets, vertex_element_size, normal_element_size, 0, 0, vertex_array_shape, noattrib, noskin, array_len, noindex, 0, laabb, bone_aabb, bone_uv_scale); aabb.merge_with(laabb); ERR_FAIL_COND_V_MSG(err2 != OK, ERR_INVALID_DATA, "Invalid blend shape array format for surface."); @@ -1048,6 +1288,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa surface_data.blend_shape_data = blend_shape_data; surface_data.bone_aabbs = bone_aabb; surface_data.lods = lods; + surface_data.uv_scale = uv_scale; return OK; } @@ -1061,13 +1302,14 @@ void RenderingServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_p mesh_add_surface(p_mesh, sd); } -Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const { +Array RenderingServer::_get_array_from_surface(uint64_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len, const AABB &p_aabb) const { uint32_t offsets[RS::ARRAY_MAX]; uint32_t vertex_elem_size; + uint32_t normal_elem_size; uint32_t attrib_elem_size; uint32_t skin_elem_size; - mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets, vertex_elem_size, attrib_elem_size, skin_elem_size); + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets, vertex_elem_size, normal_elem_size, attrib_elem_size, skin_elem_size); Array ret; ret.resize(RS::ARRAY_MAX); @@ -1077,7 +1319,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t const uint8_t *sr = p_skin_data.ptr(); for (int i = 0; i < RS::ARRAY_MAX; i++) { - if (!(p_format & (1 << i))) { + if (!(p_format & (1ULL << i))) { continue; } @@ -1104,9 +1346,54 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t { Vector3 *w = arr_3d.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const float *v = reinterpret_cast<const float *>(&r[j * vertex_elem_size + offsets[i]]); - w[j] = Vector3(v[0], v[1], v[2]); + if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + bool using_normals_tangents = (p_format & RS::ARRAY_FORMAT_NORMAL) && (p_format & RS::ARRAY_FORMAT_TANGENT); + + // We only have vertices to read, so just read them and skip everything else. + if (!using_normals_tangents) { + for (int j = 0; j < p_vertex_len; j++) { + const uint16_t *v = reinterpret_cast<const uint16_t *>(&r[j * vertex_elem_size + offsets[i]]); + Vector3 vec = Vector3(float(v[0]) / 65535.0, float(v[1]) / 65535.0, float(v[2]) / 65535.0); + w[j] = (vec * p_aabb.size) + p_aabb.position; + } + continue; + } + + Vector<Vector3> normals; + normals.resize(p_vertex_len); + Vector3 *normalsw = normals.ptrw(); + + Vector<float> tangents; + tangents.resize(p_vertex_len * 4); + float *tangentsw = tangents.ptrw(); + + for (int j = 0; j < p_vertex_len; j++) { + const uint32_t n = *(const uint32_t *)&r[j * normal_elem_size + offsets[RS::ARRAY_NORMAL]]; + Vector3 axis = Vector3::octahedron_decode(Vector2((n & 0xFFFF) / 65535.0, ((n >> 16) & 0xFFFF) / 65535.0)); + + const uint16_t *v = reinterpret_cast<const uint16_t *>(&r[j * vertex_elem_size + offsets[i]]); + Vector3 vec = Vector3(float(v[0]) / 65535.0, float(v[1]) / 65535.0, float(v[2]) / 65535.0); + float angle = float(v[3]) / 65535.0; + w[j] = (vec * p_aabb.size) + p_aabb.position; + + Vector3 normal; + Vector4 tan; + _get_tbn_from_axis_angle(axis, angle, normal, tan); + + normalsw[j] = normal; + tangentsw[j * 4 + 0] = tan.x; + tangentsw[j * 4 + 1] = tan.y; + tangentsw[j * 4 + 2] = tan.z; + tangentsw[j * 4 + 3] = tan.w; + } + ret[RS::ARRAY_NORMAL] = normals; + ret[RS::ARRAY_FORMAT_TANGENT] = tangents; + + } else { + for (int j = 0; j < p_vertex_len; j++) { + const float *v = reinterpret_cast<const float *>(&r[j * vertex_elem_size + offsets[i]]); + w[j] = Vector3(v[0], v[1], v[2]); + } } } @@ -1115,39 +1402,41 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t } break; case RS::ARRAY_NORMAL: { - Vector<Vector3> arr; - arr.resize(p_vertex_len); - - Vector3 *w = arr.ptrw(); + if (!(p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + Vector<Vector3> arr; + arr.resize(p_vertex_len); - for (int j = 0; j < p_vertex_len; j++) { - const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]]; + Vector3 *w = arr.ptrw(); - w[j] = Vector3::octahedron_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0)); - } + for (int j = 0; j < p_vertex_len; j++) { + const uint32_t v = *(const uint32_t *)&r[j * normal_elem_size + offsets[i]]; - ret[i] = arr; + w[j] = Vector3::octahedron_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0)); + } + ret[i] = arr; + } } break; case RS::ARRAY_TANGENT: { - Vector<float> arr; - arr.resize(p_vertex_len * 4); - - float *w = arr.ptrw(); + if (!(p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + Vector<float> arr; + arr.resize(p_vertex_len * 4); - for (int j = 0; j < p_vertex_len; j++) { - const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]]; - float tangent_sign; - Vector3 res = Vector3::octahedron_tangent_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0), &tangent_sign); - w[j * 4 + 0] = res.x; - w[j * 4 + 1] = res.y; - w[j * 4 + 2] = res.z; - w[j * 4 + 3] = tangent_sign; - } + float *w = arr.ptrw(); - ret[i] = arr; + for (int j = 0; j < p_vertex_len; j++) { + const uint32_t v = *(const uint32_t *)&r[j * normal_elem_size + offsets[i]]; + float tangent_sign; + Vector3 res = Vector3::octahedron_tangent_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0), &tangent_sign); + w[j * 4 + 0] = res.x; + w[j * 4 + 1] = res.y; + w[j * 4 + 2] = res.z; + w[j * 4 + 3] = tangent_sign; + } + ret[i] = arr; + } } break; case RS::ARRAY_COLOR: { Vector<Color> arr; @@ -1168,12 +1457,17 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t arr.resize(p_vertex_len); Vector2 *w = arr.ptrw(); - - for (int j = 0; j < p_vertex_len; j++) { - const float *v = reinterpret_cast<const float *>(&ar[j * attrib_elem_size + offsets[i]]); - w[j] = Vector2(v[0], v[1]); + if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + for (int j = 0; j < p_vertex_len; j++) { + const uint16_t *v = reinterpret_cast<const uint16_t *>(&ar[j * attrib_elem_size + offsets[i]]); + w[j] = Vector2(float(v[0]) / 65535.0, float(v[1]) / 65535.0); + } + } else { + for (int j = 0; j < p_vertex_len; j++) { + const float *v = reinterpret_cast<const float *>(&ar[j * attrib_elem_size + offsets[i]]); + w[j] = Vector2(v[0], v[1]); + } } - ret[i] = arr; } break; @@ -1183,9 +1477,16 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector2 *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const float *v = reinterpret_cast<const float *>(&ar[j * attrib_elem_size + offsets[i]]); - w[j] = Vector2(v[0], v[1]); + if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + for (int j = 0; j < p_vertex_len; j++) { + const uint16_t *v = reinterpret_cast<const uint16_t *>(&ar[j * attrib_elem_size + offsets[i]]); + w[j] = Vector2(float(v[0]) / 65535.0, float(v[1]) / 65535.0); + } + } else { + for (int j = 0; j < p_vertex_len; j++) { + const float *v = reinterpret_cast<const float *>(&ar[j * attrib_elem_size + offsets[i]]); + w[j] = Vector2(v[0], v[1]); + } } ret[i] = arr; @@ -1358,12 +1659,13 @@ TypedArray<Array> RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mes uint32_t bs_offsets[RS::ARRAY_MAX]; uint32_t bs_format = (sd.format & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK); uint32_t vertex_elem_size; + uint32_t normal_elem_size; uint32_t attrib_elem_size; uint32_t skin_elem_size; + //CLAY + mesh_surface_make_offsets_from_format(bs_format, sd.vertex_count, 0, bs_offsets, vertex_elem_size, normal_elem_size, attrib_elem_size, skin_elem_size); - mesh_surface_make_offsets_from_format(bs_format, sd.vertex_count, 0, bs_offsets, vertex_elem_size, attrib_elem_size, skin_elem_size); - - int divisor = vertex_elem_size * sd.vertex_count; + int divisor = (vertex_elem_size + normal_elem_size) * sd.vertex_count; ERR_FAIL_COND_V((blend_shape_data.size() % divisor) != 0, Array()); uint32_t blend_shape_count = blend_shape_data.size() / divisor; @@ -1375,7 +1677,7 @@ TypedArray<Array> RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mes for (uint32_t i = 0; i < blend_shape_count; i++) { Vector<uint8_t> bs_data = blend_shape_data.slice(i * divisor, (i + 1) * divisor); Vector<uint8_t> unused; - blend_shape_array.set(i, _get_array_from_surface(bs_format, bs_data, unused, unused, sd.vertex_count, unused, 0)); + blend_shape_array.set(i, _get_array_from_surface(bs_format, bs_data, unused, unused, sd.vertex_count, unused, 0, sd.aabb)); } return blend_shape_array; @@ -1395,9 +1697,9 @@ Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p Vector<uint8_t> index_data = p_data.index_data; int index_len = p_data.index_count; - uint32_t format = p_data.format; + uint64_t format = p_data.format; - return _get_array_from_surface(format, vertex_data, attrib_data, skin_data, vertex_len, index_data, index_len); + return _get_array_from_surface(format, vertex_data, attrib_data, skin_data, vertex_len, index_data, index_len, p_data.aabb); } #if 0 Array RenderingServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surface) const { @@ -1531,7 +1833,9 @@ static RS::SurfaceData _dict_to_surf(const Dictionary &p_dictionary) { RS::SurfaceData sd; sd.primitive = RS::PrimitiveType(int(p_dictionary["primitive"])); - sd.format = p_dictionary["format"]; + if (p_dictionary.has("uv_scale")) { + sd.format = p_dictionary["format"]; + } sd.vertex_data = p_dictionary["vertex_data"]; if (p_dictionary.has("attribute_data")) { sd.attribute_data = p_dictionary["attribute_data"]; @@ -1549,6 +1853,7 @@ static RS::SurfaceData _dict_to_surf(const Dictionary &p_dictionary) { } sd.aabb = p_dictionary["aabb"]; + sd.uv_scale = p_dictionary["uv_scale"]; if (p_dictionary.has("lods")) { Array lods = p_dictionary["lods"]; @@ -1610,6 +1915,7 @@ Dictionary RenderingServer::_mesh_get_surface(RID p_mesh, int p_idx) { d["index_count"] = sd.index_count; } d["aabb"] = sd.aabb; + d["uv_scale"] = sd.uv_scale; if (sd.lods.size()) { Array lods; @@ -1663,6 +1969,117 @@ void RenderingServer::_particles_set_trail_bind_poses(RID p_particles, const Typ particles_set_trail_bind_poses(p_particles, tbposes); } +Vector<uint8_t> _convert_surface_version_1_to_surface_version_2(uint64_t p_format, Vector<uint8_t> p_vertex_data, uint32_t p_vertex_count, uint32_t p_old_stride, uint32_t p_vertex_size, uint32_t p_normal_size, uint32_t p_position_stride, uint32_t p_normal_tangent_stride) { + Vector<uint8_t> new_vertex_data; + new_vertex_data.resize(p_vertex_data.size()); + uint8_t *dst_vertex_ptr = new_vertex_data.ptrw(); + + const uint8_t *src_vertex_ptr = p_vertex_data.ptr(); + + uint32_t position_size = p_position_stride * p_vertex_count; + + for (uint32_t j = 0; j < RS::ARRAY_COLOR; j++) { + if (!(p_format & (1ULL << j))) { + continue; + } + switch (j) { + case RS::ARRAY_VERTEX: { + if (p_format & RS::ARRAY_FLAG_USE_2D_VERTICES) { + for (uint32_t i = 0; i < p_vertex_count; i++) { + const float *src = (const float *)&src_vertex_ptr[i * p_old_stride]; + float *dst = (float *)&dst_vertex_ptr[i * p_position_stride]; + dst[0] = src[0]; + dst[1] = src[1]; + } + } else { + for (uint32_t i = 0; i < p_vertex_count; i++) { + const float *src = (const float *)&src_vertex_ptr[i * p_old_stride]; + float *dst = (float *)&dst_vertex_ptr[i * p_position_stride]; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + } + } + } break; + case RS::ARRAY_NORMAL: { + for (uint32_t i = 0; i < p_vertex_count; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * p_old_stride + p_vertex_size]; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * p_normal_tangent_stride + position_size]; + + dst[0] = src[0]; + dst[1] = src[1]; + } + } break; + case RS::ARRAY_TANGENT: { + for (uint32_t i = 0; i < p_vertex_count; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * p_old_stride + p_vertex_size + p_normal_size]; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * p_normal_tangent_stride + position_size + p_normal_size]; + + dst[0] = src[0]; + dst[1] = src[1]; + } + } break; + } + } + return new_vertex_data; +} + +#ifndef DISABLE_DEPRECATED +void RenderingServer::_fix_surface_compatibility(SurfaceData &p_surface) { + uint64_t surface_version = p_surface.format & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); + ERR_FAIL_COND_MSG(surface_version > ARRAY_FLAG_FORMAT_CURRENT_VERSION, "Cannot convert surface with version provided (" + itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + ") to current version (" + itos((RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + ")"); + + if (surface_version == ARRAY_FLAG_FORMAT_VERSION_1) { + // The only difference for now is that Version 1 uses interleaved vertex positions while version 2 does not. + // I.e. PNTPNTPNT -> PPPNTNTNT. + WARN_PRINT_ED("Upgrading mesh from older surface format. Once saved again (or re-imported), this mesh will be incompatible with earlier versions of Godot."); + + int vertex_size = 0; + int normal_size = 0; + int tangent_size = 0; + if (p_surface.format & ARRAY_FORMAT_VERTEX) { + if (p_surface.format & ARRAY_FLAG_USE_2D_VERTICES) { + vertex_size = sizeof(float) * 2; + } else { + vertex_size = sizeof(float) * 3; + } + } + if (p_surface.format & ARRAY_FORMAT_NORMAL) { + normal_size += sizeof(uint16_t) * 2; + } + if (p_surface.format & ARRAY_FORMAT_TANGENT) { + tangent_size = sizeof(uint16_t) * 2; + } + int stride = p_surface.vertex_data.size() / p_surface.vertex_count; + int position_stride = vertex_size; + int normal_tangent_stride = normal_size + tangent_size; + + p_surface.vertex_data = _convert_surface_version_1_to_surface_version_2(p_surface.format, p_surface.vertex_data, p_surface.vertex_count, stride, vertex_size, normal_size, position_stride, normal_tangent_stride); + + if (p_surface.blend_shape_data.size() > 0) { + // The size of one blend shape. + int divisor = (vertex_size + normal_size + tangent_size) * p_surface.vertex_count; + ERR_FAIL_COND((p_surface.blend_shape_data.size() % divisor) != 0); + + uint32_t blend_shape_count = p_surface.blend_shape_data.size() / divisor; + + Vector<uint8_t> new_blend_shape_data; + for (uint32_t i = 0; i < blend_shape_count; i++) { + Vector<uint8_t> bs_data = p_surface.blend_shape_data.slice(i * divisor, (i + 1) * divisor); + Vector<uint8_t> blend_shape = _convert_surface_version_1_to_surface_version_2(p_surface.format, bs_data, p_surface.vertex_count, stride, vertex_size, normal_size, position_stride, normal_tangent_stride); + new_blend_shape_data.append_array(blend_shape); + } + + ERR_FAIL_COND(p_surface.blend_shape_data.size() != new_blend_shape_data.size()); + + p_surface.blend_shape_data = new_blend_shape_data; + } + } + p_surface.format &= ~(ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); + p_surface.format |= ARRAY_FLAG_FORMAT_CURRENT_VERSION & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); +} +#endif + void RenderingServer::_bind_methods() { BIND_CONSTANT(NO_INDEX_ARRAY); BIND_CONSTANT(ARRAY_WEIGHTS_SIZE); @@ -1753,6 +2170,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("mesh_create"), &RenderingServer::mesh_create); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_count", "array_index"), &RenderingServer::mesh_surface_get_format_offset); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_vertex_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_vertex_stride); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_normal_tangent_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_normal_tangent_stride); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_attribute_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_attribute_stride); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_skin_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_skin_stride); ClassDB::bind_method(D_METHOD("mesh_add_surface", "mesh", "surface"), &RenderingServer::_mesh_add_surface); @@ -1835,6 +2253,15 @@ void RenderingServer::_bind_methods() { BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_8_BONE_WEIGHTS); BIND_BITFIELD_FLAG(ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY); + BIND_BITFIELD_FLAG(ARRAY_FLAG_COMPRESS_ATTRIBUTES); + + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_VERSION_BASE); + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_VERSION_SHIFT); + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_VERSION_1); + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_VERSION_2); + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_CURRENT_VERSION); + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_VERSION_MASK); + BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP); |