summaryrefslogtreecommitdiffstats
path: root/servers/rendering_server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering_server.cpp')
-rw-r--r--servers/rendering_server.cpp657
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);