diff options
Diffstat (limited to 'servers/rendering_server.cpp')
-rw-r--r-- | servers/rendering_server.cpp | 884 |
1 files changed, 739 insertions, 145 deletions
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 4c6b765157..655b748d3f 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "rendering_server.h" +#include "rendering_server.compat.inc" #include "core/config/project_settings.h" #include "core/object/worker_thread_pool.h" @@ -103,7 +104,7 @@ PackedInt64Array RenderingServer::_instances_cull_convex_bind(const TypedArray<P } Vector<Plane> planes; for (int i = 0; i < p_convex.size(); ++i) { - Variant v = p_convex[i]; + const Variant &v = p_convex[i]; ERR_FAIL_COND_V(v.get_type() != Variant::PLANE, PackedInt64Array()); planes.push_back(v); } @@ -322,7 +323,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 normal = p_normal.normalized(); + Vector3 tangent = Vector3(p_tangent.x, p_tangent.y, p_tangent.z).normalized(); + float d = p_tangent.w; + Vector3 binormal = normal.cross(tangent).normalized(); + real_t angle; + + Basis tbn = Basis(); + tbn.rows[0] = tangent; + tbn.rows[1] = binormal; + tbn.rows[2] = normal; + tbn.get_axis_angle(r_axis, angle); + r_angle = float(angle); + + 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; + + Basis tbn = Basis(p_axis, angle); + Vector3 tan = tbn.rows[0]; + r_tangent = Vector4(tan.x, tan.y, tan.z, binormal_sign); + r_normal = tbn.rows[2]; +} + +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 +368,51 @@ 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()); + + if (min_val.x >= 0.0 && min_val2.x >= 0.0 && max_val.x <= 1.0 && max_val2.x <= 1.0 && + min_val.y >= 0.0 && min_val2.y >= 0.0 && max_val.y <= 1.0 && max_val2.y <= 1.0) { + // When all channels are in the 0-1 range, we will compress to 16-bit without scaling to + // preserve the bits as best as possible. + r_uv_scale = Vector4(0.0, 0.0, 0.0, 0.0); + } else { + 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; } @@ -372,77 +449,261 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const Vector3 *src = array.ptr(); - // Setting vertices means regenerating the AABB. - AABB aabb; + r_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) { + r_aabb = AABB(src[i], SMALL_VEC3); + } else { + r_aabb.expand_to(src[i]); + } + } + + if (!(p_format & RS::ARRAY_FORMAT_NORMAL)) { + // Early out if we are only setting vertex positions. + for (int i = 0; i < p_vertex_array_len; i++) { + Vector3 pos = (src[i] - r_aabb.position) / r_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); + + 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(); + + 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 && tangent_type != Variant::NIL, ERR_INVALID_PARAMETER); + + // 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] - r_aabb.position) / r_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 if (tangent_type == Variant::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] - r_aabb.position) / r_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 { // No tangent array. + // Set data for vertex, normal, and tangent. + for (int i = 0; i < p_vertex_array_len; i++) { + float angle; + Vector3 axis; + // Generate an arbitrary vector that is tangential to normal. + Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normal_src[i].normalized()); + Vector4 tangent = Vector4(tan.x, tan.y, tan.z, 1.0); + _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] - r_aabb.position) / r_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 }; memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3); if (i == 0) { - aabb = AABB(src[i], SMALL_VEC3); + r_aabb = AABB(src[i], SMALL_VEC3); } else { - aabb.expand_to(src[i]); + r_aabb.expand_to(src[i]); } } } - - r_aabb = aabb; } } break; case RS::ARRAY_NORMAL: { - 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; + // 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); - 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 && type != Variant::NIL, 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), + }; + + if (vector[0] == 0 && vector[1] == 65535) { + // (1, 1) and (0, 1) decode to the same value, but (0, 1) messes with our compression detection. + // So we sanitize here. + vector[0] = 65535; + } + + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); + } + } else if (type == Variant::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(); + + 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), + }; + + if (vector[0] == 0 && vector[1] == 65535) { + // (1, 1) and (0, 1) decode to the same value, but (0, 1) messes with our compression detection. + // So we sanitize here. + vector[0] = 65535; + } + + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); + } + } else { // No tangent array. + ERR_FAIL_COND_V(p_arrays[RS::ARRAY_NORMAL].get_type() != Variant::PACKED_VECTOR3_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(); + // Set data for tangent. + for (int i = 0; i < p_vertex_array_len; i++) { + // Generate an arbitrary vector that is tangential to normal. + Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normal_src[i].normalized()); + Vector2 res = tan.octahedron_tangent_encode(1.0); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + if (vector[0] == 0 && vector[1] == 65535) { + // (1, 1) and (0, 1) decode to the same value, but (0, 1) messes with our compression detection. + // So we sanitize here. + vector[0] = 65535; + } - memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4); + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); + } } } } break; @@ -472,13 +733,23 @@ 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(); + if (p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + for (int i = 0; i < p_vertex_array_len; i++) { + Vector2 vec = src[i]; + if (!r_uv_scale.is_zero_approx()) { + // 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); + } - 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); + 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 +761,21 @@ 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]; + if (!r_uv_scale.is_zero_approx()) { + // 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: @@ -619,7 +902,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_INT32_ARRAY, ERR_INVALID_PARAMETER); Vector<int> indices = p_arrays[ai]; - ERR_FAIL_COND_V(indices.size() == 0, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(indices.is_empty(), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(indices.size() != p_index_array_len, ERR_INVALID_PARAMETER); /* determine whether using 16 or 32 bits indices */ @@ -704,45 +987,62 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint uint32_t RenderingServer::mesh_surface_get_format_offset(BitField<ArrayFormat> p_format, int p_vertex_len, int p_array_index) const { ERR_FAIL_INDEX_V(p_array_index, ARRAY_MAX, 0); - p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; + p_format = uint64_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]; } uint32_t RenderingServer::mesh_surface_get_format_vertex_stride(BitField<ArrayFormat> p_format, int p_vertex_len) const { - p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; + p_format = uint64_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 = uint64_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 ntstr; +} + 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; + p_format = uint64_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; + p_format = uint64_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 +1053,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 +1072,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 +1081,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 +1154,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 +1164,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 +1179,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()) { @@ -889,10 +1194,15 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa array_len = v3.size(); } break; default: { - ERR_FAIL_V(ERR_INVALID_DATA); + ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Vertex array must be a PackedVector2Array or PackedVector3Array."); } break; } ERR_FAIL_COND_V(array_len == 0, ERR_INVALID_DATA); + } else if (i == RS::ARRAY_NORMAL) { + if (p_arrays[RS::ARRAY_TANGENT].get_type() == Variant::NIL) { + // We must use tangents if using normals. + format |= (1ULL << RS::ARRAY_TANGENT); + } } else if (i == RS::ARRAY_BONES) { switch (p_arrays[i].get_type()) { case Variant::PACKED_INT32_ARRAY: { @@ -905,7 +1215,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa } } break; default: { - ERR_FAIL_V(ERR_INVALID_DATA); + ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Bones array must be a PackedInt32Array."); } break; } } else if (i == RS::ARRAY_INDEX) { @@ -930,7 +1240,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 +1248,32 @@ 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."); + } + + 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 +1293,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 +1310,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."); @@ -1003,7 +1327,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa float distance = E; ERR_CONTINUE(distance <= 0.0); Vector<int> indices = p_lods[E]; - ERR_CONTINUE(indices.size() == 0); + ERR_CONTINUE(indices.is_empty()); uint32_t index_count = indices.size(); ERR_CONTINUE(index_count >= (uint32_t)index_array_len); // Should be smaller.. @@ -1048,6 +1372,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 +1386,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 Vector4 &p_uv_scale) 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 +1403,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 +1430,52 @@ 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) { + // We only have vertices to read, so just read them and skip everything else. + if (!(p_format & RS::ARRAY_FORMAT_NORMAL)) { + 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_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 +1484,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); + if (!(p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + Vector<Vector3> arr; + arr.resize(p_vertex_len); - Vector3 *w = arr.ptrw(); + Vector3 *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]]; - - 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); + if (!(p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + Vector<float> arr; + arr.resize(p_vertex_len * 4); - float *w = arr.ptrw(); - - 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 +1539,22 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t arr.resize(p_vertex_len); Vector2 *w = arr.ptrw(); + 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]]); + Vector2 vec = Vector2(float(v[0]) / 65535.0, float(v[1]) / 65535.0); + if (!p_uv_scale.is_zero_approx()) { + vec = (vec - Vector2(0.5, 0.5)) * Vector2(p_uv_scale.x, p_uv_scale.y); + } - 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]); + w[j] = vec; + } + } 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 +1564,20 @@ 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]]); + Vector2 vec = Vector2(float(v[0]) / 65535.0, float(v[1]) / 65535.0); + if (!p_uv_scale.is_zero_approx()) { + vec = (vec - Vector2(0.5, 0.5)) * Vector2(p_uv_scale.z, p_uv_scale.w); + } + w[j] = vec; + } + } 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 +1750,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; - mesh_surface_make_offsets_from_format(bs_format, sd.vertex_count, 0, bs_offsets, vertex_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, normal_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 +1768,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, sd.uv_scale)); } return blend_shape_array; @@ -1389,15 +1782,15 @@ Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p Vector<uint8_t> attrib_data = p_data.attribute_data; Vector<uint8_t> skin_data = p_data.skin_data; - ERR_FAIL_COND_V(vertex_data.size() == 0 && (p_data.format & RS::ARRAY_FORMAT_VERTEX), Array()); + ERR_FAIL_COND_V(vertex_data.is_empty() && (p_data.format & RS::ARRAY_FORMAT_VERTEX), Array()); int vertex_len = p_data.vertex_count; 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, p_data.uv_scale); } #if 0 Array RenderingServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surface) const { @@ -1410,6 +1803,14 @@ Array RenderingServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_su } #endif +Rect2 RenderingServer::debug_canvas_item_get_rect(RID p_item) { +#ifdef TOOLS_ENABLED + return _debug_canvas_item_get_rect(p_item); +#else + return Rect2(); +#endif +} + int RenderingServer::global_shader_uniform_type_get_shader_datatype(GlobalShaderParameterType p_type) { switch (p_type) { case RS::GLOBAL_VAR_TYPE_BOOL: @@ -1549,6 +1950,9 @@ static RS::SurfaceData _dict_to_surf(const Dictionary &p_dictionary) { } sd.aabb = p_dictionary["aabb"]; + if (p_dictionary.has("uv_scale")) { + sd.uv_scale = p_dictionary["uv_scale"]; + } if (p_dictionary.has("lods")) { Array lods = p_dictionary["lods"]; @@ -1610,6 +2014,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 +2068,162 @@ 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; +} + +#ifdef TOOLS_ENABLED +void RenderingServer::set_surface_upgrade_callback(SurfaceUpgradeCallback p_callback) { + surface_upgrade_callback = p_callback; +} + +void RenderingServer::set_warn_on_surface_upgrade(bool p_warn) { + warn_on_surface_upgrade = p_warn; +} +#endif + +#ifndef DISABLE_DEPRECATED +void RenderingServer::fix_surface_compatibility(SurfaceData &p_surface, const String &p_path) { + 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) + ")"); + +#ifdef TOOLS_ENABLED + // Editor callback to ask user about re-saving all meshes. + if (surface_upgrade_callback && warn_on_surface_upgrade) { + surface_upgrade_callback(); + } + + if (warn_on_surface_upgrade) { + WARN_PRINT_ONCE_ED("At least one surface uses an old surface format and needs to be upgraded. The upgrade happens automatically at load time every time until the mesh is saved again or re-imported. Once saved (or re-imported), this mesh will be incompatible with earlier versions of Godot."); + + if (!p_path.is_empty()) { + WARN_PRINT("A surface of " + p_path + " uses an old surface format and needs to be upgraded."); + } + } +#endif + + 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. + + if (p_surface.vertex_data.size() > 0 && p_surface.vertex_count > 0) { + 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 + +#ifdef TOOLS_ENABLED +void RenderingServer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { + String pf = p_function; + if (p_idx == 0) { + if (pf == "global_shader_parameter_set" || pf == "global_shader_parameter_set_override" || + pf == "global_shader_parameter_get" || pf == "global_shader_parameter_get_type" || pf == "global_shader_parameter_remove") { + for (StringName E : global_shader_parameter_get_list()) { + r_options->push_back(E.operator String().quote()); + } + } else if (pf == "has_os_feature") { + for (String E : { "\"rgtc\"", "\"s3tc\"", "\"bptc\"", "\"etc\"", "\"etc2\"", "\"astc\"" }) { + r_options->push_back(E); + } + } + } + Object::get_argument_options(p_function, p_idx, r_options); +} +#endif + void RenderingServer::_bind_methods() { BIND_CONSTANT(NO_INDEX_ARRAY); BIND_CONSTANT(ARRAY_WEIGHTS_SIZE); @@ -1697,7 +2258,10 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_set_path", "texture", "path"), &RenderingServer::texture_set_path); ClassDB::bind_method(D_METHOD("texture_get_path", "texture"), &RenderingServer::texture_get_path); + ClassDB::bind_method(D_METHOD("texture_get_format", "texture"), &RenderingServer::texture_get_format); + ClassDB::bind_method(D_METHOD("texture_set_force_redraw_if_visible", "texture", "enable"), &RenderingServer::texture_set_force_redraw_if_visible); + ClassDB::bind_method(D_METHOD("texture_rd_create", "rd_texture", "layer_type"), &RenderingServer::texture_rd_create, DEFVAL(RenderingServer::TEXTURE_LAYERED_2D_ARRAY)); ClassDB::bind_method(D_METHOD("texture_get_rd_texture", "texture", "srgb"), &RenderingServer::texture_get_rd_texture, DEFVAL(false)); ClassDB::bind_method(D_METHOD("texture_get_native_handle", "texture", "srgb"), &RenderingServer::texture_get_native_handle, DEFVAL(false)); @@ -1750,6 +2314,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); @@ -1832,6 +2397,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); @@ -1854,6 +2428,8 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("multimesh_instance_set_custom_data", "multimesh", "index", "custom_data"), &RenderingServer::multimesh_instance_set_custom_data); ClassDB::bind_method(D_METHOD("multimesh_get_mesh", "multimesh"), &RenderingServer::multimesh_get_mesh); ClassDB::bind_method(D_METHOD("multimesh_get_aabb", "multimesh"), &RenderingServer::multimesh_get_aabb); + ClassDB::bind_method(D_METHOD("multimesh_set_custom_aabb", "multimesh", "aabb"), &RenderingServer::multimesh_set_custom_aabb); + ClassDB::bind_method(D_METHOD("multimesh_get_custom_aabb", "multimesh"), &RenderingServer::multimesh_get_custom_aabb); ClassDB::bind_method(D_METHOD("multimesh_instance_get_transform", "multimesh", "index"), &RenderingServer::multimesh_instance_get_transform); ClassDB::bind_method(D_METHOD("multimesh_instance_get_transform_2d", "multimesh", "index"), &RenderingServer::multimesh_instance_get_transform_2d); ClassDB::bind_method(D_METHOD("multimesh_instance_get_color", "multimesh", "index"), &RenderingServer::multimesh_instance_get_color); @@ -1978,6 +2554,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_box_projection", "probe", "enable"), &RenderingServer::reflection_probe_set_enable_box_projection); ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_shadows", "probe", "enable"), &RenderingServer::reflection_probe_set_enable_shadows); ClassDB::bind_method(D_METHOD("reflection_probe_set_cull_mask", "probe", "layers"), &RenderingServer::reflection_probe_set_cull_mask); + ClassDB::bind_method(D_METHOD("reflection_probe_set_reflection_mask", "probe", "layers"), &RenderingServer::reflection_probe_set_reflection_mask); ClassDB::bind_method(D_METHOD("reflection_probe_set_resolution", "probe", "resolution"), &RenderingServer::reflection_probe_set_resolution); ClassDB::bind_method(D_METHOD("reflection_probe_set_mesh_lod_threshold", "probe", "pixels"), &RenderingServer::reflection_probe_set_mesh_lod_threshold); @@ -2067,11 +2644,14 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &RenderingServer::particles_set_emitting); ClassDB::bind_method(D_METHOD("particles_get_emitting", "particles"), &RenderingServer::particles_get_emitting); ClassDB::bind_method(D_METHOD("particles_set_amount", "particles", "amount"), &RenderingServer::particles_set_amount); + ClassDB::bind_method(D_METHOD("particles_set_amount_ratio", "particles", "ratio"), &RenderingServer::particles_set_amount_ratio); ClassDB::bind_method(D_METHOD("particles_set_lifetime", "particles", "lifetime"), &RenderingServer::particles_set_lifetime); ClassDB::bind_method(D_METHOD("particles_set_one_shot", "particles", "one_shot"), &RenderingServer::particles_set_one_shot); ClassDB::bind_method(D_METHOD("particles_set_pre_process_time", "particles", "time"), &RenderingServer::particles_set_pre_process_time); ClassDB::bind_method(D_METHOD("particles_set_explosiveness_ratio", "particles", "ratio"), &RenderingServer::particles_set_explosiveness_ratio); ClassDB::bind_method(D_METHOD("particles_set_randomness_ratio", "particles", "ratio"), &RenderingServer::particles_set_randomness_ratio); + ClassDB::bind_method(D_METHOD("particles_set_interp_to_end", "particles", "factor"), &RenderingServer::particles_set_interp_to_end); + ClassDB::bind_method(D_METHOD("particles_set_emitter_velocity", "particles", "velocity"), &RenderingServer::particles_set_emitter_velocity); ClassDB::bind_method(D_METHOD("particles_set_custom_aabb", "particles", "aabb"), &RenderingServer::particles_set_custom_aabb); ClassDB::bind_method(D_METHOD("particles_set_speed_scale", "particles", "scale"), &RenderingServer::particles_set_speed_scale); ClassDB::bind_method(D_METHOD("particles_set_use_local_coordinates", "particles", "enable"), &RenderingServer::particles_set_use_local_coordinates); @@ -2228,6 +2808,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_positional_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &RenderingServer::viewport_set_positional_shadow_atlas_quadrant_subdivision); ClassDB::bind_method(D_METHOD("viewport_set_msaa_3d", "viewport", "msaa"), &RenderingServer::viewport_set_msaa_3d); ClassDB::bind_method(D_METHOD("viewport_set_msaa_2d", "viewport", "msaa"), &RenderingServer::viewport_set_msaa_2d); + ClassDB::bind_method(D_METHOD("viewport_set_use_hdr_2d", "viewport", "enabled"), &RenderingServer::viewport_set_use_hdr_2d); ClassDB::bind_method(D_METHOD("viewport_set_screen_space_aa", "viewport", "mode"), &RenderingServer::viewport_set_screen_space_aa); ClassDB::bind_method(D_METHOD("viewport_set_use_taa", "viewport", "enable"), &RenderingServer::viewport_set_use_taa); ClassDB::bind_method(D_METHOD("viewport_set_use_debanding", "viewport", "enable"), &RenderingServer::viewport_set_use_debanding); @@ -2248,6 +2829,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_BILINEAR); BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_FSR); + BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_FSR2); BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_MAX); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED); @@ -2297,6 +2879,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_TYPE_VISIBLE); BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_TYPE_SHADOW); + BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_TYPE_CANVAS); BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_TYPE_MAX); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_DISABLED); @@ -2325,6 +2908,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_OCCLUDERS); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_MOTION_VECTORS); + BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_INTERNAL_BUFFER); BIND_ENUM_CONSTANT(VIEWPORT_VRS_DISABLED); BIND_ENUM_CONSTANT(VIEWPORT_VRS_TEXTURE); @@ -2360,7 +2944,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "use_1d_color_correction", "color_correction"), &RenderingServer::environment_set_adjustment); ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance"), &RenderingServer::environment_set_ssr); ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "power", "detail", "horizon", "sharpness", "light_affect", "ao_channel_affect"), &RenderingServer::environment_set_ssao); - ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective", "sky_affect"), &RenderingServer::environment_set_fog); + ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective", "sky_affect", "fog_mode"), &RenderingServer::environment_set_fog, DEFVAL(RS::ENV_FOG_MODE_EXPONENTIAL)); ClassDB::bind_method(D_METHOD("environment_set_sdfgi", "env", "enable", "cascades", "min_cell_size", "y_scale", "use_occlusion", "bounce_feedback", "read_sky", "energy", "normal_bias", "probe_bias"), &RenderingServer::environment_set_sdfgi); ClassDB::bind_method(D_METHOD("environment_set_volumetric_fog", "env", "enable", "density", "albedo", "emission", "emission_energy", "anisotropy", "length", "p_detail_spread", "gi_inject", "temporal_reprojection", "temporal_reprojection_amount", "ambient_inject", "sky_affect"), &RenderingServer::environment_set_volumetric_fog); @@ -2403,6 +2987,9 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_REPLACE); BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_MIX); + BIND_ENUM_CONSTANT(ENV_FOG_MODE_EXPONENTIAL); + BIND_ENUM_CONSTANT(ENV_FOG_MODE_DEPTH); + BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_LINEAR); BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_REINHARD); BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_FILMIC); @@ -2636,6 +3223,8 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_item_set_visibility_notifier", "item", "enable", "area", "enter_callable", "exit_callable"), &RenderingServer::canvas_item_set_visibility_notifier); ClassDB::bind_method(D_METHOD("canvas_item_set_canvas_group_mode", "item", "mode", "clear_margin", "fit_empty", "fit_margin", "blur_mipmaps"), &RenderingServer::canvas_item_set_canvas_group_mode, DEFVAL(5.0), DEFVAL(false), DEFVAL(0.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("debug_canvas_item_get_rect", "item"), &RenderingServer::debug_canvas_item_get_rect); + BIND_ENUM_CONSTANT(NINE_PATCH_STRETCH); BIND_ENUM_CONSTANT(NINE_PATCH_TILE); BIND_ENUM_CONSTANT(NINE_PATCH_TILE_FIT); @@ -2780,7 +3369,6 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_default_clear_color"), &RenderingServer::get_default_clear_color); ClassDB::bind_method(D_METHOD("set_default_clear_color", "color"), &RenderingServer::set_default_clear_color); - ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingServer::has_feature); ClassDB::bind_method(D_METHOD("has_os_feature", "feature"), &RenderingServer::has_os_feature); ClassDB::bind_method(D_METHOD("set_debug_generate_wireframes", "generate"), &RenderingServer::set_debug_generate_wireframes); @@ -2798,9 +3386,6 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(RENDERING_INFO_BUFFER_MEM_USED); BIND_ENUM_CONSTANT(RENDERING_INFO_VIDEO_MEM_USED); - BIND_ENUM_CONSTANT(FEATURE_SHADERS); - BIND_ENUM_CONSTANT(FEATURE_MULTITHREADED); - ADD_SIGNAL(MethodInfo("frame_pre_draw")); ADD_SIGNAL(MethodInfo("frame_post_draw")); @@ -2808,6 +3393,15 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("force_draw", "swap_buffers", "frame_step"), &RenderingServer::draw, DEFVAL(true), DEFVAL(0.0)); ClassDB::bind_method(D_METHOD("get_rendering_device"), &RenderingServer::get_rendering_device); ClassDB::bind_method(D_METHOD("create_local_rendering_device"), &RenderingServer::create_local_rendering_device); + + ClassDB::bind_method(D_METHOD("call_on_render_thread", "callable"), &RenderingServer::call_on_render_thread); + +#ifndef DISABLE_DEPRECATED + ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingServer::has_feature); + + BIND_ENUM_CONSTANT(FEATURE_SHADERS); + BIND_ENUM_CONSTANT(FEATURE_MULTITHREADED); +#endif } void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry3D::MeshData &p_mesh_data) { @@ -2895,7 +3489,7 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"), 2); GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality.mobile", 0); - GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/2d/shadow_atlas/size", PROPERTY_HINT_RANGE, "128,16384"), 2048); // Number of commands that can be drawn per frame. GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/gl_compatibility/item_buffer_size", PROPERTY_HINT_RANGE, "128,1048576,1"), 16384); @@ -2906,15 +3500,15 @@ void RenderingServer::init() { GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug", false); GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug.release", true); - GLOBAL_DEF_RST("rendering/reflections/sky_reflections/roughness_layers", 8); // Assumes a 256x256 cubemap + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/reflections/sky_reflections/roughness_layers", PROPERTY_HINT_RANGE, "1,32,1"), 8); // Assumes a 256x256 cubemap GLOBAL_DEF_RST("rendering/reflections/sky_reflections/texture_array_reflections", true); GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections.mobile", false); - GLOBAL_DEF_RST("rendering/reflections/sky_reflections/ggx_samples", 32); - GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples.mobile", 16); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/reflections/sky_reflections/ggx_samples", PROPERTY_HINT_RANGE, "0,256,1"), 32); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/sky_reflections/ggx_samples.mobile", PROPERTY_HINT_RANGE, "0,128,1"), 16); GLOBAL_DEF("rendering/reflections/sky_reflections/fast_filter_high_quality", false); - GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size", 256); - GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size.mobile", 128); - GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_count", 64); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_size", PROPERTY_HINT_RANGE, "0,4096,1"), 256); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_size.mobile", PROPERTY_HINT_RANGE, "0,2048,1"), 128); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_count", PROPERTY_HINT_RANGE, "0,256,1"), 64); GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false); @@ -2925,8 +3519,8 @@ void RenderingServer::init() { GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley", false); GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley.mobile", true); - GLOBAL_DEF("rendering/driver/depth_prepass/enable", true); - GLOBAL_DEF("rendering/driver/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple"); + GLOBAL_DEF_RST("rendering/driver/depth_prepass/enable", true); + GLOBAL_DEF_RST("rendering/driver/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple"); GLOBAL_DEF_RST("rendering/textures/default_filters/use_nearest_mipmap_filter", false); GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/textures/default_filters/anisotropic_filtering_level", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Faster),4× (Fast),8× (Average),16× (Slow)")), 2); @@ -2953,7 +3547,7 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01"), 0.25); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01"), 0.18); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/scaling_3d/mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast)"), 0); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/scaling_3d/mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast),FSR 2.2 (Slow)"), 0); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/scaling_3d/scale", PROPERTY_HINT_RANGE, "0.25,2.0,0.01"), 1.0); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/scaling_3d/fsr_sharpness", PROPERTY_HINT_RANGE, "0,2,0.1"), 0.2f); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/textures/default_filters/texture_mipmap_bias", PROPERTY_HINT_RANGE, "-2,2,0.001"), 0.0f); @@ -2961,7 +3555,7 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/textures/decals/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Linear (Fast),Nearest Mipmap (Fast),Linear Mipmap (Fast),Nearest Mipmap Anisotropic (Average),Linear Mipmap Anisotropic (Average)"), DECAL_FILTER_LINEAR_MIPMAPS); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/textures/light_projectors/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Linear (Fast),Nearest Mipmap (Fast),Linear Mipmap (Fast),Nearest Mipmap Anisotropic (Average),Linear Mipmap Anisotropic (Average)"), LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS); - GLOBAL_DEF_RST("rendering/occlusion_culling/occlusion_rays_per_thread", 512); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/occlusion_culling/occlusion_rays_per_thread", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), 512); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/glow/upscale_mode", PROPERTY_HINT_ENUM, "Linear (Fast),Bicubic (Slow)"), 1); GLOBAL_DEF("rendering/environment/glow/upscale_mode.mobile", 0); @@ -2972,9 +3566,10 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"), 0.05); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"), 0.01); - GLOBAL_DEF("rendering/limits/global_shader_variables/buffer_size", 65536); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/global_shader_variables/buffer_size", PROPERTY_HINT_RANGE, "1,1048576,1"), 65536); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/lightmapping/probe_capture/update_speed", PROPERTY_HINT_RANGE, "0.001,256,0.001"), 15); + GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/lightmapping/primitive_meshes/texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.2); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/probe_ray_count", PROPERTY_HINT_ENUM, "8 (Fastest),16,32,64,96,128 (Slowest)"), 1); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/frames_to_converge", PROPERTY_HINT_ENUM, "5 (Less Latency but Lower Quality),10,15,20,25,30 (More Latency but Higher Quality)"), 5); @@ -2986,7 +3581,6 @@ void RenderingServer::init() { GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"), 10); GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 1000); - GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 500); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1"), 512); |