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.cpp884
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);