diff options
475 files changed, 6704 insertions, 3953 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 690e74855f..0b4abac1af 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -52,5 +52,8 @@ body: attributes: label: Minimal reproduction project description: | - A small Godot project which reproduces the issue. Highly recommended to speed up troubleshooting. - Drag and drop a ZIP archive to upload it. Be sure to not include the ".godot" folder in the archive. + A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the `.godot` folder in the archive (but keep `project.godot`). + Required, unless the reproduction steps are trivial and don't require any project files to be followed. In this case, write "N/A" in the field. + Drag and drop a ZIP archive to upload it. **Do not select another field until the project is done uploading.** + validations: + required: true diff --git a/.gitignore b/.gitignore index ca7d850f9e..15c1e50277 100644 --- a/.gitignore +++ b/.gitignore @@ -318,6 +318,7 @@ _ReSharper*/ # Others ClientBin/ +enc_temp_folder/ ~$* *.dbmdl *.dbproj.schemaview diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a1e8d3a59d..63e6a89e64 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,6 +63,8 @@ understand that: - What happens to you may not happen to other users. - We can't take the time to look at your project, understand how it is set up and then figure out why it's failing. +- On the contributors' end, recreating a test project from scratch takes valuable + time that can be saved by uploading a *minimal* project. To speed up our work, **please upload a minimal project** that isolates and reproduces the issue. This is always the **best way for us to fix it**. @@ -74,7 +76,7 @@ if your ZIP file isn't accepted by GitHub because it's too large. We recommend always attaching a minimal reproduction project, even if the issue may seem simple to reproduce manually. -**Note for C# users:** If your issue is not .NET-specific, please upload a +**Note for C# users:** If your issue is *not* .NET-specific, please upload a minimal reproduction project written in GDScript. This will make it easier for contributors to reproduce the issue locally as not everyone has a .NET setup available. diff --git a/core/io/image.cpp b/core/io/image.cpp index 65addaf964..21146dd80c 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -1341,78 +1341,126 @@ void Image::crop(int p_width, int p_height) { void Image::rotate_90(ClockDirection p_direction) { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); - ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); - ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); - - int saved_width = height; - int saved_height = width; - - if (width != height) { - int n = MAX(width, height); - resize(n, n, INTERPOLATE_NEAREST); - } + ERR_FAIL_COND_MSG(width <= 0, "The Image width specified (" + itos(width) + " pixels) must be greater than 0 pixels."); + ERR_FAIL_COND_MSG(height <= 0, "The Image height specified (" + itos(height) + " pixels) must be greater than 0 pixels."); bool used_mipmaps = has_mipmaps(); if (used_mipmaps) { clear_mipmaps(); } + // In-place 90 degrees rotation by following the permutation cycles. { - uint8_t *w = data.ptrw(); - uint8_t src[16]; - uint8_t dst[16]; + // Explanation by example (clockwise): + // + // abc da + // def -> eb + // fc + // + // In memory: + // 012345 012345 + // abcdef -> daebfc + // + // Permutation cycles: + // (0 --a--> 1 --b--> 3 --d--> 0) + // (2 --c--> 5 --f--> 4 --e--> 2) + // + // Applying cycles (backwards): + // 0->s s=a (store) + // 3->0 abcdef -> dbcdef + // 1->3 dbcdef -> dbcbef + // s->1 dbcbef -> dacbef + // + // 2->s s=c + // 4->2 dacbef -> daebef + // 5->4 daebef -> daebff + // s->5 daebff -> daebfc + + const int w = width; + const int h = height; + const int size = w * h; + + uint8_t *data_ptr = data.ptrw(); uint32_t pixel_size = get_format_pixel_size(format); - // Flip. + uint8_t single_pixel_buffer[16]; - if (p_direction == CLOCKWISE) { - for (int y = 0; y < height / 2; y++) { - for (int x = 0; x < width; x++) { - _get_pixelb(x, y, pixel_size, w, src); - _get_pixelb(x, height - y - 1, pixel_size, w, dst); +#define PREV_INDEX_IN_CYCLE(index) (p_direction == CLOCKWISE) ? ((h - 1 - (index % h)) * w + (index / h)) : ((index % h) * w + (w - 1 - (index / h))) - _put_pixelb(x, height - y - 1, pixel_size, w, src); - _put_pixelb(x, y, pixel_size, w, dst); + if (w == h) { // Square case, 4-length cycles only (plus irrelevant thus skipped 1-length cycle in the middle for odd-sized squares). + for (int y = 0; y < h / 2; y++) { + for (int x = 0; x < (w + 1) / 2; x++) { + int current = y * w + x; + memcpy(single_pixel_buffer, data_ptr + current * pixel_size, pixel_size); + for (int i = 0; i < 3; i++) { + int prev = PREV_INDEX_IN_CYCLE(current); + memcpy(data_ptr + current * pixel_size, data_ptr + prev * pixel_size, pixel_size); + current = prev; + } + memcpy(data_ptr + current * pixel_size, single_pixel_buffer, pixel_size); } } - } else { - for (int y = 0; y < height; y++) { - for (int x = 0; x < width / 2; x++) { - _get_pixelb(x, y, pixel_size, w, src); - _get_pixelb(width - x - 1, y, pixel_size, w, dst); + } else { // Rectangular case (w != h), kinda unpredictable cycles. + int permuted_pixels_count = 0; + + for (int i = 0; i < size; i++) { + int prev = PREV_INDEX_IN_CYCLE(i); + if (prev == i) { + // 1-length cycle, pixel remains at the same index. + permuted_pixels_count++; + continue; + } - _put_pixelb(width - x - 1, y, pixel_size, w, src); - _put_pixelb(x, y, pixel_size, w, dst); + // Check whether we already processed this cycle. + // We iterate over it and if we'll find an index smaller than `i` then we already + // processed this cycle because we always start at the smallest index in the cycle. + // TODO: Improve this naive approach, can be done better. + while (prev > i) { + prev = PREV_INDEX_IN_CYCLE(prev); + } + if (prev < i) { + continue; } - } - } - // Transpose. + // Save the in-cycle pixel with the smallest index (`i`). + memcpy(single_pixel_buffer, data_ptr + i * pixel_size, pixel_size); - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - if (x < y) { - _get_pixelb(x, y, pixel_size, w, src); - _get_pixelb(y, x, pixel_size, w, dst); + // Overwrite pixels one by one by the preceding pixel in the cycle. + int current = i; + prev = PREV_INDEX_IN_CYCLE(current); + while (prev != i) { + memcpy(data_ptr + current * pixel_size, data_ptr + prev * pixel_size, pixel_size); + permuted_pixels_count++; - _put_pixelb(y, x, pixel_size, w, src); - _put_pixelb(x, y, pixel_size, w, dst); + current = prev; + prev = PREV_INDEX_IN_CYCLE(current); + }; + + // Overwrite the remaining pixel in the cycle by the saved pixel with the smallest index. + memcpy(data_ptr + current * pixel_size, single_pixel_buffer, pixel_size); + permuted_pixels_count++; + + if (permuted_pixels_count == size) { + break; } } + + width = h; + height = w; } + +#undef PREV_INDEX_IN_CYCLE } - if (saved_width != saved_height) { - resize(saved_width, saved_height, INTERPOLATE_NEAREST); - } else if (used_mipmaps) { + if (used_mipmaps) { generate_mipmaps(); } } void Image::rotate_180() { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); - ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); - ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); + ERR_FAIL_COND_MSG(width <= 0, "The Image width specified (" + itos(width) + " pixels) must be greater than 0 pixels."); + ERR_FAIL_COND_MSG(height <= 0, "The Image height specified (" + itos(height) + " pixels) must be greater than 0 pixels."); bool used_mipmaps = has_mipmaps(); if (used_mipmaps) { @@ -1420,19 +1468,21 @@ void Image::rotate_180() { } { - uint8_t *w = data.ptrw(); - uint8_t src[16]; - uint8_t dst[16]; + uint8_t *data_ptr = data.ptrw(); uint32_t pixel_size = get_format_pixel_size(format); - for (int y = 0; y < height / 2; y++) { - for (int x = 0; x < width; x++) { - _get_pixelb(x, y, pixel_size, w, src); - _get_pixelb(width - x - 1, height - y - 1, pixel_size, w, dst); + uint8_t single_pixel_buffer[16]; - _put_pixelb(width - x - 1, height - y - 1, pixel_size, w, src); - _put_pixelb(x, y, pixel_size, w, dst); - } + uint8_t *from_begin_ptr = data_ptr; + uint8_t *from_end_ptr = data_ptr + (width * height - 1) * pixel_size; + + while (from_begin_ptr < from_end_ptr) { + memcpy(single_pixel_buffer, from_begin_ptr, pixel_size); + memcpy(from_begin_ptr, from_end_ptr, pixel_size); + memcpy(from_end_ptr, single_pixel_buffer, pixel_size); + + from_begin_ptr += pixel_size; + from_end_ptr -= pixel_size; } } diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index aa1b323db2..0118b4c6af 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -107,6 +107,8 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String & } Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encrypt) { + ERR_FAIL_COND_V_MSG(file.is_null(), ERR_INVALID_PARAMETER, "File must be opened before use."); + Ref<FileAccess> f = FileAccess::open(p_src, FileAccess::READ); if (f.is_null()) { return ERR_FILE_CANT_OPEN; diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 41ec6d8ce3..d7bb025b69 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -487,7 +487,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { euler.z = 0.0f; } return euler; - } break; + } case EulerOrder::XZY: { // Euler angles in XZY convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix @@ -516,7 +516,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { euler.z = -Math_PI / 2.0f; } return euler; - } break; + } case EulerOrder::YXZ: { // Euler angles in YXZ convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix @@ -554,7 +554,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { } return euler; - } break; + } case EulerOrder::YZX: { // Euler angles in YZX convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix @@ -639,7 +639,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { euler.z = -Math::atan2(rows[0][1], rows[1][1]); } return euler; - } break; + } default: { ERR_FAIL_V_MSG(Vector3(), "Invalid parameter for get_euler(order)"); } diff --git a/core/math/color.h b/core/math/color.h index a23a4953ce..5630539aa7 100644 --- a/core/math/color.h +++ b/core/math/color.h @@ -105,12 +105,10 @@ struct _NO_DISCARD_ Color { _FORCE_INLINE_ Color lerp(const Color &p_to, float p_weight) const { Color res = *this; - - res.r += (p_weight * (p_to.r - r)); - res.g += (p_weight * (p_to.g - g)); - res.b += (p_weight * (p_to.b - b)); - res.a += (p_weight * (p_to.a - a)); - + res.r = Math::lerp(res.r, p_to.r, p_weight); + res.g = Math::lerp(res.g, p_to.g, p_weight); + res.b = Math::lerp(res.b, p_to.b, p_weight); + res.a = Math::lerp(res.a, p_to.a, p_weight); return res; } diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 0af529ad98..8dff8e6e7e 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -364,6 +364,26 @@ public: return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3; } + static _ALWAYS_INLINE_ double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + double omt = (1.0 - p_t); + double omt2 = omt * omt; + double t2 = p_t * p_t; + + double d = (p_control_1 - p_start) * 3.0 * omt2 + (p_control_2 - p_control_1) * 6.0 * omt * p_t + (p_end - p_control_2) * 3.0 * t2; + return d; + } + + static _ALWAYS_INLINE_ float bezier_derivative(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + float omt = (1.0f - p_t); + float omt2 = omt * omt; + float t2 = p_t * p_t; + + float d = (p_control_1 - p_start) * 3.0f * omt2 + (p_control_2 - p_control_1) * 6.0f * omt * p_t + (p_end - p_control_2) * 3.0f * t2; + return d; + } + static _ALWAYS_INLINE_ double lerp_angle(double p_from, double p_to, double p_weight) { double difference = fmod(p_to - p_from, Math_TAU); double distance = fmod(2.0 * difference, Math_TAU) - difference; diff --git a/core/math/projection.cpp b/core/math/projection.cpp index 70cc9b5f7c..9af388b081 100644 --- a/core/math/projection.cpp +++ b/core/math/projection.cpp @@ -181,7 +181,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); return new_plane; - } break; + } case PLANE_FAR: { Plane new_plane = Plane(matrix[3] - matrix[2], matrix[7] - matrix[6], @@ -191,7 +191,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); return new_plane; - } break; + } case PLANE_LEFT: { Plane new_plane = Plane(matrix[3] + matrix[0], matrix[7] + matrix[4], @@ -201,7 +201,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); return new_plane; - } break; + } case PLANE_TOP: { Plane new_plane = Plane(matrix[3] - matrix[1], matrix[7] - matrix[5], @@ -211,7 +211,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); return new_plane; - } break; + } case PLANE_RIGHT: { Plane new_plane = Plane(matrix[3] - matrix[0], matrix[7] - matrix[4], @@ -221,7 +221,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); return new_plane; - } break; + } case PLANE_BOTTOM: { Plane new_plane = Plane(matrix[3] + matrix[1], matrix[7] + matrix[5], @@ -231,7 +231,7 @@ Plane Projection::get_projection_plane(Planes p_plane) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); return new_plane; - } break; + } } return Plane(); diff --git a/core/math/vector2.h b/core/math/vector2.h index 5775d8e735..835c3d1ba6 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -112,6 +112,7 @@ struct _NO_DISCARD_ Vector2 { _FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const; _FORCE_INLINE_ Vector2 cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const; _FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const; + _FORCE_INLINE_ Vector2 bezier_derivative(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const; Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const; @@ -242,10 +243,8 @@ _FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const { Vector2 Vector2::lerp(const Vector2 &p_to, const real_t p_weight) const { Vector2 res = *this; - - res.x += (p_weight * (p_to.x - x)); - res.y += (p_weight * (p_to.y - y)); - + res.x = Math::lerp(res.x, p_to.x, p_weight); + res.y = Math::lerp(res.y, p_to.y, p_weight); return res; } @@ -278,15 +277,16 @@ Vector2 Vector2::cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_ Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const { Vector2 res = *this; + res.x = Math::bezier_interpolate(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t); + res.y = Math::bezier_interpolate(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t); + return res; +} - /* Formula from Wikipedia article on Bezier curves. */ - real_t omt = (1.0 - p_t); - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = p_t * p_t; - real_t t3 = t2 * p_t; - - return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; +Vector2 Vector2::bezier_derivative(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const { + Vector2 res = *this; + res.x = Math::bezier_derivative(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t); + res.y = Math::bezier_derivative(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t); + return res; } Vector2 Vector2::direction_to(const Vector2 &p_to) const { diff --git a/core/math/vector3.h b/core/math/vector3.h index 19771eb312..dc74096690 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -100,6 +100,7 @@ struct _NO_DISCARD_ Vector3 { _FORCE_INLINE_ Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const; _FORCE_INLINE_ Vector3 cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const; _FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const; + _FORCE_INLINE_ Vector3 bezier_derivative(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const; Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const; @@ -208,10 +209,11 @@ Vector3 Vector3::round() const { } Vector3 Vector3::lerp(const Vector3 &p_to, const real_t p_weight) const { - return Vector3( - x + (p_weight * (p_to.x - x)), - y + (p_weight * (p_to.y - y)), - z + (p_weight * (p_to.z - z))); + Vector3 res = *this; + res.x = Math::lerp(res.x, p_to.x, p_weight); + res.y = Math::lerp(res.y, p_to.y, p_weight); + res.z = Math::lerp(res.z, p_to.z, p_weight); + return res; } Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const { @@ -254,15 +256,18 @@ Vector3 Vector3::cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_ Vector3 Vector3::bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const { Vector3 res = *this; + res.x = Math::bezier_interpolate(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t); + res.y = Math::bezier_interpolate(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t); + res.z = Math::bezier_interpolate(res.z, p_control_1.z, p_control_2.z, p_end.z, p_t); + return res; +} - /* Formula from Wikipedia article on Bezier curves. */ - real_t omt = (1.0 - p_t); - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = p_t * p_t; - real_t t3 = t2 * p_t; - - return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; +Vector3 Vector3::bezier_derivative(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const { + Vector3 res = *this; + res.x = Math::bezier_derivative(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t); + res.y = Math::bezier_derivative(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t); + res.z = Math::bezier_derivative(res.z, p_control_1.z, p_control_2.z, p_end.z, p_t); + return res; } real_t Vector3::distance_to(const Vector3 &p_to) const { diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp index 3b189f7ed4..5ddf2bb6f6 100644 --- a/core/math/vector4.cpp +++ b/core/math/vector4.cpp @@ -130,11 +130,12 @@ Vector4 Vector4::round() const { } Vector4 Vector4::lerp(const Vector4 &p_to, const real_t p_weight) const { - return Vector4( - x + (p_weight * (p_to.x - x)), - y + (p_weight * (p_to.y - y)), - z + (p_weight * (p_to.z - z)), - w + (p_weight * (p_to.w - w))); + Vector4 res = *this; + res.x = Math::lerp(res.x, p_to.x, p_weight); + res.y = Math::lerp(res.y, p_to.y, p_weight); + res.z = Math::lerp(res.z, p_to.z, p_weight); + res.w = Math::lerp(res.w, p_to.w, p_weight); + return res; } Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const { diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 056c57a5f1..36a0d03aaf 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -409,7 +409,9 @@ bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_v if (values.has(p_name)) { Variant defval; if (script->get_property_default_value(p_name, defval)) { - if (defval == p_value) { + // The evaluate function ensures that a NIL variant is equal to e.g. an empty Resource. + // Simply doing defval == p_value does not do this. + if (Variant::evaluate(Variant::OP_EQUAL, defval, p_value)) { values.erase(p_name); return true; } @@ -419,7 +421,7 @@ bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_v } else { Variant defval; if (script->get_property_default_value(p_name, defval)) { - if (defval != p_value) { + if (Variant::evaluate(Variant::OP_NOT_EQUAL, defval, p_value)) { values[p_name] = p_value; } return true; diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 8993f9667d..4e26b61334 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -161,6 +161,18 @@ bool CharString::operator<(const CharString &p_right) const { return is_str_less(get_data(), p_right.get_data()); } +bool CharString::operator==(const CharString &p_right) const { + if (length() == 0) { + // True if both have length 0, false if only p_right has a length + return p_right.length() == 0; + } else if (p_right.length() == 0) { + // False due to unequal length + return false; + } + + return strcmp(ptr(), p_right.ptr()) == 0; +} + CharString &CharString::operator+=(char p_char) { const int lhs_len = length(); resize(lhs_len + 2); @@ -1256,8 +1268,8 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int return ret; } -Vector<float> String::split_floats(const String &p_splitter, bool p_allow_empty) const { - Vector<float> ret; +Vector<double> String::split_floats(const String &p_splitter, bool p_allow_empty) const { + Vector<double> ret; int from = 0; int len = length(); diff --git a/core/string/ustring.h b/core/string/ustring.h index 8af74584f3..ed3848fb8a 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -156,6 +156,7 @@ public: void operator=(const char *p_cstr); bool operator<(const CharString &p_right) const; + bool operator==(const CharString &p_right) const; CharString &operator+=(char p_char); int length() const { return size() ? size() - 1 : 0; } const char *get_data() const; @@ -348,7 +349,7 @@ public: Vector<String> split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const; Vector<String> rsplit(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const; Vector<String> split_spaces() const; - Vector<float> split_floats(const String &p_splitter, bool p_allow_empty = true) const; + Vector<double> split_floats(const String &p_splitter, bool p_allow_empty = true) const; Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const; Vector<int> split_ints(const String &p_splitter, bool p_allow_empty = true) const; Vector<int> split_ints_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const; diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h index 456a7b01ed..059f30df38 100644 --- a/core/templates/hashfuncs.h +++ b/core/templates/hashfuncs.h @@ -310,6 +310,7 @@ struct HashMapHasherDefault { static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); } static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); } static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); } + static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.ptr()); } static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); } static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); } static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); } diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index a231a956bf..8f0e47a520 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1615,6 +1615,7 @@ static void _register_variant_builtin_methods() { bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray()); bind_method(Vector2, cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray()); bind_method(Vector2, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray()); + bind_method(Vector2, bezier_derivative, sarray("control_1", "control_2", "end", "t"), varray()); bind_method(Vector2, max_axis_index, sarray(), varray()); bind_method(Vector2, min_axis_index, sarray(), varray()); bind_method(Vector2, move_toward, sarray("to", "delta"), varray()); @@ -1707,6 +1708,7 @@ static void _register_variant_builtin_methods() { bind_method(Vector3, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray()); bind_method(Vector3, cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray()); bind_method(Vector3, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray()); + bind_method(Vector3, bezier_derivative, sarray("control_1", "control_2", "end", "t"), varray()); bind_method(Vector3, move_toward, sarray("to", "delta"), varray()); bind_method(Vector3, dot, sarray("with"), varray()); bind_method(Vector3, cross, sarray("with"), varray()); diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 3843c32bcc..bf4f761f2b 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -335,6 +335,9 @@ struct VariantUtilityFunctions { } switch (from.get_type()) { + case Variant::INT: { + return lerpf(VariantInternalAccessor<int64_t>::get(&from), to, weight); + } break; case Variant::FLOAT: { return lerpf(VariantInternalAccessor<double>::get(&from), to, weight); } break; @@ -389,6 +392,10 @@ struct VariantUtilityFunctions { return Math::bezier_interpolate(p_start, p_control_1, p_control_2, p_end, p_t); } + static inline double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) { + return Math::bezier_derivative(p_start, p_control_1, p_control_2, p_end, p_t); + } + static inline double lerp_angle(double from, double to, double weight) { return Math::lerp_angle(from, to, weight); } @@ -1437,6 +1444,7 @@ void Variant::_register_variant_utility_functions() { FUNCBINDR(cubic_interpolate_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(cubic_interpolate_angle_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(bezier_interpolate, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(bezier_derivative, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(remap, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index b9965508e2..3eb0d3eaf3 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -106,6 +106,17 @@ [/codeblock] </description> </method> + <method name="bezier_derivative"> + <return type="float" /> + <param index="0" name="start" type="float" /> + <param index="1" name="control_1" type="float" /> + <param index="2" name="control_2" type="float" /> + <param index="3" name="end" type="float" /> + <param index="4" name="t" type="float" /> + <description> + Returns the derivative at the given [param t] on a one-dimensional [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by the given [param control_1], [param control_2], and [param end] points. + </description> + </method> <method name="bezier_interpolate"> <return type="float" /> <param index="0" name="start" type="float" /> @@ -527,7 +538,7 @@ <param index="2" name="weight" type="Variant" /> <description> Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. If this is not desired, use [method clamp] on the result of this function. - Both [param from] and [param to] must be the same type. Supported types: [float], [Vector2], [Vector3], [Vector4], [Color], [Quaternion], [Basis]. + Both [param from] and [param to] must be the same type. Supported types: [int], [float], [Vector2], [Vector3], [Vector4], [Color], [Quaternion], [Basis]. [codeblock] lerp(0, 4, 0.75) # Returns 3.0 [/codeblock] diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index 008296713d..af8d9c416f 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -568,13 +568,6 @@ The animation step value. </member> </members> - <signals> - <signal name="tracks_changed"> - <description> - Emitted when there's a change in the list of tracks, e.g. tracks are added, moved or have changed paths. - </description> - </signal> - </signals> <constants> <constant name="TYPE_VALUE" value="0" enum="TrackType"> Value tracks set values in node properties, but only those which can be interpolated. For 3D position/rotation/scale, using the dedicated [constant TYPE_POSITION_3D], [constant TYPE_ROTATION_3D] and [constant TYPE_SCALE_3D] track types instead of [constant TYPE_VALUE] is recommended for performance reasons. diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml index ab948dd0de..b9c8ab0f6c 100644 --- a/doc/classes/ArrayMesh.xml +++ b/doc/classes/ArrayMesh.xml @@ -25,10 +25,12 @@ m.mesh = arr_mesh [/gdscript] [csharp] - var vertices = new Godot.Collections.Array<Vector3>(); - vertices.Add(new Vector3(0, 1, 0)); - vertices.Add(new Vector3(1, 0, 0)); - vertices.Add(new Vector3(0, 0, 1)); + var vertices = new Vector3[] + { + new Vector3(0, 1, 0), + new Vector3(1, 0, 0), + new Vector3(0, 0, 1), + }; // Initialize the ArrayMesh. var arrMesh = new ArrayMesh(); @@ -38,7 +40,7 @@ // Create the Mesh. arrMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, arrays); - var m = new MeshInstance(); + var m = new MeshInstance3D(); m.Mesh = arrMesh; [/csharp] [/codeblocks] diff --git a/doc/classes/AudioEffectDistortion.xml b/doc/classes/AudioEffectDistortion.xml index 6bd8522459..ef39a9c60e 100644 --- a/doc/classes/AudioEffectDistortion.xml +++ b/doc/classes/AudioEffectDistortion.xml @@ -2,11 +2,11 @@ <class name="AudioEffectDistortion" inherits="AudioEffect" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Adds a distortion audio effect to an Audio bus. - Modify the sound to make it distorted. + Modifies the sound to make it distorted. </brief_description> <description> Different types are available: clip, tan, lo-fi (bit crushing), overdrive, or waveshape. - By distorting the waveform the frequency content change, which will often make the sound "crunchy" or "abrasive". For games, it can simulate sound coming from some saturated device or speaker very efficiently. + By distorting the waveform the frequency content changes, which will often make the sound "crunchy" or "abrasive". For games, it can simulate sound coming from some saturated device or speaker very efficiently. </description> <tutorials> <link title="Audio buses">$DOCS_URL/tutorials/audio/audio_buses.html</link> @@ -22,10 +22,10 @@ Distortion type. </member> <member name="post_gain" type="float" setter="set_post_gain" getter="get_post_gain" default="0.0"> - Increases or decreases the volume after the effect. Value can range from -80 to 24. + Increases or decreases the volume after the effect, in decibels. Value can range from -80 to 24. </member> <member name="pre_gain" type="float" setter="set_pre_gain" getter="get_pre_gain" default="0.0"> - Increases or decreases the volume before the effect. Value can range from -60 to 60. + Increases or decreases the volume before the effect, in decibels. Value can range from -60 to 60. </member> </members> <constants> @@ -35,10 +35,10 @@ <constant name="MODE_ATAN" value="1" enum="Mode"> </constant> <constant name="MODE_LOFI" value="2" enum="Mode"> - Low-resolution digital distortion effect. You can use it to emulate the sound of early digital audio devices. + Low-resolution digital distortion effect (bit depth reduction). You can use it to emulate the sound of early digital audio devices. </constant> <constant name="MODE_OVERDRIVE" value="3" enum="Mode"> - Emulates the warm distortion produced by a field effect transistor, which is commonly used in solid-state musical instrument amplifiers. + Emulates the warm distortion produced by a field effect transistor, which is commonly used in solid-state musical instrument amplifiers. The [member drive] property has no effect in this mode. </constant> <constant name="MODE_WAVESHAPE" value="4" enum="Mode"> Waveshaper distortions are used mainly by electronic musicians to achieve an extra-abrasive sound. diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml index ae86fd0e66..81755b580f 100644 --- a/doc/classes/AudioStreamPlayer2D.xml +++ b/doc/classes/AudioStreamPlayer2D.xml @@ -29,7 +29,7 @@ <return type="void" /> <param index="0" name="from_position" type="float" default="0.0" /> <description> - Plays the audio from the given position [param from_position], in seconds. + Queues the audio to play on the next physics frame, from the given position [param from_position], in seconds. </description> </method> <method name="seek"> @@ -73,7 +73,7 @@ The pitch and the tempo of the audio, as a multiplier of the audio sample's sample rate. </member> <member name="playing" type="bool" setter="_set_playing" getter="is_playing" default="false"> - If [code]true[/code], audio is playing. + If [code]true[/code], audio is playing or is queued to be played (see [method play]). </member> <member name="stream" type="AudioStream" setter="set_stream" getter="get_stream"> The [AudioStream] object to be played. diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml index 11d6e9cc7a..f711210ca1 100644 --- a/doc/classes/AudioStreamPlayer3D.xml +++ b/doc/classes/AudioStreamPlayer3D.xml @@ -29,7 +29,7 @@ <return type="void" /> <param index="0" name="from_position" type="float" default="0.0" /> <description> - Plays the audio from the given position [param from_position], in seconds. + Queues the audio to play on the next physics frame, from the given position [param from_position], in seconds. </description> </method> <method name="seek"> @@ -94,7 +94,7 @@ The pitch and the tempo of the audio, as a multiplier of the audio sample's sample rate. </member> <member name="playing" type="bool" setter="_set_playing" getter="is_playing" default="false"> - If [code]true[/code], audio is playing. + If [code]true[/code], audio is playing or is queued to be played (see [method play]). </member> <member name="stream" type="AudioStream" setter="set_stream" getter="get_stream"> The [AudioStream] resource to be played. diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml index dd48ee6790..1fb4f91920 100644 --- a/doc/classes/Callable.xml +++ b/doc/classes/Callable.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="Callable" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> - An object representing a method in a certain object that can be called. + Built-in type representing a method in an object instance or a standalone function. </brief_description> <description> - [Callable] is a first class object which can be held in variables and passed to functions. It represents a given method in an [Object], and is typically used for signal callbacks. + [Callable] is a built-in [Variant] type that represents a function. It can either be a method within an [Object] instance, or a standalone function not related to any object, like a lambda function. Like all [Variant] types, it can be stored in variables and passed to other functions. It is most commonly used for signal callbacks. [b]Example:[/b] [codeblocks] [gdscript] @@ -32,6 +32,18 @@ } [/csharp] [/codeblocks] + In GDScript, it's possible to create lambda functions within a method. Lambda functions are custom callables that are not associated with an [Object] instance. Optionally, lambda functions can also be named. The name will be displayed in the debugger, or when calling [method get_method]. + [codeblock] + func _init(): + var my_lambda = func (message): + print(message) + + # Prints Hello everyone! + my_lambda.call("Hello everyone!") + + # Prints "Attack!", when the button_pressed signal is emitted. + button_pressed.connect(func(): print("Attack!")) + [/codeblock] </description> <tutorials> </tutorials> @@ -39,7 +51,7 @@ <constructor name="Callable"> <return type="Callable" /> <description> - Constructs a null [Callable] with no object nor method bound. + Constructs an empty [Callable], with no object nor method bound. </description> </constructor> <constructor name="Callable"> @@ -54,7 +66,7 @@ <param index="0" name="object" type="Object" /> <param index="1" name="method" type="StringName" /> <description> - Creates a new [Callable] for the method called [param method] in the specified [param object]. + Creates a new [Callable] for the method named [param method] in the specified [param object]. </description> </constructor> </constructors> @@ -62,7 +74,7 @@ <method name="bind" qualifiers="vararg const"> <return type="Callable" /> <description> - Returns a copy of this [Callable] with the arguments bound. Bound arguments are passed after the arguments supplied by [method call]. + Returns a copy of this [Callable] with one or more arguments bound. When called, the bound arguments are passed [i]after[/i] the arguments supplied by [method call]. </description> </method> <method name="call" qualifiers="vararg const"> @@ -85,13 +97,13 @@ <return type="Variant" /> <param index="0" name="arguments" type="Array" /> <description> - Calls the method represented by this [Callable]. Contrary to [method call], this method does not take a variable number of arguments but expects all arguments to be passed via a single [Array]. + Calls the method represented by this [Callable]. Unlike [method call], this method expects all arguments to be contained inside the [param arguments] [Array]. </description> </method> <method name="get_method" qualifiers="const"> <return type="StringName" /> <description> - Returns the name of the method represented by this [Callable]. + Returns the name of the method represented by this [Callable]. If the callable is a lambda function, returns the function's name. </description> </method> <method name="get_object" qualifiers="const"> @@ -116,7 +128,7 @@ <method name="is_custom" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if this [Callable] is a custom callable whose behavior differs based on implementation details. Custom callables are used in the engine for various reasons. If [code]true[/code], you can't use [method get_method]. + Returns [code]true[/code] if this [Callable] is a custom callable. Custom callables are created from [method bind] or [method unbind]. In GDScript, lambda functions are also custom callables. </description> </method> <method name="is_null" qualifiers="const"> @@ -128,33 +140,33 @@ <method name="is_standard" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if this [Callable] is a standard callable, referencing an object and a method using a [StringName]. + Returns [code]true[/code] if this [Callable] is a standard callable. This method is the opposite of [method is_custom]. Returns [code]false[/code] if this callable is a lambda function. </description> </method> <method name="is_valid" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if the object exists and has a valid function assigned, or is a custom callable. + Returns [code]true[/code] if the callable's object exists and has a valid method name assigned, or is a custom callable. </description> </method> <method name="rpc" qualifiers="vararg const"> <return type="void" /> <description> - Perform an RPC (Remote Procedure Call). This is used for multiplayer and is normally not available unless the function being called has been marked as [i]RPC[/i]. Calling it on unsupported functions will result in an error. + Perform an RPC (Remote Procedure Call). This is used for multiplayer and is normally not available, unless the function being called has been marked as [i]RPC[/i]. Calling this method on unsupported functions will result in an error. </description> </method> <method name="rpc_id" qualifiers="vararg const"> <return type="void" /> <param index="0" name="peer_id" type="int" /> <description> - Perform an RPC (Remote Procedure Call) on a specific peer ID (see multiplayer documentation for reference). This is used for multiplayer and is normally not available unless the function being called has been marked as [i]RPC[/i]. Calling it on unsupported functions will result in an error. + Perform an RPC (Remote Procedure Call) on a specific peer ID (see multiplayer documentation for reference). This is used for multiplayer and is normally not available unless the function being called has been marked as [i]RPC[/i]. Calling this method on unsupported functions will result in an error. </description> </method> <method name="unbind" qualifiers="const"> <return type="Callable" /> <param index="0" name="argcount" type="int" /> <description> - Returns a copy of this [Callable] with the arguments unbound. Calling the returned [Callable] will call the method without the extra arguments that are supplied in the [Callable] on which you are calling this method. + Returns a copy of this [Callable] with the arguments unbound, as defined by [param argcount]. Calling the returned [Callable] will call the method without the extra arguments that are supplied in the [Callable] on which you are calling this method. </description> </method> </methods> diff --git a/doc/classes/CanvasGroup.xml b/doc/classes/CanvasGroup.xml index 3bea8cde21..d2bcf3c7ac 100644 --- a/doc/classes/CanvasGroup.xml +++ b/doc/classes/CanvasGroup.xml @@ -1,8 +1,11 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="CanvasGroup" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + Merges several 2D nodes into a single draw operation. </brief_description> <description> + Child [CanvasItem] nodes of a [CanvasGroup] are drawn as a single object. It allows to e.g. draw overlapping translucent 2D nodes without blending (set [member CanvasItem.self_modulate] property of [CanvasGroup] to achieve this effect). + [b]Note:[/b] Since [CanvasGroup] and [member CanvasItem.clip_children] both utilize the backbuffer, children of a [CanvasGroup] who have their [member CanvasItem.clip_children] set to anything other than [constant CanvasItem.CLIP_CHILDREN_DISABLED] will not function correctly. </description> <tutorials> </tutorials> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index a2859552a9..50bbbc71a0 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -672,12 +672,16 @@ Represents the size of the [enum TextureRepeat] enum. </constant> <constant name="CLIP_CHILDREN_DISABLED" value="0" enum="ClipChildrenMode"> + Child draws over parent and is not clipped. </constant> <constant name="CLIP_CHILDREN_ONLY" value="1" enum="ClipChildrenMode"> + Parent is used for the purposes of clipping only. Child is clipped to the parent's visible area, parent is not drawn. </constant> <constant name="CLIP_CHILDREN_AND_DRAW" value="2" enum="ClipChildrenMode"> + Parent is used for clipping child, but parent is also drawn underneath child as normal before clipping child to its visible area. </constant> <constant name="CLIP_CHILDREN_MAX" value="3" enum="ClipChildrenMode"> + Represents the size of the [enum ClipChildrenMode] enum. </constant> </constants> </class> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 2159001a30..8a38deeebe 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -1010,6 +1010,10 @@ <member name="layout_direction" type="int" setter="set_layout_direction" getter="get_layout_direction" enum="Control.LayoutDirection" default="0"> Controls layout direction and text writing direction. Right-to-left layouts are necessary for certain languages (e.g. Arabic and Hebrew). </member> + <member name="localize_numeral_system" type="bool" setter="set_localize_numeral_system" getter="is_localizing_numeral_system" default="true"> + If [code]true[/code], automatically converts code line numbers, list indices, [SpinBox] and [ProgressBar] values from the Western Arabic (0..9) to the numeral systems used in current locale. + [b]Note:[/b] Numbers within the text are not automatically converted, it can be done manually, using [method TextServer.format_number]. + </member> <member name="mouse_default_cursor_shape" type="int" setter="set_default_cursor_shape" getter="get_default_cursor_shape" enum="Control.CursorShape" default="0"> The default cursor shape for this control. Useful for Godot plugins and applications or games that use the system's mouse cursors. [b]Note:[/b] On Linux, shapes may vary depending on the cursor theme of the system. diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml index 3e4e05f51a..67e4e45e52 100644 --- a/doc/classes/Curve3D.xml +++ b/doc/classes/Curve3D.xml @@ -132,6 +132,15 @@ If the curve has no up vectors, the function sends an error to the console, and returns [code](0, 1, 0)[/code]. </description> </method> + <method name="sample_baked_with_rotation" qualifiers="const"> + <return type="Transform3D" /> + <param index="0" name="offset" type="float" /> + <param index="1" name="cubic" type="bool" default="false" /> + <param index="2" name="apply_tilt" type="bool" default="false" /> + <description> + Similar with [code]interpolate_baked()[/code]. The the return value is [code]Transform3D[/code], with [code]origin[/code] as point position, [code]basis.x[/code] as sideway vector, [code]basis.y[/code] as up vector, [code]basis.z[/code] as forward vector. When the curve length is 0, there is no reasonable way to caculate the rotation, all vectors aligned with global space axes. + </description> + </method> <method name="samplef" qualifiers="const"> <return type="Vector3" /> <param index="0" name="fofs" type="float" /> @@ -183,6 +192,15 @@ [param tolerance_degrees] controls how many degrees the midpoint of a segment may deviate from the real curve, before the segment has to be subdivided. </description> </method> + <method name="tessellate_even_length" qualifiers="const"> + <return type="PackedVector3Array" /> + <param index="0" name="max_stages" type="int" default="5" /> + <param index="1" name="tolerance_length" type="float" default="0.2" /> + <description> + Returns a list of points along the curve, with almost uniform density. [param max_stages] controls how many subdivisions a curve segment may face before it is considered approximate enough. Each subdivision splits the segment in half, so the default 5 stages may mean up to 32 subdivisions per curve segment. Increase with care! + [param tolerance_length] controls the maximal distance between two neighbouring points, before the segment has to be subdivided. + </description> + </method> </methods> <members> <member name="bake_interval" type="float" setter="set_bake_interval" getter="get_bake_interval" default="0.2"> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 806588d100..adcc87d062 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -719,44 +719,64 @@ </signals> <constants> <constant name="CONTAINER_TOOLBAR" value="0" enum="CustomControlContainer"> + Main editor toolbar, next to play buttons. </constant> <constant name="CONTAINER_SPATIAL_EDITOR_MENU" value="1" enum="CustomControlContainer"> + The toolbar that appears when 3D editor is active. </constant> <constant name="CONTAINER_SPATIAL_EDITOR_SIDE_LEFT" value="2" enum="CustomControlContainer"> + Left sidebar of the 3D editor. </constant> <constant name="CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT" value="3" enum="CustomControlContainer"> + Right sidebar of the 3D editor. </constant> <constant name="CONTAINER_SPATIAL_EDITOR_BOTTOM" value="4" enum="CustomControlContainer"> + Bottom panel of the 3D editor. </constant> <constant name="CONTAINER_CANVAS_EDITOR_MENU" value="5" enum="CustomControlContainer"> + The toolbar that appears when 2D editor is active. </constant> <constant name="CONTAINER_CANVAS_EDITOR_SIDE_LEFT" value="6" enum="CustomControlContainer"> + Left sidebar of the 2D editor. </constant> <constant name="CONTAINER_CANVAS_EDITOR_SIDE_RIGHT" value="7" enum="CustomControlContainer"> + Right sidebar of the 2D editor. </constant> <constant name="CONTAINER_CANVAS_EDITOR_BOTTOM" value="8" enum="CustomControlContainer"> + Bottom panel of the 2D editor. </constant> <constant name="CONTAINER_INSPECTOR_BOTTOM" value="9" enum="CustomControlContainer"> + Bottom section of the inspector. </constant> <constant name="CONTAINER_PROJECT_SETTING_TAB_LEFT" value="10" enum="CustomControlContainer"> + Tab of Project Settings dialog, to the left of other tabs. </constant> <constant name="CONTAINER_PROJECT_SETTING_TAB_RIGHT" value="11" enum="CustomControlContainer"> + Tab of Project Settings dialog, to the right of other tabs. </constant> <constant name="DOCK_SLOT_LEFT_UL" value="0" enum="DockSlot"> + Dock slot, left side, upper-left (empty in default layout). </constant> <constant name="DOCK_SLOT_LEFT_BL" value="1" enum="DockSlot"> + Dock slot, left side, bottom-left (empty in default layout). </constant> <constant name="DOCK_SLOT_LEFT_UR" value="2" enum="DockSlot"> + Dock slot, left side, upper-right (in default layout includes Scene and Import docks). </constant> <constant name="DOCK_SLOT_LEFT_BR" value="3" enum="DockSlot"> + Dock slot, left side, bottom-right (in default layout includes FileSystem dock). </constant> <constant name="DOCK_SLOT_RIGHT_UL" value="4" enum="DockSlot"> + Dock slot, right side, upper-left (empty in default layout). </constant> <constant name="DOCK_SLOT_RIGHT_BL" value="5" enum="DockSlot"> + Dock slot, right side, bottom-left (empty in default layout). </constant> <constant name="DOCK_SLOT_RIGHT_UR" value="6" enum="DockSlot"> + Dock slot, right side, upper-right (in default layout includes Inspector, Node and History docks). </constant> <constant name="DOCK_SLOT_RIGHT_BR" value="7" enum="DockSlot"> + Dock slot, right side, bottom-right (empty in default layout). </constant> <constant name="DOCK_SLOT_MAX" value="8" enum="DockSlot"> Represents the size of the [enum DockSlot] enum. diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml index 2aca19510b..e18bea1f67 100644 --- a/doc/classes/EditorProperty.xml +++ b/doc/classes/EditorProperty.xml @@ -150,7 +150,7 @@ <param index="1" name="pinned" type="bool" /> <description> Emit it if you want to mark (or unmark) the value of a property for being saved regardless of being equal to the default value. - The default value is the one the property will get when the node is just instantiated and can come from an ancestor scene in the inheritance/instancing chain, a script or a builtin class. + The default value is the one the property will get when the node is just instantiated and can come from an ancestor scene in the inheritance/instantiation chain, a script or a builtin class. </description> </signal> <signal name="resource_selected"> diff --git a/doc/classes/FileSystemDock.xml b/doc/classes/FileSystemDock.xml index 5578f449b3..00f5c7ddff 100644 --- a/doc/classes/FileSystemDock.xml +++ b/doc/classes/FileSystemDock.xml @@ -46,7 +46,7 @@ <description> </description> </signal> - <signal name="instance"> + <signal name="instantiate"> <param index="0" name="files" type="PackedStringArray" /> <description> </description> diff --git a/doc/classes/HSlider.xml b/doc/classes/HSlider.xml index cb0a8b34db..19bb26a1b0 100644 --- a/doc/classes/HSlider.xml +++ b/doc/classes/HSlider.xml @@ -29,6 +29,7 @@ The background of the area to the left of the grabber. </theme_item> <theme_item name="grabber_area_highlight" data_type="style" type="StyleBox"> + The background of the area to the left of the grabber that displays when it's being hovered or focused. </theme_item> <theme_item name="slider" data_type="style" type="StyleBox"> The background for the whole slider. Determines the height of the [code]grabber_area[/code]. diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml index 615aceac53..cd87b4558f 100644 --- a/doc/classes/Label.xml +++ b/doc/classes/Label.xml @@ -50,6 +50,7 @@ Controls the text's horizontal alignment. Supports left, center, right, and fill, or justify. Set it to one of the [enum HorizontalAlignment] constants. </member> <member name="label_settings" type="LabelSettings" setter="set_label_settings" getter="get_label_settings"> + A [LabelSettings] resource that can be shared between multiple [Label] nodes. Takes priority over theme properties. </member> <member name="language" type="String" setter="set_language" getter="get_language" default=""""> Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead. @@ -100,7 +101,7 @@ Default text [Color] of the [Label]. </theme_item> <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> - The tint of text outline. + The color of text outline. </theme_item> <theme_item name="font_shadow_color" data_type="color" type="Color" default="Color(0, 0, 0, 0)"> [Color] of the text's shadow effect. diff --git a/doc/classes/LabelSettings.xml b/doc/classes/LabelSettings.xml index aa972f2cf3..d73cb78295 100644 --- a/doc/classes/LabelSettings.xml +++ b/doc/classes/LabelSettings.xml @@ -1,29 +1,40 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="LabelSettings" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + Collection of common settings to customize label text. </brief_description> <description> + [LabelSettings] is a resource that can be assigned to a [Label] node to customize it. It will take priority over the properties defined in theme. The resource can be shared between multiple labels and swapped on the fly, so it's convenient and flexible way to setup text style. </description> <tutorials> </tutorials> <members> <member name="font" type="Font" setter="set_font" getter="get_font"> + [Font] used for the text. </member> <member name="font_color" type="Color" setter="set_font_color" getter="get_font_color" default="Color(1, 1, 1, 1)"> + Color of the text. </member> <member name="font_size" type="int" setter="set_font_size" getter="get_font_size" default="16"> + Size of the text. </member> <member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="3.0"> + Vertical space between lines when the text is multiline. </member> <member name="outline_color" type="Color" setter="set_outline_color" getter="get_outline_color" default="Color(1, 1, 1, 1)"> + The color of the outline. </member> <member name="outline_size" type="int" setter="set_outline_size" getter="get_outline_size" default="0"> + Text outline size. </member> <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color(0, 0, 0, 0)"> + Color of the shadow effect. If alpha is [code]0[/code], no shadow will be drawn. </member> <member name="shadow_offset" type="Vector2" setter="set_shadow_offset" getter="get_shadow_offset" default="Vector2(1, 1)"> + Offset of the shadow effect, in pixels. </member> <member name="shadow_size" type="int" setter="set_shadow_size" getter="get_shadow_size" default="1"> + Size of the shadow effect. </member> </members> </class> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index f910112a76..21fb9d139c 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -991,7 +991,7 @@ <constant name="DUPLICATE_SCRIPTS" value="4" enum="DuplicateFlags"> Duplicate the node's scripts. </constant> - <constant name="DUPLICATE_USE_INSTANCING" value="8" enum="DuplicateFlags"> + <constant name="DUPLICATE_USE_INSTANTIATION" value="8" enum="DuplicateFlags"> Duplicate using instancing. An instance stays linked to the original so when the original changes, the instance changes too. </constant> diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml index 022b4826ea..c82ed5f143 100644 --- a/doc/classes/NodePath.xml +++ b/doc/classes/NodePath.xml @@ -187,12 +187,14 @@ <return type="bool" /> <param index="0" name="right" type="NodePath" /> <description> + Returns [code]true[/code] if two node paths are not equal. </description> </operator> <operator name="operator =="> <return type="bool" /> <param index="0" name="right" type="NodePath" /> <description> + Returns [code]true[/code] if two node paths are equal, i.e. all node names in the path are the same and in the same order. </description> </operator> </operators> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index 318f2cfade..bf15f96291 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -1,33 +1,27 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> - Base class for all non-built-in types. + Base class for all other classes in the engine. </brief_description> <description> - Every class which is not a built-in type inherits from this class. - You can construct Objects from scripting languages, using [code]Object.new()[/code] in GDScript, or [code]new Object[/code] in C#. - Objects do not manage memory. If a class inherits from Object, you will have to delete instances of it manually. To do so, call the [method free] method from your script or delete the instance from C++. - Some classes that extend Object add memory management. This is the case of [RefCounted], which counts references and deletes itself automatically when no longer referenced. [Node], another fundamental type, deletes all its children when freed from memory. - Objects export properties, which are mainly useful for storage and editing, but not really so much in programming. Properties are exported in [method _get_property_list] and handled in [method _get] and [method _set]. However, scripting languages and C++ have simpler means to export them. - Property membership can be tested directly in GDScript using [code]in[/code]: - [codeblocks] - [gdscript] - var n = Node2D.new() - print("position" in n) # Prints "true". - print("other_property" in n) # Prints "false". - [/gdscript] - [csharp] - var node = new Node2D(); - // C# has no direct equivalent to GDScript's `in` operator here, but we - // can achieve the same behavior by performing `Get` with a null check. - GD.Print(node.Get("position") != null); // Prints "true". - GD.Print(node.Get("other_property") != null); // Prints "false". - [/csharp] - [/codeblocks] - The [code]in[/code] operator will evaluate to [code]true[/code] as long as the key exists, even if the value is [code]null[/code]. - Objects also receive notifications. Notifications are a simple way to notify the object about different events, so they can all be handled together. See [method _notification]. - [b]Note:[/b] Unlike references to a [RefCounted], references to an Object stored in a variable can become invalid without warning. Therefore, it's recommended to use [RefCounted] for data classes instead of [Object]. - [b]Note:[/b] The [code]script[/code] property is not exposed like most properties, but it does have a setter and getter ([code]set_script()[/code] and [code]get_script()[/code]). + An advanced [Variant] type. All classes in the engine inherit from Object. Each class may define new properties, methods or signals, which are available to all inheriting classes. For example, a [Sprite2D] instance is able to call [method Node.add_child] because it inherits from [Node]. + You can create new instances, using [code]Object.new()[/code] in GDScript, or [code]new Object[/code] in C#. + To delete an Object instance, call [method free]. This is necessary for most classes inheriting Object, because they do not manage memory on their own, and will otherwise cause memory leaks when no longer in use. There are a few classes that perform memory management. For example, [RefCounted] (and by extension [Resource]) deletes itself when no longer referenced, and [Node] deletes its children when freed. + Objects can have a [Script] attached to them. Once the [Script] is instantiated, it effectively acts as an extension to the base class, allowing it to define and inherit new properties, methods and signals. + Inside a [Script], [method _get_property_list] may be overriden to customize properties in several ways. This allows them to be available to the editor, display as lists of options, sub-divide into groups, save on disk, etc. Scripting languages offer easier ways to customize properties, such as with the [annotation @GDScript.@export] annotation. + Godot is very dynamic. An object's script, and therefore its properties, methods and signals, can be changed at run-time. Because of this, there can be occasions where, for example, a property required by a method may not exist. To prevent run-time errors, see methods such as [method set], [method get], [method call], [method has_method], [method has_signal], etc. Note that these methods are [b]much[/b] slower than direct references. + In GDScript, you can also check if a given property, method, or signal name exists in an object with the [code]in[/code] operator: + [codeblock] + var node = Node.new() + print("name" in node) # Prints true + print("get_parent" in node) # Prints true + print("tree_entered" in node) # Prints true + print("unknown" in node) # Prints false + [/codeblock] + Notifications are [int] constants commonly sent and received by objects. For example, on every rendered frame, the [SceneTree] notifies nodes inside the tree with a [constant Node.NOTIFICATION_PROCESS]. The nodes receive it and may call [method Node._process] to update. To make use of notifications, see [method notification] and [method _notification]. + Lastly, every object can also contain metadata (data about data). [method set_meta] can be useful to store information that the object itself does not depend on. To keep your code clean, making excessive use of metadata is discouraged. + [b]Note:[/b] Unlike references to a [RefCounted], references to an object stored in a variable can become invalid without being set to [code]null[/code]. To check if an object has been deleted, do [i]not[/i] compare it against [code]null[/code]. Instead, use [method @GlobalScope.is_instance_valid]. It's also recommended to inherit from [RefCounted] for classes storing data instead of [Object]. + [b]Note:[/b] The [code]script[/code] is not exposed like most properties. To set or get an object's [Script] in code, use [method set_script] and [method get_script], respectively. </description> <tutorials> <link title="When and how to avoid using nodes for everything">$DOCS_URL/tutorials/best_practices/node_alternatives.html</link> @@ -38,46 +32,174 @@ <return type="Variant" /> <param index="0" name="property" type="StringName" /> <description> - Virtual method which can be overridden to customize the return value of [method get]. - Returns the given property. Returns [code]null[/code] if the [param property] does not exist. + Override this method to customize the behavior of [method get]. Should return the given [param property]'s value, or [code]null[/code] if the [param property] should be handled normally. + Combined with [method _set] and [method _get_property_list], this method allows defining custom properties, which is particularly useful for editor plugins. Note that a property must be present in [method get_property_list], otherwise this method will not be called. + [codeblocks] + [gdscript] + func _get(property): + if (property == "fake_property"): + print("Getting my property!") + return 4 + + func _get_property_list(): + return [ + { "name": "fake_property", "type": TYPE_INT } + ] + [/gdscript] + [csharp] + public override Variant _Get(StringName property) + { + if (property == "FakeProperty") + { + GD.Print("Getting my property!"); + return 4; + } + return default; + } + + public override Godot.Collections.Array<Godot.Collections.Dictionary> _GetPropertyList() + { + return new Godot.Collections.Array<Godot.Collections.Dictionary>() + { + new Godot.Collections.Dictionary() + { + { "name", "FakeProperty" }, + { "type", (int)Variant.Type.Int } + } + }; + } + [/csharp] + [/codeblocks] </description> </method> <method name="_get_property_list" qualifiers="virtual"> <return type="Dictionary[]" /> <description> - Virtual method which can be overridden to customize the return value of [method get_property_list]. - Returns the object's property list as an [Array] of dictionaries. - Each property's [Dictionary] must contain at least [code]name: String[/code] and [code]type: int[/code] (see [enum Variant.Type]) entries. Optionally, it can also include [code]hint: int[/code] (see [enum PropertyHint]), [code]hint_string: String[/code], and [code]usage: int[/code] (see [enum PropertyUsageFlags]). + Override this method to customize how script properties should be handled by the engine. + Should return a property list, as an [Array] of dictionaries. The result is added to the array of [method get_property_list], and should be formatted in the same way. Each [Dictionary] must at least contain the [code]name[/code] and [code]type[/code] entries. + The example below displays [code]hammer_type[/code] in the Inspector dock, only if [code]holding_hammer[/code] is [code]true[/code]: + [codeblocks] + [gdscript] + @tool + extends Node2D + + @export var holding_hammer = false: + set(value): + holding_hammer = value + notify_property_list_changed() + var hammer_type = 0 + + func _get_property_list(): + # By default, `hammer_type` is not visible in the editor. + var property_usage = PROPERTY_USAGE_NO_EDITOR + + if holding_hammer: + property_usage = PROPERTY_USAGE_DEFAULT + + var properties = [] + properties.append({ + "name": "hammer_type", + "type": TYPE_INT, + "usage": property_usage, # See above assignment. + "hint": PROPERTY_HINT_ENUM, + "hint_string": "Wooden,Iron,Golden,Enchanted" + }) + + return properties + [/gdscript] + [csharp] + [Tool] + public class MyNode2D : Node2D + { + private bool _holdingHammer; + + [Export] + public bool HoldingHammer + { + get => _holdingHammer; + set + { + _holdingHammer = value; + NotifyPropertyListChanged(); + } + } + + public int HammerType { get; set; } + + public override Godot.Collections.Array<Godot.Collections.Dictionary> _GetPropertyList() + { + // By default, `HammerType` is not visible in the editor. + var propertyUsage = PropertyUsageFlags.NoEditor; + + if (HoldingHammer) + { + propertyUsage = PropertyUsageFlags.Default; + } + + var properties = new Godot.Collections.Array<Godot.Collections.Dictionary>(); + properties.Add(new Godot.Collections.Dictionary() + { + { "name", "HammerType" }, + { "type", (int)Variant.Type.Int }, + { "usage", (int)propertyUsage }, // See above assignment. + { "hint", (int)PropertyHint.Enum }, + { "hint_string", "Wooden,Iron,Golden,Enchanted" } + }); + + return properties; + } + } + [/csharp] + [/codeblocks] + [b]Note:[/b] This method is intended for advanced purposes. For most common use cases, the scripting languages offer easier ways to handle properties. See [annotation @GDScript.@export], [annotation @GDScript.@export_enum], [annotation @GDScript.@export_group], etc. + [b]Note:[/b] If the object's script is not [annotation @GDScript.@tool], this method will not be called in the editor. </description> </method> <method name="_init" qualifiers="virtual"> <return type="void" /> <description> - Called when the object is initialized in memory. Can be defined to take in parameters, that are passed in when constructing. - [b]Note:[/b] If [method _init] is defined with required parameters, then explicit construction is the only valid means of creating an Object of the class. If any other means (such as [method PackedScene.instantiate]) is used, then initialization will fail. + Called when the object's script is instantiated, oftentimes after the object is initialized in memory (through [code]Object.new()[/code] in GDScript, or [code]new Object[/code] in C#). It can be also defined to take in parameters. This method is similar to a constructor in most programming languages. + [b]Note:[/b] If [method _init] is defined with [i]required[/i] parameters, the Object with script may only be created directly. If any other means (such as [method PackedScene.instantiate] or [method Node.duplicate]) are used, the script's initialization will fail. </description> </method> <method name="_notification" qualifiers="virtual"> <return type="void" /> <param index="0" name="what" type="int" /> <description> - Called whenever the object receives a notification, which is identified in [param what] by a constant. The base [Object] has two constants [constant NOTIFICATION_POSTINITIALIZE] and [constant NOTIFICATION_PREDELETE], but subclasses such as [Node] define a lot more notifications which are also received by this method. + Called when the object receives a notification, which can be identified in [param what] by comparing it with a constant. See also [method notification]. + [codeblocks] + [gdscript] + func _notification(what): + if what == NOTIFICATION_PREDELETE: + print("Goodbye!") + [/gdscript] + [csharp] + public override void _Notification(long what) + { + if (what == NotificationPredelete) + { + GD.Print("Goodbye!"); + } + } + [/csharp] + [/codeblocks] + [b]Note:[/b] The base [Object] defines a few notifications ([constant NOTIFICATION_POSTINITIALIZE] and [constant NOTIFICATION_PREDELETE]). Inheriting classes such as [Node] define a lot more notifications, which are also received by this method. </description> </method> <method name="_property_can_revert" qualifiers="virtual"> <return type="bool" /> <param index="0" name="property" type="StringName" /> <description> - Virtual methods that can be overridden to customize the property revert behavior in the editor. - Returns [code]true[/code] if the property identified by [code]name[/code] can be reverted to a default value. Override [method _property_get_revert] to return the actual value. + Override this method to customize the given [param property]'s revert behavior. Should return [code]true[/code] if the [param property] can be reverted in the Inspector dock. Use [method _property_get_revert] to specify the [param property]'s default value. + [b]Note:[/b] This method must return consistently, regardless of the current value of the [param property]. </description> </method> <method name="_property_get_revert" qualifiers="virtual"> <return type="Variant" /> <param index="0" name="property" type="StringName" /> <description> - Virtual methods that can be overridden to customize the property revert behavior in the editor. - Returns the default value of the property identified by [code]name[/code]. [method _property_can_revert] must be overridden as well for this method to be called. + Override this method to customize the given [param property]'s revert behavior. Should return the default value for the [param property]. If the default value differs from the [param property]'s current value, a revert icon is displayed in the Inspector dock. + [b]Note:[/b] [method _property_can_revert] must also be overridden for this method to be called. </description> </method> <method name="_set" qualifiers="virtual"> @@ -85,15 +207,58 @@ <param index="0" name="property" type="StringName" /> <param index="1" name="value" type="Variant" /> <description> - Virtual method which can be overridden to customize the return value of [method set]. - Sets a property. Returns [code]true[/code] if the [param property] exists. + Override this method to customize the behavior of [method set]. Should set the [param property] to [param value] and return [code]true[/code], or [code]false[/code] if the [param property] should be handled normally. The [i]exact[/i] way to set the [param property] is up to this method's implementation. + Combined with [method _get] and [method _get_property_list], this method allows defining custom properties, which is particularly useful for editor plugins. Note that a property [i]must[/i] be present in [method get_property_list], otherwise this method will not be called. + [codeblocks] + [gdscript] + func _set(property, value): + if (property == "fake_property"): + print("Setting my property to ", value) + + func _get_property_list(): + return [ + { "name": "fake_property", "type": TYPE_INT } + ] + [/gdscript] + [csharp] + public override void _Set(StringName property, Variant value) + { + if (property == "FakeProperty") + { + GD.Print($"Setting my property to {value}"); + return true; + } + + return false; + } + + public override Godot.Collections.Array<Godot.Collections.Dictionary> _GetPropertyList() + { + return new Godot.Collections.Array<Godot.Collections.Dictionary>() + { + new Godot.Collections.Dictionary() + { + { "name", "FakeProperty" }, + { "type", (int)Variant.Type.Int } + } + }; + } + [/csharp] + [/codeblocks] </description> </method> <method name="_to_string" qualifiers="virtual"> <return type="String" /> <description> - Virtual method which can be overridden to customize the return value of [method to_string], and thus the object's representation where it is converted to a string, e.g. with [code]print(obj)[/code]. - Returns a [String] representing the object. If not overridden, defaults to [code]"[ClassName:RID]"[/code]. + Override this method to customize the return value of [method to_string], and therefore the object's representation as a [String]. + [codeblock] + func _to_string(): + return "Welcome to Godot 4!" + + func _init(): + print(self) # Prints Welcome to Godot 4!" + var a = str(self) # a is "Welcome to Godot 4!" + [/codeblock] </description> </method> <method name="add_user_signal"> @@ -101,15 +266,37 @@ <param index="0" name="signal" type="String" /> <param index="1" name="arguments" type="Array" default="[]" /> <description> - Adds a user-defined [param signal]. Arguments are optional, but can be added as an [Array] of dictionaries, each containing [code]name: String[/code] and [code]type: int[/code] (see [enum Variant.Type]) entries. + Adds a user-defined [param signal]. Optional arguments for the signal can be added as an [Array] of dictionaries, each defining a [code]name[/code] [String] and a [code]type[/code] [int] (see [enum Variant.Type]). See also [method has_user_signal]. + [codeblocks] + [gdscript] + add_user_signal("hurt", [ + { "name": "damage", "type": TYPE_INT }, + { "name": "source", "type": TYPE_OBJECT } + ]) + [/gdscript] + [csharp] + AddUserSignal("Hurt", new Godot.Collections.Array() + { + new Godot.Collections.Dictionary() + { + { "name", "damage" }, + { "type", (int)Variant.Type.Int } + }, + new Godot.Collections.Dictionary() + { + { "name", "source" }, + { "type", (int)Variant.Type.Object } + } + }); + [/csharp] + [/codeblocks] </description> </method> <method name="call" qualifiers="vararg"> <return type="Variant" /> <param index="0" name="method" type="StringName" /> <description> - Calls the [param method] on the object and returns the result. This method supports a variable number of arguments, so parameters are passed as a comma separated list. - [b]Example:[/b] + Calls the [param method] on the object and returns the result. This method supports a variable number of arguments, so parameters can be passed as a comma separated list. [codeblocks] [gdscript] var node = Node3D.new() @@ -120,15 +307,14 @@ node.Call("rotate", new Vector3(1f, 0f, 0f), 1.571f); [/csharp] [/codeblocks] - [b]Note:[/b] In C#, the method name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined methods where you should use the same convention as in the C# source (typically PascalCase). + [b]Note:[/b] In C#, [param method] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]MethodName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="call_deferred" qualifiers="vararg"> <return type="Variant" /> <param index="0" name="method" type="StringName" /> <description> - Calls the [param method] on the object during idle time. This method supports a variable number of arguments, so parameters are passed as a comma separated list. - [b]Example:[/b] + Calls the [param method] on the object during idle time. This method supports a variable number of arguments, so parameters can be passed as a comma separated list. [codeblocks] [gdscript] var node = Node3D.new() @@ -139,7 +325,7 @@ node.CallDeferred("rotate", new Vector3(1f, 0f, 0f), 1.571f); [/csharp] [/codeblocks] - [b]Note:[/b] In C#, the method name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined methods where you should use the same convention as in the C# source (typically PascalCase). + [b]Note:[/b] In C#, [param method] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]MethodName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="callv"> @@ -147,7 +333,7 @@ <param index="0" name="method" type="StringName" /> <param index="1" name="arg_array" type="Array" /> <description> - Calls the [param method] on the object and returns the result. Contrarily to [method call], this method does not support a variable number of arguments but expects all parameters to be via a single [Array]. + Calls the [param method] on the object and returns the result. Unlike [method call], this method expects all parameters to be contained inside [param arg_array]. [codeblocks] [gdscript] var node = Node3D.new() @@ -158,12 +344,13 @@ node.Callv("rotate", new Godot.Collections.Array { new Vector3(1f, 0f, 0f), 1.571f }); [/csharp] [/codeblocks] + [b]Note:[/b] In C#, [param method] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]MethodName[/code] class to avoid allocating a new [StringName] on each call </description> </method> <method name="can_translate_messages" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if the object can translate strings. See [method set_message_translation] and [method tr]. + Returns [code]true[/code] if the object is allowed to translate messages with [method tr] and [method tr_n]. See also [method set_message_translation]. </description> </method> <method name="connect"> @@ -172,23 +359,23 @@ <param index="1" name="callable" type="Callable" /> <param index="2" name="flags" type="int" default="0" /> <description> - Connects a [param signal] to a [param callable]. Use [param flags] to set deferred or one-shot connections. See [enum ConnectFlags] constants. - A signal can only be connected once to a [Callable]. It will print an error if already connected, unless the signal was connected with [constant CONNECT_REFERENCE_COUNTED]. To avoid this, first, use [method is_connected] to check for existing connections. - If the callable's target is destroyed in the game's lifecycle, the connection will be lost. + Connects a [param signal] by name to a [param callable]. Optional [param flags] can be also added to configure the connection's behavior (see [enum ConnectFlags] constants). + A signal can only be connected once to the same [Callable]. If the signal is already connected, this method returns [constant ERR_INVALID_PARAMETER] and pushes an error message, unless the signal is connected with [constant CONNECT_REFERENCE_COUNTED]. To prevent this, use [method is_connected] first to check for existing connections. + If the [param callable]'s object is freed, the connection will be lost. [b]Examples with recommended syntax:[/b] - Connecting signals is one of the most common operations in Godot and the API gives many options to do so, which are described further down. The code block below shows the recommended approach for both GDScript and C#. + Connecting signals is one of the most common operations in Godot and the API gives many options to do so, which are described further down. The code block below shows the recommended approach. [codeblocks] [gdscript] func _ready(): var button = Button.new() - # `button_down` here is a Signal object, and we thus call the Signal.connect() method, - # not Object.connect(). See discussion below for a more in-depth overview of the API. + # `button_down` here is a Signal variant type, and we thus call the Signal.connect() method, not Object.connect(). + # See discussion below for a more in-depth overview of the API. button.button_down.connect(_on_button_down) - # This assumes that a `Player` class exists which defines a `hit` signal. + # This assumes that a `Player` class exists, which defines a `hit` signal. var player = Player.new() - # We use Signal.connect() again, and we also use the Callable.bind() method which - # returns a new Callable with the parameter binds. + # We use Signal.connect() again, and we also use the Callable.bind() method, + # which returns a new Callable with the parameter binds. player.hit.connect(_on_player_hit.bind("sword", 100)) func _on_button_down(): @@ -204,7 +391,7 @@ // C# supports passing signals as events, so we can use this idiomatic construct: button.ButtonDown += OnButtonDown; - // This assumes that a `Player` class exists which defines a `Hit` signal. + // This assumes that a `Player` class exists, which defines a `Hit` signal. var player = new Player(); // Signals as events (`player.Hit += OnPlayerHit;`) do not support argument binding. You have to use: player.Hit.Connect(OnPlayerHit, new Godot.Collections.Array {"sword", 100 }); @@ -261,44 +448,41 @@ } [/csharp] [/codeblocks] - While all options have the same outcome ([code]button[/code]'s [signal BaseButton.button_down] signal will be connected to [code]_on_button_down[/code]), option 3 offers the best validation: it will print a compile-time error if either the [code]button_down[/code] signal or the [code]_on_button_down[/code] callable are undefined. On the other hand, option 2 only relies on string names and will only be able to validate either names at runtime: it will print a runtime error if [code]"button_down"[/code] doesn't correspond to a signal, or if [code]"_on_button_down"[/code] is not a registered method in the object [code]self[/code]. The main reason for using options 1, 2, or 4 would be if you actually need to use strings (e.g. to connect signals programmatically based on strings read from a configuration file). Otherwise, option 3 is the recommended (and fastest) method. - [b]Parameter bindings and passing:[/b] - For legacy or language-specific reasons, there are also several ways to bind parameters to signals. One can pass a [code]binds[/code] [Array] to [method Object.connect] or [method Signal.connect], or use the recommended [method Callable.bind] method to create a new callable from an existing one, with the given parameter binds. - One can also pass additional parameters when emitting the signal with [method emit_signal]. The examples below show the relationship between those two types of parameters. + While all options have the same outcome ([code]button[/code]'s [signal BaseButton.button_down] signal will be connected to [code]_on_button_down[/code]), [b]option 3[/b] offers the best validation: it will print a compile-time error if either the [code]button_down[/code] [Signal] or the [code]_on_button_down[/code] [Callable] are not defined. On the other hand, [b]option 2[/b] only relies on string names and will only be able to validate either names at runtime: it will print a runtime error if [code]"button_down"[/code] doesn't correspond to a signal, or if [code]"_on_button_down"[/code] is not a registered method in the object [code]self[/code]. The main reason for using options 1, 2, or 4 would be if you actually need to use strings (e.g. to connect signals programmatically based on strings read from a configuration file). Otherwise, option 3 is the recommended (and fastest) method. + [b]Binding and passing parameters:[/b] + The syntax to bind parameters is through [method Callable.bind], which returns a copy of the [Callable] with its parameters bound. + When calling [method emit_signal], the signal parameters can be also passed. The examples below show the relationship between these signal parameters and bound parameters. [codeblocks] [gdscript] func _ready(): - # This assumes that a `Player` class exists which defines a `hit` signal. + # This assumes that a `Player` class exists, which defines a `hit` signal. var player = Player.new() - # Option 1: Using Callable.bind(). player.hit.connect(_on_player_hit.bind("sword", 100)) - # Option 2: Using a `binds` Array in Signal.connect() (same syntax for Object.connect()). - player.hit.connect(_on_player_hit, ["sword", 100]) # Parameters added when emitting the signal are passed first. player.emit_signal("hit", "Dark lord", 5) - # Four arguments, since we pass two when emitting (hit_by, level) - # and two when connecting (weapon_type, damage). + # We pass two arguments when emitting (`hit_by`, `level`), + # and bind two more arguments when connecting (`weapon_type`, `damage`). func _on_player_hit(hit_by, level, weapon_type, damage): print("Hit by %s (level %d) with weapon %s for %d damage." % [hit_by, level, weapon_type, damage]) [/gdscript] [csharp] public override void _Ready() { - // This assumes that a `Player` class exists which defines a `Hit` signal. + // This assumes that a `Player` class exists, which defines a `Hit` signal. var player = new Player(); // Option 1: Using Callable.Bind(). This way we can still use signals as events. player.Hit += OnPlayerHit.Bind("sword", 100); - // Option 2: Using a `binds` Array in Signal.Connect() (same syntax for Object.Connect()). + // Option 2: Using a `binds` Array in Signal.Connect(). player.Hit.Connect(OnPlayerHit, new Godot.Collections.Array{ "sword", 100 }); // Parameters added when emitting the signal are passed first. player.EmitSignal("hit", "Dark lord", 5); } - // Four arguments, since we pass two when emitting (hitBy, level) - // and two when connecting (weaponType, damage). + // We pass two arguments when emitting (`hit_by`, `level`), + // and bind two more arguments when connecting (`weapon_type`, `damage`). private void OnPlayerHit(string hitBy, int level, string weaponType, int damage) { GD.Print(String.Format("Hit by {0} (level {1}) with weapon {2} for {3} damage.", hitBy, level, weaponType, damage)); @@ -312,57 +496,68 @@ <param index="0" name="signal" type="StringName" /> <param index="1" name="callable" type="Callable" /> <description> - Disconnects a [param signal] from a given [param callable]. - If you try to disconnect a connection that does not exist, the method will print an error. Use [method is_connected] to ensure that the connection exists. + Disconnects a [param signal] by name from a given [param callable]. If the connection does not exist, generates an error. Use [method is_connected] to make sure that the connection exists. </description> </method> <method name="emit_signal" qualifiers="vararg"> <return type="int" enum="Error" /> <param index="0" name="signal" type="StringName" /> <description> - Emits the given [param signal]. The signal must exist, so it should be a built-in signal of this class or one of its parent classes, or a user-defined signal. This method supports a variable number of arguments, so parameters are passed as a comma separated list. - [b]Example:[/b] + Emits the given [param signal] by name. The signal must exist, so it should be a built-in signal of this class or one of its inherited classes, or a user-defined signal (see [method add_user_signal]). This method supports a variable number of arguments, so parameters can be passed as a comma separated list. + Returns [constant ERR_UNAVAILABLE] if [param signal] does not exist or the parameters are invalid. [codeblocks] [gdscript] emit_signal("hit", "sword", 100) emit_signal("game_over") [/gdscript] [csharp] - EmitSignal("hit", "sword", 100); - EmitSignal("game_over"); + EmitSignal("Hit", "sword", 100); + EmitSignal("GameOver"); [/csharp] [/codeblocks] + [b]Note:[/b] In C#, [param signal] must be in snake_case when referring to built-in Godot signals. Prefer using the names exposed in the [code]SignalName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="free"> <return type="void" /> <description> - Deletes the object from memory. Any pre-existing reference to the freed object will become invalid, e.g. [code]is_instance_valid(object)[/code] will return [code]false[/code]. + Deletes the object from memory. Pre-existing references to the object become invalid, and any attempt to access them will result in a run-time error. Checking the references with [method @GlobalScope.is_instance_valid] will return [code]false[/code]. </description> </method> <method name="get" qualifiers="const"> <return type="Variant" /> <param index="0" name="property" type="StringName" /> <description> - Returns the [Variant] value of the given [param property]. If the [param property] doesn't exist, this will return [code]null[/code]. - [b]Note:[/b] In C#, the property name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined properties where you should use the same convention as in the C# source (typically PascalCase). + Returns the [Variant] value of the given [param property]. If the [param property] does not exist, this method returns [code]null[/code]. + [codeblocks] + [gdscript] + var node = Node2D.new() + node.rotation = 1.5 + var a = node.get("rotation") # a is 1.5 + [/gdscript] + [csharp] + var node = new Node2D(); + node.Rotation = 1.5f; + var a = node.Get("rotation"); // a is 1.5 + [/csharp] + [/codeblocks] + [b]Note:[/b] In C#, [param property] must be in snake_case when referring to built-in Godot properties. Prefer using the names exposed in the [code]PropertyName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="get_class" qualifiers="const"> <return type="String" /> <description> - Returns the object's class as a [String]. See also [method is_class]. - [b]Note:[/b] [method get_class] does not take [code]class_name[/code] declarations into account. If the object has a [code]class_name[/code] defined, the base class name will be returned instead. + Returns the object's built-in class name, as a [String]. See also [method is_class]. + [b]Note:[/b] This method ignores [code]class_name[/code] declarations. If this object's script has defined a [code]class_name[/code], the base, built-in class name is returned instead. </description> </method> <method name="get_incoming_connections" qualifiers="const"> <return type="Dictionary[]" /> <description> - Returns an [Array] of dictionaries with information about signals that are connected to the object. - Each [Dictionary] contains three String entries: - - [code]source[/code] is a reference to the signal emitter. - - [code]signal_name[/code] is the name of the connected signal. - - [code]method_name[/code] is the name of the method to which the signal is connected. + Returns an [Array] of signal connections received by this object. Each connection is represented as a [Dictionary] that contains three entries: + - [code]signal[/code] is a reference to the [Signal]; + - [code]callable[/code] is a reference to the [Callable]; + - [code]flags[/code] is a combination of [enum ConnectFlags]. </description> </method> <method name="get_indexed" qualifiers="const"> @@ -371,14 +566,28 @@ <description> Gets the object's property indexed by the given [param property_path]. The path should be a [NodePath] relative to the current object and can use the colon character ([code]:[/code]) to access nested properties. [b]Examples:[/b] [code]"position:x"[/code] or [code]"material:next_pass:blend_mode"[/code]. - [b]Note:[/b] Even though the method takes [NodePath] argument, it doesn't support actual paths to [Node]s in the scene tree, only colon-separated sub-property paths. For the purpose of nodes, use [method Node.get_node_and_resource] instead. + [codeblocks] + [gdscript] + var node = Node2D.new() + node.position = Vector2(5, -10) + var a = node.get_indexed("position") # a is Vector2(5, -10) + var b = node.get_indexed("position:y") # b is -10 + [/gdscript] + [csharp] + var node = new Node2D(); + node.Position = new Vector2(5, -10); + var a = node.GetIndexed("position"); // a is Vector2(5, -10) + var b = node.GetIndexed("position:y"); // b is -10 + [/csharp] + [/codeblocks] + [b]Note:[/b] In C#, [param property_path] must be in snake_case when referring to built-in Godot properties. + [b]Note:[/b] This method does not support actual paths to nodes in the [SceneTree], only sub-property paths. In the context of nodes, use [method Node.get_node_and_resource] instead. </description> </method> <method name="get_instance_id" qualifiers="const"> <return type="int" /> <description> - Returns the object's unique instance ID. - This ID can be saved in [EncodedObjectAsID], and can be used to retrieve the object instance with [method @GlobalScope.instance_from_id]. + Returns the object's unique instance ID. This ID can be saved in [EncodedObjectAsID], and can be used to retrieve this object instance with [method @GlobalScope.instance_from_id]. </description> </method> <method name="get_meta" qualifiers="const"> @@ -386,47 +595,62 @@ <param index="0" name="name" type="StringName" /> <param index="1" name="default" type="Variant" default="null" /> <description> - Returns the object's metadata entry for the given [param name]. - Throws error if the entry does not exist, unless [param default] is not [code]null[/code] (in which case the default value will be returned). See also [method has_meta], [method set_meta] and [method remove_meta]. - [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector and should not be edited. + Returns the object's metadata value for the given entry [param name]. If the entry does not exist, returns [param default]. If [param default] is [code]null[/code], an error is also generated. + [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector dock and should not be edited. </description> </method> <method name="get_meta_list" qualifiers="const"> <return type="PackedStringArray" /> <description> - Returns the object's metadata as a [PackedStringArray]. + Returns the object's metadata entry names as a [PackedStringArray]. </description> </method> <method name="get_method_list" qualifiers="const"> <return type="Dictionary[]" /> <description> - Returns the object's methods and their signatures as an [Array]. + Returns this object's methods and their signatures as an [Array] of dictionaries. Each [Dictionary] contains the following entries: + - [code]name[/code] is the name of the method, as a [String]; + - [code]args[/code] is an [Array] of dictionaries representing the arguments; + - [code]default_args[/code] is the default arguments as an [Array] of variants; + - [code]flags[/code] is a combination of [enum MethodFlags]; + - [code]id[/code] is the method's internal identifier [int]; + - [code]return[/code] is the returned value, as a [Dictionary]; + [b]Note:[/b] The dictionaries of [code]args[/code] and [code]return[/code] are formatted identically to the results of [method get_property_list], although not all entries are used. </description> </method> <method name="get_property_list" qualifiers="const"> <return type="Dictionary[]" /> <description> - Returns the object's property list as an [Array] of dictionaries. - Each property's [Dictionary] contain at least [code]name: String[/code] and [code]type: int[/code] (see [enum Variant.Type]) entries. Optionally, it can also include [code]hint: int[/code] (see [enum PropertyHint]), [code]hint_string: String[/code], and [code]usage: int[/code] (see [enum PropertyUsageFlags]). + Returns the object's property list as an [Array] of dictionaries. Each [Dictionary] contains the following entries: + - [code]name[/code] is the property's name, as a [String]; + - [code]class_name[/code] is an empty [StringName], unless the property is [constant TYPE_OBJECT] and it inherits from a class; + - [code]type[/code] is the property's type, as an [int] (see [enum Variant.Type]); + - [code]hint[/code] is [i]how[/i] the property is meant to be edited (see [enum PropertyHint]); + - [code]hint_string[/code] depends on the hint (see [enum PropertyHint]); + - [code]usage[/code] is a combination of [enum PropertyUsageFlags]. </description> </method> <method name="get_script" qualifiers="const"> <return type="Variant" /> <description> - Returns the object's [Script] instance, or [code]null[/code] if none is assigned. + Returns the object's [Script] instance, or [code]null[/code] if no script is attached. </description> </method> <method name="get_signal_connection_list" qualifiers="const"> <return type="Dictionary[]" /> <param index="0" name="signal" type="StringName" /> <description> - Returns an [Array] of connections for the given [param signal]. + Returns an [Array] of connections for the given [param signal] name. Each connection is represented as a [Dictionary] that contains three entries: + - [code]signal[/code] is a reference to the [Signal]; + - [code]callable[/code] is a reference to the [Callable]; + - [code]flags[/code] is a combination of [enum ConnectFlags]. </description> </method> <method name="get_signal_list" qualifiers="const"> <return type="Dictionary[]" /> <description> - Returns the list of signals as an [Array] of dictionaries. + Returns the list of existing signals as an [Array] of dictionaries. + [b]Note:[/b] Due of the implementation, each [Dictionary] is formatted very similarly to the returned values of [method get_method_list]. </description> </method> <method name="has_meta" qualifiers="const"> @@ -434,34 +658,36 @@ <param index="0" name="name" type="StringName" /> <description> Returns [code]true[/code] if a metadata entry is found with the given [param name]. See also [method get_meta], [method set_meta] and [method remove_meta]. - [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector and should not be edited. + [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector and should not be edited, although it can still be found by this method. </description> </method> <method name="has_method" qualifiers="const"> <return type="bool" /> <param index="0" name="method" type="StringName" /> <description> - Returns [code]true[/code] if the object contains the given [param method]. + Returns [code]true[/code] if the the given [param method] name exists in the object. + [b]Note:[/b] In C#, [param method] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]MethodName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="has_signal" qualifiers="const"> <return type="bool" /> <param index="0" name="signal" type="StringName" /> <description> - Returns [code]true[/code] if the given [param signal] exists. + Returns [code]true[/code] if the given [param signal] name exists in the object. + [b]Note:[/b] In C#, [param signal] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]SignalName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="has_user_signal" qualifiers="const"> <return type="bool" /> <param index="0" name="signal" type="StringName" /> <description> - Returns [code]true[/code] if the given user-defined [param signal] exists. Only signals added using [method add_user_signal] are taken into account. + Returns [code]true[/code] if the given user-defined [param signal] name exists. Only signals added with [method add_user_signal] are included. </description> </method> <method name="is_blocking_signals" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if signal emission blocking is enabled. + Returns [code]true[/code] if the object is blocking its signals from being emitted. See [method set_block_signals]. </description> </method> <method name="is_class" qualifiers="const"> @@ -469,7 +695,21 @@ <param index="0" name="class" type="String" /> <description> Returns [code]true[/code] if the object inherits from the given [param class]. See also [method get_class]. - [b]Note:[/b] [method is_class] does not take [code]class_name[/code] declarations into account. If the object has a [code]class_name[/code] defined, [method is_class] will return [code]false[/code] for that name. + [codeblocks] + [gdscript] + var sprite2d = Sprite2D.new() + sprite2d.is_class("Sprite2D") # Returns true + sprite2d.is_class("Node") # Returns true + sprite2d.is_class("Node3D") # Returns false + [/gdscript] + [csharp] + var sprite2d = new Sprite2D(); + sprite2d.IsClass("Sprite2D"); // Returns true + sprite2d.IsClass("Node"); // Returns true + sprite2d.IsClass("Node3D"); // Returns false + [/csharp] + [/codeblocks] + [b]Note:[/b] This method ignores [code]class_name[/code] declarations in the object's script. </description> </method> <method name="is_connected" qualifiers="const"> @@ -477,7 +717,8 @@ <param index="0" name="signal" type="StringName" /> <param index="1" name="callable" type="Callable" /> <description> - Returns [code]true[/code] if a connection exists for a given [param signal] and [param callable]. + Returns [code]true[/code] if a connection exists between the given [param signal] name and [param callable]. + [b]Note:[/b] In C#, [param signal] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]SignalName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="is_queued_for_deletion" qualifiers="const"> @@ -491,21 +732,43 @@ <param index="0" name="what" type="int" /> <param index="1" name="reversed" type="bool" default="false" /> <description> - Send a given notification to the object, which will also trigger a call to the [method _notification] method of all classes that the object inherits from. - If [param reversed] is [code]true[/code], [method _notification] is called first on the object's own class, and then up to its successive parent classes. If [param reversed] is [code]false[/code], [method _notification] is called first on the highest ancestor ([Object] itself), and then down to its successive inheriting classes. + Sends the given [param what] notification to all classes inherited by the object, triggering calls to [method _notification], starting from the highest ancestor (the [Object] class) and going down to the object's script. + If [param reversed] is [code]true[/code], the call order is reversed. + [codeblocks] + [gdscript] + var player = Node2D.new() + player.set_script(load("res://player.gd")) + + player.notification(NOTIFICATION_ENTER_TREE) + # The call order is Object -> Node -> Node2D -> player.gd. + + player.notification(NOTIFICATION_ENTER_TREE, true) + # The call order is player.gd -> Node2D -> Node -> Object. + [/gdscript] + [csharp] + var player = new Node2D(); + player.SetScript(GD.Load("res://player.gd")); + + player.Notification(NotificationEnterTree); + // The call order is Object -> Node -> Node2D -> player.gd. + + player.notification(NotificationEnterTree, true); + // The call order is player.gd -> Node2D -> Node -> Object. + [/csharp] + [/codeblocks] </description> </method> <method name="notify_property_list_changed"> <return type="void" /> <description> - Notify the editor that the property list has changed by emitting the [signal property_list_changed] signal, so that editor plugins can take the new values into account. + Emits the [signal property_list_changed] signal. This is mainly used to refresh the editor, so that the Inspector and editor plugins are properly updated. </description> </method> <method name="remove_meta"> <return type="void" /> <param index="0" name="name" type="StringName" /> <description> - Removes a given entry from the object's metadata. See also [method has_meta], [method get_meta] and [method set_meta]. + Removes the given entry [param name] from the object's metadata. See also [method has_meta], [method get_meta] and [method set_meta]. [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector and should not be edited. </description> </method> @@ -514,15 +777,27 @@ <param index="0" name="property" type="StringName" /> <param index="1" name="value" type="Variant" /> <description> - Assigns a new value to the given property. If the [param property] does not exist or the given value's type doesn't match, nothing will happen. - [b]Note:[/b] In C#, the property name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined properties where you should use the same convention as in the C# source (typically PascalCase). + Assigns [param value] to the given [param property]. If the property does not exist or the given [param value]'s type doesn't match, nothing happens. + [codeblocks] + [gdscript] + var node = Node2D.new() + node.set("global_scale", Vector2(8, 2.5)) + print(node.global_scale) # Prints (8, 2.5) + [/gdscript] + [csharp] + var node = new Node2D(); + node.Set("global_scale", new Vector2(8, 2.5)); + GD.Print(node.GlobalScale); // Prints Vector2(8, 2.5) + [/csharp] + [/codeblocks] + [b]Note:[/b] In C#, [param property] must be in snake_case when referring to built-in Godot properties. Prefer using the names exposed in the [code]PropertyName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="set_block_signals"> <return type="void" /> <param index="0" name="enable" type="bool" /> <description> - If set to [code]true[/code], signal emission is blocked. + If set to [code]true[/code], the object becomes unable to emit signals. As such, [method emit_signal] and signal connections will not work, until it is set to [code]false[/code]. </description> </method> <method name="set_deferred"> @@ -530,8 +805,30 @@ <param index="0" name="property" type="StringName" /> <param index="1" name="value" type="Variant" /> <description> - Assigns a new value to the given property, after the current frame's physics step. This is equivalent to calling [method set] via [method call_deferred], i.e. [code]call_deferred("set", property, value)[/code]. - [b]Note:[/b] In C#, the property name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined properties where you should use the same convention as in the C# source (typically PascalCase). + Assigns [param value] to the given [param property], after the current frame's physics step. This is equivalent to calling [method set] through [method call_deferred]. + [codeblocks] + [gdscript] + var node = Node2D.new() + add_child(node) + + node.rotation = 45.0 + node.set_deferred("rotation", 90.0) + print(node.rotation) # Prints 45.0 + + await get_tree().process_frame + print(node.rotation) # Prints 90.0 + [/gdscript] + [csharp] + var node = new Node2D(); + node.Rotation = 45f; + node.SetDeferred("rotation", 90f); + GD.Print(node.Rotation); // Prints 45.0 + + await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame); + GD.Print(node.Rotation); // Prints 90.0 + [/csharp] + [/codeblocks] + [b]Note:[/b] In C#, [param property] must be in snake_case when referring to built-in Godot properties. Prefer using the names exposed in the [code]PropertyName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="set_indexed"> @@ -539,29 +836,29 @@ <param index="0" name="property_path" type="NodePath" /> <param index="1" name="value" type="Variant" /> <description> - Assigns a new value to the property identified by the [param property_path]. The path should be a [NodePath] relative to the current object and can use the colon character ([code]:[/code]) to access nested properties. - [b]Example:[/b] + Assigns a new [param value] to the property identified by the [param property_path]. The path should be a [NodePath] relative to this object, and can use the colon character ([code]:[/code]) to access nested properties. [codeblocks] [gdscript] var node = Node2D.new() node.set_indexed("position", Vector2(42, 0)) node.set_indexed("position:y", -10) - print(node.position) # (42, -10) + print(node.position) # Prints (42, -10) [/gdscript] [csharp] var node = new Node2D(); node.SetIndexed("position", new Vector2(42, 0)); node.SetIndexed("position:y", -10); - GD.Print(node.Position); // (42, -10) + GD.Print(node.Position); // Prints (42, -10) [/csharp] [/codeblocks] + [b]Note:[/b] In C#, [param property_path] must be in snake_case when referring to built-in Godot properties. </description> </method> <method name="set_message_translation"> <return type="void" /> <param index="0" name="enable" type="bool" /> <description> - Defines whether the object can translate strings (with calls to [method tr]). Enabled by default. + If set to [code]true[/code], allows the object to translate messages with [method tr] and [method tr_n]. Enabled by default. See also [method can_translate_messages]. </description> </method> <method name="set_meta"> @@ -569,24 +866,23 @@ <param index="0" name="name" type="StringName" /> <param index="1" name="value" type="Variant" /> <description> - Adds, changes or removes a given entry in the object's metadata. Metadata are serialized and can take any [Variant] value. - To remove a given entry from the object's metadata, use [method remove_meta]. Metadata is also removed if its value is set to [code]null[/code]. This means you can also use [code]set_meta("name", null)[/code] to remove metadata for [code]"name"[/code]. See also [method has_meta] and [method get_meta]. - [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector and should not be edited. + Adds or changes the entry [param name] inside the object's metadata. The metadata [param value] can be any [Variant], although some types cannot be serialised correctly. + If [param value] is [code]null[/code], the entry is removed. This is the equivalent of using [method remove_meta]. See also [method has_meta] and [method get_meta]. + [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector dock and should not be edited. </description> </method> <method name="set_script"> <return type="void" /> <param index="0" name="script" type="Variant" /> <description> - Assigns a script to the object. Each object can have a single script assigned to it, which are used to extend its functionality. - If the object already had a script, the previous script instance will be freed and its variables and state will be lost. The new script's [method _init] method will be called. + Attaches [param script] to the object, and instantiates it. As a result, the script's [method _init] is called. A [Script] is used to extend the object's functionality. + If a script already exists, its instance is detached, and its property values and state are lost. Built-in property values are still kept. </description> </method> <method name="to_string"> <return type="String" /> <description> - Returns a [String] representing the object. If not overridden, defaults to [code]"[ClassName:RID]"[/code]. - Override the method [method _to_string] to customize the [String] representation. + Returns a [String] representing the object. Defaults to [code]"<ClassName#RID>"[/code]. Override [method _to_string] to customize the string representation of the object. </description> </method> <method name="tr" qualifiers="const"> @@ -594,9 +890,9 @@ <param index="0" name="message" type="StringName" /> <param index="1" name="context" type="StringName" default="""" /> <description> - Translates a message using translation catalogs configured in the Project Settings. An additional context could be used to specify the translation context. - Only works if message translation is enabled (which it is by default), otherwise it returns the [param message] unchanged. See [method set_message_translation]. - See [url=$DOCS_URL/tutorials/i18n/internationalizing_games.html]Internationalizing games[/url] for examples of the usage of this method. + Translates a [param message], using the translation catalogs configured in the Project Settings. Further [param context] can be specified to help with the translation. + If [method can_translate_messages] is [code]false[/code], or no translation is available, this method returns the [param message] without changes. See [method set_message_translation]. + For detailed examples, see [url=$DOCS_URL/tutorials/i18n/internationalizing_games.html]Internationalizing games[/url]. </description> </method> <method name="tr_n" qualifiers="const"> @@ -606,43 +902,45 @@ <param index="2" name="n" type="int" /> <param index="3" name="context" type="StringName" default="""" /> <description> - Translates a message involving plurals using translation catalogs configured in the Project Settings. An additional context could be used to specify the translation context. - Only works if message translation is enabled (which it is by default), otherwise it returns the [param message] or [param plural_message] unchanged. See [method set_message_translation]. - The number [param n] is the number or quantity of the plural object. It will be used to guide the translation system to fetch the correct plural form for the selected language. - [b]Note:[/b] Negative and floating-point values usually represent physical entities for which singular and plural don't clearly apply. In such cases, use [method tr]. - See [url=$DOCS_URL/tutorials/i18n/localization_using_gettext.html]Localization using gettext[/url] for examples of the usage of this method. + Translates a [param message] or [param plural_message], using the translation catalogs configured in the Project Settings. Further [param context] can be specified to help with the translation. + If [method can_translate_messages] is [code]false[/code], or no translation is available, this method returns [param message] or [param plural_message], without changes. See [method set_message_translation]. + The [param n] is the number, or amount, of the message's subject. It is used by the translation system to fetch the correct plural form for the current language. + For detailed examples, see [url=$DOCS_URL/tutorials/i18n/localization_using_gettext.html]Localization using gettext[/url]. + [b]Note:[/b] Negative and [float] numbers may not properly apply to some countable subjects. It's recommended handling these cases with [method tr]. </description> </method> </methods> <signals> <signal name="property_list_changed"> <description> + Emitted when [method notify_property_list_changed] is called. </description> </signal> <signal name="script_changed"> <description> - Emitted whenever the object's script is changed. + Emitted when the object's script is changed. + [b]Note:[/b] When this signal is emitted, the new script is not initialized yet. If you need to access the new script, defer connections to this signal with [constant CONNECT_DEFERRED]. </description> </signal> </signals> <constants> <constant name="NOTIFICATION_POSTINITIALIZE" value="0"> - Called right when the object is initialized. Not available in script. + Notification received when the object is initialized, before its script is attached. Used internally. </constant> <constant name="NOTIFICATION_PREDELETE" value="1"> - Called before the object is about to be deleted. + Notification received when the object is about to be deleted. Can act as the deconstructor of some programming languages. </constant> <constant name="CONNECT_DEFERRED" value="1" enum="ConnectFlags"> - Connects a signal in deferred mode. This way, signal emissions are stored in a queue, then set on idle time. + Deferred connections trigger their [Callable]s on idle time, rather than instantly. </constant> <constant name="CONNECT_PERSIST" value="2" enum="ConnectFlags"> - Persisting connections are saved when the object is serialized to file. + Persisting connections are stored when the object is serialized (such as when using [method PackedScene.pack]). In the editor, connections created through the Node dock are always persisting. </constant> <constant name="CONNECT_ONE_SHOT" value="4" enum="ConnectFlags"> One-shot connections disconnect themselves after emission. </constant> <constant name="CONNECT_REFERENCE_COUNTED" value="8" enum="ConnectFlags"> - Connect a signal as reference-counted. This means that a given signal can be connected several times to the same target, and will only be fully disconnected once no references are left. + Reference-counted connections can be assigned to the same [Callable] multiple times. Each disconnection decreases the internal counter. The signal fully disconnects only when the counter reaches 0. </constant> </constants> </class> diff --git a/doc/classes/OfflineMultiplayerPeer.xml b/doc/classes/OfflineMultiplayerPeer.xml new file mode 100644 index 0000000000..5e15992d54 --- /dev/null +++ b/doc/classes/OfflineMultiplayerPeer.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="OfflineMultiplayerPeer" inherits="MultiplayerPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + A [MultiplayerPeer] which is always connected and acts as a server. + </brief_description> + <description> + This is the default [member MultiplayerAPI.multiplayer_peer] for the [member Node.multiplayer]. It mimics the behavior of a server with no peers connected. + This means that the [SceneTree] will act as the multiplayer authority by default. Calls to [method MultiplayerAPI.is_server] will return [code]true[/code], and calls to [method MultiplayerAPI.get_unique_id] will return [constant MultiplayerPeer.TARGET_PEER_SERVER]. + </description> + <tutorials> + </tutorials> +</class> diff --git a/doc/classes/PathFollow3D.xml b/doc/classes/PathFollow3D.xml index ba7207be8f..fa7580b7b6 100644 --- a/doc/classes/PathFollow3D.xml +++ b/doc/classes/PathFollow3D.xml @@ -9,6 +9,16 @@ </description> <tutorials> </tutorials> + <methods> + <method name="correct_posture" qualifiers="static"> + <return type="Transform3D" /> + <param index="0" name="transform" type="Transform3D" /> + <param index="1" name="rotation_mode" type="int" enum="PathFollow3D.RotationMode" /> + <description> + Correct the [code]transform[/code]. [code]rotation_mode[/code] implicitly specifies how posture (forward, up and sideway direction) is caculated. + </description> + </method> + </methods> <members> <member name="cubic_interp" type="bool" setter="set_cubic_interpolation" getter="get_cubic_interpolation" default="true"> If [code]true[/code], the position between two cached points is interpolated cubically, and linearly otherwise. @@ -30,6 +40,9 @@ <member name="rotation_mode" type="int" setter="set_rotation_mode" getter="get_rotation_mode" enum="PathFollow3D.RotationMode" default="3"> Allows or forbids rotation on one or more axes, depending on the [enum RotationMode] constants being used. </member> + <member name="tilt_enabled" type="bool" setter="set_tilt_enabled" getter="is_tilt_enabled" default="true"> + If [code]true[/code], the tilt property of [Curve3D] takes effect. + </member> <member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0"> The node's offset perpendicular to the curve. </member> diff --git a/doc/classes/PhysicalSkyMaterial.xml b/doc/classes/PhysicalSkyMaterial.xml index 9d303d80e5..a8cfb9abc2 100644 --- a/doc/classes/PhysicalSkyMaterial.xml +++ b/doc/classes/PhysicalSkyMaterial.xml @@ -12,27 +12,28 @@ </tutorials> <members> <member name="energy_multiplier" type="float" setter="set_energy_multiplier" getter="get_energy_multiplier" default="1.0"> + The sky's overall brightness multiplier. Higher values result in a brighter sky. </member> <member name="ground_color" type="Color" setter="set_ground_color" getter="get_ground_color" default="Color(0.1, 0.07, 0.034, 1)"> Modulates the [Color] on the bottom half of the sky to represent the ground. </member> <member name="mie_coefficient" type="float" setter="set_mie_coefficient" getter="get_mie_coefficient" default="0.005"> - Controls the strength of mie scattering for the sky. Mie scattering results from light colliding with larger particles (like water). On earth, mie scattering results in a whitish color around the sun and horizon. + Controls the strength of [url=https://en.wikipedia.org/wiki/Mie_scattering]Mie scattering[/url] for the sky. Mie scattering results from light colliding with larger particles (like water). On earth, Mie scattering results in a whitish color around the sun and horizon. </member> <member name="mie_color" type="Color" setter="set_mie_color" getter="get_mie_color" default="Color(0.69, 0.729, 0.812, 1)"> - Controls the [Color] of the mie scattering effect. While not physically accurate, this allows for the creation of alien-looking planets. + Controls the [Color] of the [url=https://en.wikipedia.org/wiki/Mie_scattering]Mie scattering[/url] effect. While not physically accurate, this allows for the creation of alien-looking planets. </member> <member name="mie_eccentricity" type="float" setter="set_mie_eccentricity" getter="get_mie_eccentricity" default="0.8"> - Controls the direction of the mie scattering. A value of [code]1[/code] means that when light hits a particle it's passing through straight forward. A value of [code]-1[/code] means that all light is scatter backwards. + Controls the direction of the [url=https://en.wikipedia.org/wiki/Mie_scattering]Mie scattering[/url]. A value of [code]1[/code] means that when light hits a particle it's passing through straight forward. A value of [code]-1[/code] means that all light is scatter backwards. </member> <member name="night_sky" type="Texture2D" setter="set_night_sky" getter="get_night_sky"> [Texture2D] for the night sky. This is added to the sky, so if it is bright enough, it may be visible during the day. </member> <member name="rayleigh_coefficient" type="float" setter="set_rayleigh_coefficient" getter="get_rayleigh_coefficient" default="2.0"> - Controls the strength of the Rayleigh scattering. Rayleigh scattering results from light colliding with small particles. It is responsible for the blue color of the sky. + Controls the strength of the [url=https://en.wikipedia.org/wiki/Rayleigh_scattering]Rayleigh scattering[/url]. Rayleigh scattering results from light colliding with small particles. It is responsible for the blue color of the sky. </member> <member name="rayleigh_color" type="Color" setter="set_rayleigh_color" getter="get_rayleigh_color" default="Color(0.3, 0.405, 0.6, 1)"> - Controls the [Color] of the Rayleigh scattering. While not physically accurate, this allows for the creation of alien-looking planets. For example, setting this to a red [Color] results in a Mars-looking atmosphere with a corresponding blue sunset. + Controls the [Color] of the [url=https://en.wikipedia.org/wiki/Rayleigh_scattering]Rayleigh scattering[/url]. While not physically accurate, this allows for the creation of alien-looking planets. For example, setting this to a red [Color] results in a Mars-looking atmosphere with a corresponding blue sunset. </member> <member name="sun_disk_scale" type="float" setter="set_sun_disk_scale" getter="get_sun_disk_scale" default="1.0"> Sets the size of the sun disk. Default value is based on Sol's perceived size from Earth. diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml index 59660b4de5..30fa54d669 100644 --- a/doc/classes/PhysicsBody2D.xml +++ b/doc/classes/PhysicsBody2D.xml @@ -25,12 +25,12 @@ </method> <method name="move_and_collide"> <return type="KinematicCollision2D" /> - <param index="0" name="distance" type="Vector2" /> + <param index="0" name="motion" type="Vector2" /> <param index="1" name="test_only" type="bool" default="false" /> <param index="2" name="safe_margin" type="float" default="0.08" /> <param index="3" name="recovery_as_collision" type="bool" default="false" /> <description> - Moves the body along the vector [param distance]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. + Moves the body along the vector [param motion]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param motion] should be computed using [code]delta[/code]. Returns a [KinematicCollision2D], which contains information about the collision when stopped, or when touching another body along the motion. If [param test_only] is [code]true[/code], the body does not move but the would-be collision information is given. [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.safe_margin] for more details). @@ -47,13 +47,13 @@ <method name="test_move"> <return type="bool" /> <param index="0" name="from" type="Transform2D" /> - <param index="1" name="distance" type="Vector2" /> + <param index="1" name="motion" type="Vector2" /> <param index="2" name="collision" type="KinematicCollision2D" default="null" /> <param index="3" name="safe_margin" type="float" default="0.08" /> <param index="4" name="recovery_as_collision" type="bool" default="false" /> <description> - Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. - Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [param distance]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path. + Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param motion] should be computed using [code]delta[/code]. + Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [param motion]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path. [param collision] is an optional object of type [KinematicCollision2D], which contains additional information about the collision when stopped, or when touching another body along the motion. [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.safe_margin] for more details). If [param recovery_as_collision] is [code]true[/code], any depenetration from the recovery phase is also reported as a collision; this is useful for checking whether the body would [i]touch[/i] any other bodies. diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml index bf7882a1ea..2ef54683f2 100644 --- a/doc/classes/PhysicsBody3D.xml +++ b/doc/classes/PhysicsBody3D.xml @@ -32,13 +32,13 @@ </method> <method name="move_and_collide"> <return type="KinematicCollision3D" /> - <param index="0" name="distance" type="Vector3" /> + <param index="0" name="motion" type="Vector3" /> <param index="1" name="test_only" type="bool" default="false" /> <param index="2" name="safe_margin" type="float" default="0.001" /> <param index="3" name="recovery_as_collision" type="bool" default="false" /> <param index="4" name="max_collisions" type="int" default="1" /> <description> - Moves the body along the vector [param distance]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. + Moves the body along the vector [param motion]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param motion] should be computed using [code]delta[/code]. The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision when stopped, or when touching another body along the motion. If [param test_only] is [code]true[/code], the body does not move but the would-be collision information is given. [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.safe_margin] for more details). @@ -64,14 +64,14 @@ <method name="test_move"> <return type="bool" /> <param index="0" name="from" type="Transform3D" /> - <param index="1" name="distance" type="Vector3" /> + <param index="1" name="motion" type="Vector3" /> <param index="2" name="collision" type="KinematicCollision3D" default="null" /> <param index="3" name="safe_margin" type="float" default="0.001" /> <param index="4" name="recovery_as_collision" type="bool" default="false" /> <param index="5" name="max_collisions" type="int" default="1" /> <description> - Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. - Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [param distance]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path. + Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param motion] should be computed using [code]delta[/code]. + Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [param motion]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path. [param collision] is an optional object of type [KinematicCollision3D], which contains additional information about the collision when stopped, or when touching another body along the motion. [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.safe_margin] for more details). If [param recovery_as_collision] is [code]true[/code], any depenetration from the recovery phase is also reported as a collision; this is useful for checking whether the body would [i]touch[/i] any other bodies. diff --git a/doc/classes/PhysicsPointQueryParameters2D.xml b/doc/classes/PhysicsPointQueryParameters2D.xml index a6cbe2d574..e49d2a9f5f 100644 --- a/doc/classes/PhysicsPointQueryParameters2D.xml +++ b/doc/classes/PhysicsPointQueryParameters2D.xml @@ -22,7 +22,7 @@ The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> - The list of objects or object [RID]s that will be excluded from collisions. + The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject2D.get_rid] to get the [RID] associated with a [CollisionObject2D]-derived node. </member> <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)"> The position being queried for, in global coordinates. diff --git a/doc/classes/PhysicsPointQueryParameters3D.xml b/doc/classes/PhysicsPointQueryParameters3D.xml index bedf05ce99..3270d3686d 100644 --- a/doc/classes/PhysicsPointQueryParameters3D.xml +++ b/doc/classes/PhysicsPointQueryParameters3D.xml @@ -18,8 +18,8 @@ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="4294967295"> The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> - <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]"> - The list of objects or object [RID]s that will be excluded from collisions. + <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> + The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject3D.get_rid] to get the [RID] associated with a [CollisionObject3D]-derived node. </member> <member name="position" type="Vector3" setter="set_position" getter="get_position" default="Vector3(0, 0, 0)"> The position being queried for, in global coordinates. diff --git a/doc/classes/PhysicsRayQueryParameters2D.xml b/doc/classes/PhysicsRayQueryParameters2D.xml index d6a2662adc..cf5c31d9ec 100644 --- a/doc/classes/PhysicsRayQueryParameters2D.xml +++ b/doc/classes/PhysicsRayQueryParameters2D.xml @@ -35,7 +35,7 @@ The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> - The list of objects or object [RID]s that will be excluded from collisions. + The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject2D.get_rid] to get the [RID] associated with a [CollisionObject2D]-derived node. </member> <member name="from" type="Vector2" setter="set_from" getter="get_from" default="Vector2(0, 0)"> The starting point of the ray being queried for, in global coordinates. diff --git a/doc/classes/PhysicsRayQueryParameters3D.xml b/doc/classes/PhysicsRayQueryParameters3D.xml index 620aa6bf5f..4f70eedb21 100644 --- a/doc/classes/PhysicsRayQueryParameters3D.xml +++ b/doc/classes/PhysicsRayQueryParameters3D.xml @@ -14,7 +14,7 @@ <param index="0" name="from" type="Vector3" /> <param index="1" name="to" type="Vector3" /> <param index="2" name="collision_mask" type="int" default="4294967295" /> - <param index="3" name="exclude" type="Array" default="[]" /> + <param index="3" name="exclude" type="RID[]" default="[]" /> <description> Returns a new, pre-configured [PhysicsRayQueryParameters3D] object. Use it to quickly create query parameters using the most common options. [codeblock] @@ -34,8 +34,8 @@ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="4294967295"> The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> - <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]"> - The list of objects or object [RID]s that will be excluded from collisions. + <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> + The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject3D.get_rid] to get the [RID] associated with a [CollisionObject3D]-derived node. </member> <member name="from" type="Vector3" setter="set_from" getter="get_from" default="Vector3(0, 0, 0)"> The starting point of the ray being queried for, in global coordinates. diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml index 8dcb329e7e..a73e60c6f5 100644 --- a/doc/classes/PhysicsShapeQueryParameters2D.xml +++ b/doc/classes/PhysicsShapeQueryParameters2D.xml @@ -19,7 +19,7 @@ The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> - The list of objects or object [RID]s that will be excluded from collisions. + The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject2D.get_rid] to get the [RID] associated with a [CollisionObject2D]-derived node. </member> <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0"> The collision margin for the shape. diff --git a/doc/classes/PhysicsShapeQueryParameters3D.xml b/doc/classes/PhysicsShapeQueryParameters3D.xml index 64100f847b..a3ff1765f9 100644 --- a/doc/classes/PhysicsShapeQueryParameters3D.xml +++ b/doc/classes/PhysicsShapeQueryParameters3D.xml @@ -18,8 +18,8 @@ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="4294967295"> The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> - <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]"> - The list of objects or object [RID]s that will be excluded from collisions. + <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> + The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject3D.get_rid] to get the [RID] associated with a [CollisionObject3D]-derived node. </member> <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0"> The collision margin for the shape. diff --git a/doc/classes/PhysicsTestMotionParameters2D.xml b/doc/classes/PhysicsTestMotionParameters2D.xml index 5b969ea869..be5e5a3617 100644 --- a/doc/classes/PhysicsTestMotionParameters2D.xml +++ b/doc/classes/PhysicsTestMotionParameters2D.xml @@ -14,9 +14,9 @@ If set to [code]false[/code], shapes of type [constant PhysicsServer2D.SHAPE_SEPARATION_RAY] are only used for separation when overlapping with other bodies. That's the main use for separation ray shapes. </member> <member name="exclude_bodies" type="RID[]" setter="set_exclude_bodies" getter="get_exclude_bodies" default="[]"> - Optional array of body [RID] to exclude from collision. + Optional array of body [RID] to exclude from collision. Use [method CollisionObject2D.get_rid] to get the [RID] associated with a [CollisionObject2D]-derived node. </member> - <member name="exclude_objects" type="Array" setter="set_exclude_objects" getter="get_exclude_objects" default="[]"> + <member name="exclude_objects" type="int[]" setter="set_exclude_objects" getter="get_exclude_objects" default="[]"> Optional array of object unique instance ID to exclude from collision. See [method Object.get_instance_id]. </member> <member name="from" type="Transform2D" setter="set_from" getter="get_from" default="Transform2D(1, 0, 0, 1, 0, 0)"> diff --git a/doc/classes/PhysicsTestMotionParameters3D.xml b/doc/classes/PhysicsTestMotionParameters3D.xml index ea9bca6a35..be7d05691e 100644 --- a/doc/classes/PhysicsTestMotionParameters3D.xml +++ b/doc/classes/PhysicsTestMotionParameters3D.xml @@ -13,10 +13,10 @@ If set to [code]true[/code], shapes of type [constant PhysicsServer3D.SHAPE_SEPARATION_RAY] are used to detect collisions and can stop the motion. Can be useful when snapping to the ground. If set to [code]false[/code], shapes of type [constant PhysicsServer3D.SHAPE_SEPARATION_RAY] are only used for separation when overlapping with other bodies. That's the main use for separation ray shapes. </member> - <member name="exclude_bodies" type="Array" setter="set_exclude_bodies" getter="get_exclude_bodies" default="[]"> - Optional array of body [RID] to exclude from collision. + <member name="exclude_bodies" type="RID[]" setter="set_exclude_bodies" getter="get_exclude_bodies" default="[]"> + Optional array of body [RID] to exclude from collision. Use [method CollisionObject3D.get_rid] to get the [RID] associated with a [CollisionObject3D]-derived node. </member> - <member name="exclude_objects" type="Array" setter="set_exclude_objects" getter="get_exclude_objects" default="[]"> + <member name="exclude_objects" type="int[]" setter="set_exclude_objects" getter="get_exclude_objects" default="[]"> Optional array of object unique instance ID to exclude from collision. See [method Object.get_instance_id]. </member> <member name="from" type="Transform3D" setter="set_from" getter="get_from" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> diff --git a/doc/classes/Popup.xml b/doc/classes/Popup.xml index 3fcf0a9b8f..a56bf77774 100644 --- a/doc/classes/Popup.xml +++ b/doc/classes/Popup.xml @@ -4,7 +4,7 @@ Popup is a base window container for popup-like subwindows. </brief_description> <description> - Popup is a base window container for popup-like subwindows. It's a modal by default (see [member popup_window]) and has helpers for custom popup behavior. + Popup is a base window container for popup-like subwindows. It's a modal by default (see [member Window.popup_window]) and has helpers for custom popup behavior. </description> <tutorials> </tutorials> diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml index 0dcb33ac4c..a69163f429 100644 --- a/doc/classes/PopupMenu.xml +++ b/doc/classes/PopupMenu.xml @@ -544,6 +544,7 @@ </signal> <signal name="menu_changed"> <description> + Emitted when any item is added, modified or removed. </description> </signal> </signals> @@ -576,8 +577,10 @@ Width of the single indentation level. </theme_item> <theme_item name="item_end_padding" data_type="constant" type="int" default="2"> + Horizontal padding to the right of the items (or left, in RTL layout). </theme_item> <theme_item name="item_start_padding" data_type="constant" type="int" default="2"> + Horizontal padding to the left of the items (or right, in RTL layout). </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the item text outline. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 3478215f4f..b6f92c2c40 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -401,7 +401,7 @@ <member name="debug/gdscript/warnings/redundant_await" type="int" setter="" getter="" default="1"> When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a function that is not a coroutine is called with await. </member> - <member name="debug/gdscript/warnings/return_value_discarded" type="int" setter="" getter="" default="1"> + <member name="debug/gdscript/warnings/return_value_discarded" type="int" setter="" getter="" default="0"> When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a function without using its return value (by assigning it to a variable or using it as a function argument). Such return values are sometimes used to denote possible errors using the [enum Error] enum. </member> <member name="debug/gdscript/warnings/shadowed_global_identifier" type="int" setter="" getter="" default="1"> @@ -839,6 +839,7 @@ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. </member> <member name="input/ui_swap_input_direction" type="Dictionary" setter="" getter=""> + Default [InputEventAction] to swap input direction, i.e. change between left-to-right to right-to-left modes. Affects text-editting controls ([LineEdit], [TextEdit]). </member> <member name="input/ui_text_add_selection_for_next_occurrence" type="Dictionary" setter="" getter=""> If a selection is currently active with the last caret in text fields, searches for the next occurrence of the selection, adds a caret and selects the next occurrence. diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml index 28fe42afae..d39e50d5f0 100644 --- a/doc/classes/Rect2.xml +++ b/doc/classes/Rect2.xml @@ -82,9 +82,9 @@ var rect2 = rect.expand(Vector2(0, -1)) [/gdscript] [csharp] - # position (-3, 2), size (1, 1) + // position (-3, 2), size (1, 1) var rect = new Rect2(new Vector2(-3, 2), new Vector2(1, 1)); - # position (-3, -1), size (3, 4), so we fit both rect and Vector2(0, -1) + // position (-3, -1), size (3, 4), so we fit both rect and Vector2(0, -1) var rect2 = rect.Expand(new Vector2(0, -1)); [/csharp] [/codeblocks] diff --git a/doc/classes/Rect2i.xml b/doc/classes/Rect2i.xml index 6d4c113609..325ead0cfa 100644 --- a/doc/classes/Rect2i.xml +++ b/doc/classes/Rect2i.xml @@ -79,9 +79,9 @@ var rect2 = rect.expand(Vector2i(0, -1)) [/gdscript] [csharp] - # position (-3, 2), size (1, 1) + // position (-3, 2), size (1, 1) var rect = new Rect2i(new Vector2i(-3, 2), new Vector2i(1, 1)); - # position (-3, -1), size (3, 4), so we fit both rect and Vector2i(0, -1) + // position (-3, -1), size (3, 4), so we fit both rect and Vector2i(0, -1) var rect2 = rect.Expand(new Vector2i(0, -1)); [/csharp] [/codeblocks] diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index 2de812f5fc..580ce6f382 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -9,8 +9,8 @@ <methods> <method name="barrier"> <return type="void" /> - <param index="0" name="from" type="int" default="7" /> - <param index="1" name="to" type="int" default="7" /> + <param index="0" name="from" type="int" enum="RenderingDevice.BarrierMask" default="7" /> + <param index="1" name="to" type="int" enum="RenderingDevice.BarrierMask" default="7" /> <description> </description> </method> @@ -19,7 +19,7 @@ <param index="0" name="buffer" type="RID" /> <param index="1" name="offset" type="int" /> <param index="2" name="size_bytes" type="int" /> - <param index="3" name="post_barrier" type="int" default="7" /> + <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" /> <description> </description> </method> @@ -35,7 +35,7 @@ <param index="1" name="offset" type="int" /> <param index="2" name="size_bytes" type="int" /> <param index="3" name="data" type="PackedByteArray" /> - <param index="4" name="post_barrier" type="int" default="7" /> + <param index="4" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" /> <description> </description> </method> @@ -83,7 +83,7 @@ </method> <method name="compute_list_end"> <return type="void" /> - <param index="0" name="post_barrier" type="int" default="7" /> + <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" /> <description> </description> </method> @@ -223,7 +223,7 @@ </method> <method name="draw_list_end"> <return type="void" /> - <param index="0" name="post_barrier" type="int" default="7" /> + <param index="0" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" /> <description> </description> </method> @@ -534,7 +534,7 @@ <param index="3" name="mipmap_count" type="int" /> <param index="4" name="base_layer" type="int" /> <param index="5" name="layer_count" type="int" /> - <param index="6" name="post_barrier" type="int" default="7" /> + <param index="6" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" /> <description> </description> </method> @@ -549,7 +549,7 @@ <param index="6" name="dst_mipmap" type="int" /> <param index="7" name="src_layer" type="int" /> <param index="8" name="dst_layer" type="int" /> - <param index="9" name="post_barrier" type="int" default="7" /> + <param index="9" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" /> <description> </description> </method> @@ -609,7 +609,7 @@ <return type="int" enum="Error" /> <param index="0" name="from_texture" type="RID" /> <param index="1" name="to_texture" type="RID" /> - <param index="2" name="post_barrier" type="int" default="7" /> + <param index="2" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" /> <description> </description> </method> @@ -618,7 +618,7 @@ <param index="0" name="texture" type="RID" /> <param index="1" name="layer" type="int" /> <param index="2" name="data" type="PackedByteArray" /> - <param index="3" name="post_barrier" type="int" default="7" /> + <param index="3" name="post_barrier" type="int" enum="RenderingDevice.BarrierMask" default="7" /> <description> </description> </method> @@ -648,8 +648,9 @@ <param index="0" name="vertex_count" type="int" /> <param index="1" name="vertex_format" type="int" /> <param index="2" name="src_buffers" type="RID[]" /> + <param index="3" name="offsets" type="PackedInt64Array" default="PackedInt64Array()" /> <description> - Creates a vertex array based on the specified buffers. + Creates a vertex array based on the specified buffers. Optionally, [param offsets] (in bytes) may be defined for each buffer. </description> </method> <method name="vertex_buffer_create"> @@ -668,16 +669,6 @@ </method> </methods> <constants> - <constant name="BARRIER_MASK_RASTER" value="1"> - </constant> - <constant name="BARRIER_MASK_COMPUTE" value="2"> - </constant> - <constant name="BARRIER_MASK_TRANSFER" value="4"> - </constant> - <constant name="BARRIER_MASK_ALL" value="7"> - </constant> - <constant name="BARRIER_MASK_NO_BARRIER" value="8"> - </constant> <constant name="DEVICE_TYPE_OTHER" value="0" enum="DeviceType"> Rendering device type does not match any of the other enum values or is unknown. </constant> @@ -1160,6 +1151,16 @@ </constant> <constant name="DATA_FORMAT_MAX" value="218" enum="DataFormat"> </constant> + <constant name="BARRIER_MASK_RASTER" value="1" enum="BarrierMask" is_bitfield="true"> + </constant> + <constant name="BARRIER_MASK_COMPUTE" value="2" enum="BarrierMask" is_bitfield="true"> + </constant> + <constant name="BARRIER_MASK_TRANSFER" value="4" enum="BarrierMask" is_bitfield="true"> + </constant> + <constant name="BARRIER_MASK_ALL_BARRIERS" value="7" enum="BarrierMask" is_bitfield="true"> + </constant> + <constant name="BARRIER_MASK_NO_BARRIER" value="8" enum="BarrierMask" is_bitfield="true"> + </constant> <constant name="TEXTURE_TYPE_1D" value="0" enum="TextureType"> </constant> <constant name="TEXTURE_TYPE_2D" value="1" enum="TextureType"> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 13e5470a56..2ffa4dc50b 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -838,6 +838,8 @@ <method name="create_local_rendering_device" qualifiers="const"> <return type="RenderingDevice" /> <description> + Creates a RenderingDevice that can be used to do draw and compute operations on a separate thread. Cannot draw to the screen nor share data with the global RenderingDevice. + [b]Note:[/b] When using the OpenGL backend or when running in headless mode, this function always returns [code]null[/code]. </description> </method> <method name="decal_create"> @@ -1273,6 +1275,8 @@ <method name="get_rendering_device" qualifiers="const"> <return type="RenderingDevice" /> <description> + Returns the global RenderingDevice. + [b]Note:[/b] When using the OpenGL backend or when running in headless mode, this function always returns [code]null[/code]. </description> </method> <method name="get_rendering_info"> diff --git a/doc/classes/ScrollContainer.xml b/doc/classes/ScrollContainer.xml index b96b7187e4..af39261e81 100644 --- a/doc/classes/ScrollContainer.xml +++ b/doc/classes/ScrollContainer.xml @@ -49,6 +49,7 @@ Controls whether horizontal scrollbar can be used and when it should be visible. See [enum ScrollMode] for options. </member> <member name="scroll_deadzone" type="int" setter="set_deadzone" getter="get_deadzone" default="0"> + Deadzone for touch scrolling. Lower deadzone makes the scrolling more sensitive. </member> <member name="scroll_horizontal" type="int" setter="set_h_scroll" getter="get_h_scroll" default="0"> The current horizontal scroll value. diff --git a/doc/classes/Signal.xml b/doc/classes/Signal.xml index d99477ee95..3412cd2140 100644 --- a/doc/classes/Signal.xml +++ b/doc/classes/Signal.xml @@ -1,9 +1,29 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="Signal" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> - Class representing a signal defined in an object. + Built-in type representing a signal defined in an object. </brief_description> <description> + [Signal] is a built-in [Variant] type that represents a signal of an [Object] instance. Like all [Variant] types, it can be stored in variables and passed to functions. Signals allow all connected [Callable]s (and by extension their respective objects) to listen and react to events, without directly referencing one another. This keeps the code flexible and easier to manage. + In GDScript, signals can be declared with the [code]signal[/code] keyword. In C#, you may use the [code][Signal][/code] attribute on a delegate. + [codeblocks] + [gdscript] + signal attacked + + # Additional arguments may be declared. + # These arguments must be passed when the signal is emitted. + signal item_dropped(item_name, amount) + [/gdscript] + [csharp] + [Signal] + delegate void Attacked(); + + // Additional arguments may be declared. + // These arguments must be passed when the signal is emitted. + [Signal] + delegate void ItemDropped(itemName: string, amount: int); + [/csharp] + [/codeblocks] </description> <tutorials> <link title="Using Signals">$DOCS_URL/getting_started/step_by_step/signals.html</link> @@ -13,7 +33,7 @@ <constructor name="Signal"> <return type="Signal" /> <description> - Constructs a null [Signal] with no object nor signal name bound. + Constructs an empty [Signal] with no object nor signal name bound. </description> </constructor> <constructor name="Signal"> @@ -28,7 +48,7 @@ <param index="0" name="object" type="Object" /> <param index="1" name="signal" type="StringName" /> <description> - Creates a new [Signal] with the name [param signal] in the specified [param object]. + Creates a new [Signal] named [param signal] in the specified [param object]. </description> </constructor> </constructors> @@ -38,12 +58,13 @@ <param index="0" name="callable" type="Callable" /> <param index="1" name="flags" type="int" default="0" /> <description> - Connects this signal to the specified [Callable], optionally providing connection flags. You can provide additional arguments to the connected method call by using [method Callable.bind]. + Connects this signal to the specified [param callable]. Optional [param flags] can be also added to configure the connection's behavior (see [enum Object.ConnectFlags] constants). You can provide additional arguments to the connected [param callable] by using [method Callable.bind]. + A signal can only be connected once to the same [Callable]. If the signal is already connected, returns [constant ERR_INVALID_PARAMETER] and pushes an error message, unless the signal is connected with [constant Object.CONNECT_REFERENCE_COUNTED]. To prevent this, use [method is_connected] first to check for existing connections. [codeblock] for button in $Buttons.get_children(): - button.pressed.connect(on_pressed.bind(button)) + button.pressed.connect(_on_pressed.bind(button)) - func on_pressed(button): + func _on_pressed(button): print(button.name, " was pressed") [/codeblock] </description> @@ -52,13 +73,13 @@ <return type="void" /> <param index="0" name="callable" type="Callable" /> <description> - Disconnects this signal from the specified [Callable]. + Disconnects this signal from the specified [Callable]. If the connection does not exist, generates an error. Use [method is_connected] to make sure that the connection exists. </description> </method> <method name="emit" qualifiers="vararg const"> <return type="void" /> <description> - Emits this signal to all connected objects. + Emits this signal. All [Callable]s connected to this signal will be triggered. This method supports a variable number of arguments, so parameters can be passed as a comma separated list. </description> </method> <method name="get_connections" qualifiers="const"> @@ -95,6 +116,7 @@ <method name="is_null" qualifiers="const"> <return type="bool" /> <description> + Returns [code]true[/code] if the signal's name does not exist in its object, or the object is not valid. </description> </method> </methods> @@ -103,12 +125,14 @@ <return type="bool" /> <param index="0" name="right" type="Signal" /> <description> + Returns [code]true[/code] if the signals do not share the same object and name. </description> </operator> <operator name="operator =="> <return type="bool" /> <param index="0" name="right" type="Signal" /> <description> + Returns [code]true[/code] if both signals share the same object and name. </description> </operator> </operators> diff --git a/doc/classes/SpinBox.xml b/doc/classes/SpinBox.xml index e214867890..7d63747bd2 100644 --- a/doc/classes/SpinBox.xml +++ b/doc/classes/SpinBox.xml @@ -46,6 +46,7 @@ </methods> <members> <member name="alignment" type="int" setter="set_horizontal_alignment" getter="get_horizontal_alignment" enum="HorizontalAlignment" default="0"> + Changes the alignment of the underlying [LineEdit]. </member> <member name="custom_arrow_step" type="float" setter="set_custom_arrow_step" getter="get_custom_arrow_step" default="0.0"> If not [code]0[/code], [code]value[/code] will always be rounded to a multiple of [code]custom_arrow_step[/code] when interacting with the arrow buttons of the [SpinBox]. diff --git a/doc/classes/Sprite3D.xml b/doc/classes/Sprite3D.xml index 956e646702..01671aa04e 100644 --- a/doc/classes/Sprite3D.xml +++ b/doc/classes/Sprite3D.xml @@ -19,6 +19,7 @@ The number of columns in the sprite sheet. </member> <member name="region_enabled" type="bool" setter="set_region_enabled" getter="is_region_enabled" default="false"> + If [code]true[/code], the sprite will use [member region_rect] and display only the specified part of its texture. </member> <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2(0, 0, 0, 0)"> The region of the atlas texture to display. [member region_enabled] must be [code]true[/code]. diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 999913b1ac..c186952c74 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -27,14 +27,14 @@ <return type="String" /> <param index="0" name="from" type="NodePath" /> <description> - Constructs a new String from the given [NodePath]. + Constructs a new [String] from the given [NodePath]. </description> </constructor> <constructor name="String"> <return type="String" /> <param index="0" name="from" type="StringName" /> <description> - Constructs a new String from the given [StringName]. + Constructs a new [String] from the given [StringName]. </description> </constructor> </constructors> @@ -51,7 +51,7 @@ <description> Returns an array containing the bigrams (pairs of consecutive letters) of this string. [codeblock] - print("Bigrams".bigrams()) # Prints "[Bi, ig, gr, ra, am, ms]" + print("Bigrams".bigrams()) # Prints ["Bi", "ig", "gr", "ra", "am", "ms"] [/codeblock] </description> </method> @@ -738,7 +738,7 @@ </description> </method> <method name="split_floats" qualifiers="const"> - <return type="PackedFloat32Array" /> + <return type="PackedFloat64Array" /> <param index="0" name="delimiter" type="String" /> <param index="1" name="allow_empty" type="bool" default="true" /> <description> @@ -920,66 +920,88 @@ <return type="bool" /> <param index="0" name="right" type="String" /> <description> + Returns [code]true[/code] if both strings do not contain the same sequence of characters. </description> </operator> <operator name="operator !="> <return type="bool" /> <param index="0" name="right" type="StringName" /> <description> + Returns [code]true[/code] if this [String] is not equivalent to the given [StringName]. </description> </operator> <operator name="operator %"> <return type="String" /> <param index="0" name="right" type="Variant" /> <description> + Formats the [String], replacing the placeholders with one or more parameters. + To pass multiple parameters, [param right] needs to be an [Array]. + [codeblock] + print("I caught %d fishes!" % 2) # Prints "I caught 2 fishes!" + + var my_message = "Travelling to %s, at %2.2f per second." + var location = "Deep Valley" + var speed = 40.3485 + print(my_message % [location, speed]) # Prints "Travelling to Deep Valley, at 40.35 km/h." + [/codeblock] + In C#, there is no direct equivalent to this operator. Use the [method format] method, instead. + For more information, see the [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_format_string.html]GDScript format strings[/url] tutorial. </description> </operator> <operator name="operator +"> <return type="String" /> <param index="0" name="right" type="String" /> <description> + Appends [param right] at the end of this [String], also known as a string concatenation. </description> </operator> <operator name="operator <"> <return type="bool" /> <param index="0" name="right" type="String" /> <description> + Returns [code]true[/code] if the left [String] comes before [param right] in [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode order[/url], which roughly matches the alphabetical order. Useful for sorting. </description> </operator> <operator name="operator <="> <return type="bool" /> <param index="0" name="right" type="String" /> <description> + Returns [code]true[/code] if the left [String] comes before [param right] in [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode order[/url], which roughly matches the alphabetical order, or if both are equal. </description> </operator> <operator name="operator =="> <return type="bool" /> <param index="0" name="right" type="String" /> <description> + Returns [code]true[/code] if both strings contain the same sequence of characters. </description> </operator> <operator name="operator =="> <return type="bool" /> <param index="0" name="right" type="StringName" /> <description> + Returns [code]true[/code] if this [String] is equivalent to the given [StringName]. </description> </operator> <operator name="operator >"> <return type="bool" /> <param index="0" name="right" type="String" /> <description> + Returns [code]true[/code] if the left [String] comes after [param right] in [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode order[/url], which roughly matches the alphabetical order. Useful for sorting. </description> </operator> <operator name="operator >="> <return type="bool" /> <param index="0" name="right" type="String" /> <description> + Returns [code]true[/code] if the left [String] comes after [param right] in [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode order[/url], which roughly matches the alphabetical order, or if both are equal. </description> </operator> <operator name="operator []"> <return type="String" /> <param index="0" name="index" type="int" /> <description> + Returns a new [String] that only contains the character at [param index]. Indices start from [code]0[/code]. If [param index] is greater or equal to [code]0[/code], the character is fetched starting from the beginning of the string. If [param index] is a negative value, it is fetched starting from the end. Accessing a string out-of-bounds will cause a run-time error, pausing the project execution if run from the editor. </description> </operator> </operators> diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml index c40d8929fc..02e9c62cd6 100644 --- a/doc/classes/StringName.xml +++ b/doc/classes/StringName.xml @@ -5,7 +5,7 @@ </brief_description> <description> [StringName]s are immutable strings designed for general-purpose representation of unique names (also called "string interning"). [StringName] ensures that only one instance of a given name exists (so two [StringName]s with the same value are the same object). Comparing them is much faster than with regular [String]s, because only the pointers are compared, not the whole strings. - You will usually just pass a [String] to methods expecting a [StringName] and it will be automatically converted, but you may occasionally want to construct a [StringName] ahead of time with [StringName] or the literal syntax [code]&"example"[/code]. + You will usually just pass a [String] to methods expecting a [StringName] and it will be automatically converted, but you may occasionally want to construct a [StringName] ahead of time with [StringName] or, in GDScript, the literal syntax [code]&"example"[/code]. See also [NodePath], which is a similar concept specifically designed to store pre-parsed node paths. </description> <tutorials> @@ -28,7 +28,7 @@ <return type="StringName" /> <param index="0" name="from" type="String" /> <description> - Creates a new [StringName] from the given [String]. [code]StringName("example")[/code] is equivalent to [code]&"example"[/code]. + Creates a new [StringName] from the given [String]. In GDScript, [code]StringName("example")[/code] is equivalent to [code]&"example"[/code]. </description> </constructor> </constructors> @@ -45,48 +45,56 @@ <return type="bool" /> <param index="0" name="right" type="String" /> <description> + Returns [code]true[/code] if this [StringName] is not equivalent to the given [String]. </description> </operator> <operator name="operator !="> <return type="bool" /> <param index="0" name="right" type="StringName" /> <description> + Returns [code]true[/code] if the [StringName] and [param right] do not refer to the same name. Comparisons between [StringName]s are much faster than regular [String] comparisons. </description> </operator> <operator name="operator <"> <return type="bool" /> <param index="0" name="right" type="StringName" /> <description> + Returns [code]true[/code] if the left [String] comes before [param right] in [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode order[/url], which roughly matches the alphabetical order. Useful for sorting. </description> </operator> <operator name="operator <="> <return type="bool" /> <param index="0" name="right" type="StringName" /> <description> + Returns [code]true[/code] if the left [String] comes before [param right] in [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode order[/url], which roughly matches the alphabetical order, or if both are equal. </description> </operator> <operator name="operator =="> <return type="bool" /> <param index="0" name="right" type="String" /> <description> + Returns [code]true[/code] if this [StringName] is equivalent to the given [String]. </description> </operator> <operator name="operator =="> <return type="bool" /> <param index="0" name="right" type="StringName" /> <description> + Returns [code]true[/code] if the [StringName] and [param right] refer to the same name. Comparisons between [StringName]s are much faster than regular [String] comparisons. </description> </operator> <operator name="operator >"> <return type="bool" /> <param index="0" name="right" type="StringName" /> <description> + Returns [code]true[/code] if the left [StringName] comes after [param right] in [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode order[/url], which roughly matches the alphabetical order. Useful for sorting. </description> </operator> <operator name="operator >="> <return type="bool" /> <param index="0" name="right" type="StringName" /> <description> + Returns [code]true[/code] if the left [StringName] comes after [param right] in [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode order[/url], which roughly matches the alphabetical order, or if both are equal. </description> </operator> </operators> diff --git a/doc/classes/TextureButton.xml b/doc/classes/TextureButton.xml index 043eeb9a80..b185828577 100644 --- a/doc/classes/TextureButton.xml +++ b/doc/classes/TextureButton.xml @@ -27,19 +27,19 @@ <member name="texture_click_mask" type="BitMap" setter="set_click_mask" getter="get_click_mask"> Pure black and white [BitMap] image to use for click detection. On the mask, white pixels represent the button's clickable area. Use it to create buttons with curved shapes. </member> - <member name="texture_disabled" type="Texture2D" setter="set_disabled_texture" getter="get_disabled_texture"> + <member name="texture_disabled" type="Texture2D" setter="set_texture_disabled" getter="get_texture_disabled"> Texture to display when the node is disabled. See [member BaseButton.disabled]. </member> - <member name="texture_focused" type="Texture2D" setter="set_focused_texture" getter="get_focused_texture"> + <member name="texture_focused" type="Texture2D" setter="set_texture_focused" getter="get_texture_focused"> Texture to display when the node has mouse or keyboard focus. [member texture_focused] is displayed [i]over[/i] the base texture, so a partially transparent texture should be used to ensure the base texture remains visible. A texture that represents an outline or an underline works well for this purpose. To disable the focus visual effect, assign a fully transparent texture of any size. Note that disabling the focus visual effect will harm keyboard/controller navigation usability, so this is not recommended for accessibility reasons. </member> - <member name="texture_hover" type="Texture2D" setter="set_hover_texture" getter="get_hover_texture"> + <member name="texture_hover" type="Texture2D" setter="set_texture_hover" getter="get_texture_hover"> Texture to display when the mouse hovers the node. </member> - <member name="texture_normal" type="Texture2D" setter="set_normal_texture" getter="get_normal_texture"> + <member name="texture_normal" type="Texture2D" setter="set_texture_normal" getter="get_texture_normal"> Texture to display by default, when the node is [b]not[/b] in the disabled, focused, hover or pressed state. </member> - <member name="texture_pressed" type="Texture2D" setter="set_pressed_texture" getter="get_pressed_texture"> + <member name="texture_pressed" type="Texture2D" setter="set_texture_pressed" getter="get_texture_pressed"> Texture to display on mouse down over the node, if the node has keyboard focus and the player presses the Enter key or if the player presses the [member BaseButton.shortcut] key. </member> </members> diff --git a/doc/classes/TextureProgressBar.xml b/doc/classes/TextureProgressBar.xml index 54b77bf5eb..d7a9d06a15 100644 --- a/doc/classes/TextureProgressBar.xml +++ b/doc/classes/TextureProgressBar.xml @@ -13,6 +13,7 @@ <return type="int" /> <param index="0" name="margin" type="int" enum="Side" /> <description> + Returns the stretch margin with the specified index. See [member stretch_margin_bottom] and related properties. </description> </method> <method name="set_stretch_margin"> @@ -20,6 +21,7 @@ <param index="0" name="margin" type="int" enum="Side" /> <param index="1" name="value" type="int" /> <description> + Sets the stretch margin with the specified index. See [member stretch_margin_bottom] and related properties. </description> </method> </methods> diff --git a/doc/classes/TileData.xml b/doc/classes/TileData.xml index 798a536a88..f815b8d0c3 100644 --- a/doc/classes/TileData.xml +++ b/doc/classes/TileData.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="TileData" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + Settings for a single tile in a [TileSet]. </brief_description> <description> + [TileData] object represents a single tile in a [TileSet]. It is usually edited using the tileset editor, but it can be modified at runtime using [method TileMap._tile_data_runtime_update]. </description> <tutorials> </tutorials> @@ -196,32 +198,43 @@ </methods> <members> <member name="flip_h" type="bool" setter="set_flip_h" getter="get_flip_h" default="false"> + If [code]true[/code], the tile will have its texture flipped horizontally. </member> <member name="flip_v" type="bool" setter="set_flip_v" getter="get_flip_v" default="false"> + If [code]true[/code], the tile will have its texture flipped vertically. </member> <member name="material" type="Material" setter="set_material" getter="get_material"> The [Material] to use for this [TileData]. This can be a [CanvasItemMaterial] to use the default shader, or a [ShaderMaterial] to use a custom shader. </member> <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> + Color modulation of the tile. </member> <member name="probability" type="float" setter="set_probability" getter="get_probability" default="1.0"> + Relative probability of this tile being selected when drawing a pattern of random tiles. </member> <member name="terrain" type="int" setter="set_terrain" getter="get_terrain" default="-1"> + ID of the terrain from the terrain set that the tile uses. </member> <member name="terrain_set" type="int" setter="set_terrain_set" getter="get_terrain_set" default="-1"> + ID of the terrain set that the tile uses. </member> <member name="texture_offset" type="Vector2i" setter="set_texture_offset" getter="get_texture_offset" default="Vector2i(0, 0)"> + Offsets the position of where the tile is drawn. </member> <member name="transpose" type="bool" setter="set_transpose" getter="get_transpose" default="false"> + If [code]true[/code], the tile will display transposed, i.e. with horizontal and vertical texture UVs swapped. </member> <member name="y_sort_origin" type="int" setter="set_y_sort_origin" getter="get_y_sort_origin" default="0"> + Vertical point of the tile used for determining y-sorted order. </member> <member name="z_index" type="int" setter="set_z_index" getter="get_z_index" default="0"> + Ordering index of this tile, relative to [TileMap]. </member> </members> <signals> <signal name="changed"> <description> + Emitted when any of the properties are changed. </description> </signal> </signals> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index bf79821e2d..6a016c3ebd 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -84,6 +84,7 @@ <return type="int" /> <param index="0" name="column" type="int" /> <description> + Returns the expand ratio assigned to the column. </description> </method> <method name="get_column_title" qualifiers="const"> @@ -223,12 +224,14 @@ <return type="bool" /> <param index="0" name="column" type="int" /> <description> + Returns [code]true[/code] if the column has enabled clipping (see [method set_column_clip_content]). </description> </method> <method name="is_column_expanding" qualifiers="const"> <return type="bool" /> <param index="0" name="column" type="int" /> <description> + Returns [code]true[/code] if the column has enabled expanding (see [method set_column_expand]). </description> </method> <method name="scroll_to_item"> @@ -244,6 +247,7 @@ <param index="0" name="column" type="int" /> <param index="1" name="enable" type="bool" /> <description> + Allows to enable clipping for column's content, making the content size ignored. </description> </method> <method name="set_column_custom_minimum_width"> @@ -259,7 +263,7 @@ <param index="0" name="column" type="int" /> <param index="1" name="expand" type="bool" /> <description> - If [code]true[/code], the column will have the "Expand" flag of [Control]. Columns that have the "Expand" flag will use their "min_width" in a similar fashion to [member Control.size_flags_stretch_ratio]. + If [code]true[/code], the column will have the "Expand" flag of [Control]. Columns that have the "Expand" flag will use their expand ratio in a similar fashion to [member Control.size_flags_stretch_ratio] (see [method set_column_expand_ratio]). </description> </method> <method name="set_column_expand_ratio"> @@ -267,6 +271,7 @@ <param index="0" name="column" type="int" /> <param index="1" name="ratio" type="int" /> <description> + Sets the relative expand ratio for a column. See [method set_column_expand]. </description> </method> <method name="set_column_title"> diff --git a/doc/classes/VSlider.xml b/doc/classes/VSlider.xml index 488154106f..4bc98dea6f 100644 --- a/doc/classes/VSlider.xml +++ b/doc/classes/VSlider.xml @@ -33,7 +33,7 @@ The background of the area below the grabber. </theme_item> <theme_item name="grabber_area_highlight" data_type="style" type="StyleBox"> - The background of the area below the grabber, to the left of the grabber. + The background of the area below the grabber that displays when it's being hovered or focused. </theme_item> <theme_item name="slider" data_type="style" type="StyleBox"> The background for the whole slider. Determines the width of the [code]grabber_area[/code]. diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index 5590f82336..fac672c764 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -5,7 +5,8 @@ </brief_description> <description> 2-element structure that can be used to represent positions in 2D space or any other pair of numeric values. - It uses floating-point coordinates. See [Vector2i] for its integer counterpart. + It uses floating-point coordinates. By default, these floating-point values use 32-bit precision, unlike [float] which is always 64-bit. If double precision is needed, compile the engine with the option [code]float=64[/code]. + See [Vector2i] for its integer counterpart. [b]Note:[/b] In a boolean context, a Vector2 will evaluate to [code]false[/code] if it's equal to [code]Vector2(0, 0)[/code]. Otherwise, a Vector2 will always evaluate to [code]true[/code]. </description> <tutorials> @@ -85,6 +86,16 @@ Returns the aspect ratio of this vector, the ratio of [member x] to [member y]. </description> </method> + <method name="bezier_derivative" qualifiers="const"> + <return type="Vector2" /> + <param index="0" name="control_1" type="Vector2" /> + <param index="1" name="control_2" type="Vector2" /> + <param index="2" name="end" type="Vector2" /> + <param index="3" name="t" type="float" /> + <description> + Returns the derivative at the given [param t] on the [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by this vector and the given [param control_1], [param control_2], and [param end] points. + </description> + </method> <method name="bezier_interpolate" qualifiers="const"> <return type="Vector2" /> <param index="0" name="control_1" type="Vector2" /> diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml index eab880e57f..fd02e3c530 100644 --- a/doc/classes/Vector2i.xml +++ b/doc/classes/Vector2i.xml @@ -5,7 +5,7 @@ </brief_description> <description> 2-element structure that can be used to represent positions in 2D space or any other pair of numeric values. - It uses integer coordinates and is therefore preferable to [Vector2] when exact precision is required. + It uses integer coordinates and is therefore preferable to [Vector2] when exact precision is required. Note that the values are limited to 32 bits, and unlike [Vector2] this cannot be configured with an engine build option. Use [int] or [PackedInt64Array] if 64-bit values are needed. [b]Note:[/b] In a boolean context, a Vector2i will evaluate to [code]false[/code] if it's equal to [code]Vector2i(0, 0)[/code]. Otherwise, a Vector2i will always evaluate to [code]true[/code]. </description> <tutorials> diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index 1a2cdfe10e..f075915a9c 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -5,7 +5,8 @@ </brief_description> <description> 3-element structure that can be used to represent positions in 3D space or any other triplet of numeric values. - It uses floating-point coordinates. See [Vector3i] for its integer counterpart. + It uses floating-point coordinates. By default, these floating-point values use 32-bit precision, unlike [float] which is always 64-bit. If double precision is needed, compile the engine with the option [code]float=64[/code]. + See [Vector3i] for its integer counterpart. [b]Note:[/b] In a boolean context, a Vector3 will evaluate to [code]false[/code] if it's equal to [code]Vector3(0, 0, 0)[/code]. Otherwise, a Vector3 will always evaluate to [code]true[/code]. </description> <tutorials> @@ -61,6 +62,16 @@ Returns the unsigned minimum angle to the given vector, in radians. </description> </method> + <method name="bezier_derivative" qualifiers="const"> + <return type="Vector3" /> + <param index="0" name="control_1" type="Vector3" /> + <param index="1" name="control_2" type="Vector3" /> + <param index="2" name="end" type="Vector3" /> + <param index="3" name="t" type="float" /> + <description> + Returns the derivative at the given [param t] on the [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by this vector and the given [param control_1], [param control_2], and [param end] points. + </description> + </method> <method name="bezier_interpolate" qualifiers="const"> <return type="Vector3" /> <param index="0" name="control_1" type="Vector3" /> diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml index 1c2a033f7a..eb64e098ce 100644 --- a/doc/classes/Vector3i.xml +++ b/doc/classes/Vector3i.xml @@ -5,7 +5,7 @@ </brief_description> <description> 3-element structure that can be used to represent positions in 3D space or any other triplet of numeric values. - It uses integer coordinates and is therefore preferable to [Vector3] when exact precision is required. + It uses integer coordinates and is therefore preferable to [Vector3] when exact precision is required. Note that the values are limited to 32 bits, and unlike [Vector3] this cannot be configured with an engine build option. Use [int] or [PackedInt64Array] if 64-bit values are needed. [b]Note:[/b] In a boolean context, a Vector3i will evaluate to [code]false[/code] if it's equal to [code]Vector3i(0, 0, 0)[/code]. Otherwise, a Vector3i will always evaluate to [code]true[/code]. </description> <tutorials> diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml index 662d0bce3a..a2759937c1 100644 --- a/doc/classes/Vector4.xml +++ b/doc/classes/Vector4.xml @@ -5,7 +5,8 @@ </brief_description> <description> 4-element structure that can be used to represent any quadruplet of numeric values. - It uses floating-point coordinates. See [Vector4i] for its integer counterpart. + It uses floating-point coordinates. By default, these floating-point values use 32-bit precision, unlike [float] which is always 64-bit. If double precision is needed, compile the engine with the option [code]float=64[/code]. + See [Vector4i] for its integer counterpart. [b]Note:[/b] In a boolean context, a Vector4 will evaluate to [code]false[/code] if it's equal to [code]Vector4(0, 0, 0, 0)[/code]. Otherwise, a Vector4 will always evaluate to [code]true[/code]. </description> <tutorials> diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml index e9ac5b9475..2dc10234ee 100644 --- a/doc/classes/Vector4i.xml +++ b/doc/classes/Vector4i.xml @@ -5,7 +5,7 @@ </brief_description> <description> 4-element structure that can be used to represent 4D grid coordinates or sets of integers. - It uses integer coordinates. See [Vector4] for its floating-point counterpart. + It uses integer coordinates and is therefore preferable to [Vector4] when exact precision is required. Note that the values are limited to 32 bits, and unlike [Vector4] this cannot be configured with an engine build option. Use [int] or [PackedInt64Array] if 64-bit values are needed. </description> <tutorials> </tutorials> diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index 492a438d9b..e5a0bbb008 100755 --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -29,6 +29,12 @@ MARKUP_ALLOWED_SUBSEQUENT = " -.,:;!?\\/'\")]}>" # write in this script (check `translate()` uses), and also hardcoded in # `doc/translations/extract.py` to include them in the source POT file. BASE_STRINGS = [ + "All classes", + "Globals", + "Nodes", + "Resources", + "Other objects", + "Variant types", "Description", "Tutorials", "Properties", @@ -63,6 +69,19 @@ strings_l10n: Dict[str, str] = {} STYLES: Dict[str, str] = {} +CLASS_GROUPS: Dict[str, str] = { + "global": "Globals", + "node": "Nodes", + "resource": "Resources", + "object": "Other objects", + "variant": "Variant types", +} +CLASS_GROUPS_BASE: Dict[str, str] = { + "node": "Node", + "resource": "Resource", + "object": "Object", +} + class State: def __init__(self) -> None: @@ -329,7 +348,7 @@ class State: return cast def sort_classes(self) -> None: - self.classes = OrderedDict(sorted(self.classes.items(), key=lambda t: t[0])) + self.classes = OrderedDict(sorted(self.classes.items(), key=lambda t: t[0].lower())) class TypeName: @@ -601,12 +620,25 @@ def main() -> None: print("Generating the RST class reference...") + grouped_classes: Dict[str, List[str]] = {} + for class_name, class_def in state.classes.items(): if args.filter and not pattern.search(class_def.filepath): continue state.current_class = class_name make_rst_class(class_def, state, args.dry_run, args.output) + group_name = get_class_group(class_def, state) + + if group_name not in grouped_classes: + grouped_classes[group_name] = [] + grouped_classes[group_name].append(class_name) + + print("") + print("Generating the index file...") + + make_rst_index(grouped_classes, args.dry_run, args.output) + print("") if state.num_warnings >= 2: @@ -655,6 +687,42 @@ def translate(string: str) -> str: return strings_l10n.get(string, string) +def get_git_branch() -> str: + if hasattr(version, "docs") and version.docs != "latest": + return version.docs + + return "master" + + +def get_class_group(class_def: ClassDef, state: State) -> str: + group_name = "variant" + class_name = class_def.name + + if class_name.startswith("@"): + group_name = "global" + elif class_def.inherits: + inherits = class_def.inherits.strip() + + while inherits in state.classes: + if inherits == "Node": + group_name = "node" + break + if inherits == "Resource": + group_name = "resource" + break + if inherits == "Object": + group_name = "object" + break + + inode = state.classes[inherits].inherits + if inode: + inherits = inode.strip() + else: + break + + return group_name + + # Generator methods. @@ -672,10 +740,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: # Warn contributors not to edit this file directly. # Also provide links to the source files for reference. - git_branch = "master" - if hasattr(version, "docs") and version.docs != "latest": - git_branch = version.docs - + git_branch = get_git_branch() source_xml_path = os.path.relpath(class_def.filepath, root_directory).replace("\\", "/") source_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/{source_xml_path}" generator_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/doc/tools/make_rst.py" @@ -723,15 +788,30 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: f.write(make_type(child, state)) f.write("\n\n") + has_description = False + # Brief description - if class_def.brief_description is not None: + if class_def.brief_description is not None and class_def.brief_description.strip() != "": + has_description = True + f.write(f"{format_text_block(class_def.brief_description.strip(), class_def, state)}\n\n") # Class description if class_def.description is not None and class_def.description.strip() != "": + has_description = True + f.write(make_heading("Description", "-")) f.write(f"{format_text_block(class_def.description.strip(), class_def, state)}\n\n") + if not has_description: + f.write(".. container:: contribute\n\n\t") + f.write( + translate( + "There is currently no description for this class. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!" + ) + + "\n\n" + ) + # Online tutorials if len(class_def.tutorials) > 0: f.write(make_heading("Tutorials", "-")) @@ -872,6 +952,14 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: if m.description is not None and m.description.strip() != "": f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n") + else: + f.write(".. container:: contribute\n\n\t") + f.write( + translate( + "There is currently no description for this annotation. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!" + ) + + "\n\n" + ) index += 1 @@ -904,6 +992,14 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: if property_def.text is not None and property_def.text.strip() != "": f.write(f"{format_text_block(property_def.text.strip(), property_def, state)}\n\n") + else: + f.write(".. container:: contribute\n\n\t") + f.write( + translate( + "There is currently no description for this property. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!" + ) + + "\n\n" + ) index += 1 @@ -925,6 +1021,14 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: if m.description is not None and m.description.strip() != "": f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n") + else: + f.write(".. container:: contribute\n\n\t") + f.write( + translate( + "There is currently no description for this constructor. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!" + ) + + "\n\n" + ) index += 1 @@ -945,6 +1049,14 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: if m.description is not None and m.description.strip() != "": f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n") + else: + f.write(".. container:: contribute\n\n\t") + f.write( + translate( + "There is currently no description for this method. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!" + ) + + "\n\n" + ) index += 1 @@ -956,17 +1068,24 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: for i, m in enumerate(method_list): if index != 0: f.write("----\n\n") - - if i == 0: - f.write( - f".. _class_{class_name}_operator_{sanitize_operator_name(m.name, state)}_{m.return_type.type_name}:\n\n" - ) - + out = f".. _class_{class_name}_operator_{sanitize_operator_name(m.name, state)}" + for parameter in m.parameters: + out += f"_{parameter.type_name.type_name}" + out += f":\n\n" + f.write(out) ret_type, signature = make_method_signature(class_def, m, "", state) f.write(f"- {ret_type} {signature}\n\n") if m.description is not None and m.description.strip() != "": f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n") + else: + f.write(".. container:: contribute\n\n\t") + f.write( + translate( + "There is currently no description for this operator. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!" + ) + + "\n\n" + ) index += 1 @@ -992,6 +1111,14 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: if theme_item_def.text is not None and theme_item_def.text.strip() != "": f.write(f"{format_text_block(theme_item_def.text.strip(), theme_item_def, state)}\n\n") + else: + f.write(".. container:: contribute\n\n\t") + f.write( + translate( + "There is currently no description for this theme property. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!" + ) + + "\n\n" + ) index += 1 @@ -1051,7 +1178,10 @@ def make_method_signature( if isinstance(definition, MethodDef) and ref_type != "": if ref_type == "operator": op_name = definition.name.replace("<", "\\<") # So operator "<" gets correctly displayed. - out += f":ref:`{op_name}<class_{class_def.name}_{ref_type}_{sanitize_operator_name(definition.name, state)}_{definition.return_type.type_name}>` " + out += f":ref:`{op_name}<class_{class_def.name}_{ref_type}_{sanitize_operator_name(definition.name, state)}" + for parameter in definition.parameters: + out += f"_{parameter.type_name.type_name}" + out += f">` " else: out += f":ref:`{definition.name}<class_{class_def.name}_{ref_type}_{definition.name}>` " else: @@ -1142,6 +1272,53 @@ def make_link(url: str, title: str) -> str: return f"`{url} <{url}>`__" +def make_rst_index(grouped_classes: Dict[str, List[str]], dry_run: bool, output_dir: str) -> None: + + if dry_run: + f = open(os.devnull, "w", encoding="utf-8") + else: + f = open(os.path.join(output_dir, "index.rst"), "w", encoding="utf-8") + + # Remove the "Edit on Github" button from the online docs page. + f.write(":github_url: hide\n\n") + + # Warn contributors not to edit this file directly. + # Also provide links to the source files for reference. + + git_branch = get_git_branch() + generator_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/doc/tools/make_rst.py" + + f.write(".. DO NOT EDIT THIS FILE!!!\n") + f.write(".. Generated automatically from Godot engine sources.\n") + f.write(f".. Generator: {generator_github_url}.\n\n") + + f.write(".. _doc_class_reference:\n\n") + + main_title = translate("All classes") + f.write(f"{main_title}\n") + f.write(f"{'=' * len(main_title)}\n\n") + + for group_name in CLASS_GROUPS: + if group_name in grouped_classes: + group_title = translate(CLASS_GROUPS[group_name]) + + f.write(f"{group_title}\n") + f.write(f"{'=' * len(group_title)}\n\n") + + f.write(".. toctree::\n") + f.write(" :maxdepth: 1\n") + f.write(f" :name: toc-class-ref-{group_name}s\n") + f.write("\n") + + if group_name in CLASS_GROUPS_BASE: + f.write(f" class_{CLASS_GROUPS_BASE[group_name].lower()}\n") + + for class_name in grouped_classes[group_name]: + f.write(f" class_{class_name.lower()}\n") + + f.write("\n") + + # Formatting helpers. diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index ca806304c5..cdae05a516 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -153,48 +153,6 @@ void main() { uv += 1e-5; } -#ifdef USE_ATTRIBUTES -#if 0 - if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_SKELETON) && bone_weights != vec4(0.0)) { //must be a valid bone - //skeleton transform - ivec4 bone_indicesi = ivec4(bone_indices); - - uvec2 tex_ofs = bone_indicesi.x * 2; - - mat2x4 m; - m = mat2x4( - texelFetch(skeleton_buffer, tex_ofs + 0), - texelFetch(skeleton_buffer, tex_ofs + 1)) * - bone_weights.x; - - tex_ofs = bone_indicesi.y * 2; - - m += mat2x4( - texelFetch(skeleton_buffer, tex_ofs + 0), - texelFetch(skeleton_buffer, tex_ofs + 1)) * - bone_weights.y; - - tex_ofs = bone_indicesi.z * 2; - - m += mat2x4( - texelFetch(skeleton_buffer, tex_ofs + 0), - texelFetch(skeleton_buffer, tex_ofs + 1)) * - bone_weights.z; - - tex_ofs = bone_indicesi.w * 2; - - m += mat2x4( - texelFetch(skeleton_buffer, tex_ofs + 0), - texelFetch(skeleton_buffer, tex_ofs + 1)) * - bone_weights.w; - - mat4 bone_matrix = skeleton_data.skeleton_transform * transpose(mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))) * skeleton_data.skeleton_transform_inverse; - - //outvec = bone_matrix * outvec; - } -#endif -#endif - vertex = (canvas_transform * vec4(vertex, 0.0, 1.0)).xy; vertex_interp = vertex; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index f14ed24965..04dba602dd 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -102,7 +102,7 @@ vec3 oct_to_vec3(vec2 e) { vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); float t = max(-v.z, 0.0); v.xy += t * -sign(v.xy); - return v; + return normalize(v); } #ifdef USE_INSTANCING @@ -920,6 +920,7 @@ void main() { #else vec3 view = -normalize(vertex_interp); #endif + highp mat4 model_matrix = world_transform; vec3 albedo = vec3(1.0); vec3 backlight = vec3(0.0); vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0); diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 767ac2bf1a..15743c2d78 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -251,6 +251,8 @@ void TextureStorage::canvas_texture_free(RID p_rid) { void TextureStorage::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture); + ERR_FAIL_NULL(ct); + switch (p_channel) { case RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE: { ct->diffuse = p_texture; @@ -266,6 +268,8 @@ void TextureStorage::canvas_texture_set_channel(RID p_canvas_texture, RS::Canvas void TextureStorage::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) { CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture); + ERR_FAIL_NULL(ct); + ct->specular_color.r = p_specular_color.r; ct->specular_color.g = p_specular_color.g; ct->specular_color.b = p_specular_color.b; @@ -274,11 +278,15 @@ void TextureStorage::canvas_texture_set_shading_parameters(RID p_canvas_texture, void TextureStorage::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture); + ERR_FAIL_NULL(ct); + ct->texture_filter = p_filter; } void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture); + ERR_FAIL_NULL(ct); + ct->texture_repeat = p_repeat; } diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index c7c5fadbeb..01d1583ca4 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -47,7 +47,7 @@ static const uint32_t SMALL_ALLOCATION_MAX_SIZE = 4096; // Get the Vulkan object information and possible stage access types (bitwise OR'd with incoming values). -RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &r_stage_mask, VkAccessFlags &r_access_mask, uint32_t p_post_barrier) { +RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &r_stage_mask, VkAccessFlags &r_access_mask, BitField<BarrierMask> p_post_barrier) { Buffer *buffer = nullptr; if (vertex_buffer_owner.owns(p_buffer)) { buffer = vertex_buffer_owner.get_or_null(p_buffer); @@ -55,11 +55,11 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; r_access_mask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; if (buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) { - if (p_post_barrier & BARRIER_MASK_RASTER) { + if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) { r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; } - if (p_post_barrier & BARRIER_MASK_COMPUTE) { + if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; } @@ -69,20 +69,20 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID r_access_mask |= VK_ACCESS_INDEX_READ_BIT; buffer = index_buffer_owner.get_or_null(p_buffer); } else if (uniform_buffer_owner.owns(p_buffer)) { - if (p_post_barrier & BARRIER_MASK_RASTER) { + if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) { r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; } - if (p_post_barrier & BARRIER_MASK_COMPUTE) { + if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; } r_access_mask |= VK_ACCESS_UNIFORM_READ_BIT; buffer = uniform_buffer_owner.get_or_null(p_buffer); } else if (texture_buffer_owner.owns(p_buffer)) { - if (p_post_barrier & BARRIER_MASK_RASTER) { + if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) { r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; r_access_mask |= VK_ACCESS_SHADER_READ_BIT; } - if (p_post_barrier & BARRIER_MASK_COMPUTE) { + if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; r_access_mask |= VK_ACCESS_SHADER_READ_BIT; } @@ -90,11 +90,11 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID buffer = &texture_buffer_owner.get_or_null(p_buffer)->buffer; } else if (storage_buffer_owner.owns(p_buffer)) { buffer = storage_buffer_owner.get_or_null(p_buffer); - if (p_post_barrier & BARRIER_MASK_RASTER) { + if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) { r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (p_post_barrier & BARRIER_MASK_COMPUTE) { + if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } @@ -2009,7 +2009,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T if (p_data.size()) { for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { - _texture_update(id, i, p_data[i], RD::BARRIER_MASK_ALL, true); + _texture_update(id, i, p_data[i], RD::BARRIER_MASK_ALL_BARRIERS, true); } } return id; @@ -2414,7 +2414,7 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p return id; } -Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier) { +Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) { return _texture_update(p_texture, p_layer, p_data, p_post_barrier, false); } @@ -2434,7 +2434,7 @@ static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_ } } -Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier, bool p_use_setup_queue) { +Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, bool p_use_setup_queue) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG((draw_list || compute_list) && !p_use_setup_queue, ERR_INVALID_PARAMETER, @@ -2608,15 +2608,15 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co { uint32_t barrier_flags = 0; uint32_t access_flags = 0; - if (p_post_barrier & BARRIER_MASK_COMPUTE) { + if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (p_post_barrier & BARRIER_MASK_RASTER) { + if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) { barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (p_post_barrier & BARRIER_MASK_TRANSFER) { + if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; } @@ -2869,7 +2869,7 @@ Size2i RenderingDeviceVulkan::texture_size(RID p_texture) { return Size2i(tex->width, tex->height); } -Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, uint32_t p_post_barrier) { +Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier) { _THREAD_SAFE_METHOD_ Texture *src_tex = texture_owner.get_or_null(p_from_texture); @@ -2994,15 +2994,15 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, uint32_t barrier_flags = 0; uint32_t access_flags = 0; - if (p_post_barrier & BARRIER_MASK_COMPUTE) { + if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (p_post_barrier & BARRIER_MASK_RASTER) { + if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) { barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (p_post_barrier & BARRIER_MASK_TRANSFER) { + if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; } @@ -3064,7 +3064,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, return OK; } -Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, uint32_t p_post_barrier) { +Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier) { _THREAD_SAFE_METHOD_ Texture *src_tex = texture_owner.get_or_null(p_from_texture); @@ -3172,15 +3172,15 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID uint32_t barrier_flags = 0; uint32_t access_flags = 0; - if (p_post_barrier & BARRIER_MASK_COMPUTE) { + if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (p_post_barrier & BARRIER_MASK_RASTER) { + if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) { barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (p_post_barrier & BARRIER_MASK_TRANSFER) { + if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; } @@ -3235,7 +3235,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID return OK; } -Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, uint32_t p_post_barrier) { +Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier) { _THREAD_SAFE_METHOD_ Texture *src_tex = texture_owner.get_or_null(p_texture); @@ -3308,15 +3308,15 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t barrier_flags = 0; uint32_t access_flags = 0; - if (p_post_barrier & BARRIER_MASK_COMPUTE) { + if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (p_post_barrier & BARRIER_MASK_RASTER) { + if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) { barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (p_post_barrier & BARRIER_MASK_TRANSFER) { + if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; } @@ -3826,7 +3826,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF vrs_reference.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; vrs_reference.aspectMask = VK_IMAGE_ASPECT_NONE; - Size2i texel_size = context->get_vrs_capabilities().max_texel_size; + Size2i texel_size = context->get_vrs_capabilities().texel_size; VkFragmentShadingRateAttachmentInfoKHR &vrs_attachment_info = vrs_attachment_info_array[i]; vrs_attachment_info.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; @@ -4378,7 +4378,7 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons return id; } -RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers) { +RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers, const Vector<uint64_t> &p_offsets) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); @@ -4392,6 +4392,13 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo VertexArray vertex_array; + if (p_offsets.is_empty()) { + vertex_array.offsets.resize_zeroed(p_src_buffers.size()); + } else { + ERR_FAIL_COND_V(p_offsets.size() != p_src_buffers.size(), RID()); + vertex_array.offsets = p_offsets; + } + vertex_array.vertex_count = p_vertex_count; vertex_array.description = p_vertex_format; vertex_array.max_instances_allowed = 0xFFFFFFFF; // By default as many as you want. @@ -4423,7 +4430,6 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo } vertex_array.buffers.push_back(buffer->buffer); - vertex_array.offsets.push_back(0); // Offset unused, but passing anyway. } RID id = vertex_array_owner.make_rid(vertex_array); @@ -6315,7 +6321,7 @@ void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_ us->invalidated_callback_userdata = p_userdata; } -Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier) { +Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER, @@ -6325,7 +6331,7 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint VkPipelineStageFlags dst_stage_mask = 0; VkAccessFlags dst_access = 0; - if (p_post_barrier & BARRIER_MASK_TRANSFER) { + if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { // Protect subsequent updates. dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT; dst_access = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -6361,7 +6367,7 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint return err; } -Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier) { +Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG((p_size % 4) != 0, ERR_INVALID_PARAMETER, @@ -6373,7 +6379,7 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3 VkPipelineStageFlags dst_stage_mask = 0; VkAccessFlags dst_access = 0; - if (p_post_barrier & BARRIER_MASK_TRANSFER) { + if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { // Protect subsequent updates. dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT; dst_access = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -6412,7 +6418,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { VkPipelineShaderStageCreateFlags src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT; VkAccessFlags src_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT; // Get the vulkan buffer and the potential stage/access possible. - Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_ALL); + Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_ALL_BARRIERS); if (!buffer) { ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving."); } @@ -8084,7 +8090,7 @@ void RenderingDeviceVulkan::_draw_list_free(Rect2i *r_last_viewport) { _THREAD_SAFE_UNLOCK_ } -void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) { +void RenderingDeviceVulkan::draw_list_end(BitField<BarrierMask> p_post_barrier) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_MSG(!draw_list, "Immediate draw list is already inactive."); @@ -8106,15 +8112,15 @@ void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) { uint32_t barrier_flags = 0; uint32_t access_flags = 0; - if (p_post_barrier & BARRIER_MASK_COMPUTE) { + if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (p_post_barrier & BARRIER_MASK_RASTER) { + if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) { barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT /*| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT*/; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT /*| VK_ACCESS_INDIRECT_COMMAND_READ_BIT*/; } - if (p_post_barrier & BARRIER_MASK_TRANSFER) { + if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; } @@ -8592,20 +8598,20 @@ void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) { #endif } -void RenderingDeviceVulkan::compute_list_end(uint32_t p_post_barrier) { +void RenderingDeviceVulkan::compute_list_end(BitField<BarrierMask> p_post_barrier) { ERR_FAIL_COND(!compute_list); uint32_t barrier_flags = 0; uint32_t access_flags = 0; - if (p_post_barrier & BARRIER_MASK_COMPUTE) { + if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) { barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } - if (p_post_barrier & BARRIER_MASK_RASTER) { + if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) { barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT; } - if (p_post_barrier & BARRIER_MASK_TRANSFER) { + if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) { barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; } @@ -8673,43 +8679,45 @@ void RenderingDeviceVulkan::compute_list_end(uint32_t p_post_barrier) { _THREAD_SAFE_UNLOCK_ } -void RenderingDeviceVulkan::barrier(uint32_t p_from, uint32_t p_to) { +void RenderingDeviceVulkan::barrier(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) { uint32_t src_barrier_flags = 0; uint32_t src_access_flags = 0; - if (p_from & BARRIER_MASK_COMPUTE) { - src_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - src_access_flags |= VK_ACCESS_SHADER_WRITE_BIT; - } - if (p_from & BARRIER_MASK_RASTER) { - src_barrier_flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - src_access_flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - } - if (p_from & BARRIER_MASK_TRANSFER) { - src_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; - src_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; - } if (p_from == 0) { src_barrier_flags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + } else { + if (p_from.has_flag(BARRIER_MASK_COMPUTE)) { + src_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + src_access_flags |= VK_ACCESS_SHADER_WRITE_BIT; + } + if (p_from.has_flag(BARRIER_MASK_RASTER)) { + src_barrier_flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + src_access_flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + } + if (p_from.has_flag(BARRIER_MASK_TRANSFER)) { + src_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; + src_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT; + } } uint32_t dst_barrier_flags = 0; uint32_t dst_access_flags = 0; - if (p_to & BARRIER_MASK_COMPUTE) { - dst_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - } - if (p_to & BARRIER_MASK_RASTER) { - dst_barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; - dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT; - } - if (p_to & BARRIER_MASK_TRANSFER) { - dst_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; - dst_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; - } if (p_to == 0) { dst_barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + } else { + if (p_to.has_flag(BARRIER_MASK_COMPUTE)) { + dst_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + } + if (p_to.has_flag(BARRIER_MASK_RASTER)) { + dst_barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; + dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + } + if (p_to.has_flag(BARRIER_MASK_TRANSFER)) { + dst_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; + dst_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; + } } _memory_barrier(src_barrier_flags, dst_barrier_flags, src_access_flags, dst_access_flags, true); @@ -9724,6 +9732,12 @@ uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) const { VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities(); return subgroup_capabilities.supported_operations_flags_rd(); } + case LIMIT_VRS_TEXEL_WIDTH: { + return context->get_vrs_capabilities().texel_size.x; + } + case LIMIT_VRS_TEXEL_HEIGHT: { + return context->get_vrs_capabilities().texel_size.y; + } default: ERR_FAIL_V(0); } diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index 7c75e9bb2e..537ad88f5a 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -162,7 +162,7 @@ class RenderingDeviceVulkan : public RenderingDevice { uint32_t texture_upload_region_size_px = 0; Vector<uint8_t> _texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d = false); - Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier, bool p_use_setup_queue); + Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, bool p_use_setup_queue); /*****************/ /**** SAMPLER ****/ @@ -909,7 +909,7 @@ class RenderingDeviceVulkan : public RenderingDevice { Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass, uint32_t *r_subpass_count); Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures); _FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id); - Buffer *_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &dst_stage_mask, VkAccessFlags &dst_access, uint32_t p_post_barrier); + Buffer *_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &dst_stage_mask, VkAccessFlags &dst_access, BitField<BarrierMask> p_post_barrier); Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass); void _draw_list_free(Rect2i *r_last_viewport = nullptr); @@ -1052,7 +1052,7 @@ public: virtual RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, uint64_t p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers); virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D); - virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); + virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer); virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const; @@ -1060,9 +1060,9 @@ public: virtual bool texture_is_valid(RID p_texture); virtual Size2i texture_size(RID p_texture); - virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, uint32_t p_post_barrier = BARRIER_MASK_ALL); - virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, uint32_t p_post_barrier = BARRIER_MASK_ALL); - virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, uint32_t p_post_barrier = BARRIER_MASK_ALL); + virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); + virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); /*********************/ /**** FRAMEBUFFER ****/ @@ -1095,7 +1095,7 @@ public: // Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated. virtual VertexFormatID vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats); - virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers); + virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers, const Vector<uint64_t> &p_offsets = Vector<uint64_t>()); virtual RID index_buffer_create(uint32_t p_size_indices, IndexBufferFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_restart_indices = false); @@ -1124,8 +1124,8 @@ public: virtual bool uniform_set_is_valid(RID p_uniform_set); virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata); - virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); // Works for any buffer. - virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL); + virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); // Works for any buffer. + virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); virtual Vector<uint8_t> buffer_get_data(RID p_buffer); /*************************/ @@ -1176,7 +1176,7 @@ public: virtual DrawListID draw_list_switch_to_next_pass(); virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids); - virtual void draw_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL); + virtual void draw_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); /***********************/ /**** COMPUTE LISTS ****/ @@ -1191,9 +1191,9 @@ public: virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups); virtual void compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads); virtual void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset); - virtual void compute_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL); + virtual void compute_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); - virtual void barrier(uint32_t p_from = BARRIER_MASK_ALL, uint32_t p_to = BARRIER_MASK_ALL); + virtual void barrier(BitField<BarrierMask> p_from = BARRIER_MASK_ALL_BARRIERS, BitField<BarrierMask> p_to = BARRIER_MASK_ALL_BARRIERS); virtual void full_barrier(); /**************/ diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index 464ab474e1..028c7dca6f 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -68,7 +68,7 @@ Vector<VkAttachmentReference> VulkanContext::_convert_VkAttachmentReference2(uin } VkResult VulkanContext::vkCreateRenderPass2KHR(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass) { - if (has_renderpass2_ext) { + if (is_device_extension_enabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) { if (fpCreateRenderPass2KHR == nullptr) { fpCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(p_device, "vkCreateRenderPass2KHR"); } @@ -400,16 +400,28 @@ Error VulkanContext::_obtain_vulkan_version() { return OK; } -Error VulkanContext::_initialize_extensions() { - uint32_t instance_extension_count = 0; +bool VulkanContext::instance_extensions_initialized = false; +HashMap<CharString, bool> VulkanContext::requested_instance_extensions; + +void VulkanContext::register_requested_instance_extension(const CharString &extension_name, bool p_required) { + ERR_FAIL_COND_MSG(instance_extensions_initialized, "You can only registered extensions before the Vulkan instance is created"); + ERR_FAIL_COND(requested_instance_extensions.has(extension_name)); + + requested_instance_extensions[extension_name] = p_required; +} + +Error VulkanContext::_initialize_instance_extensions() { + enabled_instance_extension_names.clear(); - enabled_extension_count = 0; - enabled_debug_utils = false; - enabled_debug_report = false; - // Look for instance extensions. - VkBool32 surfaceExtFound = 0; - VkBool32 platformSurfaceExtFound = 0; - memset(extension_names, 0, sizeof(extension_names)); + // Make sure our core extensions are here + register_requested_instance_extension(VK_KHR_SURFACE_EXTENSION_NAME, true); + register_requested_instance_extension(_get_platform_surface_extension(), true); + + if (_use_validation_layers()) { + register_requested_instance_extension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, false); + } + + register_requested_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false); // Only enable debug utils in verbose mode or DEV_ENABLED. // End users would get spammed with messages of varying verbosity due to the @@ -420,54 +432,141 @@ Error VulkanContext::_initialize_extensions() { #else bool want_debug_utils = OS::get_singleton()->is_stdout_verbose(); #endif + if (want_debug_utils) { + register_requested_instance_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, false); + } + // Load instance extensions that are available... + uint32_t instance_extension_count = 0; VkResult err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr); ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_INCOMPLETE, ERR_CANT_CREATE); + ERR_FAIL_COND_V_MSG(instance_extension_count == 0, ERR_CANT_CREATE, "No instance extensions found, is a driver installed?"); - if (instance_extension_count > 0) { - VkExtensionProperties *instance_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * instance_extension_count); - err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions); - if (err != VK_SUCCESS && err != VK_INCOMPLETE) { - free(instance_extensions); - ERR_FAIL_V(ERR_CANT_CREATE); + VkExtensionProperties *instance_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * instance_extension_count); + err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions); + if (err != VK_SUCCESS && err != VK_INCOMPLETE) { + free(instance_extensions); + ERR_FAIL_V(ERR_CANT_CREATE); + } +#ifdef DEV_ENABLED + for (uint32_t i = 0; i < instance_extension_count; i++) { + print_verbose(String("VULKAN: Found instance extension ") + String(instance_extensions[i].extensionName)); + } +#endif + + // Enable all extensions that are supported and requested + for (uint32_t i = 0; i < instance_extension_count; i++) { + CharString extension_name(instance_extensions[i].extensionName); + if (requested_instance_extensions.has(extension_name)) { + enabled_instance_extension_names.insert(extension_name); } - for (uint32_t i = 0; i < instance_extension_count; i++) { - if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { - surfaceExtFound = 1; - extension_names[enabled_extension_count++] = VK_KHR_SURFACE_EXTENSION_NAME; - } + } - if (!strcmp(_get_platform_surface_extension(), instance_extensions[i].extensionName)) { - platformSurfaceExtFound = 1; - extension_names[enabled_extension_count++] = _get_platform_surface_extension(); - } - if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extensionName)) { - if (_use_validation_layers()) { - extension_names[enabled_extension_count++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME; - enabled_debug_report = true; - } - } - if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instance_extensions[i].extensionName)) { - if (want_debug_utils) { - extension_names[enabled_extension_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; - enabled_debug_utils = true; - } - } - if (!strcmp(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, instance_extensions[i].extensionName)) { - extension_names[enabled_extension_count++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; - } - if (enabled_extension_count >= MAX_EXTENSIONS) { + // Now check our requested extensions + for (KeyValue<CharString, bool> &requested_extension : requested_instance_extensions) { + if (!enabled_instance_extension_names.has(requested_extension.key)) { + if (requested_extension.value) { free(instance_extensions); - ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG"); + ERR_FAIL_V_MSG(ERR_BUG, String("Required extension ") + String(requested_extension.key) + String(" not found, is a driver installed?")); + } else { + print_verbose(String("Optional extension ") + String(requested_extension.key) + String(" not found")); } } + } - free(instance_extensions); + free(instance_extensions); + + instance_extensions_initialized = true; + return OK; +} + +bool VulkanContext::device_extensions_initialized = false; +HashMap<CharString, bool> VulkanContext::requested_device_extensions; + +void VulkanContext::register_requested_device_extension(const CharString &extension_name, bool p_required) { + ERR_FAIL_COND_MSG(device_extensions_initialized, "You can only registered extensions before the Vulkan instance is created"); + ERR_FAIL_COND(requested_device_extensions.has(extension_name)); + + requested_device_extensions[extension_name] = p_required; +} + +Error VulkanContext::_initialize_device_extensions() { + // Look for device extensions. + enabled_device_extension_names.clear(); + + // Make sure our core extensions are here + register_requested_device_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true); + + register_requested_device_extension(VK_KHR_MULTIVIEW_EXTENSION_NAME, false); + register_requested_device_extension(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, false); + register_requested_device_extension(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, false); + register_requested_device_extension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false); + register_requested_device_extension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, false); + + // TODO consider the following extensions: + // - VK_KHR_spirv_1_4 + // - VK_KHR_swapchain_mutable_format + // - VK_EXT_full_screen_exclusive + // - VK_EXT_hdr_metadata + // - VK_KHR_depth_stencil_resolve + + // Even though the user "enabled" the extension via the command + // line, we must make sure that it's enumerated for use with the + // device. Therefore, disable it here, and re-enable it again if + // enumerated. + if (VK_KHR_incremental_present_enabled) { + register_requested_device_extension(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, false); + } + if (VK_GOOGLE_display_timing_enabled) { + register_requested_device_extension(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, false); } - ERR_FAIL_COND_V_MSG(!surfaceExtFound, ERR_CANT_CREATE, "No surface extension found, is a driver installed?"); - ERR_FAIL_COND_V_MSG(!platformSurfaceExtFound, ERR_CANT_CREATE, "No platform surface extension found, is a driver installed?"); + // obtain available device extensions + uint32_t device_extension_count = 0; + VkResult err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, nullptr); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + ERR_FAIL_COND_V_MSG(device_extension_count == 0, ERR_CANT_CREATE, + "vkEnumerateDeviceExtensionProperties failed to find any extensions\n\n" + "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" + "vkCreateInstance Failure"); + VkExtensionProperties *device_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * device_extension_count); + err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, device_extensions); + if (err) { + free(device_extensions); + ERR_FAIL_V(ERR_CANT_CREATE); + } + +#ifdef DEV_ENABLED + for (uint32_t i = 0; i < device_extension_count; i++) { + print_verbose(String("VULKAN: Found device extension ") + String(device_extensions[i].extensionName)); + } +#endif + + // Enable all extensions that are supported and requested + for (uint32_t i = 0; i < device_extension_count; i++) { + CharString extension_name(device_extensions[i].extensionName); + if (requested_device_extensions.has(extension_name)) { + enabled_device_extension_names.insert(extension_name); + } + } + + // Now check our requested extensions + for (KeyValue<CharString, bool> &requested_extension : requested_device_extensions) { + if (!enabled_device_extension_names.has(requested_extension.key)) { + if (requested_extension.value) { + free(device_extensions); + ERR_FAIL_V_MSG(ERR_BUG, + String("vkEnumerateDeviceExtensionProperties failed to find the ") + String(requested_extension.key) + String(" extension.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\nvkCreateInstance Failure")); + } else { + print_verbose(String("Optional extension ") + String(requested_extension.key) + String(" not found")); + } + } + } + + free(device_extensions); + + device_extensions_initialized = true; return OK; } @@ -625,6 +724,9 @@ Error VulkanContext::_check_capabilities() { vrs_capabilities.pipeline_vrs_supported = false; vrs_capabilities.primitive_vrs_supported = false; vrs_capabilities.attachment_vrs_supported = false; + vrs_capabilities.min_texel_size = Size2i(); + vrs_capabilities.max_texel_size = Size2i(); + vrs_capabilities.texel_size = Size2i(); multiview_capabilities.is_supported = false; multiview_capabilities.geometry_shader_is_supported = false; multiview_capabilities.tessellation_shader_is_supported = false; @@ -641,180 +743,176 @@ Error VulkanContext::_check_capabilities() { storage_buffer_capabilities.storage_push_constant_16_is_supported = false; storage_buffer_capabilities.storage_input_output_16 = false; - // Check for extended features. - PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2"); - if (vkGetPhysicalDeviceFeatures2_func == nullptr) { - // In Vulkan 1.0 might be accessible under its original extension name. - vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR"); - } - if (vkGetPhysicalDeviceFeatures2_func != nullptr) { - // Check our extended features. - VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = { - /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR, - /*pNext*/ nullptr, - /*pipelineFragmentShadingRate*/ false, - /*primitiveFragmentShadingRate*/ false, - /*attachmentFragmentShadingRate*/ false, - }; + if (is_instance_extension_enabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { + // Check for extended features. + PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2"); + if (vkGetPhysicalDeviceFeatures2_func == nullptr) { + // In Vulkan 1.0 might be accessible under its original extension name. + vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR"); + } + if (vkGetPhysicalDeviceFeatures2_func != nullptr) { + // Check our extended features. + VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR, + /*pNext*/ nullptr, + /*pipelineFragmentShadingRate*/ false, + /*primitiveFragmentShadingRate*/ false, + /*attachmentFragmentShadingRate*/ false, + }; - VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = { - /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR, - /*pNext*/ &vrs_features, - /*shaderFloat16*/ false, - /*shaderInt8*/ false, - }; + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR, + /*pNext*/ &vrs_features, + /*shaderFloat16*/ false, + /*shaderInt8*/ false, + }; - VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = { - /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, - /*pNext*/ &shader_features, - /*storageBuffer16BitAccess*/ false, - /*uniformAndStorageBuffer16BitAccess*/ false, - /*storagePushConstant16*/ false, - /*storageInputOutput16*/ false, - }; + VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, + /*pNext*/ &shader_features, + /*storageBuffer16BitAccess*/ false, + /*uniformAndStorageBuffer16BitAccess*/ false, + /*storagePushConstant16*/ false, + /*storageInputOutput16*/ false, + }; - VkPhysicalDeviceMultiviewFeatures multiview_features = { - /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, - /*pNext*/ &storage_feature, - /*multiview*/ false, - /*multiviewGeometryShader*/ false, - /*multiviewTessellationShader*/ false, - }; + VkPhysicalDeviceMultiviewFeatures multiview_features = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, + /*pNext*/ &storage_feature, + /*multiview*/ false, + /*multiviewGeometryShader*/ false, + /*multiviewTessellationShader*/ false, + }; - VkPhysicalDeviceFeatures2 device_features; - device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - device_features.pNext = &multiview_features; + VkPhysicalDeviceFeatures2 device_features; + device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + device_features.pNext = &multiview_features; - vkGetPhysicalDeviceFeatures2_func(gpu, &device_features); + vkGetPhysicalDeviceFeatures2_func(gpu, &device_features); - // We must check that the relative extension is present before assuming a - // feature as enabled. Actually, according to the spec we shouldn't add the - // structs in pNext at all, but this works fine. - // See also: https://github.com/godotengine/godot/issues/65409 - for (uint32_t i = 0; i < enabled_extension_count; ++i) { - if (!strcmp(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, extension_names[i])) { + // We must check that the relative extension is present before assuming a + // feature as enabled. Actually, according to the spec we shouldn't add the + // structs in pNext at all, but this works fine. + // See also: https://github.com/godotengine/godot/issues/65409 + if (is_device_extension_enabled(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) { vrs_capabilities.pipeline_vrs_supported = vrs_features.pipelineFragmentShadingRate; vrs_capabilities.primitive_vrs_supported = vrs_features.primitiveFragmentShadingRate; vrs_capabilities.attachment_vrs_supported = vrs_features.attachmentFragmentShadingRate; - - continue; } - if (!strcmp(VK_KHR_MULTIVIEW_EXTENSION_NAME, extension_names[i])) { + if (is_device_extension_enabled(VK_KHR_MULTIVIEW_EXTENSION_NAME)) { multiview_capabilities.is_supported = multiview_features.multiview; multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader; multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader; - - continue; } - if (!strcmp(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, extension_names[i])) { + if (is_device_extension_enabled(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) { shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16; shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8; - - continue; } - if (!strcmp(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, extension_names[i])) { + if (is_device_extension_enabled(VK_KHR_16BIT_STORAGE_EXTENSION_NAME)) { storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = storage_feature.storageBuffer16BitAccess; storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = storage_feature.uniformAndStorageBuffer16BitAccess; storage_buffer_capabilities.storage_push_constant_16_is_supported = storage_feature.storagePushConstant16; storage_buffer_capabilities.storage_input_output_16 = storage_feature.storageInputOutput16; - - continue; } } - } - - // Check extended properties. - PFN_vkGetPhysicalDeviceProperties2 device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2"); - if (device_properties_func == nullptr) { - // In Vulkan 1.0 might be accessible under its original extension name. - device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2KHR"); - } - if (device_properties_func != nullptr) { - VkPhysicalDeviceFragmentShadingRatePropertiesKHR vrsProperties{}; - VkPhysicalDeviceMultiviewProperties multiviewProperties{}; - VkPhysicalDeviceSubgroupProperties subgroupProperties{}; - VkPhysicalDeviceProperties2 physicalDeviceProperties{}; - void *nextptr = nullptr; - if (!(vulkan_major == 1 && vulkan_minor == 0)) { - subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; - subgroupProperties.pNext = nextptr; - - nextptr = &subgroupProperties; + // Check extended properties. + PFN_vkGetPhysicalDeviceProperties2 device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2"); + if (device_properties_func == nullptr) { + // In Vulkan 1.0 might be accessible under its original extension name. + device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2KHR"); } + if (device_properties_func != nullptr) { + VkPhysicalDeviceFragmentShadingRatePropertiesKHR vrsProperties{}; + VkPhysicalDeviceMultiviewProperties multiviewProperties{}; + VkPhysicalDeviceSubgroupProperties subgroupProperties{}; + VkPhysicalDeviceProperties2 physicalDeviceProperties{}; + void *nextptr = nullptr; + + if (!(vulkan_major == 1 && vulkan_minor == 0)) { + subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; + subgroupProperties.pNext = nextptr; + + nextptr = &subgroupProperties; + } - if (multiview_capabilities.is_supported) { - multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES; - multiviewProperties.pNext = nextptr; + if (multiview_capabilities.is_supported) { + multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES; + multiviewProperties.pNext = nextptr; - nextptr = &multiviewProperties; - } + nextptr = &multiviewProperties; + } - if (vrs_capabilities.attachment_vrs_supported) { - vrsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; - vrsProperties.pNext = nextptr; + if (vrs_capabilities.attachment_vrs_supported) { + vrsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; + vrsProperties.pNext = nextptr; - nextptr = &vrsProperties; - } + nextptr = &vrsProperties; + } - physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - physicalDeviceProperties.pNext = nextptr; + physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + physicalDeviceProperties.pNext = nextptr; - device_properties_func(gpu, &physicalDeviceProperties); + device_properties_func(gpu, &physicalDeviceProperties); - subgroup_capabilities.size = subgroupProperties.subgroupSize; - subgroup_capabilities.supportedStages = subgroupProperties.supportedStages; - subgroup_capabilities.supportedOperations = subgroupProperties.supportedOperations; - // Note: quadOperationsInAllStages will be true if: - // - supportedStages has VK_SHADER_STAGE_ALL_GRAPHICS + VK_SHADER_STAGE_COMPUTE_BIT. - // - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT. - subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages; + subgroup_capabilities.size = subgroupProperties.subgroupSize; + subgroup_capabilities.supportedStages = subgroupProperties.supportedStages; + subgroup_capabilities.supportedOperations = subgroupProperties.supportedOperations; + // Note: quadOperationsInAllStages will be true if: + // - supportedStages has VK_SHADER_STAGE_ALL_GRAPHICS + VK_SHADER_STAGE_COMPUTE_BIT. + // - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT. + subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages; - if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) { - print_verbose("- Vulkan Variable Rate Shading supported:"); - if (vrs_capabilities.pipeline_vrs_supported) { - print_verbose(" Pipeline fragment shading rate"); - } - if (vrs_capabilities.primitive_vrs_supported) { - print_verbose(" Primitive fragment shading rate"); - } - if (vrs_capabilities.attachment_vrs_supported) { - // TODO expose these somehow to the end user. - vrs_capabilities.min_texel_size.x = vrsProperties.minFragmentShadingRateAttachmentTexelSize.width; - vrs_capabilities.min_texel_size.y = vrsProperties.minFragmentShadingRateAttachmentTexelSize.height; - vrs_capabilities.max_texel_size.x = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.width; - vrs_capabilities.max_texel_size.y = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.height; + if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) { + print_verbose("- Vulkan Variable Rate Shading supported:"); + if (vrs_capabilities.pipeline_vrs_supported) { + print_verbose(" Pipeline fragment shading rate"); + } + if (vrs_capabilities.primitive_vrs_supported) { + print_verbose(" Primitive fragment shading rate"); + } + if (vrs_capabilities.attachment_vrs_supported) { + // TODO expose these somehow to the end user. + vrs_capabilities.min_texel_size.x = vrsProperties.minFragmentShadingRateAttachmentTexelSize.width; + vrs_capabilities.min_texel_size.y = vrsProperties.minFragmentShadingRateAttachmentTexelSize.height; + vrs_capabilities.max_texel_size.x = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.width; + vrs_capabilities.max_texel_size.y = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.height; + + // We'll attempt to default to a texel size of 16x16 + vrs_capabilities.texel_size.x = CLAMP(16, vrs_capabilities.min_texel_size.x, vrs_capabilities.max_texel_size.x); + vrs_capabilities.texel_size.y = CLAMP(16, vrs_capabilities.min_texel_size.y, vrs_capabilities.max_texel_size.y); + + print_verbose(String(" Attachment fragment shading rate") + String(", min texel size: (") + itos(vrs_capabilities.min_texel_size.x) + String(", ") + itos(vrs_capabilities.min_texel_size.y) + String(")") + String(", max texel size: (") + itos(vrs_capabilities.max_texel_size.x) + String(", ") + itos(vrs_capabilities.max_texel_size.y) + String(")")); + } - print_verbose(String(" Attachment fragment shading rate") + String(", min texel size: (") + itos(vrs_capabilities.min_texel_size.x) + String(", ") + itos(vrs_capabilities.min_texel_size.y) + String(")") + String(", max texel size: (") + itos(vrs_capabilities.max_texel_size.x) + String(", ") + itos(vrs_capabilities.max_texel_size.y) + String(")")); + } else { + print_verbose("- Vulkan Variable Rate Shading not supported"); } - } else { - print_verbose("- Vulkan Variable Rate Shading not supported"); - } + if (multiview_capabilities.is_supported) { + multiview_capabilities.max_view_count = multiviewProperties.maxMultiviewViewCount; + multiview_capabilities.max_instance_count = multiviewProperties.maxMultiviewInstanceIndex; - if (multiview_capabilities.is_supported) { - multiview_capabilities.max_view_count = multiviewProperties.maxMultiviewViewCount; - multiview_capabilities.max_instance_count = multiviewProperties.maxMultiviewInstanceIndex; + print_verbose("- Vulkan multiview supported:"); + print_verbose(" max view count: " + itos(multiview_capabilities.max_view_count)); + print_verbose(" max instances: " + itos(multiview_capabilities.max_instance_count)); + } else { + print_verbose("- Vulkan multiview not supported"); + } - print_verbose("- Vulkan multiview supported:"); - print_verbose(" max view count: " + itos(multiview_capabilities.max_view_count)); - print_verbose(" max instances: " + itos(multiview_capabilities.max_instance_count)); + print_verbose("- Vulkan subgroup:"); + print_verbose(" size: " + itos(subgroup_capabilities.size)); + print_verbose(" stages: " + subgroup_capabilities.supported_stages_desc()); + print_verbose(" supported ops: " + subgroup_capabilities.supported_operations_desc()); + if (subgroup_capabilities.quadOperationsInAllStages) { + print_verbose(" quad operations in all stages"); + } } else { - print_verbose("- Vulkan multiview not supported"); - } - - print_verbose("- Vulkan subgroup:"); - print_verbose(" size: " + itos(subgroup_capabilities.size)); - print_verbose(" stages: " + subgroup_capabilities.supported_stages_desc()); - print_verbose(" supported ops: " + subgroup_capabilities.supported_operations_desc()); - if (subgroup_capabilities.quadOperationsInAllStages) { - print_verbose(" quad operations in all stages"); + print_verbose("- Couldn't call vkGetPhysicalDeviceProperties2"); } - } else { - print_verbose("- Couldn't call vkGetPhysicalDeviceProperties2"); } return OK; @@ -826,12 +924,19 @@ Error VulkanContext::_create_instance() { // Initialize extensions. { - Error err = _initialize_extensions(); + Error err = _initialize_instance_extensions(); if (err != OK) { return err; } } + int enabled_extension_count = 0; + const char *enabled_extension_names[MAX_EXTENSIONS]; + ERR_FAIL_COND_V(enabled_instance_extension_names.size() > MAX_EXTENSIONS, ERR_CANT_CREATE); + for (const CharString &extension_name : enabled_instance_extension_names) { + enabled_extension_names[enabled_extension_count++] = extension_name.ptr(); + } + CharString cs = GLOBAL_GET("application/config/name").operator String().utf8(); const VkApplicationInfo app = { /*sType*/ VK_STRUCTURE_TYPE_APPLICATION_INFO, @@ -846,7 +951,7 @@ Error VulkanContext::_create_instance() { inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; inst_info.pApplicationInfo = &app; inst_info.enabledExtensionCount = enabled_extension_count; - inst_info.ppEnabledExtensionNames = (const char *const *)extension_names; + inst_info.ppEnabledExtensionNames = (const char *const *)enabled_extension_names; if (_use_validation_layers()) { _get_preferred_validation_layers(&inst_info.enabledLayerCount, &inst_info.ppEnabledLayerNames); } @@ -856,9 +961,9 @@ Error VulkanContext::_create_instance() { * After the instance is created, we use the instance-based * function to register the final callback. */ - VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info; - VkDebugReportCallbackCreateInfoEXT dbg_report_callback_create_info{}; - if (enabled_debug_utils) { + VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info = {}; + VkDebugReportCallbackCreateInfoEXT dbg_report_callback_create_info = {}; + if (is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { // VK_EXT_debug_utils style. dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; dbg_messenger_create_info.pNext = nullptr; @@ -871,7 +976,7 @@ Error VulkanContext::_create_instance() { dbg_messenger_create_info.pfnUserCallback = _debug_messenger_callback; dbg_messenger_create_info.pUserData = this; inst_info.pNext = &dbg_messenger_create_info; - } else if (enabled_debug_report) { + } else if (is_instance_extension_enabled(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) { dbg_report_callback_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; dbg_report_callback_create_info.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | @@ -911,7 +1016,7 @@ Error VulkanContext::_create_instance() { volkLoadInstance(inst); #endif - if (enabled_debug_utils) { + if (is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { // Setup VK_EXT_debug_utils function pointers always (we use them for debug labels and names). CreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugUtilsMessengerEXT"); @@ -952,7 +1057,7 @@ Error VulkanContext::_create_instance() { ERR_FAIL_V(ERR_CANT_CREATE); break; } - } else if (enabled_debug_report) { + } else if (is_instance_extension_enabled(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) { CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugReportCallbackEXT"); DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(inst, "vkDebugReportMessageEXT"); DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugReportCallbackEXT"); @@ -1133,12 +1238,6 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) { free(physical_devices); - // Look for device extensions. - uint32_t device_extension_count = 0; - VkBool32 swapchainExtFound = 0; - enabled_extension_count = 0; - memset(extension_names, 0, sizeof(extension_names)); - // Get identifier properties. vkGetPhysicalDeviceProperties(gpu, &gpu_props); @@ -1164,84 +1263,13 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) { device_api_version = gpu_props.apiVersion; - err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, nullptr); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - - if (device_extension_count > 0) { - VkExtensionProperties *device_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * device_extension_count); - err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, device_extensions); - if (err) { - free(device_extensions); - ERR_FAIL_V(ERR_CANT_CREATE); - } - - for (uint32_t i = 0; i < device_extension_count; i++) { - if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, device_extensions[i].extensionName)) { - swapchainExtFound = 1; - extension_names[enabled_extension_count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME; - } - if (!strcmp(VK_KHR_MULTIVIEW_EXTENSION_NAME, device_extensions[i].extensionName)) { - // If multiview is supported, enable it. - extension_names[enabled_extension_count++] = VK_KHR_MULTIVIEW_EXTENSION_NAME; - } - if (!strcmp(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, device_extensions[i].extensionName)) { - // if shading rate image is supported, enable it - extension_names[enabled_extension_count++] = VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME; - } - if (!strcmp(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, device_extensions[i].extensionName)) { - has_renderpass2_ext = true; - extension_names[enabled_extension_count++] = VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME; - } - if (enabled_extension_count >= MAX_EXTENSIONS) { - free(device_extensions); - ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG"); - } - } - - if (VK_KHR_incremental_present_enabled) { - // Even though the user "enabled" the extension via the command - // line, we must make sure that it's enumerated for use with the - // device. Therefore, disable it here, and re-enable it again if - // enumerated. - VK_KHR_incremental_present_enabled = false; - for (uint32_t i = 0; i < device_extension_count; i++) { - if (!strcmp(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, device_extensions[i].extensionName)) { - extension_names[enabled_extension_count++] = VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME; - VK_KHR_incremental_present_enabled = true; - } - if (enabled_extension_count >= MAX_EXTENSIONS) { - free(device_extensions); - ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG"); - } - } - } - - if (VK_GOOGLE_display_timing_enabled) { - // Even though the user "enabled" the extension via the command - // line, we must make sure that it's enumerated for use with the - // device. Therefore, disable it here, and re-enable it again if - // enumerated. - VK_GOOGLE_display_timing_enabled = false; - for (uint32_t i = 0; i < device_extension_count; i++) { - if (!strcmp(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, device_extensions[i].extensionName)) { - extension_names[enabled_extension_count++] = VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME; - VK_GOOGLE_display_timing_enabled = true; - } - if (enabled_extension_count >= MAX_EXTENSIONS) { - free(device_extensions); - ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG"); - } - } + { + Error _err = _initialize_device_extensions(); + if (_err != OK) { + return _err; } - - free(device_extensions); } - ERR_FAIL_COND_V_MSG(!swapchainExtFound, ERR_CANT_CREATE, - "vkEnumerateDeviceExtensionProperties failed to find the " VK_KHR_SWAPCHAIN_EXTENSION_NAME - " extension.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\n" - "vkCreateInstance Failure"); - // Call with nullptr data to get count. vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr); ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE); @@ -1302,7 +1330,7 @@ Error VulkanContext::_create_device() { }; nextptr = &shader_features; - VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features; + VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = {}; if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) { // Insert into our chain to enable these features if they are available. vrs_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; @@ -1314,9 +1342,9 @@ Error VulkanContext::_create_device() { nextptr = &vrs_features; } - VkPhysicalDeviceVulkan11Features vulkan11features; - VkPhysicalDevice16BitStorageFeaturesKHR storage_feature; - VkPhysicalDeviceMultiviewFeatures multiview_features; + VkPhysicalDeviceVulkan11Features vulkan11features = {}; + VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {}; + VkPhysicalDeviceMultiviewFeatures multiview_features = {}; if (vulkan_major > 1 || vulkan_minor >= 2) { // In Vulkan 1.2 and newer we use a newer struct to enable various features. @@ -1355,6 +1383,13 @@ Error VulkanContext::_create_device() { } } + uint32_t enabled_extension_count = 0; + const char *enabled_extension_names[MAX_EXTENSIONS]; + ERR_FAIL_COND_V(enabled_device_extension_names.size() > MAX_EXTENSIONS, ERR_CANT_CREATE); + for (const CharString &extension_name : enabled_device_extension_names) { + enabled_extension_names[enabled_extension_count++] = extension_name.ptr(); + } + VkDeviceCreateInfo sdevice = { /*sType*/ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, /*pNext*/ nextptr, @@ -1364,7 +1399,7 @@ Error VulkanContext::_create_device() { /*enabledLayerCount*/ 0, /*ppEnabledLayerNames*/ nullptr, /*enabledExtensionCount*/ enabled_extension_count, - /*ppEnabledExtensionNames*/ (const char *const *)extension_names, + /*ppEnabledExtensionNames*/ (const char *const *)enabled_extension_names, /*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here. }; if (separate_present_queue) { @@ -1452,7 +1487,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) { GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR); GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR); GET_DEVICE_PROC_ADDR(device, QueuePresentKHR); - if (VK_GOOGLE_display_timing_enabled) { + if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) { GET_DEVICE_PROC_ADDR(device, GetRefreshCycleDurationGOOGLE); GET_DEVICE_PROC_ADDR(device, GetPastPresentationTimingGOOGLE); } @@ -2207,7 +2242,7 @@ Error VulkanContext::swap_buffers() { VkResult err; #if 0 - if (VK_GOOGLE_display_timing_enabled) { + if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) { // Look at what happened to previous presents, and make appropriate // adjustments in timing. DemoUpdateTargetIPD(demo); @@ -2328,7 +2363,7 @@ Error VulkanContext::swap_buffers() { } #if 0 - if (VK_KHR_incremental_present_enabled) { + if (is_device_extension_enabled(VK_KHR_incremental_present_enabled)) { // If using VK_KHR_incremental_present, we provide a hint of the region // that contains changed content relative to the previously-presented // image. The implementation can use this hint in order to save @@ -2359,7 +2394,7 @@ Error VulkanContext::swap_buffers() { #endif #if 0 - if (VK_GOOGLE_display_timing_enabled) { + if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) { VkPresentTimeGOOGLE ptime; if (prev_desired_present_time == 0) { // This must be the first present for this swapchain. @@ -2389,7 +2424,7 @@ Error VulkanContext::swap_buffers() { /*swapchainCount*/ present.swapchainCount, /*pTimes*/ &ptime, }; - if (VK_GOOGLE_display_timing_enabled) { + if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) { present.pNext = &present_time; } } @@ -2462,6 +2497,13 @@ RID VulkanContext::local_device_create() { queues[0].pQueuePriorities = queue_priorities; queues[0].flags = 0; + uint32_t enabled_extension_count = 0; + const char *enabled_extension_names[MAX_EXTENSIONS]; + ERR_FAIL_COND_V(enabled_device_extension_names.size() > MAX_EXTENSIONS, RID()); + for (const CharString &extension_name : enabled_device_extension_names) { + enabled_extension_names[enabled_extension_count++] = extension_name.ptr(); + } + VkDeviceCreateInfo sdevice = { /*sType =*/VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, /*pNext */ nullptr, @@ -2471,7 +2513,7 @@ RID VulkanContext::local_device_create() { /*enabledLayerCount */ 0, /*ppEnabledLayerNames */ nullptr, /*enabledExtensionCount */ enabled_extension_count, - /*ppEnabledExtensionNames */ (const char *const *)extension_names, + /*ppEnabledExtensionNames */ (const char *const *)enabled_extension_names, /*pEnabledFeatures */ &physical_device_features, // If specific features are required, pass them in here. }; err = vkCreateDevice(gpu, &sdevice, nullptr, &ld.device); @@ -2536,7 +2578,7 @@ void VulkanContext::local_device_free(RID p_local_device) { } void VulkanContext::command_begin_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color) { - if (!enabled_debug_utils) { + if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { return; } @@ -2553,7 +2595,7 @@ void VulkanContext::command_begin_label(VkCommandBuffer p_command_buffer, String } void VulkanContext::command_insert_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color) { - if (!enabled_debug_utils) { + if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { return; } CharString cs = p_label_name.utf8(); @@ -2569,14 +2611,14 @@ void VulkanContext::command_insert_label(VkCommandBuffer p_command_buffer, Strin } void VulkanContext::command_end_label(VkCommandBuffer p_command_buffer) { - if (!enabled_debug_utils) { + if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { return; } CmdEndDebugUtilsLabelEXT(p_command_buffer); } void VulkanContext::set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name) { - if (!enabled_debug_utils) { + if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { return; } CharString obj_data = p_object_name.utf8(); @@ -2637,7 +2679,7 @@ VulkanContext::~VulkanContext() { vkDestroySemaphore(device, image_ownership_semaphores[i], nullptr); } } - if (inst_initialized && enabled_debug_utils) { + if (inst_initialized && is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { DestroyDebugUtilsMessengerEXT(inst, dbg_messenger, nullptr); } if (inst_initialized && dbg_debug_report != VK_NULL_HANDLE) { diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h index d6a25c5cd7..0d49f5fe9f 100644 --- a/drivers/vulkan/vulkan_context.h +++ b/drivers/vulkan/vulkan_context.h @@ -34,6 +34,7 @@ #include "core/error/error_list.h" #include "core/os/mutex.h" #include "core/string/ustring.h" +#include "core/templates/hash_map.h" #include "core/templates/rb_map.h" #include "core/templates/rid_owner.h" #include "servers/display_server.h" @@ -76,6 +77,8 @@ public: Size2i min_texel_size; Size2i max_texel_size; + + Size2i texel_size; // The texel size we'll use }; struct ShaderCapabilities { @@ -182,19 +185,15 @@ private: int command_buffer_count = 1; // Extensions. + static bool instance_extensions_initialized; + static HashMap<CharString, bool> requested_instance_extensions; + HashSet<CharString> enabled_instance_extension_names; + static bool device_extensions_initialized; + static HashMap<CharString, bool> requested_device_extensions; + HashSet<CharString> enabled_device_extension_names; bool VK_KHR_incremental_present_enabled = true; bool VK_GOOGLE_display_timing_enabled = true; - uint32_t enabled_extension_count = 0; - const char *extension_names[MAX_EXTENSIONS]; - bool enabled_debug_utils = false; - bool has_renderpass2_ext = false; - - /** - * True if VK_EXT_debug_report extension is used. VK_EXT_debug_report is deprecated but it is - * still used if VK_EXT_debug_utils is not available. - */ - bool enabled_debug_report = false; PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT = nullptr; PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT = nullptr; @@ -223,7 +222,8 @@ private: VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE; Error _obtain_vulkan_version(); - Error _initialize_extensions(); + Error _initialize_instance_extensions(); + Error _initialize_device_extensions(); Error _check_capabilities(); VkBool32 _check_layers(uint32_t check_count, const char *const *check_names, uint32_t layer_count, VkLayerProperties *layers); @@ -273,7 +273,7 @@ protected: public: // Extension calls. - bool supports_renderpass2() const { return has_renderpass2_ext; } + bool supports_renderpass2() const { return is_device_extension_enabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); } VkResult vkCreateRenderPass2KHR(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass); uint32_t get_vulkan_major() const { return vulkan_major; }; @@ -293,6 +293,16 @@ public: static void set_vulkan_hooks(VulkanHooks *p_vulkan_hooks) { vulkan_hooks = p_vulkan_hooks; }; + static void register_requested_instance_extension(const CharString &extension_name, bool p_required); + bool is_instance_extension_enabled(const CharString &extension_name) const { + return enabled_instance_extension_names.has(extension_name); + } + + static void register_requested_device_extension(const CharString &extension_name, bool p_required); + bool is_device_extension_enabled(const CharString &extension_name) const { + return enabled_device_extension_names.has(extension_name); + } + void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height); int window_get_width(DisplayServer::WindowID p_window = 0); int window_get_height(DisplayServer::WindowID p_window = 0); diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index 3b9d6c18eb..c376d5434f 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -443,7 +443,7 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info TreeItem *event_item = action_tree->create_item(action_item); // First Column - Text - event_item->set_text(0, event_config_dialog->get_event_text(event, true)); + event_item->set_text(0, EventListenerLineEdit::get_event_text(event, true)); event_item->set_meta("__event", event); event_item->set_meta("__index", evnt_idx); diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 4c7ebca299..da75bf1f3b 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -903,11 +903,17 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } float zoom_value = timeline->get_zoom()->get_max() - zv; - timeline->get_zoom()->set_value(zoom_value); - timeline->call_deferred("set_value", minimum_time); + if (Math::is_finite(minimum_time) && Math::is_finite(maximum_time) && maximum_time - minimum_time > CMP_EPSILON) { + timeline->get_zoom()->set_value(zoom_value); + timeline->call_deferred("set_value", minimum_time); + } - v_scroll = (maximum_value + minimum_value) / 2.0; - v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9); + if (Math::is_finite(minimum_value) && Math::is_finite(maximum_value)) { + v_scroll = (maximum_value + minimum_value) / 2.0; + if (maximum_value - minimum_value > CMP_EPSILON) { + v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9); + } + } queue_redraw(); accept_event(); @@ -938,9 +944,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { Vector2 popup_pos = get_screen_position() + mb->get_position(); menu->clear(); - if (!locked_tracks.has(selected_track) || locked_tracks.has(selected_track)) { - menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT); - } + menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT); if (selection.size()) { menu->add_separator(); menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 0c8176a44b..8305baf0a1 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1678,6 +1678,7 @@ void AnimationTimelineEdit::_notification(int p_what) { } draw_line(Vector2(0, get_size().height), get_size(), linecolor, Math::round(EDSCALE)); + update_values(); } break; } } @@ -1700,7 +1701,6 @@ void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation, boo play_position->hide(); } queue_redraw(); - update_values(); } Size2 AnimationTimelineEdit::get_minimum_size() const { @@ -1749,6 +1749,7 @@ void AnimationTimelineEdit::update_values() { length->set_step(1); length->set_tooltip_text(TTR("Animation length (frames)")); time_icon->set_tooltip_text(TTR("Animation length (frames)")); + track_edit->editor->_update_key_edit(); } else { length->set_value(animation->get_length()); length->set_step(0.001); @@ -1893,7 +1894,6 @@ void AnimationTimelineEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origi void AnimationTimelineEdit::set_use_fps(bool p_use_fps) { use_fps = p_use_fps; - update_values(); queue_redraw(); } @@ -3446,8 +3446,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re track_edits[_get_track_selected()]->release_focus(); } if (animation.is_valid()) { - animation->disconnect("tracks_changed", callable_mp(this, &AnimationTrackEditor::_animation_changed)); - animation->disconnect("changed", callable_mp(this, &AnimationTrackEditor::_sync_animation_change)); + animation->disconnect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed)); _clear_selection(); } animation = p_anim; @@ -3458,8 +3457,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re _update_tracks(); if (animation.is_valid()) { - animation->connect("tracks_changed", callable_mp(this, &AnimationTrackEditor::_animation_changed), CONNECT_DEFERRED); - animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_sync_animation_change), CONNECT_DEFERRED); + animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed), CONNECT_DEFERRED); hscroll->show(); edit->set_disabled(read_only); @@ -4650,10 +4648,6 @@ void AnimationTrackEditor::_redraw_groups() { } } -void AnimationTrackEditor::_sync_animation_change() { - bezier_edit->queue_redraw(); -} - void AnimationTrackEditor::_animation_changed() { if (animation_changing_awaiting_update) { return; // All will be updated, don't bother with anything. @@ -4793,6 +4787,7 @@ void AnimationTrackEditor::_update_step(double p_new_step) { if (step_value != 0.0) { step_value = 1.0 / step_value; } + timeline->queue_redraw(); } undo_redo->add_do_method(animation.ptr(), "set_step", step_value); undo_redo->add_undo_method(animation.ptr(), "set_step", animation->get_step()); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 5c51921d93..db2f8b32dc 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -135,6 +135,7 @@ class AnimationTrackEditor; class AnimationTrackEdit : public Control { GDCLASS(AnimationTrackEdit, Control); + friend class AnimationTimelineEdit; enum { MENU_CALL_MODE_CONTINUOUS, @@ -293,6 +294,7 @@ public: class AnimationTrackEditor : public VBoxContainer { GDCLASS(AnimationTrackEditor, VBoxContainer); + friend class AnimationTimelineEdit; Ref<Animation> animation; bool read_only = false; @@ -326,7 +328,6 @@ class AnimationTrackEditor : public VBoxContainer { bool animation_changing_awaiting_update = false; void _animation_update(); // Updated by AnimationTrackEditor(this) int _get_track_selected(); - void _sync_animation_change(); void _animation_changed(); void _update_tracks(); void _redraw_tracks(); diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 510dc345bf..e907d5a281 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -91,10 +91,10 @@ void FindReplaceBar::_notification(int p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { find_prev->set_icon(get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons"))); find_next->set_icon(get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons"))); - hide_button->set_normal_texture(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); - hide_button->set_hover_texture(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); - hide_button->set_pressed_texture(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); - hide_button->set_custom_minimum_size(hide_button->get_normal_texture()->get_size()); + hide_button->set_texture_normal(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); + hide_button->set_texture_hover(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); + hide_button->set_texture_pressed(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); + hide_button->set_custom_minimum_size(hide_button->get_texture_normal()->get_size()); } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -377,10 +377,12 @@ void FindReplaceBar::_update_results_count() { if (is_whole_words()) { if (col_pos > 0 && !is_symbol(line_text[col_pos - 1])) { - break; + col_pos += searched.length(); + continue; } - if (col_pos + line_text.length() < line_text.length() && !is_symbol(line_text[col_pos + searched.length()])) { - break; + if (col_pos + searched.length() < line_text.length() && !is_symbol(line_text[col_pos + searched.length()])) { + col_pos += searched.length(); + continue; } } diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index cdc3e220fb..785476d75b 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -501,7 +501,7 @@ String CreateDialog::get_selected_type() { return selected->get_text(0); } -Variant CreateDialog::instance_selected() { +Variant CreateDialog::instantiate_selected() { TreeItem *selected = search_options->get_selected(); if (!selected) { @@ -519,7 +519,7 @@ Variant CreateDialog::instance_selected() { n->set_name(custom); } } else { - obj = EditorNode::get_editor_data().instance_custom_type(selected->get_text(0), custom); + obj = EditorNode::get_editor_data().instantiate_custom_type(selected->get_text(0), custom); } } else { obj = ClassDB::instantiate(selected->get_text(0)); diff --git a/editor/create_dialog.h b/editor/create_dialog.h index f2e741624f..961538d8b7 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -110,7 +110,7 @@ protected: void _save_and_update_favorite_list(); public: - Variant instance_selected(); + Variant instantiate_selected(); String get_selected_type(); void set_base_type(const String &p_base) { base_type = p_base; } diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 49fbaa81bc..150257a95c 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -167,7 +167,7 @@ void EditorDebuggerNode::_text_editor_stack_goto(const ScriptEditorDebugger *p_d void EditorDebuggerNode::_bind_methods() { // LiveDebug. ClassDB::bind_method("live_debug_create_node", &EditorDebuggerNode::live_debug_create_node); - ClassDB::bind_method("live_debug_instance_node", &EditorDebuggerNode::live_debug_instance_node); + ClassDB::bind_method("live_debug_instantiate_node", &EditorDebuggerNode::live_debug_instantiate_node); ClassDB::bind_method("live_debug_remove_node", &EditorDebuggerNode::live_debug_remove_node); ClassDB::bind_method("live_debug_remove_and_keep_node", &EditorDebuggerNode::live_debug_remove_and_keep_node); ClassDB::bind_method("live_debug_restore_node", &EditorDebuggerNode::live_debug_restore_node); @@ -676,9 +676,9 @@ void EditorDebuggerNode::live_debug_create_node(const NodePath &p_parent, const }); } -void EditorDebuggerNode::live_debug_instance_node(const NodePath &p_parent, const String &p_path, const String &p_name) { +void EditorDebuggerNode::live_debug_instantiate_node(const NodePath &p_parent, const String &p_path, const String &p_name) { _for_all(tabs, [&](ScriptEditorDebugger *dbg) { - dbg->live_debug_instance_node(p_parent, p_path, p_name); + dbg->live_debug_instantiate_node(p_parent, p_path, p_name); }); } diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h index 259efeb47b..7f7279ae74 100644 --- a/editor/debugger/editor_debugger_node.h +++ b/editor/debugger/editor_debugger_node.h @@ -191,7 +191,7 @@ public: void set_live_debugging(bool p_enabled); void update_live_edit_root(); void live_debug_create_node(const NodePath &p_parent, const String &p_type, const String &p_name); - void live_debug_instance_node(const NodePath &p_parent, const String &p_path, const String &p_name); + void live_debug_instantiate_node(const NodePath &p_parent, const String &p_path, const String &p_name); void live_debug_remove_node(const NodePath &p_at); void live_debug_remove_and_keep_node(const NodePath &p_at, ObjectID p_keep_id); void live_debug_restore_node(ObjectID p_id, const NodePath &p_at, int p_at_pos); diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index fd77ad784a..178010d852 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -1253,13 +1253,13 @@ void ScriptEditorDebugger::live_debug_create_node(const NodePath &p_parent, cons } } -void ScriptEditorDebugger::live_debug_instance_node(const NodePath &p_parent, const String &p_path, const String &p_name) { +void ScriptEditorDebugger::live_debug_instantiate_node(const NodePath &p_parent, const String &p_path, const String &p_name) { if (live_debug) { Array msg; msg.push_back(p_parent); msg.push_back(p_path); msg.push_back(p_name); - _put_msg("scene:live_instance_node", msg); + _put_msg("scene:live_instantiate_node", msg); } } @@ -1596,7 +1596,7 @@ void ScriptEditorDebugger::_tab_changed(int p_tab) { void ScriptEditorDebugger::_bind_methods() { ClassDB::bind_method(D_METHOD("live_debug_create_node"), &ScriptEditorDebugger::live_debug_create_node); - ClassDB::bind_method(D_METHOD("live_debug_instance_node"), &ScriptEditorDebugger::live_debug_instance_node); + ClassDB::bind_method(D_METHOD("live_debug_instantiate_node"), &ScriptEditorDebugger::live_debug_instantiate_node); ClassDB::bind_method(D_METHOD("live_debug_remove_node"), &ScriptEditorDebugger::live_debug_remove_node); ClassDB::bind_method(D_METHOD("live_debug_remove_and_keep_node"), &ScriptEditorDebugger::live_debug_remove_and_keep_node); ClassDB::bind_method(D_METHOD("live_debug_restore_node"), &ScriptEditorDebugger::live_debug_restore_node); diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h index 22d6e48294..06bff39053 100644 --- a/editor/debugger/script_editor_debugger.h +++ b/editor/debugger/script_editor_debugger.h @@ -259,7 +259,7 @@ public: void set_live_debugging(bool p_enable); void live_debug_create_node(const NodePath &p_parent, const String &p_type, const String &p_name); - void live_debug_instance_node(const NodePath &p_parent, const String &p_path, const String &p_name); + void live_debug_instantiate_node(const NodePath &p_parent, const String &p_path, const String &p_name); void live_debug_remove_node(const NodePath &p_at); void live_debug_remove_and_keep_node(const NodePath &p_at, ObjectID p_keep_id); void live_debug_restore_node(ObjectID p_id, const NodePath &p_at, int p_at_pos); diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp index 3f93fa1f41..b92b0fca59 100644 --- a/editor/editor_command_palette.cpp +++ b/editor/editor_command_palette.cpp @@ -171,7 +171,13 @@ void EditorCommandPalette::_confirmed() { } void EditorCommandPalette::open_popup() { - popup_centered_clamped(Size2i(600, 440), 0.8f); + static bool was_showed = false; + if (!was_showed) { + was_showed = true; + popup_centered_clamped(Size2(600, 440) * EDSCALE, 0.8f); + } else { + show(); + } command_search_box->clear(); command_search_box->grab_focus(); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index a3dd19bb67..48be0c9c00 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -486,7 +486,7 @@ void EditorData::add_custom_type(const String &p_type, const String &p_inherits, custom_types[p_inherits].push_back(ct); } -Variant EditorData::instance_custom_type(const String &p_type, const String &p_inherits) { +Variant EditorData::instantiate_custom_type(const String &p_type, const String &p_inherits) { if (get_custom_types().has(p_inherits)) { for (int i = 0; i < get_custom_types()[p_inherits].size(); i++) { if (get_custom_types()[p_inherits][i].name == p_type) { diff --git a/editor/editor_data.h b/editor/editor_data.h index 4f1740d4f0..aad00f3ff8 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -181,7 +181,7 @@ public: void restore_editor_global_states(); void add_custom_type(const String &p_type, const String &p_inherits, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon); - Variant instance_custom_type(const String &p_type, const String &p_inherits); + Variant instantiate_custom_type(const String &p_type, const String &p_inherits); void remove_custom_type(const String &p_type); const HashMap<String, Vector<CustomType>> &get_custom_types() const { return custom_types; } const CustomType *get_custom_type_by_name(const String &p_name) const; diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index efa85dadee..676e4b0b33 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -446,7 +446,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { return OK; } -void EditorHelp::_update_method_list(const Vector<DocData::MethodDoc> p_methods, bool &r_method_descrpitons) { +void EditorHelp::_update_method_list(const Vector<DocData::MethodDoc> p_methods) { Ref<Font> font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts")); class_desc->pop(); // title font size class_desc->pop(); // title font @@ -496,10 +496,6 @@ void EditorHelp::_update_method_list(const Vector<DocData::MethodDoc> p_methods, class_desc->pop(); //cell } - if (!m[i].description.strip_edges().is_empty() || m[i].errors_returned.size() > 0) { - r_method_descrpitons = true; - } - _add_method(m[i], true); } @@ -717,11 +713,15 @@ void EditorHelp::_update_doc() { class_desc->add_newline(); } + bool has_description = false; + class_desc->add_newline(); class_desc->add_newline(); // Brief description if (!cd.brief_description.strip_edges().is_empty()) { + has_description = true; + class_desc->push_color(text_color); class_desc->push_font(doc_bold_font); class_desc->push_indent(1); @@ -736,6 +736,8 @@ void EditorHelp::_update_doc() { // Class description if (!cd.description.strip_edges().is_empty()) { + has_description = true; + section_line.push_back(Pair<String, int>(TTR("Description"), class_desc->get_paragraph_count() - 2)); description_line = class_desc->get_paragraph_count() - 2; class_desc->push_color(title_color); @@ -760,6 +762,22 @@ void EditorHelp::_update_doc() { class_desc->add_newline(); } + if (!has_description) { + class_desc->add_image(get_theme_icon(SNAME("Error"), SNAME("EditorIcons"))); + class_desc->add_text(" "); + class_desc->push_color(comment_color); + + if (cd.is_script_doc) { + class_desc->append_text(TTR("There is currently no description for this class.")); + } else { + class_desc->append_text(TTR("There is currently no description for this class. Please help us by [color=$color][url=$url]contributing one[/url][/color]!").replace("$url", CONTRIBUTE_URL).replace("$color", link_color_text)); + } + + class_desc->pop(); + class_desc->add_newline(); + class_desc->add_newline(); + } + // Online tutorials if (cd.tutorials.size()) { class_desc->push_color(title_color); @@ -796,7 +814,6 @@ void EditorHelp::_update_doc() { // Properties overview HashSet<String> skip_methods; - bool property_descr = false; bool has_properties = cd.properties.size() != 0; if (cd.is_script_doc) { @@ -874,7 +891,6 @@ void EditorHelp::_update_doc() { if (describe) { class_desc->pop(); - property_descr = true; } class_desc->pop(); @@ -959,9 +975,6 @@ void EditorHelp::_update_doc() { } // Methods overview - bool constructor_descriptions = false; - bool method_descriptions = false; - bool operator_descriptions = false; bool sort_methods = EDITOR_GET("text_editor/help/sort_functions_alphabetically"); Vector<DocData::MethodDoc> methods; @@ -989,19 +1002,20 @@ void EditorHelp::_update_doc() { class_desc->push_font(doc_title_font); class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Constructors")); - _update_method_list(cd.constructors, constructor_descriptions); + _update_method_list(cd.constructors); } if (!methods.is_empty()) { if (sort_methods) { methods.sort(); } + section_line.push_back(Pair<String, int>(TTR("Methods"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Methods")); - _update_method_list(methods, method_descriptions); + _update_method_list(methods); } if (!cd.operators.is_empty()) { @@ -1014,7 +1028,7 @@ void EditorHelp::_update_doc() { class_desc->push_font(doc_title_font); class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Operators")); - _update_method_list(cd.operators, operator_descriptions); + _update_method_list(cd.operators); } // Theme properties @@ -1349,7 +1363,7 @@ void EditorHelp::_update_doc() { if (constants[i].value.begins_with("Color(") && constants[i].value.ends_with(")")) { String stripped = constants[i].value.replace(" ", "").replace("Color(", "").replace(")", ""); - Vector<float> color = stripped.split_floats(","); + PackedFloat64Array color = stripped.split_floats(","); if (color.size() >= 3) { class_desc->push_color(Color(color[0], color[1], color[2])); _add_bulletpoint(); @@ -1507,7 +1521,7 @@ void EditorHelp::_update_doc() { } // Property descriptions - if (property_descr) { + if (has_properties) { section_line.push_back(Pair<String, int>(TTR("Property Descriptions"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); @@ -1682,7 +1696,7 @@ void EditorHelp::_update_doc() { } // Constructor descriptions - if (constructor_descriptions) { + if (!cd.constructors.is_empty()) { section_line.push_back(Pair<String, int>(TTR("Constructor Descriptions"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); @@ -1692,7 +1706,7 @@ void EditorHelp::_update_doc() { } // Method descriptions - if (method_descriptions) { + if (!methods.is_empty()) { section_line.push_back(Pair<String, int>(TTR("Method Descriptions"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); @@ -1702,7 +1716,7 @@ void EditorHelp::_update_doc() { } // Operator descriptions - if (operator_descriptions) { + if (!cd.operators.is_empty()) { section_line.push_back(Pair<String, int>(TTR("Operator Descriptions"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); @@ -1710,6 +1724,8 @@ void EditorHelp::_update_doc() { class_desc->add_text(TTR("Operator Descriptions")); _update_method_descriptions(cd, cd.operators, "operator"); } + + // Free the scroll. scroll_locked = false; } @@ -2419,10 +2435,10 @@ void FindBar::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { find_prev->set_icon(get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons"))); find_next->set_icon(get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons"))); - hide_button->set_normal_texture(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); - hide_button->set_hover_texture(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); - hide_button->set_pressed_texture(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); - hide_button->set_custom_minimum_size(hide_button->get_normal_texture()->get_size()); + hide_button->set_texture_normal(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); + hide_button->set_texture_hover(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); + hide_button->set_texture_pressed(get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); + hide_button->set_custom_minimum_size(hide_button->get_texture_normal()->get_size()); matches_label->add_theme_color_override("font_color", results_count > 0 ? get_theme_color(SNAME("font_color"), SNAME("Label")) : get_theme_color(SNAME("error_color"), SNAME("Editor"))); } break; diff --git a/editor/editor_help.h b/editor/editor_help.h index c9c1afb51b..15bfdc7c91 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -167,7 +167,7 @@ class EditorHelp : public VBoxContainer { Error _goto_desc(const String &p_class, int p_vscr = -1); //void _update_history_buttons(); - void _update_method_list(const Vector<DocData::MethodDoc> p_methods, bool &r_method_descrpitons); + void _update_method_list(const Vector<DocData::MethodDoc> p_methods); void _update_method_descriptions(const DocData::ClassDoc p_classdoc, const Vector<DocData::MethodDoc> p_methods, const String &p_method_type); void _update_doc(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index cbad9aa737..995cfb138c 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -70,7 +70,6 @@ #include "servers/physics_server_2d.h" #include "servers/rendering/rendering_device.h" -#include "editor/animation_track_editor.h" #include "editor/audio_stream_preview.h" #include "editor/debugger/debug_adapter/debug_adapter_server.h" #include "editor/debugger/editor_debugger_node.h" @@ -82,7 +81,6 @@ #include "editor/editor_data.h" #include "editor/editor_feature_profile.h" #include "editor/editor_file_dialog.h" -#include "editor/editor_file_system.h" #include "editor/editor_folding.h" #include "editor/editor_help.h" #include "editor/editor_inspector.h" @@ -92,12 +90,8 @@ #include "editor/editor_plugin.h" #include "editor/editor_properties.h" #include "editor/editor_property_name_processor.h" -#include "editor/editor_quick_open.h" -#include "editor/editor_resource_picker.h" -#include "editor/editor_resource_preview.h" #include "editor/editor_run.h" #include "editor/editor_run_native.h" -#include "editor/editor_run_script.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_settings_dialog.h" @@ -123,7 +117,6 @@ #include "editor/import/resource_importer_imagefont.h" #include "editor/import/resource_importer_layered_texture.h" #include "editor/import/resource_importer_obj.h" -#include "editor/import/resource_importer_scene.h" #include "editor/import/resource_importer_shader_file.h" #include "editor/import/resource_importer_texture.h" #include "editor/import/resource_importer_texture_atlas.h" @@ -133,78 +126,21 @@ #include "editor/multi_node_edit.h" #include "editor/node_dock.h" #include "editor/plugin_config_dialog.h" -#include "editor/plugins/animation_blend_space_1d_editor.h" -#include "editor/plugins/animation_blend_space_2d_editor.h" -#include "editor/plugins/animation_blend_tree_editor_plugin.h" #include "editor/plugins/animation_player_editor_plugin.h" -#include "editor/plugins/animation_state_machine_editor.h" -#include "editor/plugins/animation_tree_editor_plugin.h" #include "editor/plugins/asset_library_editor_plugin.h" -#include "editor/plugins/audio_stream_randomizer_editor_plugin.h" -#include "editor/plugins/bit_map_editor_plugin.h" -#include "editor/plugins/bone_map_editor_plugin.h" -#include "editor/plugins/camera_3d_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" -#include "editor/plugins/cast_2d_editor_plugin.h" -#include "editor/plugins/collision_polygon_2d_editor_plugin.h" -#include "editor/plugins/collision_shape_2d_editor_plugin.h" -#include "editor/plugins/control_editor_plugin.h" -#include "editor/plugins/cpu_particles_2d_editor_plugin.h" -#include "editor/plugins/cpu_particles_3d_editor_plugin.h" -#include "editor/plugins/curve_editor_plugin.h" #include "editor/plugins/debugger_editor_plugin.h" -#include "editor/plugins/editor_debugger_plugin.h" -#include "editor/plugins/editor_preview_plugins.h" #include "editor/plugins/editor_resource_conversion_plugin.h" -#include "editor/plugins/font_config_plugin.h" #include "editor/plugins/gdextension_export_plugin.h" -#include "editor/plugins/gpu_particles_2d_editor_plugin.h" -#include "editor/plugins/gpu_particles_3d_editor_plugin.h" -#include "editor/plugins/gpu_particles_collision_sdf_editor_plugin.h" -#include "editor/plugins/gradient_editor_plugin.h" -#include "editor/plugins/gradient_texture_2d_editor_plugin.h" -#include "editor/plugins/input_event_editor_plugin.h" -#include "editor/plugins/light_occluder_2d_editor_plugin.h" -#include "editor/plugins/lightmap_gi_editor_plugin.h" -#include "editor/plugins/line_2d_editor_plugin.h" #include "editor/plugins/material_editor_plugin.h" -#include "editor/plugins/mesh_editor_plugin.h" -#include "editor/plugins/mesh_instance_3d_editor_plugin.h" #include "editor/plugins/mesh_library_editor_plugin.h" -#include "editor/plugins/multimesh_editor_plugin.h" -#include "editor/plugins/navigation_link_2d_editor_plugin.h" -#include "editor/plugins/navigation_polygon_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" -#include "editor/plugins/occluder_instance_3d_editor_plugin.h" #include "editor/plugins/packed_scene_translation_parser_plugin.h" -#include "editor/plugins/path_2d_editor_plugin.h" -#include "editor/plugins/path_3d_editor_plugin.h" -#include "editor/plugins/physical_bone_3d_editor_plugin.h" -#include "editor/plugins/polygon_2d_editor_plugin.h" -#include "editor/plugins/polygon_3d_editor_plugin.h" -#include "editor/plugins/resource_preloader_editor_plugin.h" #include "editor/plugins/root_motion_editor_plugin.h" -#include "editor/plugins/script_editor_plugin.h" #include "editor/plugins/script_text_editor.h" -#include "editor/plugins/shader_editor_plugin.h" -#include "editor/plugins/shader_file_editor_plugin.h" -#include "editor/plugins/skeleton_2d_editor_plugin.h" -#include "editor/plugins/skeleton_3d_editor_plugin.h" -#include "editor/plugins/skeleton_ik_3d_editor_plugin.h" -#include "editor/plugins/sprite_2d_editor_plugin.h" -#include "editor/plugins/sprite_frames_editor_plugin.h" -#include "editor/plugins/style_box_editor_plugin.h" -#include "editor/plugins/sub_viewport_preview_editor_plugin.h" #include "editor/plugins/text_editor.h" -#include "editor/plugins/texture_3d_editor_plugin.h" -#include "editor/plugins/texture_editor_plugin.h" -#include "editor/plugins/texture_layered_editor_plugin.h" -#include "editor/plugins/texture_region_editor_plugin.h" -#include "editor/plugins/theme_editor_plugin.h" -#include "editor/plugins/tiles/tiles_editor_plugin.h" #include "editor/plugins/version_control_editor_plugin.h" #include "editor/plugins/visual_shader_editor_plugin.h" -#include "editor/plugins/voxel_gi_editor_plugin.h" #include "editor/progress_dialog.h" #include "editor/project_settings_editor.h" #include "editor/register_exporters.h" @@ -1764,7 +1700,7 @@ void EditorNode::_save_scene(String p_file, int idx) { } if (!scene->get_scene_file_path().is_empty() && _validate_scene_recursive(scene->get_scene_file_path(), scene)) { - show_accept(TTR("This scene can't be saved because there is a cyclic instancing inclusion.\nPlease resolve it and then attempt to save again."), TTR("OK")); + show_accept(TTR("This scene can't be saved because there is a cyclic instance inclusion.\nPlease resolve it and then attempt to save again."), TTR("OK")); return; } @@ -2332,7 +2268,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) { if (get_edited_scene() && !get_edited_scene()->get_scene_file_path().is_empty()) { String source_scene = get_edited_scene()->get_scene_file_path(); if (FileAccess::exists(source_scene + ".import")) { - editable_info = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); + editable_info = TTR("This scene was imported, so changes to it won't be kept.\nInstantiating or inheriting it will allow you to make changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); info_is_warning = true; } } @@ -3993,7 +3929,7 @@ bool EditorNode::is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_ return false; } -void EditorNode::request_instance_scene(const String &p_path) { +void EditorNode::request_instantiate_scene(const String &p_path) { SceneTreeDock::get_singleton()->instantiate(p_path); } @@ -4129,63 +4065,6 @@ bool EditorNode::is_scene_in_use(const String &p_path) { return false; } -void EditorNode::register_editor_types() { - ResourceLoader::set_timestamp_on_load(true); - ResourceSaver::set_timestamp_on_save(true); - - GDREGISTER_CLASS(EditorPaths); - GDREGISTER_CLASS(EditorPlugin); - GDREGISTER_CLASS(EditorTranslationParserPlugin); - GDREGISTER_CLASS(EditorImportPlugin); - GDREGISTER_CLASS(EditorScript); - GDREGISTER_CLASS(EditorSelection); - GDREGISTER_CLASS(EditorFileDialog); - GDREGISTER_ABSTRACT_CLASS(EditorSettings); - GDREGISTER_CLASS(EditorNode3DGizmo); - GDREGISTER_CLASS(EditorNode3DGizmoPlugin); - GDREGISTER_ABSTRACT_CLASS(EditorResourcePreview); - GDREGISTER_CLASS(EditorResourcePreviewGenerator); - GDREGISTER_ABSTRACT_CLASS(EditorFileSystem); - GDREGISTER_CLASS(EditorFileSystemDirectory); - GDREGISTER_CLASS(EditorVCSInterface); - GDREGISTER_ABSTRACT_CLASS(ScriptEditor); - GDREGISTER_ABSTRACT_CLASS(ScriptEditorBase); - GDREGISTER_CLASS(EditorSyntaxHighlighter); - GDREGISTER_ABSTRACT_CLASS(EditorInterface); - GDREGISTER_CLASS(EditorExportPlugin); - GDREGISTER_ABSTRACT_CLASS(EditorExportPlatform); - GDREGISTER_CLASS(EditorResourceConversionPlugin); - GDREGISTER_CLASS(EditorSceneFormatImporter); - GDREGISTER_CLASS(EditorScenePostImportPlugin); - GDREGISTER_CLASS(EditorInspector); - GDREGISTER_CLASS(EditorInspectorPlugin); - GDREGISTER_CLASS(EditorProperty); - GDREGISTER_CLASS(AnimationTrackEditPlugin); - GDREGISTER_CLASS(ScriptCreateDialog); - GDREGISTER_CLASS(EditorFeatureProfile); - GDREGISTER_CLASS(EditorSpinSlider); - GDREGISTER_CLASS(EditorResourcePicker); - GDREGISTER_CLASS(EditorScriptPicker); - GDREGISTER_ABSTRACT_CLASS(EditorUndoRedoManager); - - GDREGISTER_ABSTRACT_CLASS(FileSystemDock); - GDREGISTER_VIRTUAL_CLASS(EditorFileSystemImportFormatSupportQuery); - - GDREGISTER_CLASS(EditorScenePostImport); - GDREGISTER_CLASS(EditorCommandPalette); - GDREGISTER_CLASS(EditorDebuggerPlugin); - GDREGISTER_ABSTRACT_CLASS(EditorDebuggerSession); -} - -void EditorNode::unregister_editor_types() { - _init_callbacks.clear(); - if (EditorPaths::get_singleton()) { - EditorPaths::free(); - } - - EditorResourcePicker::clear_caches(); -} - void EditorNode::stop_child_process(OS::ProcessID p_pid) { if (has_child_process(p_pid)) { editor_run.stop_child_process(p_pid); @@ -4558,6 +4437,7 @@ void EditorNode::_dock_floating_close_request(Control *p_control) { dock_slot[window_slot]->add_child(p_control); dock_slot[window_slot]->move_child(p_control, MIN((int)window->get_meta("dock_index"), dock_slot[window_slot]->get_tab_count())); dock_slot[window_slot]->set_current_tab(window->get_meta("dock_index")); + dock_slot[window_slot]->set_tab_title(dock_slot[window_slot]->get_tab_idx_from_control(p_control), TTRGET(p_control->get_name())); window->queue_free(); @@ -4581,7 +4461,7 @@ void EditorNode::_dock_make_float() { dock_slot[dock_popup_selected_idx]->remove_child(dock); Window *window = memnew(Window); - window->set_title(dock->get_name()); + window->set_title(TTRGET(dock->get_name())); Panel *p = memnew(Panel); p->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("PanelForeground"), SNAME("EditorStyles"))); p->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); @@ -5235,6 +5115,10 @@ bool EditorNode::immediate_confirmation_dialog(const String &p_text, const Strin return singleton->immediate_dialog_confirmed; } +void EditorNode::cleanup() { + _init_callbacks.clear(); +} + int EditorNode::get_current_tab() { return scene_tabs->get_current_tab(); } @@ -7102,7 +6986,7 @@ EditorNode::EditorNode() { FileSystemDock *filesystem_dock = memnew(FileSystemDock); filesystem_dock->connect("inherit", callable_mp(this, &EditorNode::_inherit_request)); - filesystem_dock->connect("instance", callable_mp(this, &EditorNode::_instantiate_request)); + filesystem_dock->connect("instantiate", callable_mp(this, &EditorNode::_instantiate_request)); filesystem_dock->connect("display_mode_changed", callable_mp(this, &EditorNode::_save_docks)); get_project_settings()->connect_filesystem_dock_signals(filesystem_dock); @@ -7325,7 +7209,6 @@ EditorNode::EditorNode() { add_child(audio_preview_gen); add_editor_plugin(memnew(DebuggerEditorPlugin(debug_menu))); - add_editor_plugin(memnew(DebugAdapterServer())); disk_changed = memnew(ConfirmationDialog); { @@ -7375,63 +7258,7 @@ EditorNode::EditorNode() { raise_bottom_panel_item(AnimationPlayerEditor::get_singleton()); add_editor_plugin(VersionControlEditorPlugin::get_singleton()); - - // This list is alphabetized, and plugins that depend on Node2D are in their own section below. - add_editor_plugin(memnew(AnimationTreeEditorPlugin)); add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor))); - add_editor_plugin(memnew(AudioStreamRandomizerEditorPlugin)); - add_editor_plugin(memnew(BitMapEditorPlugin)); - add_editor_plugin(memnew(BoneMapEditorPlugin)); - add_editor_plugin(memnew(Camera3DEditorPlugin)); - add_editor_plugin(memnew(ControlEditorPlugin)); - add_editor_plugin(memnew(CPUParticles3DEditorPlugin)); - add_editor_plugin(memnew(CurveEditorPlugin)); - add_editor_plugin(memnew(FontEditorPlugin)); - add_editor_plugin(memnew(GPUParticles3DEditorPlugin)); - add_editor_plugin(memnew(GPUParticlesCollisionSDF3DEditorPlugin)); - add_editor_plugin(memnew(GradientEditorPlugin)); - add_editor_plugin(memnew(GradientTexture2DEditorPlugin)); - add_editor_plugin(memnew(InputEventEditorPlugin)); - add_editor_plugin(memnew(LightmapGIEditorPlugin)); - add_editor_plugin(memnew(MaterialEditorPlugin)); - add_editor_plugin(memnew(MeshEditorPlugin)); - add_editor_plugin(memnew(MeshInstance3DEditorPlugin)); - add_editor_plugin(memnew(MeshLibraryEditorPlugin)); - add_editor_plugin(memnew(MultiMeshEditorPlugin)); - add_editor_plugin(memnew(OccluderInstance3DEditorPlugin)); - add_editor_plugin(memnew(Path3DEditorPlugin)); - add_editor_plugin(memnew(PhysicalBone3DEditorPlugin)); - add_editor_plugin(memnew(Polygon3DEditorPlugin)); - add_editor_plugin(memnew(ResourcePreloaderEditorPlugin)); - add_editor_plugin(memnew(ShaderEditorPlugin)); - add_editor_plugin(memnew(ShaderFileEditorPlugin)); - add_editor_plugin(memnew(Skeleton3DEditorPlugin)); - add_editor_plugin(memnew(SkeletonIK3DEditorPlugin)); - add_editor_plugin(memnew(SpriteFramesEditorPlugin)); - add_editor_plugin(memnew(StyleBoxEditorPlugin)); - add_editor_plugin(memnew(SubViewportPreviewEditorPlugin)); - add_editor_plugin(memnew(Texture3DEditorPlugin)); - add_editor_plugin(memnew(TextureEditorPlugin)); - add_editor_plugin(memnew(TextureLayeredEditorPlugin)); - add_editor_plugin(memnew(TextureRegionEditorPlugin)); - add_editor_plugin(memnew(ThemeEditorPlugin)); - add_editor_plugin(memnew(VoxelGIEditorPlugin)); - - // 2D - add_editor_plugin(memnew(CollisionPolygon2DEditorPlugin)); - add_editor_plugin(memnew(CollisionShape2DEditorPlugin)); - add_editor_plugin(memnew(CPUParticles2DEditorPlugin)); - add_editor_plugin(memnew(GPUParticles2DEditorPlugin)); - add_editor_plugin(memnew(LightOccluder2DEditorPlugin)); - add_editor_plugin(memnew(Line2DEditorPlugin)); - add_editor_plugin(memnew(NavigationLink2DEditorPlugin)); - add_editor_plugin(memnew(NavigationPolygonEditorPlugin)); - add_editor_plugin(memnew(Path2DEditorPlugin)); - add_editor_plugin(memnew(Polygon2DEditorPlugin)); - add_editor_plugin(memnew(Cast2DEditorPlugin)); - add_editor_plugin(memnew(Skeleton2DEditorPlugin)); - add_editor_plugin(memnew(Sprite2DEditorPlugin)); - add_editor_plugin(memnew(TilesEditorPlugin)); for (int i = 0; i < EditorPlugins::get_plugin_count(); i++) { add_editor_plugin(EditorPlugins::create(i)); diff --git a/editor/editor_node.h b/editor/editor_node.h index f27fe429b9..ff0338a794 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -713,9 +713,6 @@ public: bool call_build(); - static void register_editor_types(); - static void unregister_editor_types(); - static EditorNode *get_singleton() { return singleton; } static EditorLog *get_log() { return singleton->log; } @@ -749,6 +746,8 @@ public: static bool immediate_confirmation_dialog(const String &p_text, const String &p_ok_text = TTR("Ok"), const String &p_cancel_text = TTR("Cancel")); + static void cleanup(); + EditorPlugin *get_editor_plugin_screen() { return editor_plugin_screen; } EditorPluginList *get_editor_plugins_force_input_forwarding() { return editor_plugins_force_input_forwarding; } EditorPluginList *get_editor_plugins_force_over() { return editor_plugins_force_over; } @@ -816,7 +815,7 @@ public: void setup_color_picker(ColorPicker *picker); - void request_instance_scene(const String &p_path); + void request_instantiate_scene(const String &p_path); void request_instantiate_scenes(const Vector<String> &p_files); void set_convert_old_scene(bool p_old) { convert_old = p_old; } diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 9c639164f2..d736675faf 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -322,7 +322,7 @@ typedef EditorPlugin *(*EditorPluginCreateFunc)(); class EditorPlugins { enum { - MAX_CREATE_FUNCS = 64 + MAX_CREATE_FUNCS = 128 }; static EditorPluginCreateFunc creation_funcs[MAX_CREATE_FUNCS]; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index d71976a1af..8c53f576ac 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -31,6 +31,7 @@ #include "editor_properties.h" #include "core/config/project_settings.h" +#include "core/core_string_names.h" #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_properties_array_dict.h" @@ -1169,9 +1170,9 @@ void EditorPropertyLayers::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - button->set_normal_texture(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); - button->set_pressed_texture(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); - button->set_disabled_texture(get_theme_icon(SNAME("GuiTabMenu"), SNAME("EditorIcons"))); + button->set_texture_normal(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); + button->set_texture_pressed(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); + button->set_texture_disabled(get_theme_icon(SNAME("GuiTabMenu"), SNAME("EditorIcons"))); } break; } } @@ -1811,8 +1812,8 @@ void EditorPropertyVector2::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons"))); - linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons"))); + linked->set_texture_normal(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons"))); + linked->set_texture_pressed(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons"))); const Color *colors = _get_property_colors(); for (int i = 0; i < 2; i++) { @@ -2089,8 +2090,8 @@ void EditorPropertyVector3::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons"))); - linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons"))); + linked->set_texture_normal(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons"))); + linked->set_texture_pressed(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons"))); const Color *colors = _get_property_colors(); for (int i = 0; i < 3; i++) { @@ -2224,8 +2225,8 @@ void EditorPropertyVector2i::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons"))); - linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons"))); + linked->set_texture_normal(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons"))); + linked->set_texture_pressed(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons"))); const Color *colors = _get_property_colors(); for (int i = 0; i < 2; i++) { @@ -2475,8 +2476,8 @@ void EditorPropertyVector3i::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons"))); - linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons"))); + linked->set_texture_normal(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons"))); + linked->set_texture_pressed(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons"))); const Color *colors = _get_property_colors(); for (int i = 0; i < 3; i++) { @@ -3844,8 +3845,11 @@ void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource, void EditorPropertyResource::_resource_changed(const Ref<Resource> &p_resource) { // Make visual script the correct type. Ref<Script> s = p_resource; + + // The bool is_script applies only to an object's main script. + // Changing the value of Script-type exported variables of the main script should not trigger saving/reloading properties. bool is_script = false; - if (get_edited_object() && s.is_valid()) { + if (get_edited_object() && s.is_valid() && get_edited_property() == CoreStringNames::get_singleton()->_script) { is_script = true; InspectorDock::get_singleton()->store_script_properties(get_edited_object()); s->call("set_instance_base_type", get_edited_object()->get_class()); diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp index a2dfa4f80e..bd8b753720 100644 --- a/editor/editor_property_name_processor.cpp +++ b/editor/editor_property_name_processor.cpp @@ -64,6 +64,10 @@ String EditorPropertyNameProcessor::_capitalize_name(const String &p_name) const Vector<String> parts = p_name.split("_", false); for (int i = 0; i < parts.size(); i++) { + // Articles/conjunctions/prepositions which should only be capitalized if first word. + if (i != 0 && stop_words.find(parts[i]) != -1) { + continue; + } HashMap<String, String>::ConstIterator remap = capitalize_string_remaps.find(parts[i]); if (remap) { parts.write[i] = remap->value; @@ -143,6 +147,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["gdscript"] = "GDScript"; capitalize_string_remaps["ggx"] = "GGX"; capitalize_string_remaps["gi"] = "GI"; + capitalize_string_remaps["gl"] = "GL"; capitalize_string_remaps["glb"] = "GLB"; capitalize_string_remaps["gles2"] = "GLES2"; capitalize_string_remaps["gles3"] = "GLES3"; @@ -157,6 +162,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["html"] = "HTML"; capitalize_string_remaps["http"] = "HTTP"; capitalize_string_remaps["id"] = "ID"; + capitalize_string_remaps["ids"] = "IDs"; capitalize_string_remaps["igd"] = "IGD"; capitalize_string_remaps["ik"] = "IK"; capitalize_string_remaps["image@2x"] = "Image @2x"; @@ -223,6 +229,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["svg"] = "SVG"; capitalize_string_remaps["taa"] = "TAA"; capitalize_string_remaps["tcp"] = "TCP"; + capitalize_string_remaps["tls"] = "TLS"; capitalize_string_remaps["ui"] = "UI"; capitalize_string_remaps["url"] = "URL"; capitalize_string_remaps["urls"] = "URLs"; @@ -237,6 +244,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["vector2"] = "Vector2"; capitalize_string_remaps["vpn"] = "VPN"; capitalize_string_remaps["vram"] = "VRAM"; + capitalize_string_remaps["vrs"] = "VRS"; capitalize_string_remaps["vsync"] = "V-Sync"; capitalize_string_remaps["wap"] = "WAP"; capitalize_string_remaps["webp"] = "WebP"; @@ -246,9 +254,31 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["wifi"] = "Wi-Fi"; capitalize_string_remaps["x86"] = "x86"; capitalize_string_remaps["xr"] = "XR"; + capitalize_string_remaps["xray"] = "X-Ray"; capitalize_string_remaps["xy"] = "XY"; capitalize_string_remaps["xz"] = "XZ"; capitalize_string_remaps["yz"] = "YZ"; + + // Articles, conjunctions, prepositions. + stop_words = LocalVector<String>({ + "a", + "an", + "and", + "as", + "at", + "by", + "for", + "in", + "not", + "of", + "on", + "or", + "over", + "per", + "the", + "then", + "to", + }); } EditorPropertyNameProcessor::~EditorPropertyNameProcessor() { diff --git a/editor/editor_property_name_processor.h b/editor/editor_property_name_processor.h index 37d905c806..fcabbfd9d3 100644 --- a/editor/editor_property_name_processor.h +++ b/editor/editor_property_name_processor.h @@ -40,6 +40,7 @@ class EditorPropertyNameProcessor : public Node { mutable HashMap<String, String> capitalize_string_cache; HashMap<String, String> capitalize_string_remaps; + LocalVector<String> stop_words; // Exceptions that shouldn't be capitalized. // Capitalizes property path segments. String _capitalize_name(const String &p_name) const; diff --git a/editor/editor_quick_open.cpp b/editor/editor_quick_open.cpp index 50429878f9..bb533b88d6 100644 --- a/editor/editor_quick_open.cpp +++ b/editor/editor_quick_open.cpp @@ -32,12 +32,20 @@ #include "core/os/keyboard.h" #include "editor/editor_node.h" +#include "editor/editor_scale.h" void EditorQuickOpen::popup_dialog(const String &p_base, bool p_enable_multi, bool p_dontclear) { base_type = p_base; allow_multi_select = p_enable_multi; search_options->set_select_mode(allow_multi_select ? Tree::SELECT_MULTI : Tree::SELECT_SINGLE); - popup_centered_clamped(Size2i(600, 440), 0.8f); + + static bool was_showed = false; + if (!was_showed) { + was_showed = true; + popup_centered_clamped(Size2(600, 440) * EDSCALE, 0.8f); + } else { + show(); + } EditorFileSystemDirectory *efsd = EditorFileSystem::get_singleton()->get_filesystem(); _build_search_cache(efsd); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 20a9826edb..acc8b3b6a2 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -438,7 +438,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { } if (!obj) { - obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource"); + obj = EditorNode::get_editor_data().instantiate_custom_type(intype, "Resource"); } Resource *resp = Object::cast_to<Resource>(obj); diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index ae47bbe864..5c8ef89ac9 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -312,7 +312,9 @@ void SectionedInspector::_search_changed(const String &p_what) { void SectionedInspector::_notification(int p_what) { switch (p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - inspector->set_property_name_style(EditorPropertyNameProcessor::get_settings_style()); + if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/localize_settings")) { + inspector->set_property_name_style(EditorPropertyNameProcessor::get_settings_style()); + } } break; } } diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index 77a0d9f85c..b1b54fd717 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -152,7 +152,9 @@ void EditorSettingsDialog::_notification(int p_what) { _update_shortcuts(); } - inspector->update_category_list(); + if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/localize_settings")) { + inspector->update_category_list(); + } } break; } } diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 692deb3beb..df28b2e6ab 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -240,7 +240,8 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, float p_scale, float // with integer editor scales. const bool upsample = !Math::is_equal_approx(Math::round(p_scale), p_scale); ImageLoaderSVG img_loader; - img_loader.create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_colors); + Error err = img_loader.create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_colors); + ERR_FAIL_COND_V_MSG(err != OK, Ref<ImageTexture>(), "Failed generating icon, unsupported or invalid SVG data in editor theme."); if (p_saturation != 1.0) { img->adjust_bcs(1.0, 1.0, p_saturation); } diff --git a/editor/event_listener_line_edit.cpp b/editor/event_listener_line_edit.cpp index e4c35a5b81..1b081f9091 100644 --- a/editor/event_listener_line_edit.cpp +++ b/editor/event_listener_line_edit.cpp @@ -30,6 +30,72 @@ #include "editor/event_listener_line_edit.h" +#include "core/input/input_map.h" + +// Maps to 2*axis if value is neg, or 2*axis+1 if value is pos. +static const char *_joy_axis_descriptions[(size_t)JoyAxis::MAX * 2] = { + TTRC("Left Stick Left, Joystick 0 Left"), + TTRC("Left Stick Right, Joystick 0 Right"), + TTRC("Left Stick Up, Joystick 0 Up"), + TTRC("Left Stick Down, Joystick 0 Down"), + TTRC("Right Stick Left, Joystick 1 Left"), + TTRC("Right Stick Right, Joystick 1 Right"), + TTRC("Right Stick Up, Joystick 1 Up"), + TTRC("Right Stick Down, Joystick 1 Down"), + TTRC("Joystick 2 Left"), + TTRC("Left Trigger, Sony L2, Xbox LT, Joystick 2 Right"), + TTRC("Joystick 2 Up"), + TTRC("Right Trigger, Sony R2, Xbox RT, Joystick 2 Down"), + TTRC("Joystick 3 Left"), + TTRC("Joystick 3 Right"), + TTRC("Joystick 3 Up"), + TTRC("Joystick 3 Down"), + TTRC("Joystick 4 Left"), + TTRC("Joystick 4 Right"), + TTRC("Joystick 4 Up"), + TTRC("Joystick 4 Down"), +}; + +String EventListenerLineEdit::get_event_text(const Ref<InputEvent> &p_event, bool p_include_device) { + ERR_FAIL_COND_V_MSG(p_event.is_null(), String(), "Provided event is not a valid instance of InputEvent"); + + String text = p_event->as_text(); + + Ref<InputEventKey> key = p_event; + if (key.is_valid() && key->is_command_or_control_autoremap()) { +#ifdef MACOS_ENABLED + text = text.replace("Command", "Command/Ctrl"); +#else + text = text.replace("Ctrl", "Command/Ctrl"); +#endif + } + Ref<InputEventMouse> mouse = p_event; + Ref<InputEventJoypadMotion> jp_motion = p_event; + Ref<InputEventJoypadButton> jp_button = p_event; + if (jp_motion.is_valid()) { + // Joypad motion events will display slightly differently than what the event->as_text() provides. See #43660. + String desc = TTR("Unknown Joypad Axis"); + if (jp_motion->get_axis() < JoyAxis::MAX) { + desc = RTR(_joy_axis_descriptions[2 * (size_t)jp_motion->get_axis() + (jp_motion->get_axis_value() < 0 ? 0 : 1)]); + } + + text = vformat("Joypad Axis %s %s (%s)", itos((int64_t)jp_motion->get_axis()), jp_motion->get_axis_value() < 0 ? "-" : "+", desc); + } + if (p_include_device && (mouse.is_valid() || jp_button.is_valid() || jp_motion.is_valid())) { + String device_string = get_device_string(p_event->get_device()); + text += vformat(" - %s", device_string); + } + + return text; +} + +String EventListenerLineEdit::get_device_string(int p_device) { + if (p_device == InputMap::ALL_DEVICES) { + return TTR("All Devices"); + } + return TTR("Device") + " " + itos(p_device); +} + bool EventListenerLineEdit::_is_event_allowed(const Ref<InputEvent> &p_event) const { const Ref<InputEventMouseButton> mb = p_event; const Ref<InputEventKey> k = p_event; @@ -71,7 +137,7 @@ void EventListenerLineEdit::gui_input(const Ref<InputEvent> &p_event) { } event = p_event; - set_text(event->as_text()); + set_text(get_event_text(event, false)); emit_signal("event_changed", event); } diff --git a/editor/event_listener_line_edit.h b/editor/event_listener_line_edit.h index c4cd5e4511..487efbc368 100644 --- a/editor/event_listener_line_edit.h +++ b/editor/event_listener_line_edit.h @@ -61,6 +61,9 @@ protected: static void _bind_methods(); public: + static String get_event_text(const Ref<InputEvent> &p_event, bool p_include_device); + static String get_device_string(int p_device); + Ref<InputEvent> get_event() const; void clear_event(); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index bda5dd68c4..8df5808b11 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1852,8 +1852,8 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected } } break; - case FILE_INSTANCE: { - // Instance all selected scenes. + case FILE_INSTANTIATE: { + // Instantiate all selected scenes. Vector<String> paths; for (int i = 0; i < p_selected.size(); i++) { String fpath = p_selected[i]; @@ -1862,7 +1862,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected } } if (!paths.is_empty()) { - emit_signal(SNAME("instance"), paths); + emit_signal(SNAME("instantiate"), paths); } } break; @@ -2077,7 +2077,7 @@ void FileSystemDock::_resource_created() { return; } - Variant c = new_resource_dialog->instance_selected(); + Variant c = new_resource_dialog->instantiate_selected(); ERR_FAIL_COND(!c); Resource *r = Object::cast_to<Resource>(c); @@ -2540,7 +2540,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str } else { p_popup->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Open Scenes"), FILE_OPEN); } - p_popup->add_icon_item(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), TTR("Instance"), FILE_INSTANCE); + p_popup->add_icon_item(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), TTR("Instantiate"), FILE_INSTANTIATE); p_popup->add_separator(); } else if (filenames.size() == 1) { p_popup->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Open"), FILE_OPEN); @@ -2994,7 +2994,7 @@ void FileSystemDock::_file_sort_popup(int p_id) { MenuButton *FileSystemDock::_create_file_menu_button() { MenuButton *button = memnew(MenuButton); button->set_flat(true); - button->set_tooltip_text(TTR("Sort files")); + button->set_tooltip_text(TTR("Sort Files")); PopupMenu *p = button->get_popup(); p->connect("id_pressed", callable_mp(this, &FileSystemDock::_file_sort_popup)); @@ -3023,7 +3023,7 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock); ADD_SIGNAL(MethodInfo("inherit", PropertyInfo(Variant::STRING, "file"))); - ADD_SIGNAL(MethodInfo("instance", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"))); + ADD_SIGNAL(MethodInfo("instantiate", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"))); ADD_SIGNAL(MethodInfo("file_removed", PropertyInfo(Variant::STRING, "file"))); ADD_SIGNAL(MethodInfo("folder_removed", PropertyInfo(Variant::STRING, "folder"))); @@ -3057,14 +3057,14 @@ FileSystemDock::FileSystemDock() { button_hist_prev->set_flat(true); button_hist_prev->set_disabled(true); button_hist_prev->set_focus_mode(FOCUS_NONE); - button_hist_prev->set_tooltip_text(TTR("Previous Folder/File")); + button_hist_prev->set_tooltip_text(TTR("Go to previous selected folder/file.")); toolbar_hbc->add_child(button_hist_prev); button_hist_next = memnew(Button); button_hist_next->set_flat(true); button_hist_next->set_disabled(true); button_hist_next->set_focus_mode(FOCUS_NONE); - button_hist_next->set_tooltip_text(TTR("Next Folder/File")); + button_hist_next->set_tooltip_text(TTR("Go to next selected folder/file.")); toolbar_hbc->add_child(button_hist_next); current_path = memnew(LineEdit); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index ebb6f1e2a0..c4ce500c1e 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -79,7 +79,7 @@ private: FILE_OPEN, FILE_INHERIT, FILE_MAIN_SCENE, - FILE_INSTANCE, + FILE_INSTANTIATE, FILE_ADD_FAVORITE, FILE_REMOVE_FAVORITE, FILE_DEPENDENCIES, diff --git a/editor/icons/ArrowDown.svg b/editor/icons/ArrowDown.svg index d24357d2c5..f17c1bede7 100644 --- a/editor/icons/ArrowDown.svg +++ b/editor/icons/ArrowDown.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3.002a1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l2.293 2.293h-4.5859c-.55228 0-1 .4477-1 1s.44772 1 1 1h4.5859l-2.293 2.293a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l4-4a1.0001 1.0001 0 0 0 0-1.4141l-4-4a1 1 0 0 0 -.7207-.29102z" fill="#e0e0e0" fill-opacity=".99608" transform="matrix(0 1 -1 0 16.0021 -.00004)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3.002a1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l2.293 2.293h-4.5859c-.55228 0-1 .4477-1 1s.44772 1 1 1h4.5859l-2.293 2.293a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l4-4a1.0001 1.0001 0 0 0 0-1.4141l-4-4a1 1 0 0 0 -.7207-.29102z" fill="#e0e0e0" transform="matrix(0 1 -1 0 16.0021 -.00004)"/></svg> diff --git a/editor/icons/ArrowLeft.svg b/editor/icons/ArrowLeft.svg index ddd2f4e353..1a923cb6db 100644 --- a/editor/icons/ArrowLeft.svg +++ b/editor/icons/ArrowLeft.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9863 3.002a1 1 0 0 0 -.69336.29102l-4 4a1.0001 1.0001 0 0 0 0 1.4141l4 4a1 1 0 0 0 1.4141 0 1 1 0 0 0 0-1.4141l-2.293-2.293h4.5859a1 1 0 0 0 1-1 1 1 0 0 0 -1-1h-4.5859l2.293-2.293a1 1 0 0 0 0-1.4141 1 1 0 0 0 -.7207-.29102z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9863 3.002a1 1 0 0 0 -.69336.29102l-4 4a1.0001 1.0001 0 0 0 0 1.4141l4 4a1 1 0 0 0 1.4141 0 1 1 0 0 0 0-1.4141l-2.293-2.293h4.5859a1 1 0 0 0 1-1 1 1 0 0 0 -1-1h-4.5859l2.293-2.293a1 1 0 0 0 0-1.4141 1 1 0 0 0 -.7207-.29102z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/ArrowRight.svg b/editor/icons/ArrowRight.svg index a0c78dc1eb..da706c17ba 100644 --- a/editor/icons/ArrowRight.svg +++ b/editor/icons/ArrowRight.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3.002a1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l2.293 2.293h-4.5859c-.55228 0-1 .4477-1 1s.44772 1 1 1h4.5859l-2.293 2.293a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l4-4a1.0001 1.0001 0 0 0 0-1.4141l-4-4a1 1 0 0 0 -.7207-.29102z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3.002a1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l2.293 2.293h-4.5859c-.55228 0-1 .4477-1 1s.44772 1 1 1h4.5859l-2.293 2.293a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l4-4a1.0001 1.0001 0 0 0 0-1.4141l-4-4a1 1 0 0 0 -.7207-.29102z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/ArrowUp.svg b/editor/icons/ArrowUp.svg index f71f95c7b1..1381fea1b4 100644 --- a/editor/icons/ArrowUp.svg +++ b/editor/icons/ArrowUp.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8.00008 1049.4022a1 1 0 0 0 .69336-.291 1 1 0 0 0 0-1.4141l-2.293-2.293h4.5859c.55228 0 1-.4477 1-1s-.44772-1-1-1h-4.5859l2.293-2.293a1 1 0 0 0 0-1.4141 1 1 0 0 0 -1.4141 0l-4 4a1.0001 1.0001 0 0 0 0 1.4141l4 4a1 1 0 0 0 .7207.291z" fill="#e0e0e0" fill-opacity=".99608" transform="matrix(0 1 -1 0 1052.4021 -.00004)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8.00008 1049.4022a1 1 0 0 0 .69336-.291 1 1 0 0 0 0-1.4141l-2.293-2.293h4.5859c.55228 0 1-.4477 1-1s-.44772-1-1-1h-4.5859l2.293-2.293a1 1 0 0 0 0-1.4141 1 1 0 0 0 -1.4141 0l-4 4a1.0001 1.0001 0 0 0 0 1.4141l4 4a1 1 0 0 0 .7207.291z" fill="#e0e0e0" transform="matrix(0 1 -1 0 1052.4021 -.00004)"/></svg> diff --git a/editor/icons/AutoKey.svg b/editor/icons/AutoKey.svg index acc6665baf..877b00722f 100644 --- a/editor/icons/AutoKey.svg +++ b/editor/icons/AutoKey.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><circle cx="8" cy="5" r="4"/><path d="m11 13c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1 .00001-.55228.44772-.99999 1-1h1v-2h-1c-1.6569 0-3 1.3431-3 3z" fill-opacity=".99608"/><path d="m4 10c-1.6569 0-3 1.3431-3 3v3h2v-3c.0000096-.5523.44772-1 1-1h1v-2z" fill-opacity=".99608"/><path d="m8 10c-3 0-3 3-3 3s0 3 3 3h1v-2h-1s-1 0-1-1h3 1s0-3-3-3zm-1 1h2v1h-2z"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><circle cx="8" cy="5" r="4"/><path d="m11 13c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1 .00001-.55228.44772-.99999 1-1h1v-2h-1c-1.6569 0-3 1.3431-3 3z"/><path d="m4 10c-1.6569 0-3 1.3431-3 3v3h2v-3c.0000096-.5523.44772-1 1-1h1v-2z"/><path d="m8 10c-3 0-3 3-3 3s0 3 3 3h1v-2h-1s-1 0-1-1h3 1s0-3-3-3zm-1 1h2v1h-2z"/></g></svg> diff --git a/editor/icons/Blend.svg b/editor/icons/Blend.svg index 4de2fa5a43..e692fc1c30 100644 --- a/editor/icons/Blend.svg +++ b/editor/icons/Blend.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1v2h2.5859l-3.5859 3.5859-4.293-4.293-1.4141 1.4141 4.293 4.293-4.293 4.293 1.4141 1.4141 4.293-4.293 3.5859 3.5859h-2.5859v2h5a1.0001 1.0001 0 0 0 1-1v-5h-2v2.5859l-3.5859-3.5859 3.5859-3.5859v2.5859h2v-5a1.0001 1.0001 0 0 0 -1-1h-5z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1v2h2.5859l-3.5859 3.5859-4.293-4.293-1.4141 1.4141 4.293 4.293-4.293 4.293 1.4141 1.4141 4.293-4.293 3.5859 3.5859h-2.5859v2h5a1.0001 1.0001 0 0 0 1-1v-5h-2v2.5859l-3.5859-3.5859 3.5859-3.5859v2.5859h2v-5a1.0001 1.0001 0 0 0 -1-1h-5z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/Bone.svg b/editor/icons/Bone.svg index cbfa4794ed..f86b981619 100644 --- a/editor/icons/Bone.svg +++ b/editor/icons/Bone.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.478 1037.4a2.4664 2.4663 0 0 0 -1.7804.7205 2.4664 2.4663 0 0 0 -.31408 3.1041l-3.559 3.5608a2.4664 2.4663 0 0 0 -3.1023.3121 2.4664 2.4663 0 0 0 0 3.4876 2.4664 2.4663 0 0 0 1.397.6955 2.4664 2.4663 0 0 0 .69561 1.397 2.4664 2.4663 0 0 0 3.4877 0 2.4664 2.4663 0 0 0 .31408-3.1041l3.5609-3.5608a2.4664 2.4663 0 0 0 3.1004-.3102 2.4664 2.4663 0 0 0 0-3.4875 2.4664 2.4663 0 0 0 -1.397-.6974 2.4664 2.4663 0 0 0 -.69561-1.3971 2.4664 2.4663 0 0 0 -1.7072-.7205z" fill="#e0e0e0" fill-opacity=".99608" transform="translate(0 -1036.4)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.478 1037.4a2.4664 2.4663 0 0 0 -1.7804.7205 2.4664 2.4663 0 0 0 -.31408 3.1041l-3.559 3.5608a2.4664 2.4663 0 0 0 -3.1023.3121 2.4664 2.4663 0 0 0 0 3.4876 2.4664 2.4663 0 0 0 1.397.6955 2.4664 2.4663 0 0 0 .69561 1.397 2.4664 2.4663 0 0 0 3.4877 0 2.4664 2.4663 0 0 0 .31408-3.1041l3.5609-3.5608a2.4664 2.4663 0 0 0 3.1004-.3102 2.4664 2.4663 0 0 0 0-3.4875 2.4664 2.4663 0 0 0 -1.397-.6974 2.4664 2.4663 0 0 0 -.69561-1.3971 2.4664 2.4663 0 0 0 -1.7072-.7205z" fill="#e0e0e0" transform="translate(0 -1036.4)"/></svg> diff --git a/editor/icons/CPUParticles3D.svg b/editor/icons/CPUParticles3D.svg index d7ced5fc6b..5001375f80 100644 --- a/editor/icons/CPUParticles3D.svg +++ b/editor/icons/CPUParticles3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4.5587261.60940813c-.4226244 0-.7617187.3410473-.7617187.76367177v.5078126c0 .1028478.020058.199689.056641.2890624h-1.1933597c-.4226245 0-.7617188.3390944-.7617188.7617188v.921875c-.040428-.00657-.0767989-.0234375-.1191406-.0234375h-.5078125c-.42262448 0-.76367188.3410475-.76367188.7636719v.3730468c0 .4226245.3410474.7617188.76367188.7617188h.5078125c.042396 0 .078663-.016851.1191406-.023437v4.4531248c-.040428-.0066-.076799-.02344-.1191406-.02344h-.5078125c-.42262448 0-.76367188.341047-.76367188.763672v.373047c0 .422625.3410474.761718.76367188.761718h.5078125c.042396 0 .078663-.01685.1191406-.02344v1.125c0 .422624.3390944.763672.7617188.763672h1.1367187v.457031c0 .422624.3390943.763672.7617187.763672h.3730469c.4226244 0 .7636719-.341048.7636719-.763672v-.457031h4.4062501v.457031c0 .422624.339094.763672.761719.763672h.373047c.422624 0 .763671-.341048.763671-.763672v-.457031h1.269532c.422625 0 .763672-.341048.763672-.763672v-1.111328c.01774.0012.03272.0098.05078.0098h.507812c.422624 0 .763672-.339093.763672-.761718v-.373047c0-.422624-.341048-.763672-.763672-.763672h-.507812c-.01803 0-.03307.0085-.05078.0098v-4.4258454c.01774.00122.03272.00977.05078.00977h.507812c.422624 0 .763672-.3390943.763672-.7617188v-.3730512c0-.4226244-.341048-.7636719-.763672-.7636719h-.507812c-.01803 0-.03307.00855-.05078.00977v-.9082075c0-.4226244-.341047-.7617187-.763672-.7617188h-1.328125c.03658-.089375.05859-.1862118.05859-.2890624v-.5078126c0-.42262437-.341047-.76367177-.763671-.76367177h-.373047c-.422625 0-.761719.3410474-.761719.76367177v.5078126c0 .1028478.02006.1996891.05664.2890624h-4.5214809c.036585-.0893749.0585938-.1862118.0585938-.2890624v-.5078126c0-.42262437-.3410475-.76367177-.7636719-.76367177zm3.2382813 2.35742177a3.279661 3.6440678 0 0 1 3.2128906 2.9394532 2.1864407 2.1864407 0 0 1 1.888672 2.1621094 2.1864407 2.1864407 0 0 1 -2.1875 2.1855475h-5.8300782a2.1864407 2.1864407 0 0 1 -2.1855469-2.1855475 2.1864407 2.1864407 0 0 1 1.8847656-2.1640626 3.279661 3.6440678 0 0 1 3.2167969-2.9375zm-2.9160156 8.0156251a.72881355.72881355 0 0 1 .7285156.728516.72881355.72881355 0 0 1 -.7285156.730469.72881355.72881355 0 0 1 -.7285157-.730469.72881355.72881355 0 0 1 .7285157-.728516zm5.8300782 0a.72881355.72881355 0 0 1 .730469.728516.72881355.72881355 0 0 1 -.730469.730469.72881355.72881355 0 0 1 -.7285157-.730469.72881355.72881355 0 0 1 .7285157-.728516zm-2.9140626.728516a.72881355.72881355 0 0 1 .7285156.730469.72881355.72881355 0 0 1 -.7285156.728515.72881355.72881355 0 0 1 -.7285156-.728515.72881355.72881355 0 0 1 .7285156-.730469z" fill="#fc7f7f" fill-opacity=".996078"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4.5587261.60940813c-.4226244 0-.7617187.3410473-.7617187.76367177v.5078126c0 .1028478.020058.199689.056641.2890624h-1.1933597c-.4226245 0-.7617188.3390944-.7617188.7617188v.921875c-.040428-.00657-.0767989-.0234375-.1191406-.0234375h-.5078125c-.42262448 0-.76367188.3410475-.76367188.7636719v.3730468c0 .4226245.3410474.7617188.76367188.7617188h.5078125c.042396 0 .078663-.016851.1191406-.023437v4.4531248c-.040428-.0066-.076799-.02344-.1191406-.02344h-.5078125c-.42262448 0-.76367188.341047-.76367188.763672v.373047c0 .422625.3410474.761718.76367188.761718h.5078125c.042396 0 .078663-.01685.1191406-.02344v1.125c0 .422624.3390944.763672.7617188.763672h1.1367187v.457031c0 .422624.3390943.763672.7617187.763672h.3730469c.4226244 0 .7636719-.341048.7636719-.763672v-.457031h4.4062501v.457031c0 .422624.339094.763672.761719.763672h.373047c.422624 0 .763671-.341048.763671-.763672v-.457031h1.269532c.422625 0 .763672-.341048.763672-.763672v-1.111328c.01774.0012.03272.0098.05078.0098h.507812c.422624 0 .763672-.339093.763672-.761718v-.373047c0-.422624-.341048-.763672-.763672-.763672h-.507812c-.01803 0-.03307.0085-.05078.0098v-4.4258454c.01774.00122.03272.00977.05078.00977h.507812c.422624 0 .763672-.3390943.763672-.7617188v-.3730512c0-.4226244-.341048-.7636719-.763672-.7636719h-.507812c-.01803 0-.03307.00855-.05078.00977v-.9082075c0-.4226244-.341047-.7617187-.763672-.7617188h-1.328125c.03658-.089375.05859-.1862118.05859-.2890624v-.5078126c0-.42262437-.341047-.76367177-.763671-.76367177h-.373047c-.422625 0-.761719.3410474-.761719.76367177v.5078126c0 .1028478.02006.1996891.05664.2890624h-4.5214809c.036585-.0893749.0585938-.1862118.0585938-.2890624v-.5078126c0-.42262437-.3410475-.76367177-.7636719-.76367177zm3.2382813 2.35742177a3.279661 3.6440678 0 0 1 3.2128906 2.9394532 2.1864407 2.1864407 0 0 1 1.888672 2.1621094 2.1864407 2.1864407 0 0 1 -2.1875 2.1855475h-5.8300782a2.1864407 2.1864407 0 0 1 -2.1855469-2.1855475 2.1864407 2.1864407 0 0 1 1.8847656-2.1640626 3.279661 3.6440678 0 0 1 3.2167969-2.9375zm-2.9160156 8.0156251a.72881355.72881355 0 0 1 .7285156.728516.72881355.72881355 0 0 1 -.7285156.730469.72881355.72881355 0 0 1 -.7285157-.730469.72881355.72881355 0 0 1 .7285157-.728516zm5.8300782 0a.72881355.72881355 0 0 1 .730469.728516.72881355.72881355 0 0 1 -.730469.730469.72881355.72881355 0 0 1 -.7285157-.730469.72881355.72881355 0 0 1 .7285157-.728516zm-2.9140626.728516a.72881355.72881355 0 0 1 .7285156.730469.72881355.72881355 0 0 1 -.7285156.728515.72881355.72881355 0 0 1 -.7285156-.728515.72881355.72881355 0 0 1 .7285156-.730469z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/CameraTexture.svg b/editor/icons/CameraTexture.svg index adb4762082..91e3fe9b41 100644 --- a/editor/icons/CameraTexture.svg +++ b/editor/icons/CameraTexture.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55228 0-1 .44772-1 1v12c0 .55228.44772 1 1 1h12c.55228 0 1-.44772 1-1v-12c0-.55228-.44772-1-1-1zm1 2h10v8h-10zm5.8184 1.0039c-.85534.0009758-1.5654.66069-1.6289 1.5137-.30036-.27229-.69029-.4234-1.0957-.42383-.90315 0-1.6367.73162-1.6367 1.6348.0009732.69217.43922 1.3103 1.0918 1.541v1.1855c0 .30198.24293.54492.54492.54492h3.2695c.30199 0 .54492-.24294.54492-.54492v-.54492l1.6367 1.0898v-3.2715l-1.6367 1.0918v-.96484c.34606-.30952.54406-.75251.54492-1.2168 0-.90315-.73162-1.6348-1.6348-1.6348z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55228 0-1 .44772-1 1v12c0 .55228.44772 1 1 1h12c.55228 0 1-.44772 1-1v-12c0-.55228-.44772-1-1-1zm1 2h10v8h-10zm5.8184 1.0039c-.85534.0009758-1.5654.66069-1.6289 1.5137-.30036-.27229-.69029-.4234-1.0957-.42383-.90315 0-1.6367.73162-1.6367 1.6348.0009732.69217.43922 1.3103 1.0918 1.541v1.1855c0 .30198.24293.54492.54492.54492h3.2695c.30199 0 .54492-.24294.54492-.54492v-.54492l1.6367 1.0898v-3.2715l-1.6367 1.0918v-.96484c.34606-.30952.54406-.75251.54492-1.2168 0-.90315-.73162-1.6348-1.6348-1.6348z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/CanvasItem.svg b/editor/icons/CanvasItem.svg index f396290436..0d9b47613a 100644 --- a/editor/icons/CanvasItem.svg +++ b/editor/icons/CanvasItem.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2.9208 1046.4c-.26373.3-.4204.7296-.4204 1.2383 0 1.6277-3.1381-.1781-.33757 2.6703.88382.899 2.6544.6701 3.5382-.2288.88384-.899.88382-2.3565 0-3.2554-1.1002-1.1191-2.2001-1.0845-2.7803-.4244zm2.3802-1.6103 2.4005 2.4416 6.8014-6.9177c.66286-.6742.66286-1.7673 0-2.4415-.66288-.6741-1.7376-.6741-2.4005 0z" fill="#e0e0e0" fill-opacity=".99608" transform="translate(0 -1036.4)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2.9208 1046.4c-.26373.3-.4204.7296-.4204 1.2383 0 1.6277-3.1381-.1781-.33757 2.6703.88382.899 2.6544.6701 3.5382-.2288.88384-.899.88382-2.3565 0-3.2554-1.1002-1.1191-2.2001-1.0845-2.7803-.4244zm2.3802-1.6103 2.4005 2.4416 6.8014-6.9177c.66286-.6742.66286-1.7673 0-2.4415-.66288-.6741-1.7376-.6741-2.4005 0z" fill="#e0e0e0" transform="translate(0 -1036.4)"/></svg> diff --git a/editor/icons/CanvasLayer.svg b/editor/icons/CanvasLayer.svg index 6e98fd1ba9..87295e6099 100644 --- a/editor/icons/CanvasLayer.svg +++ b/editor/icons/CanvasLayer.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2v6h1v-6a1 1 0 0 1 1-1h6v-1zm10.303 0c-.4344 0-.86973.16881-1.2012.50586l-6.8008 6.918 2.4004 2.4414 6.8008-6.918c.66286-.6742.66286-1.7672 0-2.4414-.33144-.33705-.76482-.50586-1.1992-.50586zm.69727 6v6a1 1 0 0 1 -1 1h-6v1h6a2 2 0 0 0 2-2v-6zm-9.8848 2.5781c-.48501-.048725-.90521.12503-1.1953.45508-.26373.3-.41992.72958-.41992 1.2383 0 1.6277-3.1385-.17848-.33789 2.6699.88382.899 2.6552.67038 3.5391-.22852.88384-.899.88382-2.357 0-3.2559-.55011-.55955-1.1009-.83018-1.5859-.87891z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2v6h1v-6a1 1 0 0 1 1-1h6v-1zm10.303 0c-.4344 0-.86973.16881-1.2012.50586l-6.8008 6.918 2.4004 2.4414 6.8008-6.918c.66286-.6742.66286-1.7672 0-2.4414-.33144-.33705-.76482-.50586-1.1992-.50586zm.69727 6v6a1 1 0 0 1 -1 1h-6v1h6a2 2 0 0 0 2-2v-6zm-9.8848 2.5781c-.48501-.048725-.90521.12503-1.1953.45508-.26373.3-.41992.72958-.41992 1.2383 0 1.6277-3.1385-.17848-.33789 2.6699.88382.899 2.6552.67038 3.5391-.22852.88384-.899.88382-2.357 0-3.2559-.55011-.55955-1.1009-.83018-1.5859-.87891z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/CharacterBody3D.svg b/editor/icons/CharacterBody3D.svg index d0def4f14a..21a642cacb 100644 --- a/editor/icons/CharacterBody3D.svg +++ b/editor/icons/CharacterBody3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1c-.55401 0-1 .44599-1 1v3c0 .55401.44599 1 1 1h1v.99023a1.0001 1.0001 0 0 0 -.31641.0625l-2.0508.68359-.68359-2.0508a1.0001 1.0001 0 0 0 -.99023-.69727 1.0001 1.0001 0 0 0 -.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656.63281l1.6836-.56055v.61133c0 .04088.018715.07566.023437.11523l-4.5781 3.0527a1.0001 1.0001 0 1 0 1.1094 1.6641l5.0566-3.3711 1.4941 2.9863a1.0001 1.0001 0 0 0 1.2109.50195l3-1a1.0001 1.0001 0 1 0 -.63281-1.8965l-2.1777.72461-.97461-1.9512c.2759-.17764.46875-.47227.46875-.82617v-1h1.3828l.72266 1.4473a1.0001 1.0001 0 1 0 1.7891-.89453l-1-2a1.0001 1.0001 0 0 0 -.89453-.55273h-3v-1h1c.55401 0 1-.44599 1-1v-3c0-.55401-.44599-1-1-1zm0 2h1v2h-1z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1c-.55401 0-1 .44599-1 1v3c0 .55401.44599 1 1 1h1v.99023a1.0001 1.0001 0 0 0 -.31641.0625l-2.0508.68359-.68359-2.0508a1.0001 1.0001 0 0 0 -.99023-.69727 1.0001 1.0001 0 0 0 -.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656.63281l1.6836-.56055v.61133c0 .04088.018715.07566.023437.11523l-4.5781 3.0527a1.0001 1.0001 0 1 0 1.1094 1.6641l5.0566-3.3711 1.4941 2.9863a1.0001 1.0001 0 0 0 1.2109.50195l3-1a1.0001 1.0001 0 1 0 -.63281-1.8965l-2.1777.72461-.97461-1.9512c.2759-.17764.46875-.47227.46875-.82617v-1h1.3828l.72266 1.4473a1.0001 1.0001 0 1 0 1.7891-.89453l-1-2a1.0001 1.0001 0 0 0 -.89453-.55273h-3v-1h1c.55401 0 1-.44599 1-1v-3c0-.55401-.44599-1-1-1zm0 2h1v2h-1z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/Clear.svg b/editor/icons/Clear.svg index 43c00311bc..577cacba22 100644 --- a/editor/icons/Clear.svg +++ b/editor/icons/Clear.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a1 1 0 0 0 -1 1v5h-2c-1.108 0-2 .892-2 2v1h10v-1c0-1.108-.892-2-2-2h-2v-5a1 1 0 0 0 -1-1zm-5 10v4l10-1v-3z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a1 1 0 0 0 -1 1v5h-2c-1.108 0-2 .892-2 2v1h10v-1c0-1.108-.892-2-2-2h-2v-5a1 1 0 0 0 -1-1zm-5 10v4l10-1v-3z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/CollisionPolygon3D.svg b/editor/icons/CollisionPolygon3D.svg index 57531fa9f4..121bd82685 100644 --- a/editor/icons/CollisionPolygon3D.svg +++ b/editor/icons/CollisionPolygon3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1050.4h-12v-12h12l-6 6z" fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-opacity=".99608" stroke-width="2" transform="translate(0 -1036.4)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1050.4h-12v-12h12l-6 6z" fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-width="2" transform="translate(0 -1036.4)"/></svg> diff --git a/editor/icons/CollisionShape3D.svg b/editor/icons/CollisionShape3D.svg index 7a8bbf8050..d7f8a308e6 100644 --- a/editor/icons/CollisionShape3D.svg +++ b/editor/icons/CollisionShape3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1050.4-6-3v-6l6-3 6 3v6z" fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-opacity=".99608" stroke-width="2" transform="translate(0 -1036.399988)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1050.4-6-3v-6l6-3 6 3v6z" fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-width="2" transform="translate(0 -1036.399988)"/></svg> diff --git a/editor/icons/CompressedTexture2D.svg b/editor/icons/CompressedTexture2D.svg index 068f65dead..54ff10b3c1 100644 --- a/editor/icons/CompressedTexture2D.svg +++ b/editor/icons/CompressedTexture2D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1 1 0 0 0 -1 1v12a1 1 0 0 0 1 1h6v-2h2v-2h-2-5v-8h5v-2zm6 2v2h2v-2zm2 0h2v-2h-2zm2 0v2h2v-2zm0 2h-2v2h2zm0 2v2h2v-2zm0 2h-2v2h2zm0 2v2h2v-2zm0 2h-2v2h2zm-2-4v-2h-2v-1h-1v1h-1v1h-1v1h-1v1h2 2v-1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1 1 0 0 0 -1 1v12a1 1 0 0 0 1 1h6v-2h2v-2h-2-5v-8h5v-2zm6 2v2h2v-2zm2 0h2v-2h-2zm2 0v2h2v-2zm0 2h-2v2h2zm0 2v2h2v-2zm0 2h-2v2h2zm0 2v2h2v-2zm0 2h-2v2h2zm-2-4v-2h-2v-1h-1v1h-1v1h-1v1h-1v1h2 2v-1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/CurveTexture.svg b/editor/icons/CurveTexture.svg index 761fb9a45b..f5a2eec195 100644 --- a/editor/icons/CurveTexture.svg +++ b/editor/icons/CurveTexture.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55228 0-1 .44772-1 1v9.1602c.32185-.10966.66-.16382 1-.16016.33117 0 .66575-.007902 1-.013672v-7.9863h10v1.1348c.29007-.10393.59442-.16256.90234-.17383.37315-.012796.74541.044169 1.0977.16797v-2.1289c0-.55228-.44772-1-1-1h-12zm7 4v1h-1v1h-2v1h-1v1h-1v1h2 2 .39062c1.1119-.56677 1.9678-1.4538 2.6094-3.4727v-.52734h-1v-1h-1zm4.9668.98828a1.0001 1.0001 0 0 0 -.92774.73828c-.92743 3.246-2.6356 4.6825-4.6523 5.4668-2.0168.7843-4.3867.80664-6.3867.80664a1.0001 1.0001 0 1 0 0 2c2 0 4.6301.023994 7.1133-.94141 2.4832-.9657 4.7751-3.0292 5.8477-6.7832a1.0001 1.0001 0 0 0 -.99414-1.2871z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55228 0-1 .44772-1 1v9.1602c.32185-.10966.66-.16382 1-.16016.33117 0 .66575-.007902 1-.013672v-7.9863h10v1.1348c.29007-.10393.59442-.16256.90234-.17383.37315-.012796.74541.044169 1.0977.16797v-2.1289c0-.55228-.44772-1-1-1h-12zm7 4v1h-1v1h-2v1h-1v1h-1v1h2 2 .39062c1.1119-.56677 1.9678-1.4538 2.6094-3.4727v-.52734h-1v-1h-1zm4.9668.98828a1.0001 1.0001 0 0 0 -.92774.73828c-.92743 3.246-2.6356 4.6825-4.6523 5.4668-2.0168.7843-4.3867.80664-6.3867.80664a1.0001 1.0001 0 1 0 0 2c2 0 4.6301.023994 7.1133-.94141 2.4832-.9657 4.7751-3.0292 5.8477-6.7832a1.0001 1.0001 0 0 0 -.99414-1.2871z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/DebugSkipBreakpointsOff.svg b/editor/icons/DebugSkipBreakpointsOff.svg index aef0d45a05..c0b6e8d188 100644 --- a/editor/icons/DebugSkipBreakpointsOff.svg +++ b/editor/icons/DebugSkipBreakpointsOff.svg @@ -1 +1,2 @@ -<svg height="17" viewBox="0 0 17 17" width="17" xmlns="http://www.w3.org/2000/svg"><path d="m4.8983252 3.006855a1.6192284 1.3289529 0 0 1 -.0000431.0097" stroke-width=".626319"/><path d="m8.796752 5.0553513a2.563139 3.6270869 0 0 1 -.0000683.02648" stroke-width=".626319"/><path d="m13.121337 4.512148a6.1594577 6.0545759 0 0 1 -.248787 8.20109 6.1594577 6.0545759 0 0 1 -8.3355404.427215 6.1594577 6.0545759 0 0 1 -1.1151058-8.1311866 6.1594577 6.0545759 0 0 1 8.1530832-1.7576713" fill="#fc7f7f" fill-opacity=".996078" stroke-width="1.019123"/></svg> +<svg height="17" width="17" xmlns="http://www.w3.org/2000/svg"><circle cx="8.5" cy="8.5" r="6" fill="#fc7f7f" stroke-width="1"/></svg> + diff --git a/editor/icons/DebugSkipBreakpointsOn.svg b/editor/icons/DebugSkipBreakpointsOn.svg index d8fbc6e43a..abea9579cf 100644 --- a/editor/icons/DebugSkipBreakpointsOn.svg +++ b/editor/icons/DebugSkipBreakpointsOn.svg @@ -1 +1,2 @@ -<svg height="17" viewBox="0 0 17 17" width="17" xmlns="http://www.w3.org/2000/svg"><path d="m4.8983252 3.006855a1.6192284 1.3289529 0 0 1 -.0000431.0097" stroke-width=".626319"/><path d="m8.796752 5.0553513a2.563139 3.6270869 0 0 1 -.0000683.02648" stroke-width=".626319"/><path d="m13.121337 4.512148a6.1594577 6.0545759 0 0 1 -.248787 8.20109 6.1594577 6.0545759 0 0 1 -8.3355404.427215 6.1594577 6.0545759 0 0 1 -1.1151058-8.1311866 6.1594577 6.0545759 0 0 1 8.1530832-1.7576713" fill="#fc7f7f" fill-opacity=".996078" stroke-width="1.019123"/><path d="m-9.290675 10.816157h18.575495v2.518711h-18.575495z" fill="#e0e0e0" stroke-width="1.187332" transform="matrix(.70605846 -.70815355 .70605846 .70815355 0 0)"/></svg> +<svg height="17" width="17" xmlns="http://www.w3.org/2000/svg"><circle cx="8.5" cy="8.5" r="6" fill="#fc7f7f" stroke-width="1"/><path d="M1.077 14.239 14.192 1.084l1.779 1.784L2.855 16.022z" fill="#e0e0e0"/></svg> + diff --git a/editor/icons/DirectionalLight3D.svg b/editor/icons/DirectionalLight3D.svg index ef25fd473a..a7c05452de 100644 --- a/editor/icons/DirectionalLight3D.svg +++ b/editor/icons/DirectionalLight3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v3h2v-3zm-2.5352 2.0508-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm7.0703 0-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm-3.5352 1.9492c-1.6569 0-3 1.3432-3 3s1.3431 3 3 3 3-1.3432 3-3-1.3431-3-3-3zm-7 2v2h3v-2zm11 0v2h3v-2zm-7.5352 3.1211-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm7.0703 0-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm-4.5352 1.8789v3h2v-3z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v3h2v-3zm-2.5352 2.0508-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm7.0703 0-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm-3.5352 1.9492c-1.6569 0-3 1.3432-3 3s1.3431 3 3 3 3-1.3432 3-3-1.3431-3-3-3zm-7 2v2h3v-2zm11 0v2h3v-2zm-7.5352 3.1211-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm7.0703 0-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm-4.5352 1.8789v3h2v-3z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/EditorPlugin.svg b/editor/icons/EditorPlugin.svg index 7008762fa8..8fab923c6d 100644 --- a/editor/icons/EditorPlugin.svg +++ b/editor/icons/EditorPlugin.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55226.0001-.99994.4477-1 1v8c.0000552.5523.44774.9999 1 1h3v.27148a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -1-1.7305v-.26953h3c.55226-.0001.99994-.4477 1-1v-3h.27148a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-.26953v-3c-.000055-.5523-.44774-.9999-1-1h-8z" fill="#e0e0e0" fill-opacity=".99608" fill-rule="evenodd"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55226.0001-.99994.4477-1 1v8c.0000552.5523.44774.9999 1 1h3v.27148a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -1-1.7305v-.26953h3c.55226-.0001.99994-.4477 1-1v-3h.27148a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-.26953v-3c-.000055-.5523-.44774-.9999-1-1h-8z" fill="#e0e0e0" fill-rule="evenodd"/></svg> diff --git a/editor/icons/Eraser.svg b/editor/icons/Eraser.svg index 4995fa863c..c9be2569ef 100644 --- a/editor/icons/Eraser.svg +++ b/editor/icons/Eraser.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.228155 1.5447161-9.60250173 9.6107429 1.41421353 1.414213 1.6134635 1.885612.00693-.0069 4.2288056.000024 7.4852811-7.4852817zm-4.4456043 7.2823178 2.3136653 2.5858141-1.0357479 1.035746h-2.5853592l-1.0209853-1.293133z" fill="#e0e0e0" fill-opacity=".996078" stroke-width="1.02405"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.228155 1.5447161-9.60250173 9.6107429 1.41421353 1.414213 1.6134635 1.885612.00693-.0069 4.2288056.000024 7.4852811-7.4852817zm-4.4456043 7.2823178 2.3136653 2.5858141-1.0357479 1.035746h-2.5853592l-1.0209853-1.293133z" fill="#e0e0e0" stroke-width="1.02405"/></svg> diff --git a/editor/icons/FogVolume.svg b/editor/icons/FogVolume.svg index b0a18eb29d..89ee466db4 100644 --- a/editor/icons/FogVolume.svg +++ b/editor/icons/FogVolume.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><g fill-opacity=".996078"><path d="m4.5 9.0000002c-.2761429-.0000014-.5000014.2238571-.5.5-.0000014.2761429.2238571.5000008.5.4999998l8-.0000002c.276143.0000012.500001-.2238569.5-.4999998.000001-.2761429-.223857-.5000014-.5-.5z"/><path d="m3.5 11c-.2761429-.000001-.5000014.223857-.5.5-.0000014.276143.2238571.500001.5.5h5c.2761429.000001.500001-.223857.5-.5.000001-.276143-.2238571-.500001-.5-.5z"/><path d="m5.5 13c-.2761424 0-.5.223858-.5.5s.2238576.5.5.5h5c.276142 0 .5-.223858.5-.5s-.223858-.5-.5-.5z"/></g><path d="m2.5 8s-1.5 0-1.5-1.5 2-1.5 2-1.5 0-4 3.5-4 3.5 3 3.5 3 1.260711-2 3-1 .5 3 .5 3 1.5 0 1.5 1-1 1-1 1z" fill-opacity=".99608"/><path d="m10.5 11c-.276143-.000001-.500001.223857-.5.5-.000001.276143.223857.500001.5.5h2.5c.276143.000001.500001-.223857.5-.5.000001-.276143-.223857-.500001-.5-.5z" fill-opacity=".996078"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><g><path d="m4.5 9.0000002c-.2761429-.0000014-.5000014.2238571-.5.5-.0000014.2761429.2238571.5000008.5.4999998l8-.0000002c.276143.0000012.500001-.2238569.5-.4999998.000001-.2761429-.223857-.5000014-.5-.5z"/><path d="m3.5 11c-.2761429-.000001-.5000014.223857-.5.5-.0000014.276143.2238571.500001.5.5h5c.2761429.000001.500001-.223857.5-.5.000001-.276143-.2238571-.500001-.5-.5z"/><path d="m5.5 13c-.2761424 0-.5.223858-.5.5s.2238576.5.5.5h5c.276142 0 .5-.223858.5-.5s-.223858-.5-.5-.5z"/></g><path d="m2.5 8s-1.5 0-1.5-1.5 2-1.5 2-1.5 0-4 3.5-4 3.5 3 3.5 3 1.260711-2 3-1 .5 3 .5 3 1.5 0 1.5 1-1 1-1 1z"/><path d="m10.5 11c-.276143-.000001-.500001.223857-.5.5-.000001.276143.223857.500001.5.5h2.5c.276143.000001.500001-.223857.5-.5.000001-.276143-.223857-.500001-.5-.5z"/></g></svg> diff --git a/editor/icons/GPUParticles3D.svg b/editor/icons/GPUParticles3D.svg index bbc90ec35f..521a93efc6 100644 --- a/editor/icons/GPUParticles3D.svg +++ b/editor/icons/GPUParticles3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a4.5 5 0 0 0 -4.4141 4.0312 3 3 0 0 0 -2.5859 2.9688 3 3 0 0 0 3 3h8a3 3 0 0 0 3-3 3 3 0 0 0 -2.5898-2.9668 4.5 5 0 0 0 -4.4102-4.0332zm-4 11a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm8 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-4 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a4.5 5 0 0 0 -4.4141 4.0312 3 3 0 0 0 -2.5859 2.9688 3 3 0 0 0 3 3h8a3 3 0 0 0 3-3 3 3 0 0 0 -2.5898-2.9668 4.5 5 0 0 0 -4.4102-4.0332zm-4 11a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm8 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-4 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/GPUParticlesAttractorBox3D.svg b/editor/icons/GPUParticlesAttractorBox3D.svg index 7a2ee7a6b9..fdf65d11cb 100644 --- a/editor/icons/GPUParticlesAttractorBox3D.svg +++ b/editor/icons/GPUParticlesAttractorBox3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#fc7f7f" fill-opacity=".996078" r="1"/><g fill="none" stroke="#fc7f7f" stroke-opacity=".996078"><ellipse cx="8" cy="-8" rx="2.339226" ry="4.949748" transform="rotate(90)"/><ellipse cx="8" cy="8" rx="2.339226" ry="4.949748"/><path d="m1.498906 1.498906h13.002189v13.002188h-13.002189z" stroke-width=".997813"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#fc7f7f" r="1"/><g fill="none" stroke="#fc7f7f"><ellipse cx="8" cy="-8" rx="2.339226" ry="4.949748" transform="rotate(90)"/><ellipse cx="8" cy="8" rx="2.339226" ry="4.949748"/><path d="m1.498906 1.498906h13.002189v13.002188h-13.002189z" stroke-width=".997813"/></g></svg> diff --git a/editor/icons/GPUParticlesAttractorSphere3D.svg b/editor/icons/GPUParticlesAttractorSphere3D.svg index 2215331a18..15a8016827 100644 --- a/editor/icons/GPUParticlesAttractorSphere3D.svg +++ b/editor/icons/GPUParticlesAttractorSphere3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="-8" cy="-7.999999" fill="none" rx="6.499003" ry="6.499001" stroke="#fc7f7f" stroke-opacity=".996078" stroke-width="1.002" transform="scale(-1)"/><circle cx="8" cy="8" fill="#fc7f7f" fill-opacity=".996078" r="1"/><g fill="none" stroke="#fc7f7f" stroke-opacity=".996078"><ellipse cx="11.313708" rx="2.339226" ry="4.949748" transform="matrix(.70710678 .70710678 -.70710678 .70710678 0 0)"/><ellipse cy="11.313708" rx="2.339226" ry="4.949748" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 0)"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="-8" cy="-7.999999" fill="none" rx="6.499003" ry="6.499001" stroke="#fc7f7f" stroke-width="1.002" transform="scale(-1)"/><circle cx="8" cy="8" fill="#fc7f7f" r="1"/><g fill="none" stroke="#fc7f7f"><ellipse cx="11.313708" rx="2.339226" ry="4.949748" transform="matrix(.70710678 .70710678 -.70710678 .70710678 0 0)"/><ellipse cy="11.313708" rx="2.339226" ry="4.949748" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 0)"/></g></svg> diff --git a/editor/icons/GPUParticlesAttractorVectorField3D.svg b/editor/icons/GPUParticlesAttractorVectorField3D.svg index 87b2b21804..c9e0b4fae3 100644 --- a/editor/icons/GPUParticlesAttractorVectorField3D.svg +++ b/editor/icons/GPUParticlesAttractorVectorField3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="6.663637" cy="9.245457" fill="#fc7f7f" fill-opacity=".996078" rx="1.030661" ry=".998146"/><ellipse cx="-6.672815" cy="-9.387111" fill="none" rx="2.408711" ry="5.096776" stroke="#fc7f7f" stroke-opacity=".996078" stroke-width="1.0297" transform="matrix(-.99999945 .00104887 .00104887 -.99999945 0 0)"/><ellipse cx="9.387111" cy="-6.672815" fill="none" rx="2.408711" ry="5.096776" stroke="#fc7f7f" stroke-opacity=".996078" stroke-width="1.0297" transform="matrix(-.00104887 .99999945 -.99999945 .00104887 0 0)"/><g fill="#fc7f7f" fill-opacity=".996078"><path d="m11.8 15 2.4-2.4.8.8v-2.4h-2.4l.8.8-2.4 2.4z"/><path d="m11 6 3-3 1 1v-3h-3l1 1-3 3z"/><path d="m1.8 5 2.4-2.4.8.8v-2.4h-2.4l.8.8-2.4 2.4z"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="6.663637" cy="9.245457" fill="#fc7f7f" rx="1.030661" ry=".998146"/><ellipse cx="-6.672815" cy="-9.387111" fill="none" rx="2.408711" ry="5.096776" stroke="#fc7f7f" stroke-width="1.0297" transform="matrix(-.99999945 .00104887 .00104887 -.99999945 0 0)"/><ellipse cx="9.387111" cy="-6.672815" fill="none" rx="2.408711" ry="5.096776" stroke="#fc7f7f" stroke-width="1.0297" transform="matrix(-.00104887 .99999945 -.99999945 .00104887 0 0)"/><g fill="#fc7f7f"><path d="m11.8 15 2.4-2.4.8.8v-2.4h-2.4l.8.8-2.4 2.4z"/><path d="m11 6 3-3 1 1v-3h-3l1 1-3 3z"/><path d="m1.8 5 2.4-2.4.8.8v-2.4h-2.4l.8.8-2.4 2.4z"/></g></svg> diff --git a/editor/icons/GPUParticlesCollisionBox3D.svg b/editor/icons/GPUParticlesCollisionBox3D.svg index 4f7325d086..ca595f16eb 100644 --- a/editor/icons/GPUParticlesCollisionBox3D.svg +++ b/editor/icons/GPUParticlesCollisionBox3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f" fill-opacity=".996078"><path d="m7.5 2.8124998-5.5883107 2.7941554v5.7660988l5.5883107 2.794155 5.588311-2.794155v-5.7660988zm0 1.6886278 3.145021 1.5732692-3.145021 1.5717523-3.1450214-1.5717523zm-3.9916505 2.8362274 3.1933204 1.5966602v3.1465378l-3.1933204-1.598256zm7.9833015 0v3.145021l-3.1933209 1.598257v-3.146538z" stroke-width=".851579"/><circle cx="1.875" cy="3.75" r=".9375"/><circle cx="13.124999" cy="3.75" r=".9375"/><circle cx="9.374999" cy="1.875" r=".9375"/><circle cx="5.625" cy="1.875" r=".9375"/></g></svg> +<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><path d="m7.5 2.8124998-5.5883107 2.7941554v5.7660988l5.5883107 2.794155 5.588311-2.794155v-5.7660988zm0 1.6886278 3.145021 1.5732692-3.145021 1.5717523-3.1450214-1.5717523zm-3.9916505 2.8362274 3.1933204 1.5966602v3.1465378l-3.1933204-1.598256zm7.9833015 0v3.145021l-3.1933209 1.598257v-3.146538z" stroke-width=".851579"/><circle cx="1.875" cy="3.75" r=".9375"/><circle cx="13.124999" cy="3.75" r=".9375"/><circle cx="9.374999" cy="1.875" r=".9375"/><circle cx="5.625" cy="1.875" r=".9375"/></g></svg> diff --git a/editor/icons/GPUParticlesCollisionSDF3D.svg b/editor/icons/GPUParticlesCollisionSDF3D.svg index 00eca8295d..38fe6c49f8 100644 --- a/editor/icons/GPUParticlesCollisionSDF3D.svg +++ b/editor/icons/GPUParticlesCollisionSDF3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 14h-12v-9s3 4 5.9999999 3.9999999c3.0000001-.0000001 6.0000001-3.9999999 6.0000001-3.9999999z" fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-opacity=".996078" stroke-width="2"/><g fill="#fc7f7f" fill-opacity=".996078"><circle cx="2" cy="2" r="1"/><circle cx="14" cy="2" r="1"/><circle cx="10" cy="5" r="1"/><circle cx="6" cy="5" r="1"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 14h-12v-9s3 4 5.9999999 3.9999999c3.0000001-.0000001 6.0000001-3.9999999 6.0000001-3.9999999z" fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-width="2"/><g fill="#fc7f7f"><circle cx="2" cy="2" r="1"/><circle cx="14" cy="2" r="1"/><circle cx="10" cy="5" r="1"/><circle cx="6" cy="5" r="1"/></g></svg> diff --git a/editor/icons/GPUParticlesCollisionSphere3D.svg b/editor/icons/GPUParticlesCollisionSphere3D.svg index cd188ddacc..4aa3f7c5bf 100644 --- a/editor/icons/GPUParticlesCollisionSphere3D.svg +++ b/editor/icons/GPUParticlesCollisionSphere3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f" fill-opacity=".996078"><path d="m8 3.0532484c-3.2888554 0-5.9733758 2.6845204-5.9733758 5.9733758 0 3.2889408 2.6845204 5.9733758 5.9733758 5.9733758 3.288855 0 5.973376-2.684435 5.973376-5.9733758 0-3.2888554-2.684521-5.9733758-5.973376-5.9733758zm-.8533394 1.79005v4.1567016c-1.1034532-.0608789-2.2238878-.2544573-3.3650586-.5900074.256693-1.7901354 1.6087154-3.2141029 3.3650586-3.5667027zm1.7066788 0c1.7535276.3520281 3.1035956 1.77213 3.3633516 3.55834-1.113266.3129793-2.2321649.5142138-3.3633516.5866709zm3.2300606 5.3599956c-.434043 1.51792-1.663927 2.690664-3.2300606 3.005035v-2.518376c1.0915918-.0617 2.1691036-.227875 3.2300606-.486668zm-8.161765.015c1.0865571.272147 2.162106.428504 3.2250256.480003v2.510013c-1.5608431-.313338-2.7870065-1.479605-3.2250256-2.990016z" stroke-width=".853339"/><circle cx="2" cy="5" r="1"/><circle cx="14" cy="5" r="1"/><circle cx="10" cy="2" r="1"/><circle cx="6" cy="2" r="1"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><path d="m8 3.0532484c-3.2888554 0-5.9733758 2.6845204-5.9733758 5.9733758 0 3.2889408 2.6845204 5.9733758 5.9733758 5.9733758 3.288855 0 5.973376-2.684435 5.973376-5.9733758 0-3.2888554-2.684521-5.9733758-5.973376-5.9733758zm-.8533394 1.79005v4.1567016c-1.1034532-.0608789-2.2238878-.2544573-3.3650586-.5900074.256693-1.7901354 1.6087154-3.2141029 3.3650586-3.5667027zm1.7066788 0c1.7535276.3520281 3.1035956 1.77213 3.3633516 3.55834-1.113266.3129793-2.2321649.5142138-3.3633516.5866709zm3.2300606 5.3599956c-.434043 1.51792-1.663927 2.690664-3.2300606 3.005035v-2.518376c1.0915918-.0617 2.1691036-.227875 3.2300606-.486668zm-8.161765.015c1.0865571.272147 2.162106.428504 3.2250256.480003v2.510013c-1.5608431-.313338-2.7870065-1.479605-3.2250256-2.990016z" stroke-width=".853339"/><circle cx="2" cy="5" r="1"/><circle cx="14" cy="5" r="1"/><circle cx="10" cy="2" r="1"/><circle cx="6" cy="2" r="1"/></g></svg> diff --git a/editor/icons/GradientTexture1D.svg b/editor/icons/GradientTexture1D.svg index fa03e69805..9be4b00329 100644 --- a/editor/icons/GradientTexture1D.svg +++ b/editor/icons/GradientTexture1D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m12.5 10.5v-7h-3v1h-1v1h1v1h-1v1h1v1h-1v1h1v1zm-4-1h-1v1h1zm-1 0v-1h-1v1zm0-1h1v-1h-1zm0-1v-1h-1v1zm0-1h1v-1h-1zm0-1v-1h-1v1zm0-1h1v-1h-1z" stroke-width=".787342"/><path d="m2 1c-.552285 0-1 .4477153-1 1v12.000001c0 .552285.447715 1 1 1h11.999999c.552285 0 1-.447715 1-1v-12.000001c0-.5522847-.447715-1-1-1zm1 2.0000001h9.999999v8.0000009h-9.999999z" fill-opacity=".99608"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m12.5 10.5v-7h-3v1h-1v1h1v1h-1v1h1v1h-1v1h1v1zm-4-1h-1v1h1zm-1 0v-1h-1v1zm0-1h1v-1h-1zm0-1v-1h-1v1zm0-1h1v-1h-1zm0-1v-1h-1v1zm0-1h1v-1h-1z" stroke-width=".787342"/><path d="m2 1c-.552285 0-1 .4477153-1 1v12.000001c0 .552285.447715 1 1 1h11.999999c.552285 0 1-.447715 1-1v-12.000001c0-.5522847-.447715-1-1-1zm1 2.0000001h9.999999v8.0000009h-9.999999z"/></g></svg> diff --git a/editor/icons/GuiVisibilityHidden.svg b/editor/icons/GuiVisibilityHidden.svg index 6152fe8acf..1052d6dfcb 100644 --- a/editor/icons/GuiVisibilityHidden.svg +++ b/editor/icons/GuiVisibilityHidden.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2.9609 7.7266-1.9219.54883c.31999 1.12.8236 2.0593 1.4316 2.8398l-.83398.83398 1.4141 1.4141.84375-.84375c.98585.74762 2.0766 1.2067 3.1055 1.3867v1.0938h2v-1.0938c1.0288-.17998 2.1196-.6391 3.1055-1.3867l.84375.84375 1.4141-1.4141-.83398-.83398c.60804-.78055 1.1117-1.7199 1.4316-2.8398l-1.9219-.54883c-.8756 3.0646-3.5391 4.2734-5.0391 4.2734s-4.1635-1.2088-5.0391-4.2734z" fill="#e0e0e0" fill-opacity=".99608" fill-rule="evenodd"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2.9609 7.7266-1.9219.54883c.31999 1.12.8236 2.0593 1.4316 2.8398l-.83398.83398 1.4141 1.4141.84375-.84375c.98585.74762 2.0766 1.2067 3.1055 1.3867v1.0938h2v-1.0938c1.0288-.17998 2.1196-.6391 3.1055-1.3867l.84375.84375 1.4141-1.4141-.83398-.83398c.60804-.78055 1.1117-1.7199 1.4316-2.8398l-1.9219-.54883c-.8756 3.0646-3.5391 4.2734-5.0391 4.2734s-4.1635-1.2088-5.0391-4.2734z" fill="#e0e0e0" fill-rule="evenodd"/></svg> diff --git a/editor/icons/GuiVisibilityVisible.svg b/editor/icons/GuiVisibilityVisible.svg index 32eaea633b..96659eb655 100644 --- a/editor/icons/GuiVisibilityVisible.svg +++ b/editor/icons/GuiVisibilityVisible.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.00586.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0-.55273c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#e0e0e0" fill-opacity=".99608" fill-rule="evenodd"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.00586.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0-.55273c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#e0e0e0" fill-rule="evenodd"/></svg> diff --git a/editor/icons/GuiVisibilityXray.svg b/editor/icons/GuiVisibilityXray.svg index 109911df45..29ca9d0810 100644 --- a/editor/icons/GuiVisibilityXray.svg +++ b/editor/icons/GuiVisibilityXray.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-rule="evenodd"><path d="m7.9998 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.00586.5703c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0-.5527c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill-opacity=".39216"/><path d="m8 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.00586.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246v-2a4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2z" fill-opacity=".99608"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-rule="evenodd"><path d="m7.9998 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.00586.5703c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0-.5527c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill-opacity=".39216"/><path d="m8 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.00586.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246v-2a4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2z"/></g></svg> diff --git a/editor/icons/HTTPRequest.svg b/editor/icons/HTTPRequest.svg index 1a2187fe15..34912dcd2b 100644 --- a/editor/icons/HTTPRequest.svg +++ b/editor/icons/HTTPRequest.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 1-3 4h2v3h2v-3h2zm7 0v3h-2l3 4 3-4h-2v-3zm-10 9v2 1 2h1v-2h1v2h1v-5h-1v2h-1v-2zm4 0v1h1v4h1v-4h1v-1zm4 0v1h1v4h1v-4h1v-1zm4 0v2 1 2h1v-2h1 1v-1-2h-2zm1 1h1v1h-1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 1-3 4h2v3h2v-3h2zm7 0v3h-2l3 4 3-4h-2v-3zm-10 9v2 1 2h1v-2h1v2h1v-5h-1v2h-1v-2zm4 0v1h1v4h1v-4h1v-1zm4 0v1h1v4h1v-4h1v-1zm4 0v2 1 2h1v-2h1 1v-1-2h-2zm1 1h1v1h-1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/History.svg b/editor/icons/History.svg index 45bc565088..cb1bb4178f 100644 --- a/editor/icons/History.svg +++ b/editor/icons/History.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".99608" transform="translate(0 -1036.4)"><path d="m9 2a6 6 0 0 0 -6 6h2a4 4 0 0 1 4-4 4 4 0 0 1 4 4 4 4 0 0 1 -4 4v2a6 6 0 0 0 6-6 6 6 0 0 0 -6-6z" transform="translate(0 1036.4)"/><path d="m4.118 1048.3-1.6771-.9683-1.6771-.9682 1.6771-.9683 1.6771-.9682-.0000001 1.9365z" transform="matrix(0 -1.1926 1.5492 0 -1617 1049.3)"/><path d="m8 1041.4h2v4h-2z"/><path d="m8 1043.4h4v2h-4z"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 2a6 6 0 0 0 -6 6h2a4 4 0 0 1 4-4 4 4 0 0 1 4 4 4 4 0 0 1 -4 4v2a6 6 0 0 0 6-6 6 6 0 0 0 -6-6z" transform="translate(0 1036.4)"/><path d="m4.118 1048.3-1.6771-.9683-1.6771-.9682 1.6771-.9683 1.6771-.9682-.0000001 1.9365z" transform="matrix(0 -1.1926 1.5492 0 -1617 1049.3)"/><path d="m8 1041.4h2v4h-2z"/><path d="m8 1043.4h4v2h-4z"/></g></svg> diff --git a/editor/icons/Hsize.svg b/editor/icons/Hsize.svg index c7b62e58c8..cf805fce50 100644 --- a/editor/icons/Hsize.svg +++ b/editor/icons/Hsize.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 7v-2l-3 3 3 3v-2h8v2l3-3-3-3v2z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 7v-2l-3 3 3 3v-2h8v2l3-3-3-3v2z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/Image.svg b/editor/icons/Image.svg index ddf97ec59e..a990974a4f 100644 --- a/editor/icons/Image.svg +++ b/editor/icons/Image.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1 1 0 0 0 -1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-12a1 1 0 0 0 -1-1zm1 2h10v8h-10zm6 2-1.5 2.5-.70117 1.168-.099609-.16797-.89844-1.5-.90039 1.5-.90039 1.5h1.8008.19922 1.5996 1.4004 3l-1.5-2.5-1.5-2.5z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1 1 0 0 0 -1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-12a1 1 0 0 0 -1-1zm1 2h10v8h-10zm6 2-1.5 2.5-.70117 1.168-.099609-.16797-.89844-1.5-.90039 1.5-.90039 1.5h1.8008.19922 1.5996 1.4004 3l-1.5-2.5-1.5-2.5z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/ImageTexture.svg b/editor/icons/ImageTexture.svg index 013e847db3..25d4b53d00 100644 --- a/editor/icons/ImageTexture.svg +++ b/editor/icons/ImageTexture.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1 1 0 0 0 -1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-12a1 1 0 0 0 -1-1zm1 2h10v8h-10zm6 2v1h-1v1h-2v1h-1v1h-1v1h2 2 2 2v-2h-1v-2h-1v-1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1 1 0 0 0 -1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-12a1 1 0 0 0 -1-1zm1 2h10v8h-10zm6 2v1h-1v1h-2v1h-1v1h-1v1h2 2 2 2v-2h-1v-2h-1v-1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/JoyAxis.svg b/editor/icons/JoyAxis.svg index 1ab65f0af0..11c694aede 100644 --- a/editor/icons/JoyAxis.svg +++ b/editor/icons/JoyAxis.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m27 1038.4h7v14h-7z" fill="#fff" fill-opacity=".99608"/><g fill="#e0e0e0"><path d="m3 1a2 2 0 0 0 -2 2v10a2 2 0 0 0 2 2h12v-14zm4 2h2a1 1 0 0 1 1 1v2h2a1 1 0 0 1 1 1v2a1 1 0 0 1 -1 1h-2v2a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1-1v-2h-2a1 1 0 0 1 -1-1v-2a1 1 0 0 1 1-1h2v-2a1 1 0 0 1 1-1z" fill-opacity=".99608" transform="translate(0 1036.4)"/><circle cx="8" cy="1044.4" r="1"/></g></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m27 1038.4h7v14h-7z" fill="#fff"/><g fill="#e0e0e0"><path d="m3 1a2 2 0 0 0 -2 2v10a2 2 0 0 0 2 2h12v-14zm4 2h2a1 1 0 0 1 1 1v2h2a1 1 0 0 1 1 1v2a1 1 0 0 1 -1 1h-2v2a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1-1v-2h-2a1 1 0 0 1 -1-1v-2a1 1 0 0 1 1-1h2v-2a1 1 0 0 1 1-1z" transform="translate(0 1036.4)"/><circle cx="8" cy="1044.4" r="1"/></g></g></svg> diff --git a/editor/icons/JoyButton.svg b/editor/icons/JoyButton.svg index 080d91ad53..d3d6e22929 100644 --- a/editor/icons/JoyButton.svg +++ b/editor/icons/JoyButton.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill-opacity=".99608" transform="translate(0 -1036.4)"><path d="m27 1038.4h7v14h-7z" fill="#fff"/><path d="m1 1v14h12c1.1046 0 2-.8954 2-2v-10c0-1.1046-.89543-2-2-2zm7 1a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2zm-4 4a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2zm8 0a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2zm-4 4a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#e0e0e0" transform="translate(0 1036.4)"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m27 1038.4h7v14h-7z" fill="#fff"/><path d="m1 1v14h12c1.1046 0 2-.8954 2-2v-10c0-1.1046-.89543-2-2-2zm7 1a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2zm-4 4a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2zm8 0a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2zm-4 4a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#e0e0e0" transform="translate(0 1036.4)"/></g></svg> diff --git a/editor/icons/Joypad.svg b/editor/icons/Joypad.svg index 3c6bbf2980..ead745379b 100644 --- a/editor/icons/Joypad.svg +++ b/editor/icons/Joypad.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 3c-.55226.0000552-.99994.44774-1 1v8c.0000552.55226.44774.99994 1 1h14c.55226-.000055.99994-.44774 1-1v-8c-.000055-.55226-.44774-.99994-1-1zm2 2h2v2h2v2h-2v2h-2v-2h-2v-2h2zm10.5 0a1.5 1.5 0 0 1 1.5 1.5 1.5 1.5 0 0 1 -1.5 1.5 1.5 1.5 0 0 1 -1.5-1.5 1.5 1.5 0 0 1 1.5-1.5zm-3 3a1.5 1.5 0 0 1 1.5 1.5 1.5 1.5 0 0 1 -1.5 1.5 1.5 1.5 0 0 1 -1.5-1.5 1.5 1.5 0 0 1 1.5-1.5z" fill="#e0e0e0" fill-opacity=".99608" fill-rule="evenodd"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 3c-.55226.0000552-.99994.44774-1 1v8c.0000552.55226.44774.99994 1 1h14c.55226-.000055.99994-.44774 1-1v-8c-.000055-.55226-.44774-.99994-1-1zm2 2h2v2h2v2h-2v2h-2v-2h-2v-2h2zm10.5 0a1.5 1.5 0 0 1 1.5 1.5 1.5 1.5 0 0 1 -1.5 1.5 1.5 1.5 0 0 1 -1.5-1.5 1.5 1.5 0 0 1 1.5-1.5zm-3 3a1.5 1.5 0 0 1 1.5 1.5 1.5 1.5 0 0 1 -1.5 1.5 1.5 1.5 0 0 1 -1.5-1.5 1.5 1.5 0 0 1 1.5-1.5z" fill="#e0e0e0" fill-rule="evenodd"/></svg> diff --git a/editor/icons/Key.svg b/editor/icons/Key.svg index 544ebe5a47..01bf51dbd8 100644 --- a/editor/icons/Key.svg +++ b/editor/icons/Key.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11 4a4 4 0 0 0 -3.8691 3h-6.1309v2h1v2h3v-2h2.1328a4 4 0 0 0 3.8672 3 4 4 0 0 0 4-4 4 4 0 0 0 -4-4zm0 2a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11 4a4 4 0 0 0 -3.8691 3h-6.1309v2h1v2h3v-2h2.1328a4 4 0 0 0 3.8672 3 4 4 0 0 0 4-4 4 4 0 0 0 -4-4zm0 2a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/KeyNext.svg b/editor/icons/KeyNext.svg index 83a8329494..47387c875a 100644 --- a/editor/icons/KeyNext.svg +++ b/editor/icons/KeyNext.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#5fff97"/><path d="m11 1a4 4 0 0 0 -3.8691 3h-6.1309v2h1v2h3v-2h2.1328a4 4 0 0 0 2.8672 2.8691v-.86914h3.6387a4 4 0 0 0 1.3613-3 4 4 0 0 0 -4-4zm0 2a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#5fff97"/><path d="m11 1a4 4 0 0 0 -3.8691 3h-6.1309v2h1v2h3v-2h2.1328a4 4 0 0 0 2.8672 2.8691v-.86914h3.6387a4 4 0 0 0 1.3613-3 4 4 0 0 0 -4-4zm0 2a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/KeyPosition.svg b/editor/icons/KeyPosition.svg index 260a6f582f..c0fa703462 100644 --- a/editor/icons/KeyPosition.svg +++ b/editor/icons/KeyPosition.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-.195 0-.38964.07519-.53906.22461l-3.2363 3.2363c-.29884.29884-.29884.77929 0 1.0781l3.2363 3.2363c.29884.29884.77929.29884 1.0781 0l3.2363-3.2363c.29884-.29884.29884-.77929 0-1.0781l-3.2363-3.2363c-.14942-.14942-.34406-.22461-.53906-.22461zm-7 7v5c0 1.6569 1.3471 3.114 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1v-5zm7 2c-1.645 0-3 1.355-3 3s1.355 3 3 3 3-1.355 3-3-1.355-3-3-3zm3 3c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1 .00001-.55228.44772-.99999 1-1h1v-2h-1c-1.6569 0-3 1.3431-3 3zm-3-1c.56413 0 1 .4359 1 1 0 .5642-.43587 1-1 1s-1-.4358-1-1c0-.5641.43587-1 1-1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-.195 0-.38964.07519-.53906.22461l-3.2363 3.2363c-.29884.29884-.29884.77929 0 1.0781l3.2363 3.2363c.29884.29884.77929.29884 1.0781 0l3.2363-3.2363c.29884-.29884.29884-.77929 0-1.0781l-3.2363-3.2363c-.14942-.14942-.34406-.22461-.53906-.22461zm-7 7v5c0 1.6569 1.3471 3.114 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1v-5zm7 2c-1.645 0-3 1.355-3 3s1.355 3 3 3 3-1.355 3-3-1.355-3-3-3zm3 3c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1 .00001-.55228.44772-.99999 1-1h1v-2h-1c-1.6569 0-3 1.3431-3 3zm-3-1c.56413 0 1 .4359 1 1 0 .5642-.43587 1-1 1s-1-.4358-1-1c0-.5641.43587-1 1-1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/KeyRotation.svg b/editor/icons/KeyRotation.svg index 284a835467..391511df7c 100644 --- a/editor/icons/KeyRotation.svg +++ b/editor/icons/KeyRotation.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-.195 0-.38964.07519-.53906.22461l-3.2363 3.2363c-.29884.29884-.29884.77929 0 1.0781l3.2363 3.2363c.29884.29884.77929.29884 1.0781 0l3.2363-3.2363c.29884-.29884.29884-.77929 0-1.0781l-3.2363-3.2363c-.14942-.14942-.34406-.22461-.53906-.22461zm3 7v5c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228 0-.99999-.4477-1-1v-1h2v-2h-2v-2zm0 5c0-1.645-1.355-3-3-3s-3 1.355-3 3 1.355 3 3 3 3-1.355 3-3zm-7-3c-1.6569 0-3 1.3431-3 3v3h2v-3c.0000096-.5523.44772-1 1-1h1v-2zm4 2c.56413 0 1 .4359 1 1 0 .5642-.43587 1-1 1s-1-.4358-1-1c0-.5641.43587-1 1-1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-.195 0-.38964.07519-.53906.22461l-3.2363 3.2363c-.29884.29884-.29884.77929 0 1.0781l3.2363 3.2363c.29884.29884.77929.29884 1.0781 0l3.2363-3.2363c.29884-.29884.29884-.77929 0-1.0781l-3.2363-3.2363c-.14942-.14942-.34406-.22461-.53906-.22461zm3 7v5c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228 0-.99999-.4477-1-1v-1h2v-2h-2v-2zm0 5c0-1.645-1.355-3-3-3s-3 1.355-3 3 1.355 3 3 3 3-1.355 3-3zm-7-3c-1.6569 0-3 1.3431-3 3v3h2v-3c.0000096-.5523.44772-1 1-1h1v-2zm4 2c.56413 0 1 .4359 1 1 0 .5642-.43587 1-1 1s-1-.4358-1-1c0-.5641.43587-1 1-1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/KeyScale.svg b/editor/icons/KeyScale.svg index 84805191f2..5caf80e68e 100644 --- a/editor/icons/KeyScale.svg +++ b/editor/icons/KeyScale.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-.195 0-.38964.07519-.53906.22461l-3.2363 3.2363c-.29884.29884-.29884.77929 0 1.0781l3.2363 3.2363c.29884.29884.77929.29884 1.0781 0l3.2363-3.2363c.29884-.29884.29884-.77929 0-1.0781l-3.2363-3.2363c-.14942-.14942-.34406-.22461-.53906-.22461zm3 7v5c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1v-5zm-8 2c-.71466-.0001-1.3751.3811-1.7324 1-.35727.6188-.35727 1.3812 0 2 .35733.6189 1.0178 1.0001 1.7324 1h-2v2h2c.71466.0001 1.3751-.3811 1.7324-1 .35727-.6188.35727-1.3812 0-2-.35733-.6189-1.0178-1.0001-1.7324-1h2v-2zm6 0c-1.6569 0-3 1.3431-3 3s1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1 .0000096-.55228.44772-.99999 1-1h1v-2z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-.195 0-.38964.07519-.53906.22461l-3.2363 3.2363c-.29884.29884-.29884.77929 0 1.0781l3.2363 3.2363c.29884.29884.77929.29884 1.0781 0l3.2363-3.2363c.29884-.29884.29884-.77929 0-1.0781l-3.2363-3.2363c-.14942-.14942-.34406-.22461-.53906-.22461zm3 7v5c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1v-5zm-8 2c-.71466-.0001-1.3751.3811-1.7324 1-.35727.6188-.35727 1.3812 0 2 .35733.6189 1.0178 1.0001 1.7324 1h-2v2h2c.71466.0001 1.3751-.3811 1.7324-1 .35727-.6188.35727-1.3812 0-2-.35733-.6189-1.0178-1.0001-1.7324-1h2v-2zm6 0c-1.6569 0-3 1.3431-3 3s1.3431 3 3 3h1v-2h-1c-.55228-.00001-.99999-.44772-1-1 .0000096-.55228.44772-.99999 1-1h1v-2z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/LightmapProbe.svg b/editor/icons/LightmapProbe.svg index 07f2b41a7c..dc5d8321e7 100644 --- a/editor/icons/LightmapProbe.svg +++ b/editor/icons/LightmapProbe.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 9h3v-2h-3zm2.050781 2.535156 1.414063 1.414063 1.414062-1.414063-1.414062-1.414062zm0-7.070312 1.414063 1.414062 1.414062-1.414062-1.414062-1.414063zm1.949219 3.535156c0 1.6569 1.3432 3 3 3s3-1.3431 3-3-1.3432-3-3-3-3 1.3431-3 3zm3 7c3.865993 0 7-3.134007 7-7s-3.134007-7-7-7v2.333984c2.577329 0 4.666016 2.088687 4.666016 4.666016s-2.088687 4.666016-4.666016 4.666016z" fill="#fc7f7f" fill-opacity=".996078" stroke-width="1.16667"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 9h3v-2h-3zm2.050781 2.535156 1.414063 1.414063 1.414062-1.414063-1.414062-1.414062zm0-7.070312 1.414063 1.414062 1.414062-1.414062-1.414062-1.414063zm1.949219 3.535156c0 1.6569 1.3432 3 3 3s3-1.3431 3-3-1.3432-3-3-3-3 1.3431-3 3zm3 7c3.865993 0 7-3.134007 7-7s-3.134007-7-7-7v2.333984c2.577329 0 4.666016 2.088687 4.666016 4.666016s-2.088687 4.666016-4.666016 4.666016z" fill="#fc7f7f" stroke-width="1.16667"/></svg> diff --git a/editor/icons/ListSelect.svg b/editor/icons/ListSelect.svg index 9e2bf381d3..f1dac744d4 100644 --- a/editor/icons/ListSelect.svg +++ b/editor/icons/ListSelect.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h8.2578l-.82227-2h-5.4355v-2h4.6113l-.82227-2h-3.7891v-2h3.8867a1.5002 1.5002 0 0 1 1.0977-.49805v-.0019531a1.5002 1.5002 0 0 1 .58594.11133l.94531.38867h.48438v.19922l2 .82227v-7.0215h-11zm2 2h7v2h-7zm5 5 3.291 8 .94726-2.8203 1.8828 1.8828.94336-.94141-1.8848-1.8828 2.8203-.94726-8-3.291z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h8.2578l-.82227-2h-5.4355v-2h4.6113l-.82227-2h-3.7891v-2h3.8867a1.5002 1.5002 0 0 1 1.0977-.49805v-.0019531a1.5002 1.5002 0 0 1 .58594.11133l.94531.38867h.48438v.19922l2 .82227v-7.0215h-11zm2 2h7v2h-7zm5 5 3.291 8 .94726-2.8203 1.8828 1.8828.94336-.94141-1.8848-1.8828 2.8203-.94726-8-3.291z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/Loop.svg b/editor/icons/Loop.svg index 7fd8561bc4..9bbf168189 100644 --- a/editor/icons/Loop.svg +++ b/editor/icons/Loop.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1v2h-2a5 5 0 0 0 -5 5 5 5 0 0 0 1.0039 2.9961l1.4355-1.4355a3 3 0 0 1 -.43945-1.5605 3 3 0 0 1 3-3h2v2l2-1.5 2-1.5-2-1.5-2-1.5zm5.9961 4.0039-1.4355 1.4355a3 3 0 0 1 .43945 1.5605 3 3 0 0 1 -3 3h-2v-2l-2 1.5-2 1.5 2 1.5 2 1.5v-2h2a5 5 0 0 0 5-5 5 5 0 0 0 -1.0039-2.9961z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1v2h-2a5 5 0 0 0 -5 5 5 5 0 0 0 1.0039 2.9961l1.4355-1.4355a3 3 0 0 1 -.43945-1.5605 3 3 0 0 1 3-3h2v2l2-1.5 2-1.5-2-1.5-2-1.5zm5.9961 4.0039-1.4355 1.4355a3 3 0 0 1 .43945 1.5605 3 3 0 0 1 -3 3h-2v-2l-2 1.5-2 1.5 2 1.5 2 1.5v-2h2a5 5 0 0 0 5-5 5 5 0 0 0 -1.0039-2.9961z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/Marker3D.svg b/editor/icons/Marker3D.svg index 894b195589..bbc531cc3e 100644 --- a/editor/icons/Marker3D.svg +++ b/editor/icons/Marker3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v4h2v-4zm-6 6v2h4v-2zm10 0v2h4v-2zm-4 4v4h2v-4z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v4h2v-4zm-6 6v2h4v-2zm10 0v2h4v-2zm-4 4v4h2v-4z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/MeshInstance3D.svg b/editor/icons/MeshInstance3D.svg index a9258505f8..67757dafd2 100644 --- a/editor/icons/MeshInstance3D.svg +++ b/editor/icons/MeshInstance3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h6.541a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -1.0312-1.75h.03125v-6.5215a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm2.4141 3h5.8574a2 2 0 0 0 .72852.73047v5.8555l-6.5859-6.5859zm-1.4141 1.4141 6.5859 6.5859h-5.8574a2 2 0 0 0 -.72852-.73047v-5.8555z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h6.541a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -1.0312-1.75h.03125v-6.5215a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm2.4141 3h5.8574a2 2 0 0 0 .72852.73047v5.8555l-6.5859-6.5859zm-1.4141 1.4141 6.5859 6.5859h-5.8574a2 2 0 0 0 -.72852-.73047v-5.8555z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/MeshTexture.svg b/editor/icons/MeshTexture.svg index 988882c960..ccf16b828b 100644 --- a/editor/icons/MeshTexture.svg +++ b/editor/icons/MeshTexture.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h6.541c.35663.61771 1.0152.99874 1.7285 1 1.1046 0 2-.89543 2-2 .000101-.72747-.39481-1.3976-1.0312-1.75h.03125v-6.5215c.61771-.35663.99874-1.0152 1-1.7285 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1zm1.7266 3h.6875 5.168.68945c.17478.30301.42598.55488.72852.73047v.68359 5.1719.68555c-.30301.17478-.55488.42598-.73047.72852h-.68359-5.1719-.68555c-.17478-.30301-.42598-.55488-.72852-.73047v-.6875l-.0039062.003907v-5.8574c.30302-.17478.55488-.42598.73047-.72852zm4.0859 2.25v.70117h-.8125v.69922h-1.625v.69922h-.8125v.69922h-.8125v.70117h1.625 1.625 1.625 1.625v-1.4004h-.8125v-1.3984h-.8125v-.70117h-.8125z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h6.541c.35663.61771 1.0152.99874 1.7285 1 1.1046 0 2-.89543 2-2 .000101-.72747-.39481-1.3976-1.0312-1.75h.03125v-6.5215c.61771-.35663.99874-1.0152 1-1.7285 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1zm1.7266 3h.6875 5.168.68945c.17478.30301.42598.55488.72852.73047v.68359 5.1719.68555c-.30301.17478-.55488.42598-.73047.72852h-.68359-5.1719-.68555c-.17478-.30301-.42598-.55488-.72852-.73047v-.6875l-.0039062.003907v-5.8574c.30302-.17478.55488-.42598.73047-.72852zm4.0859 2.25v.70117h-.8125v.69922h-1.625v.69922h-.8125v.69922h-.8125v.70117h1.625 1.625 1.625 1.625v-1.4004h-.8125v-1.3984h-.8125v-.70117h-.8125z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/MirrorX.svg b/editor/icons/MirrorX.svg index fa668986ac..84c1da1b66 100644 --- a/editor/icons/MirrorX.svg +++ b/editor/icons/MirrorX.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#e0e0e0" stroke-opacity=".99608" stroke-width="2" transform="translate(0 -1036.4)"><path d="m4 1042.4-2 2 2 2" stroke-linecap="round" stroke-linejoin="round"/><path d="m2 1044.4h11"/><path d="m12 1042.4 2 2-2 2" stroke-linecap="round" stroke-linejoin="round"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#e0e0e0" stroke-width="2" transform="translate(0 -1036.4)"><path d="m4 1042.4-2 2 2 2" stroke-linecap="round" stroke-linejoin="round"/><path d="m2 1044.4h11"/><path d="m12 1042.4 2 2-2 2" stroke-linecap="round" stroke-linejoin="round"/></g></svg> diff --git a/editor/icons/MirrorY.svg b/editor/icons/MirrorY.svg index bb4e4d3543..beaf8b0536 100644 --- a/editor/icons/MirrorY.svg +++ b/editor/icons/MirrorY.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11.012 1048.4a1.0001 1.0001 0 0 0 -1.7168-.6973l-.29297.293v-7.1719l.29297.293a1.0001 1.0001 0 0 0 1.7148-.7266 1.0001 1.0001 0 0 0 -.30078-.6875l-2-2a1.0001 1.0001 0 0 0 -1.4141 0l-2 2a1.0001 1.0001 0 1 0 1.4141 1.4141l.29297-.293v7.1719l-.29297-.293a1.0001 1.0001 0 1 0 -1.4141 1.4141l2 2a1.0001 1.0001 0 0 0 1.4141 0l2-2a1.0001 1.0001 0 0 0 .30273-.7168z" fill="#e0e0e0" fill-opacity=".99608" transform="translate(0 -1036.4)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11.012 1048.4a1.0001 1.0001 0 0 0 -1.7168-.6973l-.29297.293v-7.1719l.29297.293a1.0001 1.0001 0 0 0 1.7148-.7266 1.0001 1.0001 0 0 0 -.30078-.6875l-2-2a1.0001 1.0001 0 0 0 -1.4141 0l-2 2a1.0001 1.0001 0 1 0 1.4141 1.4141l.29297-.293v7.1719l-.29297-.293a1.0001 1.0001 0 1 0 -1.4141 1.4141l2 2a1.0001 1.0001 0 0 0 1.4141 0l2-2a1.0001 1.0001 0 0 0 .30273-.7168z" fill="#e0e0e0" transform="translate(0 -1036.4)"/></svg> diff --git a/editor/icons/MoveDown.svg b/editor/icons/MoveDown.svg index 3c2d771cd5..85301f7f22 100644 --- a/editor/icons/MoveDown.svg +++ b/editor/icons/MoveDown.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a1.0001 1.0001 0 1 0 0 2h4a1.0001 1.0001 0 1 0 0-2zm2 4c-.55231 0-1 .4477-1 1v5.1484l-2.2188-2.7734c-.34504-.4317-.97482-.50165-1.4062-.15625-.4305.3449-.5004.9732-.15625 1.4043l4 5c.18868.2369.4745.37695.77734.37695.30559.0009.59477-.13795.78516-.37695l4-5c.34415-.4311.27424-1.0594-.15625-1.4043-.43143-.3454-1.0612-.27545-1.4062.15625l-2.2188 2.7734v-5.1484c0-.5523-.44769-1-1-1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a1.0001 1.0001 0 1 0 0 2h4a1.0001 1.0001 0 1 0 0-2zm2 4c-.55231 0-1 .4477-1 1v5.1484l-2.2188-2.7734c-.34504-.4317-.97482-.50165-1.4062-.15625-.4305.3449-.5004.9732-.15625 1.4043l4 5c.18868.2369.4745.37695.77734.37695.30559.0009.59477-.13795.78516-.37695l4-5c.34415-.4311.27424-1.0594-.15625-1.4043-.43143-.3454-1.0612-.27545-1.4062.15625l-2.2188 2.7734v-5.1484c0-.5523-.44769-1-1-1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/MoveLeft.svg b/editor/icons/MoveLeft.svg index 8f96ee0060..eedae80a81 100644 --- a/editor/icons/MoveLeft.svg +++ b/editor/icons/MoveLeft.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 10a1.0001 1.0001 0 1 1 -2 0v-4a1.0001 1.0001 0 1 1 2 0zm-4-2c0 .55231-.4477 1-1 1h-5.1484l2.7734 2.2188c.4317.34504.50165.97482.15625 1.4062-.3449.4305-.9732.5004-1.4043.15625l-5-4c-.2369-.18868-.37695-.4745-.37695-.77734-.0009-.30559.13795-.59477.37695-.78516l5-4c.4311-.34415 1.0594-.27424 1.4043.15625.3454.43143.27545 1.0612-.15625 1.4062l-2.7734 2.2188h5.1484c.5523 0 1 .44769 1 1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 10a1.0001 1.0001 0 1 1 -2 0v-4a1.0001 1.0001 0 1 1 2 0zm-4-2c0 .55231-.4477 1-1 1h-5.1484l2.7734 2.2188c.4317.34504.50165.97482.15625 1.4062-.3449.4305-.9732.5004-1.4043.15625l-5-4c-.2369-.18868-.37695-.4745-.37695-.77734-.0009-.30559.13795-.59477.37695-.78516l5-4c.4311-.34415 1.0594-.27424 1.4043.15625.3454.43143.27545 1.0612-.15625 1.4062l-2.7734 2.2188h5.1484c.5523 0 1 .44769 1 1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/MoveRight.svg b/editor/icons/MoveRight.svg index ee8d1b45a4..951755fabe 100644 --- a/editor/icons/MoveRight.svg +++ b/editor/icons/MoveRight.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 10a1.0001 1.0001 0 1 0 2 0v-4a1.0001 1.0001 0 1 0 -2 0zm4-2c0 .55231.4477 1 1 1h5.1484l-2.7734 2.2188c-.4317.34504-.50165.97482-.15625 1.4062.3449.4305.9732.5004 1.4043.15625l5-4c.2369-.18868.37695-.4745.37695-.77734.0009-.30559-.13795-.59477-.37695-.78516l-5-4c-.4311-.34415-1.0594-.27424-1.4043.15625-.3454.43143-.27545 1.0612.15625 1.4062l2.7734 2.2188h-5.1484c-.5523 0-1 .44769-1 1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 10a1.0001 1.0001 0 1 0 2 0v-4a1.0001 1.0001 0 1 0 -2 0zm4-2c0 .55231.4477 1 1 1h5.1484l-2.7734 2.2188c-.4317.34504-.50165.97482-.15625 1.4062.3449.4305.9732.5004 1.4043.15625l5-4c.2369-.18868.37695-.4745.37695-.77734.0009-.30559-.13795-.59477-.37695-.78516l-5-4c-.4311-.34415-1.0594-.27424-1.4043.15625-.3454.43143-.27545 1.0612.15625 1.4062l2.7734 2.2188h-5.1484c-.5523 0-1 .44769-1 1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/MoveUp.svg b/editor/icons/MoveUp.svg index f1302b2984..6cdc984ebc 100644 --- a/editor/icons/MoveUp.svg +++ b/editor/icons/MoveUp.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 15a1.0001 1.0001 0 1 1 0-2h4a1.0001 1.0001 0 1 1 0 2zm2-4c-.55231 0-1-.4477-1-1v-5.1484l-2.2188 2.7734c-.34504.4317-.97482.50165-1.4062.15625-.4305-.3449-.5004-.9732-.15625-1.4043l4-5c.18868-.2369.4745-.37695.77734-.37695.30559-.0009.59477.13795.78516.37695l4 5c.34415.4311.27424 1.0594-.15625 1.4043-.43143.3454-1.0612.27545-1.4062-.15625l-2.2188-2.7734v5.1484c0 .5523-.44769 1-1 1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 15a1.0001 1.0001 0 1 1 0-2h4a1.0001 1.0001 0 1 1 0 2zm2-4c-.55231 0-1-.4477-1-1v-5.1484l-2.2188 2.7734c-.34504.4317-.97482.50165-1.4062.15625-.4305-.3449-.5004-.9732-.15625-1.4043l4-5c.18868-.2369.4745-.37695.77734-.37695.30559-.0009.59477.13795.78516.37695l4 5c.34415.4311.27424 1.0594-.15625 1.4043-.43143.3454-1.0612.27545-1.4062-.15625l-2.2188-2.7734v5.1484c0 .5523-.44769 1-1 1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/MultiMeshInstance3D.svg b/editor/icons/MultiMeshInstance3D.svg index 3ccd2c9cbe..eb82d4928b 100644 --- a/editor/icons/MultiMeshInstance3D.svg +++ b/editor/icons/MultiMeshInstance3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h1.2695v-2h-1.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l3.5859 3.5859h1.4141v-1.4141l-3.5859-3.5859h5.8574c.17532.30158.42647.55205.72852.72656v1.2734h2v-1.2695c.61831-.35698.99944-1.0165 1-1.7305 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1zm8 7v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h1.2695v-2h-1.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l3.5859 3.5859h1.4141v-1.4141l-3.5859-3.5859h5.8574c.17532.30158.42647.55205.72852.72656v1.2734h2v-1.2695c.61831-.35698.99944-1.0165 1-1.7305 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1zm8 7v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/Navigation3D.svg b/editor/icons/Navigation3D.svg index 646500d9ed..79cca958f8 100644 --- a/editor/icons/Navigation3D.svg +++ b/editor/icons/Navigation3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1050.4 5-2 5 2-5-12z" fill="#fc7f7f" fill-opacity=".99608" fill-rule="evenodd" transform="translate(0 -1036.4)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1050.4 5-2 5 2-5-12z" fill="#fc7f7f" fill-rule="evenodd" transform="translate(0 -1036.4)"/></svg> diff --git a/editor/icons/NavigationLink2D.svg b/editor/icons/NavigationLink2D.svg index 6c5f17e256..df470ece57 100644 --- a/editor/icons/NavigationLink2D.svg +++ b/editor/icons/NavigationLink2D.svg @@ -1,4 +1,4 @@ <svg version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<path d="m12.386 5.3097c-0.69157-0.021112-1.3071 0.36382-1.7492 0.86685-0.58 0.58-1.16 1.16-1.74 1.74 0.4588-0.28502 1.0599-0.064948 1.4771-0.037996 0.45549-0.44357 0.89024-0.91006 1.3596-1.3383 0.56256-0.44564 1.4906-0.15731 1.7028 0.52802 0.18967 0.4871-0.049221 1.0098-0.43284 1.3208-0.70048 0.68896-1.3789 1.4022-2.0935 2.0755-0.47999 0.3725-1.2044 0.226-1.5679-0.24034-0.38763-0.38194-1.0641 0.16031-0.78317 0.6241 0.6767 0.94379 2.1573 1.1282 3.0411 0.36751 0.80287-0.7704 1.5793-1.5696 2.3665-2.3564 0.79925-0.83719 0.70104-2.3112-0.19552-3.0393-0.38108-0.32877-0.8822-0.5119-1.385-0.51049zm-3.051 3.051c-0.69157-0.021106-1.3071 0.36382-1.7492 0.86685-0.67513 0.68452-1.37 1.3506-2.0319 2.0474-0.75433 0.87744-0.58087 2.3428 0.34933 3.0252 0.84748 0.68613 2.192 0.54839 2.8998-0.27341 0.63032-0.63031 1.2606-1.2606 1.8909-1.8909-0.4587 0.28554-1.0602 0.0659-1.477 0.038069-0.45445 0.44348-0.88773 0.91034-1.3564 1.3383-0.56256 0.44565-1.4906 0.15731-1.7028-0.52802-0.18967-0.4871 0.049229-1.0098 0.43284-1.3208 0.70048-0.68896 1.3789-1.4022 2.0935-2.0755 0.48-0.3725 1.2044-0.22601 1.5679 0.24036 0.38733 0.38325 1.064-0.16067 0.78313-0.6241-0.39353-0.52481-1.0429-0.84871-1.7002-0.8434z" fill="#8ea6f4" fill-opacity=".99608" stroke-linecap="round" stroke-linejoin="round" stroke-width=".013911"/> -<path d="m2 1c-0.61942-0.0066969-1.0877 0.60314-1 1.198 0.00345 3.968-0.006897 7.9364 0.00517 11.904 0.043388 0.62851 0.69346 0.98513 1.272 0.89776h2.5896c-0.77174-0.5015-1.2078-1.2613-1.3143-2.3356-0.11601-1.1701 0.63729-2.024 1.6748-3.1566 0.65335-0.71326 1.4757-1.5822 2.3587-2.3316 0.76308-0.64765 1.7509-1.679 2.9376-2.578 0.91259-0.69136 2.2893-0.74691 3.1014-0.33143 0.91184 0.46649 1.2635 1.1209 1.4067 1.3826-0.0052-2.335-0.02135-1.3526-0.03955-3.6863 5e-3 -0.64349-0.67497-1.0568-1.2694-0.96289z" fill="#8ea6f4" fill-opacity=".99608"/> +<path d="m12.386 5.3097c-0.69157-0.021112-1.3071 0.36382-1.7492 0.86685-0.58 0.58-1.16 1.16-1.74 1.74 0.4588-0.28502 1.0599-0.064948 1.4771-0.037996 0.45549-0.44357 0.89024-0.91006 1.3596-1.3383 0.56256-0.44564 1.4906-0.15731 1.7028 0.52802 0.18967 0.4871-0.049221 1.0098-0.43284 1.3208-0.70048 0.68896-1.3789 1.4022-2.0935 2.0755-0.47999 0.3725-1.2044 0.226-1.5679-0.24034-0.38763-0.38194-1.0641 0.16031-0.78317 0.6241 0.6767 0.94379 2.1573 1.1282 3.0411 0.36751 0.80287-0.7704 1.5793-1.5696 2.3665-2.3564 0.79925-0.83719 0.70104-2.3112-0.19552-3.0393-0.38108-0.32877-0.8822-0.5119-1.385-0.51049zm-3.051 3.051c-0.69157-0.021106-1.3071 0.36382-1.7492 0.86685-0.67513 0.68452-1.37 1.3506-2.0319 2.0474-0.75433 0.87744-0.58087 2.3428 0.34933 3.0252 0.84748 0.68613 2.192 0.54839 2.8998-0.27341 0.63032-0.63031 1.2606-1.2606 1.8909-1.8909-0.4587 0.28554-1.0602 0.0659-1.477 0.038069-0.45445 0.44348-0.88773 0.91034-1.3564 1.3383-0.56256 0.44565-1.4906 0.15731-1.7028-0.52802-0.18967-0.4871 0.049229-1.0098 0.43284-1.3208 0.70048-0.68896 1.3789-1.4022 2.0935-2.0755 0.48-0.3725 1.2044-0.22601 1.5679 0.24036 0.38733 0.38325 1.064-0.16067 0.78313-0.6241-0.39353-0.52481-1.0429-0.84871-1.7002-0.8434z" fill="#8ea6f4" stroke-linecap="round" stroke-linejoin="round" stroke-width=".013911"/> +<path d="m2 1c-0.61942-0.0066969-1.0877 0.60314-1 1.198 0.00345 3.968-0.006897 7.9364 0.00517 11.904 0.043388 0.62851 0.69346 0.98513 1.272 0.89776h2.5896c-0.77174-0.5015-1.2078-1.2613-1.3143-2.3356-0.11601-1.1701 0.63729-2.024 1.6748-3.1566 0.65335-0.71326 1.4757-1.5822 2.3587-2.3316 0.76308-0.64765 1.7509-1.679 2.9376-2.578 0.91259-0.69136 2.2893-0.74691 3.1014-0.33143 0.91184 0.46649 1.2635 1.1209 1.4067 1.3826-0.0052-2.335-0.02135-1.3526-0.03955-3.6863 5e-3 -0.64349-0.67497-1.0568-1.2694-0.96289z" fill="#8ea6f4"/> </svg> diff --git a/editor/icons/NavigationLink3D.svg b/editor/icons/NavigationLink3D.svg index ea4092c2c7..05f36da2b2 100644 --- a/editor/icons/NavigationLink3D.svg +++ b/editor/icons/NavigationLink3D.svg @@ -1,4 +1,4 @@ <svg version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<path d="m12.386 5.3097c-0.69157-0.021112-1.3071 0.36382-1.7492 0.86685-0.58 0.58-1.16 1.16-1.74 1.74 0.4588-0.28502 1.0599-0.064948 1.4771-0.037996 0.45549-0.44357 0.89024-0.91006 1.3596-1.3383 0.56256-0.44564 1.4906-0.15731 1.7028 0.52802 0.18967 0.4871-0.049221 1.0098-0.43284 1.3208-0.70048 0.68896-1.3789 1.4022-2.0935 2.0755-0.47999 0.3725-1.2044 0.226-1.5679-0.24034-0.38763-0.38194-1.0641 0.16031-0.78317 0.6241 0.6767 0.94379 2.1573 1.1282 3.0411 0.36751 0.80287-0.7704 1.5793-1.5696 2.3665-2.3564 0.79925-0.83719 0.70104-2.3112-0.19552-3.0393-0.38108-0.32877-0.8822-0.5119-1.385-0.51049zm-3.051 3.051c-0.69157-0.021106-1.3071 0.36382-1.7492 0.86685-0.67513 0.68452-1.37 1.3506-2.0319 2.0474-0.75433 0.87744-0.58087 2.3428 0.34933 3.0252 0.84748 0.68613 2.192 0.54839 2.8998-0.27341 0.63032-0.63031 1.2606-1.2606 1.8909-1.8909-0.4587 0.28554-1.0602 0.0659-1.477 0.038069-0.45445 0.44348-0.88773 0.91034-1.3564 1.3383-0.56256 0.44565-1.4906 0.15731-1.7028-0.52802-0.18967-0.4871 0.049229-1.0098 0.43284-1.3208 0.70048-0.68896 1.3789-1.4022 2.0935-2.0755 0.48-0.3725 1.2044-0.22601 1.5679 0.24036 0.38733 0.38325 1.064-0.16067 0.78313-0.6241-0.39353-0.52481-1.0429-0.84871-1.7002-0.8434z" fill="#fc7e7e" fill-opacity=".99608" stroke-linecap="round" stroke-linejoin="round" stroke-width=".013911"/> -<path d="m2 1c-0.61942-0.0066969-1.0877 0.60314-1 1.198 0.00345 3.968-0.006897 7.9364 0.00517 11.904 0.043388 0.62851 0.69346 0.98513 1.272 0.89776h2.5896c-0.77174-0.5015-1.2078-1.2613-1.3143-2.3356-0.11601-1.1701 0.63729-2.024 1.6748-3.1566 0.65335-0.71326 1.4757-1.5822 2.3587-2.3316 0.76308-0.64765 1.7509-1.679 2.9376-2.578 0.91259-0.69136 2.2893-0.74691 3.1014-0.33143 0.91184 0.46649 1.2635 1.1209 1.4067 1.3826-0.0052-2.335-0.02135-1.3526-0.03955-3.6863 5e-3 -0.64349-0.67497-1.0568-1.2694-0.96289z" fill="#fc7d7d" fill-opacity=".99608"/> +<path d="m12.386 5.3097c-0.69157-0.021112-1.3071 0.36382-1.7492 0.86685-0.58 0.58-1.16 1.16-1.74 1.74 0.4588-0.28502 1.0599-0.064948 1.4771-0.037996 0.45549-0.44357 0.89024-0.91006 1.3596-1.3383 0.56256-0.44564 1.4906-0.15731 1.7028 0.52802 0.18967 0.4871-0.049221 1.0098-0.43284 1.3208-0.70048 0.68896-1.3789 1.4022-2.0935 2.0755-0.47999 0.3725-1.2044 0.226-1.5679-0.24034-0.38763-0.38194-1.0641 0.16031-0.78317 0.6241 0.6767 0.94379 2.1573 1.1282 3.0411 0.36751 0.80287-0.7704 1.5793-1.5696 2.3665-2.3564 0.79925-0.83719 0.70104-2.3112-0.19552-3.0393-0.38108-0.32877-0.8822-0.5119-1.385-0.51049zm-3.051 3.051c-0.69157-0.021106-1.3071 0.36382-1.7492 0.86685-0.67513 0.68452-1.37 1.3506-2.0319 2.0474-0.75433 0.87744-0.58087 2.3428 0.34933 3.0252 0.84748 0.68613 2.192 0.54839 2.8998-0.27341 0.63032-0.63031 1.2606-1.2606 1.8909-1.8909-0.4587 0.28554-1.0602 0.0659-1.477 0.038069-0.45445 0.44348-0.88773 0.91034-1.3564 1.3383-0.56256 0.44565-1.4906 0.15731-1.7028-0.52802-0.18967-0.4871 0.049229-1.0098 0.43284-1.3208 0.70048-0.68896 1.3789-1.4022 2.0935-2.0755 0.48-0.3725 1.2044-0.22601 1.5679 0.24036 0.38733 0.38325 1.064-0.16067 0.78313-0.6241-0.39353-0.52481-1.0429-0.84871-1.7002-0.8434z" fill="#fc7e7e" stroke-linecap="round" stroke-linejoin="round" stroke-width=".013911"/> +<path d="m2 1c-0.61942-0.0066969-1.0877 0.60314-1 1.198 0.00345 3.968-0.006897 7.9364 0.00517 11.904 0.043388 0.62851 0.69346 0.98513 1.272 0.89776h2.5896c-0.77174-0.5015-1.2078-1.2613-1.3143-2.3356-0.11601-1.1701 0.63729-2.024 1.6748-3.1566 0.65335-0.71326 1.4757-1.5822 2.3587-2.3316 0.76308-0.64765 1.7509-1.679 2.9376-2.578 0.91259-0.69136 2.2893-0.74691 3.1014-0.33143 0.91184 0.46649 1.2635 1.1209 1.4067 1.3826-0.0052-2.335-0.02135-1.3526-0.03955-3.6863 5e-3 -0.64349-0.67497-1.0568-1.2694-0.96289z" fill="#fc7d7d"/> </svg> diff --git a/editor/icons/NavigationRegion3D.svg b/editor/icons/NavigationRegion3D.svg index 39b6d0ca13..523ae4d20d 100644 --- a/editor/icons/NavigationRegion3D.svg +++ b/editor/icons/NavigationRegion3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.1339223.0000569-.2535666.030668-.3652344.074219-.022275.00881-.041042.020919-.0625.03125-.088962.042467-.1681009.095499-.2382812.1601562-.021532.01952-.042739.037285-.0625.058594-.074111.081092-.13722.1698052-.1816406.2695312-.00343.00765-.00847.013733-.011719.021484l-.00195.00195c-.0452281.1091913-.0629952.2269004-.0683623.3457062-.0005086.0130821-.0078112.023903-.0078125.0371094v12c.0000552.552262.4477381.999945 1 1h4.8847656a2.1184381 2.1184381 0 0 1 .1328125-.744141l2.9999999-7.9999996a2.1184381 2.1184381 0 0 1 2.007813-1.3730469 2.1184381 2.1184381 0 0 1 1.957031 1.3730469l1.017578 2.7128906v-6.96875c-.000001-.013206-.0073-.024027-.0078-.037109-.0054-.1188058-.02313-.2365149-.06836-.3457031l-.002-.00195c-.0032-.00756-.0084-.013999-.01172-.021484-.04442-.099726-.107529-.188439-.18164-.2695312-.01976-.021308-.04097-.039073-.0625-.058594-.07018-.064657-.149319-.1176895-.238282-.1601562-.02146-.010331-.04022-.022439-.0625-.03125-.111631-.0435548-.231276-.0741656-.365198-.0742225zm10 6-3 8 3-2 3 2z" fill="#fc7f7f" fill-opacity=".996078" fill-rule="evenodd"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.1339223.0000569-.2535666.030668-.3652344.074219-.022275.00881-.041042.020919-.0625.03125-.088962.042467-.1681009.095499-.2382812.1601562-.021532.01952-.042739.037285-.0625.058594-.074111.081092-.13722.1698052-.1816406.2695312-.00343.00765-.00847.013733-.011719.021484l-.00195.00195c-.0452281.1091913-.0629952.2269004-.0683623.3457062-.0005086.0130821-.0078112.023903-.0078125.0371094v12c.0000552.552262.4477381.999945 1 1h4.8847656a2.1184381 2.1184381 0 0 1 .1328125-.744141l2.9999999-7.9999996a2.1184381 2.1184381 0 0 1 2.007813-1.3730469 2.1184381 2.1184381 0 0 1 1.957031 1.3730469l1.017578 2.7128906v-6.96875c-.000001-.013206-.0073-.024027-.0078-.037109-.0054-.1188058-.02313-.2365149-.06836-.3457031l-.002-.00195c-.0032-.00756-.0084-.013999-.01172-.021484-.04442-.099726-.107529-.188439-.18164-.2695312-.01976-.021308-.04097-.039073-.0625-.058594-.07018-.064657-.149319-.1176895-.238282-.1601562-.02146-.010331-.04022-.022439-.0625-.03125-.111631-.0435548-.231276-.0741656-.365198-.0742225zm10 6-3 8 3-2 3 2z" fill="#fc7f7f" fill-rule="evenodd"/></svg> diff --git a/editor/icons/Node3D.svg b/editor/icons/Node3D.svg index c8a3163e51..620bc95229 100644 --- a/editor/icons/Node3D.svg +++ b/editor/icons/Node3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/OccluderInstance3D.svg b/editor/icons/OccluderInstance3D.svg index cc7ccc410f..18f6054873 100644 --- a/editor/icons/OccluderInstance3D.svg +++ b/editor/icons/OccluderInstance3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.90625 1a7 7 0 0 0 -1.2988281.1386719 4.5 4.5 0 0 1 3.3925781 4.3613281 4.5 4.5 0 0 1 -4.5 4.5 4.5 4.5 0 0 1 -4.359375-3.3886719 7 7 0 0 0 -.140625 1.3886719 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7 7 7 0 0 0 -.09375 0z" fill="#fc7f7f" fill-opacity=".996078" stroke-width=".365215"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.90625 1a7 7 0 0 0 -1.2988281.1386719 4.5 4.5 0 0 1 3.3925781 4.3613281 4.5 4.5 0 0 1 -4.5 4.5 4.5 4.5 0 0 1 -4.359375-3.3886719 7 7 0 0 0 -.140625 1.3886719 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7 7 7 0 0 0 -.09375 0z" fill="#fc7f7f" stroke-width=".365215"/></svg> diff --git a/editor/icons/OmniLight3D.svg b/editor/icons/OmniLight3D.svg index 391e9104a1..9d874b359c 100644 --- a/editor/icons/OmniLight3D.svg +++ b/editor/icons/OmniLight3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a5 5 0 0 0 -5 5 5 5 0 0 0 3 4.5762v2.4238h4v-2.4199a5 5 0 0 0 3-4.5801 5 5 0 0 0 -5-5zm0 2a3 3 0 0 1 3 3 3 3 0 0 1 -3 3 3 3 0 0 1 -3-3 3 3 0 0 1 3-3zm-1 11v1h2v-1z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a5 5 0 0 0 -5 5 5 5 0 0 0 3 4.5762v2.4238h4v-2.4199a5 5 0 0 0 3-4.5801 5 5 0 0 0 -5-5zm0 2a3 3 0 0 1 3 3 3 3 0 0 1 -3 3 3 3 0 0 1 -3-3 3 3 0 0 1 3-3zm-1 11v1h2v-1z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/ParallaxBackground.svg b/editor/icons/ParallaxBackground.svg index f188230fcc..71a586eff4 100644 --- a/editor/icons/ParallaxBackground.svg +++ b/editor/icons/ParallaxBackground.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m2 2a1 1 0 0 0 -1 1v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-10a1 1 0 0 0 -1-1zm0 1h12v10h-12zm5 2-3 3 3 3zm2 0v6l3-3z" fill="#e0e0e0" fill-opacity=".99608" transform="translate(0 1036.4)"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m2 2a1 1 0 0 0 -1 1v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-10a1 1 0 0 0 -1-1zm0 1h12v10h-12zm5 2-3 3 3 3zm2 0v6l3-3z" fill="#e0e0e0" transform="translate(0 1036.4)"/></g></svg> diff --git a/editor/icons/Path3D.svg b/editor/icons/Path3D.svg index 076ce9acd2..4e84cf9789 100644 --- a/editor/icons/Path3D.svg +++ b/editor/icons/Path3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 1a2 2 0 0 0 -2 2 2 2 0 0 0 .84961 1.6328c-.19239.88508-.55317 1.3394-.98633 1.6426-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c.8927-.62488 1.5321-1.6538 1.8184-3.0977a2 2 0 0 0 1.1699-1.8164 2 2 0 0 0 -2-2z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 1a2 2 0 0 0 -2 2 2 2 0 0 0 .84961 1.6328c-.19239.88508-.55317 1.3394-.98633 1.6426-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c.8927-.62488 1.5321-1.6538 1.8184-3.0977a2 2 0 0 0 1.1699-1.8164 2 2 0 0 0 -2-2z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/PathFollow3D.svg b/editor/icons/PathFollow3D.svg index f9bb38939e..01da0b0114 100644 --- a/editor/icons/PathFollow3D.svg +++ b/editor/icons/PathFollow3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 0-3 4h1.9473c-.1385 1.3203-.5583 1.9074-1.084 2.2754-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c1.0528-.73697 1.7552-2.032 1.9375-3.9141h2.0508l-3-4z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 0-3 4h1.9473c-.1385 1.3203-.5583 1.9074-1.084 2.2754-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c1.0528-.73697 1.7552-2.032 1.9375-3.9141h2.0508l-3-4z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/Progress1.svg b/editor/icons/Progress1.svg index 07505ddd67..d9a58d837e 100644 --- a/editor/icons/Progress1.svg +++ b/editor/icons/Progress1.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1037.4v3.0547a4 4 0 0 1 1.0273.4258l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223z" fill-opacity=".99608"/><path d="m7 1.0801a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1037.4v3.0547a4 4 0 0 1 1.0273.4258l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223z"/><path d="m7 1.0801a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/></g></svg> diff --git a/editor/icons/Progress2.svg b/editor/icons/Progress2.svg index 0a48f7d3f5..d98de2e78b 100644 --- a/editor/icons/Progress2.svg +++ b/editor/icons/Progress2.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm-1.3203 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m13.6 1040.2-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855z" fill-opacity=".99608"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm-1.3203 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m13.6 1040.2-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855z"/></g></svg> diff --git a/editor/icons/Progress3.svg b/editor/icons/Progress3.svg index a7f0f9c973..a1e84fa7cf 100644 --- a/editor/icons/Progress3.svg +++ b/editor/icons/Progress3.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm4.8926 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m11.867 1045.4a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547z" fill-opacity=".99608"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm4.8926 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m11.867 1045.4a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547z"/></g></svg> diff --git a/editor/icons/Progress4.svg b/editor/icons/Progress4.svg index 171920915e..04a556fd93 100644 --- a/editor/icons/Progress4.svg +++ b/editor/icons/Progress4.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m10.027 1047.8a4 4 0 0 1 -1.0273.4277v3.0508a7 7 0 0 0 3.1855-1.3203z" fill-opacity=".99608"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m10.027 1047.8a4 4 0 0 1 -1.0273.4277v3.0508a7 7 0 0 0 3.1855-1.3203z"/></g></svg> diff --git a/editor/icons/Progress5.svg b/editor/icons/Progress5.svg index 7289b7b8fe..d5a5432781 100644 --- a/editor/icons/Progress5.svg +++ b/editor/icons/Progress5.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-1.8398 2.4414a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m5.9727 1047.8-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.4258z" fill-opacity=".99608"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-1.8398 2.4414a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m5.9727 1047.8-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.4258z"/></g></svg> diff --git a/editor/icons/Progress6.svg b/editor/icons/Progress6.svg index 3deba6d48c..95aebb3cf5 100644 --- a/editor/icons/Progress6.svg +++ b/editor/icons/Progress6.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-1.7324 5.1855a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m1.0801 1045.4a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508z" fill-opacity=".99608"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm-4.5996 2.7344a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-1.7324 5.1855a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m1.0801 1045.4a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508z"/></g></svg> diff --git a/editor/icons/Progress7.svg b/editor/icons/Progress7.svg index 546155dc59..cbcd7df35f 100644 --- a/editor/icons/Progress7.svg +++ b/editor/icons/Progress7.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm6.5996 2.7344-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m2.4004 1040.2a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582z" fill-opacity=".99608"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-2 .0019531a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.42773v-3.0508zm6.5996 2.7344-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m2.4004 1040.2a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582z"/></g></svg> diff --git a/editor/icons/Progress8.svg b/editor/icons/Progress8.svg index b56ffcb727..900b681c69 100644 --- a/editor/icons/Progress8.svg +++ b/editor/icons/Progress8.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-6.5996 2.7363a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m7 1037.4a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.4277z" fill-opacity=".99608"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 1.0781v3.0547a4 4 0 0 1 1.0273.42578l2.1582-2.1582a7 7 0 0 0 -3.1855-1.3223zm-6.5996 2.7363a7 7 0 0 0 -1.3223 3.1855h3.0547a4 4 0 0 1 .42578-1.0273l-2.1582-2.1582zm11.199 0-2.1582 2.1582a4 4 0 0 1 .42774 1.0273h3.0508a7 7 0 0 0 -1.3203-3.1855zm-12.52 5.1855a7 7 0 0 0 1.3203 3.1855l2.1582-2.1582a4 4 0 0 1 -.42773-1.0273h-3.0508zm10.787 0a4 4 0 0 1 -.42578 1.0273l2.1582 2.1582a7 7 0 0 0 1.3223-3.1855h-3.0547zm-5.8945 2.4414-2.1582 2.1582a7 7 0 0 0 3.1855 1.3223v-3.0547a4 4 0 0 1 -1.0273-.42578zm4.0547 0a4 4 0 0 1 -1.0273.42774v3.0508a7 7 0 0 0 3.1855-1.3203l-2.1582-2.1582z" fill-opacity=".19608" transform="translate(0 1036.4)"/><path d="m7 1037.4a7 7 0 0 0 -3.1855 1.3203l2.1582 2.1582a4 4 0 0 1 1.0273-.4277z"/></g></svg> diff --git a/editor/icons/ProxyTexture.svg b/editor/icons/ProxyTexture.svg index 526f21c379..5435e72a1b 100644 --- a/editor/icons/ProxyTexture.svg +++ b/editor/icons/ProxyTexture.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h4v-4zm6 0v2h6v8h-6v4h7a1 1 0 0 0 1-1v-12a1 1 0 0 0 -1-1zm2 4v1h-1v1h-1v3h1 2 2v-2h-1v-2h-1v-1zm-8 1v4h4v-4zm0 5v4h4v-4z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h4v-4zm6 0v2h6v8h-6v4h7a1 1 0 0 0 1-1v-12a1 1 0 0 0 -1-1zm2 4v1h-1v1h-1v3h1 2 2v-2h-1v-2h-1v-1zm-8 1v4h4v-4zm0 5v4h4v-4z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/Quad.svg b/editor/icons/Quad.svg index 70ef6b7227..5627876bfb 100644 --- a/editor/icons/Quad.svg +++ b/editor/icons/Quad.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 10 2h2 12v-2-12h-12zm3.4141 2h8.5859v8.5859zm-1.4141 1.4141 8.5859 8.5859h-8.5859z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 10 2h2 12v-2-12h-12zm3.4141 2h8.5859v8.5859zm-1.4141 1.4141 8.5859 8.5859h-8.5859z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/RayCast3D.svg b/editor/icons/RayCast3D.svg index 9670e63022..59a5e181d6 100644 --- a/editor/icons/RayCast3D.svg +++ b/editor/icons/RayCast3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v9h-3l4 5 4-5h-3v-9z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v9h-3l4 5 4-5h-3v-9z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/ReflectionProbe.svg b/editor/icons/ReflectionProbe.svg index a88a3524be..dee37be8be 100644 --- a/editor/icons/ReflectionProbe.svg +++ b/editor/icons/ReflectionProbe.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10 2a1.0001 1.0001 0 1 0 0 2h1.5859l-4.5195 4.5195-4.2988-5.1582-1.5352 1.2793 5 6a1.0001 1.0001 0 0 0 1.4746.064453l5.293-5.293v1.5879a1.0001 1.0001 0 1 0 2 0v-4a1.0001 1.0001 0 0 0 -1-1h-4zm-9 7v5a1.0001 1.0001 0 0 0 1 1h12a1.0001 1.0001 0 0 0 1-1v-4h-2v3h-10v-4z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10 2a1.0001 1.0001 0 1 0 0 2h1.5859l-4.5195 4.5195-4.2988-5.1582-1.5352 1.2793 5 6a1.0001 1.0001 0 0 0 1.4746.064453l5.293-5.293v1.5879a1.0001 1.0001 0 1 0 2 0v-4a1.0001 1.0001 0 0 0 -1-1h-4zm-9 7v5a1.0001 1.0001 0 0 0 1 1h12a1.0001 1.0001 0 0 0 1-1v-4h-2v3h-10v-4z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/Reload.svg b/editor/icons/Reload.svg index 1200df1dde..4891455cea 100644 --- a/editor/icons/Reload.svg +++ b/editor/icons/Reload.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".99608" transform="translate(0 -1036.4)"><path d="m9 2a6 6 0 0 0 -6 6h2a4 4 0 0 1 4-4 4 4 0 0 1 4 4 4 4 0 0 1 -4 4v2a6 6 0 0 0 6-6 6 6 0 0 0 -6-6z" transform="translate(0 1036.4)"/><path d="m4.118 1048.3-1.6771-.9683-1.6771-.9682 1.6771-.9683 1.6771-.9682-.0000001 1.9365z" transform="matrix(0 -1.1926 1.5492 0 -1617 1049.3)"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 2a6 6 0 0 0 -6 6h2a4 4 0 0 1 4-4 4 4 0 0 1 4 4 4 4 0 0 1 -4 4v2a6 6 0 0 0 6-6 6 6 0 0 0 -6-6z" transform="translate(0 1036.4)"/><path d="m4.118 1048.3-1.6771-.9683-1.6771-.9682 1.6771-.9683 1.6771-.9682-.0000001 1.9365z" transform="matrix(0 -1.1926 1.5492 0 -1617 1049.3)"/></g></svg> diff --git a/editor/icons/ReloadSmall.svg b/editor/icons/ReloadSmall.svg index 9418a57ab1..ca13da056d 100644 --- a/editor/icons/ReloadSmall.svg +++ b/editor/icons/ReloadSmall.svg @@ -1 +1 @@ -<svg height="14" viewBox="0 0 14 14" width="14" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".99608" transform="translate(0 -1038.4)"><path d="m8 1039.4a6 6 0 0 0 -6 6h2a4 4 0 0 1 4-4 4 4 0 0 1 4 4 4 4 0 0 1 -4 4v2a6 6 0 0 0 6-6 6 6 0 0 0 -6-6z"/><path d="m4.118 1048.3-1.6771-.9683-1.6771-.9682 1.6771-.9683 1.6771-.9682-.0000001 1.9365z" transform="matrix(0 -1.1926 1.5492 0 -1618 1050.3)"/></g></svg> +<svg height="14" viewBox="0 0 14 14" width="14" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1038.4)"><path d="m8 1039.4a6 6 0 0 0 -6 6h2a4 4 0 0 1 4-4 4 4 0 0 1 4 4 4 4 0 0 1 -4 4v2a6 6 0 0 0 6-6 6 6 0 0 0 -6-6z"/><path d="m4.118 1048.3-1.6771-.9683-1.6771-.9682 1.6771-.9683 1.6771-.9682-.0000001 1.9365z" transform="matrix(0 -1.1926 1.5492 0 -1618 1050.3)"/></g></svg> diff --git a/editor/icons/Remove.svg b/editor/icons/Remove.svg index 5bcdf8e569..eb8e244d9a 100644 --- a/editor/icons/Remove.svg +++ b/editor/icons/Remove.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1v1h-4v2h14v-2h-4v-1zm-3 4v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-8zm1 2h2v6h-2zm4 0h2v6h-2zm4 0h2v6h-2z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1v1h-4v2h14v-2h-4v-1zm-3 4v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-8zm1 2h2v6h-2zm4 0h2v6h-2zm4 0h2v6h-2z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/RigidBody3D.svg b/editor/icons/RigidBody3D.svg index 7f5db4ce88..593f6e1f57 100644 --- a/editor/icons/RigidBody3D.svg +++ b/editor/icons/RigidBody3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 .035156.69922 7 7 0 0 0 .27734 1.3691 7 7 0 0 0 .91016 1.8848 7 7 0 0 0 .30273.4082c.000785-.00256.0011667-.005252.0019532-.007812a7 7 0 0 0 5.4727 2.6465 7 7 0 0 0 3.2422-.80273c.001374.000393.002531.00156.003906.001953a7 7 0 0 0 .035156-.021485 7 7 0 0 0 .42578-.25 7 7 0 0 0 .16992-.10352 7 7 0 0 0 .36914-.26953 7 7 0 0 0 .20508-.15625 7 7 0 0 0 .3418-.30859 7 7 0 0 0 .16406-.1543 7 7 0 0 0 .33008-.36133 7 7 0 0 0 .14062-.16016 7 7 0 0 0 .27734-.37305 7 7 0 0 0 .13867-.19531 7 7 0 0 0 .21875-.36133 7 7 0 0 0 .14258-.25 7 7 0 0 0 .15625-.33398 7 7 0 0 0 .13867-.31055 7 7 0 0 0 .10742-.30859 7 7 0 0 0 .11914-.35352 7 7 0 0 0 .087891-.36914 7 7 0 0 0 .066406-.29297 7 7 0 0 0 .056641-.40039 7 7 0 0 0 .037109-.3125 7 7 0 0 0 .025391-.55273 7 7 0 0 0 -4.3848-6.4883 7 7 0 0 0 -.007812-.0039063 7 7 0 0 0 -.001953 0 7 7 0 0 0 -.61523-.21289 7 7 0 0 0 -.044922-.015625 7 7 0 0 0 -.0058594-.0019531 7 7 0 0 0 -.55078-.13086 7 7 0 0 0 -.14062-.03125 7 7 0 0 0 -.55078-.072266 7 7 0 0 0 -.14258-.017578 7 7 0 0 0 -.55469-.025391zm1.9512 1.334a6 6 0 0 1 4.0488 5.666h-7a2 2 0 0 0 -.94922-1.6992c1.3464-2.0289 2.6038-3.2631 3.9004-3.9668zm-6.8281 2.1797c.14632.65093.35776 1.2833.68359 1.8848a2 2 0 0 0 -.80664 1.6016h-1a6 6 0 0 1 1.123-3.4863zm1.877 1.4863a2 2 0 0 0 -.10938.0039062 2 2 0 0 1 .10938-.0039062zm-.18945.011719a2 2 0 0 0 -.12109.013672 2 2 0 0 1 .12109-.013672zm-.44141.09375a2 2 0 0 0 -.056641.019531 2 2 0 0 1 .056641-.019531zm-1.3594 2.0605a2 2 0 0 0 .013672.11914 2 2 0 0 1 -.013672-.11914zm.027344.20898a2 2 0 0 0 .017578.080078 2 2 0 0 1 -.017578-.080078zm.73438 1.1992a2 2 0 0 0 1.2285.42578 2 2 0 0 0 1.0508-.30078c1.345 2.0268 2.6013 3.2645 3.8965 3.9688a6 6 0 0 1 -1.9473.33203 6 6 0 0 1 -5.0547-2.7695c.23771-.5785.50336-1.1403.82617-1.6563z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 .035156.69922 7 7 0 0 0 .27734 1.3691 7 7 0 0 0 .91016 1.8848 7 7 0 0 0 .30273.4082c.000785-.00256.0011667-.005252.0019532-.007812a7 7 0 0 0 5.4727 2.6465 7 7 0 0 0 3.2422-.80273c.001374.000393.002531.00156.003906.001953a7 7 0 0 0 .035156-.021485 7 7 0 0 0 .42578-.25 7 7 0 0 0 .16992-.10352 7 7 0 0 0 .36914-.26953 7 7 0 0 0 .20508-.15625 7 7 0 0 0 .3418-.30859 7 7 0 0 0 .16406-.1543 7 7 0 0 0 .33008-.36133 7 7 0 0 0 .14062-.16016 7 7 0 0 0 .27734-.37305 7 7 0 0 0 .13867-.19531 7 7 0 0 0 .21875-.36133 7 7 0 0 0 .14258-.25 7 7 0 0 0 .15625-.33398 7 7 0 0 0 .13867-.31055 7 7 0 0 0 .10742-.30859 7 7 0 0 0 .11914-.35352 7 7 0 0 0 .087891-.36914 7 7 0 0 0 .066406-.29297 7 7 0 0 0 .056641-.40039 7 7 0 0 0 .037109-.3125 7 7 0 0 0 .025391-.55273 7 7 0 0 0 -4.3848-6.4883 7 7 0 0 0 -.007812-.0039063 7 7 0 0 0 -.001953 0 7 7 0 0 0 -.61523-.21289 7 7 0 0 0 -.044922-.015625 7 7 0 0 0 -.0058594-.0019531 7 7 0 0 0 -.55078-.13086 7 7 0 0 0 -.14062-.03125 7 7 0 0 0 -.55078-.072266 7 7 0 0 0 -.14258-.017578 7 7 0 0 0 -.55469-.025391zm1.9512 1.334a6 6 0 0 1 4.0488 5.666h-7a2 2 0 0 0 -.94922-1.6992c1.3464-2.0289 2.6038-3.2631 3.9004-3.9668zm-6.8281 2.1797c.14632.65093.35776 1.2833.68359 1.8848a2 2 0 0 0 -.80664 1.6016h-1a6 6 0 0 1 1.123-3.4863zm1.877 1.4863a2 2 0 0 0 -.10938.0039062 2 2 0 0 1 .10938-.0039062zm-.18945.011719a2 2 0 0 0 -.12109.013672 2 2 0 0 1 .12109-.013672zm-.44141.09375a2 2 0 0 0 -.056641.019531 2 2 0 0 1 .056641-.019531zm-1.3594 2.0605a2 2 0 0 0 .013672.11914 2 2 0 0 1 -.013672-.11914zm.027344.20898a2 2 0 0 0 .017578.080078 2 2 0 0 1 -.017578-.080078zm.73438 1.1992a2 2 0 0 0 1.2285.42578 2 2 0 0 0 1.0508-.30078c1.345 2.0268 2.6013 3.2645 3.8965 3.9688a6 6 0 0 1 -1.9473.33203 6 6 0 0 1 -5.0547-2.7695c.23771-.5785.50336-1.1403.82617-1.6563z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/RotateLeft.svg b/editor/icons/RotateLeft.svg index 1200df1dde..4891455cea 100644 --- a/editor/icons/RotateLeft.svg +++ b/editor/icons/RotateLeft.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".99608" transform="translate(0 -1036.4)"><path d="m9 2a6 6 0 0 0 -6 6h2a4 4 0 0 1 4-4 4 4 0 0 1 4 4 4 4 0 0 1 -4 4v2a6 6 0 0 0 6-6 6 6 0 0 0 -6-6z" transform="translate(0 1036.4)"/><path d="m4.118 1048.3-1.6771-.9683-1.6771-.9682 1.6771-.9683 1.6771-.9682-.0000001 1.9365z" transform="matrix(0 -1.1926 1.5492 0 -1617 1049.3)"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m9 2a6 6 0 0 0 -6 6h2a4 4 0 0 1 4-4 4 4 0 0 1 4 4 4 4 0 0 1 -4 4v2a6 6 0 0 0 6-6 6 6 0 0 0 -6-6z" transform="translate(0 1036.4)"/><path d="m4.118 1048.3-1.6771-.9683-1.6771-.9682 1.6771-.9683 1.6771-.9682-.0000001 1.9365z" transform="matrix(0 -1.1926 1.5492 0 -1617 1049.3)"/></g></svg> diff --git a/editor/icons/RotateRight.svg b/editor/icons/RotateRight.svg index d69e6a7705..7c9da781dc 100644 --- a/editor/icons/RotateRight.svg +++ b/editor/icons/RotateRight.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".99608" transform="matrix(-1 0 0 1 16.026308 -1036.4)"><path d="m9 2a6 6 0 0 0 -6 6h2a4 4 0 0 1 4-4 4 4 0 0 1 4 4 4 4 0 0 1 -4 4v2a6 6 0 0 0 6-6 6 6 0 0 0 -6-6z" transform="translate(0 1036.4)"/><path d="m4.118 1048.3-1.6771-.9683-1.6771-.9682 1.6771-.9683 1.6771-.9682-.0000001 1.9365z" transform="matrix(0 -1.1926 1.5492 0 -1617 1049.3)"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="matrix(-1 0 0 1 16.026308 -1036.4)"><path d="m9 2a6 6 0 0 0 -6 6h2a4 4 0 0 1 4-4 4 4 0 0 1 4 4 4 4 0 0 1 -4 4v2a6 6 0 0 0 6-6 6 6 0 0 0 -6-6z" transform="translate(0 1036.4)"/><path d="m4.118 1048.3-1.6771-.9683-1.6771-.9682 1.6771-.9683 1.6771-.9682-.0000001 1.9365z" transform="matrix(0 -1.1926 1.5492 0 -1617 1049.3)"/></g></svg> diff --git a/editor/icons/Search.svg b/editor/icons/Search.svg index fff4a3cb19..847163d766 100644 --- a/editor/icons/Search.svg +++ b/editor/icons/Search.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a5 5 0 0 0 -5 5 5 5 0 0 0 5 5 5 5 0 0 0 2.7539-.83203l4.3164 4.3164 1.4141-1.4141-4.3164-4.3164a5 5 0 0 0 .83203-2.7539 5 5 0 0 0 -5-5zm0 2a3 3 0 0 1 3 3 3 3 0 0 1 -3 3 3 3 0 0 1 -3-3 3 3 0 0 1 3-3z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a5 5 0 0 0 -5 5 5 5 0 0 0 5 5 5 5 0 0 0 2.7539-.83203l4.3164 4.3164 1.4141-1.4141-4.3164-4.3164a5 5 0 0 0 .83203-2.7539 5 5 0 0 0 -5-5zm0 2a3 3 0 0 1 3 3 3 3 0 0 1 -3 3 3 3 0 0 1 -3-3 3 3 0 0 1 3-3z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/Shortcut.svg b/editor/icons/Shortcut.svg index 4ef16f0401..2e9a69d8b6 100644 --- a/editor/icons/Shortcut.svg +++ b/editor/icons/Shortcut.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 2c-.55228 0-1 .4477-1 1v9.084c.0004015.506.448.91602 1 .91602h8c.552 0 .9996-.41002 1-.91602v-9.084c0-.5523-.44772-1-1-1zm-3 2v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-9h-1v9a.99998.99998 0 0 1 -1 1h-10a1 1 0 0 1 -1-1v-9zm6 0h3l-1 3h2l-4 4 1-3h-2z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 2c-.55228 0-1 .4477-1 1v9.084c.0004015.506.448.91602 1 .91602h8c.552 0 .9996-.41002 1-.91602v-9.084c0-.5523-.44772-1-1-1zm-3 2v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-9h-1v9a.99998.99998 0 0 1 -1 1h-10a1 1 0 0 1 -1-1v-9zm6 0h3l-1 3h2l-4 4 1-3h-2z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/Skeleton3D.svg b/editor/icons/Skeleton3D.svg index f1a1db86a9..19a796c4f1 100644 --- a/editor/icons/Skeleton3D.svg +++ b/editor/icons/Skeleton3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 2a4 4 0 0 0 -4 4 4 4 0 0 0 2 3.4531v3.5469a2 2 0 0 0 1 1.7324 2 2 0 0 0 1 .26562v.001953h4v-.001953a2 2 0 0 0 1-.26562 2 2 0 0 0 1-1.7324v-3.5469a4 4 0 0 0 2-3.4531 4 4 0 0 0 -4-4zm-1 3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-4 2h2v1h-2zm-2 2h1v1h1v-1h1 1v1h1v-1h1v.86719 3.1328h-1v-1h-1v1h-1-1v-1h-1v1h-1v-3.1309-.86914z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 2a4 4 0 0 0 -4 4 4 4 0 0 0 2 3.4531v3.5469a2 2 0 0 0 1 1.7324 2 2 0 0 0 1 .26562v.001953h4v-.001953a2 2 0 0 0 1-.26562 2 2 0 0 0 1-1.7324v-3.5469a4 4 0 0 0 2-3.4531 4 4 0 0 0 -4-4zm-1 3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-4 2h2v1h-2zm-2 2h1v1h1v-1h1 1v1h1v-1h1v.86719 3.1328h-1v-1h-1v1h-1-1v-1h-1v1h-1v-3.1309-.86914z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/SoftBody3D.svg b/editor/icons/SoftBody3D.svg index 7bc9a22c22..1bd2531ce9 100644 --- a/editor/icons/SoftBody3D.svg +++ b/editor/icons/SoftBody3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1s-3 5 0 7-1 7-1 7h13s3-6 0-8 1-6 1-6zm2 2h7s-2 3 1 5 0 5 0 5h-7s2-4-1-6 0-4 0-4z" fill="#fc7f7f" fill-opacity=".996078"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1s-3 5 0 7-1 7-1 7h13s3-6 0-8 1-6 1-6zm2 2h7s-2 3 1 5 0 5 0 5h-7s2-4-1-6 0-4 0-4z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/SpotLight3D.svg b/editor/icons/SpotLight3D.svg index 73b738efcf..27c318257a 100644 --- a/editor/icons/SpotLight3D.svg +++ b/editor/icons/SpotLight3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a1 1 0 0 0 -1 1v3.6934c-1.7861.86608-3 2.4605-3 4.3066h4a2 2 0 0 0 2 2 2 2 0 0 0 2-2h4c0-1.8462-1.2139-3.4406-3-4.3066v-3.6934a1 1 0 0 0 -1-1zm-1.0977 9.6348-1.7324 1 1 1.7305 1.7324-1zm6.1953 0-1 1.7305 1.7324 1 1-1.7305zm-4.0977 2.3652v2h2v-2z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a1 1 0 0 0 -1 1v3.6934c-1.7861.86608-3 2.4605-3 4.3066h4a2 2 0 0 0 2 2 2 2 0 0 0 2-2h4c0-1.8462-1.2139-3.4406-3-4.3066v-3.6934a1 1 0 0 0 -1-1zm-1.0977 9.6348-1.7324 1 1 1.7305 1.7324-1zm6.1953 0-1 1.7305 1.7324 1 1-1.7305zm-4.0977 2.3652v2h2v-2z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/StaticBody3D.svg b/editor/icons/StaticBody3D.svg index 55b061571f..1172fb0821 100644 --- a/editor/icons/StaticBody3D.svg +++ b/editor/icons/StaticBody3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -1.4141.58594 2 2 0 0 0 -.58594 1.4141v10a2 2 0 0 0 .58594 1.4141 2 2 0 0 0 1.4141.58594h10a2 2 0 0 0 2-2v-10a2 2 0 0 0 -2-2h-10zm0 1h10a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-10a1 1 0 0 1 -1-1v-10a1 1 0 0 1 1-1zm0 1v2h2v-2zm8 0v2h2v-2zm-8 8v2h2v-2zm8 0v2h2v-2z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -1.4141.58594 2 2 0 0 0 -.58594 1.4141v10a2 2 0 0 0 .58594 1.4141 2 2 0 0 0 1.4141.58594h10a2 2 0 0 0 2-2v-10a2 2 0 0 0 -2-2h-10zm0 1h10a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-10a1 1 0 0 1 -1-1v-10a1 1 0 0 1 1-1zm0 1v2h2v-2zm8 0v2h2v-2zm-8 8v2h2v-2zm8 0v2h2v-2z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/SubViewport.svg b/editor/icons/SubViewport.svg index 1e17ae234f..d5da67ee53 100644 --- a/editor/icons/SubViewport.svg +++ b/editor/icons/SubViewport.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-.5304.0000801-1.0390625.2108475-1.4140625.5859375-.37509.37501-.5858575.8836225-.5859375 1.4140625v8c.0000803.5304.2108475 1.039063.5859375 1.414062.37501.375091.8836225.585858 1.4140625.585938h10c1.1046 0 2-.89543 2-2v-8c0-1.1046-.89543-2-2-2zm0 1h10c.55228.0000096.99999.44772 1 1v8c-.00001.55228-.44772.99999-1 1h-10c-.55228-.00001-.99999-.44772-1-1v-8c.0000096-.55228.44772-.99999 1-1zm3 1c-.5304.0001-1.0390625.2108375-1.4140625.5859375-.37509.375-.5858575.8836225-.5859375 1.4140625v4c.00008.5304.2108475 1.039062.5859375 1.414062.37501.3751.8836225.585838 1.4140625.585938h4c1.1046 0 2-.8954 2-2v-4c0-1.1046-.89543-2-2-2zm0 1h4c.55228 0 .99999.4477 1 1v4c-.00001.5523-.44772 1-1 1h-4c-.55228 0-.99999-.4477-1-1v-4c.00001-.5523.44772-1 1-1z" fill="#e0e0e0" fill-opacity=".996078"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-.5304.0000801-1.0390625.2108475-1.4140625.5859375-.37509.37501-.5858575.8836225-.5859375 1.4140625v8c.0000803.5304.2108475 1.039063.5859375 1.414062.37501.375091.8836225.585858 1.4140625.585938h10c1.1046 0 2-.89543 2-2v-8c0-1.1046-.89543-2-2-2zm0 1h10c.55228.0000096.99999.44772 1 1v8c-.00001.55228-.44772.99999-1 1h-10c-.55228-.00001-.99999-.44772-1-1v-8c.0000096-.55228.44772-.99999 1-1zm3 1c-.5304.0001-1.0390625.2108375-1.4140625.5859375-.37509.375-.5858575.8836225-.5859375 1.4140625v4c.00008.5304.2108475 1.039062.5859375 1.414062.37501.3751.8836225.585838 1.4140625.585938h4c1.1046 0 2-.8954 2-2v-4c0-1.1046-.89543-2-2-2zm0 1h4c.55228 0 .99999.4477 1 1v4c-.00001.5523-.44772 1-1 1h-4c-.55228 0-.99999-.4477-1-1v-4c.00001-.5523.44772-1 1-1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/Texture2DArray.svg b/editor/icons/Texture2DArray.svg index a71860023b..6d5bf0deb8 100644 --- a/editor/icons/Texture2DArray.svg +++ b/editor/icons/Texture2DArray.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(-.359546 .287637)"><path d="m2 1c-.5522847 0-1 .4477153-1 1v12c0 .552285.4477153 1 1 1h12c.552285 0 1-.447715 1-1v-12c0-.5522847-.447715-1-1-1zm1 2h10v8h-10z" fill-opacity=".99608" transform="translate(.359546 -.287637)"/><g fill-opacity=".996078" stroke-width=".207395" transform="matrix(1.6197742 0 0 .750929 -3.723153 1.832957)"><path d="m4.9900159 2.5027746h1.85211v1.3316838h-.926055v5.3267353h.926055v1.3316833h-1.85211z"/><path d="m9.9289759 10.492877h-1.85211v-1.3316833h.926055v-5.3267353h-.926055v-1.3316838h1.85211z"/></g></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(-.359546 .287637)"><path d="m2 1c-.5522847 0-1 .4477153-1 1v12c0 .552285.4477153 1 1 1h12c.552285 0 1-.447715 1-1v-12c0-.5522847-.447715-1-1-1zm1 2h10v8h-10z" transform="translate(.359546 -.287637)"/><g stroke-width=".207395" transform="matrix(1.6197742 0 0 .750929 -3.723153 1.832957)"><path d="m4.9900159 2.5027746h1.85211v1.3316838h-.926055v5.3267353h.926055v1.3316833h-1.85211z"/><path d="m9.9289759 10.492877h-1.85211v-1.3316833h.926055v-5.3267353h-.926055v-1.3316838h1.85211z"/></g></g></svg> diff --git a/editor/icons/ToolMove.svg b/editor/icons/ToolMove.svg index b83f62265f..8c14b76eba 100644 --- a/editor/icons/ToolMove.svg +++ b/editor/icons/ToolMove.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9844 1.002a1.0001 1.0001 0 0 0 -.69141.29102l-2 2 1.4141 1.4141 1.293-1.293 1.293 1.293 1.4141-1.4141-2-2a1.0001 1.0001 0 0 0 -.72266-.29102zm-4.6914 4.291-2 2a1.0001 1.0001 0 0 0 0 1.4141l2 2 1.4141-1.4141-1.293-1.293 1.293-1.293-1.4141-1.4141zm9.4141 0-1.4141 1.4141 1.293 1.293-1.293 1.293 1.4141 1.4141 2-2a1.0001 1.0001 0 0 0 0-1.4141l-2-2zm-4.707.70703a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-1.293 5.293-1.4141 1.4141 2 2a1.0001 1.0001 0 0 0 1.4141 0l2-2-1.4141-1.4141-1.293 1.293-1.293-1.293z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9844 1.002a1.0001 1.0001 0 0 0 -.69141.29102l-2 2 1.4141 1.4141 1.293-1.293 1.293 1.293 1.4141-1.4141-2-2a1.0001 1.0001 0 0 0 -.72266-.29102zm-4.6914 4.291-2 2a1.0001 1.0001 0 0 0 0 1.4141l2 2 1.4141-1.4141-1.293-1.293 1.293-1.293-1.4141-1.4141zm9.4141 0-1.4141 1.4141 1.293 1.293-1.293 1.293 1.4141 1.4141 2-2a1.0001 1.0001 0 0 0 0-1.4141l-2-2zm-4.707.70703a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-1.293 5.293-1.4141 1.4141 2 2a1.0001 1.0001 0 0 0 1.4141 0l2-2-1.4141-1.4141-1.293 1.293-1.293-1.293z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/ToolPan.svg b/editor/icons/ToolPan.svg index 28ffe6336a..51db68ae74 100644 --- a/editor/icons/ToolPan.svg +++ b/editor/icons/ToolPan.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10 1a1 1 0 0 0 -1 1v6h-1v-5a1 1 0 0 0 -1-1 1 1 0 0 0 -1 1v8 .033203l-2.4746-1.8086c-.52015-.3803-1.1948-.4556-1.6504 0-.45566.4556-.45561 1.1948 0 1.6504l4.125 4.125h6a2 2 0 0 0 2-2v-5-4a1 1 0 0 0 -1-1 1 1 0 0 0 -1 1v4h-1v-6a1 1 0 0 0 -1-1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10 1a1 1 0 0 0 -1 1v6h-1v-5a1 1 0 0 0 -1-1 1 1 0 0 0 -1 1v8 .033203l-2.4746-1.8086c-.52015-.3803-1.1948-.4556-1.6504 0-.45566.4556-.45561 1.1948 0 1.6504l4.125 4.125h6a2 2 0 0 0 2-2v-5-4a1 1 0 0 0 -1-1 1 1 0 0 0 -1 1v4h-1v-6a1 1 0 0 0 -1-1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/ToolRotate.svg b/editor/icons/ToolRotate.svg index 41dd22584d..0fa1904937 100644 --- a/editor/icons/ToolRotate.svg +++ b/editor/icons/ToolRotate.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8.0879 1.002a7 7 0 0 0 -.30469.0019531 7 7 0 0 0 -.69727.056641 7 7 0 0 0 -5.9512 5.5742 7 7 0 0 0 1.9707 6.3652h-1.1055v2h4a1.0001 1.0001 0 0 0 .9707-1.2422l-1-4-1.9414.48633.28125 1.1211a5 5 0 0 1 -1.3105-3.3652 5 5 0 0 1 5-5 5 5 0 0 1 5 5 5 5 0 0 1 -1.4668 3.5332l1.416 1.416a7 7 0 0 0 1.3281-8.0449 7 7 0 0 0 -6.1895-3.9023zm-.087891 4.998a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8.0879 1.002a7 7 0 0 0 -.30469.0019531 7 7 0 0 0 -.69727.056641 7 7 0 0 0 -5.9512 5.5742 7 7 0 0 0 1.9707 6.3652h-1.1055v2h4a1.0001 1.0001 0 0 0 .9707-1.2422l-1-4-1.9414.48633.28125 1.1211a5 5 0 0 1 -1.3105-3.3652 5 5 0 0 1 5-5 5 5 0 0 1 5 5 5 5 0 0 1 -1.4668 3.5332l1.416 1.416a7 7 0 0 0 1.3281-8.0449 7 7 0 0 0 -6.1895-3.9023zm-.087891 4.998a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/ToolScale.svg b/editor/icons/ToolScale.svg index 730143a474..9ebeaffeae 100644 --- a/editor/icons/ToolScale.svg +++ b/editor/icons/ToolScale.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1h2.5859l-1.293 1.293 1.4141 1.4141 1.293-1.293v2.5859a1 1 0 0 0 1 1 1 1 0 0 0 1-1v-5a1.0001 1.0001 0 0 0 -1-1zm-1 5a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-6 2a1 1 0 0 0 -1 1v5a1.0001 1.0001 0 0 0 1 1h5a1 1 0 0 0 1-1 1 1 0 0 0 -1-1h-2.5859l1.293-1.293-1.4141-1.4141-1.293 1.293v-2.5859a1 1 0 0 0 -1-1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1h2.5859l-1.293 1.293 1.4141 1.4141 1.293-1.293v2.5859a1 1 0 0 0 1 1 1 1 0 0 0 1-1v-5a1.0001 1.0001 0 0 0 -1-1zm-1 5a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-6 2a1 1 0 0 0 -1 1v5a1.0001 1.0001 0 0 0 1 1h5a1 1 0 0 0 1-1 1 1 0 0 0 -1-1h-2.5859l1.293-1.293-1.4141-1.4141-1.293 1.293v-2.5859a1 1 0 0 0 -1-1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/TripleBar.svg b/editor/icons/TripleBar.svg index 2b521e6c15..6baea09478 100644 --- a/editor/icons/TripleBar.svg +++ b/editor/icons/TripleBar.svg @@ -1 +1 @@ -<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m1.9375 4h12.062zm0 4h12.062zm0 4h12.062z" fill="none" stroke="#e0e0e0" stroke-opacity=".99608" stroke-width=".92823"/></svg> +<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m1.9375 4h12.062zm0 4h12.062zm0 4h12.062z" fill="none" stroke="#e0e0e0" stroke-width=".92823"/></svg> diff --git a/editor/icons/VehicleBody3D.svg b/editor/icons/VehicleBody3D.svg index 00e4696a17..5e21f40c85 100644 --- a/editor/icons/VehicleBody3D.svg +++ b/editor/icons/VehicleBody3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 3a1 1 0 0 0 -1 1l-1 3h-2v4h1.0508c.23167-1.1411 1.2398-2 2.4492-2s2.2175.85893 2.4492 2h2.1016c.23167-1.1411 1.2398-2 2.4492-2s2.2175.85893 2.4492 2h1.0508v-4h-4v-4zm1 1h4v3h-4zm-1.5 6a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5zm7 0a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 3a1 1 0 0 0 -1 1l-1 3h-2v4h1.0508c.23167-1.1411 1.2398-2 2.4492-2s2.2175.85893 2.4492 2h2.1016c.23167-1.1411 1.2398-2 2.4492-2s2.2175.85893 2.4492 2h1.0508v-4h-4v-4zm1 1h4v3h-4zm-1.5 6a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5zm7 0a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/VehicleWheel3D.svg b/editor/icons/VehicleWheel3D.svg index 4c825d6e34..540bad8ab0 100644 --- a/editor/icons/VehicleWheel3D.svg +++ b/editor/icons/VehicleWheel3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm0 2a5 5 0 0 1 5 5 5 5 0 0 1 -5 5 5 5 0 0 1 -5-5 5 5 0 0 1 5-5zm0 1a4 4 0 0 0 -4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0 -4-4zm0 1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-2 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-2 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm0 2a5 5 0 0 1 5 5 5 5 0 0 1 -5 5 5 5 0 0 1 -5-5 5 5 0 0 1 5-5zm0 1a4 4 0 0 0 -4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0 -4-4zm0 1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-2 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-2 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/Viewport.svg b/editor/icons/Viewport.svg index 7d388c1c6d..9de1e8b05a 100644 --- a/editor/icons/Viewport.svg +++ b/editor/icons/Viewport.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-.5304.0000801-1.0391.21085-1.4141.58594-.37509.37501-.58586.88366-.58594 1.4141v8c.0000803.5304.21085 1.0391.58594 1.4141.37501.37509.88366.58586 1.4141.58594h10c1.1046 0 2-.89543 2-2v-8c0-1.1046-.89543-2-2-2zm0 1h10c.55228.0000096.99999.44772 1 1v8c-.00001.55228-.44772.99999-1 1h-10c-.55228-.00001-.99999-.44772-1-1v-8c.0000096-.55228.44772-.99999 1-1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-.5304.0000801-1.0391.21085-1.4141.58594-.37509.37501-.58586.88366-.58594 1.4141v8c.0000803.5304.21085 1.0391.58594 1.4141.37501.37509.88366.58586 1.4141.58594h10c1.1046 0 2-.89543 2-2v-8c0-1.1046-.89543-2-2-2zm0 1h10c.55228.0000096.99999.44772 1 1v8c-.00001.55228-.44772.99999-1 1h-10c-.55228-.00001-.99999-.44772-1-1v-8c.0000096-.55228.44772-.99999 1-1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/ViewportSpeed.svg b/editor/icons/ViewportSpeed.svg index 57292e2e91..caed3cb1de 100644 --- a/editor/icons/ViewportSpeed.svg +++ b/editor/icons/ViewportSpeed.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-width="3.77953"><path d="m6.0285136 0c-1.0906961 0-2.0000127.90931655-2.0000127 2.0000126v2.3105008c-.3234859-.1927559-.6845858-.3367559-1.0781102-.3223937-1.3171276.048-2.24957487 1.4115024-1.8164032 2.6561764l.9960945 2.9883213c.183927.5526806.6039307.9375116 1.1054741 1.1581986l-2.30275287 1.537096c-.49591181.31937-.83535119.846198-.91211339 1.373102-.07676977.526904.06603212 1.019906.33007748 1.416.26404536.396095.66572598.719811 1.18163158.851603.5153008.131528 1.1318173.02268 1.6171842-.312566h.00195l4.1015433-2.734413.9863434 1.972611c.4415244.884069 1.4843716 1.316372 2.4218832 1.00388l3-.999987-.02929.01134c.570898-.17159 1.048139-.590173 1.265613-1.082078.217466-.491906.208418-1.011893.05664-1.466797-.119282-.357543-.41469-.637606-.728504-.892611.261162-.206362.546142-.39171.681638-.730394.195632-.489109.17105-1.1070991-.08984-1.6289007l-1.000027-2.0011107c-.337916-.6777827-1.033625-1.1077039-1.789039-1.1075905h-.419906c.196645-.3087874.419906-.6128126.419906-.9999874v-3.0000001c0-1.09069605-.909317-2.0000126-2.000012-2.0000126z"/><path d="m6.0285136.99998741c-.5540032 0-.9999874.44598429-.9999874 1.00002519v3.0000001c0 .5540031.4459842.9999874.9999874.9999874h.9999874v.9902362a1.0001008 1.0001008 0 0 0 -.316407.062362l-2.0507716.6835656-.6836032-2.0507717a1.0001008 1.0001008 0 0 0 -.9902362-.6972473 1.0001008 1.0001008 0 0 0 -.9082205 1.328126l.9999874 3.0000001a1.0001008 1.0001008 0 0 0 1.2656126.6328063l1.6835906-.5605418v.6113008c0 .040819.018709.075591.023433.1152757l-4.5781418 3.052762a1.0001008 1.0001008 0 1 0 1.1093669 1.664051l5.05663-3.371112 1.4941228 2.986356a1.0001008 1.0001008 0 0 0 1.210922.501921l3.000001-.999987a1.0001008 1.0001008 0 1 0 -.632807-1.896378l-2.177726.724611-.9746262-1.951182c.275898-.177637.4687372-.472252.4687372-.8261665v-.9999874h1.382815l.722646 1.4472569a1.0001246 1.0001246 0 1 0 1.789077-.8945388l-.999987-1.9999748a1.0001008 1.0001008 0 0 0 -.894539-.5527559h-2.9999995v-.9999874h.9999875c.554003 0 .999987-.4459843.999987-.9999874v-3.0000001c0-.5540409-.445984-1.00002519-.999987-1.00002519zm0 2.00001259h.9999874v2.0000127h-.9999874z" fill="#fff" fill-opacity=".99608"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-width="3.77953"><path d="m6.0285136 0c-1.0906961 0-2.0000127.90931655-2.0000127 2.0000126v2.3105008c-.3234859-.1927559-.6845858-.3367559-1.0781102-.3223937-1.3171276.048-2.24957487 1.4115024-1.8164032 2.6561764l.9960945 2.9883213c.183927.5526806.6039307.9375116 1.1054741 1.1581986l-2.30275287 1.537096c-.49591181.31937-.83535119.846198-.91211339 1.373102-.07676977.526904.06603212 1.019906.33007748 1.416.26404536.396095.66572598.719811 1.18163158.851603.5153008.131528 1.1318173.02268 1.6171842-.312566h.00195l4.1015433-2.734413.9863434 1.972611c.4415244.884069 1.4843716 1.316372 2.4218832 1.00388l3-.999987-.02929.01134c.570898-.17159 1.048139-.590173 1.265613-1.082078.217466-.491906.208418-1.011893.05664-1.466797-.119282-.357543-.41469-.637606-.728504-.892611.261162-.206362.546142-.39171.681638-.730394.195632-.489109.17105-1.1070991-.08984-1.6289007l-1.000027-2.0011107c-.337916-.6777827-1.033625-1.1077039-1.789039-1.1075905h-.419906c.196645-.3087874.419906-.6128126.419906-.9999874v-3.0000001c0-1.09069605-.909317-2.0000126-2.000012-2.0000126z"/><path d="m6.0285136.99998741c-.5540032 0-.9999874.44598429-.9999874 1.00002519v3.0000001c0 .5540031.4459842.9999874.9999874.9999874h.9999874v.9902362a1.0001008 1.0001008 0 0 0 -.316407.062362l-2.0507716.6835656-.6836032-2.0507717a1.0001008 1.0001008 0 0 0 -.9902362-.6972473 1.0001008 1.0001008 0 0 0 -.9082205 1.328126l.9999874 3.0000001a1.0001008 1.0001008 0 0 0 1.2656126.6328063l1.6835906-.5605418v.6113008c0 .040819.018709.075591.023433.1152757l-4.5781418 3.052762a1.0001008 1.0001008 0 1 0 1.1093669 1.664051l5.05663-3.371112 1.4941228 2.986356a1.0001008 1.0001008 0 0 0 1.210922.501921l3.000001-.999987a1.0001008 1.0001008 0 1 0 -.632807-1.896378l-2.177726.724611-.9746262-1.951182c.275898-.177637.4687372-.472252.4687372-.8261665v-.9999874h1.382815l.722646 1.4472569a1.0001246 1.0001246 0 1 0 1.789077-.8945388l-.999987-1.9999748a1.0001008 1.0001008 0 0 0 -.894539-.5527559h-2.9999995v-.9999874h.9999875c.554003 0 .999987-.4459843.999987-.9999874v-3.0000001c0-.5540409-.445984-1.00002519-.999987-1.00002519zm0 2.00001259h.9999874v2.0000127h-.9999874z" fill="#fff"/></g></svg> diff --git a/editor/icons/ViewportTexture.svg b/editor/icons/ViewportTexture.svg index 3dd448b1ac..a5b1e4ab07 100644 --- a/editor/icons/ViewportTexture.svg +++ b/editor/icons/ViewportTexture.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-.5304.0000801-1.0391.21085-1.4141.58594-.37509.37501-.58586.88366-.58594 1.4141v8c.0000803.5304.21085 1.0391.58594 1.4141.37501.37509.88366.58586 1.4141.58594h10c1.1046 0 2-.89543 2-2v-8c0-1.1046-.89543-2-2-2h-10zm0 1h10c.55228.0000096.99999.44772 1 1v8c-.00001.55228-.44772.99999-1 1h-10c-.55228-.00001-.99999-.44772-1-1v-8c.0000096-.55228.44772-.99999 1-1zm6 3v1h-1v1h-2v1h-1v1h-1v1h2 2 2 2v-2h-1v-1-1h-1v-1z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-.5304.0000801-1.0391.21085-1.4141.58594-.37509.37501-.58586.88366-.58594 1.4141v8c.0000803.5304.21085 1.0391.58594 1.4141.37501.37509.88366.58586 1.4141.58594h10c1.1046 0 2-.89543 2-2v-8c0-1.1046-.89543-2-2-2h-10zm0 1h10c.55228.0000096.99999.44772 1 1v8c-.00001.55228-.44772.99999-1 1h-10c-.55228-.00001-.99999-.44772-1-1v-8c.0000096-.55228.44772-.99999 1-1zm6 3v1h-1v1h-2v1h-1v1h-1v1h2 2 2 2v-2h-1v-1-1h-1v-1z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/VisibleOnScreenEnabler3D.svg b/editor/icons/VisibleOnScreenEnabler3D.svg index 6923bcb46b..1c24a348a5 100644 --- a/editor/icons/VisibleOnScreenEnabler3D.svg +++ b/editor/icons/VisibleOnScreenEnabler3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v3h1v-2h2v-1zm11 0v1h2v2h1v-3zm-4 1c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0-.55273c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-7 6v3h3v-1h-2v-2zm13 0v2h-2v1h3v-3z" fill="#fc7f7f" fill-opacity=".99608" fill-rule="evenodd"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v3h1v-2h2v-1zm11 0v1h2v2h1v-3zm-4 1c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0-.55273c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-7 6v3h3v-1h-2v-2zm13 0v2h-2v1h3v-3z" fill="#fc7f7f" fill-rule="evenodd"/></svg> diff --git a/editor/icons/VisibleOnScreenNotifier3D.svg b/editor/icons/VisibleOnScreenNotifier3D.svg index 2fdf784701..f731ae99a2 100644 --- a/editor/icons/VisibleOnScreenNotifier3D.svg +++ b/editor/icons/VisibleOnScreenNotifier3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 1v6h2v-6zm-4 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246 1.4907 0 3.2717-.65207 4.7109-2h-.71094-2v-.54102a4 4 0 0 1 -2 .54102 4 4 0 0 1 -4-4 4 4 0 0 1 4-4 4 4 0 0 1 2 .54102v-2.1816c-.68312-.23834-1.3644-.35938-2-.35938zm0 4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm4 2v2h2v-2z" fill="#fc7f7f" fill-opacity=".99608" fill-rule="evenodd"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 1v6h2v-6zm-4 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246 1.4907 0 3.2717-.65207 4.7109-2h-.71094-2v-.54102a4 4 0 0 1 -2 .54102 4 4 0 0 1 -4-4 4 4 0 0 1 4-4 4 4 0 0 1 2 .54102v-2.1816c-.68312-.23834-1.3644-.35938-2-.35938zm0 4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm4 2v2h2v-2z" fill="#fc7f7f" fill-rule="evenodd"/></svg> diff --git a/editor/icons/VoxelGI.svg b/editor/icons/VoxelGI.svg index f5e1025260..58567569af 100644 --- a/editor/icons/VoxelGI.svg +++ b/editor/icons/VoxelGI.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1.0001 1.0001 0 0 0 -1 1v12a1.0001 1.0001 0 0 0 1 1h4v-2h-3v-10h9v-2zm9 3a4 4 0 0 0 -4 4 4 4 0 0 0 2 3.459v.54102c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1v-.54102a4 4 0 0 0 2-3.459 4 4 0 0 0 -4-4zm0 2a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2zm-1 8v1h2v-1z" fill="#fc7f7f" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1.0001 1.0001 0 0 0 -1 1v12a1.0001 1.0001 0 0 0 1 1h4v-2h-3v-10h9v-2zm9 3a4 4 0 0 0 -4 4 4 4 0 0 0 2 3.459v.54102c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1v-.54102a4 4 0 0 0 2-3.459 4 4 0 0 0 -4-4zm0 2a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2zm-1 8v1h2v-1z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/WorldEnvironment.svg b/editor/icons/WorldEnvironment.svg index d26ec52034..6c7e34657f 100644 --- a/editor/icons/WorldEnvironment.svg +++ b/editor/icons/WorldEnvironment.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm-1.7305 2.3125c-.83125 1.5372-1.2685 3.1037-1.2695 4.6816-.64057-.11251-1.3005-.27158-1.9766-.47266a5 5 0 0 1 3.2461-4.209zm3.4629.0039062a5 5 0 0 1 3.2383 4.1875c-.65187.17448-1.3077.32867-1.9727.44922-.00845-1.5627-.44294-3.1141-1.2656-4.6367zm-1.7324.0078126c1.0126 1.593 1.5 3.1425 1.5 4.6758 0 .054042-.0066161.10803-.0078125.16211-.96392.096801-1.9566.1103-2.9844.027344-.0016335-.063192-.0078125-.12632-.0078125-.18945 0-1.5333.48744-3.0828 1.5-4.6758zm4.8789 5.7578a5 5 0 0 1 -3.1484 3.6055c.57106-1.0564.95277-2.1268 1.1367-3.2051.68204-.10905 1.3556-.23789 2.0117-.40039zm-9.7461.033203c.68377.18153 1.3555.33345 2.0098.43164.18781 1.0551.56647 2.1026 1.125 3.1367a5 5 0 0 1 -3.1348-3.5684zm6.168.55469c-.22615.98866-.65424 1.9884-1.3008 3.0059-.63811-1.0042-1.0645-1.9908-1.293-2.9668.89027.054126 1.7517.029377 2.5938-.039062z" fill="#fc7f7f" fill-opacity=".99608"/><path d="m8 1v2.3242c1.0126 1.593 1.5 3.1425 1.5 4.6758 0 .054042-.0066161.10803-.0078125.16211-.4894.049148-.98713.077552-1.4922.082031v1.4922c.43915-.0075968.87287-.031628 1.3008-.066406-.22615.98866-.65424 1.9884-1.3008 3.0059v2.3242a7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm1.7324 2.3164a5 5 0 0 1 3.2383 4.1875c-.65187.17448-1.3077.32867-1.9727.44922-.00845-1.5627-.44294-3.1141-1.2656-4.6367zm3.1465 5.7656a5 5 0 0 1 -3.1484 3.6055c.57106-1.0564.95277-2.1268 1.1367-3.2051.68204-.10905 1.3556-.23789 2.0117-.40039z" fill="#8da5f3"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm-1.7305 2.3125c-.83125 1.5372-1.2685 3.1037-1.2695 4.6816-.64057-.11251-1.3005-.27158-1.9766-.47266a5 5 0 0 1 3.2461-4.209zm3.4629.0039062a5 5 0 0 1 3.2383 4.1875c-.65187.17448-1.3077.32867-1.9727.44922-.00845-1.5627-.44294-3.1141-1.2656-4.6367zm-1.7324.0078126c1.0126 1.593 1.5 3.1425 1.5 4.6758 0 .054042-.0066161.10803-.0078125.16211-.96392.096801-1.9566.1103-2.9844.027344-.0016335-.063192-.0078125-.12632-.0078125-.18945 0-1.5333.48744-3.0828 1.5-4.6758zm4.8789 5.7578a5 5 0 0 1 -3.1484 3.6055c.57106-1.0564.95277-2.1268 1.1367-3.2051.68204-.10905 1.3556-.23789 2.0117-.40039zm-9.7461.033203c.68377.18153 1.3555.33345 2.0098.43164.18781 1.0551.56647 2.1026 1.125 3.1367a5 5 0 0 1 -3.1348-3.5684zm6.168.55469c-.22615.98866-.65424 1.9884-1.3008 3.0059-.63811-1.0042-1.0645-1.9908-1.293-2.9668.89027.054126 1.7517.029377 2.5938-.039062z" fill="#fc7f7f"/><path d="m8 1v2.3242c1.0126 1.593 1.5 3.1425 1.5 4.6758 0 .054042-.0066161.10803-.0078125.16211-.4894.049148-.98713.077552-1.4922.082031v1.4922c.43915-.0075968.87287-.031628 1.3008-.066406-.22615.98866-.65424 1.9884-1.3008 3.0059v2.3242a7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm1.7324 2.3164a5 5 0 0 1 3.2383 4.1875c-.65187.17448-1.3077.32867-1.9727.44922-.00845-1.5627-.44294-3.1141-1.2656-4.6367zm3.1465 5.7656a5 5 0 0 1 -3.1484 3.6055c.57106-1.0564.95277-2.1268 1.1367-3.2051.68204-.10905 1.3556-.23789 2.0117-.40039z" fill="#8da5f3"/></g></svg> diff --git a/editor/icons/Zoom.svg b/editor/icons/Zoom.svg index fc0102f0e3..6e6462af35 100644 --- a/editor/icons/Zoom.svg +++ b/editor/icons/Zoom.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a5 5 0 0 0 -5 5 5 5 0 0 0 5 5 5 5 0 0 0 2.752-.83398l4.3184 4.3184 1.4141-1.4141-4.3184-4.3184a5 5 0 0 0 .41016-.75195h-.57617v-2h-1a3 3 0 0 1 -3 3 3 3 0 0 1 -3-3 3 3 0 0 1 3-3 3 3 0 0 1 2 .76758v-1.7676h.99023a5 5 0 0 0 -2.9902-1zm5 0v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#e0e0e0" fill-opacity=".99608"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a5 5 0 0 0 -5 5 5 5 0 0 0 5 5 5 5 0 0 0 2.752-.83398l4.3184 4.3184 1.4141-1.4141-4.3184-4.3184a5 5 0 0 0 .41016-.75195h-.57617v-2h-1a3 3 0 0 1 -3 3 3 3 0 0 1 -3-3 3 3 0 0 1 3-3 3 3 0 0 1 2 .76758v-1.7676h.99023a5 5 0 0 0 -2.9902-1zm5 0v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#e0e0e0"/></svg> diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp index a8cd4c3e49..f635c74547 100644 --- a/editor/import/audio_stream_import_settings.cpp +++ b/editor/import/audio_stream_import_settings.cpp @@ -288,17 +288,15 @@ void AudioStreamImportSettings::_draw_indicator() { float preview_len = zoom_bar->get_page(); float beat_size = 60 / float(stream->get_bpm()); int prev_beat = 0; - int last_text_end_x = 0; for (int i = 0; i < rect.size.width; i++) { float ofs = preview_offset + i * preview_len / rect.size.width; int beat = int(ofs / beat_size); if (beat != prev_beat) { String text = itos(beat); int text_w = beat_font->get_string_size(text).width; - if (i - text_w / 2 > last_text_end_x + 2 * EDSCALE && beat == _hovering_beat) { + if (i - text_w / 2 > 2 * EDSCALE && beat == _hovering_beat) { int x_ofs = i - text_w / 2; _indicator->draw_string(beat_font, Point2(x_ofs, 2 * EDSCALE + beat_font->get_ascent(main_size)), text, HORIZONTAL_ALIGNMENT_LEFT, rect.size.width - x_ofs, Font::DEFAULT_FONT_SIZE, color); - last_text_end_x = i + text_w / 2; break; } prev_beat = beat; diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp index c577c61db7..cb2a8205c2 100644 --- a/editor/input_event_configuration_dialog.cpp +++ b/editor/input_event_configuration_dialog.cpp @@ -38,63 +38,6 @@ #include "scene/gui/separator.h" #include "scene/gui/tree.h" -// Maps to 2*axis if value is neg, or 2*axis+1 if value is pos. -static const char *_joy_axis_descriptions[(size_t)JoyAxis::MAX * 2] = { - TTRC("Left Stick Left, Joystick 0 Left"), - TTRC("Left Stick Right, Joystick 0 Right"), - TTRC("Left Stick Up, Joystick 0 Up"), - TTRC("Left Stick Down, Joystick 0 Down"), - TTRC("Right Stick Left, Joystick 1 Left"), - TTRC("Right Stick Right, Joystick 1 Right"), - TTRC("Right Stick Up, Joystick 1 Up"), - TTRC("Right Stick Down, Joystick 1 Down"), - TTRC("Joystick 2 Left"), - TTRC("Left Trigger, Sony L2, Xbox LT, Joystick 2 Right"), - TTRC("Joystick 2 Up"), - TTRC("Right Trigger, Sony R2, Xbox RT, Joystick 2 Down"), - TTRC("Joystick 3 Left"), - TTRC("Joystick 3 Right"), - TTRC("Joystick 3 Up"), - TTRC("Joystick 3 Down"), - TTRC("Joystick 4 Left"), - TTRC("Joystick 4 Right"), - TTRC("Joystick 4 Up"), - TTRC("Joystick 4 Down"), -}; - -String InputEventConfigurationDialog::get_event_text(const Ref<InputEvent> &p_event, bool p_include_device) const { - ERR_FAIL_COND_V_MSG(p_event.is_null(), String(), "Provided event is not a valid instance of InputEvent"); - - String text = p_event->as_text(); - - Ref<InputEventKey> key = p_event; - if (key.is_valid() && key->is_command_or_control_autoremap()) { -#ifdef MACOS_ENABLED - text = text.replace("Command", "Command/Ctrl"); -#else - text = text.replace("Ctrl", "Command/Ctrl"); -#endif - } - Ref<InputEventMouse> mouse = p_event; - Ref<InputEventJoypadMotion> jp_motion = p_event; - Ref<InputEventJoypadButton> jp_button = p_event; - if (jp_motion.is_valid()) { - // Joypad motion events will display slightly differently than what the event->as_text() provides. See #43660. - String desc = TTR("Unknown Joypad Axis"); - if (jp_motion->get_axis() < JoyAxis::MAX) { - desc = RTR(_joy_axis_descriptions[2 * (size_t)jp_motion->get_axis() + (jp_motion->get_axis_value() < 0 ? 0 : 1)]); - } - - text = vformat("Joypad Axis %s %s (%s)", itos((int64_t)jp_motion->get_axis()), jp_motion->get_axis_value() < 0 ? "-" : "+", desc); - } - if (p_include_device && (mouse.is_valid() || jp_button.is_valid() || jp_motion.is_valid())) { - String device_string = _get_device_string(p_event->get_device()); - text += vformat(" - %s", device_string); - } - - return text; -} - void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, bool p_update_input_list_selection) { if (p_event.is_valid()) { event = p_event; @@ -107,7 +50,7 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, b } // Update Label - event_as_text->set_text(get_event_text(event, true)); + event_as_text->set_text(EventListenerLineEdit::get_event_text(event, true)); Ref<InputEventKey> k = p_event; Ref<InputEventMouseButton> mb = p_event; @@ -222,14 +165,7 @@ void InputEventConfigurationDialog::_on_listen_input_changed(const Ref<InputEven } if (joym.is_valid()) { - float axis_value = joym->get_axis_value(); - if (ABS(axis_value) < 0.9) { - // Ignore motion below 0.9 magnitude to avoid accidental touches - return; - } else { - // Always make the value 1 or -1 for display consistency - joym->set_axis_value(SIGN(axis_value)); - } + joym->set_axis_value(SIGN(joym->get_axis_value())); } if (k.is_valid()) { @@ -305,7 +241,7 @@ void InputEventConfigurationDialog::_update_input_list() { Ref<InputEventMouseButton> mb; mb.instantiate(); mb->set_button_index(mouse_buttons[i]); - String desc = get_event_text(mb, false); + String desc = EventListenerLineEdit::get_event_text(mb, false); if (!search_term.is_empty() && desc.findn(search_term) == -1) { continue; @@ -328,7 +264,7 @@ void InputEventConfigurationDialog::_update_input_list() { Ref<InputEventJoypadButton> joyb; joyb.instantiate(); joyb->set_button_index((JoyButton)i); - String desc = get_event_text(joyb, false); + String desc = EventListenerLineEdit::get_event_text(joyb, false); if (!search_term.is_empty() && desc.findn(search_term) == -1) { continue; @@ -354,7 +290,7 @@ void InputEventConfigurationDialog::_update_input_list() { joym.instantiate(); joym->set_axis((JoyAxis)axis); joym->set_axis_value(direction); - String desc = get_event_text(joym, false); + String desc = EventListenerLineEdit::get_event_text(joym, false); if (!search_term.is_empty() && desc.findn(search_term) == -1) { continue; @@ -513,7 +449,7 @@ void InputEventConfigurationDialog::_device_selection_changed(int p_option_butto // Subtract 1 as option index 0 corresponds to "All Devices" (value of -1) // and option index 1 corresponds to device 0, etc... event->set_device(p_option_button_index - 1); - event_as_text->set_text(get_event_text(event, true)); + event_as_text->set_text(EventListenerLineEdit::get_event_text(event, true)); } void InputEventConfigurationDialog::_set_current_device(int p_device) { @@ -524,13 +460,6 @@ int InputEventConfigurationDialog::_get_current_device() const { return device_id_option->get_selected() - 1; } -String InputEventConfigurationDialog::_get_device_string(int p_device) const { - if (p_device == InputMap::ALL_DEVICES) { - return TTR("All Devices"); - } - return TTR("Device") + " " + itos(p_device); -} - void InputEventConfigurationDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { @@ -659,7 +588,7 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() { device_id_option = memnew(OptionButton); device_id_option->set_h_size_flags(Control::SIZE_EXPAND_FILL); for (int i = -1; i < 8; i++) { - device_id_option->add_item(_get_device_string(i)); + device_id_option->add_item(EventListenerLineEdit::get_device_string(i)); } device_id_option->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_device_selection_changed)); _set_current_device(InputMap::ALL_DEVICES); diff --git a/editor/input_event_configuration_dialog.h b/editor/input_event_configuration_dialog.h index fc590cba26..eb6eb485ea 100644 --- a/editor/input_event_configuration_dialog.h +++ b/editor/input_event_configuration_dialog.h @@ -105,7 +105,6 @@ private: void _device_selection_changed(int p_option_button_index); void _set_current_device(int p_device); int _get_current_device() const; - String _get_device_string(int p_device) const; protected: void _notification(int p_what); @@ -114,7 +113,6 @@ public: // Pass an existing event to configure it. Alternatively, pass no event to start with a blank configuration. void popup_and_configure(const Ref<InputEvent> &p_event = Ref<InputEvent>()); Ref<InputEvent> get_event() const; - String get_event_text(const Ref<InputEvent> &p_event, bool p_include_device) const; void set_allowed_input_types(int p_type_masks); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index bd2eb5fd9e..8cb0e4e8d7 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -365,7 +365,7 @@ void InspectorDock::_select_history(int p_idx) { } void InspectorDock::_resource_created() { - Variant c = new_resource_dialog->instance_selected(); + Variant c = new_resource_dialog->instantiate_selected(); ERR_FAIL_COND(!c); Resource *r = Object::cast_to<Resource>(c); @@ -670,14 +670,14 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { backward_button = memnew(Button); backward_button->set_flat(true); general_options_hb->add_child(backward_button); - backward_button->set_tooltip_text(TTR("Go to the previous edited object in history.")); + backward_button->set_tooltip_text(TTR("Go to previous edited object in history.")); backward_button->set_disabled(true); backward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_back)); forward_button = memnew(Button); forward_button->set_flat(true); general_options_hb->add_child(forward_button); - forward_button->set_tooltip_text(TTR("Go to the next edited object in history.")); + forward_button->set_tooltip_text(TTR("Go to next edited object in history.")); forward_button->set_disabled(true); forward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_forward)); diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index f16a6bfa88..d11217cc5e 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -69,7 +69,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven menu->add_submenu_item(TTR("Add Animation"), "animations"); - AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree(); + AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_animation_tree(); ERR_FAIL_COND(!gp); if (gp->has_node(gp->get_animation_player())) { @@ -177,7 +177,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); blend_pos += blend_space->get_min_space(); - AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos); + AnimationTreeEditor::get_singleton()->get_animation_tree()->set(get_blend_position_path(), blend_pos); blend_space_draw->queue_redraw(); } @@ -200,7 +200,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); blend_pos += blend_space->get_min_space(); - AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos); + AnimationTreeEditor::get_singleton()->get_animation_tree()->set(get_blend_position_path(), blend_pos); blend_space_draw->queue_redraw(); } @@ -298,7 +298,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { color.a *= 0.5; } - float point = AnimationTreeEditor::get_singleton()->get_tree()->get(get_blend_position_path()); + float point = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(get_blend_position_path()); point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); point *= s.width; @@ -568,10 +568,10 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) { case NOTIFICATION_PROCESS: { String error; - if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) { + if (!AnimationTreeEditor::get_singleton()->get_animation_tree()->is_active()) { error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) { - error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason(); + } else if (AnimationTreeEditor::get_singleton()->get_animation_tree()->is_state_invalid()) { + error = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_invalid_state_reason(); } if (error != error_label->get_text()) { diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 3ec8324e1d..0adac598a6 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -115,7 +115,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); menu->add_submenu_item(TTR("Add Animation"), "animations"); - AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree(); + AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_animation_tree(); ERR_FAIL_COND(!gp); if (gp && gp->has_node(gp->get_animation_player())) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); @@ -270,7 +270,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); blend_pos += blend_space->get_min_space(); - AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos); + AnimationTreeEditor::get_singleton()->get_animation_tree()->set(get_blend_position_path(), blend_pos); blend_space_draw->queue_redraw(); } @@ -306,7 +306,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); blend_pos += blend_space->get_min_space(); - AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos); + AnimationTreeEditor::get_singleton()->get_animation_tree()->set(get_blend_position_path(), blend_pos); blend_space_draw->queue_redraw(); } @@ -589,7 +589,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { color.a *= 0.5; } - Vector2 blend_pos = AnimationTreeEditor::get_singleton()->get_tree()->get(get_blend_position_path()); + Vector2 blend_pos = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(get_blend_position_path()); Vector2 point = blend_pos; point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); @@ -797,12 +797,12 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { case NOTIFICATION_PROCESS: { String error; - if (!AnimationTreeEditor::get_singleton()->get_tree()) { + if (!AnimationTreeEditor::get_singleton()->get_animation_tree()) { error = TTR("BlendSpace2D does not belong to an AnimationTree node."); - } else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) { + } else if (!AnimationTreeEditor::get_singleton()->get_animation_tree()->is_active()) { error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) { - error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason(); + } else if (AnimationTreeEditor::get_singleton()->get_animation_tree()->is_state_invalid()) { + error = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_invalid_state_reason(); } else if (blend_space->get_triangle_count() == 0) { error = TTR("No triangles exist, so no blending can take place."); } diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 6d00e77a4b..1a4774b98b 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -96,7 +96,7 @@ Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const { } void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) { - AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_tree(); + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); updating = true; undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS); undo_redo->add_do_property(tree, p_property, p_value); @@ -174,10 +174,10 @@ void AnimationNodeBlendTreeEditor::update_graph() { continue; } String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name; - EditorProperty *prop = EditorInspector::instantiate_property_editor(AnimationTreeEditor::get_singleton()->get_tree(), F.type, base_path, F.hint, F.hint_string, F.usage); + EditorProperty *prop = EditorInspector::instantiate_property_editor(AnimationTreeEditor::get_singleton()->get_animation_tree(), F.type, base_path, F.hint, F.hint_string, F.usage); if (prop) { prop->set_read_only(read_only); - prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_tree(), base_path); + prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_animation_tree(), base_path); prop->update_property(); prop->set_name_split_ratio(0); prop->connect("property_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_property_changed)); @@ -225,7 +225,7 @@ void AnimationNodeBlendTreeEditor::update_graph() { ProgressBar *pb = memnew(ProgressBar); - AnimationTree *player = AnimationTreeEditor::get_singleton()->get_tree(); + AnimationTree *player = AnimationTreeEditor::get_singleton()->get_animation_tree(); if (player->has_node(player->get_animation_player())) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(player->get_node(player->get_animation_player())); if (ap) { @@ -589,14 +589,14 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano return false; } - NodePath player_path = AnimationTreeEditor::get_singleton()->get_tree()->get_animation_player(); + NodePath player_path = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_animation_player(); - if (!AnimationTreeEditor::get_singleton()->get_tree()->has_node(player_path)) { + if (!AnimationTreeEditor::get_singleton()->get_animation_tree()->has_node(player_path)) { EditorNode::get_singleton()->show_warning(TTR("No animation player set, so unable to retrieve track names.")); return false; } - AnimationPlayer *player = Object::cast_to<AnimationPlayer>(AnimationTreeEditor::get_singleton()->get_tree()->get_node(player_path)); + AnimationPlayer *player = Object::cast_to<AnimationPlayer>(AnimationTreeEditor::get_singleton()->get_animation_tree()->get_node(player_path)); if (!player) { EditorNode::get_singleton()->show_warning(TTR("Player path set is invalid, so unable to retrieve track names.")); return false; @@ -829,10 +829,10 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { case NOTIFICATION_PROCESS: { String error; - if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) { + if (!AnimationTreeEditor::get_singleton()->get_animation_tree()->is_active()) { error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) { - error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason(); + } else if (AnimationTreeEditor::get_singleton()->get_animation_tree()->is_state_invalid()) { + error = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_invalid_state_reason(); } if (error != error_label->get_text()) { @@ -849,13 +849,13 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { for (const AnimationNodeBlendTree::NodeConnection &E : conns) { float activity = 0; StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node; - if (AnimationTreeEditor::get_singleton()->get_tree() && !AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) { - activity = AnimationTreeEditor::get_singleton()->get_tree()->get_connection_activity(path, E.input_index); + if (AnimationTreeEditor::get_singleton()->get_animation_tree() && !AnimationTreeEditor::get_singleton()->get_animation_tree()->is_state_invalid()) { + activity = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_connection_activity(path, E.input_index); } graph->set_connection_activity(E.output_node, 0, E.input_node, E.input_index, activity); } - AnimationTree *graph_player = AnimationTreeEditor::get_singleton()->get_tree(); + AnimationTree *graph_player = AnimationTreeEditor::get_singleton()->get_animation_tree(); AnimationPlayer *player = nullptr; if (graph_player->has_node(graph_player->get_animation_player())) { player = Object::cast_to<AnimationPlayer>(graph_player->get_node(graph_player->get_animation_player())); @@ -871,7 +871,7 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { E.value->set_max(anim->get_length()); //StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node; StringName time_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E.key) + "/time"; - E.value->set_value(AnimationTreeEditor::get_singleton()->get_tree()->get(time_path)); + E.value->set_value(AnimationTreeEditor::get_singleton()->get_animation_tree()->get(time_path)); } } } @@ -952,8 +952,8 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima undo_redo->create_action(TTR("Node Renamed")); undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name); undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name); - undo_redo->add_do_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + prev_name, base_path + name); - undo_redo->add_undo_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + name, base_path + prev_name); + undo_redo->add_do_method(AnimationTreeEditor::get_singleton()->get_animation_tree(), "rename_parameter", base_path + prev_name, base_path + name); + undo_redo->add_undo_method(AnimationTreeEditor::get_singleton()->get_animation_tree(), "rename_parameter", base_path + name, base_path + prev_name); undo_redo->add_do_method(this, "update_graph"); undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index cc709182a8..060e9d0d10 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -76,7 +76,7 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) { } void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) { - Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); + Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); if (playback.is_null()) { return; } @@ -739,7 +739,7 @@ void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) { ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); menu->add_submenu_item(TTR("Add Animation"), "animations"); - AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree(); + AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_animation_tree(); ERR_FAIL_COND(!gp); if (gp && gp->has_node(gp->get_animation_player())) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); @@ -1181,7 +1181,7 @@ void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(const Vector2 &p_fr } void AnimationNodeStateMachineEditor::_state_machine_draw() { - Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); + Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); Ref<StyleBoxFlat> style = get_theme_stylebox(SNAME("state_machine_frame"), SNAME("GraphNode")); Ref<StyleBoxFlat> style_selected = get_theme_stylebox(SNAME("state_machine_selected_frame"), SNAME("GraphNode")); @@ -1369,7 +1369,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { } StringName fullpath = AnimationTreeEditor::get_singleton()->get_base_path() + String(tl.advance_condition_name); - if (tl.advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(fullpath))) { + if (tl.advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_animation_tree()->get(fullpath))) { tl.advance_condition_state = true; tl.auto_advance = true; } @@ -1484,7 +1484,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { } void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { - Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); + Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); if (!playback.is_valid() || !playback->is_playing()) { return; @@ -1578,15 +1578,15 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { case NOTIFICATION_PROCESS: { String error; - Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); + Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); if (error_time > 0) { error = error_text; error_time -= get_process_delta_time(); - } else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) { + } else if (!AnimationTreeEditor::get_singleton()->get_animation_tree()->is_active()) { error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) { - error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason(); + } else if (AnimationTreeEditor::get_singleton()->get_animation_tree()->is_state_invalid()) { + error = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_invalid_state_reason(); /*} else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) { if (state_machine->get_start_node() == StringName() || state_machine->get_end_node() == StringName()) { error = TTR("Start and end nodes are needed for a sub-transition."); @@ -1638,7 +1638,7 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { break; } - bool acstate = transition_lines[i].advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + String(transition_lines[i].advance_condition_name))); + bool acstate = transition_lines[i].advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + String(transition_lines[i].advance_condition_name))); if (transition_lines[i].advance_condition_state != acstate) { state_machine_draw->queue_redraw(); @@ -1693,7 +1693,7 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { Ref<AnimationNodeStateMachinePlayback> current_node_playback; while (anodesm.is_valid()) { - current_node_playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + next + "/playback"); + current_node_playback = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + next + "/playback"); next += "/" + current_node_playback->get_current_node(); anodesm = anodesm->get_node(current_node_playback->get_current_node()); } diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index 1de4fbaabc..61aa861a3f 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -74,6 +74,12 @@ void AnimationTreeEditor::edit(AnimationTree *p_tree) { edit_path(path); } +void AnimationTreeEditor::_node_removed(Node *p_node) { + if (p_node == tree) { + tree = nullptr; + } +} + void AnimationTreeEditor::_path_button_pressed(int p_path) { edited_path.clear(); for (int i = 0; i <= p_path; i++) { @@ -167,6 +173,9 @@ void AnimationTreeEditor::enter_editor(const String &p_path) { void AnimationTreeEditor::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + get_tree()->connect("node_removed", callable_mp(this, &AnimationTreeEditor::_node_removed)); + } break; case NOTIFICATION_PROCESS: { ObjectID root; if (tree && tree->get_tree_root().is_valid()) { @@ -181,6 +190,9 @@ void AnimationTreeEditor::_notification(int p_what) { edit_path(edited_path); } } break; + case NOTIFICATION_EXIT_TREE: { + get_tree()->disconnect("node_removed", callable_mp(this, &AnimationTreeEditor::_node_removed)); + } break; } } diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h index 9ef9fff8cd..e1d9536f03 100644 --- a/editor/plugins/animation_tree_editor_plugin.h +++ b/editor/plugins/animation_tree_editor_plugin.h @@ -35,8 +35,6 @@ #include "scene/animation/animation_tree.h" #include "scene/gui/button.h" #include "scene/gui/graph_edit.h" -#include "scene/gui/popup.h" -#include "scene/gui/tree.h" class EditorFileDialog; @@ -71,12 +69,13 @@ class AnimationTreeEditor : public VBoxContainer { protected: void _notification(int p_what); + void _node_removed(Node *p_node); static void _bind_methods(); static AnimationTreeEditor *singleton; public: - AnimationTree *get_tree() { return tree; } + AnimationTree *get_animation_tree() { return tree; } void add_plugin(AnimationTreeNodeEditorPlugin *p_editor); void remove_plugin(AnimationTreeNodeEditorPlugin *p_editor); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 51b65e8eb0..72bee901bf 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -65,13 +65,13 @@ void EditorAssetLibraryItem::set_image(int p_type, int p_index, const Ref<Textur ERR_FAIL_COND(p_type != EditorAssetLibrary::IMAGE_QUEUE_ICON); ERR_FAIL_COND(p_index != 0); - icon->set_normal_texture(p_image); + icon->set_texture_normal(p_image); } void EditorAssetLibraryItem::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - icon->set_normal_texture(get_theme_icon(SNAME("ProjectIconLoading"), SNAME("EditorIcons"))); + icon->set_texture_normal(get_theme_icon(SNAME("ProjectIconLoading"), SNAME("EditorIcons"))); category->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5)); author->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5)); price->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5)); @@ -402,7 +402,7 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("AssetLib"))); status->add_theme_color_override("font_color", get_theme_color(SNAME("status_color"), SNAME("AssetLib"))); - dismiss_button->set_normal_texture(get_theme_icon(SNAME("dismiss"), SNAME("AssetLib"))); + dismiss_button->set_texture_normal(get_theme_icon(SNAME("dismiss"), SNAME("AssetLib"))); } break; case NOTIFICATION_PROCESS: { diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index c834e0e93e..9ceedb18b3 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -38,9 +38,9 @@ void BoneMapperButton::fetch_textures() { if (selected) { - set_normal_texture(get_theme_icon(SNAME("BoneMapperHandleSelected"), SNAME("EditorIcons"))); + set_texture_normal(get_theme_icon(SNAME("BoneMapperHandleSelected"), SNAME("EditorIcons"))); } else { - set_normal_texture(get_theme_icon(SNAME("BoneMapperHandle"), SNAME("EditorIcons"))); + set_texture_normal(get_theme_icon(SNAME("BoneMapperHandle"), SNAME("EditorIcons"))); } set_offset(SIDE_LEFT, 0); set_offset(SIDE_RIGHT, 0); @@ -742,7 +742,6 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) { } else { p_bone_map->_set_skeleton_bone_name("LeftEye", skeleton->get_bone_name(bone_idx)); } - bone_idx = -1; bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, neck_or_head); if (bone_idx == -1) { @@ -750,7 +749,6 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) { } else { p_bone_map->_set_skeleton_bone_name("RightEye", skeleton->get_bone_name(bone_idx)); } - bone_idx = -1; picklist.clear(); // 4-2. Guess Jaw diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 5584b0299c..0fe77ec400 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -5624,13 +5624,13 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons } Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); - if (!instantiated_scene) { // error on instancing + if (!instantiated_scene) { // Error on instantiation. return false; } Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); - if (!edited_scene->get_scene_file_path().is_empty()) { // cyclical instancing + if (!edited_scene->get_scene_file_path().is_empty()) { // Cyclic instantiation. if (_cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) { memdelete(instantiated_scene); return false; @@ -5647,7 +5647,7 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons String new_name = parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - undo_redo->add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), path, new_name); + undo_redo->add_do_method(ed, "live_debug_instantiate_node", edited_scene->get_path_to(parent), path, new_name); undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name)); CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instantiated_scene); @@ -5720,7 +5720,7 @@ void CanvasItemEditorViewport::_perform_drop_data() { files_str += error_files[i].get_file().get_basename() + ","; } files_str = files_str.substr(0, files_str.length() - 1); - accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.get_data())); + accept->set_text(vformat(TTR("Error instantiating scene from %s"), files_str.get_data())); accept->popup_centered(); } } diff --git a/editor/plugins/gradient_editor.cpp b/editor/plugins/gradient_editor.cpp index f6d5adcd68..c466a82f7d 100644 --- a/editor/plugins/gradient_editor.cpp +++ b/editor/plugins/gradient_editor.cpp @@ -57,7 +57,7 @@ int GradientEditor::_get_point_from_pos(int x) { for (int i = 0; i < points.size(); i++) { // Check if we clicked at point. float distance = ABS(x - points[i].offset * total_w); - float min = (draw_point_width / 2 * 1.7); //make it easier to grab + float min = (handle_width / 2 * 1.7); // Make it easier to grab. if (distance <= min && distance < min_distance) { result = i; min_distance = distance; @@ -397,7 +397,7 @@ void GradientEditor::_notification(int p_what) { } case NOTIFICATION_THEME_CHANGED: { draw_spacing = BASE_SPACING * get_theme_default_base_scale(); - draw_point_width = BASE_POINT_WIDTH * get_theme_default_base_scale(); + handle_width = BASE_HANDLE_WIDTH * get_theme_default_base_scale(); } break; case NOTIFICATION_DRAW: { @@ -408,32 +408,38 @@ void GradientEditor::_notification(int p_what) { return; // Safety check. We have division by 'h'. And in any case there is nothing to draw with such size. } - int total_w = get_size().width - get_size().height - draw_spacing; + int total_w = get_size().width - get_size().height - draw_spacing - handle_width; // Draw checker pattern for ramp. - draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(0, 0, total_w, h), true); + draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(handle_width / 2, 0, total_w, h), true); // Draw color ramp. gradient_cache->set_points(points); gradient_cache->set_interpolation_mode(interpolation_mode); preview_texture->set_gradient(gradient_cache); - draw_texture_rect(preview_texture, Rect2(0, 0, total_w, h)); + draw_texture_rect(preview_texture, Rect2(handle_width / 2, 0, total_w, h)); + + // Draw borders around color ramp if in focus. + if (has_focus()) { + draw_rect(Rect2(handle_width / 2, 0, total_w, h), Color(1, 1, 1, 0.9), false); + } // Draw point markers. for (int i = 0; i < points.size(); i++) { - Color col = points[i].color.inverted(); + Color col = points[i].color.get_v() > 0.5 ? Color(0, 0, 0) : Color(1, 1, 1); col.a = 0.9; - draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col); - Rect2 rect = Rect2(points[i].offset * total_w - draw_point_width / 2, h / 2, draw_point_width, h / 2); + draw_line(Vector2(points[i].offset * total_w + handle_width / 2, 0), Vector2(points[i].offset * total_w + handle_width / 2, h / 2), col); + Rect2 rect = Rect2(points[i].offset * total_w, h / 2, handle_width, h / 2); draw_rect(rect, points[i].color, true); draw_rect(rect, col, false); if (grabbed == i) { + const Color focus_color = get_theme_color(SNAME("accent_color"), SNAME("Editor")); rect = rect.grow(-1); if (has_focus()) { - draw_rect(rect, Color(1, 0, 0, 0.9), false); + draw_rect(rect, focus_color, false); } else { - draw_rect(rect, Color(0.6, 0, 0, 0.9), false); + draw_rect(rect, focus_color.darkened(0.4), false); } rect = rect.grow(-1); @@ -442,23 +448,16 @@ void GradientEditor::_notification(int p_what) { } // Draw "button" for color selector. - draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + draw_spacing, 0, h, h), true); + int button_offset = total_w + handle_width + draw_spacing; + draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(button_offset, 0, h, h), true); if (grabbed != -1) { // Draw with selection color. - draw_rect(Rect2(total_w + draw_spacing, 0, h, h), points[grabbed].color); + draw_rect(Rect2(button_offset, 0, h, h), points[grabbed].color); } else { // If no color selected draw grey color with 'X' on top. - draw_rect(Rect2(total_w + draw_spacing, 0, h, h), Color(0.5, 0.5, 0.5, 1)); - draw_line(Vector2(total_w + draw_spacing, 0), Vector2(total_w + draw_spacing + h, h), Color(1, 1, 1, 0.6)); - draw_line(Vector2(total_w + draw_spacing, h), Vector2(total_w + draw_spacing + h, 0), Color(1, 1, 1, 0.6)); - } - - // Draw borders around color ramp if in focus. - if (has_focus()) { - draw_line(Vector2(-1, -1), Vector2(total_w + 1, -1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(total_w + 1, -1), Vector2(total_w + 1, h + 1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(total_w + 1, h + 1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(-1, -1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); + draw_rect(Rect2(button_offset, 0, h, h), Color(0.5, 0.5, 0.5, 1)); + draw_line(Vector2(button_offset, 0), Vector2(button_offset + h, h), Color(1, 1, 1, 0.6)); + draw_line(Vector2(button_offset, h), Vector2(button_offset + h, 0), Color(1, 1, 1, 0.6)); } } break; diff --git a/editor/plugins/gradient_editor.h b/editor/plugins/gradient_editor.h index 816b539ba2..f27cd8a188 100644 --- a/editor/plugins/gradient_editor.h +++ b/editor/plugins/gradient_editor.h @@ -53,10 +53,10 @@ class GradientEditor : public Control { // Make sure to use the scaled value below. const int BASE_SPACING = 3; - const int BASE_POINT_WIDTH = 8; + const int BASE_HANDLE_WIDTH = 8; int draw_spacing = BASE_SPACING; - int draw_point_width = BASE_POINT_WIDTH; + int handle_width = BASE_HANDLE_WIDTH; void _gradient_changed(); void _ramp_changed(); diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index fe7713f175..759c1c967d 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -72,15 +72,15 @@ void MaterialEditor::_update_theme_item_cache() { void MaterialEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - light_1_switch->set_normal_texture(theme_cache.light_1_on); - light_1_switch->set_pressed_texture(theme_cache.light_1_off); - light_2_switch->set_normal_texture(theme_cache.light_2_on); - light_2_switch->set_pressed_texture(theme_cache.light_2_off); - - sphere_switch->set_normal_texture(theme_cache.sphere_off); - sphere_switch->set_pressed_texture(theme_cache.sphere_on); - box_switch->set_normal_texture(theme_cache.box_off); - box_switch->set_pressed_texture(theme_cache.box_on); + light_1_switch->set_texture_normal(theme_cache.light_1_on); + light_1_switch->set_texture_pressed(theme_cache.light_1_off); + light_2_switch->set_texture_normal(theme_cache.light_2_on); + light_2_switch->set_texture_pressed(theme_cache.light_2_off); + + sphere_switch->set_texture_normal(theme_cache.sphere_off); + sphere_switch->set_texture_pressed(theme_cache.sphere_on); + box_switch->set_texture_normal(theme_cache.box_off); + box_switch->set_texture_pressed(theme_cache.box_on); } break; case NOTIFICATION_DRAW: { diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index be26baaea5..57dc92a9ee 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -61,10 +61,10 @@ void MeshEditor::_update_theme_item_cache() { void MeshEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - light_1_switch->set_normal_texture(theme_cache.light_1_on); - light_1_switch->set_pressed_texture(theme_cache.light_1_off); - light_2_switch->set_normal_texture(theme_cache.light_2_on); - light_2_switch->set_pressed_texture(theme_cache.light_2_off); + light_1_switch->set_texture_normal(theme_cache.light_1_on); + light_1_switch->set_texture_pressed(theme_cache.light_1_off); + light_2_switch->set_texture_normal(theme_cache.light_2_on); + light_2_switch->set_texture_pressed(theme_cache.light_2_off); } break; } } diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 5929807f98..ca6d65bd57 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -4039,7 +4039,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po return false; } - if (!EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path().is_empty()) { // cyclical instancing + if (!EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path().is_empty()) { // Cyclic instantiation. if (_cyclical_dependency_exists(EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path(), instantiated_scene)) { memdelete(instantiated_scene); return false; @@ -4058,7 +4058,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po String new_name = parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - undo_redo->add_do_method(ed, "live_debug_instance_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name); + undo_redo->add_do_method(ed, "live_debug_instantiate_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name); undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); Node3D *node3d = Object::cast_to<Node3D>(instantiated_scene); @@ -4129,7 +4129,7 @@ void Node3DEditorViewport::_perform_drop_data() { files_str += error_files[i].get_file().get_basename() + ","; } files_str = files_str.substr(0, files_str.length() - 1); - accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.get_data())); + accept->set_text(vformat(TTR("Error instantiating scene from %s"), files_str.get_data())); accept->popup_centered(); } } diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp index a38a040814..596b2c0edb 100644 --- a/editor/plugins/root_motion_editor_plugin.cpp +++ b/editor/plugins/root_motion_editor_plugin.cpp @@ -47,8 +47,6 @@ void EditorPropertyRootMotion::_confirmed() { } void EditorPropertyRootMotion::_node_assign() { - NodePath current = get_edited_object()->get(get_edited_property()); - AnimationTree *atree = Object::cast_to<AnimationTree>(get_edited_object()); if (!atree->has_node(atree->get_animation_player())) { EditorNode::get_singleton()->show_warning(TTR("AnimationTree has no path set to an AnimationPlayer")); @@ -75,7 +73,10 @@ void EditorPropertyRootMotion::_node_assign() { for (const StringName &E : animations) { Ref<Animation> anim = player->get_animation(E); for (int i = 0; i < anim->get_track_count(); i++) { - paths.insert(anim->track_get_path(i)); + String pathname = anim->track_get_path(i).get_concatenated_names(); + if (!paths.has(pathname)) { + paths.insert(pathname); + } } } } @@ -124,66 +125,33 @@ void EditorPropertyRootMotion::_node_assign() { continue; //no node, can't edit } - if (path.get_subname_count()) { - String concat = path.get_concatenated_subnames(); - - Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); - if (skeleton && skeleton->find_bone(concat) != -1) { - //path in skeleton - const String &bone = concat; - int idx = skeleton->find_bone(bone); - List<String> bone_path; - while (idx != -1) { - bone_path.push_front(skeleton->get_bone_name(idx)); - idx = skeleton->get_bone_parent(idx); + Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); + if (skeleton) { + HashMap<int, TreeItem *> items; + items.insert(-1, ti); + Ref<Texture> bone_icon = get_theme_icon(SNAME("BoneAttachment3D"), SNAME("EditorIcons")); + Vector<int> bones_to_process = skeleton->get_parentless_bones(); + while (bones_to_process.size() > 0) { + int current_bone_idx = bones_to_process[0]; + bones_to_process.erase(current_bone_idx); + + Vector<int> current_bone_child_bones = skeleton->get_bone_children(current_bone_idx); + int child_bone_size = current_bone_child_bones.size(); + for (int i = 0; i < child_bone_size; i++) { + bones_to_process.push_back(current_bone_child_bones[i]); } - accum += ":"; - for (List<String>::Element *F = bone_path.front(); F; F = F->next()) { - if (F != bone_path.front()) { - accum += "/"; - } - - accum += F->get(); - if (!parenthood.has(accum)) { - ti = filters->create_item(ti); - parenthood[accum] = ti; - ti->set_text(0, F->get()); - ti->set_selectable(0, true); - ti->set_editable(0, false); - ti->set_icon(0, get_theme_icon(SNAME("BoneAttachment3D"), SNAME("EditorIcons"))); - ti->set_metadata(0, accum); - } else { - ti = parenthood[accum]; - } - } + const int parent_idx = skeleton->get_bone_parent(current_bone_idx); + TreeItem *parent_item = items.find(parent_idx)->value; - ti->set_selectable(0, true); - ti->set_text(0, concat); - ti->set_icon(0, get_theme_icon(SNAME("BoneAttachment3D"), SNAME("EditorIcons"))); - ti->set_metadata(0, path); - if (path == current) { - ti->select(0); - } + TreeItem *joint_item = filters->create_item(parent_item); + items.insert(current_bone_idx, joint_item); - } else { - //just a property - ti = filters->create_item(ti); - ti->set_text(0, concat); - ti->set_selectable(0, true); - ti->set_metadata(0, path); - if (path == current) { - ti->select(0); - } - } - } else { - if (ti) { - //just a node, likely call or animation track - ti->set_selectable(0, true); - ti->set_metadata(0, path); - if (path == current) { - ti->select(0); - } + joint_item->set_text(0, skeleton->get_bone_name(current_bone_idx)); + joint_item->set_icon(0, bone_icon); + joint_item->set_selectable(0, true); + joint_item->set_metadata(0, accum + ":" + skeleton->get_bone_name(current_bone_idx)); + joint_item->set_collapsed(true); } } } @@ -199,7 +167,6 @@ void EditorPropertyRootMotion::_node_clear() { void EditorPropertyRootMotion::update_property() { NodePath p = get_edited_object()->get(get_edited_property()); - assign->set_tooltip_text(p); if (p == NodePath()) { assign->set_icon(Ref<Texture2D>()); @@ -208,26 +175,8 @@ void EditorPropertyRootMotion::update_property() { return; } - Node *base_node = nullptr; - if (base_hint != NodePath()) { - if (get_tree()->get_root()->has_node(base_hint)) { - base_node = get_tree()->get_root()->get_node(base_hint); - } - } else { - base_node = Object::cast_to<Node>(get_edited_object()); - } - - if (!base_node || !base_node->has_node(p)) { - assign->set_icon(Ref<Texture2D>()); - assign->set_text(p); - return; - } - - Node *target_node = base_node->get_node(p); - ERR_FAIL_COND(!target_node); - - assign->set_text(target_node->get_name()); - assign->set_icon(EditorNode::get_singleton()->get_object_icon(target_node, "Node")); + assign->set_icon(Ref<Texture2D>()); + assign->set_text(p); } void EditorPropertyRootMotion::setup(const NodePath &p_base_hint) { @@ -282,9 +231,6 @@ bool EditorInspectorRootMotionPlugin::can_handle(Object *p_object) { bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { if (p_path == "root_motion_track" && p_object->is_class("AnimationTree") && p_type == Variant::NODE_PATH) { EditorPropertyRootMotion *editor = memnew(EditorPropertyRootMotion); - if (p_hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && !p_hint_text.is_empty()) { - editor->setup(p_hint_text); - } add_property_editor(p_path, editor); return true; } diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 0d12d07aa7..4e66dc3d7e 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1860,7 +1860,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { if (valid) { color_args = line.substr(begin, end - begin); String stripped = color_args.replace(" ", "").replace("(", "").replace(")", ""); - Vector<float> color = stripped.split_floats(","); + PackedFloat64Array color = stripped.split_floats(","); if (color.size() > 2) { float alpha = color.size() > 3 ? color[3] : 1.0f; color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha)); diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp index 4874944d33..dd644cb369 100644 --- a/editor/plugins/shader_file_editor_plugin.cpp +++ b/editor/plugins/shader_file_editor_plugin.cpp @@ -286,6 +286,7 @@ ShaderFileEditor::ShaderFileEditor() { error_text = memnew(RichTextLabel); error_text->set_v_size_flags(SIZE_EXPAND_FILL); + error_text->set_selection_enabled(true); main_vb->add_child(error_text); } diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 58c25c1a5d..2a05f95321 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -714,12 +714,12 @@ void Skeleton3DEditor::create_editors() { // Skeleton options. PopupMenu *p = skeleton_options->get_popup(); - p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_all_poses", TTR("Reset all bone Poses")), SKELETON_OPTION_RESET_ALL_POSES); - p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_selected_poses", TTR("Reset selected Poses")), SKELETON_OPTION_RESET_SELECTED_POSES); - p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/all_poses_to_rests", TTR("Apply all poses to rests")), SKELETON_OPTION_ALL_POSES_TO_RESTS); - p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/selected_poses_to_rests", TTR("Apply selected poses to rests")), SKELETON_OPTION_SELECTED_POSES_TO_RESTS); - p->add_item(TTR("Create physical skeleton"), SKELETON_OPTION_CREATE_PHYSICAL_SKELETON); - p->add_item(TTR("Export skeleton profile"), SKELETON_OPTION_EXPORT_SKELETON_PROFILE); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_all_poses", TTR("Reset All Bone Poses")), SKELETON_OPTION_RESET_ALL_POSES); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_selected_poses", TTR("Reset Selected Poses")), SKELETON_OPTION_RESET_SELECTED_POSES); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/all_poses_to_rests", TTR("Apply All Poses to Rests")), SKELETON_OPTION_ALL_POSES_TO_RESTS); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/selected_poses_to_rests", TTR("Apply Selected Poses to Rests")), SKELETON_OPTION_SELECTED_POSES_TO_RESTS); + p->add_item(TTR("Create Physical Skeleton"), SKELETON_OPTION_CREATE_PHYSICAL_SKELETON); + p->add_item(TTR("Export Skeleton Profile"), SKELETON_OPTION_EXPORT_SKELETON_PROFILE); p->connect("id_pressed", callable_mp(this, &Skeleton3DEditor::_on_click_skeleton_option)); set_bone_options_enabled(false); @@ -1239,7 +1239,7 @@ int Skeleton3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gi Skeleton3DEditor *se = Skeleton3DEditor::get_singleton(); - if (!se->is_edit_mode()) { + if (!se || !se->is_edit_mode()) { return -1; } diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp index fffcce6d9a..16a6a48df9 100644 --- a/editor/plugins/style_box_editor_plugin.cpp +++ b/editor/plugins/style_box_editor_plugin.cpp @@ -80,9 +80,9 @@ void StyleBoxPreview::_notification(int p_what) { // See https://github.com/godotengine/godot/issues/50743. break; } - grid_preview->set_normal_texture(get_theme_icon(SNAME("StyleBoxGridInvisible"), SNAME("EditorIcons"))); - grid_preview->set_pressed_texture(get_theme_icon(SNAME("StyleBoxGridVisible"), SNAME("EditorIcons"))); - grid_preview->set_hover_texture(get_theme_icon(SNAME("StyleBoxGridVisible"), SNAME("EditorIcons"))); + grid_preview->set_texture_normal(get_theme_icon(SNAME("StyleBoxGridInvisible"), SNAME("EditorIcons"))); + grid_preview->set_texture_pressed(get_theme_icon(SNAME("StyleBoxGridVisible"), SNAME("EditorIcons"))); + grid_preview->set_texture_hover(get_theme_icon(SNAME("StyleBoxGridVisible"), SNAME("EditorIcons"))); checkerboard->set_texture(get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"))); } break; } diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index a7d90856ac..42eceb82ab 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -1138,6 +1138,7 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2 void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, String p_property, String p_label, Variant p_default_value) { ERR_FAIL_COND_MSG(!property.is_empty(), "Cannot setup TileDataDefaultEditor twice"); property = p_property; + property_type = p_type; // Update everything. if (property_editor) { @@ -1182,6 +1183,10 @@ void TileDataDefaultEditor::_notification(int p_what) { } } +Variant::Type TileDataDefaultEditor::get_property_type() { + return property_type; +} + TileDataDefaultEditor::TileDataDefaultEditor() { undo_redo = EditorNode::get_undo_redo(); @@ -2476,9 +2481,6 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi if (terrain_set == -1 || !tile_data || tile_data->get_terrain_set() != terrain_set) { // Paint terrain sets. - if (mb->get_button_index() == MouseButton::RIGHT) { - terrain_set = -1; - } drag_type = DRAG_TYPE_PAINT_TERRAIN_SET; drag_modified.clear(); drag_painted_value = int(dummy_object->get("terrain_set")); diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index c1560138b2..0a947fce8b 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -220,6 +220,7 @@ protected: StringName type; String property; + Variant::Type property_type; void _notification(int p_what); virtual Variant _get_painted_value(); @@ -237,6 +238,7 @@ public: virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override; void setup_property_editor(Variant::Type p_type, String p_property, String p_label = "", Variant p_default_value = Variant()); + Variant::Type get_property_type(); TileDataDefaultEditor(); ~TileDataDefaultEditor(); diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 57416ff55f..93f9df4d6e 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -2267,6 +2267,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { patterns_help_label = memnew(Label); patterns_help_label->set_text(TTR("Drag and drop or paste a TileMap selection here to store a pattern.")); + patterns_help_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); patterns_help_label->set_anchors_and_offsets_preset(Control::PRESET_CENTER); patterns_item_list->add_child(patterns_help_label); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index ab54a093f2..8e69abd7ff 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -737,18 +737,29 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { // --- Custom Data --- ADD_TILE_DATA_EDITOR_GROUP("Custom Data"); for (int i = 0; i < tile_set->get_custom_data_layers_count(); i++) { - if (tile_set->get_custom_data_layer_name(i).is_empty()) { - ADD_TILE_DATA_EDITOR(group, vformat("Custom Data %d", i), vformat("custom_data_%d", i)); + String editor_name = vformat("custom_data_%d", i); + String prop_name = tile_set->get_custom_data_layer_name(i); + Variant::Type prop_type = tile_set->get_custom_data_layer_type(i); + + if (prop_name.is_empty()) { + ADD_TILE_DATA_EDITOR(group, vformat("Custom Data %d", i), editor_name); } else { - ADD_TILE_DATA_EDITOR(group, tile_set->get_custom_data_layer_name(i), vformat("custom_data_%d", i)); + ADD_TILE_DATA_EDITOR(group, prop_name, editor_name); + } + + // If the type of the edited property has been changed, delete the + // editor and create a new one. + if (tile_data_editors.has(editor_name) && ((TileDataDefaultEditor *)tile_data_editors[editor_name])->get_property_type() != prop_type) { + tile_data_editors[vformat("custom_data_%d", i)]->queue_free(); + tile_data_editors.erase(vformat("custom_data_%d", i)); } - if (!tile_data_editors.has(vformat("custom_data_%d", i))) { + if (!tile_data_editors.has(editor_name)) { TileDataDefaultEditor *tile_data_custom_data_editor = memnew(TileDataDefaultEditor()); tile_data_custom_data_editor->hide(); - tile_data_custom_data_editor->setup_property_editor(tile_set->get_custom_data_layer_type(i), vformat("custom_data_%d", i), tile_set->get_custom_data_layer_name(i)); + tile_data_custom_data_editor->setup_property_editor(prop_type, editor_name, prop_name); tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); - tile_data_editors[vformat("custom_data_%d", i)] = tile_data_custom_data_editor; + tile_data_editors[editor_name] = tile_data_custom_data_editor; } } for (int i = tile_set->get_custom_data_layers_count(); tile_data_editors.has(vformat("custom_data_%d", i)); i++) { diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 5e25d343b0..eaae9555dc 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -701,7 +701,7 @@ TileSetEditor::TileSetEditor() { source_sort_button = memnew(MenuButton); source_sort_button->set_flat(true); - source_sort_button->set_tooltip_text(TTR("Sort sources")); + source_sort_button->set_tooltip_text(TTR("Sort Sources")); PopupMenu *p = source_sort_button->get_popup(); p->connect("id_pressed", callable_mp(this, &TileSetEditor::_set_source_sort)); @@ -801,6 +801,7 @@ TileSetEditor::TileSetEditor() { patterns_help_label = memnew(Label); patterns_help_label->set_text(TTR("Add new patterns in the TileMap editing mode.")); + patterns_help_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); patterns_help_label->set_anchors_and_offsets_preset(Control::PRESET_CENTER); patterns_item_list->add_child(patterns_help_label); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index c8f6a2431d..adc93c0752 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -816,8 +816,8 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { if (vsnode->is_output_port_expandable(i)) { TextureButton *expand = memnew(TextureButton); expand->set_toggle_mode(true); - expand->set_normal_texture(editor->get_theme_icon(SNAME("GuiTreeArrowDown"), SNAME("EditorIcons"))); - expand->set_pressed_texture(editor->get_theme_icon(SNAME("GuiTreeArrowRight"), SNAME("EditorIcons"))); + expand->set_texture_normal(editor->get_theme_icon(SNAME("GuiTreeArrowDown"), SNAME("EditorIcons"))); + expand->set_texture_pressed(editor->get_theme_icon(SNAME("GuiTreeArrowRight"), SNAME("EditorIcons"))); expand->set_v_size_flags(Control::SIZE_SHRINK_CENTER); expand->set_pressed(vsnode->_is_output_port_expanded(i)); expand->connect("pressed", callable_mp(editor, &VisualShaderEditor::_expand_output_port).bind(p_id, i, !vsnode->_is_output_port_expanded(i)), CONNECT_DEFERRED); @@ -826,8 +826,8 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { if (vsnode->has_output_port_preview(i) && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) { TextureButton *preview = memnew(TextureButton); preview->set_toggle_mode(true); - preview->set_normal_texture(editor->get_theme_icon(SNAME("GuiVisibilityHidden"), SNAME("EditorIcons"))); - preview->set_pressed_texture(editor->get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons"))); + preview->set_texture_normal(editor->get_theme_icon(SNAME("GuiVisibilityHidden"), SNAME("EditorIcons"))); + preview->set_texture_pressed(editor->get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons"))); preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER); register_output_port(p_id, j, preview); @@ -3623,12 +3623,6 @@ void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos, VisualShaderNod node_filter->select_all(); } -void VisualShaderEditor::_show_varying_menu() { - varying_options->set_item_disabled(int(VaryingMenuOptions::REMOVE), visual_shader->get_varyings_count() == 0); - varying_options->set_position(graph->get_screen_position() + varying_button->get_position() + Size2(0, varying_button->get_size().height)); - varying_options->popup(); -} - void VisualShaderEditor::_varying_menu_id_pressed(int p_idx) { switch (VaryingMenuOptions(p_idx)) { case VaryingMenuOptions::ADD: { @@ -4334,7 +4328,7 @@ void VisualShaderEditor::_update_varying_tree() { } } - varying_options->set_item_disabled(int(VaryingMenuOptions::REMOVE), count == 0); + varying_button->get_popup()->set_item_disabled(int(VaryingMenuOptions::REMOVE), count == 0); } void VisualShaderEditor::_varying_create() { @@ -4809,17 +4803,15 @@ VisualShaderEditor::VisualShaderEditor() { graph->get_zoom_hbox()->move_child(add_node, 0); add_node->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_members_dialog).bind(false, VisualShaderNode::PORT_TYPE_MAX, VisualShaderNode::PORT_TYPE_MAX)); - varying_button = memnew(Button); - varying_button->set_flat(true); + varying_button = memnew(MenuButton); varying_button->set_text(TTR("Manage Varyings")); + varying_button->set_switch_on_hover(true); graph->get_zoom_hbox()->add_child(varying_button); - varying_button->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_varying_menu)); - varying_options = memnew(PopupMenu); - add_child(varying_options); - varying_options->add_item(TTR("Add Varying"), int(VaryingMenuOptions::ADD)); - varying_options->add_item(TTR("Remove Varying"), int(VaryingMenuOptions::REMOVE)); - varying_options->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_varying_menu_id_pressed)); + PopupMenu *varying_menu = varying_button->get_popup(); + varying_menu->add_item(TTR("Add Varying"), int(VaryingMenuOptions::ADD)); + varying_menu->add_item(TTR("Remove Varying"), int(VaryingMenuOptions::REMOVE)); + varying_menu->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_varying_menu_id_pressed)); preview_shader = memnew(Button); preview_shader->set_flat(true); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 5e21215738..e673051eb3 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -165,8 +165,7 @@ class VisualShaderEditor : public VBoxContainer { Ref<VisualShader> visual_shader; GraphEdit *graph = nullptr; Button *add_node = nullptr; - Button *varying_button = nullptr; - PopupMenu *varying_options = nullptr; + MenuButton *varying_button = nullptr; Button *preview_shader = nullptr; OptionButton *edit_type = nullptr; @@ -283,7 +282,6 @@ class VisualShaderEditor : public VBoxContainer { void _tools_menu_option(int p_idx); void _show_members_dialog(bool at_mouse_pos, VisualShaderNode::PortType p_input_port_type = VisualShaderNode::PORT_TYPE_MAX, VisualShaderNode::PortType p_output_port_type = VisualShaderNode::PORT_TYPE_MAX); - void _show_varying_menu(); void _varying_menu_id_pressed(int p_idx); void _show_add_varying_dialog(); void _show_remove_varying_dialog(); diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index 8de2833240..90738a59e8 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -465,6 +465,7 @@ static const char *gdscript_function_renames[][2] = { { "post_import", "_post_import" }, // EditorScenePostImport { "print_stray_nodes", "print_orphan_nodes" }, // Node { "property_list_changed_notify", "notify_property_list_changed" }, // Object + { "raise", "move_to_front" }, // CanvasItem { "recognize", "_recognize" }, // ResourceFormatLoader { "regen_normalmaps", "regen_normal_maps" }, // ArrayMesh { "remove", "remove_at" }, // Array, broke Directory @@ -2171,7 +2172,7 @@ int ProjectConverter3To4::validate_conversion() { lines.append(line); } } - print_line(vformat("Checking for conversion - %d/%d file - \"%s\" with size - %d KB"), i + 1, collected_files.size(), file_name.trim_prefix("res://"), file_size / 1024); + print_line(vformat("Checking for conversion - %d/%d file - \"%s\" with size - %d KB", i + 1, collected_files.size(), file_name.trim_prefix("res://"), file_size / 1024)); Vector<String> changed_elements; Vector<String> reason; @@ -2443,10 +2444,10 @@ bool ProjectConverter3To4::test_conversion(RegExContainer ®_container) { valid = valid && test_conversion_with_regex("\n\nmaster func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); valid = valid && test_conversion_with_regex("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); - valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function\n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function \n set(mod_value):\n mod_value # TODOConverter40 Non existent set function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() : get = get_function, set = set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() : set = set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() : set = set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() : get = get_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid && test_conversion_gdscript_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); @@ -3142,17 +3143,17 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai // Setget Setget if (line.contains("setget")) { - line = reg_container.reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + line = reg_container.reg_setget_setget.sub(line, "var $1$2: get = $4, set = $3", true); } // Setget set if (line.contains("setget")) { - line = reg_container.reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + line = reg_container.reg_setget_set.sub(line, "var $1$2: set = $3", true); } // Setget get if (line.contains("setget")) { - line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true); + line = reg_container.reg_setget_get.sub(line, "var $1$2: get = $3", true); } // OS.window_fullscreen = a -> if a: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) else: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index b2a2566ad4..02d59921bf 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1376,7 +1376,7 @@ void ProjectList::create_project_item_control(int p_index) { favorite_box->set_name("FavoriteBox"); TextureButton *favorite = memnew(TextureButton); favorite->set_name("FavoriteButton"); - favorite->set_normal_texture(favorite_icon); + favorite->set_texture_normal(favorite_icon); // This makes the project's "hover" style display correctly when hovering the favorite icon. favorite->set_mouse_filter(MOUSE_FILTER_PASS); favorite->connect("pressed", callable_mp(this, &ProjectList::_favorite_pressed).bind(hb)); diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp new file mode 100644 index 0000000000..d3097a694e --- /dev/null +++ b/editor/register_editor_types.cpp @@ -0,0 +1,221 @@ +/*************************************************************************/ +/* register_editor_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "register_editor_types.h" + +#include "core/extension/native_extension_manager.h" + +#include "editor/animation_track_editor.h" +#include "editor/debugger/debug_adapter/debug_adapter_server.h" +#include "editor/editor_command_palette.h" +#include "editor/editor_feature_profile.h" +#include "editor/editor_file_dialog.h" +#include "editor/editor_file_system.h" +#include "editor/editor_node.h" +#include "editor/editor_paths.h" +#include "editor/editor_resource_picker.h" +#include "editor/editor_resource_preview.h" +#include "editor/editor_run_script.h" +#include "editor/editor_translation_parser.h" +#include "editor/editor_undo_redo_manager.h" +#include "editor/filesystem_dock.h" +#include "editor/import/editor_import_plugin.h" +#include "editor/import/resource_importer_scene.h" +#include "editor/plugins/animation_tree_editor_plugin.h" +#include "editor/plugins/audio_stream_randomizer_editor_plugin.h" +#include "editor/plugins/bit_map_editor_plugin.h" +#include "editor/plugins/bone_map_editor_plugin.h" +#include "editor/plugins/camera_3d_editor_plugin.h" +#include "editor/plugins/cast_2d_editor_plugin.h" +#include "editor/plugins/collision_polygon_2d_editor_plugin.h" +#include "editor/plugins/collision_shape_2d_editor_plugin.h" +#include "editor/plugins/control_editor_plugin.h" +#include "editor/plugins/cpu_particles_2d_editor_plugin.h" +#include "editor/plugins/cpu_particles_3d_editor_plugin.h" +#include "editor/plugins/curve_editor_plugin.h" +#include "editor/plugins/editor_debugger_plugin.h" +#include "editor/plugins/font_config_plugin.h" +#include "editor/plugins/gpu_particles_2d_editor_plugin.h" +#include "editor/plugins/gpu_particles_3d_editor_plugin.h" +#include "editor/plugins/gpu_particles_collision_sdf_editor_plugin.h" +#include "editor/plugins/gradient_editor_plugin.h" +#include "editor/plugins/gradient_texture_2d_editor_plugin.h" +#include "editor/plugins/input_event_editor_plugin.h" +#include "editor/plugins/light_occluder_2d_editor_plugin.h" +#include "editor/plugins/lightmap_gi_editor_plugin.h" +#include "editor/plugins/line_2d_editor_plugin.h" +#include "editor/plugins/material_editor_plugin.h" +#include "editor/plugins/mesh_editor_plugin.h" +#include "editor/plugins/mesh_instance_3d_editor_plugin.h" +#include "editor/plugins/mesh_library_editor_plugin.h" +#include "editor/plugins/multimesh_editor_plugin.h" +#include "editor/plugins/navigation_link_2d_editor_plugin.h" +#include "editor/plugins/navigation_polygon_editor_plugin.h" +#include "editor/plugins/node_3d_editor_gizmos.h" +#include "editor/plugins/occluder_instance_3d_editor_plugin.h" +#include "editor/plugins/path_2d_editor_plugin.h" +#include "editor/plugins/path_3d_editor_plugin.h" +#include "editor/plugins/physical_bone_3d_editor_plugin.h" +#include "editor/plugins/polygon_2d_editor_plugin.h" +#include "editor/plugins/polygon_3d_editor_plugin.h" +#include "editor/plugins/resource_preloader_editor_plugin.h" +#include "editor/plugins/script_editor_plugin.h" +#include "editor/plugins/shader_editor_plugin.h" +#include "editor/plugins/shader_file_editor_plugin.h" +#include "editor/plugins/skeleton_2d_editor_plugin.h" +#include "editor/plugins/skeleton_3d_editor_plugin.h" +#include "editor/plugins/skeleton_ik_3d_editor_plugin.h" +#include "editor/plugins/sprite_2d_editor_plugin.h" +#include "editor/plugins/sprite_frames_editor_plugin.h" +#include "editor/plugins/style_box_editor_plugin.h" +#include "editor/plugins/sub_viewport_preview_editor_plugin.h" +#include "editor/plugins/texture_3d_editor_plugin.h" +#include "editor/plugins/texture_editor_plugin.h" +#include "editor/plugins/texture_layered_editor_plugin.h" +#include "editor/plugins/texture_region_editor_plugin.h" +#include "editor/plugins/theme_editor_plugin.h" +#include "editor/plugins/tiles/tiles_editor_plugin.h" +#include "editor/plugins/version_control_editor_plugin.h" +#include "editor/plugins/visual_shader_editor_plugin.h" +#include "editor/plugins/voxel_gi_editor_plugin.h" + +void register_editor_types() { + ResourceLoader::set_timestamp_on_load(true); + ResourceSaver::set_timestamp_on_save(true); + + GDREGISTER_CLASS(EditorPaths); + GDREGISTER_CLASS(EditorPlugin); + GDREGISTER_CLASS(EditorTranslationParserPlugin); + GDREGISTER_CLASS(EditorImportPlugin); + GDREGISTER_CLASS(EditorScript); + GDREGISTER_CLASS(EditorSelection); + GDREGISTER_CLASS(EditorFileDialog); + GDREGISTER_ABSTRACT_CLASS(EditorSettings); + GDREGISTER_CLASS(EditorNode3DGizmo); + GDREGISTER_CLASS(EditorNode3DGizmoPlugin); + GDREGISTER_ABSTRACT_CLASS(EditorResourcePreview); + GDREGISTER_CLASS(EditorResourcePreviewGenerator); + GDREGISTER_ABSTRACT_CLASS(EditorFileSystem); + GDREGISTER_CLASS(EditorFileSystemDirectory); + GDREGISTER_CLASS(EditorVCSInterface); + GDREGISTER_ABSTRACT_CLASS(ScriptEditor); + GDREGISTER_ABSTRACT_CLASS(ScriptEditorBase); + GDREGISTER_CLASS(EditorSyntaxHighlighter); + GDREGISTER_ABSTRACT_CLASS(EditorInterface); + GDREGISTER_CLASS(EditorExportPlugin); + GDREGISTER_ABSTRACT_CLASS(EditorExportPlatform); + GDREGISTER_CLASS(EditorResourceConversionPlugin); + GDREGISTER_CLASS(EditorSceneFormatImporter); + GDREGISTER_CLASS(EditorScenePostImportPlugin); + GDREGISTER_CLASS(EditorInspector); + GDREGISTER_CLASS(EditorInspectorPlugin); + GDREGISTER_CLASS(EditorProperty); + GDREGISTER_CLASS(AnimationTrackEditPlugin); + GDREGISTER_CLASS(ScriptCreateDialog); + GDREGISTER_CLASS(EditorFeatureProfile); + GDREGISTER_CLASS(EditorSpinSlider); + GDREGISTER_CLASS(EditorResourcePicker); + GDREGISTER_CLASS(EditorScriptPicker); + GDREGISTER_ABSTRACT_CLASS(EditorUndoRedoManager); + + GDREGISTER_ABSTRACT_CLASS(FileSystemDock); + GDREGISTER_VIRTUAL_CLASS(EditorFileSystemImportFormatSupportQuery); + + GDREGISTER_CLASS(EditorScenePostImport); + GDREGISTER_CLASS(EditorCommandPalette); + GDREGISTER_CLASS(EditorDebuggerPlugin); + GDREGISTER_ABSTRACT_CLASS(EditorDebuggerSession); + + // This list is alphabetized, and plugins that depend on Node2D are in their own section below. + EditorPlugins::add_by_type<AnimationTreeEditorPlugin>(); + EditorPlugins::add_by_type<AudioStreamRandomizerEditorPlugin>(); + EditorPlugins::add_by_type<BitMapEditorPlugin>(); + EditorPlugins::add_by_type<BoneMapEditorPlugin>(); + EditorPlugins::add_by_type<Camera3DEditorPlugin>(); + EditorPlugins::add_by_type<ControlEditorPlugin>(); + EditorPlugins::add_by_type<CPUParticles3DEditorPlugin>(); + EditorPlugins::add_by_type<CurveEditorPlugin>(); + EditorPlugins::add_by_type<DebugAdapterServer>(); + EditorPlugins::add_by_type<FontEditorPlugin>(); + EditorPlugins::add_by_type<GPUParticles3DEditorPlugin>(); + EditorPlugins::add_by_type<GPUParticlesCollisionSDF3DEditorPlugin>(); + EditorPlugins::add_by_type<GradientEditorPlugin>(); + EditorPlugins::add_by_type<GradientTexture2DEditorPlugin>(); + EditorPlugins::add_by_type<InputEventEditorPlugin>(); + EditorPlugins::add_by_type<LightmapGIEditorPlugin>(); + EditorPlugins::add_by_type<MaterialEditorPlugin>(); + EditorPlugins::add_by_type<MeshEditorPlugin>(); + EditorPlugins::add_by_type<MeshInstance3DEditorPlugin>(); + EditorPlugins::add_by_type<MeshLibraryEditorPlugin>(); + EditorPlugins::add_by_type<MultiMeshEditorPlugin>(); + EditorPlugins::add_by_type<OccluderInstance3DEditorPlugin>(); + EditorPlugins::add_by_type<Path3DEditorPlugin>(); + EditorPlugins::add_by_type<PhysicalBone3DEditorPlugin>(); + EditorPlugins::add_by_type<Polygon3DEditorPlugin>(); + EditorPlugins::add_by_type<ResourcePreloaderEditorPlugin>(); + EditorPlugins::add_by_type<ShaderEditorPlugin>(); + EditorPlugins::add_by_type<ShaderFileEditorPlugin>(); + EditorPlugins::add_by_type<Skeleton3DEditorPlugin>(); + EditorPlugins::add_by_type<SkeletonIK3DEditorPlugin>(); + EditorPlugins::add_by_type<SpriteFramesEditorPlugin>(); + EditorPlugins::add_by_type<StyleBoxEditorPlugin>(); + EditorPlugins::add_by_type<SubViewportPreviewEditorPlugin>(); + EditorPlugins::add_by_type<Texture3DEditorPlugin>(); + EditorPlugins::add_by_type<TextureEditorPlugin>(); + EditorPlugins::add_by_type<TextureLayeredEditorPlugin>(); + EditorPlugins::add_by_type<TextureRegionEditorPlugin>(); + EditorPlugins::add_by_type<ThemeEditorPlugin>(); + EditorPlugins::add_by_type<VoxelGIEditorPlugin>(); + + // 2D + EditorPlugins::add_by_type<CollisionPolygon2DEditorPlugin>(); + EditorPlugins::add_by_type<CollisionShape2DEditorPlugin>(); + EditorPlugins::add_by_type<CPUParticles2DEditorPlugin>(); + EditorPlugins::add_by_type<GPUParticles2DEditorPlugin>(); + EditorPlugins::add_by_type<LightOccluder2DEditorPlugin>(); + EditorPlugins::add_by_type<Line2DEditorPlugin>(); + EditorPlugins::add_by_type<NavigationLink2DEditorPlugin>(); + EditorPlugins::add_by_type<NavigationPolygonEditorPlugin>(); + EditorPlugins::add_by_type<Path2DEditorPlugin>(); + EditorPlugins::add_by_type<Polygon2DEditorPlugin>(); + EditorPlugins::add_by_type<Cast2DEditorPlugin>(); + EditorPlugins::add_by_type<Skeleton2DEditorPlugin>(); + EditorPlugins::add_by_type<Sprite2DEditorPlugin>(); + EditorPlugins::add_by_type<TilesEditorPlugin>(); +} + +void unregister_editor_types() { + EditorNode::cleanup(); + if (EditorPaths::get_singleton()) { + EditorPaths::free(); + } + + EditorResourcePicker::clear_caches(); +} diff --git a/editor/register_editor_types.h b/editor/register_editor_types.h new file mode 100644 index 0000000000..f53e7e3649 --- /dev/null +++ b/editor/register_editor_types.h @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* register_editor_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef REGISTER_EDITOR_TYPES_H +#define REGISTER_EDITOR_TYPES_H + +void register_editor_types(); +void unregister_editor_types(); + +#endif // REGISTER_EDITOR_TYPES_H diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp index 5b54a5a229..9f3ce26a59 100644 --- a/editor/scene_create_dialog.cpp +++ b/editor/scene_create_dialog.cpp @@ -175,7 +175,7 @@ Node *SceneCreateDialog::create_scene_root() { root = gui_ctl; } break; case ROOT_OTHER: - root = Object::cast_to<Node>(select_node_dialog->instance_selected()); + root = Object::cast_to<Node>(select_node_dialog->instantiate_selected()); break; } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index a7124c130b..8c0a30836f 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -33,6 +33,7 @@ #include "core/config/project_settings.h" #include "core/input/input.h" #include "core/io/resource_saver.h" +#include "core/object/class_db.h" #include "core/object/message_queue.h" #include "core/os/keyboard.h" #include "editor/debugger/editor_debugger_node.h" @@ -106,7 +107,7 @@ void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) { #endif // MODULE_REGEX_ENABLED } else if (ED_IS_SHORTCUT("scene_tree/add_child_node", p_event)) { _tool_selected(TOOL_NEW); - } else if (ED_IS_SHORTCUT("scene_tree/instance_scene", p_event)) { + } else if (ED_IS_SHORTCUT("scene_tree/instantiate_scene", p_event)) { _tool_selected(TOOL_INSTANTIATE); } else if (ED_IS_SHORTCUT("scene_tree/expand_collapse_all", p_event)) { _tool_selected(TOOL_EXPAND_COLLAPSE); @@ -198,7 +199,7 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!instantiated_scene) { current_option = -1; - accept->set_text(vformat(TTR("Error instancing scene from %s"), p_files[i])); + accept->set_text(vformat(TTR("Error instantiating scene from %s"), p_files[i])); accept->popup_centered(); error = true; break; @@ -206,7 +207,7 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N if (!edited_scene->get_scene_file_path().is_empty()) { if (_cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) { - accept->set_text(vformat(TTR("Cannot instance the scene '%s' because the current scene exists within one of its nodes."), p_files[i])); + accept->set_text(vformat(TTR("Cannot instantiate the scene '%s' because the current scene exists within one of its nodes."), p_files[i])); accept->popup_centered(); error = true; break; @@ -225,7 +226,7 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N return; } - editor_data->get_undo_redo()->create_action(TTR("Instance Scene(s)")); + editor_data->get_undo_redo()->create_action(TTR("Instantiate Scene(s)")); for (int i = 0; i < instances.size(); i++) { Node *instantiated_scene = instances[i]; @@ -242,7 +243,7 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N String new_name = parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), p_files[i], new_name); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instantiate_node", edited_scene->get_path_to(parent), p_files[i], new_name); editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(new_name))); } @@ -263,7 +264,7 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!instantiated_scene) { - accept->set_text(vformat(TTR("Error instancing scene from %s"), p_file)); + accept->set_text(vformat(TTR("Error instantiating scene from %s"), p_file)); accept->popup_centered(); return; } @@ -2180,7 +2181,7 @@ void SceneTreeDock::_selection_changed() { } void SceneTreeDock::_do_create(Node *p_parent) { - Variant c = create_dialog->instance_selected(); + Variant c = create_dialog->instantiate_selected(); Node *child = Object::cast_to<Node>(c); ERR_FAIL_COND(!child); @@ -2264,7 +2265,7 @@ void SceneTreeDock::_create() { for (Node *n : selection) { ERR_FAIL_COND(!n); - Variant c = create_dialog->instance_selected(); + Variant c = create_dialog->instantiate_selected(); ERR_FAIL_COND(!c); Node *newnode = Object::cast_to<Node>(c); @@ -2605,7 +2606,39 @@ void SceneTreeDock::_files_dropped(Vector<String> p_files, NodePath p_to, int p_ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) { Ref<Script> scr = ResourceLoader::load(p_file); ERR_FAIL_COND(!scr.is_valid()); - if (Node *n = get_node(p_to)) { + Node *n = get_node(p_to); + + if (!n) { + return; + } + + if (Input::get_singleton()->is_key_pressed(Key::CTRL)) { + Object *obj = ClassDB::instantiate(scr->get_instance_base_type()); + ERR_FAIL_NULL(obj); + + Node *new_node = Object::cast_to<Node>(obj); + if (!new_node) { + if (!obj->is_ref_counted()) { + memdelete(obj); + } + ERR_FAIL_MSG("Script does not extend Node-derived type."); + } + new_node->set_name(Node::adjust_name_casing(p_file.get_file().get_basename())); + new_node->set_script(scr); + + editor_data->get_undo_redo()->create_action(TTR("Instantiate Script")); + editor_data->get_undo_redo()->add_do_method(n, "add_child", new_node, true); + editor_data->get_undo_redo()->add_do_method(new_node, "set_owner", edited_scene); + editor_data->get_undo_redo()->add_do_method(editor_selection, "clear"); + editor_data->get_undo_redo()->add_do_method(editor_selection, "add_node", new_node); + editor_data->get_undo_redo()->add_do_reference(new_node); + editor_data->get_undo_redo()->add_undo_method(n, "remove_child", new_node); + + EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(n), new_node->get_class(), new_node->get_name()); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(n)).path_join(new_node->get_name()))); + editor_data->get_undo_redo()->commit_action(); + } else { editor_data->get_undo_redo()->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, n); editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", n); editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", n); @@ -2689,7 +2722,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->clear(); if (profile_allow_editing) { menu->add_icon_shortcut(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW); - menu->add_icon_shortcut(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANTIATE); + menu->add_icon_shortcut(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/instantiate_scene"), TOOL_INSTANTIATE); } menu->reset_size(); @@ -2722,7 +2755,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } menu->add_icon_shortcut(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW); - menu->add_icon_shortcut(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANTIATE); + menu->add_icon_shortcut(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/instantiate_scene"), TOOL_INSTANTIATE); } menu->add_icon_shortcut(get_theme_icon(SNAME("Collapse"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/expand_collapse_all"), TOOL_EXPAND_COLLAPSE); menu->add_separator(); @@ -3448,7 +3481,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec ED_SHORTCUT_OVERRIDE("scene_tree/batch_rename", "macos", KeyModifierMask::SHIFT | Key::ENTER); ED_SHORTCUT("scene_tree/add_child_node", TTR("Add Child Node"), KeyModifierMask::CMD_OR_CTRL | Key::A); - ED_SHORTCUT("scene_tree/instance_scene", TTR("Instantiate Child Scene"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::A); + ED_SHORTCUT("scene_tree/instantiate_scene", TTR("Instantiate Child Scene"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::A); ED_SHORTCUT("scene_tree/expand_collapse_all", TTR("Expand/Collapse Branch")); ED_SHORTCUT("scene_tree/cut_node", TTR("Cut"), KeyModifierMask::CMD_OR_CTRL | Key::X); ED_SHORTCUT("scene_tree/copy_node", TTR("Copy"), KeyModifierMask::CMD_OR_CTRL | Key::C); @@ -3480,7 +3513,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec button_instance->set_flat(true); button_instance->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_INSTANTIATE, false)); button_instance->set_tooltip_text(TTR("Instantiate a scene file as a Node. Creates an inherited scene if no root node exists.")); - button_instance->set_shortcut(ED_GET_SHORTCUT("scene_tree/instance_scene")); + button_instance->set_shortcut(ED_GET_SHORTCUT("scene_tree/instantiate_scene")); filter_hbc->add_child(button_instance); vbc->add_child(filter_hbc); @@ -3517,6 +3550,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec button_tree_menu = memnew(MenuButton); button_tree_menu->set_flat(true); + button_tree_menu->set_tooltip_text(TTR("Extra scene options.")); button_tree_menu->connect("about_to_popup", callable_mp(this, &SceneTreeDock::_update_tree_menu)); filter_hbc->add_child(button_tree_menu); diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp index 596b3eefba..9b82e80072 100644 --- a/editor/shader_globals_editor.cpp +++ b/editor/shader_globals_editor.cpp @@ -111,7 +111,7 @@ protected: undo_redo->add_do_method(this, "_var_changed"); undo_redo->add_undo_method(this, "_var_changed"); block_update = true; - undo_redo->commit_action(); + undo_redo->commit_action(false); block_update = false; return true; diff --git a/main/main.cpp b/main/main.cpp index 91d38ff6d9..55f7177258 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -95,6 +95,7 @@ #include "editor/progress_dialog.h" #include "editor/project_converter_3_to_4.h" #include "editor/project_manager.h" +#include "editor/register_editor_types.h" #ifndef NO_EDITOR_SPLASH #include "main/splash_editor.gen.h" #endif @@ -487,7 +488,7 @@ Error Main::test_setup() { #ifdef TOOLS_ENABLED ClassDB::set_current_api(ClassDB::API_EDITOR); - EditorNode::register_editor_types(); + register_editor_types(); initialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR); NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_EDITOR); @@ -540,7 +541,7 @@ void Main::test_cleanup() { #ifdef TOOLS_ENABLED NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_EDITOR); uninitialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR); - EditorNode::unregister_editor_types(); + unregister_editor_types(); #endif NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SCENE); @@ -1932,6 +1933,9 @@ error: } Error Main::setup2(Thread::ID p_main_tid_override) { + // Print engine name and version + print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); + engine->startup_benchmark_begin_measure("servers"); tsman = memnew(TextServerManager); @@ -1949,9 +1953,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) { initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS); NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS); - // Print engine name and version - print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); - if (p_main_tid_override) { Thread::main_thread_id = p_main_tid_override; } @@ -2319,7 +2320,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) { #ifdef TOOLS_ENABLED ClassDB::set_current_api(ClassDB::API_EDITOR); - EditorNode::register_editor_types(); + register_editor_types(); initialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR); NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_EDITOR); @@ -3319,7 +3320,7 @@ void Main::cleanup(bool p_force) { #ifdef TOOLS_ENABLED NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_EDITOR); uninitialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR); - EditorNode::unregister_editor_types(); + unregister_editor_types(); #endif diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj index b58f002f3c..e717b501f4 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj @@ -164,7 +164,7 @@ }; buildConfigurationList = D0BCFE2F18AEBDA2004A7AAE /* Build configuration list for PBXProject "$binary" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index bd6cef0b6e..60230257e0 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -808,6 +808,11 @@ String GDScript::_get_debug_path() const { } Error GDScript::reload(bool p_keep_state) { + if (reloading) { + return OK; + } + reloading = true; + bool has_instances; { MutexLock lock(GDScriptLanguage::singleton->mutex); @@ -830,6 +835,7 @@ Error GDScript::reload(bool p_keep_state) { // Loading a template, don't parse. #ifdef TOOLS_ENABLED if (EditorPaths::get_singleton() && basedir.begins_with(EditorPaths::get_singleton()->get_project_script_templates_dir())) { + reloading = false; return OK; } #endif @@ -839,11 +845,10 @@ Error GDScript::reload(bool p_keep_state) { if (source_path.is_empty()) { source_path = get_path(); } - if (!source_path.is_empty()) { - MutexLock lock(GDScriptCache::singleton->lock); - if (!GDScriptCache::singleton->shallow_gdscript_cache.has(source_path)) { - GDScriptCache::singleton->shallow_gdscript_cache[source_path] = this; - } + Ref<GDScript> cached_script = GDScriptCache::get_cached_script(source_path); + if (!source_path.is_empty() && cached_script.is_null()) { + MutexLock lock(GDScriptCache::singleton->mutex); + GDScriptCache::singleton->shallow_gdscript_cache[source_path] = Ref<GDScript>(this); } } @@ -856,6 +861,7 @@ Error GDScript::reload(bool p_keep_state) { } // TODO: Show all error messages. _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT); + reloading = false; return ERR_PARSE_ERROR; } @@ -872,6 +878,7 @@ Error GDScript::reload(bool p_keep_state) { _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT); e = e->next(); } + reloading = false; return ERR_PARSE_ERROR; } @@ -886,8 +893,10 @@ Error GDScript::reload(bool p_keep_state) { GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error()); } _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), false, ERR_HANDLER_SCRIPT); + reloading = false; return ERR_COMPILATION_FAILED; } else { + reloading = false; return err; } } @@ -900,6 +909,7 @@ Error GDScript::reload(bool p_keep_state) { } #endif + reloading = false; return OK; } @@ -1006,16 +1016,22 @@ Error GDScript::load_byte_code(const String &p_path) { } void GDScript::set_path(const String &p_path, bool p_take_over) { + String old_path = path; if (is_root_script()) { Script::set_path(p_path, p_take_over); } this->path = p_path; + GDScriptCache::move_script(old_path, p_path); for (KeyValue<StringName, Ref<GDScript>> &kv : subclasses) { kv.value->set_path(p_path, p_take_over); } } Error GDScript::load_source_code(const String &p_path) { + if (p_path.is_empty() || ResourceLoader::get_resource_type(p_path.get_slice("::", 0)) == "PackedScene") { + return OK; + } + Vector<uint8_t> sourcef; Error err; Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); @@ -1133,6 +1149,78 @@ GDScript *GDScript::get_root_script() { return result; } +RBSet<GDScript *> GDScript::get_dependencies() { + RBSet<GDScript *> dependencies; + + _get_dependencies(dependencies, this); + dependencies.erase(this); + + return dependencies; +} + +RBSet<GDScript *> GDScript::get_inverted_dependencies() { + RBSet<GDScript *> inverted_dependencies; + + List<GDScript *> scripts; + { + MutexLock lock(GDScriptLanguage::singleton->mutex); + + SelfList<GDScript> *elem = GDScriptLanguage::singleton->script_list.first(); + while (elem) { + scripts.push_back(elem->self()); + elem = elem->next(); + } + } + + for (GDScript *scr : scripts) { + if (scr == nullptr || scr == this || scr->destructing) { + continue; + } + + RBSet<GDScript *> scr_dependencies = scr->get_dependencies(); + if (scr_dependencies.has(this)) { + inverted_dependencies.insert(scr); + } + } + + return inverted_dependencies; +} + +RBSet<GDScript *> GDScript::get_must_clear_dependencies() { + RBSet<GDScript *> dependencies = get_dependencies(); + RBSet<GDScript *> must_clear_dependencies; + HashMap<GDScript *, RBSet<GDScript *>> inverted_dependencies; + + for (GDScript *E : dependencies) { + inverted_dependencies.insert(E, E->get_inverted_dependencies()); + } + + RBSet<GDScript *> cant_clear; + for (KeyValue<GDScript *, RBSet<GDScript *>> &E : inverted_dependencies) { + for (GDScript *F : E.value) { + if (!dependencies.has(F)) { + cant_clear.insert(E.key); + for (GDScript *G : E.key->get_dependencies()) { + cant_clear.insert(G); + } + break; + } + } + } + + for (KeyValue<GDScript *, RBSet<GDScript *>> &E : inverted_dependencies) { + if (cant_clear.has(E.key) || ScriptServer::is_global_class(E.key->get_fully_qualified_name())) { + continue; + } + must_clear_dependencies.insert(E.key); + } + + cant_clear.clear(); + dependencies.clear(); + inverted_dependencies.clear(); + return must_clear_dependencies; +} + bool GDScript::has_script_signal(const StringName &p_signal) const { if (_signals.has(p_signal)) { return true; @@ -1194,6 +1282,69 @@ String GDScript::_get_gdscript_reference_class_name(const GDScript *p_gdscript) return class_name; } +GDScript *GDScript::_get_gdscript_from_variant(const Variant &p_variant) { + Variant::Type type = p_variant.get_type(); + if (type != Variant::Type::OBJECT) + return nullptr; + + Object *obj = p_variant; + if (obj == nullptr) { + return nullptr; + } + + return Object::cast_to<GDScript>(obj); +} + +void GDScript::_get_dependencies(RBSet<GDScript *> &p_dependencies, const GDScript *p_except) { + if (skip_dependencies || p_dependencies.has(this)) { + return; + } + p_dependencies.insert(this); + + for (const KeyValue<StringName, GDScriptFunction *> &E : member_functions) { + if (E.value == nullptr) { + continue; + } + for (const Variant &V : E.value->constants) { + GDScript *scr = _get_gdscript_from_variant(V); + if (scr != nullptr && scr != p_except) { + scr->_get_dependencies(p_dependencies, p_except); + } + } + } + + if (implicit_initializer) { + for (const Variant &V : implicit_initializer->constants) { + GDScript *scr = _get_gdscript_from_variant(V); + if (scr != nullptr && scr != p_except) { + scr->_get_dependencies(p_dependencies, p_except); + } + } + } + + if (implicit_ready) { + for (const Variant &V : implicit_ready->constants) { + GDScript *scr = _get_gdscript_from_variant(V); + if (scr != nullptr && scr != p_except) { + scr->_get_dependencies(p_dependencies, p_except); + } + } + } + + for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) { + if (E.value != p_except) { + E.value->_get_dependencies(p_dependencies, p_except); + } + } + + for (const KeyValue<StringName, Variant> &E : constants) { + GDScript *scr = _get_gdscript_from_variant(E.value); + if (scr != nullptr && scr != p_except) { + scr->_get_dependencies(p_dependencies, p_except); + } + } +} + GDScript::GDScript() : script_list(this) { #ifdef DEBUG_ENABLED @@ -1253,33 +1404,58 @@ void GDScript::_init_rpc_methods_properties() { } } -GDScript::~GDScript() { - { - MutexLock lock(GDScriptLanguage::get_singleton()->mutex); +void GDScript::clear() { + if (clearing) { + return; + } + clearing = true; - while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) { - // Order matters since clearing the stack may already cause - // the GDSCriptFunctionState to be destroyed and thus removed from the list. - pending_func_states.remove(E); - E->self()->_clear_stack(); + RBSet<GDScript *> must_clear_dependencies = get_must_clear_dependencies(); + HashMap<GDScript *, ObjectID> must_clear_dependencies_objectids; + + // Log the objectids before clearing, as a cascade of clear could + // remove instances that are still in the clear loop + for (GDScript *E : must_clear_dependencies) { + must_clear_dependencies_objectids.insert(E, E->get_instance_id()); + } + + for (GDScript *E : must_clear_dependencies) { + Object *obj = ObjectDB::get_instance(must_clear_dependencies_objectids[E]); + if (obj == nullptr) { + continue; } + + E->skip_dependencies = true; + E->clear(); + E->skip_dependencies = false; + GDScriptCache::remove_script(E->get_path()); } + RBSet<StringName> member_function_names; for (const KeyValue<StringName, GDScriptFunction *> &E : member_functions) { - memdelete(E.value); + member_function_names.insert(E.key); + } + for (const StringName &E : member_function_names) { + if (member_functions.has(E)) { + memdelete(member_functions[E]); + } + } + member_function_names.clear(); + member_functions.clear(); + + for (KeyValue<StringName, GDScript::MemberInfo> &E : member_indices) { + E.value.data_type.script_type_ref = Ref<Script>(); } if (implicit_initializer) { memdelete(implicit_initializer); } + implicit_initializer = nullptr; if (implicit_ready) { memdelete(implicit_ready); } - - if (GDScriptCache::singleton) { // Cache may have been already destroyed at engine shutdown. - GDScriptCache::remove_script(get_path()); - } + implicit_ready = nullptr; _save_orphaned_subclasses(); @@ -1289,6 +1465,27 @@ GDScript::~GDScript() { _clear_doc(); } #endif + clearing = false; +} + +GDScript::~GDScript() { + if (destructing) { + return; + } + destructing = true; + + clear(); + + { + MutexLock lock(GDScriptLanguage::get_singleton()->mutex); + + while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) { + // Order matters since clearing the stack may already cause + // the GDScriptFunctionState to be destroyed and thus removed from the list. + pending_func_states.remove(E); + E->self()->_clear_stack(); + } + } #ifdef DEBUG_ENABLED { @@ -1297,6 +1494,10 @@ GDScript::~GDScript() { GDScriptLanguage::get_singleton()->script_list.remove(&script_list); } #endif + + if (GDScriptCache::singleton) { // Cache may have been already destroyed at engine shutdown. + GDScriptCache::remove_script(get_path()); + } } ////////////////////////////// @@ -2336,26 +2537,27 @@ GDScriptLanguage::~GDScriptLanguage() { // Clear dependencies between scripts, to ensure cyclic references are broken (to avoid leaks at exit). SelfList<GDScript> *s = script_list.first(); while (s) { - GDScript *scr = s->self(); // This ensures the current script is not released before we can check what's the next one // in the list (we can't get the next upfront because we don't know if the reference breaking // will cause it -or any other after it, for that matter- to be released so the next one // is not the same as before). - scr->reference(); - - for (KeyValue<StringName, GDScriptFunction *> &E : scr->member_functions) { - GDScriptFunction *func = E.value; - for (int i = 0; i < func->argument_types.size(); i++) { - func->argument_types.write[i].script_type_ref = Ref<Script>(); + Ref<GDScript> scr = s->self(); + if (scr.is_valid()) { + for (KeyValue<StringName, GDScriptFunction *> &E : scr->member_functions) { + GDScriptFunction *func = E.value; + for (int i = 0; i < func->argument_types.size(); i++) { + func->argument_types.write[i].script_type_ref = Ref<Script>(); + } + func->return_type.script_type_ref = Ref<Script>(); + } + for (KeyValue<StringName, GDScript::MemberInfo> &E : scr->member_indices) { + E.value.data_type.script_type_ref = Ref<Script>(); } - func->return_type.script_type_ref = Ref<Script>(); - } - for (KeyValue<StringName, GDScript::MemberInfo> &E : scr->member_indices) { - E.value.data_type.script_type_ref = Ref<Script>(); - } + // Clear backup for scripts that could slip out of the cyclic reference check + scr->clear(); + } s = s->next(); - scr->unreference(); } singleton = nullptr; @@ -2379,6 +2581,27 @@ Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_na return Ref<GDScript>(Object::cast_to<GDScript>(obj)); } +Ref<GDScript> GDScriptLanguage::get_script_by_fully_qualified_name(const String &p_name) { + { + MutexLock lock(mutex); + + SelfList<GDScript> *elem = script_list.first(); + while (elem) { + GDScript *scr = elem->self(); + scr = scr->find_class(p_name); + if (scr != nullptr) { + return scr; + } + elem = elem->next(); + } + } + + Ref<GDScript> scr; + scr.instantiate(); + scr->fully_qualified_name = p_name; + return scr; +} + /*************** RESOURCE ***************/ Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 61600b1258..2df89d812c 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -61,6 +61,8 @@ class GDScript : public Script { GDCLASS(GDScript, Script); bool tool = false; bool valid = false; + bool reloading = false; + bool skip_dependencies = false; struct MemberInfo { int index = 0; @@ -124,6 +126,8 @@ class GDScript : public Script { int subclass_count = 0; RBSet<Object *> instances; + bool destructing = false; + bool clearing = false; //exported members String source; String path; @@ -163,6 +167,9 @@ class GDScript : public Script { // This method will map the class name from "RefCounted" to "MyClass.InnerClass". static String _get_gdscript_reference_class_name(const GDScript *p_gdscript); + GDScript *_get_gdscript_from_variant(const Variant &p_variant); + void _get_dependencies(RBSet<GDScript *> &p_dependencies, const GDScript *p_except); + protected: bool _get(const StringName &p_name, Variant &r_ret) const; bool _set(const StringName &p_name, const Variant &p_value); @@ -173,6 +180,8 @@ protected: static void _bind_methods(); public: + void clear(); + virtual bool is_valid() const override { return valid; } bool inherits_script(const Ref<Script> &p_script) const override; @@ -193,6 +202,10 @@ public: const Ref<GDScriptNativeClass> &get_native() const { return native; } const String &get_script_class_name() const { return name; } + RBSet<GDScript *> get_dependencies(); + RBSet<GDScript *> get_inverted_dependencies(); + RBSet<GDScript *> get_must_clear_dependencies(); + virtual bool has_script_signal(const StringName &p_signal) const override; virtual void get_script_signal_list(List<MethodInfo> *r_signals) const override; @@ -270,6 +283,7 @@ class GDScriptInstance : public ScriptInstance { friend class GDScriptLambdaCallable; friend class GDScriptLambdaSelfCallable; friend class GDScriptCompiler; + friend class GDScriptCache; friend struct GDScriptUtilityFunctionsDefinitions; ObjectID owner_id; @@ -518,6 +532,8 @@ public: void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass); Ref<GDScript> get_orphan_subclass(const String &p_qualified_name); + Ref<GDScript> get_script_by_fully_qualified_name(const String &p_name); + GDScriptLanguage(); ~GDScriptLanguage(); }; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 8da77b9e5b..9b0dc9577b 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -32,6 +32,7 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" +#include "core/core_string_names.h" #include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/object/class_db.h" @@ -39,6 +40,7 @@ #include "core/templates/hash_map.h" #include "gdscript.h" #include "gdscript_utility_functions.h" +#include "scene/resources/packed_scene.h" static MethodInfo info_from_utility_func(const StringName &p_function) { ERR_FAIL_COND_V(!Variant::has_utility_function(p_function), MethodInfo()); @@ -132,7 +134,7 @@ static GDScriptParser::DataType make_builtin_meta_type(Variant::Type p_type) { return type; } -bool GDScriptAnalyzer::has_member_name_conflict_in_script_class(const StringName &p_member_name, const GDScriptParser::ClassNode *p_class) { +bool GDScriptAnalyzer::has_member_name_conflict_in_script_class(const StringName &p_member_name, const GDScriptParser::ClassNode *p_class, const GDScriptParser::Node *p_member) { if (p_class->members_indices.has(p_member_name)) { int index = p_class->members_indices[p_member_name]; const GDScriptParser::ClassNode::Member *member = &p_class->members[index]; @@ -145,6 +147,9 @@ bool GDScriptAnalyzer::has_member_name_conflict_in_script_class(const StringName member->type == GDScriptParser::ClassNode::Member::SIGNAL) { return true; } + if (p_member->type != GDScriptParser::Node::FUNCTION && member->type == GDScriptParser::ClassNode::Member::FUNCTION) { + return true; + } } return false; @@ -160,6 +165,9 @@ bool GDScriptAnalyzer::has_member_name_conflict_in_native_type(const StringName if (ClassDB::has_integer_constant(p_native_type_string, p_member_name)) { return true; } + if (p_member_name == CoreStringNames::get_singleton()->_script) { + return true; + } return false; } @@ -187,14 +195,15 @@ Error GDScriptAnalyzer::check_class_member_name_conflict(const GDScriptParser::C const GDScriptParser::DataType *current_data_type = &p_class_node->base_type; while (current_data_type && current_data_type->kind == GDScriptParser::DataType::Kind::CLASS) { GDScriptParser::ClassNode *current_class_node = current_data_type->class_type; - if (has_member_name_conflict_in_script_class(p_member_name, current_class_node)) { - push_error(vformat(R"(The member "%s" already exists in a parent class.)", p_member_name), + if (has_member_name_conflict_in_script_class(p_member_name, current_class_node, p_member_node)) { + push_error(vformat(R"(The member "%s" already exists in parent class %s.)", p_member_name, current_class_node->identifier->name), p_member_node); return ERR_PARSE_ERROR; } current_data_type = ¤t_class_node->base_type; } + // No need for native class recursion because Node exposes all Object's properties. if (current_data_type && current_data_type->kind == GDScriptParser::DataType::Kind::NATIVE) { if (current_data_type->native_type != StringName()) { return check_native_member_name_conflict( @@ -1716,7 +1725,6 @@ void GDScriptAnalyzer::resolve_parameter(GDScriptParser::ParameterNode *p_parame } else { result.type_source = GDScriptParser::DataType::INFERRED; } - result.is_constant = false; } if (p_parameter->datatype_specifier != nullptr) { @@ -1736,6 +1744,7 @@ void GDScriptAnalyzer::resolve_parameter(GDScriptParser::ParameterNode *p_parame push_error(vformat(R"(Could not infer the type of the variable "%s" because the initial value is "null".)", p_parameter->identifier->name), p_parameter->default_value); } + result.is_constant = false; p_parameter->set_datatype(result); } @@ -2856,6 +2865,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod p_identifier->variable_source = member.variable; member.variable->usages += 1; break; + case GDScriptParser::ClassNode::Member::SIGNAL: + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_SIGNAL; + break; case GDScriptParser::ClassNode::Member::FUNCTION: resolve_function_signature(member.function); p_identifier->set_datatype(make_callable_type(member.function->info)); @@ -2912,7 +2924,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod base_class = base_class->base_type.class_type; } - // Check native members. + // Check native members. No need for native class recursion because Node exposes all Object's properties. const StringName &native = base.native_type; if (class_exists(native)) { @@ -3000,6 +3012,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident p_identifier->reduced_value = p_identifier->constant_source->initializer->reduced_value; found_source = true; break; + case GDScriptParser::IdentifierNode::MEMBER_SIGNAL: case GDScriptParser::IdentifierNode::INHERITED_VARIABLE: mark_lambda_use_self(); break; @@ -3103,7 +3116,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident GDScriptParser::DataType result; result.kind = GDScriptParser::DataType::NATIVE; result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; - if (autoload.path.to_lower().ends_with(GDScriptLanguage::get_singleton()->get_extension())) { + if (ResourceLoader::get_resource_type(autoload.path) == "GDScript") { Ref<GDScriptParserRef> singl_parser = get_parser_for(autoload.path); if (singl_parser.is_valid()) { Error err = singl_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED); @@ -3111,6 +3124,18 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident result = type_from_metatype(singl_parser->get_parser()->head->get_datatype()); } } + } else if (ResourceLoader::get_resource_type(autoload.path) == "PackedScene") { + Error err = OK; + Ref<GDScript> scr = GDScriptCache::get_packed_scene_script(autoload.path, err); + if (err == OK && scr.is_valid()) { + Ref<GDScriptParserRef> singl_parser = get_parser_for(scr->get_path()); + if (singl_parser.is_valid()) { + err = singl_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED); + if (err == OK) { + result = type_from_metatype(singl_parser->get_parser()->head->get_datatype()); + } + } + } } result.is_constant = true; p_identifier->set_datatype(result); @@ -3236,9 +3261,28 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) { } } else { // TODO: Don't load if validating: use completion cache. - p_preload->resource = ResourceLoader::load(p_preload->resolved_path); - if (p_preload->resource.is_null()) { - push_error(vformat(R"(Could not preload resource file "%s".)", p_preload->resolved_path), p_preload->path); + + // Must load GDScript and PackedScenes separately to permit cyclic references + // as ResourceLoader::load() detect and reject those. + if (ResourceLoader::get_resource_type(p_preload->resolved_path) == "GDScript") { + Error err = OK; + Ref<GDScript> res = GDScriptCache::get_shallow_script(p_preload->resolved_path, err, parser->script_path); + p_preload->resource = res; + if (err != OK) { + push_error(vformat(R"(Could not preload resource script "%s".)", p_preload->resolved_path), p_preload->path); + } + } else if (ResourceLoader::get_resource_type(p_preload->resolved_path) == "PackedScene") { + Error err = OK; + Ref<PackedScene> res = GDScriptCache::get_packed_scene(p_preload->resolved_path, err, parser->script_path); + p_preload->resource = res; + if (err != OK) { + push_error(vformat(R"(Could not preload resource scene "%s".)", p_preload->resolved_path), p_preload->path); + } + } else { + p_preload->resource = ResourceLoader::load(p_preload->resolved_path); + if (p_preload->resource.is_null()) { + push_error(vformat(R"(Could not preload resource file "%s".)", p_preload->resolved_path), p_preload->path); + } } } } @@ -3280,6 +3324,17 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri // Just try to get it. bool valid = false; Variant value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid); + + // If it's a GDScript instance, try to get the full script. Maybe it's not still completely loaded. + Ref<GDScript> gdscr = Ref<GDScript>(p_subscript->base->reduced_value); + if (!valid && gdscr.is_valid()) { + Error err = OK; + GDScriptCache::get_full_script(gdscr->get_path(), err); + if (err == OK) { + value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid); + } + } + if (!valid) { push_error(vformat(R"(Cannot get member "%s" from "%s".)", p_subscript->attribute->name, p_subscript->base->reduced_value), p_subscript->index); result_type.kind = GDScriptParser::DataType::VARIANT; @@ -3662,50 +3717,43 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va scr = obj->get_script(); } if (scr.is_valid()) { - if (scr->is_valid()) { - result.script_type = scr; - result.script_path = scr->get_path(); - Ref<GDScript> gds = scr; - if (gds.is_valid()) { - result.kind = GDScriptParser::DataType::CLASS; - // This might be an inner class, so we want to get the parser for the root. - // But still get the inner class from that tree. - GDScript *current = gds.ptr(); - List<StringName> class_chain; - while (current->_owner) { - // Push to front so it's in reverse. - class_chain.push_front(current->name); - current = current->_owner; - } - - Ref<GDScriptParserRef> ref = get_parser_for(current->get_path()); - if (ref.is_null()) { - push_error("Could not find script in path.", p_source); - GDScriptParser::DataType error_type; - error_type.kind = GDScriptParser::DataType::VARIANT; - return error_type; - } - ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED); + result.script_type = scr; + result.script_path = scr->get_path(); + Ref<GDScript> gds = scr; + if (gds.is_valid()) { + result.kind = GDScriptParser::DataType::CLASS; + // This might be an inner class, so we want to get the parser for the root. + // But still get the inner class from that tree. + GDScript *current = gds.ptr(); + List<StringName> class_chain; + while (current->_owner) { + // Push to front so it's in reverse. + class_chain.push_front(current->name); + current = current->_owner; + } - GDScriptParser::ClassNode *found = ref->get_parser()->head; + Ref<GDScriptParserRef> ref = get_parser_for(current->get_path()); + if (ref.is_null()) { + push_error("Could not find script in path.", p_source); + GDScriptParser::DataType error_type; + error_type.kind = GDScriptParser::DataType::VARIANT; + return error_type; + } + ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED); - // It should be okay to assume this exists, since we have a complete script already. - for (const StringName &E : class_chain) { - found = found->get_member(E).m_class; - } + GDScriptParser::ClassNode *found = ref->get_parser()->head; - result.class_type = found; - result.script_path = ref->get_parser()->script_path; - } else { - result.kind = GDScriptParser::DataType::SCRIPT; + // It should be okay to assume this exists, since we have a complete script already. + for (const StringName &E : class_chain) { + found = found->get_member(E).m_class; } - result.native_type = scr->get_instance_base_type(); + + result.class_type = found; + result.script_path = ref->get_parser()->script_path; } else { - push_error(vformat(R"(Constant value uses script from "%s" which is loaded but not compiled.)", scr->get_path()), p_source); - result.kind = GDScriptParser::DataType::VARIANT; - result.type_source = GDScriptParser::DataType::UNDETECTED; - result.is_meta_type = false; + result.kind = GDScriptParser::DataType::SCRIPT; } + result.native_type = scr->get_instance_base_type(); } else { result.kind = GDScriptParser::DataType::NATIVE; if (result.native_type == GDScriptNativeClass::get_class_static()) { diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index 217a856ce0..23a3ad39a5 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -45,7 +45,7 @@ class GDScriptAnalyzer { List<GDScriptParser::LambdaNode *> lambda_stack; // Tests for detecting invalid overloading of script members - static _FORCE_INLINE_ bool has_member_name_conflict_in_script_class(const StringName &p_name, const GDScriptParser::ClassNode *p_current_class_node); + static _FORCE_INLINE_ bool has_member_name_conflict_in_script_class(const StringName &p_name, const GDScriptParser::ClassNode *p_current_class_node, const GDScriptParser::Node *p_member); static _FORCE_INLINE_ bool has_member_name_conflict_in_native_type(const StringName &p_name, const StringName &p_native_type_string); Error check_native_member_name_conflict(const StringName &p_member_name, const GDScriptParser::Node *p_member_node, const StringName &p_native_type_string); Error check_class_member_name_conflict(const GDScriptParser::ClassNode *p_class_node, const StringName &p_member_name, const GDScriptParser::Node *p_member_node); diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 03a101b9fc..f35318e4c6 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -36,6 +36,7 @@ #include "gdscript_analyzer.h" #include "gdscript_compiler.h" #include "gdscript_parser.h" +#include "scene/resources/packed_scene.h" bool GDScriptParserRef::is_valid() const { return parser != nullptr; @@ -96,27 +97,88 @@ Error GDScriptParserRef::raise_status(Status p_new_status) { return result; } -GDScriptParserRef::~GDScriptParserRef() { +void GDScriptParserRef::clear() { + if (cleared) { + return; + } + cleared = true; + if (parser != nullptr) { memdelete(parser); } + if (analyzer != nullptr) { memdelete(analyzer); } - MutexLock lock(GDScriptCache::singleton->lock); +} + +GDScriptParserRef::~GDScriptParserRef() { + clear(); + + MutexLock lock(GDScriptCache::singleton->mutex); GDScriptCache::singleton->parser_map.erase(path); } GDScriptCache *GDScriptCache::singleton = nullptr; +void GDScriptCache::move_script(const String &p_from, const String &p_to) { + if (singleton == nullptr || p_from == p_to) { + return; + } + + MutexLock lock(singleton->mutex); + + for (KeyValue<String, HashSet<String>> &E : singleton->packed_scene_dependencies) { + if (E.value.has(p_from)) { + E.value.insert(p_to); + E.value.erase(p_from); + } + } + + if (singleton->parser_map.has(p_from) && !p_from.is_empty()) { + singleton->parser_map[p_to] = singleton->parser_map[p_from]; + } + singleton->parser_map.erase(p_from); + + if (singleton->shallow_gdscript_cache.has(p_from) && !p_from.is_empty()) { + singleton->shallow_gdscript_cache[p_to] = singleton->shallow_gdscript_cache[p_from]; + } + singleton->shallow_gdscript_cache.erase(p_from); + + if (singleton->full_gdscript_cache.has(p_from) && !p_from.is_empty()) { + singleton->full_gdscript_cache[p_to] = singleton->full_gdscript_cache[p_from]; + } + singleton->full_gdscript_cache.erase(p_from); +} + void GDScriptCache::remove_script(const String &p_path) { - MutexLock lock(singleton->lock); + if (singleton == nullptr) { + return; + } + + MutexLock lock(singleton->mutex); + + for (KeyValue<String, HashSet<String>> &E : singleton->packed_scene_dependencies) { + if (!E.value.has(p_path)) { + continue; + } + E.value.erase(p_path); + } + + GDScriptCache::clear_unreferenced_packed_scenes(); + + if (singleton->parser_map.has(p_path)) { + singleton->parser_map[p_path]->clear(); + singleton->parser_map.erase(p_path); + } + + singleton->dependencies.erase(p_path); singleton->shallow_gdscript_cache.erase(p_path); singleton->full_gdscript_cache.erase(p_path); } Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptParserRef::Status p_status, Error &r_error, const String &p_owner) { - MutexLock lock(singleton->lock); + MutexLock lock(singleton->mutex); Ref<GDScriptParserRef> ref; if (!p_owner.is_empty()) { singleton->dependencies[p_owner].insert(p_path); @@ -163,7 +225,7 @@ String GDScriptCache::get_source_code(const String &p_path) { } Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, Error &r_error, const String &p_owner) { - MutexLock lock(singleton->lock); + MutexLock lock(singleton->mutex); if (!p_owner.is_empty()) { singleton->dependencies[p_owner].insert(p_path); } @@ -174,23 +236,22 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, Error &r_e return singleton->shallow_gdscript_cache[p_path]; } - Ref<GDScriptParserRef> parser_ref = get_parser(p_path, GDScriptParserRef::PARSED, r_error); - if (r_error != OK) { - return Ref<GDScript>(); - } - Ref<GDScript> script; script.instantiate(); script->set_path(p_path, true); script->load_source_code(p_path); - GDScriptCompiler::make_scripts(script.ptr(), parser_ref->get_parser()->get_tree(), true); - singleton->shallow_gdscript_cache[p_path] = script.ptr(); + Ref<GDScriptParserRef> parser_ref = get_parser(p_path, GDScriptParserRef::PARSED, r_error); + if (r_error == OK) { + GDScriptCompiler::make_scripts(script.ptr(), parser_ref->get_parser()->get_tree(), true); + } + + singleton->shallow_gdscript_cache[p_path] = script; return script; } Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_error, const String &p_owner, bool p_update_from_disk) { - MutexLock lock(singleton->lock); + MutexLock lock(singleton->mutex); if (!p_owner.is_empty()) { singleton->dependencies[p_owner].insert(p_path); @@ -220,19 +281,21 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro return script; } + singleton->full_gdscript_cache[p_path] = script; + singleton->shallow_gdscript_cache.erase(p_path); + r_error = script->reload(true); if (r_error) { + singleton->shallow_gdscript_cache[p_path] = script; + singleton->full_gdscript_cache.erase(p_path); return script; } - singleton->full_gdscript_cache[p_path] = script.ptr(); - singleton->shallow_gdscript_cache.erase(p_path); - return script; } Ref<GDScript> GDScriptCache::get_cached_script(const String &p_path) { - MutexLock lock(singleton->lock); + MutexLock lock(singleton->mutex); if (singleton->full_gdscript_cache.has(p_path)) { return singleton->full_gdscript_cache[p_path]; @@ -246,11 +309,11 @@ Ref<GDScript> GDScriptCache::get_cached_script(const String &p_path) { } Error GDScriptCache::finish_compiling(const String &p_owner) { - MutexLock lock(singleton->lock); + MutexLock lock(singleton->mutex); // Mark this as compiled. Ref<GDScript> script = get_cached_script(p_owner); - singleton->full_gdscript_cache[p_owner] = script.ptr(); + singleton->full_gdscript_cache[p_owner] = script; singleton->shallow_gdscript_cache.erase(p_owner); HashSet<String> depends = singleton->dependencies[p_owner]; @@ -271,13 +334,103 @@ Error GDScriptCache::finish_compiling(const String &p_owner) { return err; } +Ref<PackedScene> GDScriptCache::get_packed_scene(const String &p_path, Error &r_error, const String &p_owner) { + MutexLock lock(singleton->mutex); + + if (singleton->packed_scene_cache.has(p_path)) { + singleton->packed_scene_dependencies[p_path].insert(p_owner); + return singleton->packed_scene_cache[p_path]; + } + + Ref<PackedScene> scene = ResourceCache::get_ref(p_path); + if (scene.is_valid()) { + singleton->packed_scene_cache[p_path] = scene; + singleton->packed_scene_dependencies[p_path].insert(p_owner); + return scene; + } + scene.instantiate(); + + r_error = OK; + if (p_path.is_empty()) { + r_error = ERR_FILE_BAD_PATH; + return scene; + } + + scene->set_path(p_path); + singleton->packed_scene_cache[p_path] = scene; + singleton->packed_scene_dependencies[p_path].insert(p_owner); + + scene->recreate_state(); + scene->reload_from_file(); + return scene; +} + +Ref<GDScript> GDScriptCache::get_packed_scene_script(const String &p_path, Error &r_error) { + r_error = OK; + Ref<PackedScene> scene = get_packed_scene(p_path, r_error); + + if (r_error != OK) { + return Ref<GDScript>(); + } + + int node_count = scene->get_state()->get_node_count(); + if (node_count == 0) { + return Ref<GDScript>(); + } + + const int ROOT_NODE = 0; + for (int i = 0; i < scene->get_state()->get_node_property_count(ROOT_NODE); i++) { + if (scene->get_state()->get_node_property_name(ROOT_NODE, i) != SNAME("script")) { + continue; + } + + return scene->get_state()->get_node_property_value(ROOT_NODE, i); + } + + return Ref<GDScript>(); +} + +void GDScriptCache::clear_unreferenced_packed_scenes() { + if (singleton == nullptr) { + return; + } + + MutexLock lock(singleton->mutex); + + for (KeyValue<String, HashSet<String>> &E : singleton->packed_scene_dependencies) { + if (E.value.size() > 0 || !ResourceLoader::is_imported(E.key)) { + continue; + } + + singleton->packed_scene_dependencies.erase(E.key); + singleton->packed_scene_cache.erase(E.key); + } +} + GDScriptCache::GDScriptCache() { singleton = this; } GDScriptCache::~GDScriptCache() { + destructing = true; + + RBSet<Ref<GDScriptParserRef>> parser_map_refs; + for (KeyValue<String, GDScriptParserRef *> &E : parser_map) { + parser_map_refs.insert(E.value); + } + + for (Ref<GDScriptParserRef> &E : parser_map_refs) { + if (E.is_valid()) + E->clear(); + } + + parser_map_refs.clear(); parser_map.clear(); shallow_gdscript_cache.clear(); full_gdscript_cache.clear(); + + packed_scene_cache.clear(); + packed_scene_dependencies.clear(); + singleton = nullptr; } diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h index fcd240ba8d..0f9d87aa67 100644 --- a/modules/gdscript/gdscript_cache.h +++ b/modules/gdscript/gdscript_cache.h @@ -36,6 +36,7 @@ #include "core/templates/hash_map.h" #include "core/templates/hash_set.h" #include "gdscript.h" +#include "scene/resources/packed_scene.h" class GDScriptAnalyzer; class GDScriptParser; @@ -56,6 +57,7 @@ private: Status status = EMPTY; Error result = OK; String path; + bool cleared = false; friend class GDScriptCache; @@ -64,6 +66,7 @@ public: Status get_status() const; GDScriptParser *get_parser() const; Error raise_status(Status p_new_status); + void clear(); GDScriptParserRef() {} ~GDScriptParserRef(); @@ -72,19 +75,25 @@ public: class GDScriptCache { // String key is full path. HashMap<String, GDScriptParserRef *> parser_map; - HashMap<String, GDScript *> shallow_gdscript_cache; - HashMap<String, GDScript *> full_gdscript_cache; + HashMap<String, Ref<GDScript>> shallow_gdscript_cache; + HashMap<String, Ref<GDScript>> full_gdscript_cache; HashMap<String, HashSet<String>> dependencies; + HashMap<String, Ref<PackedScene>> packed_scene_cache; + HashMap<String, HashSet<String>> packed_scene_dependencies; friend class GDScript; friend class GDScriptParserRef; + friend class GDScriptInstance; static GDScriptCache *singleton; - Mutex lock; - static void remove_script(const String &p_path); + bool destructing = false; + + Mutex mutex; public: + static void move_script(const String &p_from, const String &p_to); + static void remove_script(const String &p_path); static Ref<GDScriptParserRef> get_parser(const String &p_path, GDScriptParserRef::Status status, Error &r_error, const String &p_owner = String()); static String get_source_code(const String &p_path); static Ref<GDScript> get_shallow_script(const String &p_path, Error &r_error, const String &p_owner = String()); @@ -92,6 +101,17 @@ public: static Ref<GDScript> get_cached_script(const String &p_path); static Error finish_compiling(const String &p_owner); + static Ref<PackedScene> get_packed_scene(const String &p_path, Error &r_error, const String &p_owner = ""); + static Ref<GDScript> get_packed_scene_script(const String &p_path, Error &r_error); + static void clear_unreferenced_packed_scenes(); + + static bool is_destructing() { + if (singleton == nullptr) { + return true; + } + return singleton->destructing; + }; + GDScriptCache(); ~GDScriptCache(); }; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 824625b745..f0ceb42f89 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -141,6 +141,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D result.script_type_ref = script; } result.script_type = script.ptr(); + result.native_type = p_datatype.native_type; } } break; case GDScriptParser::DataType::ENUM: @@ -354,11 +355,22 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (class_node->identifier && class_node->identifier->name == identifier) { res = Ref<GDScript>(main_script); } else { - res = ResourceLoader::load(ScriptServer::get_global_class_path(identifier)); - if (res.is_null()) { - _set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression); - r_error = ERR_COMPILATION_FAILED; - return GDScriptCodeGenerator::Address(); + String global_class_path = ScriptServer::get_global_class_path(identifier); + if (ResourceLoader::get_resource_type(global_class_path) == "GDScript") { + Error err = OK; + res = GDScriptCache::get_full_script(global_class_path, err); + if (err != OK) { + _set_error("Can't load global class " + String(identifier), p_expression); + r_error = ERR_COMPILATION_FAILED; + return GDScriptCodeGenerator::Address(); + } + } else { + res = ResourceLoader::load(global_class_path); + if (res.is_null()) { + _set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression); + r_error = ERR_COMPILATION_FAILED; + return GDScriptCodeGenerator::Address(); + } } } @@ -2172,6 +2184,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri parsing_classes.insert(p_script); + p_script->clearing = true; #ifdef TOOLS_ENABLED p_script->doc_functions.clear(); p_script->doc_variables.clear(); @@ -2194,10 +2207,24 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri p_script->base = Ref<GDScript>(); p_script->_base = nullptr; p_script->members.clear(); + + // This makes possible to clear script constants and member_functions without heap-use-after-free errors. + HashMap<StringName, Variant> constants; + for (const KeyValue<StringName, Variant> &E : p_script->constants) { + constants.insert(E.key, E.value); + } p_script->constants.clear(); + constants.clear(); + HashMap<StringName, GDScriptFunction *> member_functions; for (const KeyValue<StringName, GDScriptFunction *> &E : p_script->member_functions) { + member_functions.insert(E.key, E.value); + } + p_script->member_functions.clear(); + for (const KeyValue<StringName, GDScriptFunction *> &E : member_functions) { memdelete(E.value); } + member_functions.clear(); + if (p_script->implicit_initializer) { memdelete(p_script->implicit_initializer); } @@ -2212,6 +2239,8 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri p_script->implicit_initializer = nullptr; p_script->implicit_ready = nullptr; + p_script->clearing = false; + p_script->tool = parser->is_tool(); if (!p_script->name.is_empty()) { @@ -2454,10 +2483,8 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri } #ifdef TOOLS_ENABLED - p_script->member_lines[name] = inner_class->start_line; #endif - p_script->constants.insert(name, subclass); //once parsed, goes to the list of constants } diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 48a6e3fb51..7628bffd22 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -2512,7 +2512,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } static bool _get_subscript_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::SubscriptNode *p_subscript, GDScriptParser::DataType &r_base_type, Variant *r_base = nullptr) { - if (p_subscript->base->type == GDScriptParser::Node::IDENTIFIER) { + if (p_subscript->base->type == GDScriptParser::Node::IDENTIFIER && p_context.base != nullptr) { const GDScriptParser::GetNodeNode *get_node = nullptr; const GDScriptParser::IdentifierNode *identifier_node = static_cast<GDScriptParser::IdentifierNode *>(p_subscript->base); diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 98b3e40f1b..24a614b1ad 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -149,10 +149,17 @@ GDScriptFunction::GDScriptFunction() { } GDScriptFunction::~GDScriptFunction() { + get_script()->member_functions.erase(name); + for (int i = 0; i < lambdas.size(); i++) { memdelete(lambdas[i]); } + for (int i = 0; i < argument_types.size(); i++) { + argument_types.write[i].script_type_ref = Ref<Script>(); + } + return_type.script_type_ref = Ref<Script>(); + #ifdef DEBUG_ENABLED MutexLock lock(GDScriptLanguage::get_singleton()->mutex); diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index e44038d6da..6e5f7a8520 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -430,6 +430,7 @@ public: }; private: + friend class GDScript; friend class GDScriptCompiler; friend class GDScriptByteCodeGenerator; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 053d81893d..7f2f49f336 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -147,6 +147,10 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@warning_ignore", PropertyInfo(Variant::STRING, "warning")), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, varray(), true); // Networking. register_annotation(MethodInfo("@rpc", PropertyInfo(Variant::STRING, "mode"), PropertyInfo(Variant::STRING, "sync"), PropertyInfo(Variant::STRING, "transfer_mode"), PropertyInfo(Variant::INT, "transfer_channel")), AnnotationInfo::FUNCTION, &GDScriptParser::rpc_annotation, varray("", "", "", 0), true); + +#ifdef DEBUG_ENABLED + is_ignoring_warnings = !(bool)GLOBAL_GET("debug/gdscript/warnings/enable"); +#endif } GDScriptParser::~GDScriptParser() { @@ -648,7 +652,13 @@ GDScriptParser::ClassNode *GDScriptParser::parse_class() { if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier for the class name after "class".)")) { n_class->identifier = parse_identifier(); if (n_class->outer) { - n_class->fqcn = n_class->outer->fqcn + "::" + n_class->identifier->name; + String fqcn = n_class->outer->fqcn; + if (fqcn.is_empty()) { + fqcn = script_path; + } + n_class->fqcn = fqcn + "::" + n_class->identifier->name; + } else { + n_class->fqcn = n_class->identifier->name; } } @@ -1535,7 +1545,7 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, VariableNode *variable = static_cast<VariableNode *>(statement); const SuiteNode::Local &local = current_suite->get_local(variable->identifier->name); if (local.type != SuiteNode::Local::UNDEFINED) { - push_error(vformat(R"(There is already a %s named "%s" declared in this scope.)", local.get_name(), variable->identifier->name)); + push_error(vformat(R"(There is already a %s named "%s" declared in this scope.)", local.get_name(), variable->identifier->name), variable->identifier); } current_suite->add_local(variable, current_function); break; @@ -1550,7 +1560,7 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, } else { name = "variable"; } - push_error(vformat(R"(There is already a %s named "%s" declared in this scope.)", name, constant->identifier->name)); + push_error(vformat(R"(There is already a %s named "%s" declared in this scope.)", name, constant->identifier->name), constant->identifier); } current_suite->add_local(constant, current_function); break; diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index d8f5b866aa..f9a1c5a697 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -786,6 +786,7 @@ public: LOCAL_VARIABLE, LOCAL_ITERATOR, // `for` loop iterator. LOCAL_BIND, // Pattern bind. + MEMBER_SIGNAL, MEMBER_VARIABLE, MEMBER_CONSTANT, INHERITED_VARIABLE, @@ -1216,13 +1217,14 @@ private: bool can_break = false; bool can_continue = false; bool is_continue_match = false; // Whether a `continue` will act on a `match`. - bool is_ignoring_warnings = false; List<bool> multiline_stack; ClassNode *head = nullptr; Node *list = nullptr; List<ParserError> errors; + #ifdef DEBUG_ENABLED + bool is_ignoring_warnings = false; List<GDScriptWarning> warnings; HashSet<String> ignored_warnings; HashSet<uint32_t> ignored_warning_codes; diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index a0c107aa53..36bc051643 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -96,7 +96,7 @@ String GDScriptWarning::get_message() const { } break; case RETURN_VALUE_DISCARDED: { CHECK_SYMBOLS(1); - return "The function '" + symbols[0] + "()' returns a value, but this value is never used."; + return "The function '" + symbols[0] + "()' returns a value that will be discarded if not used."; } break; case PROPERTY_USED_AS_FUNCTION: { CHECK_SYMBOLS(2); @@ -171,6 +171,10 @@ int GDScriptWarning::get_default_value(Code p_code) { if (get_name_from_code(p_code).to_lower().begins_with("unsafe_")) { return WarnLevel::IGNORE; } + // Too spammy by default on common cases (connect, Tween, etc.). + if (p_code == RETURN_VALUE_DISCARDED) { + return WarnLevel::IGNORE; + } return WarnLevel::WARN; } diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index 1ccbf9d150..7f42643c8f 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -251,7 +251,10 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { return false; } } else { - if (next.get_extension().to_lower() == "gd") { + if (next.ends_with(".notest.gd")) { + next = dir->get_next(); + continue; + } else if (next.get_extension().to_lower() == "gd") { #ifndef DEBUG_ENABLED // On release builds, skip tests marked as debug only. Error open_err = OK; @@ -597,6 +600,9 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { } enable_stdout(); + + GDScriptCache::remove_script(script->get_path()); + return result; } diff --git a/modules/gdscript/tests/scripts/analyzer/errors/overload_script_variable.gd b/modules/gdscript/tests/scripts/analyzer/errors/overload_script_variable.gd new file mode 100644 index 0000000000..5c8b9fa4ae --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/overload_script_variable.gd @@ -0,0 +1,6 @@ +extends Node + +var script: int + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/overload_script_variable.out b/modules/gdscript/tests/scripts/analyzer/errors/overload_script_variable.out new file mode 100644 index 0000000000..8454aaa404 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/overload_script_variable.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Member "script" redefined (original in native class 'Node') diff --git a/modules/gdscript/tests/scripts/analyzer/errors/variable_overloads_superclass_function.gd b/modules/gdscript/tests/scripts/analyzer/errors/variable_overloads_superclass_function.gd new file mode 100644 index 0000000000..28561ff94b --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/variable_overloads_superclass_function.gd @@ -0,0 +1,9 @@ +func test(): + pass + +class A: + func overload_me(): + pass + +class B extends A: + var overload_me diff --git a/modules/gdscript/tests/scripts/analyzer/errors/variable_overloads_superclass_function.out b/modules/gdscript/tests/scripts/analyzer/errors/variable_overloads_superclass_function.out new file mode 100644 index 0000000000..32357f9f6a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/variable_overloads_superclass_function.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +The member "overload_me" already exists in parent class A. diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.notest.gd index ea744e3027..c3fc176679 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.notest.gd @@ -1,7 +1,4 @@ const A := 42 -func test(): - pass - func something(): return "OK" diff --git a/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd b/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd index 276875dd5a..9d0324ead8 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd @@ -1,4 +1,4 @@ -const Constants = preload("gdscript_to_preload.gd") +const Constants = preload("gdscript_to_preload.notest.gd") func test(): var a := Constants.A diff --git a/modules/gdscript/tests/scripts/analyzer/features/preload_cyclic_reference.gd b/modules/gdscript/tests/scripts/analyzer/features/preload_cyclic_reference.gd new file mode 100644 index 0000000000..b730453a8a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/preload_cyclic_reference.gd @@ -0,0 +1,4 @@ +const A = preload("preload_cyclic_reference_a.notest.gd") + +func test(): + A.test_cyclic_reference() diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out b/modules/gdscript/tests/scripts/analyzer/features/preload_cyclic_reference.out index d73c5eb7cd..14bb971221 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.out +++ b/modules/gdscript/tests/scripts/analyzer/features/preload_cyclic_reference.out @@ -1 +1,2 @@ GDTEST_OK +godot diff --git a/modules/gdscript/tests/scripts/analyzer/features/preload_cyclic_reference_a.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/preload_cyclic_reference_a.notest.gd new file mode 100644 index 0000000000..7a6035ded1 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/preload_cyclic_reference_a.notest.gd @@ -0,0 +1,12 @@ +const B = preload("preload_cyclic_reference_b.notest.gd") + +const WAITING_FOR = "godot" + +static func test_cyclic_reference(): + B.test_cyclic_reference() + +static func test_cyclic_reference_2(): + B.test_cyclic_reference_2() + +static func test_cyclic_reference_3(): + B.test_cyclic_reference_3() diff --git a/modules/gdscript/tests/scripts/analyzer/features/preload_cyclic_reference_b.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/preload_cyclic_reference_b.notest.gd new file mode 100644 index 0000000000..3ea5b01156 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/preload_cyclic_reference_b.notest.gd @@ -0,0 +1,10 @@ +const A = preload("preload_cyclic_reference_a.notest.gd") + +static func test_cyclic_reference(): + A.test_cyclic_reference_2() + +static func test_cyclic_reference_2(): + A.test_cyclic_reference_3() + +static func test_cyclic_reference_3(): + print(A.WAITING_FOR) diff --git a/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd index 5f73064cc0..beabf3d2e5 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/use_preload_script_as_type.gd @@ -1,4 +1,4 @@ -const preloaded : GDScript = preload("gdscript_to_preload.gd") +const preloaded : GDScript = preload("gdscript_to_preload.notest.gd") func test(): var preloaded_instance: preloaded = preloaded.new() diff --git a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out index 13f759dd46..e89bb9226f 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out +++ b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out @@ -2,4 +2,4 @@ GDTEST_OK >> WARNING >> Line: 6 >> RETURN_VALUE_DISCARDED ->> The function 'i_return_int()' returns a value, but this value is never used. +>> The function 'i_return_int()' returns a value that will be discarded if not used. diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml index 3cd0f5c0f9..588015de62 100644 --- a/modules/gltf/doc_classes/GLTFDocument.xml +++ b/modules/gltf/doc_classes/GLTFDocument.xml @@ -16,6 +16,8 @@ <param index="3" name="flags" type="int" default="0" /> <param index="4" name="bake_fps" type="int" default="30" /> <description> + Takes a [PackedByteArray] defining a gLTF and returns a [GLTFState] object through the [param state] parameter. + [b]Note:[/b] The [param base_path] tells [method append_from_buffer] where to find dependencies and can be empty. </description> </method> <method name="append_from_file"> @@ -26,6 +28,8 @@ <param index="3" name="bake_fps" type="int" default="30" /> <param index="4" name="base_path" type="String" default="""" /> <description> + Takes a path to a gLTF file and returns a [GLTFState] object through the [param state] parameter. + [b]Note:[/b] The [param base_path] tells [method append_from_file] where to find dependencies and can be empty. </description> </method> <method name="append_from_scene"> @@ -35,12 +39,14 @@ <param index="2" name="flags" type="int" default="0" /> <param index="3" name="bake_fps" type="int" default="30" /> <description> + Takes a Godot Engine scene node and returns a [GLTFState] object through the [param state] parameter. </description> </method> <method name="generate_buffer"> <return type="PackedByteArray" /> <param index="0" name="state" type="GLTFState" /> <description> + Takes a [GLTFState] object through the [param state] parameter and returns a gLTF [PackedByteArray]. </description> </method> <method name="generate_scene"> @@ -48,6 +54,23 @@ <param index="0" name="state" type="GLTFState" /> <param index="1" name="bake_fps" type="int" default="30" /> <description> + Takes a [GLTFState] object through the [param state] parameter and returns a Godot Engine scene node. + </description> + </method> + <method name="register_gltf_document_extension" qualifiers="static"> + <return type="void" /> + <param index="0" name="extension" type="GLTFDocumentExtension" /> + <param index="1" name="first_priority" type="bool" default="false" /> + <description> + Registers the given [GLTFDocumentExtension] instance with GLTFDocument. If [param first_priority] is true, this extension will be run first. Otherwise, it will be run last. + [b]Note:[/b] Like GLTFDocument itself, all GLTFDocumentExtension classes must be stateless in order to function properly. If you need to store data, use the [code]set_additional_data[/code] and [code]get_additional_data[/code] methods in [GLTFState] or [GLTFNode]. + </description> + </method> + <method name="unregister_gltf_document_extension" qualifiers="static"> + <return type="void" /> + <param index="0" name="extension" type="GLTFDocumentExtension" /> + <description> + Unregisters the given [GLTFDocumentExtension] instance. </description> </method> <method name="write_to_filesystem"> @@ -55,11 +78,9 @@ <param index="0" name="state" type="GLTFState" /> <param index="1" name="path" type="String" /> <description> + Takes a [GLTFState] object through the [param state] parameter and writes a glTF file to the filesystem. + [b]Note:[/b] The extension of the glTF file determines if it is a .glb binary file or a .gltf file. </description> </method> </methods> - <members> - <member name="extensions" type="GLTFDocumentExtension[]" setter="set_extensions" getter="get_extensions" default="[]"> - </member> - </members> </class> diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml index 936794976d..87d3d9bcb0 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml @@ -5,10 +5,22 @@ </brief_description> <description> Extends the functionality of the [GLTFDocument] class by allowing you to run arbitrary code at various stages of GLTF import or export. + To use, make a new class extending GLTFDocumentExtension, override any methods you need, make an instance of your class, and register it using [method GLTFDocument.register_gltf_document_extension]. + [b]Note:[/b] Like GLTFDocument itself, all GLTFDocumentExtension classes must be stateless in order to function properly. If you need to store data, use the [code]set_additional_data[/code] and [code]get_additional_data[/code] methods in [GLTFState] or [GLTFNode]. </description> <tutorials> </tutorials> <methods> + <method name="_convert_scene_node" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="state" type="GLTFState" /> + <param index="1" name="gltf_node" type="GLTFNode" /> + <param index="2" name="scene_node" type="Node" /> + <description> + Part of the export process. This method is run after [method _export_preflight] and before [method _export_node]. + Runs when converting the data from a Godot scene node. This method can be used to process the Godot scene node data into a format that can be used by [method _export_node]. + </description> + </method> <method name="_export_node" qualifiers="virtual"> <return type="int" /> <param index="0" name="state" type="GLTFState" /> @@ -16,23 +28,40 @@ <param index="2" name="json" type="Dictionary" /> <param index="3" name="node" type="Node" /> <description> + Part of the export process. This method is run after [method _convert_scene_node] and before [method _export_post]. + This method can be used to modify the final JSON of each node. </description> </method> <method name="_export_post" qualifiers="virtual"> <return type="int" /> <param index="0" name="state" type="GLTFState" /> <description> + Part of the export process. This method is run last, after all other parts of the export process. + This method can be used to modify the final JSON of the generated GLTF file. </description> </method> <method name="_export_preflight" qualifiers="virtual"> <return type="int" /> <param index="0" name="root" type="Node" /> <description> + Part of the export process. This method is run first, before all other parts of the export process. + The return value is used to determine if this GLTFDocumentExtension class should be used for exporting a given GLTF file. If [constant OK], the export will use this GLTFDocumentExtension class. If not overridden, [constant OK] is returned. + </description> + </method> + <method name="_generate_scene_node" qualifiers="virtual"> + <return type="Node3D" /> + <param index="0" name="state" type="GLTFState" /> + <param index="1" name="gltf_node" type="GLTFNode" /> + <param index="2" name="scene_parent" type="Node" /> + <description> + Part of the import process. This method is run after [method _parse_node_extensions] and before [method _import_post_parse]. + Runs when generating a Godot scene node from a GLTFNode. The returned node will be added to the scene tree. Multiple nodes can be generated in this step if they are added as a child of the returned node. </description> </method> <method name="_get_supported_extensions" qualifiers="virtual"> <return type="PackedStringArray" /> <description> + Part of the import process. This method is run after [method _import_preflight] and before [method _parse_node_extensions]. Returns an array of the GLTF extensions supported by this GLTFDocumentExtension class. This is used to validate if a GLTF file with required extensions can be loaded. </description> </method> @@ -43,6 +72,8 @@ <param index="2" name="json" type="Dictionary" /> <param index="3" name="node" type="Node" /> <description> + Part of the import process. This method is run after [method _import_post_parse] and before [method _import_post]. + This method can be used to make modifications to each of the generated Godot scene nodes. </description> </method> <method name="_import_post" qualifiers="virtual"> @@ -50,18 +81,35 @@ <param index="0" name="state" type="GLTFState" /> <param index="1" name="root" type="Node" /> <description> + Part of the import process. This method is run last, after all other parts of the import process. + This method can be used to modify the final Godot scene generated by the import process. </description> </method> <method name="_import_post_parse" qualifiers="virtual"> <return type="int" /> <param index="0" name="state" type="GLTFState" /> <description> + Part of the import process. This method is run after [method _generate_scene_node] and before [method _import_node]. + This method can be used to modify any of the data imported so far, including any scene nodes, before running the final per-node import step. </description> </method> <method name="_import_preflight" qualifiers="virtual"> <return type="int" /> <param index="0" name="state" type="GLTFState" /> + <param index="1" name="extensions" type="PackedStringArray" /> + <description> + Part of the import process. This method is run first, before all other parts of the import process. + The return value is used to determine if this GLTFDocumentExtension class should be used for importing a given GLTF file. If [constant OK], the import will use this GLTFDocumentExtension class. If not overridden, [constant OK] is returned. + </description> + </method> + <method name="_parse_node_extensions" qualifiers="virtual"> + <return type="int" /> + <param index="0" name="state" type="GLTFState" /> + <param index="1" name="gltf_node" type="GLTFNode" /> + <param index="2" name="extensions" type="Dictionary" /> <description> + Part of the import process. This method is run after [method _get_supported_extensions] and before [method _generate_scene_node]. + Runs when parsing the node extensions of a GLTFNode. This method can be used to process the extension JSON data into a format that can be used by [method _generate_scene_node]. </description> </method> </methods> diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index d0740cf7ca..9a554a0d49 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -66,7 +66,7 @@ </description> </method> <method name="get_materials"> - <return type="BaseMaterial3D[]" /> + <return type="Material[]" /> <description> </description> </method> @@ -169,7 +169,7 @@ </method> <method name="set_materials"> <return type="void" /> - <param index="0" name="materials" type="BaseMaterial3D[]" /> + <param index="0" name="materials" type="Material[]" /> <description> </description> </method> diff --git a/modules/gltf/editor/editor_scene_importer_gltf.h b/modules/gltf/editor/editor_scene_importer_gltf.h index b17a1e4eaa..edca038532 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.h +++ b/modules/gltf/editor/editor_scene_importer_gltf.h @@ -33,9 +33,6 @@ #ifdef TOOLS_ENABLED -#include "../gltf_document_extension.h" -#include "../gltf_state.h" - #include "editor/import/resource_importer_scene.h" class Animation; diff --git a/modules/gltf/gltf_document_extension.cpp b/modules/gltf/extensions/gltf_document_extension.cpp index 713779712c..f997fe8f66 100644 --- a/modules/gltf/gltf_document_extension.cpp +++ b/modules/gltf/extensions/gltf_document_extension.cpp @@ -31,50 +31,77 @@ #include "gltf_document_extension.h" void GLTFDocumentExtension::_bind_methods() { + // Import process. + GDVIRTUAL_BIND(_import_preflight, "state", "extensions"); GDVIRTUAL_BIND(_get_supported_extensions); - GDVIRTUAL_BIND(_import_preflight, "state"); + GDVIRTUAL_BIND(_parse_node_extensions, "state", "gltf_node", "extensions"); + GDVIRTUAL_BIND(_generate_scene_node, "state", "gltf_node", "scene_parent"); GDVIRTUAL_BIND(_import_post_parse, "state"); GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node"); GDVIRTUAL_BIND(_import_post, "state", "root"); + // Export process. GDVIRTUAL_BIND(_export_preflight, "root"); + GDVIRTUAL_BIND(_convert_scene_node, "state", "gltf_node", "scene_node"); GDVIRTUAL_BIND(_export_node, "state", "gltf_node", "json", "node"); GDVIRTUAL_BIND(_export_post, "state"); } +// Import process. +Error GLTFDocumentExtension::import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions) { + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + int err = OK; + GDVIRTUAL_CALL(_import_preflight, p_state, p_extensions, err); + return Error(err); +} + Vector<String> GLTFDocumentExtension::get_supported_extensions() { Vector<String> ret; GDVIRTUAL_CALL(_get_supported_extensions, ret); return ret; } -Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) { - ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER); +Error GLTFDocumentExtension::parse_node_extensions(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &p_extensions) { ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER); int err = OK; - GDVIRTUAL_CALL(_import_post, p_state, p_root, err); + GDVIRTUAL_CALL(_parse_node_extensions, p_state, p_gltf_node, p_extensions, err); return Error(err); } -Error GLTFDocumentExtension::import_preflight(Ref<GLTFState> p_state) { +Node3D *GLTFDocumentExtension::generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) { + ERR_FAIL_NULL_V(p_state, nullptr); + ERR_FAIL_NULL_V(p_gltf_node, nullptr); + ERR_FAIL_NULL_V(p_scene_parent, nullptr); + Node3D *ret_node = nullptr; + GDVIRTUAL_CALL(_generate_scene_node, p_state, p_gltf_node, p_scene_parent, ret_node); + return ret_node; +} + +Error GLTFDocumentExtension::import_post_parse(Ref<GLTFState> p_state) { ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); int err = OK; - GDVIRTUAL_CALL(_import_preflight, p_state, err); + GDVIRTUAL_CALL(_import_post_parse, p_state, err); return Error(err); } -Error GLTFDocumentExtension::import_post_parse(Ref<GLTFState> p_state) { +Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) { ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER); int err = OK; - GDVIRTUAL_CALL(_import_post_parse, p_state, err); + GDVIRTUAL_CALL(_import_node, p_state, p_gltf_node, r_dict, p_node, err); return Error(err); } -Error GLTFDocumentExtension::export_post(Ref<GLTFState> p_state) { +Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) { + ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER); ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); int err = OK; - GDVIRTUAL_CALL(_export_post, p_state, err); + GDVIRTUAL_CALL(_import_post, p_state, p_root, err); return Error(err); } + +// Export process. Error GLTFDocumentExtension::export_preflight(Node *p_root) { ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER); int err = OK; @@ -82,20 +109,25 @@ Error GLTFDocumentExtension::export_preflight(Node *p_root) { return Error(err); } -Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) { +void GLTFDocumentExtension::convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node) { + ERR_FAIL_NULL(p_state); + ERR_FAIL_NULL(p_gltf_node); + ERR_FAIL_NULL(p_scene_node); + GDVIRTUAL_CALL(_convert_scene_node, p_state, p_gltf_node, p_scene_node); +} + +Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) { ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER); ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER); int err = OK; - GDVIRTUAL_CALL(_import_node, p_state, p_gltf_node, r_dict, p_node, err); + GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err); return Error(err); } -Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) { +Error GLTFDocumentExtension::export_post(Ref<GLTFState> p_state) { ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); - ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER); - ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER); int err = OK; - GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err); + GDVIRTUAL_CALL(_export_post, p_state, err); return Error(err); } diff --git a/modules/gltf/gltf_document_extension.h b/modules/gltf/extensions/gltf_document_extension.h index d4bb3993dc..7cc9ca592f 100644 --- a/modules/gltf/gltf_document_extension.h +++ b/modules/gltf/extensions/gltf_document_extension.h @@ -31,8 +31,7 @@ #ifndef GLTF_DOCUMENT_EXTENSION_H #define GLTF_DOCUMENT_EXTENSION_H -#include "gltf_state.h" -#include "structures/gltf_node.h" +#include "../gltf_state.h" class GLTFDocumentExtension : public Resource { GDCLASS(GLTFDocumentExtension, Resource); @@ -41,20 +40,31 @@ protected: static void _bind_methods(); public: + // Import process. + virtual Error import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions); virtual Vector<String> get_supported_extensions(); - virtual Error import_preflight(Ref<GLTFState> p_state); + virtual Error parse_node_extensions(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &p_extensions); + virtual Node3D *generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent); virtual Error import_post_parse(Ref<GLTFState> p_state); - virtual Error export_post(Ref<GLTFState> p_state); + virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node); virtual Error import_post(Ref<GLTFState> p_state, Node *p_node); + // Export process. virtual Error export_preflight(Node *p_state); - virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node); + virtual void convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node); virtual Error export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node); + virtual Error export_post(Ref<GLTFState> p_state); + + // Import process. + GDVIRTUAL2R(int, _import_preflight, Ref<GLTFState>, Vector<String>); GDVIRTUAL0R(Vector<String>, _get_supported_extensions); - GDVIRTUAL1R(int, _import_preflight, Ref<GLTFState>); + GDVIRTUAL3R(int, _parse_node_extensions, Ref<GLTFState>, Ref<GLTFNode>, Dictionary); + GDVIRTUAL3R(Node3D *, _generate_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *); GDVIRTUAL1R(int, _import_post_parse, Ref<GLTFState>); GDVIRTUAL4R(int, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *); GDVIRTUAL2R(int, _import_post, Ref<GLTFState>, Node *); + // Export process. GDVIRTUAL1R(int, _export_preflight, Node *); + GDVIRTUAL3(_convert_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *); GDVIRTUAL4R(int, _export_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *); GDVIRTUAL1R(int, _export_post, Ref<GLTFState>); }; diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp index 1620900a04..49496afb62 100644 --- a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp +++ b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp @@ -30,7 +30,7 @@ #include "gltf_document_extension_convert_importer_mesh.h" -#include "gltf_state.h" +#include "../gltf_state.h" #include "core/error/error_macros.h" #include "scene/3d/mesh_instance_3d.h" diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.h b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.h index 00e664e73f..00e664e73f 100644 --- a/modules/gltf/gltf_document_extension_convert_importer_mesh.h +++ b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.h diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 99803ed05d..eb8f7e5ebc 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -31,8 +31,6 @@ #include "gltf_document.h" #include "extensions/gltf_spec_gloss.h" -#include "gltf_document_extension.h" -#include "gltf_document_extension_convert_importer_mesh.h" #include "gltf_state.h" #include "core/crypto/crypto_core.h" @@ -215,8 +213,7 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { return Error::FAILED; } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); err = ext->export_post(state); ERR_FAIL_COND_V(err != OK, err); @@ -454,8 +451,7 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) { node["children"] = children; } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); ERR_CONTINUE(!state->scene_nodes.find(i)); Error err = ext->export_node(state, gltf_node, node, state->scene_nodes[i]); @@ -629,6 +625,11 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) { node->light = light; } } + for (Ref<GLTFDocumentExtension> ext : document_extensions) { + ERR_CONTINUE(ext.is_null()); + Error err = ext->parse_node_extensions(state, node, extensions); + ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error " + itos(err) + " when parsing node extensions for node " + node->get_name() + " in file " + state->filename + ". Continuing."); + } } if (n.has("children")) { @@ -2483,12 +2484,12 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { if (surface_i < instance_materials.size()) { v = instance_materials.get(surface_i); } - Ref<BaseMaterial3D> mat = v; + Ref<Material> mat = v; if (!mat.is_valid()) { mat = import_mesh->get_surface_material(surface_i); } if (mat.is_valid()) { - HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex>::Iterator material_cache_i = state->material_cache.find(mat); + HashMap<Ref<Material>, GLTFMaterialIndex>::Iterator material_cache_i = state->material_cache.find(mat); if (material_cache_i && material_cache_i->value != -1) { primitive["material"] = material_cache_i->value; } else { @@ -2936,16 +2937,18 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } } - Ref<BaseMaterial3D> mat; + Ref<Material> mat; String mat_name; if (!state->discard_meshes_and_materials) { if (p.has("material")) { const int material = p["material"]; ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT); - Ref<BaseMaterial3D> mat3d = state->materials[material]; + Ref<Material> mat3d = state->materials[material]; ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT); - if (has_vertex_color) { - mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + + Ref<BaseMaterial3D> base_material = mat3d; + if (has_vertex_color && base_material.is_valid()) { + base_material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); } mat = mat3d; @@ -2953,7 +2956,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { Ref<StandardMaterial3D> mat3d; mat3d.instantiate(); if (has_vertex_color) { - mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); } mat = mat3d; } @@ -3381,8 +3384,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { Array materials; for (int32_t i = 0; i < state->materials.size(); i++) { Dictionary d; - - Ref<BaseMaterial3D> material = state->materials[i]; + Ref<Material> material = state->materials[i]; if (material.is_null()) { materials.push_back(d); continue; @@ -3390,11 +3392,12 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { if (!material->get_name().is_empty()) { d["name"] = _gen_unique_name(state, material->get_name()); } - { + Ref<BaseMaterial3D> base_material = material; + if (base_material.is_valid()) { Dictionary mr; { Array arr; - const Color c = material->get_albedo().srgb_to_linear(); + const Color c = base_material->get_albedo().srgb_to_linear(); arr.push_back(c.r); arr.push_back(c.g); arr.push_back(c.b); @@ -3403,167 +3406,169 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { } { Dictionary bct; - Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - GLTFTextureIndex gltf_texture_index = -1; + if (base_material.is_valid()) { + Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); + GLTFTextureIndex gltf_texture_index = -1; - if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { - albedo_texture->set_name(material->get_name() + "_albedo"); - gltf_texture_index = _set_texture(state, albedo_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); - } - if (gltf_texture_index != -1) { - bct["index"] = gltf_texture_index; - Dictionary extensions = _serialize_texture_transform_uv1(material); - if (!extensions.is_empty()) { - bct["extensions"] = extensions; - state->use_khr_texture_transform = true; + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { + albedo_texture->set_name(material->get_name() + "_albedo"); + gltf_texture_index = _set_texture(state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + } + if (gltf_texture_index != -1) { + bct["index"] = gltf_texture_index; + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + bct["extensions"] = extensions; + state->use_khr_texture_transform = true; + } + mr["baseColorTexture"] = bct; } - mr["baseColorTexture"] = bct; } } - - mr["metallicFactor"] = material->get_metallic(); - mr["roughnessFactor"] = material->get_roughness(); - bool has_roughness = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); - bool has_ao = material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); - bool has_metalness = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); - if (has_ao || has_roughness || has_metalness) { - Dictionary mrt; - Ref<Texture2D> roughness_texture = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); - BaseMaterial3D::TextureChannel roughness_channel = material->get_roughness_texture_channel(); - Ref<Texture2D> metallic_texture = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); - BaseMaterial3D::TextureChannel metalness_channel = material->get_metallic_texture_channel(); - Ref<Texture2D> ao_texture = material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); - BaseMaterial3D::TextureChannel ao_channel = material->get_ao_texture_channel(); - Ref<ImageTexture> orm_texture; - orm_texture.instantiate(); - Ref<Image> orm_image; - orm_image.instantiate(); - int32_t height = 0; - int32_t width = 0; - Ref<Image> ao_image; - if (has_ao) { - height = ao_texture->get_height(); - width = ao_texture->get_width(); - ao_image = ao_texture->get_image(); - Ref<ImageTexture> img_tex = ao_image; - if (img_tex.is_valid()) { - ao_image = img_tex->get_image(); + if (base_material.is_valid()) { + mr["metallicFactor"] = base_material->get_metallic(); + mr["roughnessFactor"] = base_material->get_roughness(); + bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); + bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); + bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); + if (has_ao || has_roughness || has_metalness) { + Dictionary mrt; + Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); + BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); + Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); + BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); + Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); + BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); + Ref<ImageTexture> orm_texture; + orm_texture.instantiate(); + Ref<Image> orm_image; + orm_image.instantiate(); + int32_t height = 0; + int32_t width = 0; + Ref<Image> ao_image; + if (has_ao) { + height = ao_texture->get_height(); + width = ao_texture->get_width(); + ao_image = ao_texture->get_image(); + Ref<ImageTexture> img_tex = ao_image; + if (img_tex.is_valid()) { + ao_image = img_tex->get_image(); + } + if (ao_image->is_compressed()) { + ao_image->decompress(); + } } - if (ao_image->is_compressed()) { - ao_image->decompress(); + Ref<Image> roughness_image; + if (has_roughness) { + height = roughness_texture->get_height(); + width = roughness_texture->get_width(); + roughness_image = roughness_texture->get_image(); + Ref<ImageTexture> img_tex = roughness_image; + if (img_tex.is_valid()) { + roughness_image = img_tex->get_image(); + } + if (roughness_image->is_compressed()) { + roughness_image->decompress(); + } } - } - Ref<Image> roughness_image; - if (has_roughness) { - height = roughness_texture->get_height(); - width = roughness_texture->get_width(); - roughness_image = roughness_texture->get_image(); - Ref<ImageTexture> img_tex = roughness_image; - if (img_tex.is_valid()) { - roughness_image = img_tex->get_image(); + Ref<Image> metallness_image; + if (has_metalness) { + height = metallic_texture->get_height(); + width = metallic_texture->get_width(); + metallness_image = metallic_texture->get_image(); + Ref<ImageTexture> img_tex = metallness_image; + if (img_tex.is_valid()) { + metallness_image = img_tex->get_image(); + } + if (metallness_image->is_compressed()) { + metallness_image->decompress(); + } } - if (roughness_image->is_compressed()) { - roughness_image->decompress(); + Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { + height = albedo_texture->get_height(); + width = albedo_texture->get_width(); } - } - Ref<Image> metallness_image; - if (has_metalness) { - height = metallic_texture->get_height(); - width = metallic_texture->get_width(); - metallness_image = metallic_texture->get_image(); - Ref<ImageTexture> img_tex = metallness_image; - if (img_tex.is_valid()) { - metallness_image = img_tex->get_image(); + orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); + if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { + ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); } - if (metallness_image->is_compressed()) { - metallness_image->decompress(); + if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { + roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); } - } - Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { - height = albedo_texture->get_height(); - width = albedo_texture->get_width(); - } - orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); - if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { - ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { - roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { - metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - for (int32_t h = 0; h < height; h++) { - for (int32_t w = 0; w < width; w++) { - Color c = Color(1.0f, 1.0f, 1.0f); - if (has_ao) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { - c.r = ao_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { - c.r = ao_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { - c.r = ao_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { - c.r = ao_image->get_pixel(w, h).a; + if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { + metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + for (int32_t h = 0; h < height; h++) { + for (int32_t w = 0; w < width; w++) { + Color c = Color(1.0f, 1.0f, 1.0f); + if (has_ao) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { + c.r = ao_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { + c.r = ao_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { + c.r = ao_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { + c.r = ao_image->get_pixel(w, h).a; + } } - } - if (has_roughness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).a; + if (has_roughness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).a; + } } - } - if (has_metalness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).a; + if (has_metalness) { + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).a; + } } + orm_image->set_pixel(w, h, c); } - orm_image->set_pixel(w, h, c); } - } - orm_image->generate_mipmaps(); - orm_texture->set_image(orm_image); - GLTFTextureIndex orm_texture_index = -1; - if (has_ao || has_roughness || has_metalness) { - orm_texture->set_name(material->get_name() + "_orm"); - orm_texture_index = _set_texture(state, orm_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); - } - if (has_ao) { - Dictionary occt; - occt["index"] = orm_texture_index; - d["occlusionTexture"] = occt; - } - if (has_roughness || has_metalness) { - mrt["index"] = orm_texture_index; - Dictionary extensions = _serialize_texture_transform_uv1(material); - if (!extensions.is_empty()) { - mrt["extensions"] = extensions; - state->use_khr_texture_transform = true; + orm_image->generate_mipmaps(); + orm_texture->set_image(orm_image); + GLTFTextureIndex orm_texture_index = -1; + if (has_ao || has_roughness || has_metalness) { + orm_texture->set_name(material->get_name() + "_orm"); + orm_texture_index = _set_texture(state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + } + if (has_ao) { + Dictionary occt; + occt["index"] = orm_texture_index; + d["occlusionTexture"] = occt; + } + if (has_roughness || has_metalness) { + mrt["index"] = orm_texture_index; + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + mrt["extensions"] = extensions; + state->use_khr_texture_transform = true; + } + mr["metallicRoughnessTexture"] = mrt; } - mr["metallicRoughnessTexture"] = mrt; } } d["pbrMetallicRoughness"] = mr; } - - if (material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { + if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { Dictionary nt; Ref<ImageTexture> tex; tex.instantiate(); { - Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); + Ref<Texture2D> normal_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); if (normal_texture.is_valid()) { // Code for uncompressing RG normal maps Ref<Image> img = normal_texture->get_image(); @@ -3593,30 +3598,30 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { GLTFTextureIndex gltf_texture_index = -1; if (tex.is_valid() && tex->get_image().is_valid()) { tex->set_name(material->get_name() + "_normal"); - gltf_texture_index = _set_texture(state, tex, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + gltf_texture_index = _set_texture(state, tex, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } - nt["scale"] = material->get_normal_scale(); + nt["scale"] = base_material->get_normal_scale(); if (gltf_texture_index != -1) { nt["index"] = gltf_texture_index; d["normalTexture"] = nt; } } - if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { - const Color c = material->get_emission().linear_to_srgb(); + if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { + const Color c = base_material->get_emission().linear_to_srgb(); Array arr; arr.push_back(c.r); arr.push_back(c.g); arr.push_back(c.b); d["emissiveFactor"] = arr; } - if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { + if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { Dictionary et; - Ref<Texture2D> emission_texture = material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); + Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); GLTFTextureIndex gltf_texture_index = -1; if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) { emission_texture->set_name(material->get_name() + "_emission"); - gltf_texture_index = _set_texture(state, emission_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + gltf_texture_index = _set_texture(state, emission_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } if (gltf_texture_index != -1) { @@ -3624,14 +3629,14 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { d["emissiveTexture"] = et; } } - const bool ds = material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED; + const bool ds = base_material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED; if (ds) { d["doubleSided"] = ds; } - if (material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) { + if (base_material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) { d["alphaMode"] = "MASK"; - d["alphaCutoff"] = material->get_alpha_scissor_threshold(); - } else if (material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) { + d["alphaCutoff"] = base_material->get_alpha_scissor_threshold(); + } else if (base_material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) { d["alphaMode"] = "BLEND"; } materials.push_back(d); @@ -3837,29 +3842,37 @@ void GLTFDocument::_set_texture_transform_uv1(const Dictionary &d, Ref<BaseMater if (d.has("extensions")) { const Dictionary &extensions = d["extensions"]; if (extensions.has("KHR_texture_transform")) { - const Dictionary &texture_transform = extensions["KHR_texture_transform"]; - const Array &offset_arr = texture_transform["offset"]; - if (offset_arr.size() == 2) { - const Vector3 offset_vector3 = Vector3(offset_arr[0], offset_arr[1], 0.0f); - material->set_uv1_offset(offset_vector3); - } + if (material.is_valid()) { + const Dictionary &texture_transform = extensions["KHR_texture_transform"]; + const Array &offset_arr = texture_transform["offset"]; + if (offset_arr.size() == 2) { + const Vector3 offset_vector3 = Vector3(offset_arr[0], offset_arr[1], 0.0f); + material->set_uv1_offset(offset_vector3); + } - const Array &scale_arr = texture_transform["scale"]; - if (scale_arr.size() == 2) { - const Vector3 scale_vector3 = Vector3(scale_arr[0], scale_arr[1], 1.0f); - material->set_uv1_scale(scale_vector3); + const Array &scale_arr = texture_transform["scale"]; + if (scale_arr.size() == 2) { + const Vector3 scale_vector3 = Vector3(scale_arr[0], scale_arr[1], 1.0f); + material->set_uv1_scale(scale_vector3); + } } } } } void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Ref<BaseMaterial3D> p_material) { + if (r_spec_gloss.is_null()) { + return; + } if (r_spec_gloss->spec_gloss_img.is_null()) { return; } if (r_spec_gloss->diffuse_img.is_null()) { return; } + if (p_material.is_null()) { + return; + } bool has_roughness = false; bool has_metal = false; p_material->set_roughness(1.0f); @@ -5270,6 +5283,10 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, co AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_current); _convert_animation_player_to_gltf(animation_player, state, p_gltf_parent, p_gltf_root, gltf_node, p_current); } + for (Ref<GLTFDocumentExtension> ext : document_extensions) { + ERR_CONTINUE(ext.is_null()); + ext->convert_scene_node(state, gltf_node, p_current); + } GLTFNodeIndex current_node_i = state->nodes.size(); GLTFNodeIndex gltf_root = p_gltf_root; if (gltf_root == -1) { @@ -5593,21 +5610,32 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent // and attach it to the bone_attachment scene_parent = bone_attachment; } - if (gltf_node->mesh >= 0) { - current_node = _generate_mesh_instance(state, node_index); - } else if (gltf_node->camera >= 0) { - current_node = _generate_camera(state, node_index); - } else if (gltf_node->light >= 0) { - current_node = _generate_light(state, node_index); + // Check if any GLTFDocumentExtension classes want to generate a node for us. + for (Ref<GLTFDocumentExtension> ext : document_extensions) { + ERR_CONTINUE(ext.is_null()); + current_node = ext->generate_scene_node(state, gltf_node, scene_parent); + if (current_node) { + break; + } } - - // We still have not managed to make a node. + // If none of our GLTFDocumentExtension classes generated us a node, we generate one. if (!current_node) { - current_node = _generate_spatial(state, node_index); + if (gltf_node->mesh >= 0) { + current_node = _generate_mesh_instance(state, node_index); + } else if (gltf_node->camera >= 0) { + current_node = _generate_camera(state, node_index); + } else if (gltf_node->light >= 0) { + current_node = _generate_light(state, node_index); + } else { + current_node = _generate_spatial(state, node_index); + } } + // Add the node we generated and set the owner to the scene root. scene_parent->add_child(current_node, true); if (current_node != scene_root) { - current_node->set_owner(scene_root); + Array args; + args.append(scene_root); + current_node->propagate_call(StringName("set_owner"), args); } current_node->set_transform(gltf_node->xform); current_node->set_name(gltf_node->get_name()); @@ -5673,19 +5701,32 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen // and attach it to the bone_attachment scene_parent = bone_attachment; } - - // We still have not managed to make a node - if (gltf_node->mesh >= 0) { - current_node = _generate_mesh_instance(state, node_index); - } else if (gltf_node->camera >= 0) { - current_node = _generate_camera(state, node_index); - } else if (gltf_node->light >= 0) { - current_node = _generate_light(state, node_index); + // Check if any GLTFDocumentExtension classes want to generate a node for us. + for (Ref<GLTFDocumentExtension> ext : document_extensions) { + ERR_CONTINUE(ext.is_null()); + current_node = ext->generate_scene_node(state, gltf_node, scene_parent); + if (current_node) { + break; + } + } + // If none of our GLTFDocumentExtension classes generated us a node, we generate one. + if (!current_node) { + if (gltf_node->mesh >= 0) { + current_node = _generate_mesh_instance(state, node_index); + } else if (gltf_node->camera >= 0) { + current_node = _generate_camera(state, node_index); + } else if (gltf_node->light >= 0) { + current_node = _generate_light(state, node_index); + } else { + current_node = _generate_spatial(state, node_index); + } } - + // Add the node we generated and set the owner to the scene root. scene_parent->add_child(current_node, true); if (current_node != scene_root) { - current_node->set_owner(scene_root); + Array args; + args.append(scene_root); + current_node->propagate_call(StringName("set_owner"), args); } // Do not set transform here. Transform is already applied to our bone. current_node->set_name(gltf_node->get_name()); @@ -6586,11 +6627,13 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> state->major_version = version.get_slice(".", 0).to_int(); state->minor_version = version.get_slice(".", 1).to_int(); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + document_extensions.clear(); + for (Ref<GLTFDocumentExtension> ext : all_document_extensions) { ERR_CONTINUE(ext.is_null()); - err = ext->import_preflight(state); - ERR_FAIL_COND_V(err != OK, err); + err = ext->import_preflight(state, state->json["extensionsUsed"]); + if (err == OK) { + document_extensions.push_back(ext); + } } err = _parse_gltf_state(state, p_path, p_bake_fps); @@ -6626,21 +6669,17 @@ Dictionary _serialize_texture_transform_uv(Vector2 p_offset, Vector2 p_scale) { } Dictionary GLTFDocument::_serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material) { - if (p_material.is_valid()) { - Vector3 offset = p_material->get_uv1_offset(); - Vector3 scale = p_material->get_uv1_scale(); - return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); - } - return Dictionary(); + ERR_FAIL_NULL_V(p_material, Dictionary()); + Vector3 offset = p_material->get_uv1_offset(); + Vector3 scale = p_material->get_uv1_scale(); + return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); } Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) { - if (p_material.is_valid()) { - Vector3 offset = p_material->get_uv2_offset(); - Vector3 scale = p_material->get_uv2_scale(); - return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); - } - return Dictionary(); + ERR_FAIL_NULL_V(p_material, Dictionary()); + Vector3 offset = p_material->get_uv2_offset(); + Vector3 scale = p_material->get_uv2_scale(); + return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); } Error GLTFDocument::_serialize_version(Ref<GLTFState> state) { @@ -6728,14 +6767,10 @@ void GLTFDocument::_bind_methods() { ClassDB::bind_method(D_METHOD("write_to_filesystem", "state", "path"), &GLTFDocument::write_to_filesystem); - ClassDB::bind_method(D_METHOD("set_extensions", "extensions"), - &GLTFDocument::set_extensions); - ClassDB::bind_method(D_METHOD("get_extensions"), - &GLTFDocument::get_extensions); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "extensions", PROPERTY_HINT_ARRAY_TYPE, - vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "GLTFDocumentExtension"), - PROPERTY_USAGE_DEFAULT), - "set_extensions", "get_extensions"); + ClassDB::bind_static_method("GLTFDocument", D_METHOD("register_gltf_document_extension", "extension", "first_priority"), + &GLTFDocument::register_gltf_document_extension, DEFVAL(false)); + ClassDB::bind_static_method("GLTFDocument", D_METHOD("unregister_gltf_document_extension", "extension"), + &GLTFDocument::unregister_gltf_document_extension); } void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> state) { @@ -6752,22 +6787,24 @@ void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> state) { } } -void GLTFDocument::set_extensions(TypedArray<GLTFDocumentExtension> p_extensions) { - document_extensions = p_extensions; +Vector<Ref<GLTFDocumentExtension>> GLTFDocument::all_document_extensions; + +void GLTFDocument::register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority) { + if (all_document_extensions.find(p_extension) == -1) { + if (p_first_priority) { + all_document_extensions.insert(0, p_extension); + } else { + all_document_extensions.push_back(p_extension); + } + } } -TypedArray<GLTFDocumentExtension> GLTFDocument::get_extensions() const { - return document_extensions; +void GLTFDocument::unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension) { + all_document_extensions.erase(p_extension); } -GLTFDocument::GLTFDocument() { - bool is_editor = ::Engine::get_singleton()->is_editor_hint(); - if (is_editor) { - return; - } - Ref<GLTFDocumentExtensionConvertImporterMesh> extension_editor; - extension_editor.instantiate(); - document_extensions.push_back(extension_editor); +void GLTFDocument::unregister_all_gltf_document_extensions() { + all_document_extensions.clear(); } PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> state, Error *r_err) { @@ -6852,8 +6889,7 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) { } for (KeyValue<GLTFNodeIndex, Node *> E : state->scene_nodes) { ERR_CONTINUE(!E.value); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); ERR_CONTINUE(!state->json.has("nodes")); Array nodes = state->json["nodes"]; @@ -6865,8 +6901,7 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) { ERR_CONTINUE(err != OK); } } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); err = ext->import_post(state, root); ERR_CONTINUE(err != OK); @@ -6880,11 +6915,13 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32 state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + document_extensions.clear(); + for (Ref<GLTFDocumentExtension> ext : all_document_extensions) { ERR_CONTINUE(ext.is_null()); Error err = ext->export_preflight(p_node); - ERR_FAIL_COND_V(err != OK, FAILED); + if (err == OK) { + document_extensions.push_back(ext); + } } _convert_scene_node(state, p_node, -1, -1); if (!state->buffers.size()) { @@ -6906,8 +6943,7 @@ Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_pa state->base_path = p_base_path.get_base_dir(); err = _parse(state, state->base_path, file_access, p_bake_fps); ERR_FAIL_COND_V(err != OK, err); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); err = ext->import_post_parse(state); ERR_FAIL_COND_V(err != OK, err); @@ -7030,8 +7066,7 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint r_state->base_path = base_path; err = _parse(r_state, base_path, f, p_bake_fps); ERR_FAIL_COND_V(err != OK, err); - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); err = ext->import_post_parse(r_state); ERR_FAIL_COND_V(err != OK, err); @@ -7053,8 +7088,7 @@ Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) { supported_extensions.insert("KHR_lights_punctual"); supported_extensions.insert("KHR_materials_pbrSpecularGlossiness"); supported_extensions.insert("KHR_texture_transform"); - for (int ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + for (Ref<GLTFDocumentExtension> ext : document_extensions) { ERR_CONTINUE(ext.is_null()); Vector<String> ext_supported_extensions = ext->get_supported_extensions(); for (int i = 0; i < ext_supported_extensions.size(); ++i) { diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 62b6e29fe0..5a0e4ff498 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -31,7 +31,7 @@ #ifndef GLTF_DOCUMENT_H #define GLTF_DOCUMENT_H -#include "gltf_defines.h" +#include "extensions/gltf_document_extension.h" #include "structures/gltf_animation.h" #include "scene/3d/bone_attachment_3d.h" @@ -44,13 +44,13 @@ class GLTFDocument : public Resource { GDCLASS(GLTFDocument, Resource); - TypedArray<GLTFDocumentExtension> document_extensions; + static Vector<Ref<GLTFDocumentExtension>> all_document_extensions; + Vector<Ref<GLTFDocumentExtension>> document_extensions; private: const float BAKE_FPS = 30.0f; public: - GLTFDocument(); const int32_t JOINT_GROUP_SIZE = 4; enum { @@ -76,8 +76,9 @@ protected: static void _bind_methods(); public: - void set_extensions(TypedArray<GLTFDocumentExtension> p_extensions); - TypedArray<GLTFDocumentExtension> get_extensions() const; + static void register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority = false); + static void unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension); + static void unregister_all_gltf_document_extensions(); private: void _build_parent_hierachy(Ref<GLTFState> state); diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index ac5665e396..6654c9e5d2 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -209,11 +209,11 @@ void GLTFState::set_meshes(TypedArray<GLTFMesh> p_meshes) { GLTFTemplateConvert::set_from_array(meshes, p_meshes); } -TypedArray<BaseMaterial3D> GLTFState::get_materials() { +TypedArray<Material> GLTFState::get_materials() { return GLTFTemplateConvert::to_array(materials); } -void GLTFState::set_materials(TypedArray<BaseMaterial3D> p_materials) { +void GLTFState::set_materials(TypedArray<Material> p_materials) { GLTFTemplateConvert::set_from_array(materials, p_materials); } diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index e24017b0fd..1c20520b22 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -72,8 +72,8 @@ class GLTFState : public Resource { Vector<Ref<GLTFMesh>> meshes; // meshes are loaded directly, no reason not to. Vector<AnimationPlayer *> animation_players; - HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex> material_cache; - Vector<Ref<BaseMaterial3D>> materials; + HashMap<Ref<Material>, GLTFMaterialIndex> material_cache; + Vector<Ref<Material>> materials; String scene_name; Vector<int> root_nodes; @@ -138,8 +138,8 @@ public: TypedArray<GLTFMesh> get_meshes(); void set_meshes(TypedArray<GLTFMesh> p_meshes); - TypedArray<BaseMaterial3D> get_materials(); - void set_materials(TypedArray<BaseMaterial3D> p_materials); + TypedArray<Material> get_materials(); + void set_materials(TypedArray<Material> p_materials); String get_scene_name(); void set_scene_name(String p_scene_name); diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index b9027f6e3d..a7abf256ce 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -32,11 +32,10 @@ #ifndef _3D_DISABLED +#include "extensions/gltf_document_extension_convert_importer_mesh.h" #include "extensions/gltf_light.h" #include "extensions/gltf_spec_gloss.h" #include "gltf_document.h" -#include "gltf_document_extension.h" -#include "gltf_document_extension_convert_importer_mesh.h" #include "gltf_state.h" #include "structures/gltf_accessor.h" #include "structures/gltf_animation.h" @@ -109,6 +108,11 @@ static void _editor_init() { } #endif // TOOLS_ENABLED +#define GLTF_REGISTER_DOCUMENT_EXTENSION(m_doc_ext_class) \ + Ref<m_doc_ext_class> extension_##m_doc_ext_class; \ + extension_##m_doc_ext_class.instantiate(); \ + GLTFDocument::register_gltf_document_extension(extension_##m_doc_ext_class); + void initialize_gltf_module(ModuleInitializationLevel p_level) { if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) { // glTF API available at runtime. @@ -128,6 +132,11 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(GLTFState); GDREGISTER_CLASS(GLTFTexture); GDREGISTER_CLASS(GLTFTextureSampler); + // Register GLTFDocumentExtension classes with GLTFDocument. + bool is_editor = ::Engine::get_singleton()->is_editor_hint(); + if (!is_editor) { + GLTF_REGISTER_DOCUMENT_EXTENSION(GLTFDocumentExtensionConvertImporterMesh); + } } #ifdef TOOLS_ENABLED @@ -161,6 +170,7 @@ void uninitialize_gltf_module(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } + GLTFDocument::unregister_all_gltf_document_extensions(); } #endif // _3D_DISABLED diff --git a/modules/gltf/structures/gltf_buffer_view.cpp b/modules/gltf/structures/gltf_buffer_view.cpp index ba19ed8628..a15141225b 100644 --- a/modules/gltf/structures/gltf_buffer_view.cpp +++ b/modules/gltf/structures/gltf_buffer_view.cpp @@ -30,8 +30,6 @@ #include "gltf_buffer_view.h" -#include "../gltf_document_extension.h" - void GLTFBufferView::_bind_methods() { ClassDB::bind_method(D_METHOD("get_buffer"), &GLTFBufferView::get_buffer); ClassDB::bind_method(D_METHOD("set_buffer", "buffer"), &GLTFBufferView::set_buffer); diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 0f3662c3cf..bd5c938364 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -25,12 +25,14 @@ <method name="clear_baked_meshes"> <return type="void" /> <description> + Clears all baked meshes. See [method make_baked_meshes]. </description> </method> <method name="get_bake_mesh_instance"> <return type="RID" /> <param index="0" name="idx" type="int" /> <description> + Returns [RID] of a baked mesh with the given [param idx]. </description> </method> <method name="get_bake_meshes"> @@ -133,6 +135,7 @@ <param index="0" name="gen_lightmap_uv" type="bool" default="false" /> <param index="1" name="lightmap_uv_texel_size" type="float" default="0.1" /> <description> + Bakes lightmap data for all meshes in the assigned [MeshLibrary]. </description> </method> <method name="map_to_local" qualifiers="const"> @@ -146,6 +149,7 @@ <return type="void" /> <param index="0" name="resource" type="Resource" /> <description> + Notifies the [GridMap] about changed resource and recreates octant data. </description> </method> <method name="set_cell_item"> diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp index e84d95773d..e658668355 100644 --- a/modules/mbedtls/packet_peer_mbed_dtls.cpp +++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp @@ -118,7 +118,6 @@ Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, bool p_vali ERR_FAIL_COND_V(!p_base.is_valid() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER); base = p_base; - int ret = 0; int authmode = p_validate_certs ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE; Error err = tls_ctx->init_client(MBEDTLS_SSL_TRANSPORT_DATAGRAM, authmode, p_ca_certs); @@ -130,7 +129,7 @@ Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, bool p_vali status = STATUS_HANDSHAKING; - if ((ret = _do_handshake()) != OK) { + if (_do_handshake() != OK) { status = STATUS_ERROR_HOSTNAME_MISMATCH; return FAILED; } @@ -158,7 +157,7 @@ Error PacketPeerMbedDTLS::accept_peer(Ref<PacketPeerUDP> p_base, Ref<CryptoKey> status = STATUS_HANDSHAKING; - if ((ret = _do_handshake()) != OK) { + if (_do_handshake() != OK) { status = STATUS_ERROR; return FAILED; } @@ -175,7 +174,7 @@ Error PacketPeerMbedDTLS::put_packet(const uint8_t *p_buffer, int p_bytes) { int ret = mbedtls_ssl_write(tls_ctx->get_context(), p_buffer, p_bytes); if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { - ret = 0; // non blocking io + // Non blocking io. } else if (ret <= 0) { TLSContextMbedTLS::print_mbedtls_error(ret); _cleanup(); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs index ac8d6473a6..9a46b7d164 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; #pragma warning disable CS0169 @@ -83,6 +84,10 @@ namespace Godot.SourceGenerators.Sample [Export] private StringName[] field_StringNameArray = { "foo", "bar" }; [Export] private NodePath[] field_NodePathArray = { "foo", "bar" }; [Export] private RID[] field_RIDArray = { default, default, default }; + // Note we use Array and not System.Array. This tests the generated namespace qualification. + [Export] private Int32[] field_empty_Int32Array = Array.Empty<Int32>(); + // Note we use List and not System.Collections.Generic. + [Export] private int[] field_array_from_list = new List<int>(Array.Empty<int>()).ToArray(); // Variant [Export] private Variant field_Variant = "foo"; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MoreExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MoreExportedFields.cs new file mode 100644 index 0000000000..a6c8e52667 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MoreExportedFields.cs @@ -0,0 +1,19 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +#pragma warning disable CS0169 +#pragma warning disable CS0414 + +namespace Godot.SourceGenerators.Sample +{ + [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] + [SuppressMessage("ReSharper", "RedundantNameQualifier")] + [SuppressMessage("ReSharper", "ArrangeObjectCreationWhenTypeEvident")] + [SuppressMessage("ReSharper", "InconsistentNaming")] + // We split the definition of ExportedFields to verify properties work across multiple files. + public partial class ExportedFields : Godot.Object + { + // Note we use Array and not System.Array. This tests the generated namespace qualification. + [Export] private Int64[] field_empty_Int64Array = Array.Empty<Int64>(); + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs index 8de12de23b..9e3add4262 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -165,6 +166,50 @@ namespace Godot.SourceGenerators public static string FullQualifiedName(this INamespaceSymbol namespaceSymbol) => namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal); + public static string FullQualifiedName(this ISymbol symbol) + => symbol.ToDisplayString(FullyQualifiedFormatOmitGlobal); + + public static string FullQualifiedSyntax(this SyntaxNode node, SemanticModel sm) + { + StringBuilder sb = new(); + FullQualifiedSyntax_(node, sm, sb, true); + return sb.ToString(); + } + + private static void FullQualifiedSyntax_(SyntaxNode node, SemanticModel sm, StringBuilder sb, bool isFirstNode) + { + if (node is NameSyntax ns && isFirstNode) + { + SymbolInfo nameInfo = sm.GetSymbolInfo(ns); + sb.Append(nameInfo.Symbol?.FullQualifiedName() ?? ns.ToString()); + return; + } + + bool innerIsFirstNode = true; + foreach (var child in node.ChildNodesAndTokens()) + { + if (child.HasLeadingTrivia) + { + sb.Append(child.GetLeadingTrivia()); + } + + if (child.IsNode) + { + FullQualifiedSyntax_(child.AsNode()!, sm, sb, isFirstNode: innerIsFirstNode); + innerIsFirstNode = false; + } + else + { + sb.Append(child); + } + + if (child.HasTrailingTrivia) + { + sb.Append(child.GetTrailingTrivia()); + } + } + } + public static string SanitizeQualifiedNameForUniqueHint(this string qualifiedName) => qualifiedName // AddSource() doesn't support angle brackets diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs index 1a25d684a0..88c0e71155 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs @@ -71,29 +71,29 @@ namespace Godot.SourceGenerators Expression = 19, PlaceholderText = 20, ColorNoAlpha = 21, - ImageCompressLossy = 22, - ImageCompressLossless = 23, - ObjectId = 24, - TypeString = 25, - NodePathToEditedNode = 26, - MethodOfVariantType = 27, - MethodOfBaseType = 28, - MethodOfInstance = 29, - MethodOfScript = 30, - PropertyOfVariantType = 31, - PropertyOfBaseType = 32, - PropertyOfInstance = 33, - PropertyOfScript = 34, - ObjectTooBig = 35, - NodePathValidTypes = 36, - SaveFile = 37, - GlobalSaveFile = 38, - IntIsObjectid = 39, - IntIsPointer = 41, - ArrayType = 40, - LocaleId = 42, - LocalizableString = 43, - NodeType = 44, + ObjectId = 22, + TypeString = 23, + NodePathToEditedNode = 24, + MethodOfVariantType = 25, + MethodOfBaseType = 26, + MethodOfInstance = 27, + MethodOfScript = 28, + PropertyOfVariantType = 29, + PropertyOfBaseType = 30, + PropertyOfInstance = 31, + PropertyOfScript = 32, + ObjectTooBig = 33, + NodePathValidTypes = 34, + SaveFile = 35, + GlobalSaveFile = 36, + IntIsObjectid = 37, + IntIsPointer = 38, + ArrayType = 39, + LocaleId = 40, + LocalizableString = 41, + NodeType = 42, + HideQuaternionEdit = 43, + Password = 44, Max = 45 } @@ -128,12 +128,14 @@ namespace Godot.SourceGenerators DeferredSetResource = 33554432, EditorInstantiateObject = 67108864, EditorBasicSetting = 134217728, + ReadOnly = 268435456, Array = 536870912, Default = 6, DefaultIntl = 38, NoEditor = 2 } + [Flags] public enum MethodFlags { Normal = 1, diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs index db395e21cb..abd8079922 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs @@ -3,7 +3,7 @@ using Microsoft.CodeAnalysis; namespace Godot.SourceGenerators { - public struct GodotMethodData + public readonly struct GodotMethodData { public GodotMethodData(IMethodSymbol method, ImmutableArray<MarshalType> paramTypes, ImmutableArray<ITypeSymbol> paramTypeSymbols, MarshalType? retType, ITypeSymbol? retSymbol) @@ -22,7 +22,7 @@ namespace Godot.SourceGenerators public ITypeSymbol? RetSymbol { get; } } - public struct GodotSignalDelegateData + public readonly struct GodotSignalDelegateData { public GodotSignalDelegateData(string name, INamedTypeSymbol delegateSymbol, GodotMethodData invokeMethodData) { @@ -36,7 +36,7 @@ namespace Godot.SourceGenerators public GodotMethodData InvokeMethodData { get; } } - public struct GodotPropertyData + public readonly struct GodotPropertyData { public GodotPropertyData(IPropertySymbol propertySymbol, MarshalType type) { @@ -48,7 +48,7 @@ namespace Godot.SourceGenerators public MarshalType Type { get; } } - public struct GodotFieldData + public readonly struct GodotFieldData { public GodotFieldData(IFieldSymbol fieldSymbol, MarshalType type) { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs index 81c6f2b7d5..bb9be862c4 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; namespace Godot.SourceGenerators { - internal struct MethodInfo + internal readonly struct MethodInfo { public MethodInfo(string name, PropertyInfo returnVal, MethodFlags flags, List<PropertyInfo>? arguments, diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs index b345f5f84d..2b89633ef6 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs @@ -1,6 +1,6 @@ namespace Godot.SourceGenerators { - internal struct PropertyInfo + internal readonly struct PropertyInfo { public PropertyInfo(VariantType type, string name, PropertyHint hint, string? hintString, PropertyUsageFlags usage, bool exported) diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs index 98b9745c16..9a18ba3ab2 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs @@ -170,7 +170,13 @@ namespace Godot.SourceGenerators .Select(s => s?.Initializer ?? null) .FirstOrDefault(); - string? value = initializer?.Value.ToString(); + // Fully qualify the value to avoid issues with namespaces. + string? value = null; + if (initializer != null) + { + var sm = context.Compilation.GetSemanticModel(initializer.SyntaxTree); + value = initializer.Value.FullQualifiedSyntax(sm); + } exportedMembers.Add(new ExportedPropertyMetadata( property.Name, marshalType.Value, propertyType, value)); @@ -207,7 +213,13 @@ namespace Godot.SourceGenerators .Select(s => s.Initializer) .FirstOrDefault(i => i != null); - string? value = initializer?.Value.ToString(); + // This needs to be fully qualified to avoid issues with namespaces. + string? value = null; + if (initializer != null) + { + var sm = context.Compilation.GetSemanticModel(initializer.SyntaxTree); + value = initializer.Value.FullQualifiedSyntax(sm); + } exportedMembers.Add(new ExportedPropertyMetadata( field.Name, marshalType.Value, fieldType, value)); diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/SemaphoreExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/SemaphoreExtensions.cs index 9d593fbf8a..ab21527344 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/SemaphoreExtensions.cs +++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/SemaphoreExtensions.cs @@ -13,7 +13,7 @@ namespace GodotTools.IdeMessaging.Utils return waitAsyncTask.ContinueWith<IDisposable>(t => wrapper, cancellationToken).ConfigureAwait(false); } - private struct SemaphoreSlimWaitReleaseWrapper : IDisposable + private readonly struct SemaphoreSlimWaitReleaseWrapper : IDisposable { private readonly SemaphoreSlim semaphoreSlim; diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs index 2184cae6d6..94efcba3f1 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs @@ -22,7 +22,7 @@ namespace GodotTools.Export public bool FullAot; private bool _useInterpreter; - public bool UseInterpreter { get => _useInterpreter && !LLVMOnly; set => _useInterpreter = value; } + public bool UseInterpreter { readonly get => _useInterpreter && !LLVMOnly; set => _useInterpreter = value; } public string[] ExtraAotOptions; public string[] ExtraOptimizerOptions; diff --git a/modules/mono/editor/GodotTools/GodotTools/PlaySettings.cs b/modules/mono/editor/GodotTools/GodotTools/PlaySettings.cs index 820d0c0b83..9a8fdcc7c5 100644 --- a/modules/mono/editor/GodotTools/GodotTools/PlaySettings.cs +++ b/modules/mono/editor/GodotTools/GodotTools/PlaySettings.cs @@ -1,6 +1,6 @@ namespace GodotTools { - public struct PlaySettings + public readonly struct PlaySettings { public bool HasDebugger { get; } public string DebuggerHost { get; } diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs index 686023a077..ae51c07386 100644 --- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs +++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs @@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis; namespace Godot.SourceGenerators.Internal; -internal struct CallbacksData +internal readonly struct CallbacksData { public CallbacksData(INamedTypeSymbol nativeTypeSymbol, INamedTypeSymbol funcStructSymbol) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs index d8a6644a66..a2916d4ae8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs @@ -20,7 +20,7 @@ namespace Godot /// <value>Directly uses a private field.</value> public Vector3 Position { - get { return _position; } + readonly get { return _position; } set { _position = value; } } @@ -31,7 +31,7 @@ namespace Godot /// <value>Directly uses a private field.</value> public Vector3 Size { - get { return _size; } + readonly get { return _size; } set { _size = value; } } @@ -45,7 +45,7 @@ namespace Godot /// </value> public Vector3 End { - get { return _position + _size; } + readonly get { return _position + _size; } set { _size = value - _position; } } @@ -54,7 +54,7 @@ namespace Godot /// the most-negative corner is the origin and the size is positive. /// </summary> /// <returns>The modified <see cref="AABB"/>.</returns> - public AABB Abs() + public readonly AABB Abs() { Vector3 end = End; Vector3 topLeft = new Vector3(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y), Mathf.Min(_position.z, end.z)); @@ -66,7 +66,7 @@ namespace Godot /// to <see cref="Position"/> + (<see cref="Size"/> / 2). /// </summary> /// <returns>The center.</returns> - public Vector3 GetCenter() + public readonly Vector3 GetCenter() { return _position + (_size * 0.5f); } @@ -78,7 +78,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not this <see cref="AABB"/> encloses <paramref name="with"/>. /// </returns> - public bool Encloses(AABB with) + public readonly bool Encloses(AABB with) { Vector3 srcMin = _position; Vector3 srcMax = _position + _size; @@ -98,7 +98,7 @@ namespace Godot /// </summary> /// <param name="point">The point to include.</param> /// <returns>The expanded <see cref="AABB"/>.</returns> - public AABB Expand(Vector3 point) + public readonly AABB Expand(Vector3 point) { Vector3 begin = _position; Vector3 end = _position + _size; @@ -140,7 +140,7 @@ namespace Godot /// <paramref name="idx"/> is less than 0 or greater than 7. /// </exception> /// <returns>An endpoint of the <see cref="AABB"/>.</returns> - public Vector3 GetEndpoint(int idx) + public readonly Vector3 GetEndpoint(int idx) { switch (idx) { @@ -172,7 +172,7 @@ namespace Godot /// Returns the normalized longest axis of the <see cref="AABB"/>. /// </summary> /// <returns>A vector representing the normalized longest axis of the <see cref="AABB"/>.</returns> - public Vector3 GetLongestAxis() + public readonly Vector3 GetLongestAxis() { var axis = new Vector3(1f, 0f, 0f); real_t maxSize = _size.x; @@ -195,7 +195,7 @@ namespace Godot /// Returns the <see cref="Vector3.Axis"/> index of the longest axis of the <see cref="AABB"/>. /// </summary> /// <returns>A <see cref="Vector3.Axis"/> index for which axis is longest.</returns> - public Vector3.Axis GetLongestAxisIndex() + public readonly Vector3.Axis GetLongestAxisIndex() { var axis = Vector3.Axis.X; real_t maxSize = _size.x; @@ -218,7 +218,7 @@ namespace Godot /// Returns the scalar length of the longest axis of the <see cref="AABB"/>. /// </summary> /// <returns>The scalar length of the longest axis of the <see cref="AABB"/>.</returns> - public real_t GetLongestAxisSize() + public readonly real_t GetLongestAxisSize() { real_t maxSize = _size.x; @@ -235,7 +235,7 @@ namespace Godot /// Returns the normalized shortest axis of the <see cref="AABB"/>. /// </summary> /// <returns>A vector representing the normalized shortest axis of the <see cref="AABB"/>.</returns> - public Vector3 GetShortestAxis() + public readonly Vector3 GetShortestAxis() { var axis = new Vector3(1f, 0f, 0f); real_t maxSize = _size.x; @@ -258,7 +258,7 @@ namespace Godot /// Returns the <see cref="Vector3.Axis"/> index of the shortest axis of the <see cref="AABB"/>. /// </summary> /// <returns>A <see cref="Vector3.Axis"/> index for which axis is shortest.</returns> - public Vector3.Axis GetShortestAxisIndex() + public readonly Vector3.Axis GetShortestAxisIndex() { var axis = Vector3.Axis.X; real_t maxSize = _size.x; @@ -281,7 +281,7 @@ namespace Godot /// Returns the scalar length of the shortest axis of the <see cref="AABB"/>. /// </summary> /// <returns>The scalar length of the shortest axis of the <see cref="AABB"/>.</returns> - public real_t GetShortestAxisSize() + public readonly real_t GetShortestAxisSize() { real_t maxSize = _size.x; @@ -300,7 +300,7 @@ namespace Godot /// </summary> /// <param name="dir">The direction to find support for.</param> /// <returns>A vector representing the support.</returns> - public Vector3 GetSupport(Vector3 dir) + public readonly Vector3 GetSupport(Vector3 dir) { Vector3 halfExtents = _size * 0.5f; Vector3 ofs = _position + halfExtents; @@ -315,7 +315,7 @@ namespace Godot /// Returns the volume of the <see cref="AABB"/>. /// </summary> /// <returns>The volume.</returns> - public real_t GetVolume() + public readonly real_t GetVolume() { return _size.x * _size.y * _size.z; } @@ -325,7 +325,7 @@ namespace Godot /// </summary> /// <param name="by">The amount to grow by.</param> /// <returns>The grown <see cref="AABB"/>.</returns> - public AABB Grow(real_t by) + public readonly AABB Grow(real_t by) { AABB res = this; @@ -347,7 +347,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> contains <paramref name="point"/>. /// </returns> - public bool HasPoint(Vector3 point) + public readonly bool HasPoint(Vector3 point) { if (point.x < _position.x) return false; @@ -374,7 +374,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> has surface. /// </returns> - public bool HasSurface() + public readonly bool HasSurface() { return _size.x > 0.0f || _size.y > 0.0f || _size.z > 0.0f; } @@ -388,7 +388,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> has volume. /// </returns> - public bool HasVolume() + public readonly bool HasVolume() { return _size.x > 0.0f && _size.y > 0.0f && _size.z > 0.0f; } @@ -398,7 +398,7 @@ namespace Godot /// </summary> /// <param name="with">The other <see cref="AABB"/>.</param> /// <returns>The clipped <see cref="AABB"/>.</returns> - public AABB Intersection(AABB with) + public readonly AABB Intersection(AABB with) { Vector3 srcMin = _position; Vector3 srcMax = _position + _size; @@ -447,7 +447,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not they are intersecting. /// </returns> - public bool Intersects(AABB with, bool includeBorders = false) + public readonly bool Intersects(AABB with, bool includeBorders = false) { if (includeBorders) { @@ -490,7 +490,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> intersects the <see cref="Plane"/>. /// </returns> - public bool IntersectsPlane(Plane plane) + public readonly bool IntersectsPlane(Plane plane) { Vector3[] points = { @@ -531,7 +531,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> intersects the line segment. /// </returns> - public bool IntersectsSegment(Vector3 from, Vector3 to) + public readonly bool IntersectsSegment(Vector3 from, Vector3 to) { real_t min = 0f; real_t max = 1f; @@ -590,7 +590,7 @@ namespace Godot /// </summary> /// <param name="with">The other <see cref="AABB"/>.</param> /// <returns>The merged <see cref="AABB"/>.</returns> - public AABB Merge(AABB with) + public readonly AABB Merge(AABB with) { Vector3 beg1 = _position; Vector3 beg2 = with._position; @@ -702,7 +702,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the AABB and the object are equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is AABB other && Equals(other); } @@ -714,7 +714,7 @@ namespace Godot /// </summary> /// <param name="other">The other AABB.</param> /// <returns>Whether or not the AABBs are exactly equal.</returns> - public bool Equals(AABB other) + public readonly bool Equals(AABB other) { return _position == other._position && _size == other._size; } @@ -725,7 +725,7 @@ namespace Godot /// </summary> /// <param name="other">The other AABB to compare.</param> /// <returns>Whether or not the AABBs structures are approximately equal.</returns> - public bool IsEqualApprox(AABB other) + public readonly bool IsEqualApprox(AABB other) { return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other._size); } @@ -734,7 +734,7 @@ namespace Godot /// Serves as the hash function for <see cref="AABB"/>. /// </summary> /// <returns>A hash code for this AABB.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return _position.GetHashCode() ^ _size.GetHashCode(); } @@ -743,7 +743,7 @@ namespace Godot /// Converts this <see cref="AABB"/> to a string. /// </summary> /// <returns>A string representation of this AABB.</returns> - public override string ToString() + public override readonly string ToString() { return $"{_position}, {_size}"; } @@ -752,7 +752,7 @@ namespace Godot /// Converts this <see cref="AABB"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this AABB.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"{_position.ToString(format)}, {_size.ToString(format)}"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index bb1d6e1661..5d390a298d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -29,7 +29,7 @@ namespace Godot /// <value>Equivalent to <see cref="Column0"/> and array index <c>[0]</c>.</value> public Vector3 x { - get => Column0; + readonly get => Column0; set => Column0 = value; } @@ -39,7 +39,7 @@ namespace Godot /// <value>Equivalent to <see cref="Column1"/> and array index <c>[1]</c>.</value> public Vector3 y { - get => Column1; + readonly get => Column1; set => Column1 = value; } @@ -49,7 +49,7 @@ namespace Godot /// <value>Equivalent to <see cref="Column2"/> and array index <c>[2]</c>.</value> public Vector3 z { - get => Column2; + readonly get => Column2; set => Column2 = value; } @@ -80,7 +80,7 @@ namespace Godot /// <value>Equivalent to <see cref="x"/> and array index <c>[0]</c>.</value> public Vector3 Column0 { - get => new Vector3(Row0.x, Row1.x, Row2.x); + readonly get => new Vector3(Row0.x, Row1.x, Row2.x); set { Row0.x = value.x; @@ -95,7 +95,7 @@ namespace Godot /// <value>Equivalent to <see cref="y"/> and array index <c>[1]</c>.</value> public Vector3 Column1 { - get => new Vector3(Row0.y, Row1.y, Row2.y); + readonly get => new Vector3(Row0.y, Row1.y, Row2.y); set { Row0.y = value.x; @@ -110,7 +110,7 @@ namespace Godot /// <value>Equivalent to <see cref="z"/> and array index <c>[2]</c>.</value> public Vector3 Column2 { - get => new Vector3(Row0.z, Row1.z, Row2.z); + readonly get => new Vector3(Row0.z, Row1.z, Row2.z); set { Row0.z = value.x; @@ -125,7 +125,7 @@ namespace Godot /// <value>Equivalent to the lengths of each column vector, but negative if the determinant is negative.</value> public Vector3 Scale { - get + readonly get { real_t detSign = Mathf.Sign(Determinant()); return detSign * new Vector3 @@ -154,7 +154,7 @@ namespace Godot /// <value>The basis column.</value> public Vector3 this[int column] { - get + readonly get { switch (column) { @@ -195,7 +195,7 @@ namespace Godot /// <value>The matrix element.</value> public real_t this[int column, int row] { - get + readonly get { return this[column][row]; } @@ -234,7 +234,7 @@ namespace Godot /// and is usually considered invalid. /// </summary> /// <returns>The determinant of the basis matrix.</returns> - public real_t Determinant() + public readonly real_t Determinant() { real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1]; real_t cofac10 = Row1[2] * Row2[0] - Row1[0] * Row2[2]; @@ -255,7 +255,7 @@ namespace Godot /// </summary> /// <param name="order">The Euler order to use. By default, use YXZ order (most common).</param> /// <returns>A <see cref="Vector3"/> representing the basis rotation in Euler angles.</returns> - public Vector3 GetEuler(EulerOrder order = EulerOrder.Yxz) + public readonly Vector3 GetEuler(EulerOrder order = EulerOrder.Yxz) { switch (order) { @@ -499,7 +499,7 @@ namespace Godot /// mind that quaternions should generally be preferred to Euler angles. /// </summary> /// <returns>A <see cref="Quaternion"/> representing the basis's rotation.</returns> - internal Quaternion GetQuaternion() + internal readonly Quaternion GetQuaternion() { real_t trace = Row0[0] + Row1[1] + Row2[2]; @@ -558,7 +558,7 @@ namespace Godot /// be preferred to Euler angles. /// </summary> /// <returns>The basis rotation.</returns> - public Quaternion GetRotationQuaternion() + public readonly Quaternion GetRotationQuaternion() { Basis orthonormalizedBasis = Orthonormalized(); real_t det = orthonormalizedBasis.Determinant(); @@ -581,7 +581,7 @@ namespace Godot /// <paramref name="index"/> is not 0, 1 or 2. /// </exception> /// <returns>One of <c>Row0</c>, <c>Row1</c>, or <c>Row2</c>.</returns> - public Vector3 GetRow(int index) + public readonly Vector3 GetRow(int index) { switch (index) { @@ -633,7 +633,7 @@ namespace Godot /// For further details, refer to the Godot source code. /// </summary> /// <returns>The orthogonal index.</returns> - public int GetOrthogonalIndex() + public readonly int GetOrthogonalIndex() { var orth = this; @@ -679,7 +679,7 @@ namespace Godot /// Returns the inverse of the matrix. /// </summary> /// <returns>The inverse matrix.</returns> - public Basis Inverse() + public readonly Basis Inverse() { real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1]; real_t cofac10 = Row1[2] * Row2[0] - Row1[0] * Row2[2]; @@ -709,7 +709,7 @@ namespace Godot ); } - internal Basis Lerp(Basis to, real_t weight) + internal readonly Basis Lerp(Basis to, real_t weight) { Basis b = this; b.Row0 = Row0.Lerp(to.Row0, weight); @@ -724,7 +724,7 @@ namespace Godot /// This performs a Gram-Schmidt orthonormalization on the basis of the matrix. /// </summary> /// <returns>An orthonormalized basis matrix.</returns> - public Basis Orthonormalized() + public readonly Basis Orthonormalized() { Vector3 column0 = this[0]; Vector3 column1 = this[1]; @@ -746,7 +746,7 @@ namespace Godot /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated basis matrix.</returns> - public Basis Rotated(Vector3 axis, real_t angle) + public readonly Basis Rotated(Vector3 axis, real_t angle) { return new Basis(axis, angle) * this; } @@ -756,7 +756,7 @@ namespace Godot /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled basis matrix.</returns> - public Basis Scaled(Vector3 scale) + public readonly Basis Scaled(Vector3 scale) { Basis b = this; b.Row0 *= scale.x; @@ -772,7 +772,7 @@ namespace Godot /// <param name="target">The destination basis for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting basis matrix of the interpolation.</returns> - public Basis Slerp(Basis target, real_t weight) + public readonly Basis Slerp(Basis target, real_t weight) { Quaternion from = new Quaternion(this); Quaternion to = new Quaternion(target); @@ -790,7 +790,7 @@ namespace Godot /// </summary> /// <param name="with">A vector to calculate the dot product with.</param> /// <returns>The resulting dot product.</returns> - public real_t Tdotx(Vector3 with) + public readonly real_t Tdotx(Vector3 with) { return Row0[0] * with[0] + Row1[0] * with[1] + Row2[0] * with[2]; } @@ -800,7 +800,7 @@ namespace Godot /// </summary> /// <param name="with">A vector to calculate the dot product with.</param> /// <returns>The resulting dot product.</returns> - public real_t Tdoty(Vector3 with) + public readonly real_t Tdoty(Vector3 with) { return Row0[1] * with[0] + Row1[1] * with[1] + Row2[1] * with[2]; } @@ -810,7 +810,7 @@ namespace Godot /// </summary> /// <param name="with">A vector to calculate the dot product with.</param> /// <returns>The resulting dot product.</returns> - public real_t Tdotz(Vector3 with) + public readonly real_t Tdotz(Vector3 with) { return Row0[2] * with[0] + Row1[2] * with[1] + Row2[2] * with[2]; } @@ -819,21 +819,18 @@ namespace Godot /// Returns the transposed version of the basis matrix. /// </summary> /// <returns>The transposed basis matrix.</returns> - public Basis Transposed() + public readonly Basis Transposed() { Basis tr = this; - real_t temp = tr.Row0[1]; - tr.Row0[1] = tr.Row1[0]; - tr.Row1[0] = temp; + tr.Row0[1] = Row1[0]; + tr.Row1[0] = Row0[1]; - temp = tr.Row0[2]; - tr.Row0[2] = tr.Row2[0]; - tr.Row2[0] = temp; + tr.Row0[2] = Row2[0]; + tr.Row2[0] = Row0[2]; - temp = tr.Row1[2]; - tr.Row1[2] = tr.Row2[1]; - tr.Row2[1] = temp; + tr.Row1[2] = Row2[1]; + tr.Row2[1] = Row1[2]; return tr; } @@ -1121,7 +1118,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the basis matrix and the object are exactly equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Basis other && Equals(other); } @@ -1133,7 +1130,7 @@ namespace Godot /// </summary> /// <param name="other">The other basis.</param> /// <returns>Whether or not the basis matrices are exactly equal.</returns> - public bool Equals(Basis other) + public readonly bool Equals(Basis other) { return Row0.Equals(other.Row0) && Row1.Equals(other.Row1) && Row2.Equals(other.Row2); } @@ -1144,7 +1141,7 @@ namespace Godot /// </summary> /// <param name="other">The other basis to compare.</param> /// <returns>Whether or not the bases are approximately equal.</returns> - public bool IsEqualApprox(Basis other) + public readonly bool IsEqualApprox(Basis other) { return Row0.IsEqualApprox(other.Row0) && Row1.IsEqualApprox(other.Row1) && Row2.IsEqualApprox(other.Row2); } @@ -1153,7 +1150,7 @@ namespace Godot /// Serves as the hash function for <see cref="Basis"/>. /// </summary> /// <returns>A hash code for this basis.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode(); } @@ -1162,7 +1159,7 @@ namespace Godot /// Converts this <see cref="Basis"/> to a string. /// </summary> /// <returns>A string representation of this basis.</returns> - public override string ToString() + public override readonly string ToString() { return $"[X: {x}, Y: {y}, Z: {z}]"; } @@ -1171,7 +1168,7 @@ namespace Godot /// Converts this <see cref="Basis"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this basis.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"[X: {x.ToString(format)}, Y: {y.ToString(format)}, Z: {z.ToString(format)}]"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs index 647ae436ff..85d38f9727 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs @@ -4,7 +4,7 @@ namespace Godot.Bridge; #nullable enable -public struct MethodInfo +public readonly struct MethodInfo { public StringName Name { get; init; } public PropertyInfo ReturnVal { get; init; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs index 80d6f7b4a5..0f447b93c8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs @@ -2,7 +2,7 @@ namespace Godot.Bridge; #nullable enable -public struct PropertyInfo +public readonly struct PropertyInfo { public Variant.Type Type { get; init; } public StringName Name { get; init; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index ee9e59f9fa..f49023555b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -43,7 +43,7 @@ namespace Godot /// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value> public int r8 { - get + readonly get { return (int)Math.Round(r * 255.0f); } @@ -59,7 +59,7 @@ namespace Godot /// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value> public int g8 { - get + readonly get { return (int)Math.Round(g * 255.0f); } @@ -75,7 +75,7 @@ namespace Godot /// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value> public int b8 { - get + readonly get { return (int)Math.Round(b * 255.0f); } @@ -91,7 +91,7 @@ namespace Godot /// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value> public int a8 { - get + readonly get { return (int)Math.Round(a * 255.0f); } @@ -107,7 +107,7 @@ namespace Godot /// <value>Getting is a long process, refer to the source code for details. Setting uses <see cref="FromHSV"/>.</value> public float h { - get + readonly get { float max = Math.Max(r, Math.Max(g, b)); float min = Math.Min(r, Math.Min(g, b)); @@ -155,7 +155,7 @@ namespace Godot /// <value>Getting is equivalent to the ratio between the min and max RGB value. Setting uses <see cref="FromHSV"/>.</value> public float s { - get + readonly get { float max = Math.Max(r, Math.Max(g, b)); float min = Math.Min(r, Math.Min(g, b)); @@ -176,7 +176,7 @@ namespace Godot /// <value>Getting is equivalent to using <see cref="Math.Max(float, float)"/> on the RGB components. Setting uses <see cref="FromHSV"/>.</value> public float v { - get + readonly get { return Math.Max(r, Math.Max(g, b)); } @@ -197,7 +197,7 @@ namespace Godot /// </value> public float this[int index] { - get + readonly get { switch (index) { @@ -242,7 +242,7 @@ namespace Godot /// </summary> /// <param name="over">The color to blend over.</param> /// <returns>This color blended over <paramref name="over"/>.</returns> - public Color Blend(Color over) + public readonly Color Blend(Color over) { Color res; @@ -269,7 +269,7 @@ namespace Godot /// <param name="min">The color with minimum allowed values.</param> /// <param name="max">The color with maximum allowed values.</param> /// <returns>The color with all components clamped.</returns> - public Color Clamp(Color? min = null, Color? max = null) + public readonly Color Clamp(Color? min = null, Color? max = null) { Color minimum = min ?? new Color(0, 0, 0, 0); Color maximum = max ?? new Color(1, 1, 1, 1); @@ -288,7 +288,7 @@ namespace Godot /// </summary> /// <param name="amount">The ratio to darken by.</param> /// <returns>The darkened color.</returns> - public Color Darkened(float amount) + public readonly Color Darkened(float amount) { Color res = this; res.r *= 1.0f - amount; @@ -301,7 +301,7 @@ namespace Godot /// Returns the inverted color: <c>(1 - r, 1 - g, 1 - b, a)</c>. /// </summary> /// <returns>The inverted color.</returns> - public Color Inverted() + public readonly Color Inverted() { return new Color( 1.0f - r, @@ -317,7 +317,7 @@ namespace Godot /// </summary> /// <param name="amount">The ratio to lighten by.</param> /// <returns>The darkened color.</returns> - public Color Lightened(float amount) + public readonly Color Lightened(float amount) { Color res = this; res.r += (1.0f - res.r) * amount; @@ -333,7 +333,7 @@ namespace Godot /// <param name="to">The destination color for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting color of the interpolation.</returns> - public Color Lerp(Color to, real_t weight) + public readonly Color Lerp(Color to, real_t weight) { return new Color ( @@ -351,7 +351,7 @@ namespace Godot /// <param name="to">The destination color for interpolation.</param> /// <param name="weight">A color with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting color of the interpolation.</returns> - public Color Lerp(Color to, Color weight) + public readonly Color Lerp(Color to, Color weight) { return new Color ( @@ -368,7 +368,7 @@ namespace Godot /// ABGR is the reversed version of the default format. /// </summary> /// <returns>A <see langword="uint"/> representing this color in ABGR32 format.</returns> - public uint ToAbgr32() + public readonly uint ToAbgr32() { uint c = (byte)Math.Round(a * 255); c <<= 8; @@ -387,7 +387,7 @@ namespace Godot /// ABGR is the reversed version of the default format. /// </summary> /// <returns>A <see langword="ulong"/> representing this color in ABGR64 format.</returns> - public ulong ToAbgr64() + public readonly ulong ToAbgr64() { ulong c = (ushort)Math.Round(a * 65535); c <<= 16; @@ -406,7 +406,7 @@ namespace Godot /// ARGB is more compatible with DirectX, but not used much in Godot. /// </summary> /// <returns>A <see langword="uint"/> representing this color in ARGB32 format.</returns> - public uint ToArgb32() + public readonly uint ToArgb32() { uint c = (byte)Math.Round(a * 255); c <<= 8; @@ -425,7 +425,7 @@ namespace Godot /// ARGB is more compatible with DirectX, but not used much in Godot. /// </summary> /// <returns>A <see langword="ulong"/> representing this color in ARGB64 format.</returns> - public ulong ToArgb64() + public readonly ulong ToArgb64() { ulong c = (ushort)Math.Round(a * 65535); c <<= 16; @@ -444,7 +444,7 @@ namespace Godot /// RGBA is Godot's default and recommended format. /// </summary> /// <returns>A <see langword="uint"/> representing this color in RGBA32 format.</returns> - public uint ToRgba32() + public readonly uint ToRgba32() { uint c = (byte)Math.Round(r * 255); c <<= 8; @@ -463,7 +463,7 @@ namespace Godot /// RGBA is Godot's default and recommended format. /// </summary> /// <returns>A <see langword="ulong"/> representing this color in RGBA64 format.</returns> - public ulong ToRgba64() + public readonly ulong ToRgba64() { ulong c = (ushort)Math.Round(r * 65535); c <<= 16; @@ -483,7 +483,7 @@ namespace Godot /// Whether or not to include alpha. If <see langword="false"/>, the color is RGB instead of RGBA. /// </param> /// <returns>A string for the HTML hexadecimal representation of this color.</returns> - public string ToHTML(bool includeAlpha = true) + public readonly string ToHTML(bool includeAlpha = true) { string txt = string.Empty; @@ -777,7 +777,7 @@ namespace Godot /// <param name="hue">Output parameter for the HSV hue.</param> /// <param name="saturation">Output parameter for the HSV saturation.</param> /// <param name="value">Output parameter for the HSV value.</param> - public void ToHSV(out float hue, out float saturation, out float value) + public readonly void ToHSV(out float hue, out float saturation, out float value) { float max = (float)Mathf.Max(r, Mathf.Max(g, b)); float min = (float)Mathf.Min(r, Mathf.Min(g, b)); @@ -1149,7 +1149,7 @@ namespace Godot /// </summary> /// <param name="obj">The other object to compare.</param> /// <returns>Whether or not the color and the other object are equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Color other && Equals(other); } @@ -1161,7 +1161,7 @@ namespace Godot /// </summary> /// <param name="other">The other color.</param> /// <returns>Whether or not the colors are equal.</returns> - public bool Equals(Color other) + public readonly bool Equals(Color other) { return r == other.r && g == other.g && b == other.b && a == other.a; } @@ -1172,7 +1172,7 @@ namespace Godot /// </summary> /// <param name="other">The other color to compare.</param> /// <returns>Whether or not the colors are approximately equal.</returns> - public bool IsEqualApprox(Color other) + public readonly bool IsEqualApprox(Color other) { return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(a, other.a); } @@ -1181,7 +1181,7 @@ namespace Godot /// Serves as the hash function for <see cref="Color"/>. /// </summary> /// <returns>A hash code for this color.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return r.GetHashCode() ^ g.GetHashCode() ^ b.GetHashCode() ^ a.GetHashCode(); } @@ -1190,7 +1190,7 @@ namespace Godot /// Converts this <see cref="Color"/> to a string. /// </summary> /// <returns>A string representation of this color.</returns> - public override string ToString() + public override readonly string ToString() { return $"({r}, {g}, {b}, {a})"; } @@ -1199,7 +1199,7 @@ namespace Godot /// Converts this <see cref="Color"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this color.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"({r.ToString(format)}, {g.ToString(format)}, {b.ToString(format)}, {a.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs index 664b2e0f34..42c6b0a37e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs @@ -22,7 +22,7 @@ namespace Godot /// <value>Equivalent to <see cref="x"/>, <see cref="y"/>, and <see cref="z"/>.</value> public Vector3 Normal { - get { return _normal; } + readonly get { return _normal; } set { _normal = value; } } @@ -32,7 +32,7 @@ namespace Godot /// <value>Equivalent to <see cref="Normal"/>'s X value.</value> public real_t x { - get + readonly get { return _normal.x; } @@ -48,7 +48,7 @@ namespace Godot /// <value>Equivalent to <see cref="Normal"/>'s Y value.</value> public real_t y { - get + readonly get { return _normal.y; } @@ -64,7 +64,7 @@ namespace Godot /// <value>Equivalent to <see cref="Normal"/>'s Z value.</value> public real_t z { - get + readonly get { return _normal.z; } @@ -90,7 +90,7 @@ namespace Godot /// <value>Equivalent to <see cref="Normal"/> multiplied by <see cref="D"/>.</value> public Vector3 Center { - get + readonly get { return _normal * D; } @@ -106,7 +106,7 @@ namespace Godot /// </summary> /// <param name="point">The position to use for the calculation.</param> /// <returns>The shortest distance.</returns> - public real_t DistanceTo(Vector3 point) + public readonly real_t DistanceTo(Vector3 point) { return _normal.Dot(point) - D; } @@ -118,7 +118,7 @@ namespace Godot /// <param name="point">The point to check.</param> /// <param name="tolerance">The tolerance threshold.</param> /// <returns>A <see langword="bool"/> for whether or not the plane has the point.</returns> - public bool HasPoint(Vector3 point, real_t tolerance = Mathf.Epsilon) + public readonly bool HasPoint(Vector3 point, real_t tolerance = Mathf.Epsilon) { real_t dist = _normal.Dot(point) - D; return Mathf.Abs(dist) <= tolerance; @@ -131,7 +131,7 @@ namespace Godot /// <param name="b">One of the three planes to use in the calculation.</param> /// <param name="c">One of the three planes to use in the calculation.</param> /// <returns>The intersection, or <see langword="null"/> if none is found.</returns> - public Vector3? Intersect3(Plane b, Plane c) + public readonly Vector3? Intersect3(Plane b, Plane c) { real_t denom = _normal.Cross(b._normal).Dot(c._normal); @@ -155,7 +155,7 @@ namespace Godot /// <param name="from">The start of the ray.</param> /// <param name="dir">The direction of the ray, normalized.</param> /// <returns>The intersection, or <see langword="null"/> if none is found.</returns> - public Vector3? IntersectRay(Vector3 from, Vector3 dir) + public readonly Vector3? IntersectRay(Vector3 from, Vector3 dir) { real_t den = _normal.Dot(dir); @@ -183,7 +183,7 @@ namespace Godot /// <param name="begin">The start of the line segment.</param> /// <param name="end">The end of the line segment.</param> /// <returns>The intersection, or <see langword="null"/> if none is found.</returns> - public Vector3? IntersectSegment(Vector3 begin, Vector3 end) + public readonly Vector3? IntersectSegment(Vector3 begin, Vector3 end) { Vector3 segment = begin - end; real_t den = _normal.Dot(segment); @@ -209,7 +209,7 @@ namespace Godot /// </summary> /// <param name="point">The point to check.</param> /// <returns>A <see langword="bool"/> for whether or not the point is above the plane.</returns> - public bool IsPointOver(Vector3 point) + public readonly bool IsPointOver(Vector3 point) { return _normal.Dot(point) > D; } @@ -218,7 +218,7 @@ namespace Godot /// Returns the plane scaled to unit length. /// </summary> /// <returns>A normalized version of the plane.</returns> - public Plane Normalized() + public readonly Plane Normalized() { real_t len = _normal.Length(); @@ -235,7 +235,7 @@ namespace Godot /// </summary> /// <param name="point">The point to project.</param> /// <returns>The projected point.</returns> - public Vector3 Project(Vector3 point) + public readonly Vector3 Project(Vector3 point) { return point - (_normal * DistanceTo(point)); } @@ -363,7 +363,7 @@ namespace Godot /// </summary> /// <param name="obj">The other object to compare.</param> /// <returns>Whether or not the plane and the other object are exactly equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Plane other && Equals(other); } @@ -373,7 +373,7 @@ namespace Godot /// </summary> /// <param name="other">The other plane to compare.</param> /// <returns>Whether or not the planes are exactly equal.</returns> - public bool Equals(Plane other) + public readonly bool Equals(Plane other) { return _normal == other._normal && D == other.D; } @@ -384,7 +384,7 @@ namespace Godot /// </summary> /// <param name="other">The other plane to compare.</param> /// <returns>Whether or not the planes are approximately equal.</returns> - public bool IsEqualApprox(Plane other) + public readonly bool IsEqualApprox(Plane other) { return _normal.IsEqualApprox(other._normal) && Mathf.IsEqualApprox(D, other.D); } @@ -393,7 +393,7 @@ namespace Godot /// Serves as the hash function for <see cref="Plane"/>. /// </summary> /// <returns>A hash code for this plane.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return _normal.GetHashCode() ^ D.GetHashCode(); } @@ -402,7 +402,7 @@ namespace Godot /// Converts this <see cref="Plane"/> to a string. /// </summary> /// <returns>A string representation of this plane.</returns> - public override string ToString() + public override readonly string ToString() { return $"{_normal}, {D}"; } @@ -411,7 +411,7 @@ namespace Godot /// Converts this <see cref="Plane"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this plane.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"{_normal.ToString(format)}, {D.ToString(format)}"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs index da895fd121..371729ebec 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs @@ -286,7 +286,7 @@ namespace Godot return proj * cm; } - public real_t Determinant() + public readonly real_t Determinant() { return x.w * y.z * z.y * w.x - x.z * y.w * z.y * w.x - x.w * y.y * z.z * w.x + x.y * y.w * z.z * w.x + @@ -302,13 +302,13 @@ namespace Godot x.y * y.x * z.z * w.w + x.x * y.y * z.z * w.w; } - public real_t GetAspect() + public readonly real_t GetAspect() { Vector2 vpHe = GetViewportHalfExtents(); return vpHe.x / vpHe.y; } - public real_t GetFov() + public readonly real_t GetFov() { Plane rightPlane = new Plane(x.w - x.x, y.w - y.x, z.w - z.x, -w.w + w.x).Normalized(); if (z.x == 0 && z.y == 0) @@ -327,7 +327,7 @@ namespace Godot return Mathf.RadToDeg(Mathf.Atan(aspect * Mathf.Tan(Mathf.DegToRad(fovx) * (real_t)0.5)) * (real_t)2.0); } - public real_t GetLodMultiplier() + public readonly real_t GetLodMultiplier() { if (IsOrthogonal()) { @@ -341,14 +341,14 @@ namespace Godot } } - public int GetPixelsPerMeter(int forPixelWidth) + public readonly int GetPixelsPerMeter(int forPixelWidth) { Vector3 result = this * new Vector3(1, 0, -1); return (int)((result.x * (real_t)0.5 + (real_t)0.5) * forPixelWidth); } - public Plane GetProjectionPlane(Planes plane) + public readonly Plane GetProjectionPlane(Planes plane) { Plane newPlane = plane switch { @@ -364,36 +364,36 @@ namespace Godot return newPlane.Normalized(); } - public Vector2 GetFarPlaneHalfExtents() + public readonly Vector2 GetFarPlaneHalfExtents() { var res = GetProjectionPlane(Planes.Far).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top)); return new Vector2(res.Value.x, res.Value.y); } - public Vector2 GetViewportHalfExtents() + public readonly Vector2 GetViewportHalfExtents() { var res = GetProjectionPlane(Planes.Near).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top)); return new Vector2(res.Value.x, res.Value.y); } - public real_t GetZFar() + public readonly real_t GetZFar() { return GetProjectionPlane(Planes.Far).D; } - public real_t GetZNear() + public readonly real_t GetZNear() { return -GetProjectionPlane(Planes.Near).D; } - public Projection FlippedY() + public readonly Projection FlippedY() { Projection proj = this; proj.y = -proj.y; return proj; } - public Projection PerspectiveZNearAdjusted(real_t newZNear) + public readonly Projection PerspectiveZNearAdjusted(real_t newZNear) { Projection proj = this; real_t zFar = GetZFar(); @@ -404,7 +404,7 @@ namespace Godot return proj; } - public Projection JitterOffseted(Vector2 offset) + public readonly Projection JitterOffseted(Vector2 offset) { Projection proj = this; proj.w.x += offset.x; @@ -412,7 +412,7 @@ namespace Godot return proj; } - public Projection Inverse() + public readonly Projection Inverse() { Projection proj = this; int i, j, k; @@ -535,7 +535,7 @@ namespace Godot return proj; } - public bool IsOrthogonal() + public readonly bool IsOrthogonal() { return w.w == (real_t)1.0; } @@ -654,7 +654,7 @@ namespace Godot /// </exception> public Vector4 this[int column] { - get + readonly get { switch (column) { @@ -702,7 +702,7 @@ namespace Godot /// </exception> public real_t this[int column, int row] { - get + readonly get { switch (column) { @@ -772,7 +772,7 @@ namespace Godot /// Serves as the hash function for <see cref="Projection"/>. /// </summary> /// <returns>A hash code for this projection.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); } @@ -781,7 +781,7 @@ namespace Godot /// Converts this <see cref="Projection"/> to a string. /// </summary> /// <returns>A string representation of this projection.</returns> - public override string ToString() + public override readonly string ToString() { return $"{x.x}, {x.y}, {x.z}, {x.w}\n{y.x}, {y.y}, {y.z}, {y.w}\n{z.x}, {z.y}, {z.z}, {z.w}\n{w.x}, {w.y}, {w.z}, {w.w}\n"; } @@ -790,7 +790,7 @@ namespace Godot /// Converts this <see cref="Projection"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this projection.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"{x.x.ToString(format)}, {x.y.ToString(format)}, {x.z.ToString(format)}, {x.w.ToString(format)}\n" + $"{y.x.ToString(format)}, {y.y.ToString(format)}, {y.z.ToString(format)}, {y.w.ToString(format)}\n" + @@ -804,7 +804,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Projection other && Equals(other); } @@ -814,7 +814,7 @@ namespace Godot /// </summary> /// <param name="other">The other projection.</param> /// <returns>Whether or not the projections are exactly equal.</returns> - public bool Equals(Projection other) + public readonly bool Equals(Projection other) { return x == other.x && y == other.y && z == other.z && w == other.w; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index f01f0be985..c55003586b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -58,7 +58,7 @@ namespace Godot /// </value> public real_t this[int index] { - get + readonly get { switch (index) { @@ -101,7 +101,7 @@ namespace Godot /// </summary> /// <seealso cref="LengthSquared"/> /// <value>Equivalent to <c>Mathf.Sqrt(LengthSquared)</c>.</value> - public real_t Length + public readonly real_t Length { get { return Mathf.Sqrt(LengthSquared); } } @@ -112,7 +112,7 @@ namespace Godot /// you need to compare quaternions or need the squared length for some formula. /// </summary> /// <value>Equivalent to <c>Dot(this)</c>.</value> - public real_t LengthSquared + public readonly real_t LengthSquared { get { return Dot(this); } } @@ -128,7 +128,7 @@ namespace Godot /// </summary> /// <param name="to">The other quaternion.</param> /// <returns>The angle between the quaternions.</returns> - public real_t AngleTo(Quaternion to) + public readonly real_t AngleTo(Quaternion to) { real_t dot = Dot(to); return Mathf.Acos(Mathf.Clamp(dot * dot * 2 - 1, -1, 1)); @@ -143,7 +143,7 @@ namespace Godot /// <param name="postB">A quaternion after <paramref name="b"/>.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated quaternion.</returns> - public Quaternion SphericalCubicInterpolate(Quaternion b, Quaternion preA, Quaternion postB, real_t weight) + public readonly Quaternion SphericalCubicInterpolate(Quaternion b, Quaternion preA, Quaternion postB, real_t weight) { #if DEBUG if (!IsNormalized()) @@ -212,7 +212,7 @@ namespace Godot /// <param name="preAT"></param> /// <param name="postBT"></param> /// <returns>The interpolated quaternion.</returns> - public Quaternion SphericalCubicInterpolateInTime(Quaternion b, Quaternion preA, Quaternion postB, real_t weight, real_t bT, real_t preAT, real_t postBT) + public readonly Quaternion SphericalCubicInterpolateInTime(Quaternion b, Quaternion preA, Quaternion postB, real_t weight, real_t bT, real_t preAT, real_t postBT) { #if DEBUG if (!IsNormalized()) @@ -272,12 +272,12 @@ namespace Godot /// </summary> /// <param name="b">The other quaternion.</param> /// <returns>The dot product.</returns> - public real_t Dot(Quaternion b) + public readonly real_t Dot(Quaternion b) { return (x * b.x) + (y * b.y) + (z * b.z) + (w * b.w); } - public Quaternion Exp() + public readonly Quaternion Exp() { Vector3 v = new Vector3(x, y, z); real_t theta = v.Length(); @@ -289,12 +289,12 @@ namespace Godot return new Quaternion(v, theta); } - public real_t GetAngle() + public readonly real_t GetAngle() { return 2 * Mathf.Acos(w); } - public Vector3 GetAxis() + public readonly Vector3 GetAxis() { if (Mathf.Abs(w) > 1 - Mathf.Epsilon) { @@ -312,7 +312,7 @@ namespace Godot /// the rotation angles in the format (X angle, Y angle, Z angle). /// </summary> /// <returns>The Euler angle representation of this quaternion.</returns> - public Vector3 GetEuler(EulerOrder order = EulerOrder.Yxz) + public readonly Vector3 GetEuler(EulerOrder order = EulerOrder.Yxz) { #if DEBUG if (!IsNormalized()) @@ -328,7 +328,7 @@ namespace Godot /// Returns the inverse of the quaternion. /// </summary> /// <returns>The inverse quaternion.</returns> - public Quaternion Inverse() + public readonly Quaternion Inverse() { #if DEBUG if (!IsNormalized()) @@ -343,12 +343,12 @@ namespace Godot /// Returns whether the quaternion is normalized or not. /// </summary> /// <returns>A <see langword="bool"/> for whether the quaternion is normalized or not.</returns> - public bool IsNormalized() + public readonly bool IsNormalized() { return Mathf.Abs(LengthSquared - 1) <= Mathf.Epsilon; } - public Quaternion Log() + public readonly Quaternion Log() { Vector3 v = GetAxis() * GetAngle(); return new Quaternion(v.x, v.y, v.z, 0); @@ -358,7 +358,7 @@ namespace Godot /// Returns a copy of the quaternion, normalized to unit length. /// </summary> /// <returns>The normalized quaternion.</returns> - public Quaternion Normalized() + public readonly Quaternion Normalized() { return this / Length; } @@ -372,7 +372,7 @@ namespace Godot /// <param name="to">The destination quaternion for interpolation. Must be normalized.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting quaternion of the interpolation.</returns> - public Quaternion Slerp(Quaternion to, real_t weight) + public readonly Quaternion Slerp(Quaternion to, real_t weight) { #if DEBUG if (!IsNormalized()) @@ -437,7 +437,7 @@ namespace Godot /// <param name="to">The destination quaternion for interpolation. Must be normalized.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting quaternion of the interpolation.</returns> - public Quaternion Slerpni(Quaternion to, real_t weight) + public readonly Quaternion Slerpni(Quaternion to, real_t weight) { #if DEBUG if (!IsNormalized()) @@ -762,7 +762,7 @@ namespace Godot /// </summary> /// <param name="obj">The other object to compare.</param> /// <returns>Whether or not the quaternion and the other object are exactly equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Quaternion other && Equals(other); } @@ -772,7 +772,7 @@ namespace Godot /// </summary> /// <param name="other">The other quaternion to compare.</param> /// <returns>Whether or not the quaternions are exactly equal.</returns> - public bool Equals(Quaternion other) + public readonly bool Equals(Quaternion other) { return x == other.x && y == other.y && z == other.z && w == other.w; } @@ -783,7 +783,7 @@ namespace Godot /// </summary> /// <param name="other">The other quaternion to compare.</param> /// <returns>Whether or not the quaternions are approximately equal.</returns> - public bool IsEqualApprox(Quaternion other) + public readonly bool IsEqualApprox(Quaternion other) { return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w); } @@ -792,7 +792,7 @@ namespace Godot /// Serves as the hash function for <see cref="Quaternion"/>. /// </summary> /// <returns>A hash code for this quaternion.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); } @@ -801,7 +801,7 @@ namespace Godot /// Converts this <see cref="Quaternion"/> to a string. /// </summary> /// <returns>A string representation of this quaternion.</returns> - public override string ToString() + public override readonly string ToString() { return $"({x}, {y}, {z}, {w})"; } @@ -810,7 +810,7 @@ namespace Godot /// Converts this <see cref="Quaternion"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this quaternion.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)}, {w.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs index a31fef8360..59b9faf16c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs @@ -12,9 +12,9 @@ namespace Godot /// classes such as <see cref="RenderingServer"/>. /// </summary> [StructLayout(LayoutKind.Sequential)] - public struct RID + public readonly struct RID { - private ulong _id; // Default is 0 + private readonly ulong _id; // Default is 0 internal RID(ulong id) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index e80d75dacf..b0e0e75a34 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs @@ -20,7 +20,7 @@ namespace Godot /// <value>Directly uses a private field.</value> public Vector2 Position { - get { return _position; } + readonly get { return _position; } set { _position = value; } } @@ -31,7 +31,7 @@ namespace Godot /// <value>Directly uses a private field.</value> public Vector2 Size { - get { return _size; } + readonly get { return _size; } set { _size = value; } } @@ -45,7 +45,7 @@ namespace Godot /// </value> public Vector2 End { - get { return _position + _size; } + readonly get { return _position + _size; } set { _size = value - _position; } } @@ -53,7 +53,7 @@ namespace Godot /// The area of this <see cref="Rect2"/>. /// </summary> /// <value>Equivalent to <see cref="GetArea()"/>.</value> - public real_t Area + public readonly real_t Area { get { return GetArea(); } } @@ -63,7 +63,7 @@ namespace Godot /// the top-left corner is the origin and width and height are positive. /// </summary> /// <returns>The modified <see cref="Rect2"/>.</returns> - public Rect2 Abs() + public readonly Rect2 Abs() { Vector2 end = End; Vector2 topLeft = new Vector2(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y)); @@ -79,7 +79,7 @@ namespace Godot /// The intersection of this <see cref="Rect2"/> and <paramref name="b"/>, /// or an empty <see cref="Rect2"/> if they do not intersect. /// </returns> - public Rect2 Intersection(Rect2 b) + public readonly Rect2 Intersection(Rect2 b) { Rect2 newRect = b; @@ -107,7 +107,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not this <see cref="Rect2"/> encloses <paramref name="b"/>. /// </returns> - public bool Encloses(Rect2 b) + public readonly bool Encloses(Rect2 b) { return b._position.x >= _position.x && b._position.y >= _position.y && b._position.x + b._size.x < _position.x + _size.x && @@ -119,7 +119,7 @@ namespace Godot /// </summary> /// <param name="to">The point to include.</param> /// <returns>The expanded <see cref="Rect2"/>.</returns> - public Rect2 Expand(Vector2 to) + public readonly Rect2 Expand(Vector2 to) { Rect2 expanded = this; @@ -154,7 +154,7 @@ namespace Godot /// Returns the area of the <see cref="Rect2"/>. /// </summary> /// <returns>The area.</returns> - public real_t GetArea() + public readonly real_t GetArea() { return _size.x * _size.y; } @@ -164,7 +164,7 @@ namespace Godot /// to <see cref="Position"/> + (<see cref="Size"/> / 2). /// </summary> /// <returns>The center.</returns> - public Vector2 GetCenter() + public readonly Vector2 GetCenter() { return _position + (_size * 0.5f); } @@ -177,7 +177,7 @@ namespace Godot /// <seealso cref="GrowSide(Side, real_t)"/> /// <param name="by">The amount to grow by.</param> /// <returns>The grown <see cref="Rect2"/>.</returns> - public Rect2 Grow(real_t by) + public readonly Rect2 Grow(real_t by) { Rect2 g = this; @@ -200,7 +200,7 @@ namespace Godot /// <param name="right">The amount to grow by on the right side.</param> /// <param name="bottom">The amount to grow by on the bottom side.</param> /// <returns>The grown <see cref="Rect2"/>.</returns> - public Rect2 GrowIndividual(real_t left, real_t top, real_t right, real_t bottom) + public readonly Rect2 GrowIndividual(real_t left, real_t top, real_t right, real_t bottom) { Rect2 g = this; @@ -221,7 +221,7 @@ namespace Godot /// <param name="side">The side to grow.</param> /// <param name="by">The amount to grow by.</param> /// <returns>The grown <see cref="Rect2"/>.</returns> - public Rect2 GrowSide(Side side, real_t by) + public readonly Rect2 GrowSide(Side side, real_t by) { Rect2 g = this; @@ -242,7 +242,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="Rect2"/> has area. /// </returns> - public bool HasArea() + public readonly bool HasArea() { return _size.x > 0.0f && _size.y > 0.0f; } @@ -255,7 +255,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="Rect2"/> contains <paramref name="point"/>. /// </returns> - public bool HasPoint(Vector2 point) + public readonly bool HasPoint(Vector2 point) { if (point.x < _position.x) return false; @@ -281,7 +281,7 @@ namespace Godot /// <param name="b">The other <see cref="Rect2"/> to check for intersections with.</param> /// <param name="includeBorders">Whether or not to consider borders.</param> /// <returns>A <see langword="bool"/> for whether or not they are intersecting.</returns> - public bool Intersects(Rect2 b, bool includeBorders = false) + public readonly bool Intersects(Rect2 b, bool includeBorders = false) { if (includeBorders) { @@ -330,7 +330,7 @@ namespace Godot /// </summary> /// <param name="b">The other <see cref="Rect2"/>.</param> /// <returns>The merged <see cref="Rect2"/>.</returns> - public Rect2 Merge(Rect2 b) + public readonly Rect2 Merge(Rect2 b) { Rect2 newRect; @@ -426,7 +426,7 @@ namespace Godot /// </summary> /// <param name="obj">The other object to compare.</param> /// <returns>Whether or not the rect and the other object are exactly equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Rect2 other && Equals(other); } @@ -436,7 +436,7 @@ namespace Godot /// </summary> /// <param name="other">The other rect to compare.</param> /// <returns>Whether or not the rects are exactly equal.</returns> - public bool Equals(Rect2 other) + public readonly bool Equals(Rect2 other) { return _position.Equals(other._position) && _size.Equals(other._size); } @@ -447,7 +447,7 @@ namespace Godot /// </summary> /// <param name="other">The other rect to compare.</param> /// <returns>Whether or not the rects are approximately equal.</returns> - public bool IsEqualApprox(Rect2 other) + public readonly bool IsEqualApprox(Rect2 other) { return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other.Size); } @@ -456,7 +456,7 @@ namespace Godot /// Serves as the hash function for <see cref="Rect2"/>. /// </summary> /// <returns>A hash code for this rect.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return _position.GetHashCode() ^ _size.GetHashCode(); } @@ -465,7 +465,7 @@ namespace Godot /// Converts this <see cref="Rect2"/> to a string. /// </summary> /// <returns>A string representation of this rect.</returns> - public override string ToString() + public override readonly string ToString() { return $"{_position}, {_size}"; } @@ -474,7 +474,7 @@ namespace Godot /// Converts this <see cref="Rect2"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this rect.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"{_position.ToString(format)}, {_size.ToString(format)}"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs index b2768476cc..faee81a98a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs @@ -20,7 +20,7 @@ namespace Godot /// <value>Directly uses a private field.</value> public Vector2i Position { - get { return _position; } + readonly get { return _position; } set { _position = value; } } @@ -31,7 +31,7 @@ namespace Godot /// <value>Directly uses a private field.</value> public Vector2i Size { - get { return _size; } + readonly get { return _size; } set { _size = value; } } @@ -45,7 +45,7 @@ namespace Godot /// </value> public Vector2i End { - get { return _position + _size; } + readonly get { return _position + _size; } set { _size = value - _position; } } @@ -53,7 +53,7 @@ namespace Godot /// The area of this <see cref="Rect2i"/>. /// </summary> /// <value>Equivalent to <see cref="GetArea()"/>.</value> - public int Area + public readonly int Area { get { return GetArea(); } } @@ -63,7 +63,7 @@ namespace Godot /// the top-left corner is the origin and width and height are positive. /// </summary> /// <returns>The modified <see cref="Rect2i"/>.</returns> - public Rect2i Abs() + public readonly Rect2i Abs() { Vector2i end = End; Vector2i topLeft = new Vector2i(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y)); @@ -79,7 +79,7 @@ namespace Godot /// The intersection of this <see cref="Rect2i"/> and <paramref name="b"/>, /// or an empty <see cref="Rect2i"/> if they do not intersect. /// </returns> - public Rect2i Intersection(Rect2i b) + public readonly Rect2i Intersection(Rect2i b) { Rect2i newRect = b; @@ -107,7 +107,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not this <see cref="Rect2i"/> encloses <paramref name="b"/>. /// </returns> - public bool Encloses(Rect2i b) + public readonly bool Encloses(Rect2i b) { return b._position.x >= _position.x && b._position.y >= _position.y && b._position.x + b._size.x < _position.x + _size.x && @@ -119,7 +119,7 @@ namespace Godot /// </summary> /// <param name="to">The point to include.</param> /// <returns>The expanded <see cref="Rect2i"/>.</returns> - public Rect2i Expand(Vector2i to) + public readonly Rect2i Expand(Vector2i to) { Rect2i expanded = this; @@ -154,7 +154,7 @@ namespace Godot /// Returns the area of the <see cref="Rect2i"/>. /// </summary> /// <returns>The area.</returns> - public int GetArea() + public readonly int GetArea() { return _size.x * _size.y; } @@ -166,7 +166,7 @@ namespace Godot /// value will be rounded towards <see cref="Position"/>. /// </summary> /// <returns>The center.</returns> - public Vector2i GetCenter() + public readonly Vector2i GetCenter() { return _position + (_size / 2); } @@ -179,7 +179,7 @@ namespace Godot /// <seealso cref="GrowSide(Side, int)"/> /// <param name="by">The amount to grow by.</param> /// <returns>The grown <see cref="Rect2i"/>.</returns> - public Rect2i Grow(int by) + public readonly Rect2i Grow(int by) { Rect2i g = this; @@ -202,7 +202,7 @@ namespace Godot /// <param name="right">The amount to grow by on the right side.</param> /// <param name="bottom">The amount to grow by on the bottom side.</param> /// <returns>The grown <see cref="Rect2i"/>.</returns> - public Rect2i GrowIndividual(int left, int top, int right, int bottom) + public readonly Rect2i GrowIndividual(int left, int top, int right, int bottom) { Rect2i g = this; @@ -223,7 +223,7 @@ namespace Godot /// <param name="side">The side to grow.</param> /// <param name="by">The amount to grow by.</param> /// <returns>The grown <see cref="Rect2i"/>.</returns> - public Rect2i GrowSide(Side side, int by) + public readonly Rect2i GrowSide(Side side, int by) { Rect2i g = this; @@ -244,7 +244,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="Rect2i"/> has area. /// </returns> - public bool HasArea() + public readonly bool HasArea() { return _size.x > 0 && _size.y > 0; } @@ -257,7 +257,7 @@ namespace Godot /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="Rect2i"/> contains <paramref name="point"/>. /// </returns> - public bool HasPoint(Vector2i point) + public readonly bool HasPoint(Vector2i point) { if (point.x < _position.x) return false; @@ -283,7 +283,7 @@ namespace Godot /// <param name="b">The other <see cref="Rect2i"/> to check for intersections with.</param> /// <param name="includeBorders">Whether or not to consider borders.</param> /// <returns>A <see langword="bool"/> for whether or not they are intersecting.</returns> - public bool Intersects(Rect2i b, bool includeBorders = false) + public readonly bool Intersects(Rect2i b, bool includeBorders = false) { if (includeBorders) { @@ -316,7 +316,7 @@ namespace Godot /// </summary> /// <param name="b">The other <see cref="Rect2i"/>.</param> /// <returns>The merged <see cref="Rect2i"/>.</returns> - public Rect2i Merge(Rect2i b) + public readonly Rect2i Merge(Rect2i b) { Rect2i newRect; @@ -426,7 +426,7 @@ namespace Godot /// </summary> /// <param name="obj">The other object to compare.</param> /// <returns>Whether or not the rect and the other object are equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Rect2i other && Equals(other); } @@ -436,7 +436,7 @@ namespace Godot /// </summary> /// <param name="other">The other rect to compare.</param> /// <returns>Whether or not the rects are equal.</returns> - public bool Equals(Rect2i other) + public readonly bool Equals(Rect2i other) { return _position.Equals(other._position) && _size.Equals(other._size); } @@ -445,7 +445,7 @@ namespace Godot /// Serves as the hash function for <see cref="Rect2i"/>. /// </summary> /// <returns>A hash code for this rect.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return _position.GetHashCode() ^ _size.GetHashCode(); } @@ -454,7 +454,7 @@ namespace Godot /// Converts this <see cref="Rect2i"/> to a string. /// </summary> /// <returns>A string representation of this rect.</returns> - public override string ToString() + public override readonly string ToString() { return $"{_position}, {_size}"; } @@ -463,7 +463,7 @@ namespace Godot /// Converts this <see cref="Rect2i"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this rect.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"{_position.ToString(format)}, {_size.ToString(format)}"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 894667db76..756f71e5b2 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -37,7 +37,7 @@ namespace Godot /// <value>Getting is equivalent to calling <see cref="Mathf.Atan2(real_t, real_t)"/> with the values of <see cref="x"/>.</value> public real_t Rotation { - get + readonly get { return Mathf.Atan2(x.y, x.x); } @@ -57,7 +57,7 @@ namespace Godot /// <value>Equivalent to the lengths of each column vector, but Y is negative if the determinant is negative.</value> public Vector2 Scale { - get + readonly get { real_t detSign = Mathf.Sign(BasisDeterminant()); return new Vector2(x.Length(), detSign * y.Length()); @@ -80,7 +80,7 @@ namespace Godot /// </exception> public Vector2 this[int column] { - get + readonly get { switch (column) { @@ -121,7 +121,7 @@ namespace Godot /// <param name="row">Which row, the matrix vertical position.</param> public real_t this[int column, int row] { - get + readonly get { return this[column][row]; } @@ -139,7 +139,7 @@ namespace Godot /// </summary> /// <seealso cref="Inverse"/> /// <returns>The inverse transformation matrix.</returns> - public Transform2D AffineInverse() + public readonly Transform2D AffineInverse() { real_t det = BasisDeterminant(); @@ -148,9 +148,8 @@ namespace Godot Transform2D inv = this; - real_t temp = inv[0, 0]; - inv[0, 0] = inv[1, 1]; - inv[1, 1] = temp; + inv[0, 0] = this[1, 1]; + inv[1, 1] = this[0, 0]; real_t detInv = 1.0f / det; @@ -171,7 +170,7 @@ namespace Godot /// and is usually considered invalid. /// </summary> /// <returns>The determinant of the basis matrix.</returns> - private real_t BasisDeterminant() + private readonly real_t BasisDeterminant() { return (x.x * y.y) - (x.y * y.x); } @@ -183,7 +182,7 @@ namespace Godot /// <seealso cref="BasisXformInv(Vector2)"/> /// <param name="v">A vector to transform.</param> /// <returns>The transformed vector.</returns> - public Vector2 BasisXform(Vector2 v) + public readonly Vector2 BasisXform(Vector2 v) { return new Vector2(Tdotx(v), Tdoty(v)); } @@ -198,7 +197,7 @@ namespace Godot /// <seealso cref="BasisXform(Vector2)"/> /// <param name="v">A vector to inversely transform.</param> /// <returns>The inversely transformed vector.</returns> - public Vector2 BasisXformInv(Vector2 v) + public readonly Vector2 BasisXformInv(Vector2 v) { return new Vector2(x.Dot(v), y.Dot(v)); } @@ -209,7 +208,7 @@ namespace Godot /// <param name="transform">The other transform.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated transform.</returns> - public Transform2D InterpolateWith(Transform2D transform, real_t weight) + public readonly Transform2D InterpolateWith(Transform2D transform, real_t weight) { real_t r1 = Rotation; real_t r2 = transform.Rotation; @@ -258,14 +257,13 @@ namespace Godot /// (no scaling, use <see cref="AffineInverse"/> for transforms with scaling). /// </summary> /// <returns>The inverse matrix.</returns> - public Transform2D Inverse() + public readonly Transform2D Inverse() { Transform2D inv = this; // Swap - real_t temp = inv.x.y; - inv.x.y = inv.y.x; - inv.y.x = temp; + inv.x.y = y.x; + inv.y.x = x.y; inv.origin = inv.BasisXform(-inv.origin); @@ -277,7 +275,7 @@ namespace Godot /// and normalized axis vectors (scale of 1 or -1). /// </summary> /// <returns>The orthonormalized transform.</returns> - public Transform2D Orthonormalized() + public readonly Transform2D Orthonormalized() { Transform2D on = this; @@ -301,7 +299,7 @@ namespace Godot /// </summary> /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> - public Transform2D Rotated(real_t angle) + public readonly Transform2D Rotated(real_t angle) { return this * new Transform2D(angle, new Vector2()); } @@ -313,7 +311,7 @@ namespace Godot /// </summary> /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> - public Transform2D RotatedLocal(real_t angle) + public readonly Transform2D RotatedLocal(real_t angle) { return new Transform2D(angle, new Vector2()) * this; } @@ -325,7 +323,7 @@ namespace Godot /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled transformation matrix.</returns> - public Transform2D Scaled(Vector2 scale) + public readonly Transform2D Scaled(Vector2 scale) { Transform2D copy = this; copy.x *= scale; @@ -341,7 +339,7 @@ namespace Godot /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled transformation matrix.</returns> - public Transform2D ScaledLocal(Vector2 scale) + public readonly Transform2D ScaledLocal(Vector2 scale) { Transform2D copy = this; copy.x *= scale; @@ -349,12 +347,12 @@ namespace Godot return copy; } - private real_t Tdotx(Vector2 with) + private readonly real_t Tdotx(Vector2 with) { return (this[0, 0] * with[0]) + (this[1, 0] * with[1]); } - private real_t Tdoty(Vector2 with) + private readonly real_t Tdoty(Vector2 with) { return (this[0, 1] * with[0]) + (this[1, 1] * with[1]); } @@ -366,7 +364,7 @@ namespace Godot /// </summary> /// <param name="offset">The offset to translate by.</param> /// <returns>The translated matrix.</returns> - public Transform2D Translated(Vector2 offset) + public readonly Transform2D Translated(Vector2 offset) { Transform2D copy = this; copy.origin += offset; @@ -380,7 +378,7 @@ namespace Godot /// </summary> /// <param name="offset">The offset to translate by.</param> /// <returns>The translated matrix.</returns> - public Transform2D TranslatedLocal(Vector2 offset) + public readonly Transform2D TranslatedLocal(Vector2 offset) { Transform2D copy = this; copy.origin += copy.BasisXform(offset); @@ -603,7 +601,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the transform and the object are exactly equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Transform2D other && Equals(other); } @@ -615,7 +613,7 @@ namespace Godot /// </summary> /// <param name="other">The other transform to compare.</param> /// <returns>Whether or not the matrices are exactly equal.</returns> - public bool Equals(Transform2D other) + public readonly bool Equals(Transform2D other) { return x.Equals(other.x) && y.Equals(other.y) && origin.Equals(other.origin); } @@ -626,7 +624,7 @@ namespace Godot /// </summary> /// <param name="other">The other transform to compare.</param> /// <returns>Whether or not the matrices are approximately equal.</returns> - public bool IsEqualApprox(Transform2D other) + public readonly bool IsEqualApprox(Transform2D other) { return x.IsEqualApprox(other.x) && y.IsEqualApprox(other.y) && origin.IsEqualApprox(other.origin); } @@ -635,7 +633,7 @@ namespace Godot /// Serves as the hash function for <see cref="Transform2D"/>. /// </summary> /// <returns>A hash code for this transform.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return x.GetHashCode() ^ y.GetHashCode() ^ origin.GetHashCode(); } @@ -644,7 +642,7 @@ namespace Godot /// Converts this <see cref="Transform2D"/> to a string. /// </summary> /// <returns>A string representation of this transform.</returns> - public override string ToString() + public override readonly string ToString() { return $"[X: {x}, Y: {y}, O: {origin}]"; } @@ -653,7 +651,7 @@ namespace Godot /// Converts this <see cref="Transform2D"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this transform.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"[X: {x.ToString(format)}, Y: {y.ToString(format)}, O: {origin.ToString(format)}]"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 2f7891e7ef..39167bd116 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -37,7 +37,7 @@ namespace Godot /// </exception> public Vector3 this[int column] { - get + readonly get { switch (column) { @@ -83,7 +83,7 @@ namespace Godot /// <param name="row">Which row, the matrix vertical position.</param> public real_t this[int column, int row] { - get + readonly get { if (column == 3) { @@ -108,7 +108,7 @@ namespace Godot /// </summary> /// <seealso cref="Inverse"/> /// <returns>The inverse transformation matrix.</returns> - public Transform3D AffineInverse() + public readonly Transform3D AffineInverse() { Basis basisInv = basis.Inverse(); return new Transform3D(basisInv, basisInv * -origin); @@ -120,7 +120,7 @@ namespace Godot /// <param name="transform">The other transform.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated transform.</returns> - public Transform3D InterpolateWith(Transform3D transform, real_t weight) + public readonly Transform3D InterpolateWith(Transform3D transform, real_t weight) { Basis retBasis = basis.Lerp(transform.basis, weight); Vector3 retOrigin = origin.Lerp(transform.origin, weight); @@ -133,7 +133,7 @@ namespace Godot /// (no scaling, use <see cref="AffineInverse"/> for transforms with scaling). /// </summary> /// <returns>The inverse matrix.</returns> - public Transform3D Inverse() + public readonly Transform3D Inverse() { Basis basisTr = basis.Transposed(); return new Transform3D(basisTr, basisTr * -origin); @@ -164,7 +164,7 @@ namespace Godot /// and normalized axis vectors (scale of 1 or -1). /// </summary> /// <returns>The orthonormalized transform.</returns> - public Transform3D Orthonormalized() + public readonly Transform3D Orthonormalized() { return new Transform3D(basis.Orthonormalized(), origin); } @@ -192,7 +192,7 @@ namespace Godot /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> - public Transform3D RotatedLocal(Vector3 axis, real_t angle) + public readonly Transform3D RotatedLocal(Vector3 axis, real_t angle) { Basis tmpBasis = new Basis(axis, angle); return new Transform3D(basis * tmpBasis, origin); @@ -205,7 +205,7 @@ namespace Godot /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled transformation matrix.</returns> - public Transform3D Scaled(Vector3 scale) + public readonly Transform3D Scaled(Vector3 scale) { return new Transform3D(basis.Scaled(scale), origin * scale); } @@ -217,7 +217,7 @@ namespace Godot /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled transformation matrix.</returns> - public Transform3D ScaledLocal(Vector3 scale) + public readonly Transform3D ScaledLocal(Vector3 scale) { Basis tmpBasis = Basis.FromScale(scale); return new Transform3D(basis * tmpBasis, origin); @@ -230,7 +230,7 @@ namespace Godot /// <param name="transform">The other transform.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated transform.</returns> - public Transform3D SphericalInterpolateWith(Transform3D transform, real_t weight) + public readonly Transform3D SphericalInterpolateWith(Transform3D transform, real_t weight) { /* not sure if very "efficient" but good enough? */ @@ -281,7 +281,7 @@ namespace Godot /// </summary> /// <param name="offset">The offset to translate by.</param> /// <returns>The translated matrix.</returns> - public Transform3D Translated(Vector3 offset) + public readonly Transform3D Translated(Vector3 offset) { return new Transform3D(basis, origin + offset); } @@ -293,7 +293,7 @@ namespace Godot /// </summary> /// <param name="offset">The offset to translate by.</param> /// <returns>The translated matrix.</returns> - public Transform3D TranslatedLocal(Vector3 offset) + public readonly Transform3D TranslatedLocal(Vector3 offset) { return new Transform3D(basis, new Vector3 ( @@ -617,7 +617,7 @@ namespace Godot /// </summary> /// <param name="other">The other transform to compare.</param> /// <returns>Whether or not the matrices are approximately equal.</returns> - public bool IsEqualApprox(Transform3D other) + public readonly bool IsEqualApprox(Transform3D other) { return basis.IsEqualApprox(other.basis) && origin.IsEqualApprox(other.origin); } @@ -626,7 +626,7 @@ namespace Godot /// Serves as the hash function for <see cref="Transform3D"/>. /// </summary> /// <returns>A hash code for this transform.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return basis.GetHashCode() ^ origin.GetHashCode(); } @@ -635,7 +635,7 @@ namespace Godot /// Converts this <see cref="Transform3D"/> to a string. /// </summary> /// <returns>A string representation of this transform.</returns> - public override string ToString() + public override readonly string ToString() { return $"[X: {basis.x}, Y: {basis.y}, Z: {basis.z}, O: {origin}]"; } @@ -644,7 +644,7 @@ namespace Godot /// Converts this <see cref="Transform3D"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this transform.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"[X: {basis.x.ToString(format)}, Y: {basis.y.ToString(format)}, Z: {basis.z.ToString(format)}, O: {origin.ToString(format)}]"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 87f397891e..96a6cde52c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -48,7 +48,7 @@ namespace Godot /// </value> public real_t this[int index] { - get + readonly get { switch (index) { @@ -79,7 +79,7 @@ namespace Godot /// <summary> /// Helper method for deconstruction into a tuple. /// </summary> - public void Deconstruct(out real_t x, out real_t y) + public readonly void Deconstruct(out real_t x, out real_t y) { x = this.x; y = this.y; @@ -105,7 +105,7 @@ namespace Godot /// Returns a new vector with all components in absolute values (i.e. positive). /// </summary> /// <returns>A vector with <see cref="Mathf.Abs(real_t)"/> called on each component.</returns> - public Vector2 Abs() + public readonly Vector2 Abs() { return new Vector2(Mathf.Abs(x), Mathf.Abs(y)); } @@ -117,7 +117,7 @@ namespace Godot /// called with the vector's <see cref="y"/> and <see cref="x"/> as parameters: <c>Mathf.Atan2(v.y, v.x)</c>. /// </summary> /// <returns>The angle of this vector, in radians.</returns> - public real_t Angle() + public readonly real_t Angle() { return Mathf.Atan2(y, x); } @@ -127,7 +127,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to compare this vector to.</param> /// <returns>The angle between the two vectors, in radians.</returns> - public real_t AngleTo(Vector2 to) + public readonly real_t AngleTo(Vector2 to) { return Mathf.Atan2(Cross(to), Dot(to)); } @@ -137,7 +137,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to compare this vector to.</param> /// <returns>The angle between the two vectors, in radians.</returns> - public real_t AngleToPoint(Vector2 to) + public readonly real_t AngleToPoint(Vector2 to) { return Mathf.Atan2(y - to.y, x - to.x); } @@ -146,7 +146,7 @@ namespace Godot /// Returns the aspect ratio of this vector, the ratio of <see cref="x"/> to <see cref="y"/>. /// </summary> /// <returns>The <see cref="x"/> component divided by the <see cref="y"/> component.</returns> - public real_t Aspect() + public readonly real_t Aspect() { return x / y; } @@ -156,7 +156,7 @@ namespace Godot /// </summary> /// <param name="normal">The normal vector defining the plane to bounce off. Must be normalized.</param> /// <returns>The bounced vector.</returns> - public Vector2 Bounce(Vector2 normal) + public readonly Vector2 Bounce(Vector2 normal) { return -Reflect(normal); } @@ -165,7 +165,7 @@ namespace Godot /// Returns a new vector with all components rounded up (towards positive infinity). /// </summary> /// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns> - public Vector2 Ceil() + public readonly Vector2 Ceil() { return new Vector2(Mathf.Ceil(x), Mathf.Ceil(y)); } @@ -178,7 +178,7 @@ namespace Godot /// <param name="min">The vector with minimum allowed values.</param> /// <param name="max">The vector with maximum allowed values.</param> /// <returns>The vector with all components clamped.</returns> - public Vector2 Clamp(Vector2 min, Vector2 max) + public readonly Vector2 Clamp(Vector2 min, Vector2 max) { return new Vector2 ( @@ -192,7 +192,7 @@ namespace Godot /// </summary> /// <param name="with">The other vector.</param> /// <returns>The cross product value.</returns> - public real_t Cross(Vector2 with) + public readonly real_t Cross(Vector2 with) { return (x * with.y) - (y * with.x); } @@ -206,7 +206,7 @@ namespace Godot /// <param name="postB">A vector after <paramref name="b"/>.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated vector.</returns> - public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t weight) + public readonly Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t weight) { return new Vector2 ( @@ -229,7 +229,7 @@ namespace Godot /// <param name="preAT"></param> /// <param name="postBT"></param> /// <returns>The interpolated vector.</returns> - public Vector2 CubicInterpolateInTime(Vector2 b, Vector2 preA, Vector2 postB, real_t weight, real_t t, real_t preAT, real_t postBT) + public readonly Vector2 CubicInterpolateInTime(Vector2 b, Vector2 preA, Vector2 postB, real_t weight, real_t t, real_t preAT, real_t postBT) { return new Vector2 ( @@ -247,16 +247,13 @@ namespace Godot /// <param name="end">The destination vector.</param> /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated vector.</returns> - public Vector2 BezierInterpolate(Vector2 control1, Vector2 control2, Vector2 end, real_t t) + public readonly Vector2 BezierInterpolate(Vector2 control1, Vector2 control2, Vector2 end, real_t t) { - // Formula from Wikipedia article on Bezier curves - real_t omt = 1 - t; - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = t * t; - real_t t3 = t2 * t; - - return this * omt3 + control1 * omt2 * t * 3 + control2 * omt * t2 * 3 + end * t3; + return new Vector2 + ( + Mathf.BezierInterpolate(x, control1.x, control2.x, end.x, t), + Mathf.BezierInterpolate(y, control1.y, control2.y, end.y, t) + ); } /// <summary> @@ -264,7 +261,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to point towards.</param> /// <returns>The direction from this vector to <paramref name="to"/>.</returns> - public Vector2 DirectionTo(Vector2 to) + public readonly Vector2 DirectionTo(Vector2 to) { return new Vector2(to.x - x, to.y - y).Normalized(); } @@ -276,7 +273,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to use.</param> /// <returns>The squared distance between the two vectors.</returns> - public real_t DistanceSquaredTo(Vector2 to) + public readonly real_t DistanceSquaredTo(Vector2 to) { return (x - to.x) * (x - to.x) + (y - to.y) * (y - to.y); } @@ -286,7 +283,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to use.</param> /// <returns>The distance between the two vectors.</returns> - public real_t DistanceTo(Vector2 to) + public readonly real_t DistanceTo(Vector2 to) { return Mathf.Sqrt((x - to.x) * (x - to.x) + (y - to.y) * (y - to.y)); } @@ -296,7 +293,7 @@ namespace Godot /// </summary> /// <param name="with">The other vector to use.</param> /// <returns>The dot product of the two vectors.</returns> - public real_t Dot(Vector2 with) + public readonly real_t Dot(Vector2 with) { return (x * with.x) + (y * with.y); } @@ -305,7 +302,7 @@ namespace Godot /// Returns a new vector with all components rounded down (towards negative infinity). /// </summary> /// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns> - public Vector2 Floor() + public readonly Vector2 Floor() { return new Vector2(Mathf.Floor(x), Mathf.Floor(y)); } @@ -314,7 +311,7 @@ namespace Godot /// Returns the inverse of this vector. This is the same as <c>new Vector2(1 / v.x, 1 / v.y)</c>. /// </summary> /// <returns>The inverse of this vector.</returns> - public Vector2 Inverse() + public readonly Vector2 Inverse() { return new Vector2(1 / x, 1 / y); } @@ -323,7 +320,7 @@ namespace Godot /// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise. /// </summary> /// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns> - public bool IsNormalized() + public readonly bool IsNormalized() { return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon; } @@ -333,7 +330,7 @@ namespace Godot /// </summary> /// <seealso cref="LengthSquared"/> /// <returns>The length of this vector.</returns> - public real_t Length() + public readonly real_t Length() { return Mathf.Sqrt((x * x) + (y * y)); } @@ -344,7 +341,7 @@ namespace Godot /// you need to compare vectors or need the squared length for some formula. /// </summary> /// <returns>The squared length of this vector.</returns> - public real_t LengthSquared() + public readonly real_t LengthSquared() { return (x * x) + (y * y); } @@ -356,7 +353,7 @@ namespace Godot /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting vector of the interpolation.</returns> - public Vector2 Lerp(Vector2 to, real_t weight) + public readonly Vector2 Lerp(Vector2 to, real_t weight) { return new Vector2 ( @@ -374,7 +371,7 @@ namespace Godot /// A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation. /// </param> /// <returns>The resulting vector of the interpolation.</returns> - public Vector2 Lerp(Vector2 to, Vector2 weight) + public readonly Vector2 Lerp(Vector2 to, Vector2 weight) { return new Vector2 ( @@ -388,7 +385,7 @@ namespace Godot /// </summary> /// <param name="length">The length to limit to.</param> /// <returns>The vector with its length limited.</returns> - public Vector2 LimitLength(real_t length = 1.0f) + public readonly Vector2 LimitLength(real_t length = 1.0f) { Vector2 v = this; real_t l = Length(); @@ -407,7 +404,7 @@ namespace Godot /// If both components are equal, this method returns <see cref="Axis.X"/>. /// </summary> /// <returns>The index of the highest axis.</returns> - public Axis MaxAxisIndex() + public readonly Axis MaxAxisIndex() { return x < y ? Axis.Y : Axis.X; } @@ -417,7 +414,7 @@ namespace Godot /// If both components are equal, this method returns <see cref="Axis.Y"/>. /// </summary> /// <returns>The index of the lowest axis.</returns> - public Axis MinAxisIndex() + public readonly Axis MinAxisIndex() { return x < y ? Axis.X : Axis.Y; } @@ -428,7 +425,7 @@ namespace Godot /// <param name="to">The vector to move towards.</param> /// <param name="delta">The amount to move towards by.</param> /// <returns>The resulting vector.</returns> - public Vector2 MoveToward(Vector2 to, real_t delta) + public readonly Vector2 MoveToward(Vector2 to, real_t delta) { Vector2 v = this; Vector2 vd = to - v; @@ -443,7 +440,7 @@ namespace Godot /// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>. /// </summary> /// <returns>A normalized version of the vector.</returns> - public Vector2 Normalized() + public readonly Vector2 Normalized() { Vector2 v = this; v.Normalize(); @@ -458,7 +455,7 @@ namespace Godot /// <returns> /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>. /// </returns> - public Vector2 PosMod(real_t mod) + public readonly Vector2 PosMod(real_t mod) { Vector2 v; v.x = Mathf.PosMod(x, mod); @@ -474,7 +471,7 @@ namespace Godot /// <returns> /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components. /// </returns> - public Vector2 PosMod(Vector2 modv) + public readonly Vector2 PosMod(Vector2 modv) { Vector2 v; v.x = Mathf.PosMod(x, modv.x); @@ -487,7 +484,7 @@ namespace Godot /// </summary> /// <param name="onNormal">The vector to project onto.</param> /// <returns>The projected vector.</returns> - public Vector2 Project(Vector2 onNormal) + public readonly Vector2 Project(Vector2 onNormal) { return onNormal * (Dot(onNormal) / onNormal.LengthSquared()); } @@ -497,7 +494,7 @@ namespace Godot /// </summary> /// <param name="normal">The normal vector defining the plane to reflect from. Must be normalized.</param> /// <returns>The reflected vector.</returns> - public Vector2 Reflect(Vector2 normal) + public readonly Vector2 Reflect(Vector2 normal) { #if DEBUG if (!normal.IsNormalized()) @@ -513,7 +510,7 @@ namespace Godot /// </summary> /// <param name="angle">The angle to rotate by, in radians.</param> /// <returns>The rotated vector.</returns> - public Vector2 Rotated(real_t angle) + public readonly Vector2 Rotated(real_t angle) { real_t sine = Mathf.Sin(angle); real_t cosi = Mathf.Cos(angle); @@ -527,7 +524,7 @@ namespace Godot /// with halfway cases rounded towards the nearest multiple of two. /// </summary> /// <returns>The rounded vector.</returns> - public Vector2 Round() + public readonly Vector2 Round() { return new Vector2(Mathf.Round(x), Mathf.Round(y)); } @@ -538,7 +535,7 @@ namespace Godot /// by calling <see cref="Mathf.Sign(real_t)"/> on each component. /// </summary> /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> - public Vector2 Sign() + public readonly Vector2 Sign() { Vector2 v; v.x = Mathf.Sign(x); @@ -557,7 +554,7 @@ namespace Godot /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting vector of the interpolation.</returns> - public Vector2 Slerp(Vector2 to, real_t weight) + public readonly Vector2 Slerp(Vector2 to, real_t weight) { real_t startLengthSquared = LengthSquared(); real_t endLengthSquared = to.LengthSquared(); @@ -577,7 +574,7 @@ namespace Godot /// </summary> /// <param name="normal">The normal vector defining the plane to slide on.</param> /// <returns>The slid vector.</returns> - public Vector2 Slide(Vector2 normal) + public readonly Vector2 Slide(Vector2 normal) { return this - (normal * Dot(normal)); } @@ -588,7 +585,7 @@ namespace Godot /// </summary> /// <param name="step">A vector value representing the step size to snap to.</param> /// <returns>The snapped vector.</returns> - public Vector2 Snapped(Vector2 step) + public readonly Vector2 Snapped(Vector2 step) { return new Vector2(Mathf.Snapped(x, step.x), Mathf.Snapped(y, step.y)); } @@ -598,7 +595,7 @@ namespace Godot /// compared to the original, with the same length. /// </summary> /// <returns>The perpendicular vector.</returns> - public Vector2 Orthogonal() + public readonly Vector2 Orthogonal() { return new Vector2(y, -x); } @@ -946,7 +943,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Vector2 other && Equals(other); } @@ -958,7 +955,7 @@ namespace Godot /// </summary> /// <param name="other">The other vector.</param> /// <returns>Whether or not the vectors are exactly equal.</returns> - public bool Equals(Vector2 other) + public readonly bool Equals(Vector2 other) { return x == other.x && y == other.y; } @@ -969,7 +966,7 @@ namespace Godot /// </summary> /// <param name="other">The other vector to compare.</param> /// <returns>Whether or not the vectors are approximately equal.</returns> - public bool IsEqualApprox(Vector2 other) + public readonly bool IsEqualApprox(Vector2 other) { return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y); } @@ -978,7 +975,7 @@ namespace Godot /// Serves as the hash function for <see cref="Vector2"/>. /// </summary> /// <returns>A hash code for this vector.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode(); } @@ -987,7 +984,7 @@ namespace Godot /// Converts this <see cref="Vector2"/> to a string. /// </summary> /// <returns>A string representation of this vector.</returns> - public override string ToString() + public override readonly string ToString() { return $"({x}, {y})"; } @@ -996,7 +993,7 @@ namespace Godot /// Converts this <see cref="Vector2"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"({x.ToString(format)}, {y.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs index bdadf696e3..08f2a3a8af 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs @@ -48,7 +48,7 @@ namespace Godot /// </value> public int this[int index] { - get + readonly get { switch (index) { @@ -79,7 +79,7 @@ namespace Godot /// <summary> /// Helper method for deconstruction into a tuple. /// </summary> - public void Deconstruct(out int x, out int y) + public readonly void Deconstruct(out int x, out int y) { x = this.x; y = this.y; @@ -89,7 +89,7 @@ namespace Godot /// Returns a new vector with all components in absolute values (i.e. positive). /// </summary> /// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns> - public Vector2i Abs() + public readonly Vector2i Abs() { return new Vector2i(Mathf.Abs(x), Mathf.Abs(y)); } @@ -101,7 +101,7 @@ namespace Godot /// called with the vector's <see cref="y"/> and <see cref="x"/> as parameters: <c>Mathf.Atan2(v.y, v.x)</c>. /// </summary> /// <returns>The angle of this vector, in radians.</returns> - public real_t Angle() + public readonly real_t Angle() { return Mathf.Atan2(y, x); } @@ -111,7 +111,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to compare this vector to.</param> /// <returns>The angle between the two vectors, in radians.</returns> - public real_t AngleTo(Vector2i to) + public readonly real_t AngleTo(Vector2i to) { return Mathf.Atan2(Cross(to), Dot(to)); } @@ -121,7 +121,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to compare this vector to.</param> /// <returns>The angle between the two vectors, in radians.</returns> - public real_t AngleToPoint(Vector2i to) + public readonly real_t AngleToPoint(Vector2i to) { return Mathf.Atan2(y - to.y, x - to.x); } @@ -130,7 +130,7 @@ namespace Godot /// Returns the aspect ratio of this vector, the ratio of <see cref="x"/> to <see cref="y"/>. /// </summary> /// <returns>The <see cref="x"/> component divided by the <see cref="y"/> component.</returns> - public real_t Aspect() + public readonly real_t Aspect() { return x / (real_t)y; } @@ -143,7 +143,7 @@ namespace Godot /// <param name="min">The vector with minimum allowed values.</param> /// <param name="max">The vector with maximum allowed values.</param> /// <returns>The vector with all components clamped.</returns> - public Vector2i Clamp(Vector2i min, Vector2i max) + public readonly Vector2i Clamp(Vector2i min, Vector2i max) { return new Vector2i ( @@ -157,7 +157,7 @@ namespace Godot /// </summary> /// <param name="with">The other vector.</param> /// <returns>The cross product vector.</returns> - public int Cross(Vector2i with) + public readonly int Cross(Vector2i with) { return x * with.y - y * with.x; } @@ -169,7 +169,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to use.</param> /// <returns>The squared distance between the two vectors.</returns> - public int DistanceSquaredTo(Vector2i to) + public readonly int DistanceSquaredTo(Vector2i to) { return (to - this).LengthSquared(); } @@ -179,7 +179,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to use.</param> /// <returns>The distance between the two vectors.</returns> - public real_t DistanceTo(Vector2i to) + public readonly real_t DistanceTo(Vector2i to) { return (to - this).Length(); } @@ -189,7 +189,7 @@ namespace Godot /// </summary> /// <param name="with">The other vector to use.</param> /// <returns>The dot product of the two vectors.</returns> - public int Dot(Vector2i with) + public readonly int Dot(Vector2i with) { return x * with.x + y * with.y; } @@ -199,7 +199,7 @@ namespace Godot /// </summary> /// <seealso cref="LengthSquared"/> /// <returns>The length of this vector.</returns> - public real_t Length() + public readonly real_t Length() { int x2 = x * x; int y2 = y * y; @@ -213,7 +213,7 @@ namespace Godot /// you need to compare vectors or need the squared length for some formula. /// </summary> /// <returns>The squared length of this vector.</returns> - public int LengthSquared() + public readonly int LengthSquared() { int x2 = x * x; int y2 = y * y; @@ -226,7 +226,7 @@ namespace Godot /// If both components are equal, this method returns <see cref="Axis.X"/>. /// </summary> /// <returns>The index of the highest axis.</returns> - public Axis MaxAxisIndex() + public readonly Axis MaxAxisIndex() { return x < y ? Axis.Y : Axis.X; } @@ -236,7 +236,7 @@ namespace Godot /// If both components are equal, this method returns <see cref="Axis.Y"/>. /// </summary> /// <returns>The index of the lowest axis.</returns> - public Axis MinAxisIndex() + public readonly Axis MinAxisIndex() { return x < y ? Axis.X : Axis.Y; } @@ -249,7 +249,7 @@ namespace Godot /// <returns> /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>. /// </returns> - public Vector2i PosMod(int mod) + public readonly Vector2i PosMod(int mod) { Vector2i v = this; v.x = Mathf.PosMod(v.x, mod); @@ -265,7 +265,7 @@ namespace Godot /// <returns> /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components. /// </returns> - public Vector2i PosMod(Vector2i modv) + public readonly Vector2i PosMod(Vector2i modv) { Vector2i v = this; v.x = Mathf.PosMod(v.x, modv.x); @@ -279,7 +279,7 @@ namespace Godot /// by calling <see cref="Mathf.Sign(int)"/> on each component. /// </summary> /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> - public Vector2i Sign() + public readonly Vector2i Sign() { Vector2i v = this; v.x = Mathf.Sign(v.x); @@ -292,7 +292,7 @@ namespace Godot /// compared to the original, with the same length. /// </summary> /// <returns>The perpendicular vector.</returns> - public Vector2i Orthogonal() + public readonly Vector2i Orthogonal() { return new Vector2i(y, -x); } @@ -665,7 +665,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Vector2i other && Equals(other); } @@ -675,7 +675,7 @@ namespace Godot /// </summary> /// <param name="other">The other vector.</param> /// <returns>Whether or not the vectors are equal.</returns> - public bool Equals(Vector2i other) + public readonly bool Equals(Vector2i other) { return x == other.x && y == other.y; } @@ -684,7 +684,7 @@ namespace Godot /// Serves as the hash function for <see cref="Vector2i"/>. /// </summary> /// <returns>A hash code for this vector.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode(); } @@ -693,7 +693,7 @@ namespace Godot /// Converts this <see cref="Vector2i"/> to a string. /// </summary> /// <returns>A string representation of this vector.</returns> - public override string ToString() + public override readonly string ToString() { return $"({x}, {y})"; } @@ -702,7 +702,7 @@ namespace Godot /// Converts this <see cref="Vector2i"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"({x.ToString(format)}, {y.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 6649f3b784..5fef474eed 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -58,7 +58,7 @@ namespace Godot /// </value> public real_t this[int index] { - get + readonly get { switch (index) { @@ -94,7 +94,7 @@ namespace Godot /// <summary> /// Helper method for deconstruction into a tuple. /// </summary> - public void Deconstruct(out real_t x, out real_t y, out real_t z) + public readonly void Deconstruct(out real_t x, out real_t y, out real_t z) { x = this.x; y = this.y; @@ -122,7 +122,7 @@ namespace Godot /// Returns a new vector with all components in absolute values (i.e. positive). /// </summary> /// <returns>A vector with <see cref="Mathf.Abs(real_t)"/> called on each component.</returns> - public Vector3 Abs() + public readonly Vector3 Abs() { return new Vector3(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z)); } @@ -132,7 +132,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to compare this vector to.</param> /// <returns>The unsigned angle between the two vectors, in radians.</returns> - public real_t AngleTo(Vector3 to) + public readonly real_t AngleTo(Vector3 to) { return Mathf.Atan2(Cross(to).Length(), Dot(to)); } @@ -142,7 +142,7 @@ namespace Godot /// </summary> /// <param name="normal">The normal vector defining the plane to bounce off. Must be normalized.</param> /// <returns>The bounced vector.</returns> - public Vector3 Bounce(Vector3 normal) + public readonly Vector3 Bounce(Vector3 normal) { return -Reflect(normal); } @@ -151,7 +151,7 @@ namespace Godot /// Returns a new vector with all components rounded up (towards positive infinity). /// </summary> /// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns> - public Vector3 Ceil() + public readonly Vector3 Ceil() { return new Vector3(Mathf.Ceil(x), Mathf.Ceil(y), Mathf.Ceil(z)); } @@ -164,7 +164,7 @@ namespace Godot /// <param name="min">The vector with minimum allowed values.</param> /// <param name="max">The vector with maximum allowed values.</param> /// <returns>The vector with all components clamped.</returns> - public Vector3 Clamp(Vector3 min, Vector3 max) + public readonly Vector3 Clamp(Vector3 min, Vector3 max) { return new Vector3 ( @@ -179,7 +179,7 @@ namespace Godot /// </summary> /// <param name="with">The other vector.</param> /// <returns>The cross product vector.</returns> - public Vector3 Cross(Vector3 with) + public readonly Vector3 Cross(Vector3 with) { return new Vector3 ( @@ -198,7 +198,7 @@ namespace Godot /// <param name="postB">A vector after <paramref name="b"/>.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated vector.</returns> - public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight) + public readonly Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight) { return new Vector3 ( @@ -222,7 +222,7 @@ namespace Godot /// <param name="preAT"></param> /// <param name="postBT"></param> /// <returns>The interpolated vector.</returns> - public Vector3 CubicInterpolateInTime(Vector3 b, Vector3 preA, Vector3 postB, real_t weight, real_t t, real_t preAT, real_t postBT) + public readonly Vector3 CubicInterpolateInTime(Vector3 b, Vector3 preA, Vector3 postB, real_t weight, real_t t, real_t preAT, real_t postBT) { return new Vector3 ( @@ -241,16 +241,14 @@ namespace Godot /// <param name="end">The destination vector.</param> /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated vector.</returns> - public Vector3 BezierInterpolate(Vector3 control1, Vector3 control2, Vector3 end, real_t t) + public readonly Vector3 BezierInterpolate(Vector3 control1, Vector3 control2, Vector3 end, real_t t) { - // Formula from Wikipedia article on Bezier curves - real_t omt = 1 - t; - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = t * t; - real_t t3 = t2 * t; - - return this * omt3 + control1 * omt2 * t * 3 + control2 * omt * t2 * 3 + end * t3; + return new Vector3 + ( + Mathf.BezierInterpolate(x, control1.x, control2.x, end.x, t), + Mathf.BezierInterpolate(y, control1.y, control2.y, end.y, t), + Mathf.BezierInterpolate(z, control1.z, control2.z, end.z, t) + ); } /// <summary> @@ -258,7 +256,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to point towards.</param> /// <returns>The direction from this vector to <paramref name="to"/>.</returns> - public Vector3 DirectionTo(Vector3 to) + public readonly Vector3 DirectionTo(Vector3 to) { return new Vector3(to.x - x, to.y - y, to.z - z).Normalized(); } @@ -270,7 +268,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to use.</param> /// <returns>The squared distance between the two vectors.</returns> - public real_t DistanceSquaredTo(Vector3 to) + public readonly real_t DistanceSquaredTo(Vector3 to) { return (to - this).LengthSquared(); } @@ -281,7 +279,7 @@ namespace Godot /// <seealso cref="DistanceSquaredTo(Vector3)"/> /// <param name="to">The other vector to use.</param> /// <returns>The distance between the two vectors.</returns> - public real_t DistanceTo(Vector3 to) + public readonly real_t DistanceTo(Vector3 to) { return (to - this).Length(); } @@ -291,7 +289,7 @@ namespace Godot /// </summary> /// <param name="with">The other vector to use.</param> /// <returns>The dot product of the two vectors.</returns> - public real_t Dot(Vector3 with) + public readonly real_t Dot(Vector3 with) { return (x * with.x) + (y * with.y) + (z * with.z); } @@ -300,7 +298,7 @@ namespace Godot /// Returns a new vector with all components rounded down (towards negative infinity). /// </summary> /// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns> - public Vector3 Floor() + public readonly Vector3 Floor() { return new Vector3(Mathf.Floor(x), Mathf.Floor(y), Mathf.Floor(z)); } @@ -309,7 +307,7 @@ namespace Godot /// Returns the inverse of this vector. This is the same as <c>new Vector3(1 / v.x, 1 / v.y, 1 / v.z)</c>. /// </summary> /// <returns>The inverse of this vector.</returns> - public Vector3 Inverse() + public readonly Vector3 Inverse() { return new Vector3(1 / x, 1 / y, 1 / z); } @@ -318,7 +316,7 @@ namespace Godot /// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise. /// </summary> /// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns> - public bool IsNormalized() + public readonly bool IsNormalized() { return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon; } @@ -328,7 +326,7 @@ namespace Godot /// </summary> /// <seealso cref="LengthSquared"/> /// <returns>The length of this vector.</returns> - public real_t Length() + public readonly real_t Length() { real_t x2 = x * x; real_t y2 = y * y; @@ -343,7 +341,7 @@ namespace Godot /// you need to compare vectors or need the squared length for some formula. /// </summary> /// <returns>The squared length of this vector.</returns> - public real_t LengthSquared() + public readonly real_t LengthSquared() { real_t x2 = x * x; real_t y2 = y * y; @@ -359,7 +357,7 @@ namespace Godot /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting vector of the interpolation.</returns> - public Vector3 Lerp(Vector3 to, real_t weight) + public readonly Vector3 Lerp(Vector3 to, real_t weight) { return new Vector3 ( @@ -376,7 +374,7 @@ namespace Godot /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting vector of the interpolation.</returns> - public Vector3 Lerp(Vector3 to, Vector3 weight) + public readonly Vector3 Lerp(Vector3 to, Vector3 weight) { return new Vector3 ( @@ -391,7 +389,7 @@ namespace Godot /// </summary> /// <param name="length">The length to limit to.</param> /// <returns>The vector with its length limited.</returns> - public Vector3 LimitLength(real_t length = 1.0f) + public readonly Vector3 LimitLength(real_t length = 1.0f) { Vector3 v = this; real_t l = Length(); @@ -410,7 +408,7 @@ namespace Godot /// If all components are equal, this method returns <see cref="Axis.X"/>. /// </summary> /// <returns>The index of the highest axis.</returns> - public Axis MaxAxisIndex() + public readonly Axis MaxAxisIndex() { return x < y ? (y < z ? Axis.Z : Axis.Y) : (x < z ? Axis.Z : Axis.X); } @@ -420,7 +418,7 @@ namespace Godot /// If all components are equal, this method returns <see cref="Axis.Z"/>. /// </summary> /// <returns>The index of the lowest axis.</returns> - public Axis MinAxisIndex() + public readonly Axis MinAxisIndex() { return x < y ? (x < z ? Axis.X : Axis.Z) : (y < z ? Axis.Y : Axis.Z); } @@ -431,7 +429,7 @@ namespace Godot /// <param name="to">The vector to move towards.</param> /// <param name="delta">The amount to move towards by.</param> /// <returns>The resulting vector.</returns> - public Vector3 MoveToward(Vector3 to, real_t delta) + public readonly Vector3 MoveToward(Vector3 to, real_t delta) { Vector3 v = this; Vector3 vd = to - v; @@ -446,7 +444,7 @@ namespace Godot /// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>. /// </summary> /// <returns>A normalized version of the vector.</returns> - public Vector3 Normalized() + public readonly Vector3 Normalized() { Vector3 v = this; v.Normalize(); @@ -458,7 +456,7 @@ namespace Godot /// </summary> /// <param name="with">The other vector.</param> /// <returns>A <see cref="Basis"/> representing the outer product matrix.</returns> - public Basis Outer(Vector3 with) + public readonly Basis Outer(Vector3 with) { return new Basis( x * with.x, x * with.y, x * with.z, @@ -475,7 +473,7 @@ namespace Godot /// <returns> /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>. /// </returns> - public Vector3 PosMod(real_t mod) + public readonly Vector3 PosMod(real_t mod) { Vector3 v; v.x = Mathf.PosMod(x, mod); @@ -492,7 +490,7 @@ namespace Godot /// <returns> /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components. /// </returns> - public Vector3 PosMod(Vector3 modv) + public readonly Vector3 PosMod(Vector3 modv) { Vector3 v; v.x = Mathf.PosMod(x, modv.x); @@ -506,7 +504,7 @@ namespace Godot /// </summary> /// <param name="onNormal">The vector to project onto.</param> /// <returns>The projected vector.</returns> - public Vector3 Project(Vector3 onNormal) + public readonly Vector3 Project(Vector3 onNormal) { return onNormal * (Dot(onNormal) / onNormal.LengthSquared()); } @@ -516,7 +514,7 @@ namespace Godot /// </summary> /// <param name="normal">The normal vector defining the plane to reflect from. Must be normalized.</param> /// <returns>The reflected vector.</returns> - public Vector3 Reflect(Vector3 normal) + public readonly Vector3 Reflect(Vector3 normal) { #if DEBUG if (!normal.IsNormalized()) @@ -534,7 +532,7 @@ namespace Godot /// <param name="axis">The vector to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate by, in radians.</param> /// <returns>The rotated vector.</returns> - public Vector3 Rotated(Vector3 axis, real_t angle) + public readonly Vector3 Rotated(Vector3 axis, real_t angle) { #if DEBUG if (!axis.IsNormalized()) @@ -550,7 +548,7 @@ namespace Godot /// with halfway cases rounded towards the nearest multiple of two. /// </summary> /// <returns>The rounded vector.</returns> - public Vector3 Round() + public readonly Vector3 Round() { return new Vector3(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z)); } @@ -561,7 +559,7 @@ namespace Godot /// by calling <see cref="Mathf.Sign(real_t)"/> on each component. /// </summary> /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> - public Vector3 Sign() + public readonly Vector3 Sign() { Vector3 v; v.x = Mathf.Sign(x); @@ -579,7 +577,7 @@ namespace Godot /// <param name="to">The other vector to compare this vector to.</param> /// <param name="axis">The reference axis to use for the angle sign.</param> /// <returns>The signed angle between the two vectors, in radians.</returns> - public real_t SignedAngleTo(Vector3 to, Vector3 axis) + public readonly real_t SignedAngleTo(Vector3 to, Vector3 axis) { Vector3 crossTo = Cross(to); real_t unsignedAngle = Mathf.Atan2(crossTo.Length(), Dot(to)); @@ -598,7 +596,7 @@ namespace Godot /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting vector of the interpolation.</returns> - public Vector3 Slerp(Vector3 to, real_t weight) + public readonly Vector3 Slerp(Vector3 to, real_t weight) { real_t startLengthSquared = LengthSquared(); real_t endLengthSquared = to.LengthSquared(); @@ -618,7 +616,7 @@ namespace Godot /// </summary> /// <param name="normal">The normal vector defining the plane to slide on.</param> /// <returns>The slid vector.</returns> - public Vector3 Slide(Vector3 normal) + public readonly Vector3 Slide(Vector3 normal) { return this - (normal * Dot(normal)); } @@ -629,7 +627,7 @@ namespace Godot /// </summary> /// <param name="step">A vector value representing the step size to snap to.</param> /// <returns>The snapped vector.</returns> - public Vector3 Snapped(Vector3 step) + public readonly Vector3 Snapped(Vector3 step) { return new Vector3 ( @@ -1015,7 +1013,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Vector3 other && Equals(other); } @@ -1027,7 +1025,7 @@ namespace Godot /// </summary> /// <param name="other">The other vector.</param> /// <returns>Whether or not the vectors are exactly equal.</returns> - public bool Equals(Vector3 other) + public readonly bool Equals(Vector3 other) { return x == other.x && y == other.y && z == other.z; } @@ -1038,7 +1036,7 @@ namespace Godot /// </summary> /// <param name="other">The other vector to compare.</param> /// <returns>Whether or not the vectors are approximately equal.</returns> - public bool IsEqualApprox(Vector3 other) + public readonly bool IsEqualApprox(Vector3 other) { return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z); } @@ -1047,7 +1045,7 @@ namespace Godot /// Serves as the hash function for <see cref="Vector3"/>. /// </summary> /// <returns>A hash code for this vector.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode(); } @@ -1056,7 +1054,7 @@ namespace Godot /// Converts this <see cref="Vector3"/> to a string. /// </summary> /// <returns>A string representation of this vector.</returns> - public override string ToString() + public override readonly string ToString() { return $"({x}, {y}, {z})"; } @@ -1065,7 +1063,7 @@ namespace Godot /// Converts this <see cref="Vector3"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs index e88a043cb3..e631a9f443 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs @@ -58,7 +58,7 @@ namespace Godot /// </value> public int this[int index] { - get + readonly get { switch (index) { @@ -94,7 +94,7 @@ namespace Godot /// <summary> /// Helper method for deconstruction into a tuple. /// </summary> - public void Deconstruct(out int x, out int y, out int z) + public readonly void Deconstruct(out int x, out int y, out int z) { x = this.x; y = this.y; @@ -105,7 +105,7 @@ namespace Godot /// Returns a new vector with all components in absolute values (i.e. positive). /// </summary> /// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns> - public Vector3i Abs() + public readonly Vector3i Abs() { return new Vector3i(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z)); } @@ -118,7 +118,7 @@ namespace Godot /// <param name="min">The vector with minimum allowed values.</param> /// <param name="max">The vector with maximum allowed values.</param> /// <returns>The vector with all components clamped.</returns> - public Vector3i Clamp(Vector3i min, Vector3i max) + public readonly Vector3i Clamp(Vector3i min, Vector3i max) { return new Vector3i ( @@ -135,7 +135,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to use.</param> /// <returns>The squared distance between the two vectors.</returns> - public int DistanceSquaredTo(Vector3i to) + public readonly int DistanceSquaredTo(Vector3i to) { return (to - this).LengthSquared(); } @@ -146,7 +146,7 @@ namespace Godot /// <seealso cref="DistanceSquaredTo(Vector3i)"/> /// <param name="to">The other vector to use.</param> /// <returns>The distance between the two vectors.</returns> - public real_t DistanceTo(Vector3i to) + public readonly real_t DistanceTo(Vector3i to) { return (to - this).Length(); } @@ -156,7 +156,7 @@ namespace Godot /// </summary> /// <param name="with">The other vector to use.</param> /// <returns>The dot product of the two vectors.</returns> - public int Dot(Vector3i with) + public readonly int Dot(Vector3i with) { return x * with.x + y * with.y + z * with.z; } @@ -166,7 +166,7 @@ namespace Godot /// </summary> /// <seealso cref="LengthSquared"/> /// <returns>The length of this vector.</returns> - public real_t Length() + public readonly real_t Length() { int x2 = x * x; int y2 = y * y; @@ -181,7 +181,7 @@ namespace Godot /// you need to compare vectors or need the squared length for some formula. /// </summary> /// <returns>The squared length of this vector.</returns> - public int LengthSquared() + public readonly int LengthSquared() { int x2 = x * x; int y2 = y * y; @@ -195,7 +195,7 @@ namespace Godot /// If all components are equal, this method returns <see cref="Axis.X"/>. /// </summary> /// <returns>The index of the highest axis.</returns> - public Axis MaxAxisIndex() + public readonly Axis MaxAxisIndex() { return x < y ? (y < z ? Axis.Z : Axis.Y) : (x < z ? Axis.Z : Axis.X); } @@ -205,7 +205,7 @@ namespace Godot /// If all components are equal, this method returns <see cref="Axis.Z"/>. /// </summary> /// <returns>The index of the lowest axis.</returns> - public Axis MinAxisIndex() + public readonly Axis MinAxisIndex() { return x < y ? (x < z ? Axis.X : Axis.Z) : (y < z ? Axis.Y : Axis.Z); } @@ -218,7 +218,7 @@ namespace Godot /// <returns> /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>. /// </returns> - public Vector3i PosMod(int mod) + public readonly Vector3i PosMod(int mod) { Vector3i v = this; v.x = Mathf.PosMod(v.x, mod); @@ -235,7 +235,7 @@ namespace Godot /// <returns> /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components. /// </returns> - public Vector3i PosMod(Vector3i modv) + public readonly Vector3i PosMod(Vector3i modv) { Vector3i v = this; v.x = Mathf.PosMod(v.x, modv.x); @@ -250,7 +250,7 @@ namespace Godot /// by calling <see cref="Mathf.Sign(int)"/> on each component. /// </summary> /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> - public Vector3i Sign() + public readonly Vector3i Sign() { Vector3i v = this; v.x = Mathf.Sign(v.x); @@ -674,7 +674,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Vector3i other && Equals(other); } @@ -684,7 +684,7 @@ namespace Godot /// </summary> /// <param name="other">The other vector.</param> /// <returns>Whether or not the vectors are equal.</returns> - public bool Equals(Vector3i other) + public readonly bool Equals(Vector3i other) { return x == other.x && y == other.y && z == other.z; } @@ -693,7 +693,7 @@ namespace Godot /// Serves as the hash function for <see cref="Vector3i"/>. /// </summary> /// <returns>A hash code for this vector.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode(); } @@ -702,7 +702,7 @@ namespace Godot /// Converts this <see cref="Vector3i"/> to a string. /// </summary> /// <returns>A string representation of this vector.</returns> - public override string ToString() + public override readonly string ToString() { return $"({x}, {y}, {z})"; } @@ -711,7 +711,7 @@ namespace Godot /// Converts this <see cref="Vector3i"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs index e2da41ff47..3191e8adc0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs @@ -68,7 +68,7 @@ namespace Godot /// </value> public real_t this[int index] { - get + readonly get { switch (index) { @@ -109,7 +109,7 @@ namespace Godot /// <summary> /// Helper method for deconstruction into a tuple. /// </summary> - public void Deconstruct(out real_t x, out real_t y, out real_t z, out real_t w) + public readonly void Deconstruct(out real_t x, out real_t y, out real_t z, out real_t w) { x = this.x; y = this.y; @@ -139,7 +139,7 @@ namespace Godot /// Returns a new vector with all components in absolute values (i.e. positive). /// </summary> /// <returns>A vector with <see cref="Mathf.Abs(real_t)"/> called on each component.</returns> - public Vector4 Abs() + public readonly Vector4 Abs() { return new Vector4(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z), Mathf.Abs(w)); } @@ -148,7 +148,7 @@ namespace Godot /// Returns a new vector with all components rounded up (towards positive infinity). /// </summary> /// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns> - public Vector4 Ceil() + public readonly Vector4 Ceil() { return new Vector4(Mathf.Ceil(x), Mathf.Ceil(y), Mathf.Ceil(z), Mathf.Ceil(w)); } @@ -161,7 +161,7 @@ namespace Godot /// <param name="min">The vector with minimum allowed values.</param> /// <param name="max">The vector with maximum allowed values.</param> /// <returns>The vector with all components clamped.</returns> - public Vector4 Clamp(Vector4 min, Vector4 max) + public readonly Vector4 Clamp(Vector4 min, Vector4 max) { return new Vector4 ( @@ -181,7 +181,7 @@ namespace Godot /// <param name="postB">A vector after <paramref name="b"/>.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated vector.</returns> - public Vector4 CubicInterpolate(Vector4 b, Vector4 preA, Vector4 postB, real_t weight) + public readonly Vector4 CubicInterpolate(Vector4 b, Vector4 preA, Vector4 postB, real_t weight) { return new Vector4 ( @@ -206,7 +206,7 @@ namespace Godot /// <param name="preAT"></param> /// <param name="postBT"></param> /// <returns>The interpolated vector.</returns> - public Vector4 CubicInterpolateInTime(Vector4 b, Vector4 preA, Vector4 postB, real_t weight, real_t t, real_t preAT, real_t postBT) + public readonly Vector4 CubicInterpolateInTime(Vector4 b, Vector4 preA, Vector4 postB, real_t weight, real_t t, real_t preAT, real_t postBT) { return new Vector4 ( @@ -222,7 +222,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to point towards.</param> /// <returns>The direction from this vector to <paramref name="to"/>.</returns> - public Vector4 DirectionTo(Vector4 to) + public readonly Vector4 DirectionTo(Vector4 to) { Vector4 ret = new Vector4(to.x - x, to.y - y, to.z - z, to.w - w); ret.Normalize(); @@ -236,7 +236,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to use.</param> /// <returns>The squared distance between the two vectors.</returns> - public real_t DistanceSquaredTo(Vector4 to) + public readonly real_t DistanceSquaredTo(Vector4 to) { return (to - this).LengthSquared(); } @@ -246,7 +246,7 @@ namespace Godot /// </summary> /// <param name="to">The other vector to use.</param> /// <returns>The distance between the two vectors.</returns> - public real_t DistanceTo(Vector4 to) + public readonly real_t DistanceTo(Vector4 to) { return (to - this).Length(); } @@ -256,7 +256,7 @@ namespace Godot /// </summary> /// <param name="with">The other vector to use.</param> /// <returns>The dot product of the two vectors.</returns> - public real_t Dot(Vector4 with) + public readonly real_t Dot(Vector4 with) { return (x * with.x) + (y * with.y) + (z * with.z) + (w * with.w); } @@ -265,7 +265,7 @@ namespace Godot /// Returns a new vector with all components rounded down (towards negative infinity). /// </summary> /// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns> - public Vector4 Floor() + public readonly Vector4 Floor() { return new Vector4(Mathf.Floor(x), Mathf.Floor(y), Mathf.Floor(z), Mathf.Floor(w)); } @@ -274,7 +274,7 @@ namespace Godot /// Returns the inverse of this vector. This is the same as <c>new Vector4(1 / v.x, 1 / v.y, 1 / v.z, 1 / v.w)</c>. /// </summary> /// <returns>The inverse of this vector.</returns> - public Vector4 Inverse() + public readonly Vector4 Inverse() { return new Vector4(1 / x, 1 / y, 1 / z, 1 / w); } @@ -283,7 +283,7 @@ namespace Godot /// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise. /// </summary> /// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns> - public bool IsNormalized() + public readonly bool IsNormalized() { return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon; } @@ -293,7 +293,7 @@ namespace Godot /// </summary> /// <seealso cref="LengthSquared"/> /// <returns>The length of this vector.</returns> - public real_t Length() + public readonly real_t Length() { real_t x2 = x * x; real_t y2 = y * y; @@ -309,7 +309,7 @@ namespace Godot /// you need to compare vectors or need the squared length for some formula. /// </summary> /// <returns>The squared length of this vector.</returns> - public real_t LengthSquared() + public readonly real_t LengthSquared() { real_t x2 = x * x; real_t y2 = y * y; @@ -326,7 +326,7 @@ namespace Godot /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting vector of the interpolation.</returns> - public Vector4 Lerp(Vector4 to, real_t weight) + public readonly Vector4 Lerp(Vector4 to, real_t weight) { return new Vector4 ( @@ -342,7 +342,7 @@ namespace Godot /// If all components are equal, this method returns <see cref="Axis.X"/>. /// </summary> /// <returns>The index of the highest axis.</returns> - public Axis MaxAxisIndex() + public readonly Axis MaxAxisIndex() { int max_index = 0; real_t max_value = x; @@ -362,7 +362,7 @@ namespace Godot /// If all components are equal, this method returns <see cref="Axis.W"/>. /// </summary> /// <returns>The index of the lowest axis.</returns> - public Axis MinAxisIndex() + public readonly Axis MinAxisIndex() { int min_index = 0; real_t min_value = x; @@ -381,7 +381,7 @@ namespace Godot /// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>. /// </summary> /// <returns>A normalized version of the vector.</returns> - public Vector4 Normalized() + public readonly Vector4 Normalized() { Vector4 v = this; v.Normalize(); @@ -396,7 +396,7 @@ namespace Godot /// <returns> /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>. /// </returns> - public Vector4 PosMod(real_t mod) + public readonly Vector4 PosMod(real_t mod) { return new Vector4( Mathf.PosMod(x, mod), @@ -414,7 +414,7 @@ namespace Godot /// <returns> /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components. /// </returns> - public Vector4 PosMod(Vector4 modv) + public readonly Vector4 PosMod(Vector4 modv) { return new Vector4( Mathf.PosMod(x, modv.x), @@ -429,7 +429,7 @@ namespace Godot /// with halfway cases rounded towards the nearest multiple of two. /// </summary> /// <returns>The rounded vector.</returns> - public Vector4 Round() + public readonly Vector4 Round() { return new Vector4(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z), Mathf.Round(w)); } @@ -440,7 +440,7 @@ namespace Godot /// by calling <see cref="Mathf.Sign(real_t)"/> on each component. /// </summary> /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> - public Vector4 Sign() + public readonly Vector4 Sign() { Vector4 v; v.x = Mathf.Sign(x); @@ -456,7 +456,7 @@ namespace Godot /// </summary> /// <param name="step">A vector value representing the step size to snap to.</param> /// <returns>The snapped vector.</returns> - public Vector4 Snapped(Vector4 step) + public readonly Vector4 Snapped(Vector4 step) { return new Vector4( Mathf.Snapped(x, step.x), @@ -828,7 +828,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Vector4 other && Equals(other); } @@ -840,7 +840,7 @@ namespace Godot /// </summary> /// <param name="other">The other vector.</param> /// <returns>Whether or not the vectors are exactly equal.</returns> - public bool Equals(Vector4 other) + public readonly bool Equals(Vector4 other) { return x == other.x && y == other.y && z == other.z && w == other.w; } @@ -851,7 +851,7 @@ namespace Godot /// </summary> /// <param name="other">The other vector to compare.</param> /// <returns>Whether or not the vectors are approximately equal.</returns> - public bool IsEqualApprox(Vector4 other) + public readonly bool IsEqualApprox(Vector4 other) { return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w); } @@ -860,7 +860,7 @@ namespace Godot /// Serves as the hash function for <see cref="Vector4"/>. /// </summary> /// <returns>A hash code for this vector.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); } @@ -878,7 +878,7 @@ namespace Godot /// Converts this <see cref="Vector4"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)}, {w.ToString(format)})"; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs index 4b1bb3ba19..8146991fd7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs @@ -68,7 +68,7 @@ namespace Godot /// </value> public int this[int index] { - get + readonly get { switch (index) { @@ -109,7 +109,7 @@ namespace Godot /// <summary> /// Helper method for deconstruction into a tuple. /// </summary> - public void Deconstruct(out int x, out int y, out int z, out int w) + public readonly void Deconstruct(out int x, out int y, out int z, out int w) { x = this.x; y = this.y; @@ -121,7 +121,7 @@ namespace Godot /// Returns a new vector with all components in absolute values (i.e. positive). /// </summary> /// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns> - public Vector4i Abs() + public readonly Vector4i Abs() { return new Vector4i(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z), Mathf.Abs(w)); } @@ -134,7 +134,7 @@ namespace Godot /// <param name="min">The vector with minimum allowed values.</param> /// <param name="max">The vector with maximum allowed values.</param> /// <returns>The vector with all components clamped.</returns> - public Vector4i Clamp(Vector4i min, Vector4i max) + public readonly Vector4i Clamp(Vector4i min, Vector4i max) { return new Vector4i ( @@ -150,7 +150,7 @@ namespace Godot /// </summary> /// <seealso cref="LengthSquared"/> /// <returns>The length of this vector.</returns> - public real_t Length() + public readonly real_t Length() { int x2 = x * x; int y2 = y * y; @@ -166,7 +166,7 @@ namespace Godot /// you need to compare vectors or need the squared length for some formula. /// </summary> /// <returns>The squared length of this vector.</returns> - public int LengthSquared() + public readonly int LengthSquared() { int x2 = x * x; int y2 = y * y; @@ -181,7 +181,7 @@ namespace Godot /// If all components are equal, this method returns <see cref="Axis.X"/>. /// </summary> /// <returns>The index of the highest axis.</returns> - public Axis MaxAxisIndex() + public readonly Axis MaxAxisIndex() { int max_index = 0; int max_value = x; @@ -201,7 +201,7 @@ namespace Godot /// If all components are equal, this method returns <see cref="Axis.W"/>. /// </summary> /// <returns>The index of the lowest axis.</returns> - public Axis MinAxisIndex() + public readonly Axis MinAxisIndex() { int min_index = 0; int min_value = x; @@ -222,7 +222,7 @@ namespace Godot /// by calling <see cref="Mathf.Sign(int)"/> on each component. /// </summary> /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> - public Vector4i Sign() + public readonly Vector4i Sign() { return new Vector4i(Mathf.Sign(x), Mathf.Sign(y), Mathf.Sign(z), Mathf.Sign(w)); } @@ -627,7 +627,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the vector and the object are equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is Vector4i other && Equals(other); } @@ -637,7 +637,7 @@ namespace Godot /// </summary> /// <param name="other">The other vector.</param> /// <returns>Whether or not the vectors are equal.</returns> - public bool Equals(Vector4i other) + public readonly bool Equals(Vector4i other) { return x == other.x && y == other.y && z == other.z && w == other.w; } @@ -646,7 +646,7 @@ namespace Godot /// Serves as the hash function for <see cref="Vector4i"/>. /// </summary> /// <returns>A hash code for this vector.</returns> - public override int GetHashCode() + public override readonly int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); } @@ -655,7 +655,7 @@ namespace Godot /// Converts this <see cref="Vector4i"/> to a string. /// </summary> /// <returns>A string representation of this vector.</returns> - public override string ToString() + public override readonly string ToString() { return $"({x}, {y}, {z}, {w})"; } @@ -664,7 +664,7 @@ namespace Godot /// Converts this <see cref="Vector4i"/> to a string with the given <paramref name="format"/>. /// </summary> /// <returns>A string representation of this vector.</returns> - public string ToString(string format) + public readonly string ToString(string format) { return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)}), {w.ToString(format)})"; } diff --git a/modules/multiplayer/editor/editor_network_profiler.cpp b/modules/multiplayer/editor/editor_network_profiler.cpp index a7e5b80b66..cce22b9084 100644 --- a/modules/multiplayer/editor/editor_network_profiler.cpp +++ b/modules/multiplayer/editor/editor_network_profiler.cpp @@ -36,13 +36,19 @@ void EditorNetworkProfiler::_bind_methods() { ADD_SIGNAL(MethodInfo("enable_profiling", PropertyInfo(Variant::BOOL, "enable"))); + ADD_SIGNAL(MethodInfo("open_request", PropertyInfo(Variant::STRING, "path"))); } void EditorNetworkProfiler::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - activate->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons"))); + node_icon = get_theme_icon(SNAME("Node"), SNAME("EditorIcons")); + if (activate->is_pressed()) { + activate->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"))); + } else { + activate->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons"))); + } clear_button->set_icon(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons"))); incoming_bandwidth_text->set_right_icon(get_theme_icon(SNAME("ArrowDown"), SNAME("EditorIcons"))); outgoing_bandwidth_text->set_right_icon(get_theme_icon(SNAME("ArrowUp"), SNAME("EditorIcons"))); @@ -54,29 +60,104 @@ void EditorNetworkProfiler::_notification(int p_what) { } } -void EditorNetworkProfiler::_update_frame() { +void EditorNetworkProfiler::_refresh() { + if (!dirty) { + return; + } + dirty = false; + refresh_rpc_data(); + refresh_replication_data(); +} + +void EditorNetworkProfiler::refresh_rpc_data() { counters_display->clear(); TreeItem *root = counters_display->create_item(); + int cols = counters_display->get_columns(); - for (const KeyValue<ObjectID, RPCNodeInfo> &E : nodes_data) { + for (const KeyValue<ObjectID, RPCNodeInfo> &E : rpc_data) { TreeItem *node = counters_display->create_item(root); - for (int j = 0; j < counters_display->get_columns(); ++j) { + for (int j = 0; j < cols; ++j) { node->set_text_alignment(j, j > 0 ? HORIZONTAL_ALIGNMENT_RIGHT : HORIZONTAL_ALIGNMENT_LEFT); } node->set_text(0, E.value.node_path); - node->set_text(1, E.value.incoming_rpc == 0 ? "-" : itos(E.value.incoming_rpc)); - node->set_text(2, E.value.outgoing_rpc == 0 ? "-" : itos(E.value.outgoing_rpc)); + node->set_text(1, E.value.incoming_rpc == 0 ? "-" : vformat(TTR("%d (%s)"), E.value.incoming_rpc, String::humanize_size(E.value.incoming_size))); + node->set_text(2, E.value.outgoing_rpc == 0 ? "-" : vformat(TTR("%d (%s)"), E.value.outgoing_rpc, String::humanize_size(E.value.outgoing_size))); + } +} + +void EditorNetworkProfiler::refresh_replication_data() { + replication_display->clear(); + + TreeItem *root = replication_display->create_item(); + + for (const KeyValue<ObjectID, SyncInfo> &E : sync_data) { + // Ensure the nodes have at least a temporary cache. + ObjectID ids[3] = { E.value.synchronizer, E.value.config, E.value.root_node }; + for (uint32_t i = 0; i < 3; i++) { + const ObjectID &id = ids[i]; + if (!node_data.has(id)) { + missing_node_data.insert(id); + node_data[id] = NodeInfo(id); + } + } + + TreeItem *node = replication_display->create_item(root); + + const NodeInfo &root_info = node_data[E.value.root_node]; + const NodeInfo &sync_info = node_data[E.value.synchronizer]; + const NodeInfo &cfg_info = node_data[E.value.config]; + + node->set_text(0, root_info.path.get_file()); + node->set_icon(0, has_theme_icon(root_info.type, SNAME("EditorIcons")) ? get_theme_icon(root_info.type, SNAME("EditorIcons")) : node_icon); + node->set_tooltip_text(0, root_info.path); + + node->set_text(1, sync_info.path.get_file()); + node->set_icon(1, get_theme_icon("MultiplayerSynchronizer", SNAME("EditorIcons"))); + node->set_tooltip_text(1, sync_info.path); + + int cfg_idx = cfg_info.path.find("::"); + if (cfg_info.path.begins_with("res://") && ResourceLoader::exists(cfg_info.path) && cfg_idx > 0) { + String res_idstr = cfg_info.path.substr(cfg_idx + 2).replace("SceneReplicationConfig_", ""); + String scene_path = cfg_info.path.substr(0, cfg_idx); + node->set_text(2, vformat("%s (%s)", res_idstr, scene_path.get_file())); + node->add_button(2, get_theme_icon(SNAME("InstanceOptions"), SNAME("EditorIcons"))); + node->set_tooltip_text(2, cfg_info.path); + node->set_metadata(2, scene_path); + } else { + node->set_text(2, cfg_info.path); + node->set_metadata(2, ""); + } + + node->set_text(3, vformat("%d - %d", E.value.incoming_syncs, E.value.outgoing_syncs)); + node->set_text(4, vformat("%d - %d", E.value.incoming_size, E.value.outgoing_size)); } } +Array EditorNetworkProfiler::pop_missing_node_data() { + Array out; + for (const ObjectID &id : missing_node_data) { + out.push_back(id); + } + missing_node_data.clear(); + return out; +} + +void EditorNetworkProfiler::add_node_data(const NodeInfo &p_info) { + ERR_FAIL_COND(!node_data.has(p_info.id)); + node_data[p_info.id] = p_info; + dirty = true; +} + void EditorNetworkProfiler::_activate_pressed() { if (activate->is_pressed()) { + refresh_timer->start(); activate->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"))); activate->set_text(TTR("Stop")); } else { + refresh_timer->stop(); activate->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons"))); activate->set_text(TTR("Start")); } @@ -84,25 +165,55 @@ void EditorNetworkProfiler::_activate_pressed() { } void EditorNetworkProfiler::_clear_pressed() { - nodes_data.clear(); + rpc_data.clear(); + sync_data.clear(); + node_data.clear(); + missing_node_data.clear(); set_bandwidth(0, 0); - if (frame_delay->is_stopped()) { - frame_delay->set_wait_time(0.1); - frame_delay->start(); + refresh_rpc_data(); + refresh_replication_data(); +} + +void EditorNetworkProfiler::_replication_button_clicked(TreeItem *p_item, int p_column, int p_idx, MouseButton p_button) { + if (!p_item) { + return; + } + String meta = p_item->get_metadata(p_column); + if (meta.size() && ResourceLoader::exists(meta)) { + emit_signal("open_request", meta); } } -void EditorNetworkProfiler::add_node_frame_data(const RPCNodeInfo p_frame) { - if (!nodes_data.has(p_frame.node)) { - nodes_data.insert(p_frame.node, p_frame); +void EditorNetworkProfiler::add_rpc_frame_data(const RPCNodeInfo &p_frame) { + dirty = true; + if (!rpc_data.has(p_frame.node)) { + rpc_data.insert(p_frame.node, p_frame); } else { - nodes_data[p_frame.node].incoming_rpc += p_frame.incoming_rpc; - nodes_data[p_frame.node].outgoing_rpc += p_frame.outgoing_rpc; + rpc_data[p_frame.node].incoming_rpc += p_frame.incoming_rpc; + rpc_data[p_frame.node].outgoing_rpc += p_frame.outgoing_rpc; } + if (p_frame.incoming_rpc) { + rpc_data[p_frame.node].incoming_size = p_frame.incoming_size / p_frame.incoming_rpc; + } + if (p_frame.outgoing_rpc) { + rpc_data[p_frame.node].outgoing_size = p_frame.outgoing_size / p_frame.outgoing_rpc; + } +} - if (frame_delay->is_stopped()) { - frame_delay->set_wait_time(0.1); - frame_delay->start(); +void EditorNetworkProfiler::add_sync_frame_data(const SyncInfo &p_frame) { + dirty = true; + if (!sync_data.has(p_frame.synchronizer)) { + sync_data[p_frame.synchronizer] = p_frame; + } else { + sync_data[p_frame.synchronizer].incoming_syncs += p_frame.incoming_syncs; + sync_data[p_frame.synchronizer].outgoing_syncs += p_frame.outgoing_syncs; + } + SyncInfo &info = sync_data[p_frame.synchronizer]; + if (info.incoming_syncs) { + info.incoming_size = p_frame.incoming_size / p_frame.incoming_syncs; + } + if (info.outgoing_syncs) { + info.outgoing_size = p_frame.outgoing_size / p_frame.outgoing_syncs; } } @@ -168,9 +279,17 @@ EditorNetworkProfiler::EditorNetworkProfiler() { // Set initial texts in the incoming/outgoing bandwidth labels set_bandwidth(0, 0); + HSplitContainer *sc = memnew(HSplitContainer); + add_child(sc); + sc->set_v_size_flags(SIZE_EXPAND_FILL); + sc->set_h_size_flags(SIZE_EXPAND_FILL); + sc->set_split_offset(100 * EDSCALE); + + // RPC counters_display = memnew(Tree); - counters_display->set_custom_minimum_size(Size2(300, 0) * EDSCALE); + counters_display->set_custom_minimum_size(Size2(320, 0) * EDSCALE); counters_display->set_v_size_flags(SIZE_EXPAND_FILL); + counters_display->set_h_size_flags(SIZE_EXPAND_FILL); counters_display->set_hide_folding(true); counters_display->set_hide_root(true); counters_display->set_columns(3); @@ -187,11 +306,42 @@ EditorNetworkProfiler::EditorNetworkProfiler() { counters_display->set_column_expand(2, false); counters_display->set_column_clip_content(2, true); counters_display->set_column_custom_minimum_width(2, 120 * EDSCALE); - add_child(counters_display); + sc->add_child(counters_display); + + // Replication + replication_display = memnew(Tree); + replication_display->set_custom_minimum_size(Size2(320, 0) * EDSCALE); + replication_display->set_v_size_flags(SIZE_EXPAND_FILL); + replication_display->set_h_size_flags(SIZE_EXPAND_FILL); + replication_display->set_hide_folding(true); + replication_display->set_hide_root(true); + replication_display->set_columns(5); + replication_display->set_column_titles_visible(true); + replication_display->set_column_title(0, TTR("Root")); + replication_display->set_column_expand(0, true); + replication_display->set_column_clip_content(0, true); + replication_display->set_column_custom_minimum_width(0, 80 * EDSCALE); + replication_display->set_column_title(1, TTR("Synchronizer")); + replication_display->set_column_expand(1, true); + replication_display->set_column_clip_content(1, true); + replication_display->set_column_custom_minimum_width(1, 80 * EDSCALE); + replication_display->set_column_title(2, TTR("Config")); + replication_display->set_column_expand(2, true); + replication_display->set_column_clip_content(2, true); + replication_display->set_column_custom_minimum_width(2, 80 * EDSCALE); + replication_display->set_column_title(3, TTR("Count")); + replication_display->set_column_expand(3, false); + replication_display->set_column_clip_content(3, true); + replication_display->set_column_custom_minimum_width(3, 80 * EDSCALE); + replication_display->set_column_title(4, TTR("Size")); + replication_display->set_column_expand(4, false); + replication_display->set_column_clip_content(4, true); + replication_display->set_column_custom_minimum_width(4, 80 * EDSCALE); + replication_display->connect("button_clicked", callable_mp(this, &EditorNetworkProfiler::_replication_button_clicked)); + sc->add_child(replication_display); - frame_delay = memnew(Timer); - frame_delay->set_wait_time(0.1); - frame_delay->set_one_shot(true); - add_child(frame_delay); - frame_delay->connect("timeout", callable_mp(this, &EditorNetworkProfiler::_update_frame)); + refresh_timer = memnew(Timer); + refresh_timer->set_wait_time(0.5); + refresh_timer->connect("timeout", callable_mp(this, &EditorNetworkProfiler::_refresh)); + add_child(refresh_timer); } diff --git a/modules/multiplayer/editor/editor_network_profiler.h b/modules/multiplayer/editor/editor_network_profiler.h index 98d12e3c0a..630747d988 100644 --- a/modules/multiplayer/editor/editor_network_profiler.h +++ b/modules/multiplayer/editor/editor_network_profiler.h @@ -43,30 +43,55 @@ class EditorNetworkProfiler : public VBoxContainer { GDCLASS(EditorNetworkProfiler, VBoxContainer) +public: + struct NodeInfo { + ObjectID id; + String type; + String path; + + NodeInfo() {} + NodeInfo(const ObjectID &p_id) { + id = p_id; + path = String::num_int64(p_id); + } + }; + private: using RPCNodeInfo = MultiplayerDebugger::RPCNodeInfo; + using SyncInfo = MultiplayerDebugger::SyncInfo; + bool dirty = false; + Timer *refresh_timer = nullptr; Button *activate = nullptr; Button *clear_button = nullptr; Tree *counters_display = nullptr; LineEdit *incoming_bandwidth_text = nullptr; LineEdit *outgoing_bandwidth_text = nullptr; + Tree *replication_display = nullptr; - Timer *frame_delay = nullptr; - - HashMap<ObjectID, RPCNodeInfo> nodes_data; - - void _update_frame(); + HashMap<ObjectID, RPCNodeInfo> rpc_data; + HashMap<ObjectID, SyncInfo> sync_data; + HashMap<ObjectID, NodeInfo> node_data; + HashSet<ObjectID> missing_node_data; + Ref<Texture2D> node_icon; void _activate_pressed(); void _clear_pressed(); + void _refresh(); + void _replication_button_clicked(TreeItem *p_item, int p_column, int p_idx, MouseButton p_button); protected: void _notification(int p_what); static void _bind_methods(); public: - void add_node_frame_data(const RPCNodeInfo p_frame); + void refresh_rpc_data(); + void refresh_replication_data(); + + Array pop_missing_node_data(); + void add_node_data(const NodeInfo &p_info); + void add_rpc_frame_data(const RPCNodeInfo &p_frame); + void add_sync_frame_data(const SyncInfo &p_frame); void set_bandwidth(int p_incoming, int p_outgoing); bool is_profiling(); diff --git a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp index 00b1537827..c5cf3e6f24 100644 --- a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp +++ b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp @@ -36,10 +36,18 @@ #include "editor/editor_node.h" +void MultiplayerEditorDebugger::_bind_methods() { + ADD_SIGNAL(MethodInfo("open_request", PropertyInfo(Variant::STRING, "path"))); +} + bool MultiplayerEditorDebugger::has_capture(const String &p_capture) const { return p_capture == "multiplayer"; } +void MultiplayerEditorDebugger::_open_request(const String &p_path) { + emit_signal("open_request", p_path); +} + bool MultiplayerEditorDebugger::capture(const String &p_message, const Array &p_data, int p_session) { ERR_FAIL_COND_V(!profilers.has(p_session), false); EditorNetworkProfiler *profiler = profilers[p_session]; @@ -47,10 +55,31 @@ bool MultiplayerEditorDebugger::capture(const String &p_message, const Array &p_ MultiplayerDebugger::RPCFrame frame; frame.deserialize(p_data); for (int i = 0; i < frame.infos.size(); i++) { - profiler->add_node_frame_data(frame.infos[i]); + profiler->add_rpc_frame_data(frame.infos[i]); + } + return true; + } else if (p_message == "multiplayer:syncs") { + MultiplayerDebugger::ReplicationFrame frame; + frame.deserialize(p_data); + for (const KeyValue<ObjectID, MultiplayerDebugger::SyncInfo> &E : frame.infos) { + profiler->add_sync_frame_data(E.value); + } + Array missing = profiler->pop_missing_node_data(); + if (missing.size()) { + // Asks for the object information. + get_session(p_session)->send_message("multiplayer:cache", missing); + } + return true; + } else if (p_message == "multiplayer:cache") { + ERR_FAIL_COND_V(p_data.size() % 3, false); + for (int i = 0; i < p_data.size(); i += 3) { + EditorNetworkProfiler::NodeInfo info; + info.id = p_data[i].operator ObjectID(); + info.type = p_data[i + 1].operator String(); + info.path = p_data[i + 2].operator String(); + profiler->add_node_data(info); } return true; - } else if (p_message == "multiplayer:bandwidth") { ERR_FAIL_COND_V(p_data.size() < 2, false); profiler->set_bandwidth(p_data[0], p_data[1]); @@ -62,8 +91,9 @@ bool MultiplayerEditorDebugger::capture(const String &p_message, const Array &p_ void MultiplayerEditorDebugger::_profiler_activate(bool p_enable, int p_session_id) { Ref<EditorDebuggerSession> session = get_session(p_session_id); ERR_FAIL_COND(session.is_null()); - session->toggle_profiler("multiplayer", p_enable); - session->toggle_profiler("rpc", p_enable); + session->toggle_profiler("multiplayer:bandwidth", p_enable); + session->toggle_profiler("multiplayer:rpc", p_enable); + session->toggle_profiler("multiplayer:replication", p_enable); } void MultiplayerEditorDebugger::setup_session(int p_session_id) { @@ -71,20 +101,25 @@ void MultiplayerEditorDebugger::setup_session(int p_session_id) { ERR_FAIL_COND(session.is_null()); EditorNetworkProfiler *profiler = memnew(EditorNetworkProfiler); profiler->connect("enable_profiling", callable_mp(this, &MultiplayerEditorDebugger::_profiler_activate).bind(p_session_id)); + profiler->connect("open_request", callable_mp(this, &MultiplayerEditorDebugger::_open_request)); profiler->set_name(TTR("Network Profiler")); session->add_session_tab(profiler); profilers[p_session_id] = profiler; } +/// MultiplayerEditorPlugin + MultiplayerEditorPlugin::MultiplayerEditorPlugin() { repl_editor = memnew(ReplicationEditor); button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Replication"), repl_editor); button->hide(); repl_editor->get_pin()->connect("pressed", callable_mp(this, &MultiplayerEditorPlugin::_pinned)); debugger.instantiate(); + debugger->connect("open_request", callable_mp(this, &MultiplayerEditorPlugin::_open_request)); } -MultiplayerEditorPlugin::~MultiplayerEditorPlugin() { +void MultiplayerEditorPlugin::_open_request(const String &p_path) { + get_editor_interface()->open_scene_from_path(p_path); } void MultiplayerEditorPlugin::_notification(int p_what) { diff --git a/modules/multiplayer/editor/multiplayer_editor_plugin.h b/modules/multiplayer/editor/multiplayer_editor_plugin.h index 6d1514cdb1..f29a70e897 100644 --- a/modules/multiplayer/editor/multiplayer_editor_plugin.h +++ b/modules/multiplayer/editor/multiplayer_editor_plugin.h @@ -42,8 +42,12 @@ class MultiplayerEditorDebugger : public EditorDebuggerPlugin { private: HashMap<int, EditorNetworkProfiler *> profilers; + void _open_request(const String &p_path); void _profiler_activate(bool p_enable, int p_session_id); +protected: + static void _bind_methods(); + public: virtual bool has_capture(const String &p_capture) const override; virtual bool capture(const String &p_message, const Array &p_data, int p_index) override; @@ -62,6 +66,7 @@ private: ReplicationEditor *repl_editor = nullptr; Ref<MultiplayerEditorDebugger> debugger; + void _open_request(const String &p_path); void _node_removed(Node *p_node); void _pinned(); @@ -75,7 +80,6 @@ public: virtual void make_visible(bool p_visible) override; MultiplayerEditorPlugin(); - ~MultiplayerEditorPlugin(); }; #endif // MULTIPLAYER_EDITOR_PLUGIN_H diff --git a/modules/multiplayer/multiplayer_debugger.cpp b/modules/multiplayer/multiplayer_debugger.cpp index 3d22af04dc..9086ee6ec9 100644 --- a/modules/multiplayer/multiplayer_debugger.cpp +++ b/modules/multiplayer/multiplayer_debugger.cpp @@ -30,6 +30,9 @@ #include "multiplayer_debugger.h" +#include "multiplayer_synchronizer.h" +#include "scene_replication_config.h" + #include "core/debugger/engine_debugger.h" #include "scene/main/node.h" @@ -38,19 +41,51 @@ List<Ref<EngineProfiler>> multiplayer_profilers; void MultiplayerDebugger::initialize() { Ref<BandwidthProfiler> bandwidth; bandwidth.instantiate(); - bandwidth->bind("multiplayer"); + bandwidth->bind("multiplayer:bandwidth"); multiplayer_profilers.push_back(bandwidth); Ref<RPCProfiler> rpc_profiler; rpc_profiler.instantiate(); - rpc_profiler->bind("rpc"); + rpc_profiler->bind("multiplayer:rpc"); multiplayer_profilers.push_back(rpc_profiler); + + Ref<ReplicationProfiler> replication_profiler; + replication_profiler.instantiate(); + replication_profiler->bind("multiplayer:replication"); + multiplayer_profilers.push_back(replication_profiler); + + EngineDebugger::register_message_capture("multiplayer", EngineDebugger::Capture(nullptr, &_capture)); } void MultiplayerDebugger::deinitialize() { multiplayer_profilers.clear(); } +Error MultiplayerDebugger::_capture(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured) { + if (p_msg == "cache") { + Array out; + for (int i = 0; i < p_args.size(); i++) { + ObjectID id = p_args[i].operator ObjectID(); + Object *obj = ObjectDB::get_instance(id); + ERR_CONTINUE(!obj); + if (Object::cast_to<SceneReplicationConfig>(obj)) { + out.push_back(id); + out.push_back(obj->get_class()); + out.push_back(((SceneReplicationConfig *)obj)->get_path()); + } else if (Object::cast_to<Node>(obj)) { + out.push_back(id); + out.push_back(obj->get_class()); + out.push_back(String(((Node *)obj)->get_path())); + } else { + ERR_FAIL_V(FAILED); + } + } + EngineDebugger::get_singleton()->send_message("multiplayer:cache", out); + return OK; + } + ERR_FAIL_V(FAILED); +} + // BandwidthProfiler int MultiplayerDebugger::BandwidthProfiler::bandwidth_usage(const Vector<BandwidthFrame> &p_buffer, int p_pointer) { @@ -126,12 +161,14 @@ void MultiplayerDebugger::BandwidthProfiler::tick(double p_frame_time, double p_ Array MultiplayerDebugger::RPCFrame::serialize() { Array arr; - arr.push_back(infos.size() * 4); + arr.push_back(infos.size() * 6); for (int i = 0; i < infos.size(); ++i) { arr.push_back(uint64_t(infos[i].node)); arr.push_back(infos[i].node_path); arr.push_back(infos[i].incoming_rpc); + arr.push_back(infos[i].incoming_size); arr.push_back(infos[i].outgoing_rpc); + arr.push_back(infos[i].outgoing_size); } return arr; } @@ -139,15 +176,18 @@ Array MultiplayerDebugger::RPCFrame::serialize() { bool MultiplayerDebugger::RPCFrame::deserialize(const Array &p_arr) { ERR_FAIL_COND_V(p_arr.size() < 1, false); uint32_t size = p_arr[0]; - ERR_FAIL_COND_V(size % 4, false); + ERR_FAIL_COND_V(size % 6, false); ERR_FAIL_COND_V((uint32_t)p_arr.size() != size + 1, false); - infos.resize(size / 4); + infos.resize(size / 6); int idx = 1; - for (uint32_t i = 0; i < size / 4; ++i) { + for (uint32_t i = 0; i < size / 6; i++) { infos.write[i].node = uint64_t(p_arr[idx]); infos.write[i].node_path = p_arr[idx + 1]; infos.write[i].incoming_rpc = p_arr[idx + 2]; - infos.write[i].outgoing_rpc = p_arr[idx + 3]; + infos.write[i].incoming_size = p_arr[idx + 3]; + infos.write[i].outgoing_rpc = p_arr[idx + 4]; + infos.write[i].outgoing_size = p_arr[idx + 5]; + idx += 6; } return true; } @@ -159,8 +199,6 @@ void MultiplayerDebugger::RPCProfiler::init_node(const ObjectID p_node) { rpc_node_data.insert(p_node, RPCNodeInfo()); rpc_node_data[p_node].node = p_node; rpc_node_data[p_node].node_path = Object::cast_to<Node>(ObjectDB::get_instance(p_node))->get_path(); - rpc_node_data[p_node].incoming_rpc = 0; - rpc_node_data[p_node].outgoing_rpc = 0; } void MultiplayerDebugger::RPCProfiler::toggle(bool p_enable, const Array &p_opts) { @@ -168,15 +206,18 @@ void MultiplayerDebugger::RPCProfiler::toggle(bool p_enable, const Array &p_opts } void MultiplayerDebugger::RPCProfiler::add(const Array &p_data) { - ERR_FAIL_COND(p_data.size() < 2); - const ObjectID id = p_data[0]; - const String what = p_data[1]; + ERR_FAIL_COND(p_data.size() != 3); + const String what = p_data[0]; + const ObjectID id = p_data[1]; + const int size = p_data[2]; init_node(id); RPCNodeInfo &info = rpc_node_data[id]; if (what == "rpc_in") { info.incoming_rpc++; + info.incoming_size += size; } else if (what == "rpc_out") { info.outgoing_rpc++; + info.outgoing_size += size; } } @@ -192,3 +233,101 @@ void MultiplayerDebugger::RPCProfiler::tick(double p_frame_time, double p_proces EngineDebugger::get_singleton()->send_message("multiplayer:rpc", frame.serialize()); } } + +// ReplicationProfiler + +MultiplayerDebugger::SyncInfo::SyncInfo(MultiplayerSynchronizer *p_sync) { + ERR_FAIL_COND(!p_sync); + synchronizer = p_sync->get_instance_id(); + if (p_sync->get_replication_config().is_valid()) { + config = p_sync->get_replication_config()->get_instance_id(); + } + if (p_sync->get_root_node()) { + root_node = p_sync->get_root_node()->get_instance_id(); + } +} + +void MultiplayerDebugger::SyncInfo::write_to_array(Array &r_arr) const { + r_arr.push_back(synchronizer); + r_arr.push_back(config); + r_arr.push_back(root_node); + r_arr.push_back(incoming_syncs); + r_arr.push_back(incoming_size); + r_arr.push_back(outgoing_syncs); + r_arr.push_back(outgoing_size); +} + +bool MultiplayerDebugger::SyncInfo::read_from_array(const Array &p_arr, int p_offset) { + ERR_FAIL_COND_V(p_arr.size() - p_offset < 7, false); + synchronizer = int64_t(p_arr[p_offset]); + config = int64_t(p_arr[p_offset + 1]); + root_node = int64_t(p_arr[p_offset + 2]); + incoming_syncs = p_arr[p_offset + 3]; + incoming_size = p_arr[p_offset + 4]; + outgoing_syncs = p_arr[p_offset + 5]; + outgoing_size = p_arr[p_offset + 6]; + return true; +} + +Array MultiplayerDebugger::ReplicationFrame::serialize() { + Array arr; + arr.push_back(infos.size() * 7); + for (const KeyValue<ObjectID, SyncInfo> &E : infos) { + E.value.write_to_array(arr); + } + return arr; +} + +bool MultiplayerDebugger::ReplicationFrame::deserialize(const Array &p_arr) { + ERR_FAIL_COND_V(p_arr.size() < 1, false); + uint32_t size = p_arr[0]; + ERR_FAIL_COND_V(size % 7, false); + ERR_FAIL_COND_V((uint32_t)p_arr.size() != size + 1, false); + int idx = 1; + for (uint32_t i = 0; i < size / 7; i++) { + SyncInfo info; + if (!info.read_from_array(p_arr, idx)) { + return false; + } + infos[info.synchronizer] = info; + idx += 7; + } + return true; +} + +void MultiplayerDebugger::ReplicationProfiler::toggle(bool p_enable, const Array &p_opts) { + sync_data.clear(); +} + +void MultiplayerDebugger::ReplicationProfiler::add(const Array &p_data) { + ERR_FAIL_COND(p_data.size() != 3); + const String what = p_data[0]; + const ObjectID id = p_data[1]; + const uint64_t size = p_data[2]; + MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(ObjectDB::get_instance(id)); + ERR_FAIL_COND(!sync); + if (!sync_data.has(id)) { + sync_data[id] = SyncInfo(sync); + } + SyncInfo &info = sync_data[id]; + if (what == "sync_in") { + info.incoming_syncs++; + info.incoming_size += size; + } else if (what == "sync_out") { + info.outgoing_syncs++; + info.outgoing_size += size; + } +} + +void MultiplayerDebugger::ReplicationProfiler::tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) { + uint64_t pt = OS::get_singleton()->get_ticks_msec(); + if (pt - last_profile_time > 100) { + last_profile_time = pt; + ReplicationFrame frame; + for (const KeyValue<ObjectID, SyncInfo> &E : sync_data) { + frame.infos[E.key] = E.value; + } + sync_data.clear(); + EngineDebugger::get_singleton()->send_message("multiplayer:syncs", frame.serialize()); + } +} diff --git a/modules/multiplayer/multiplayer_debugger.h b/modules/multiplayer/multiplayer_debugger.h index 4efd1da016..f5c092f0f9 100644 --- a/modules/multiplayer/multiplayer_debugger.h +++ b/modules/multiplayer/multiplayer_debugger.h @@ -35,13 +35,17 @@ #include "core/os/os.h" +class MultiplayerSynchronizer; + class MultiplayerDebugger { public: struct RPCNodeInfo { ObjectID node; String node_path; int incoming_rpc = 0; + int incoming_size = 0; int outgoing_rpc = 0; + int outgoing_size = 0; }; struct RPCFrame { @@ -51,6 +55,29 @@ public: bool deserialize(const Array &p_arr); }; + struct SyncInfo { + ObjectID synchronizer; + ObjectID config; + ObjectID root_node; + int incoming_syncs = 0; + int incoming_size = 0; + int outgoing_syncs = 0; + int outgoing_size = 0; + + void write_to_array(Array &r_arr) const; + bool read_from_array(const Array &p_arr, int p_offset); + + SyncInfo() {} + SyncInfo(MultiplayerSynchronizer *p_sync); + }; + + struct ReplicationFrame { + HashMap<ObjectID, SyncInfo> infos; + + Array serialize(); + bool deserialize(const Array &p_arr); + }; + private: class BandwidthProfiler : public EngineProfiler { protected: @@ -74,7 +101,6 @@ private: }; class RPCProfiler : public EngineProfiler { - public: private: HashMap<ObjectID, RPCNodeInfo> rpc_node_data; uint64_t last_profile_time = 0; @@ -87,6 +113,19 @@ private: void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time); }; + class ReplicationProfiler : public EngineProfiler { + private: + HashMap<ObjectID, SyncInfo> sync_data; + uint64_t last_profile_time = 0; + + public: + void toggle(bool p_enable, const Array &p_opts); + void add(const Array &p_data); + void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time); + }; + + static Error _capture(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured); + public: static void initialize(); static void deinitialize(); diff --git a/modules/multiplayer/register_types.cpp b/modules/multiplayer/register_types.cpp index 2bf1041029..ca85a46f31 100644 --- a/modules/multiplayer/register_types.cpp +++ b/modules/multiplayer/register_types.cpp @@ -47,6 +47,7 @@ void initialize_multiplayer_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(SceneReplicationConfig); GDREGISTER_CLASS(MultiplayerSpawner); GDREGISTER_CLASS(MultiplayerSynchronizer); + GDREGISTER_CLASS(OfflineMultiplayerPeer); GDREGISTER_CLASS(SceneMultiplayer); MultiplayerAPI::set_default_interface("SceneMultiplayer"); MultiplayerDebugger::initialize(); diff --git a/modules/multiplayer/scene_cache_interface.cpp b/modules/multiplayer/scene_cache_interface.cpp index 7df9b95b30..f0da4f9dfc 100644 --- a/modules/multiplayer/scene_cache_interface.cpp +++ b/modules/multiplayer/scene_cache_interface.cpp @@ -99,10 +99,6 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac Ref<MultiplayerPeer> multiplayer_peer = multiplayer->get_multiplayer_peer(); ERR_FAIL_COND(multiplayer_peer.is_null()); -#ifdef DEBUG_ENABLED - multiplayer->profile_bandwidth("out", packet.size()); -#endif - multiplayer_peer->set_transfer_channel(0); multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); multiplayer->send_command(p_from, packet.ptr(), packet.size()); @@ -155,10 +151,6 @@ Error SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, Pat Ref<MultiplayerPeer> multiplayer_peer = multiplayer->get_multiplayer_peer(); ERR_FAIL_COND_V(multiplayer_peer.is_null(), ERR_BUG); -#ifdef DEBUG_ENABLED - multiplayer->profile_bandwidth("out", packet.size() * p_peers.size()); -#endif - Error err = OK; for (int peer_id : p_peers) { multiplayer_peer->set_transfer_channel(0); diff --git a/modules/multiplayer/scene_multiplayer.cpp b/modules/multiplayer/scene_multiplayer.cpp index db7c5037cd..5042a0502d 100644 --- a/modules/multiplayer/scene_multiplayer.cpp +++ b/modules/multiplayer/scene_multiplayer.cpp @@ -40,13 +40,13 @@ #endif #ifdef DEBUG_ENABLED -void SceneMultiplayer::profile_bandwidth(const String &p_inout, int p_size) { - if (EngineDebugger::is_profiling("multiplayer")) { +_FORCE_INLINE_ void SceneMultiplayer::_profile_bandwidth(const String &p_what, int p_value) { + if (EngineDebugger::is_profiling("multiplayer:bandwidth")) { Array values; - values.push_back(p_inout); + values.push_back(p_what); values.push_back(OS::get_singleton()->get_ticks_msec()); - values.push_back(p_size); - EngineDebugger::profiler_add_frame_data("multiplayer", values); + values.push_back(p_value); + EngineDebugger::profiler_add_frame_data("multiplayer:bandwidth", values); } } #endif @@ -91,6 +91,10 @@ Error SceneMultiplayer::poll() { Error err = multiplayer_peer->get_packet(&packet, len); ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Error getting packet! %d", err)); +#ifdef DEBUG_ENABLED + _profile_bandwidth("in", len); +#endif + if (pending_peers.has(sender)) { if (pending_peers[sender].local) { // If the auth is over, admit the peer at the first packet. @@ -220,10 +224,6 @@ void SceneMultiplayer::_process_packet(int p_from, const uint8_t *p_packet, int ERR_FAIL_COND_MSG(root_path.is_empty(), "Multiplayer root was not initialized. If you are using custom multiplayer, remember to set the root path via SceneMultiplayer.set_root_path before using it."); ERR_FAIL_COND_MSG(p_packet_len < 1, "Invalid packet received. Size too small."); -#ifdef DEBUG_ENABLED - profile_bandwidth("in", p_packet_len); -#endif - // Extract the `packet_type` from the LSB three bits: uint8_t packet_type = p_packet[0] & CMD_MASK; @@ -258,6 +258,13 @@ void SceneMultiplayer::_process_packet(int p_from, const uint8_t *p_packet, int } } +#ifdef DEBUG_ENABLED +_FORCE_INLINE_ Error SceneMultiplayer::_send(const uint8_t *p_packet, int p_packet_len) { + _profile_bandwidth("out", p_packet_len); + return multiplayer_peer->put_packet(p_packet, p_packet_len); +} +#endif + Error SceneMultiplayer::send_command(int p_to, const uint8_t *p_packet, int p_packet_len) { if (server_relay && get_unique_id() != 1 && p_to != 1 && multiplayer_peer->is_server_relay_supported()) { // Send relay packet. @@ -268,19 +275,19 @@ Error SceneMultiplayer::send_command(int p_to, const uint8_t *p_packet, int p_pa relay_buffer->put_data(p_packet, p_packet_len); multiplayer_peer->set_target_peer(1); const Vector<uint8_t> data = relay_buffer->get_data_array(); - return multiplayer_peer->put_packet(data.ptr(), relay_buffer->get_position()); + return _send(data.ptr(), relay_buffer->get_position()); } if (p_to > 0) { ERR_FAIL_COND_V(!connected_peers.has(p_to), ERR_BUG); multiplayer_peer->set_target_peer(p_to); - return multiplayer_peer->put_packet(p_packet, p_packet_len); + return _send(p_packet, p_packet_len); } else { for (const int &pid : connected_peers) { if (p_to && pid == -p_to) { continue; } multiplayer_peer->set_target_peer(pid); - multiplayer_peer->put_packet(p_packet, p_packet_len); + _send(p_packet, p_packet_len); } return OK; } @@ -319,7 +326,7 @@ void SceneMultiplayer::_process_sys(int p_from, const uint8_t *p_packet, int p_p multiplayer_peer->set_transfer_channel(p_channel); if (peer > 0) { multiplayer_peer->set_target_peer(peer); - multiplayer_peer->put_packet(data.ptr(), relay_buffer->get_position()); + _send(data.ptr(), relay_buffer->get_position()); } else { for (const int &P : connected_peers) { // Not to sender, nor excluded. @@ -327,7 +334,7 @@ void SceneMultiplayer::_process_sys(int p_from, const uint8_t *p_packet, int p_p continue; } multiplayer_peer->set_target_peer(P); - multiplayer_peer->put_packet(data.ptr(), relay_buffer->get_position()); + _send(data.ptr(), relay_buffer->get_position()); } } if (peer == 0 || peer == -1) { @@ -373,11 +380,11 @@ void SceneMultiplayer::_admit_peer(int p_id) { // Send new peer to already connected. encode_uint32(p_id, &buf[2]); multiplayer_peer->set_target_peer(P); - multiplayer_peer->put_packet(buf, sizeof(buf)); + _send(buf, sizeof(buf)); // Send already connected to new peer. encode_uint32(P, &buf[2]); multiplayer_peer->set_target_peer(p_id); - multiplayer_peer->put_packet(buf, sizeof(buf)); + _send(buf, sizeof(buf)); } } @@ -412,7 +419,7 @@ void SceneMultiplayer::_del_peer(int p_id) { continue; } multiplayer_peer->set_target_peer(P); - multiplayer_peer->put_packet(buf, sizeof(buf)); + _send(buf, sizeof(buf)); } } @@ -468,7 +475,7 @@ Error SceneMultiplayer::send_auth(int p_to, Vector<uint8_t> p_data) { multiplayer_peer->set_target_peer(p_to); multiplayer_peer->set_transfer_channel(0); multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); - return multiplayer_peer->put_packet(packet_cache.ptr(), p_data.size() + 2); + return _send(packet_cache.ptr(), p_data.size() + 2); } Error SceneMultiplayer::complete_auth(int p_peer) { @@ -478,7 +485,7 @@ Error SceneMultiplayer::complete_auth(int p_peer) { pending_peers[p_peer].local = true; // Notify the remote peer that the authentication has completed. uint8_t buf[2] = { NETWORK_COMMAND_SYS, SYS_COMMAND_AUTH }; - Error err = multiplayer_peer->put_packet(buf, 2); + Error err = _send(buf, 2); // The remote peer already reported the authentication as completed, so admit the peer. // May generate new packets, so it must happen after sending confirmation. if (pending_peers[p_peer].remote) { @@ -654,6 +661,7 @@ SceneMultiplayer::SceneMultiplayer() { replicator = Ref<SceneReplicationInterface>(memnew(SceneReplicationInterface(this))); rpc = Ref<SceneRPCInterface>(memnew(SceneRPCInterface(this))); cache = Ref<SceneCacheInterface>(memnew(SceneCacheInterface(this))); + set_multiplayer_peer(Ref<OfflineMultiplayerPeer>(memnew(OfflineMultiplayerPeer))); } SceneMultiplayer::~SceneMultiplayer() { diff --git a/modules/multiplayer/scene_multiplayer.h b/modules/multiplayer/scene_multiplayer.h index b0ecc48f8c..1a8de11f3f 100644 --- a/modules/multiplayer/scene_multiplayer.h +++ b/modules/multiplayer/scene_multiplayer.h @@ -37,6 +37,31 @@ #include "scene_replication_interface.h" #include "scene_rpc_interface.h" +class OfflineMultiplayerPeer : public MultiplayerPeer { + GDCLASS(OfflineMultiplayerPeer, MultiplayerPeer); + +public: + virtual int get_available_packet_count() const override { return 0; } + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override { + *r_buffer = nullptr; + r_buffer_size = 0; + return OK; + } + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override { return OK; } + virtual int get_max_packet_size() const override { return 0; } + + virtual void set_target_peer(int p_peer_id) override {} + virtual int get_packet_peer() const override { return 0; } + virtual TransferMode get_packet_mode() const override { return TRANSFER_MODE_RELIABLE; }; + virtual int get_packet_channel() const override { return 0; } + virtual void disconnect_peer(int p_peer, bool p_force = false) override {} + virtual bool is_server() const override { return true; } + virtual void poll() override {} + virtual void close() override {} + virtual int get_unique_id() const override { return TARGET_PEER_SERVER; } + virtual ConnectionStatus get_connection_status() const override { return CONNECTION_CONNECTED; }; +}; + class SceneMultiplayer : public MultiplayerAPI { GDCLASS(SceneMultiplayer, MultiplayerAPI); @@ -103,6 +128,15 @@ private: Ref<SceneReplicationInterface> replicator; Ref<SceneRPCInterface> rpc; +#ifdef DEBUG_ENABLED + _FORCE_INLINE_ void _profile_bandwidth(const String &p_what, int p_value); + _FORCE_INLINE_ Error _send(const uint8_t *p_packet, int p_packet_len); // Also profiles. +#else + _FORCE_INLINE_ Error _send(const uint8_t *p_packet, int p_packet_len) { + return multiplayer_peer->put_packet(p_packet, p_packet_len); + } +#endif + protected: static void _bind_methods(); @@ -162,10 +196,7 @@ public: bool is_server_relay_enabled() const; Ref<SceneCacheInterface> get_path_cache() { return cache; } - -#ifdef DEBUG_ENABLED - void profile_bandwidth(const String &p_inout, int p_size); -#endif + Ref<SceneReplicationInterface> get_replicator() { return replicator; } SceneMultiplayer(); ~SceneMultiplayer(); diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp index f1bab7327a..7d9437936a 100644 --- a/modules/multiplayer/scene_replication_interface.cpp +++ b/modules/multiplayer/scene_replication_interface.cpp @@ -32,6 +32,7 @@ #include "scene_multiplayer.h" +#include "core/debugger/engine_debugger.h" #include "core/io/marshalls.h" #include "scene/main/node.h" #include "scene/scene_string_names.h" @@ -40,6 +41,18 @@ if (packet_cache.size() < m_amount) \ packet_cache.resize(m_amount); +#ifdef DEBUG_ENABLED +_FORCE_INLINE_ void SceneReplicationInterface::_profile_node_data(const String &p_what, ObjectID p_id, int p_size) { + if (EngineDebugger::is_profiling("multiplayer:replication")) { + Array values; + values.push_back(p_what); + values.push_back(p_id); + values.push_back(p_size); + EngineDebugger::profiler_add_frame_data("multiplayer:replication", values); + } +} +#endif + SceneReplicationInterface::TrackedNode &SceneReplicationInterface::_track(const ObjectID &p_id) { if (!tracked_nodes.has(p_id)) { tracked_nodes[p_id] = TrackedNode(p_id); @@ -244,15 +257,54 @@ void SceneReplicationInterface::_visibility_changed(int p_peer, ObjectID p_sid) Node *node = sync->get_root_node(); ERR_FAIL_COND(!node); // Bug. const ObjectID oid = node->get_instance_id(); - if (spawned_nodes.has(oid)) { + if (spawned_nodes.has(oid) && p_peer != multiplayer->get_unique_id()) { _update_spawn_visibility(p_peer, oid); } _update_sync_visibility(p_peer, sync); } +bool SceneReplicationInterface::is_rpc_visible(const ObjectID &p_oid, int p_peer) const { + if (!tracked_nodes.has(p_oid)) { + return true; // Untracked nodes are always visible to RPCs. + } + ERR_FAIL_COND_V(p_peer < 0, false); + const TrackedNode &tnode = tracked_nodes[p_oid]; + if (tnode.synchronizers.is_empty()) { + return true; // No synchronizers means no visibility restrictions. + } + if (tnode.remote_peer && uint32_t(p_peer) == tnode.remote_peer) { + return true; // RPCs on spawned nodes are always visible to spawner. + } else if (spawned_nodes.has(p_oid)) { + // It's a spwaned node we control, this can be fast + if (p_peer) { + return peers_info.has(p_peer) && peers_info[p_peer].spawn_nodes.has(p_oid); + } else { + for (const KeyValue<int, PeerInfo> &E : peers_info) { + if (!E.value.spawn_nodes.has(p_oid)) { + return false; // Not public. + } + } + return true; // All peers have this node. + } + } else { + // Cycle object synchronizers to check visibility. + for (const ObjectID &sid : tnode.synchronizers) { + MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(sid); + ERR_CONTINUE(!sync); + // RPC visibility is composed using OR when multiple synchronizers are present. + // Note that we don't really care about authority here which may lead to unexpected + // results when using multiple synchronizers to control the same node. + if (sync->is_visible_to(p_peer)) { + return true; + } + } + return false; // Not visible. + } +} + Error SceneReplicationInterface::_update_sync_visibility(int p_peer, MultiplayerSynchronizer *p_sync) { ERR_FAIL_COND_V(!p_sync, ERR_BUG); - if (!multiplayer->has_multiplayer_peer() || !p_sync->is_multiplayer_authority()) { + if (!multiplayer->has_multiplayer_peer() || !p_sync->is_multiplayer_authority() || p_peer == multiplayer->get_unique_id()) { return OK; } @@ -362,13 +414,8 @@ Error SceneReplicationInterface::_update_spawn_visibility(int p_peer, const Obje Error SceneReplicationInterface::_send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable) { ERR_FAIL_COND_V(!p_buffer || p_size < 1, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(!multiplayer, ERR_UNCONFIGURED); ERR_FAIL_COND_V(!multiplayer->has_multiplayer_peer(), ERR_UNCONFIGURED); -#ifdef DEBUG_ENABLED - multiplayer->profile_bandwidth("out", p_size); -#endif - Ref<MultiplayerPeer> peer = multiplayer->get_multiplayer_peer(); peer->set_transfer_channel(0); peer->set_transfer_mode(p_reliable ? MultiplayerPeer::TRANSFER_MODE_RELIABLE : MultiplayerPeer::TRANSFER_MODE_UNRELIABLE); @@ -640,6 +687,9 @@ void SceneReplicationInterface::_send_sync(int p_peer, const HashSet<ObjectID> p MultiplayerAPI::encode_and_compress_variants(varp.ptrw(), varp.size(), &ptr[ofs], size); ofs += size; } +#ifdef DEBUG_ENABLED + _profile_node_data("sync_out", oid, size); +#endif } if (ofs > 3) { // Got some left over to send. @@ -687,6 +737,9 @@ Error SceneReplicationInterface::on_sync_receive(int p_from, const uint8_t *p_bu err = MultiplayerSynchronizer::set_state(props, node, vars); ERR_FAIL_COND_V(err, err); ofs += size; +#ifdef DEBUG_ENABLED + _profile_node_data("sync_in", sync->get_instance_id(), size); +#endif } return OK; } diff --git a/modules/multiplayer/scene_replication_interface.h b/modules/multiplayer/scene_replication_interface.h index c8bd96eb87..30d58f7129 100644 --- a/modules/multiplayer/scene_replication_interface.h +++ b/modules/multiplayer/scene_replication_interface.h @@ -105,6 +105,10 @@ private: return p_id.is_valid() ? Object::cast_to<T>(ObjectDB::get_instance(p_id)) : nullptr; } +#ifdef DEBUG_ENABLED + _FORCE_INLINE_ void _profile_node_data(const String &p_what, ObjectID p_id, int p_size); +#endif + public: static void make_default(); @@ -121,6 +125,8 @@ public: Error on_despawn_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len); Error on_sync_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len); + bool is_rpc_visible(const ObjectID &p_oid, int p_peer) const; + SceneReplicationInterface(SceneMultiplayer *p_multiplayer) { multiplayer = p_multiplayer; } diff --git a/modules/multiplayer/scene_rpc_interface.cpp b/modules/multiplayer/scene_rpc_interface.cpp index acc113c901..dbf2b3751e 100644 --- a/modules/multiplayer/scene_rpc_interface.cpp +++ b/modules/multiplayer/scene_rpc_interface.cpp @@ -52,16 +52,15 @@ #define BYTE_ONLY_OR_NO_ARGS_FLAG (1 << BYTE_ONLY_OR_NO_ARGS_SHIFT) #ifdef DEBUG_ENABLED -_FORCE_INLINE_ void SceneRPCInterface::_profile_node_data(const String &p_what, ObjectID p_id) { - if (EngineDebugger::is_profiling("rpc")) { +_FORCE_INLINE_ void SceneRPCInterface::_profile_node_data(const String &p_what, ObjectID p_id, int p_size) { + if (EngineDebugger::is_profiling("multiplayer:rpc")) { Array values; - values.push_back(p_id); values.push_back(p_what); - EngineDebugger::profiler_add_frame_data("rpc", values); + values.push_back(p_id); + values.push_back(p_size); + EngineDebugger::profiler_add_frame_data("multiplayer:rpc", values); } } -#else -_FORCE_INLINE_ void SceneRPCInterface::_profile_node_data(const String &p_what, ObjectID p_id) {} #endif // Returns the packet size stripping the node path added when the node is not yet cached. @@ -277,7 +276,7 @@ void SceneRPCInterface::_process_rpc(Node *p_node, const uint16_t p_rpc_method_i argp.resize(argc); #ifdef DEBUG_ENABLED - _profile_node_data("rpc_in", p_node->get_instance_id()); + _profile_node_data("rpc_in", p_node->get_instance_id(), p_packet_len); #endif int out; @@ -296,7 +295,7 @@ void SceneRPCInterface::_process_rpc(Node *p_node, const uint16_t p_rpc_method_i } } -void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount) { +void SceneRPCInterface::_send_rpc(Node *p_node, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount) { Ref<MultiplayerPeer> peer = multiplayer->get_multiplayer_peer(); ERR_FAIL_COND_MSG(peer.is_null(), "Attempt to call RPC without active multiplayer peer."); @@ -312,12 +311,35 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con ERR_FAIL_MSG("Attempt to call RPC with unknown peer ID: " + itos(p_to) + "."); } - // See if all peers have cached path (if so, call can be fast). - int psc_id; - const bool has_all_peers = multiplayer->get_path_cache()->send_object_cache(p_from, p_to, psc_id); + // See if all peers have cached path (if so, call can be fast) while building the RPC target list. + HashSet<int> targets; + Ref<SceneCacheInterface> cache = multiplayer->get_path_cache(); + int psc_id = -1; + bool has_all_peers = true; + const ObjectID oid = p_node->get_instance_id(); + if (p_to > 0) { + ERR_FAIL_COND_MSG(!multiplayer->get_replicator()->is_rpc_visible(oid, p_to), "Attempt to call an RPC to a peer that cannot see this node. Peer ID: " + itos(p_to)); + targets.insert(p_to); + has_all_peers = cache->send_object_cache(p_node, p_to, psc_id); + } else { + bool restricted = !multiplayer->get_replicator()->is_rpc_visible(oid, 0); + for (const int &P : multiplayer->get_connected_peers()) { + if (p_to < 0 && P == -p_to) { + continue; // Excluded peer. + } + if (restricted && !multiplayer->get_replicator()->is_rpc_visible(oid, P)) { + continue; // Not visible to this peer. + } + targets.insert(P); + bool has_peer = cache->send_object_cache(p_node, P, psc_id); + has_all_peers = has_all_peers && has_peer; + } + } + if (targets.is_empty()) { + return; // No one in sight. + } // Create base packet, lots of hardcode because it must be tight. - int ofs = 0; #define MAKE_ROOM(m_amount) \ @@ -399,20 +421,21 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con ERR_FAIL_COND(node_id_compression > 3); ERR_FAIL_COND(name_id_compression > 1); - // We can now set the meta - packet_cache.write[0] = command_type + (node_id_compression << NODE_ID_COMPRESSION_SHIFT) + (name_id_compression << NAME_ID_COMPRESSION_SHIFT) + (byte_only_or_no_args ? BYTE_ONLY_OR_NO_ARGS_FLAG : 0); - #ifdef DEBUG_ENABLED - multiplayer->profile_bandwidth("out", ofs); + _profile_node_data("rpc_out", p_node->get_instance_id(), ofs); #endif + // We can now set the meta + packet_cache.write[0] = command_type + (node_id_compression << NODE_ID_COMPRESSION_SHIFT) + (name_id_compression << NAME_ID_COMPRESSION_SHIFT) + (byte_only_or_no_args ? BYTE_ONLY_OR_NO_ARGS_FLAG : 0); + // Take chance and set transfer mode, since all send methods will use it. peer->set_transfer_channel(p_config.channel); peer->set_transfer_mode(p_config.transfer_mode); if (has_all_peers) { - // They all have verified paths, so send fast. - multiplayer->send_command(p_to, packet_cache.ptr(), ofs); + for (const int P : targets) { + multiplayer->send_command(P, packet_cache.ptr(), ofs); + } } else { // Unreachable because the node ID is never compressed if the peers doesn't know it. CRASH_COND(node_id_compression != NETWORK_NODE_ID_COMPRESSION_32); @@ -420,23 +443,15 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con // Not all verified path, so send one by one. // Append path at the end, since we will need it for some packets. - NodePath from_path = multiplayer->get_root_path().rel_path_to(p_from->get_path()); + NodePath from_path = multiplayer->get_root_path().rel_path_to(p_node->get_path()); CharString pname = String(from_path).utf8(); int path_len = encode_cstring(pname.get_data(), nullptr); MAKE_ROOM(ofs + path_len); encode_cstring(pname.get_data(), &(packet_cache.write[ofs])); - for (const int &P : multiplayer->get_connected_peers()) { - if (p_to < 0 && P == -p_to) { - continue; // Continue, excluded. - } - - if (p_to > 0 && P != p_to) { - continue; // Continue, not for this peer. - } - + // Not all verified path, so check which needs the longer packet. + for (const int P : targets) { bool confirmed = multiplayer->get_path_cache()->is_cache_confirmed(from_path, P); - if (confirmed) { // This one confirmed path, so use id. encode_uint32(psc_id, &(packet_cache.write[1])); @@ -477,10 +492,6 @@ Error SceneRPCInterface::rpcp(Object *p_obj, int p_peer_id, const StringName &p_ } if (p_peer_id != caller_id) { -#ifdef DEBUG_ENABLED - _profile_node_data("rpc_out", node->get_instance_id()); -#endif - _send_rpc(node, p_peer_id, rpc_id, config, p_method, p_arg, p_argcount); } diff --git a/modules/multiplayer/scene_rpc_interface.h b/modules/multiplayer/scene_rpc_interface.h index aa9be525a2..800293714c 100644 --- a/modules/multiplayer/scene_rpc_interface.h +++ b/modules/multiplayer/scene_rpc_interface.h @@ -81,8 +81,11 @@ private: HashMap<ObjectID, RPCConfigCache> rpc_cache; +#ifdef DEBUG_ENABLED + _FORCE_INLINE_ void _profile_node_data(const String &p_what, ObjectID p_id, int p_size); +#endif + protected: - _FORCE_INLINE_ void _profile_node_data(const String &p_what, ObjectID p_id); void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); void _send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount); diff --git a/modules/openxr/action_map/openxr_action.cpp b/modules/openxr/action_map/openxr_action.cpp index 0fb4f0773f..7e02f0374d 100644 --- a/modules/openxr/action_map/openxr_action.cpp +++ b/modules/openxr/action_map/openxr_action.cpp @@ -42,7 +42,7 @@ void OpenXRAction::_bind_methods() { ClassDB::bind_method(D_METHOD("set_toplevel_paths", "toplevel_paths"), &OpenXRAction::set_toplevel_paths); ClassDB::bind_method(D_METHOD("get_toplevel_paths"), &OpenXRAction::get_toplevel_paths); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "toplevel_paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_toplevel_paths", "get_toplevel_paths"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "toplevel_paths"), "set_toplevel_paths", "get_toplevel_paths"); BIND_ENUM_CONSTANT(OPENXR_ACTION_BOOL); BIND_ENUM_CONSTANT(OPENXR_ACTION_FLOAT); diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp index 99d7a17acf..abb714c3bb 100644 --- a/modules/openxr/action_map/openxr_interaction_profile.cpp +++ b/modules/openxr/action_map/openxr_interaction_profile.cpp @@ -38,7 +38,7 @@ void OpenXRIPBinding::_bind_methods() { ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count); ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths); ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_paths", "get_paths"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths"), "set_paths", "get_paths"); ClassDB::bind_method(D_METHOD("has_path", "path"), &OpenXRIPBinding::has_path); ClassDB::bind_method(D_METHOD("add_path", "path"), &OpenXRIPBinding::add_path); diff --git a/modules/openxr/extensions/openxr_android_extension.cpp b/modules/openxr/extensions/openxr_android_extension.cpp index 8f6d5c28db..ea539f2053 100644 --- a/modules/openxr/extensions/openxr_android_extension.cpp +++ b/modules/openxr/extensions/openxr_android_extension.cpp @@ -47,7 +47,8 @@ OpenXRAndroidExtension *OpenXRAndroidExtension::get_singleton() { OpenXRAndroidExtension::OpenXRAndroidExtension(OpenXRAPI *p_openxr_api) : OpenXRExtensionWrapper(p_openxr_api) { singleton = this; - request_extensions[XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME] = nullptr; // must be available + request_extensions[XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME] = nullptr; // must be available + request_extensions[XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME] = &create_instance_extension_available; } void OpenXRAndroidExtension::on_before_instance_created() { @@ -68,6 +69,29 @@ void OpenXRAndroidExtension::on_before_instance_created() { ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to call xrInitializeLoaderKHR"); } +// We're keeping the Android create info struct here to avoid including openxr_platform.h in a header, which would break other extensions. +// This is reasonably safe as the struct is only used during intialization and the extension is a singleton. +static XrInstanceCreateInfoAndroidKHR instance_create_info; + +void *OpenXRAndroidExtension::set_instance_create_info_and_get_next_pointer(void *p_next_pointer) { + if (!create_instance_extension_available) { + return nullptr; + } + + JNIEnv *env = get_jni_env(); + JavaVM *vm; + env->GetJavaVM(&vm); + jobject activity_object = env->NewGlobalRef(static_cast<OS_Android *>(OS::get_singleton())->get_godot_java()->get_activity()); + + instance_create_info = { + .type = XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR, + .next = p_next_pointer, + .applicationVM = vm, + .applicationActivity = activity_object + }; + return &instance_create_info; +} + OpenXRAndroidExtension::~OpenXRAndroidExtension() { singleton = nullptr; } diff --git a/modules/openxr/extensions/openxr_android_extension.h b/modules/openxr/extensions/openxr_android_extension.h index eda7022064..ca6011559a 100644 --- a/modules/openxr/extensions/openxr_android_extension.h +++ b/modules/openxr/extensions/openxr_android_extension.h @@ -41,12 +41,15 @@ public: OpenXRAndroidExtension(OpenXRAPI *p_openxr_api); virtual void on_before_instance_created() override; + virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer) override; virtual ~OpenXRAndroidExtension() override; private: static OpenXRAndroidExtension *singleton; + bool create_instance_extension_available = false; + // Initialize the loader EXT_PROTO_XRRESULT_FUNC1(xrInitializeLoaderKHR, (const XrLoaderInitInfoBaseHeaderKHR *), loaderInitInfo) }; diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index c417c90d11..77b52ab355 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -65,6 +65,7 @@ public: virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } + virtual void *set_instance_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } virtual void on_before_instance_created() {} virtual void on_instance_created(const XrInstance p_instance) {} diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp index 4d996e6283..29208efb20 100644 --- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp +++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp @@ -91,8 +91,6 @@ bool OpenXRHTCViveTrackerExtension::is_path_supported(const String &p_path) { return available; } else if (p_path == "/user/vive_tracker_htcx/role/chest") { return available; - } else if (p_path == "/user/vive_tracker_htcx/role/chest") { - return available; } else if (p_path == "/user/vive_tracker_htcx/role/camera") { return available; } else if (p_path == "/user/vive_tracker_htcx/role/keyboard") { diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 88111afede..b7c95415d0 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -299,9 +299,17 @@ bool OpenXRAPI::create_instance() { XR_CURRENT_API_VERSION // apiVersion }; + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_instance_create_info_and_get_next_pointer(next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + XrInstanceCreateInfo instance_create_info = { XR_TYPE_INSTANCE_CREATE_INFO, // type - nullptr, // next + next_pointer, // next 0, // createFlags application_info, // applicationInfo 0, // enabledApiLayerCount, need to find out if we need support for this? diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index b8c412a201..2dba4916a0 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -67,8 +67,8 @@ void ImageLoaderSVG::_replace_color_property(const HashMap<Color, Color> &p_colo } } -void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map) { - ERR_FAIL_COND(Math::is_zero_approx(p_scale)); +Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map) { + ERR_FAIL_COND_V_MSG(Math::is_zero_approx(p_scale), ERR_INVALID_PARAMETER, "ImageLoaderSVG: Can't load SVG with a scale of 0."); if (p_color_map.size()) { _replace_color_property(p_color_map, "stop-color=\"", p_string); @@ -81,13 +81,23 @@ void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_strin tvg::Result result = picture->load((const char *)bytes.ptr(), bytes.size(), "svg", true); if (result != tvg::Result::Success) { - return; + return ERR_INVALID_DATA; } float fw, fh; picture->size(&fw, &fh); - uint32_t width = MIN(round(fw * p_scale), 16 * 1024); - uint32_t height = MIN(round(fh * p_scale), 16 * 1024); + uint32_t width = round(fw * p_scale); + uint32_t height = round(fh * p_scale); + + const uint32_t max_dimension = 16384; + if (width > max_dimension || height > max_dimension) { + WARN_PRINT(vformat( + String::utf8("ImageLoaderSVG: Target canvas dimensions %d×%d (with scale %.2f) exceed the max supported dimensions %d×%d. The target canvas will be scaled down."), + width, height, p_scale, max_dimension, max_dimension)); + width = MIN(width, max_dimension); + height = MIN(height, max_dimension); + } + picture->size(width, height); std::unique_ptr<tvg::SwCanvas> sw_canvas = tvg::SwCanvas::gen(); @@ -97,25 +107,25 @@ void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_strin tvg::Result res = sw_canvas->target(buffer, width, width, height, tvg::SwCanvas::ARGB8888_STRAIGHT); if (res != tvg::Result::Success) { memfree(buffer); - ERR_FAIL_MSG("ImageLoaderSVG can't create image."); + ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't set target on ThorVG canvas."); } res = sw_canvas->push(std::move(picture)); if (res != tvg::Result::Success) { memfree(buffer); - ERR_FAIL_MSG("ImageLoaderSVG can't create image."); + ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't insert ThorVG picture on canvas."); } res = sw_canvas->draw(); if (res != tvg::Result::Success) { memfree(buffer); - ERR_FAIL_MSG("ImageLoaderSVG can't create image."); + ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't draw ThorVG pictures on canvas."); } res = sw_canvas->sync(); if (res != tvg::Result::Success) { memfree(buffer); - ERR_FAIL_MSG("ImageLoaderSVG can't create image."); + ERR_FAIL_V_MSG(FAILED, "ImageLoaderSVG: Couldn't sync ThorVG canvas."); } Vector<uint8_t> image; @@ -136,6 +146,7 @@ void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_strin memfree(buffer); p_image->set_data(width, height, false, Image::FORMAT_RGBA8, image); + return OK; } void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const { @@ -145,13 +156,19 @@ void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { String svg = p_fileaccess->get_as_utf8_string(); + Error err; if (p_flags & FLAG_CONVERT_COLORS) { - create_image_from_string(p_image, svg, p_scale, false, forced_color_map); + err = create_image_from_string(p_image, svg, p_scale, false, forced_color_map); } else { - create_image_from_string(p_image, svg, p_scale, false, HashMap<Color, Color>()); + err = create_image_from_string(p_image, svg, p_scale, false, HashMap<Color, Color>()); + } + + if (err != OK) { + return err; + } else if (p_image->is_empty()) { + return ERR_INVALID_DATA; } - ERR_FAIL_COND_V(p_image->is_empty(), FAILED); if (p_flags & FLAG_FORCE_LINEAR) { p_image->srgb_to_linear(); } diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h index b0b0963c15..84511f1708 100644 --- a/modules/svg/image_loader_svg.h +++ b/modules/svg/image_loader_svg.h @@ -41,7 +41,7 @@ class ImageLoaderSVG : public ImageFormatLoader { public: static void set_forced_color_map(const HashMap<Color, Color> &p_color_map); - void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map); + Error create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map); virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) override; virtual void get_recognized_extensions(List<String> *p_extensions) const override; diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 166325c551..cf2d8c9986 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -4750,7 +4750,10 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) { i += (sd_glyphs[i].count - 1); } } - ERR_FAIL_COND_V_MSG(sd_shift != sd->break_inserts, false, "Invalid break insert count!"); + if (sd_shift < sd->break_inserts) { + // Note: should not happen with a normal text, but might be a case with special fonts that substitute a long string (with breaks opportunities in it) with a single glyph (like Font Awesome). + glyphs_new.resize(sd->glyphs.size() + sd_shift); + } if (sd->break_inserts > 0) { sd->glyphs = glyphs_new; diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index 792103cd31..63909257d9 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -438,9 +438,7 @@ void AudioStreamOggVorbis::maybe_update_info() { } if (i == 0) { packet->b_o_s = 1; - } - if (i == 0) { ERR_FAIL_COND(!vorbis_synthesis_idheader(packet)); } diff --git a/modules/zip/doc_classes/ZIPReader.xml b/modules/zip/doc_classes/ZIPReader.xml index 717116a531..055201b105 100644 --- a/modules/zip/doc_classes/ZIPReader.xml +++ b/modules/zip/doc_classes/ZIPReader.xml @@ -9,7 +9,7 @@ func read_zip_file(): var reader := ZIPReader.new() var err := reader.open("user://archive.zip") - if err == OK: + if err != OK: return PackedByteArray() var res := reader.read_file("hello.txt") reader.close() diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt index 489a81fc1a..46a334ef38 100644 --- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt @@ -37,10 +37,12 @@ import android.os.Build import android.os.Bundle import android.os.Debug import android.os.Environment +import android.util.Log import android.widget.Toast import androidx.window.layout.WindowMetricsCalculator import org.godotengine.godot.FullScreenGodotApp import org.godotengine.godot.utils.PermissionsUtil +import org.godotengine.godot.utils.ProcessPhoenix import java.util.* import kotlin.math.min @@ -56,12 +58,17 @@ import kotlin.math.min open class GodotEditor : FullScreenGodotApp() { companion object { + private val TAG = GodotEditor::class.java.simpleName + private const val WAIT_FOR_DEBUGGER = false private const val COMMAND_LINE_PARAMS = "command_line_params" private const val EDITOR_ARG = "--editor" + private const val EDITOR_ARG_SHORT = "-e" + private const val PROJECT_MANAGER_ARG = "--project-manager" + private const val PROJECT_MANAGER_ARG_SHORT = "-p" } private val commandLineParams = ArrayList<String>() @@ -105,13 +112,13 @@ open class GodotEditor : FullScreenGodotApp() { Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && (isInMultiWindowMode || isLargeScreen) for (arg in args) { - if (EDITOR_ARG == arg) { + if (EDITOR_ARG == arg || EDITOR_ARG_SHORT == arg) { targetClass = GodotEditor::class.java launchAdjacent = false break } - if (PROJECT_MANAGER_ARG == arg) { + if (PROJECT_MANAGER_ARG == arg || PROJECT_MANAGER_ARG_SHORT == arg) { targetClass = GodotProjectManager::class.java launchAdjacent = false break @@ -125,7 +132,13 @@ open class GodotEditor : FullScreenGodotApp() { if (launchAdjacent) { newInstance.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT) } - startActivity(newInstance) + if (targetClass == javaClass) { + Log.d(TAG, "Restarting $targetClass") + ProcessPhoenix.triggerRebirth(this, newInstance) + } else { + Log.d(TAG, "Starting $targetClass") + startActivity(newInstance) + } } // Get the screen's density scale diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 92e5e59496..a002a37ab9 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -299,7 +299,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { plugin.onRegisterPluginWithGodotNative(); } - setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on"))); + setKeepScreenOn(Boolean.parseBoolean(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on"))); }); // Include the returned non-null views in the Godot view hierarchy. diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index b5cb9d341d..c2c25601d7 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -71,6 +71,39 @@ static Vector3 gravity; static Vector3 magnetometer; static Vector3 gyroscope; +static void _terminate(JNIEnv *env, bool p_restart = false) { + step.set(-1); // Ensure no further steps are attempted and no further events are sent + + // lets cleanup + if (java_class_wrapper) { + memdelete(java_class_wrapper); + } + if (input_handler) { + delete input_handler; + } + // Whether restarting is handled by 'Main::cleanup()' + bool restart_on_cleanup = false; + if (os_android) { + restart_on_cleanup = os_android->is_restart_on_exit_set(); + os_android->main_loop_end(); + Main::cleanup(); + delete os_android; + } + if (godot_io_java) { + delete godot_io_java; + } + if (godot_java) { + if (!restart_on_cleanup) { + if (p_restart) { + godot_java->restart(env); + } else { + godot_java->force_quit(env); + } + } + delete godot_java; + } +} + extern "C" { JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jclass clazz, jint p_height) { @@ -104,23 +137,7 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz) { - // lets cleanup - if (java_class_wrapper) { - memdelete(java_class_wrapper); - } - if (godot_io_java) { - delete godot_io_java; - } - if (godot_java) { - delete godot_java; - } - if (input_handler) { - delete input_handler; - } - if (os_android) { - os_android->main_loop_end(); - delete os_android; - } + _terminate(env, false); } JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline) { @@ -196,9 +213,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en } } else { // Rendering context recreated because it was lost; restart app to let it reload everything - step.set(-1); // Ensure no further steps are attempted and no further events are sent - os_android->main_loop_end(); - godot_java->restart(env); + _terminate(env, true); } } } @@ -249,7 +264,7 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, bool should_swap_buffers = false; if (os_android->main_loop_iterate(&should_swap_buffers)) { - godot_java->force_quit(env); + _terminate(env, false); } return should_swap_buffers; diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 8e4d91ac50..33f1071077 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -49,6 +49,46 @@ Vector<EditorExportPlatformIOS::ExportArchitecture> EditorExportPlatformIOS::_ge return archs; } +struct IconInfo { + const char *preset_key; + const char *idiom; + const char *export_name; + const char *actual_size_side; + const char *scale; + const char *unscaled_size; + const bool force_opaque; +}; + +static const IconInfo icon_infos[] = { + // Home screen on iPhone + { PNAME("icons/iphone_120x120"), "iphone", "Icon-120.png", "120", "2x", "60x60", false }, + { PNAME("icons/iphone_120x120"), "iphone", "Icon-120.png", "120", "3x", "40x40", false }, + { PNAME("icons/iphone_180x180"), "iphone", "Icon-180.png", "180", "3x", "60x60", false }, + + // Home screen on iPad + { PNAME("icons/ipad_76x76"), "ipad", "Icon-76.png", "76", "1x", "76x76", false }, + { PNAME("icons/ipad_152x152"), "ipad", "Icon-152.png", "152", "2x", "76x76", false }, + { PNAME("icons/ipad_167x167"), "ipad", "Icon-167.png", "167", "2x", "83.5x83.5", false }, + + // App Store + { PNAME("icons/app_store_1024x1024"), "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024", true }, + + // Spotlight + { PNAME("icons/spotlight_40x40"), "ipad", "Icon-40.png", "40", "1x", "40x40", false }, + { PNAME("icons/spotlight_80x80"), "iphone", "Icon-80.png", "80", "2x", "40x40", false }, + { PNAME("icons/spotlight_80x80"), "ipad", "Icon-80.png", "80", "2x", "40x40", false }, + + // Settings + { PNAME("icons/settings_58x58"), "iphone", "Icon-58.png", "58", "2x", "29x29", false }, + { PNAME("icons/settings_58x58"), "ipad", "Icon-58.png", "58", "2x", "29x29", false }, + { PNAME("icons/settings_87x87"), "iphone", "Icon-87.png", "87", "3x", "29x29", false }, + + // Notification + { PNAME("icons/notification_40x40"), "iphone", "Icon-40.png", "40", "2x", "20x20", false }, + { PNAME("icons/notification_40x40"), "ipad", "Icon-40.png", "40", "2x", "20x20", false }, + { PNAME("icons/notification_60x60"), "iphone", "Icon-60.png", "60", "3x", "20x20", false } +}; + struct LoadingScreenInfo { const char *preset_key; const char *export_name; @@ -97,6 +137,9 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/launch_screens_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4)); + Vector<PluginConfigIOS> found_plugins = get_plugins(); for (int i = 0; i < found_plugins.size(); i++) { r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("plugins"), found_plugins[i].name)), false)); @@ -139,18 +182,13 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need access to the photo library"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photolibrary_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone/iPod Touch with Retina display - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone with Retina HD display - - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad with Retina display - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad Pro - - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // App Store - - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight on devices with Retina display - + HashSet<String> used_names; + for (uint64_t i = 0; i < sizeof(icon_infos) / sizeof(icon_infos[0]); ++i) { + if (!used_names.has(icon_infos[i].preset_key)) { + used_names.insert(icon_infos[i].preset_key); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, icon_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); + } + } r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); @@ -531,36 +569,6 @@ void EditorExportPlatformIOS::_blend_and_rotate(Ref<Image> &p_dst, Ref<Image> &p } } -struct IconInfo { - const char *preset_key; - const char *idiom; - const char *export_name; - const char *actual_size_side; - const char *scale; - const char *unscaled_size; - const bool force_opaque; -}; - -static const IconInfo icon_infos[] = { - // Home screen on iPhone - { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60", false }, - { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40", false }, - { "icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60", false }, - - // Home screen on iPad - { "icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76", false }, - { "icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76", false }, - { "icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5", false }, - - // App Store - { "icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024", true }, - - // Spotlight - { "icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40", false }, - { "icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40", false }, - { "icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40", false } -}; - Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir) { String json_description = "{\"images\":["; String sizes; @@ -568,6 +576,8 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr Ref<DirAccess> da = DirAccess::open(p_iconset_dir); ERR_FAIL_COND_V_MSG(da.is_null(), ERR_CANT_OPEN, "Cannot open directory '" + p_iconset_dir + "'."); + Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color"); + for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { IconInfo info = icon_infos[i]; int side_size = String(info.actual_size_side).to_int(); @@ -580,13 +590,17 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr if (err != OK) { add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path)); return ERR_UNCONFIGURED; + } else if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) { + add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key)); + img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int())); + Ref<Image> new_img = Image::create_empty(side_size, side_size, false, Image::FORMAT_RGBA8); + new_img->fill(boot_bg_color); + _blend_and_rotate(new_img, img, false); + err = new_img->save_png(p_iconset_dir + info.export_name); + } else { + img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int())); + err = img->save_png(p_iconset_dir + info.export_name); } - if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) { - add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key)); - return ERR_UNCONFIGURED; - } - img->resize(side_size, side_size); - err = img->save_png(p_iconset_dir + info.export_name); if (err) { add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path)); return err; @@ -598,14 +612,16 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr if (err != OK) { add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path)); return ERR_UNCONFIGURED; - } - if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) { - add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key)); - return ERR_UNCONFIGURED; - } - if (img->get_width() != side_size || img->get_height() != side_size) { + } else if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) { + add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key)); + img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int())); + Ref<Image> new_img = Image::create_empty(side_size, side_size, false, Image::FORMAT_RGBA8); + new_img->fill(boot_bg_color); + _blend_and_rotate(new_img, img, false); + err = new_img->save_png(p_iconset_dir + info.export_name); + } else if (img->get_width() != side_size || img->get_height() != side_size) { add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s): '%s' has incorrect size %s and was automatically resized to %s.", info.preset_key, icon_path, img->get_size(), Vector2i(side_size, side_size))); - img->resize(side_size, side_size); + img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int())); err = img->save_png(p_iconset_dir + info.export_name); } else { err = da->copy(icon_path, p_iconset_dir + info.export_name); @@ -650,7 +666,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor Ref<Image> image; String image_path = p_dest_dir.path_join("splash@2x.png"); image.instantiate(); - Error err = image->load(custom_launch_image_2x); + Error err = ImageLoader::load_image(custom_launch_image_2x, image); if (err) { image.unref(); @@ -664,7 +680,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor image.unref(); image_path = p_dest_dir.path_join("splash@3x.png"); image.instantiate(); - err = image->load(custom_launch_image_3x); + err = ImageLoader::load_image(custom_launch_image_3x, image); if (err) { image.unref(); @@ -681,7 +697,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor if (!splash_path.is_empty()) { splash.instantiate(); - const Error err = splash->load(splash_path); + const Error err = ImageLoader::load_image(splash_path, splash); if (err) { splash.unref(); } @@ -735,9 +751,9 @@ Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExp float aspect_ratio = (float)img->get_width() / (float)img->get_height(); if (boot_logo_scale) { if (info.height * aspect_ratio <= info.width) { - img->resize(info.height * aspect_ratio, info.height); + img->resize(info.height * aspect_ratio, info.height, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); } else { - img->resize(info.width, info.width / aspect_ratio); + img->resize(info.width, info.width / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); } } Ref<Image> new_img = Image::create_empty(info.width, info.height, false, Image::FORMAT_RGBA8); @@ -771,17 +787,17 @@ Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExp if (info.rotate) { if (boot_logo_scale) { if (info.width * aspect_ratio <= info.height) { - img_bs->resize(info.width * aspect_ratio, info.width); + img_bs->resize(info.width * aspect_ratio, info.width, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); } else { - img_bs->resize(info.height, info.height / aspect_ratio); + img_bs->resize(info.height, info.height / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); } } } else { if (boot_logo_scale) { if (info.height * aspect_ratio <= info.width) { - img_bs->resize(info.height * aspect_ratio, info.height); + img_bs->resize(info.height * aspect_ratio, info.height, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); } else { - img_bs->resize(info.width, info.width / aspect_ratio); + img_bs->resize(info.width, info.width / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int())); } } } diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index 8e75b98302..8f315f736b 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -233,6 +233,7 @@ public: void popup_close(WindowID p_window); void set_is_resizing(bool p_is_resizing); bool get_is_resizing() const; + void reparent_check(WindowID p_window); void window_update(WindowID p_window); void window_destroy(WindowID p_window); diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 3557511c28..3aff5b8b7e 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -2337,22 +2337,64 @@ void DisplayServerMacOS::window_set_current_screen(int p_screen, WindowID p_wind } } -void DisplayServerMacOS::window_set_exclusive(WindowID p_window, bool p_exclusive) { - _THREAD_SAFE_METHOD_ +void DisplayServerMacOS::reparent_check(WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; - if (wd.exclusive != p_exclusive) { - wd.exclusive = p_exclusive; - if (wd.transient_parent != INVALID_WINDOW_ID) { - WindowData &wd_parent = windows[wd.transient_parent]; - if (wd.exclusive) { - ERR_FAIL_COND_MSG([[wd_parent.window_object childWindows] count] > 0, "Transient parent has another exclusive child."); + NSScreen *screen = [wd.window_object screen]; + + if (wd.transient_parent != INVALID_WINDOW_ID) { + WindowData &wd_parent = windows[wd.transient_parent]; + NSScreen *parent_screen = [wd_parent.window_object screen]; + + if (parent_screen == screen) { + if (![[wd_parent.window_object childWindows] containsObject:wd.window_object]) { + if (wd.exclusive) { + ERR_FAIL_COND_MSG([[wd_parent.window_object childWindows] count] > 0, "Transient parent has another exclusive child."); + } + [wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; [wd_parent.window_object addChildWindow:wd.window_object ordered:NSWindowAbove]; - } else { + } + } else { + if ([[wd_parent.window_object childWindows] containsObject:wd.window_object]) { [wd_parent.window_object removeChildWindow:wd.window_object]; + [wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + [wd.window_object orderFront:nil]; } } } + + for (const WindowID &child : wd.transient_children) { + WindowData &wd_child = windows[child]; + NSScreen *child_screen = [wd_child.window_object screen]; + + if (child_screen == screen) { + if (![[wd.window_object childWindows] containsObject:wd_child.window_object]) { + if (wd_child.exclusive) { + ERR_FAIL_COND_MSG([[wd.window_object childWindows] count] > 0, "Transient parent has another exclusive child."); + } + if (wd_child.fullscreen) { + [wd_child.window_object toggleFullScreen:nil]; + } + [wd_child.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + [wd.window_object addChildWindow:wd_child.window_object ordered:NSWindowAbove]; + } + } else { + if ([[wd.window_object childWindows] containsObject:wd_child.window_object]) { + [wd.window_object removeChildWindow:wd_child.window_object]; + [wd_child.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + } + } + } +} + +void DisplayServerMacOS::window_set_exclusive(WindowID p_window, bool p_exclusive) { + _THREAD_SAFE_METHOD_ + ERR_FAIL_COND(!windows.has(p_window)); + WindowData &wd = windows[p_window]; + if (wd.exclusive != p_exclusive) { + wd.exclusive = p_exclusive; + reparent_check(p_window); + } } Point2i DisplayServerMacOS::window_get_position(WindowID p_window) const { @@ -2429,11 +2471,10 @@ void DisplayServerMacOS::window_set_transient(WindowID p_window, WindowID p_pare wd_window.transient_parent = INVALID_WINDOW_ID; wd_parent.transient_children.erase(p_window); - [wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - - if (wd_window.exclusive) { + if ([[wd_parent.window_object childWindows] containsObject:wd_window.window_object]) { [wd_parent.window_object removeChildWindow:wd_window.window_object]; } + [wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; } else { ERR_FAIL_COND(!windows.has(p_parent)); ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent"); @@ -2441,11 +2482,7 @@ void DisplayServerMacOS::window_set_transient(WindowID p_window, WindowID p_pare wd_window.transient_parent = p_parent; wd_parent.transient_children.insert(p_window); - [wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; - - if (wd_window.exclusive) { - [wd_parent.window_object addChildWindow:wd_window.window_object ordered:NSWindowAbove]; - } + reparent_check(p_window); } } diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index de6016cb9b..5860a4f0ae 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -34,6 +34,7 @@ #include "lipo.h" #include "macho.h" +#include "core/io/image_loader.h" #include "core/string/translation.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" @@ -116,7 +117,8 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "debug/export_console_script", PROPERTY_HINT_ENUM, "No,Debug Only,Debug and Release"), 1)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.icns,*.png,*.webp,*.svg"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games")); @@ -268,7 +270,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, memcpy(&p_dest.write[ofs], result.ptr(), res_size); } -void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { +void EditorExportPlatformMacOS::_make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { Ref<ImageTexture> it = memnew(ImageTexture); Vector<uint8_t> data; @@ -302,7 +304,7 @@ void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy? copy->convert(Image::FORMAT_RGBA8); - copy->resize(icon_infos[i].size, icon_infos[i].size); + copy->resize(icon_infos[i].size, icon_infos[i].size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int())); if (icon_infos[i].is_png) { // Encode PNG icon. @@ -726,7 +728,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre String str; int exitcode = 0; - Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true); + Error err = OS::get_singleton()->execute("codesign", args, &str, &exitcode, true); if (err != OK) { add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed.")); return err; @@ -1270,9 +1272,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p } else { Ref<Image> icon; icon.instantiate(); - icon->load(iconpath); - if (!icon->is_empty()) { - _make_icon(icon, data); + err = ImageLoader::load_image(iconpath, icon); + if (err == OK && !icon->is_empty()) { + _make_icon(p_preset, icon, data); } } } diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h index b6ad587caa..af7570c394 100644 --- a/platform/macos/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -53,7 +53,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform { Ref<ImageTexture> logo; void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary); - void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data); + void _make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data); Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path); Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true); diff --git a/platform/macos/godot_application_delegate.mm b/platform/macos/godot_application_delegate.mm index bacdcc2bc4..f1168c685a 100644 --- a/platform/macos/godot_application_delegate.mm +++ b/platform/macos/godot_application_delegate.mm @@ -61,7 +61,9 @@ - (void)applicationDidFinishLaunching:(NSNotification *)notice { NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; - if (nsappname == nil || isatty(STDOUT_FILENO) || isatty(STDIN_FILENO) || isatty(STDERR_FILENO)) { + NSString *nsbundleid_env = [NSString stringWithUTF8String:getenv("__CFBundleIdentifier")]; + NSString *nsbundleid = [[NSBundle mainBundle] bundleIdentifier]; + if (nsappname == nil || isatty(STDOUT_FILENO) || isatty(STDIN_FILENO) || isatty(STDERR_FILENO) || ![nsbundleid isEqualToString:nsbundleid_env]) { // If the executable is started from terminal or is not bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored). [self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02]; } diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm index 3bdbc8c5ec..27efd3ebb2 100644 --- a/platform/macos/godot_window_delegate.mm +++ b/platform/macos/godot_window_delegate.mm @@ -256,6 +256,15 @@ } } +- (void)windowDidChangeScreen:(NSNotification *)notification { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); + if (!ds || !ds->has_window(window_id)) { + return; + } + + ds->reparent_check(window_id); +} + - (void)windowDidMove:(NSNotification *)notification { DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 1cf47217ca..f04177d79a 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -31,7 +31,122 @@ #include "export_plugin.h" #include "core/config/project_settings.h" +#include "core/io/image_loader.h" #include "editor/editor_node.h" +#include "editor/editor_paths.h" + +Error EditorExportPlatformWindows::_process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path) { + static const uint8_t icon_size[] = { 16, 32, 48, 64, 128, 0 /*256*/ }; + + struct IconData { + Vector<uint8_t> data; + uint8_t pal_colors = 0; + uint16_t planes = 0; + uint16_t bpp = 32; + }; + + HashMap<uint8_t, IconData> images; + Error err; + + if (p_src_path.get_extension() == "ico") { + Ref<FileAccess> f = FileAccess::open(p_src_path, FileAccess::READ, &err); + if (err != OK) { + return err; + } + + // Read ICONDIR. + f->get_16(); // Reserved. + uint16_t icon_type = f->get_16(); // Image type: 1 - ICO. + uint16_t icon_count = f->get_16(); // Number of images. + ERR_FAIL_COND_V(icon_type != 1, ERR_CANT_OPEN); + + for (uint16_t i = 0; i < icon_count; i++) { + // Read ICONDIRENTRY. + uint16_t w = f->get_8(); // Width in pixels. + uint16_t h = f->get_8(); // Height in pixels. + uint8_t pal_colors = f->get_8(); // Number of colors in the palette (0 - no palette). + f->get_8(); // Reserved. + uint16_t planes = f->get_16(); // Number of color planes. + uint16_t bpp = f->get_16(); // Bits per pixel. + uint32_t img_size = f->get_32(); // Image data size in bytes. + uint32_t img_offset = f->get_32(); // Image data offset. + if (w != h) { + continue; + } + + // Read image data. + uint64_t prev_offset = f->get_position(); + images[w].pal_colors = pal_colors; + images[w].planes = planes; + images[w].bpp = bpp; + images[w].data.resize(img_size); + f->seek(img_offset); + f->get_buffer(images[w].data.ptrw(), img_size); + f->seek(prev_offset); + } + } else { + Ref<Image> src_image; + src_image.instantiate(); + err = ImageLoader::load_image(p_src_path, src_image); + ERR_FAIL_COND_V(err != OK || src_image->is_empty(), ERR_CANT_OPEN); + for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) { + int size = (icon_size[i] == 0) ? 256 : icon_size[i]; + + Ref<Image> res_image = src_image->duplicate(); + ERR_FAIL_COND_V(res_image.is_null() || res_image->is_empty(), ERR_CANT_OPEN); + res_image->resize(size, size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int())); + images[icon_size[i]].data = res_image->save_png_to_buffer(); + } + } + + uint16_t valid_icon_count = 0; + for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) { + if (images.has(icon_size[i])) { + valid_icon_count++; + } else { + int size = (icon_size[i] == 0) ? 256 : icon_size[i]; + add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Icon size \"%d\" is missing."), size)); + } + } + ERR_FAIL_COND_V(valid_icon_count == 0, ERR_CANT_OPEN); + + Ref<FileAccess> fw = FileAccess::open(p_dst_path, FileAccess::WRITE, &err); + if (err != OK) { + return err; + } + + // Write ICONDIR. + fw->store_16(0); // Reserved. + fw->store_16(1); // Image type: 1 - ICO. + fw->store_16(valid_icon_count); // Number of images. + + // Write ICONDIRENTRY. + uint32_t img_offset = 6 + 16 * valid_icon_count; + for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) { + if (images.has(icon_size[i])) { + const IconData &di = images[icon_size[i]]; + fw->store_8(icon_size[i]); // Width in pixels. + fw->store_8(icon_size[i]); // Height in pixels. + fw->store_8(di.pal_colors); // Number of colors in the palette (0 - no palette). + fw->store_8(0); // Reserved. + fw->store_16(di.planes); // Number of color planes. + fw->store_16(di.bpp); // Bits per pixel. + fw->store_32(di.data.size()); // Image data size in bytes. + fw->store_32(img_offset); // Image data offset. + + img_offset += di.data.size(); + } + } + + // Write image data. + for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) { + if (images.has(icon_size[i])) { + const IconData &di = images[icon_size[i]]; + fw->store_buffer(di.data.ptr(), di.data.size()); + } + } + return OK; +} Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) { if (p_preset->get("codesign/enable")) { @@ -110,8 +225,9 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray())); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/modify_resources"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico.*.png,*.webp,*.svg"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), "")); @@ -154,6 +270,15 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset icon_path = console_icon_path; } } + + String tmp_icon_path = EditorPaths::get_singleton()->get_cache_dir().path_join("_rcedit.ico"); + if (!icon_path.is_empty()) { + if (_process_icon(p_preset, icon_path, tmp_icon_path) != OK) { + add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Invalid icon file \"%s\"."), icon_path)); + icon_path = String(); + } + } + String file_verion = p_preset->get("application/file_version"); String product_version = p_preset->get("application/product_version"); String company_name = p_preset->get("application/company_name"); @@ -167,7 +292,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset args.push_back(p_path); if (!icon_path.is_empty()) { args.push_back("--set-icon"); - args.push_back(icon_path); + args.push_back(tmp_icon_path); } if (!file_verion.is_empty()) { args.push_back("--set-file-version"); @@ -211,6 +336,11 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset String str; Error err = OS::get_singleton()->execute(rcedit_path, args, &str, nullptr, true); + + if (FileAccess::exists(tmp_icon_path)) { + DirAccess::remove_file_or_error(tmp_icon_path); + } + if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) { add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > rcedit), or disable \"Application > Modify Resources\" in the export preset.")); return err; diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index 2671205fca..a9e6d51b9d 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -38,6 +38,7 @@ #include "platform/windows/logo.gen.h" class EditorExportPlatformWindows : public EditorExportPlatformPC { + Error _process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path); Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon); Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 08897bb190..d8548eb545 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -849,7 +849,19 @@ String OS_Windows::get_system_font_path(const String &p_font_name, bool p_bold, if (FAILED(hr)) { continue; } - return String::utf16((const char16_t *)&file_path[0]); + String fpath = String::utf16((const char16_t *)&file_path[0]); + + WIN32_FIND_DATAW d; + HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d); + if (fnd != INVALID_HANDLE_VALUE) { + String fname = String::utf16((const char16_t *)d.cFileName); + if (!fname.is_empty()) { + fpath = fpath.get_base_dir().path_join(fname); + } + FindClose(fnd); + } + + return fpath; } return String(); } diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 9ac3083718..2ded209180 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -284,6 +284,9 @@ bool AudioStreamPlayer2D::is_playing() const { return true; } } + if (setplay.get() >= 0) { + return true; // play() has been called this frame, but no playback exists just yet. + } return false; } diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 0f3e6c7529..7f46ec4c1e 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -34,8 +34,8 @@ #include "scene/scene_string_names.h" void PhysicsBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("move_and_collide", "motion", "test_only", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("test_move", "from", "motion", "collision", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08), DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with); @@ -54,8 +54,8 @@ PhysicsBody2D::~PhysicsBody2D() { } } -Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_distance, bool p_test_only, real_t p_margin, bool p_recovery_as_collision) { - PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_distance, p_margin); +Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin, bool p_recovery_as_collision) { + PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_motion, p_margin); parameters.recovery_as_collision = p_recovery_as_collision; PhysicsServer2D::MotionResult result; @@ -128,7 +128,7 @@ bool PhysicsBody2D::move_and_collide(const PhysicsServer2D::MotionParameters &p_ return colliding; } -bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision, real_t p_margin, bool p_recovery_as_collision) { +bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision, real_t p_margin, bool p_recovery_as_collision) { ERR_FAIL_COND_V(!is_inside_tree(), false); PhysicsServer2D::MotionResult *r = nullptr; @@ -140,7 +140,7 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distan r = &temp_result; } - PhysicsServer2D::MotionParameters parameters(p_from, p_distance, p_margin); + PhysicsServer2D::MotionParameters parameters(p_from, p_motion, p_margin); parameters.recovery_as_collision = p_recovery_as_collision; return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r); @@ -162,14 +162,14 @@ TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() { void PhysicsBody2D::add_collision_exception_with(Node *p_node) { ERR_FAIL_NULL(p_node); PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node); - ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two objects of PhysicsBody2D type."); + ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two nodes that inherit from PhysicsBody2D."); PhysicsServer2D::get_singleton()->body_add_collision_exception(get_rid(), physics_body->get_rid()); } void PhysicsBody2D::remove_collision_exception_with(Node *p_node) { ERR_FAIL_NULL(p_node); PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node); - ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two objects of PhysicsBody2D type."); + ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two nodes that inherit from PhysicsBody2D."); PhysicsServer2D::get_singleton()->body_remove_collision_exception(get_rid(), physics_body->get_rid()); } diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 932ec1de16..504e1dc333 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -47,11 +47,11 @@ protected: Ref<KinematicCollision2D> motion_cache; - Ref<KinematicCollision2D> _move(const Vector2 &p_distance, bool p_test_only = false, real_t p_margin = 0.08, bool p_recovery_as_collision = false); + Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_test_only = false, real_t p_margin = 0.08, bool p_recovery_as_collision = false); public: bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); - bool test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08, bool p_recovery_as_collision = false); + bool test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08, bool p_recovery_as_collision = false); TypedArray<PhysicsBody2D> get_collision_exceptions(); void add_collision_exception_with(Node *p_node); //must be physicsbody diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 5e77902977..2c825e8f7b 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -114,7 +114,7 @@ void Polygon2D::_notification(int p_what) { ObjectID new_skeleton_id; - if (skeleton_node) { + if (skeleton_node && !invert && bone_weights.size()) { RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton()); new_skeleton_id = skeleton_node->get_instance_id(); } else { diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 40e8818262..0159e9f313 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -1859,11 +1859,13 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_ while (q_list_element) { TileMapQuadrant &q = *q_list_element->self(); - // Clear the scenes. - for (const KeyValue<Vector2i, String> &E : q.scenes) { - Node *node = get_node_or_null(E.value); - if (node) { - node->queue_free(); + // Clear the scenes if instance cache was cleared. + if (instantiated_scenes.is_empty()) { + for (const KeyValue<Vector2i, String> &E : q.scenes) { + Node *node = get_node_or_null(E.value); + if (node) { + node->queue_free(); + } } } @@ -1871,6 +1873,15 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_ // Recreate the scenes. for (const Vector2i &E_cell : q.cells) { + Vector3i cell_coords = Vector3i(q.layer, E_cell.x, E_cell.y); + if (instantiated_scenes.has(cell_coords)) { + // Skip scene if the instance was cached (to avoid recreating scenes unnecessarily). + continue; + } + if (!Engine::get_singleton()->is_editor_hint()) { + instantiated_scenes.insert(cell_coords); + } + const TileMapCell &c = get_cell(q.layer, E_cell, true); TileSetSource *source; @@ -1907,15 +1918,16 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_ } void TileMap::_scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant) { - // Clear the scenes. - for (const KeyValue<Vector2i, String> &E : p_quadrant->scenes) { - Node *node = get_node_or_null(E.value); - if (node) { - node->queue_free(); + // Clear the scenes if instance cache was cleared. + if (instantiated_scenes.is_empty()) { + for (const KeyValue<Vector2i, String> &E : p_quadrant->scenes) { + Node *node = get_node_or_null(E.value); + if (node) { + node->queue_free(); + } } + p_quadrant->scenes.clear(); } - - p_quadrant->scenes.clear(); } void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { @@ -4037,6 +4049,7 @@ void TileMap::_bind_methods() { void TileMap::_tile_set_changed() { emit_signal(SNAME("changed")); _tile_set_changed_deferred_update_needed = true; + instantiated_scenes.clear(); call_deferred(SNAME("_tile_set_changed_deferred_update")); } diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index eaf100631e..68a5d3c80b 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -236,6 +236,8 @@ private: void _clear_layer_internals(int p_layer); void _clear_internals(); + HashSet<Vector3i> instantiated_scenes; + // Rect caching. void _recompute_rect_cache(); diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index b9d95672fe..75e840c24b 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -606,6 +606,9 @@ bool AudioStreamPlayer3D::is_playing() const { return true; } } + if (setplay.get() >= 0) { + return true; // play() has been called this frame, but no playback exists just yet. + } return false; } diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index ab4cba86fb..02ab297d8e 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -182,125 +182,31 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { if (bl == 0.0) { return; } - real_t bi = c->get_bake_interval(); - real_t o_next = progress + bi; - real_t o_prev = progress - bi; - - if (loop) { - o_next = Math::fposmod(o_next, bl); - o_prev = Math::fposmod(o_prev, bl); - } else if (rotation_mode == ROTATION_ORIENTED) { - if (o_next >= bl) { - o_next = bl; - } - if (o_prev <= 0) { - o_prev = 0; - } - } - - Vector3 pos = c->sample_baked(progress, cubic); - Transform3D t = get_transform(); - // Vector3 pos_offset = Vector3(h_offset, v_offset, 0); not used in all cases - // will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formerly used - - if (rotation_mode == ROTATION_ORIENTED) { - Vector3 forward = c->sample_baked(o_next, cubic) - pos; - - // Try with the previous position - if (forward.length_squared() < CMP_EPSILON2) { - forward = pos - c->sample_baked(o_prev, cubic); - } - - if (forward.length_squared() < CMP_EPSILON2) { - forward = Vector3(0, 0, 1); - } else { - forward.normalize(); - } - - Vector3 up = c->sample_baked_up_vector(progress, true); - if (o_next < progress) { - Vector3 up1 = c->sample_baked_up_vector(o_next, true); - Vector3 axis = up.cross(up1); - - if (axis.length_squared() < CMP_EPSILON2) { - axis = forward; - } else { - axis.normalize(); - } - - up.rotate(axis, up.angle_to(up1) * 0.5f); - } - - Vector3 scale = t.basis.get_scale(); - Vector3 sideways = up.cross(forward).normalized(); - up = forward.cross(sideways).normalized(); - - t.basis.set_columns(sideways, up, forward); - t.basis.scale_local(scale); - - t.origin = pos + sideways * h_offset + up * v_offset; - } else if (rotation_mode != ROTATION_NONE) { - // perform parallel transport - // - // see C. Dougan, The Parallel Transport Frame, Game Programming Gems 2 for example - // for a discussion about why not Frenet frame. + Transform3D t; + if (rotation_mode == ROTATION_NONE) { + Vector3 pos = c->sample_baked(progress, cubic); t.origin = pos; - if (p_update_xyz_rot && prev_offset != progress) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree. - real_t sample_distance = bi * 0.01; - Vector3 t_prev_pos_a = c->sample_baked(prev_offset - sample_distance, cubic); - Vector3 t_prev_pos_b = c->sample_baked(prev_offset + sample_distance, cubic); - Vector3 t_cur_pos_a = c->sample_baked(progress - sample_distance, cubic); - Vector3 t_cur_pos_b = c->sample_baked(progress + sample_distance, cubic); - Vector3 t_prev = (t_prev_pos_a - t_prev_pos_b).normalized(); - Vector3 t_cur = (t_cur_pos_a - t_cur_pos_b).normalized(); - - Vector3 axis = t_prev.cross(t_cur); - real_t dot = t_prev.dot(t_cur); - real_t angle = Math::acos(CLAMP(dot, -1, 1)); - - if (likely(!Math::is_zero_approx(angle))) { - if (rotation_mode == ROTATION_Y) { - // assuming we're referring to global Y-axis. is this correct? - axis.x = 0; - axis.z = 0; - } else if (rotation_mode == ROTATION_XY) { - axis.z = 0; - } else if (rotation_mode == ROTATION_XYZ) { - // all components are allowed - } + } else { + t = c->sample_baked_with_rotation(progress, cubic, false); + Vector3 forward = t.basis.get_column(2); // Retain tangent for applying tilt + t = PathFollow3D::correct_posture(t, rotation_mode); - if (likely(!Math::is_zero_approx(axis.length()))) { - t.rotate_basis(axis.normalized(), angle); - } - } + // Apply tilt *after* correct_posture + if (tilt_enabled) { + const real_t tilt = c->sample_baked_tilt(progress); - // do the additional tilting - real_t tilt_angle = c->sample_baked_tilt(progress); - Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct?? - - if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) { - if (rotation_mode == ROTATION_Y) { - tilt_axis.x = 0; - tilt_axis.z = 0; - } else if (rotation_mode == ROTATION_XY) { - tilt_axis.z = 0; - } else if (rotation_mode == ROTATION_XYZ) { - // all components are allowed - } - - if (likely(!Math::is_zero_approx(tilt_axis.length()))) { - t.rotate_basis(tilt_axis.normalized(), tilt_angle); - } - } + const Basis twist(forward, tilt); + t.basis = twist * t.basis; } - - t.translate_local(Vector3(h_offset, v_offset, 0)); - } else { - t.origin = pos + Vector3(h_offset, v_offset, 0); } + Vector3 scale = get_transform().basis.get_scale(); + + t.translate_local(Vector3(h_offset, v_offset, 0)); + t.basis.scale_local(scale); + set_transform(t); } @@ -358,6 +264,38 @@ PackedStringArray PathFollow3D::get_configuration_warnings() const { return warnings; } +Transform3D PathFollow3D::correct_posture(Transform3D p_transform, PathFollow3D::RotationMode p_rotation_mode) { + Transform3D t = p_transform; + + // Modify frame according to rotation mode. + if (p_rotation_mode == PathFollow3D::ROTATION_NONE) { + // Clear rotation. + t.basis = Basis(); + } else if (p_rotation_mode == PathFollow3D::ROTATION_ORIENTED) { + // Y-axis always straight up. + Vector3 up(0.0, 1.0, 0.0); + Vector3 forward = t.basis.get_column(2); + + t.basis = Basis::looking_at(-forward, up); + } else { + // Lock some euler axes. + Vector3 euler = t.basis.get_euler_normalized(EulerOrder::YXZ); + if (p_rotation_mode == PathFollow3D::ROTATION_Y) { + // Only Y-axis allowed. + euler[0] = 0; + euler[2] = 0; + } else if (p_rotation_mode == PathFollow3D::ROTATION_XY) { + // XY allowed. + euler[2] = 0; + } + + Basis locked = Basis::from_euler(euler, EulerOrder::YXZ); + t.basis = locked; + } + + return t; +} + void PathFollow3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_progress", "progress"), &PathFollow3D::set_progress); ClassDB::bind_method(D_METHOD("get_progress"), &PathFollow3D::get_progress); @@ -380,6 +318,11 @@ void PathFollow3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow3D::set_loop); ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow3D::has_loop); + ClassDB::bind_method(D_METHOD("set_tilt_enabled", "enabled"), &PathFollow3D::set_tilt_enabled); + ClassDB::bind_method(D_METHOD("is_tilt_enabled"), &PathFollow3D::is_tilt_enabled); + + ClassDB::bind_static_method("PathFollow3D", D_METHOD("correct_posture", "transform", "rotation_mode"), &PathFollow3D::correct_posture); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_less,or_greater,suffix:m"), "set_progress", "get_progress"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_less,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_h_offset", "get_h_offset"); @@ -387,6 +330,7 @@ void PathFollow3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ,Oriented"), "set_rotation_mode", "get_rotation_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tilt_enabled"), "set_tilt_enabled", "is_tilt_enabled"); BIND_ENUM_CONSTANT(ROTATION_NONE); BIND_ENUM_CONSTANT(ROTATION_Y); @@ -397,7 +341,6 @@ void PathFollow3D::_bind_methods() { void PathFollow3D::set_progress(real_t p_progress) { ERR_FAIL_COND(!isfinite(p_progress)); - prev_offset = progress; progress = p_progress; if (path) { @@ -409,8 +352,6 @@ void PathFollow3D::set_progress(real_t p_progress) { if (!Math::is_zero_approx(p_progress) && Math::is_zero_approx(progress)) { progress = path_length; } - } else { - progress = CLAMP(progress, 0, path_length); } } @@ -476,3 +417,11 @@ void PathFollow3D::set_loop(bool p_loop) { bool PathFollow3D::has_loop() const { return loop; } + +void PathFollow3D::set_tilt_enabled(bool p_enable) { + tilt_enabled = p_enable; +} + +bool PathFollow3D::is_tilt_enabled() const { + return tilt_enabled; +} diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h index b161b12185..9d5f694247 100644 --- a/scene/3d/path_3d.h +++ b/scene/3d/path_3d.h @@ -72,14 +72,16 @@ public: ROTATION_ORIENTED }; + static Transform3D correct_posture(Transform3D p_transform, PathFollow3D::RotationMode p_rotation_mode); + private: Path3D *path = nullptr; - real_t prev_offset = 0.0; // Offset during the last _update_transform. real_t progress = 0.0; real_t h_offset = 0.0; real_t v_offset = 0.0; bool cubic = true; bool loop = true; + bool tilt_enabled = true; RotationMode rotation_mode = ROTATION_XYZ; void _update_transform(bool p_update_xyz_rot = true); @@ -106,6 +108,9 @@ public: void set_loop(bool p_loop); bool has_loop() const; + void set_tilt_enabled(bool p_enable); + bool is_tilt_enabled() const; + void set_rotation_mode(RotationMode p_rotation_mode); RotationMode get_rotation_mode() const; diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index d9fa37ce74..d29f337fc8 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -34,8 +34,8 @@ #include "scene/scene_string_names.h" void PhysicsBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); - ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("move_and_collide", "motion", "test_only", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("test_move", "from", "motion", "collision", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock); ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock); @@ -80,19 +80,19 @@ TypedArray<PhysicsBody3D> PhysicsBody3D::get_collision_exceptions() { void PhysicsBody3D::add_collision_exception_with(Node *p_node) { ERR_FAIL_NULL(p_node); CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node); - ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds."); + ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D)."); PhysicsServer3D::get_singleton()->body_add_collision_exception(get_rid(), collision_object->get_rid()); } void PhysicsBody3D::remove_collision_exception_with(Node *p_node) { ERR_FAIL_NULL(p_node); CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node); - ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds."); + ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D)."); PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid()); } -Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_distance, bool p_test_only, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) { - PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_distance, p_margin); +Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) { + PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_motion, p_margin); parameters.max_collisions = p_max_collisions; parameters.recovery_as_collision = p_recovery_as_collision; @@ -169,7 +169,7 @@ bool PhysicsBody3D::move_and_collide(const PhysicsServer3D::MotionParameters &p_ return colliding; } -bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) { +bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) { ERR_FAIL_COND_V(!is_inside_tree(), false); PhysicsServer3D::MotionResult *r = nullptr; @@ -181,7 +181,7 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_distan r = &temp_result; } - PhysicsServer3D::MotionParameters parameters(p_from, p_distance, p_margin); + PhysicsServer3D::MotionParameters parameters(p_from, p_motion, p_margin); parameters.recovery_as_collision = p_recovery_as_collision; return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r); diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 4b874b91d9..36b7ce774c 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -50,11 +50,11 @@ protected: uint16_t locked_axis = 0; - Ref<KinematicCollision3D> _move(const Vector3 &p_distance, bool p_test_only = false, real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); + Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_test_only = false, real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); public: bool move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); - bool test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); + bool test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index 83e3369423..1814baa9e9 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -607,14 +607,14 @@ TypedArray<PhysicsBody3D> SoftBody3D::get_collision_exceptions() { void SoftBody3D::add_collision_exception_with(Node *p_node) { ERR_FAIL_NULL(p_node); CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node); - ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds."); + ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D)."); PhysicsServer3D::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid()); } void SoftBody3D::remove_collision_exception_with(Node *p_node) { ERR_FAIL_NULL(p_node); CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node); - ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds."); + ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D)."); PhysicsServer3D::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid()); } diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index f30aea3bdd..3153572517 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -309,8 +309,8 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_see if (i == point_lower || i == point_higher) { double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, weights[i], FILTER_IGNORE, true); max_time_remaining = MAX(max_time_remaining, remaining); - } else { - blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync); + } else if (sync) { + blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true); } } diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index 0d8b7ba8f7..b376f668ad 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -512,8 +512,8 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see } } - if (!found) { - blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync); + if (sync && !found) { + blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true); } } } else { @@ -550,9 +550,11 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see mind = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true); } - for (int i = 0; i < blend_points_used; i++) { - if (i != cur_closest) { - blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync); + if (sync) { + for (int i = 0; i < blend_points_used; i++) { + if (i != cur_closest) { + blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true); + } } } } diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 0c91729a6f..846c102e3f 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -726,9 +726,11 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_ double rem = 0.0; - for (int i = 0; i < enabled_inputs; i++) { - if (i != cur_current && i != cur_prev) { - blend_input(i, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync); + if (sync) { + for (int i = 0; i < enabled_inputs; i++) { + if (i != cur_current && i != cur_prev) { + blend_input(i, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true); + } } } diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 59930a3fbb..85bc4e9814 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1442,11 +1442,11 @@ void AnimationPlayer::remove_animation_library(const StringName &p_name) { } void AnimationPlayer::_ref_anim(const Ref<Animation> &p_anim) { - Ref<Animation>(p_anim)->connect(SceneStringNames::get_singleton()->tracks_changed, callable_mp(this, &AnimationPlayer::_animation_changed), CONNECT_REFERENCE_COUNTED); + Ref<Animation>(p_anim)->connect("changed", callable_mp(this, &AnimationPlayer::_animation_changed), CONNECT_REFERENCE_COUNTED); } void AnimationPlayer::_unref_anim(const Ref<Animation> &p_anim) { - Ref<Animation>(p_anim)->disconnect(SceneStringNames::get_singleton()->tracks_changed, callable_mp(this, &AnimationPlayer::_animation_changed)); + Ref<Animation>(p_anim)->disconnect("changed", callable_mp(this, &AnimationPlayer::_animation_changed)); } void AnimationPlayer::rename_animation_library(const StringName &p_name, const StringName &p_new_name) { diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 517908077d..99d450fa5b 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -221,7 +221,7 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri } blendw[i] = blendr[i] * p_blend; - if (blendw[i] > CMP_EPSILON) { + if (!Math::is_zero_approx(blendw[i])) { any_valid = true; } } @@ -236,7 +236,7 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri } blendw[i] = blendr[i] * p_blend; - if (blendw[i] > CMP_EPSILON) { + if (!Math::is_zero_approx(blendw[i])) { any_valid = true; } } @@ -252,7 +252,7 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri blendw[i] = blendr[i]; //not filtered, do not blend } - if (blendw[i] > CMP_EPSILON) { + if (!Math::is_zero_approx(blendw[i])) { any_valid = true; } } @@ -263,7 +263,7 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri for (int i = 0; i < blend_count; i++) { //regular blend blendw[i] = blendr[i] * p_blend; - if (blendw[i] > CMP_EPSILON) { + if (!Math::is_zero_approx(blendw[i])) { any_valid = true; } } @@ -289,11 +289,8 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri new_path = String(parent->base_path) + String(p_subpath) + "/"; } - // If tracks for blending don't exist for one of the animations, Rest or RESET animation is blended as init animation instead. - // Then blend weight is 0 means that the init animation blend weight is 1. - // In that case, processing only the animation with the lacking track will not process the lacking track, and will not properly apply the Reset value. - // This means that all tracks which the animations in the branch that may be blended have must be processed. - // Therefore, the blending process must be executed even if the blend weight is 0. + // This process, which depends on p_sync is needed to process sync correctly in the case of + // that a synced AnimationNodeSync exists under the un-synced AnimationNodeSync. if (!p_seek && !p_sync && !any_valid) { return p_node->_pre_process(new_path, new_parent, state, 0, p_seek, p_seek_root, p_connections); } @@ -589,6 +586,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { track_value->object = child; } + track_value->is_discrete = anim->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE || anim->value_track_get_update_mode(i) == Animation::UPDATE_TRIGGER; track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE; track_value->subpath = leftover_path; @@ -596,6 +594,13 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { track = track_value; + // If a value track without a key is cached first, the initial value cannot be determined. + // It is a corner case, but which may cause problems with blending. + ERR_CONTINUE_MSG(anim->track_get_key_count(i) == 0, "AnimationTree: '" + String(E) + "', value track: '" + String(path) + "' must have at least one key to cache for blending."); + track_value->init_value = anim->track_get_key_value(i, 0); + track_value->init_value.zero(); + + // If there is a Reset Animation, it takes precedence by overwriting. if (has_reset_anim) { int rt = reset_anim->find_track(path, track_type); if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) { @@ -796,6 +801,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { } else if (track_cache_type == Animation::TYPE_VALUE) { // If it has at least one angle interpolation, it also uses angle interpolation for blending. TrackCacheValue *track_value = memnew(TrackCacheValue); + track_value->is_discrete |= anim->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE || anim->value_track_get_update_mode(i) == Animation::UPDATE_TRIGGER; track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE; } @@ -955,8 +961,44 @@ void AnimationTree::_process_graph(double p_delta) { if (!state.valid) { return; //state is not valid. do nothing. } - //apply value/transform/bezier blends to track caches and execute method/audio/animation tracks + // Init all value/transform/blend/bezier tracks that track_cache has. + { + for (const KeyValue<NodePath, TrackCache *> &K : track_cache) { + TrackCache *track = K.value; + + switch (track->type) { + case Animation::TYPE_POSITION_3D: { + TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); + if (track->root_motion) { + t->loc = Vector3(0, 0, 0); + t->rot = Quaternion(0, 0, 0, 1); + t->scale = Vector3(0, 0, 0); + } else { + t->loc = t->init_loc; + t->rot = t->init_rot; + t->scale = t->init_scale; + } + } break; + case Animation::TYPE_BLEND_SHAPE: { + TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track); + t->value = t->init_value; + } break; + case Animation::TYPE_VALUE: { + TrackCacheValue *t = static_cast<TrackCacheValue *>(track); + t->value = t->init_value; + } break; + case Animation::TYPE_BEZIER: { + TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track); + t->value = t->init_value; + } break; + default: { + } break; + } + } + } + + // Apply value/transform/blend/bezier blends to track caches and execute method/audio/animation tracks. { bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint(); @@ -968,7 +1010,7 @@ void AnimationTree::_process_graph(double p_delta) { bool seeked = as.seeked; int pingponged = as.pingponged; #ifndef _3D_DISABLED - bool backward = signbit(delta); + bool backward = signbit(delta); // This flag is required only for the root motion since it calculates the difference between the previous and current frames. bool calc_root = !seeked || as.seek_root; #endif // _3D_DISABLED @@ -978,37 +1020,29 @@ void AnimationTree::_process_graph(double p_delta) { } NodePath path = a->track_get_path(i); - ERR_CONTINUE(!track_cache.has(path)); - TrackCache *track = track_cache[path]; + ERR_CONTINUE(!state.track_map.has(path)); + int blend_idx = state.track_map[path]; + ERR_CONTINUE(blend_idx < 0 || blend_idx >= state.track_count); + real_t blend = (*as.track_blends)[blend_idx] * weight; + if (Math::is_zero_approx(blend)) { + continue; // Nothing to blend. + } + Animation::TrackType ttype = a->track_get_type(i); if (ttype != Animation::TYPE_POSITION_3D && ttype != Animation::TYPE_ROTATION_3D && ttype != Animation::TYPE_SCALE_3D && track->type != ttype) { //broken animation, but avoid error spamming continue; } - track->root_motion = root_motion_track == path; - ERR_CONTINUE(!state.track_map.has(path)); - int blend_idx = state.track_map[path]; - - ERR_CONTINUE(blend_idx < 0 || blend_idx >= state.track_count); - - real_t blend = (*as.track_blends)[blend_idx] * weight; - switch (ttype) { case Animation::TYPE_POSITION_3D: { #ifndef _3D_DISABLED TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); if (track->root_motion && calc_root) { - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->loc = Vector3(0, 0, 0); - t->rot = Quaternion(0, 0, 0, 1); - t->scale = Vector3(0, 0, 0); - } double prev_time = time - delta; if (!backward) { if (prev_time < 0) { @@ -1084,12 +1118,6 @@ void AnimationTree::_process_graph(double p_delta) { prev_time = !backward ? 0 : (double)a->get_length(); } else { - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->loc = t->init_loc; - t->rot = t->init_rot; - t->scale = t->init_scale; - } Vector3 loc; Error err = a->position_track_interpolate(i, time, &loc); @@ -1106,12 +1134,6 @@ void AnimationTree::_process_graph(double p_delta) { #ifndef _3D_DISABLED TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); if (track->root_motion && calc_root) { - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->loc = Vector3(0, 0, 0); - t->rot = Quaternion(0, 0, 0, 1); - t->scale = Vector3(0, 0, 0); - } double prev_time = time - delta; if (!backward) { if (prev_time < 0) { @@ -1186,12 +1208,6 @@ void AnimationTree::_process_graph(double p_delta) { prev_time = !backward ? 0 : (double)a->get_length(); } else { - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->loc = t->init_loc; - t->rot = t->init_rot; - t->scale = t->init_scale; - } Quaternion rot; Error err = a->rotation_track_interpolate(i, time, &rot); @@ -1208,12 +1224,6 @@ void AnimationTree::_process_graph(double p_delta) { #ifndef _3D_DISABLED TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); if (track->root_motion && calc_root) { - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->loc = Vector3(0, 0, 0); - t->rot = Quaternion(0, 0, 0, 1); - t->scale = Vector3(0, 0, 0); - } double prev_time = time - delta; if (!backward) { if (prev_time < 0) { @@ -1289,12 +1299,6 @@ void AnimationTree::_process_graph(double p_delta) { prev_time = !backward ? 0 : (double)a->get_length(); } else { - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->loc = t->init_loc; - t->rot = t->init_rot; - t->scale = t->init_scale; - } Vector3 scale; Error err = a->scale_track_interpolate(i, time, &scale); @@ -1311,11 +1315,6 @@ void AnimationTree::_process_graph(double p_delta) { #ifndef _3D_DISABLED TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track); - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->value = t->init_value; - } - float value; Error err = a->blend_shape_track_interpolate(i, time, &value); @@ -1342,15 +1341,6 @@ void AnimationTree::_process_graph(double p_delta) { continue; } - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - if (!t->init_value) { - t->init_value = value; - t->init_value.zero(); - } - t->value = t->init_value; - } - // Special case for angle interpolation. if (t->is_using_angle) { // For blending consistency, it prevents rotation of more than 180 degrees from init_value. @@ -1379,10 +1369,6 @@ void AnimationTree::_process_graph(double p_delta) { } } } else { - if (blend < CMP_EPSILON) { - continue; //nothing to blend - } - if (seeked) { int idx = a->track_find_key(i, time); if (idx < 0) { @@ -1404,9 +1390,6 @@ void AnimationTree::_process_graph(double p_delta) { } break; case Animation::TYPE_METHOD: { - if (blend < CMP_EPSILON) { - continue; //nothing to blend - } TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track); if (seeked) { @@ -1437,17 +1420,9 @@ void AnimationTree::_process_graph(double p_delta) { real_t bezier = a->bezier_track_interpolate(i, time); bezier = _post_process_key_value(a, i, bezier, t->object); - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->value = t->init_value; - } - t->value += (bezier - t->init_value) * blend; } break; case Animation::TYPE_AUDIO: { - if (blend < CMP_EPSILON) { - continue; //nothing to blend - } TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track); if (seeked) { @@ -1555,9 +1530,6 @@ void AnimationTree::_process_graph(double p_delta) { t->object->call(SNAME("set_volume_db"), db); } break; case Animation::TYPE_ANIMATION: { - if (blend < CMP_EPSILON) { - continue; //nothing to blend - } TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track); AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t->object); @@ -1639,9 +1611,6 @@ void AnimationTree::_process_graph(double p_delta) { // finally, set the tracks for (const KeyValue<NodePath, TrackCache *> &K : track_cache) { TrackCache *track = K.value; - if (track->process_pass != process_pass) { - continue; //not processed, ignore - } switch (track->type) { case Animation::TYPE_POSITION_3D: { @@ -1691,6 +1660,10 @@ void AnimationTree::_process_graph(double p_delta) { case Animation::TYPE_VALUE: { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); + if (t->is_discrete) { + break; // Don't overwrite the value set by UPDATE_DISCRETE or UPDATE_TRIGGER. + } + if (t->init_value.get_type() == Variant::BOOL) { t->object->set_indexed(t->subpath, t->value.operator real_t() >= 0.5); } else { diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 96c1279f82..84d0a8190a 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -190,7 +190,6 @@ private: struct TrackCache { bool root_motion = false; uint64_t setup_pass = 0; - uint64_t process_pass = 0; Animation::TrackType type = Animation::TrackType::TYPE_ANIMATION; Object *object = nullptr; ObjectID object_id; @@ -233,6 +232,7 @@ private: Variant init_value; Variant value; Vector<StringName> subpath; + bool is_discrete = false; bool is_using_angle = false; TrackCacheValue() { type = Animation::TYPE_VALUE; } }; diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp index df27eecce7..599a759b08 100644 --- a/scene/debugger/scene_debugger.cpp +++ b/scene/debugger/scene_debugger.cpp @@ -187,7 +187,7 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA); live_editor->_create_node_func(p_args[0], p_args[1], p_args[2]); - } else if (p_msg == "live_instance_node") { + } else if (p_msg == "live_instantiate_node") { ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA); live_editor->_instance_node_func(p_args[0], p_args[1], p_args[2]); diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index ea310f5a12..9e0dc049e5 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -1425,7 +1425,10 @@ bool CodeEdit::is_line_numbers_zero_padded() const { } void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) { - String fc = TS->format_number(String::num(p_line + 1).lpad(line_number_digits, line_number_padding)); + String fc = String::num(p_line + 1).lpad(line_number_digits, line_number_padding); + if (is_localizing_numeral_system()) { + fc = TS->format_number(fc); + } Ref<TextLine> tl; tl.instantiate(); tl->add_string(fc, font, font_size); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 724e5bcaf6..eb9f9039b7 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -959,7 +959,7 @@ void ColorPicker::_sample_draw() { // Draw both old and new colors for easier comparison (only if spawned from a ColorPickerButton). const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95)); - if (display_old_color && old_color.a < 1.0) { + if (old_color.a < 1.0) { sample->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), rect_old, true); } @@ -1088,7 +1088,9 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { } else if (p_which == 1) { if (actual_shape == SHAPE_HSV_RECTANGLE) { Ref<Texture2D> hue = get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); - c->draw_texture_rect(hue, Rect2(Point2(), c->get_size())); + c->draw_set_transform(Point2(), -Math_PI / 2, Size2(c->get_size().x, -c->get_size().y)); + c->draw_texture_rect(hue, Rect2(Point2(), Size2(1, 1))); + c->draw_set_transform(Point2(), 0, Size2(1, 1)); int y = c->get_size().y - c->get_size().y * (1.0 - h); Color col; col.set_hsv(h, 1, 1); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index c5cb7157e8..4e76f72921 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2773,6 +2773,20 @@ bool Control::is_layout_rtl() const { return data.is_rtl; } +void Control::set_localize_numeral_system(bool p_enable) { + if (p_enable == data.localize_numeral_system) { + return; + } + + data.localize_numeral_system = p_enable; + + notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED); +} + +bool Control::is_localizing_numeral_system() const { + return data.localize_numeral_system; +} + void Control::set_auto_translate(bool p_enable) { if (p_enable == data.auto_translate) { return; @@ -3154,6 +3168,9 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("set_auto_translate", "enable"), &Control::set_auto_translate); ClassDB::bind_method(D_METHOD("is_auto_translating"), &Control::is_auto_translating); + ClassDB::bind_method(D_METHOD("set_localize_numeral_system", "enable"), &Control::set_localize_numeral_system); + ClassDB::bind_method(D_METHOD("is_localizing_numeral_system"), &Control::is_localizing_numeral_system); + ADD_GROUP("Layout", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size"); @@ -3198,8 +3215,9 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_vertical", PROPERTY_HINT_FLAGS, "Fill:1,Expand:2,Shrink Center:4,Shrink End:8"), "set_v_size_flags", "get_v_size_flags"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size_flags_stretch_ratio", PROPERTY_HINT_RANGE, "0,20,0.01,or_greater"), "set_stretch_ratio", "get_stretch_ratio"); - ADD_GROUP("Auto Translate", ""); + ADD_GROUP("Localization", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate"), "set_auto_translate", "is_auto_translating"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "localize_numeral_system"), "set_localize_numeral_system", "is_localizing_numeral_system"); ADD_GROUP("Tooltip", "tooltip_"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "tooltip_text", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip_text", "get_tooltip_text"); diff --git a/scene/gui/control.h b/scene/gui/control.h index 72e870930d..3e9bb48a4a 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -249,6 +249,7 @@ private: bool is_rtl = false; bool auto_translate = true; + bool localize_numeral_system = true; // Extra properties. @@ -595,6 +596,9 @@ public: LayoutDirection get_layout_direction() const; virtual bool is_layout_rtl() const; + void set_localize_numeral_system(bool p_enable); + bool is_localizing_numeral_system() const; + void set_auto_translate(bool p_enable); bool is_auto_translating() const; _FORCE_INLINE_ String atr(const String p_string) const { diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index cade65108c..11a3803b35 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -632,8 +632,11 @@ void FileDialog::update_file_list() { files.pop_front(); } - if (tree->get_root() && tree->get_root()->get_first_child() && tree->get_selected() == nullptr) { - tree->get_root()->get_first_child()->select(0); + if (mode != FILE_MODE_SAVE_FILE) { + // Select the first file from list if nothing is selected. + if (tree->get_root() && tree->get_root()->get_first_child() && tree->get_selected() == nullptr) { + tree->get_root()->get_first_child()->select(0); + } } } diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 0940b4c07b..6d0bbdd6af 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -491,9 +491,9 @@ void OptionButton::show_popup() { return; } - Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale(); - popup->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y)); - popup->set_size(Size2(size.width, 0)); + Size2 button_size = get_global_transform_with_canvas().get_scale() * get_size(); + popup->set_position(get_screen_position() + Size2(0, button_size.height)); + popup->set_size(Size2i(button_size.width, 0)); // If not triggered by the mouse, start the popup with the checked item (or the first enabled one) focused. if (current != NONE_SELECTED && !popup->is_item_disabled(current)) { diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp index 8369eaa227..50bcfa6a0c 100644 --- a/scene/gui/progress_bar.cpp +++ b/scene/gui/progress_bar.cpp @@ -103,7 +103,12 @@ void ProgressBar::_notification(int p_what) { } if (show_percentage) { - String txt = TS->format_number(itos(int(get_as_ratio() * 100))) + TS->percent_sign(); + String txt = itos(int(get_as_ratio() * 100)); + if (is_localizing_numeral_system()) { + txt = TS->format_number(txt) + TS->percent_sign(); + } else { + txt += String("%"); + } TextLine tl = TextLine(txt, theme_cache.font, theme_cache.font_size); Vector2 text_pos = (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round(); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 87cc26187a..a54805ce56 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -752,7 +752,10 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o prefix = _prefix; break; } else if (list_items[i]->list_type == LIST_NUMBERS) { - segment = TS->format_number(itos(list_index[i]), _find_language(l.from)); + segment = itos(list_index[i]); + if (is_localizing_numeral_system()) { + segment = TS->format_number(segment, _find_language(l.from)); + } } else if (list_items[i]->list_type == LIST_LETTERS) { segment = _letters(list_index[i], list_items[i]->capitalize); } else if (list_items[i]->list_type == LIST_ROMAN) { @@ -2686,6 +2689,7 @@ bool RichTextLabel::_validate_line_caches() { int ctrl_height = get_size().height; // Update fonts. + float old_scroll = vscroll->get_value(); if (main->first_invalid_font_line.load() != (int)main->lines.size()) { for (int i = main->first_invalid_font_line.load(); i < (int)main->lines.size(); i++) { _update_line_font(main, i, theme_cache.normal_font, theme_cache.normal_font_size); @@ -2695,6 +2699,7 @@ bool RichTextLabel::_validate_line_caches() { } if (main->first_resized_line.load() == (int)main->lines.size()) { + vscroll->set_value(old_scroll); return true; } @@ -2733,6 +2738,8 @@ bool RichTextLabel::_validate_line_caches() { vscroll->set_page(text_rect.size.height); if (scroll_follow && scroll_following) { vscroll->set_value(total_height); + } else { + vscroll->set_value(old_scroll); } updating_scroll = false; @@ -3853,6 +3860,10 @@ void RichTextLabel::append_text(const String &p_bbcode) { Color color2 = Color::from_string(subtag_b[1], fallback_color); set_cell_row_background_color(color1, color2); } + if (subtag_b.size() == 1) { + Color color1 = Color::from_string(subtag_a[1], fallback_color); + set_cell_row_background_color(color1, color1); + } } } } diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index c4000120c8..e15b3b7bd4 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -40,7 +40,10 @@ Size2 SpinBox::get_minimum_size() const { } void SpinBox::_value_changed(double p_value) { - String value = TS->format_number(String::num(get_value(), Math::range_step_decimals(get_step()))); + String value = String::num(get_value(), Math::range_step_decimals(get_step())); + if (is_localizing_numeral_system()) { + value = TS->format_number(value); + } if (!line_edit->has_focus()) { if (!prefix.is_empty()) { diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 2ca1d6239e..9830b41389 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -71,7 +71,7 @@ void SplitContainerDragger::gui_input(const Ref<InputEvent> &p_event) { Vector2i in_parent_pos = get_transform().xform(mm->get_position()); if (!sc->vertical && is_layout_rtl()) { - sc->split_offset = drag_ofs - ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from); + sc->split_offset = drag_ofs - (in_parent_pos.x - drag_from); } else { sc->split_offset = drag_ofs + ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from); } @@ -194,7 +194,6 @@ void SplitContainer::_compute_middle_sep(bool p_clamp) { // Clamp the split_offset if requested. if (p_clamp) { split_offset -= wished_middle_sep - middle_sep; - p_clamp = false; } } diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index 3ad84cbc6d..f3d9a22342 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -227,6 +227,18 @@ void SubViewportContainer::unhandled_input(const Ref<InputEvent> &p_event) { } } +void SubViewportContainer::add_child_notify(Node *p_child) { + if (Object::cast_to<SubViewport>(p_child)) { + queue_redraw(); + } +} + +void SubViewportContainer::remove_child_notify(Node *p_child) { + if (Object::cast_to<SubViewport>(p_child)) { + queue_redraw(); + } +} + PackedStringArray SubViewportContainer::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h index 63a58b5f07..fdd8fe9486 100644 --- a/scene/gui/subviewport_container.h +++ b/scene/gui/subviewport_container.h @@ -44,6 +44,9 @@ protected: void _notification(int p_what); static void _bind_methods(); + virtual void add_child_notify(Node *p_child) override; + virtual void remove_child_notify(Node *p_child) override; + public: void set_stretch(bool p_enable); bool is_stretch_enabled() const; diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index cf6681f809..f87829cf71 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -385,9 +385,6 @@ void TabBar::_notification(int p_what) { if (tabs[i].disabled) { sb = theme_cache.tab_disabled_style; col = theme_cache.font_disabled_color; - } else if (i == current) { - sb = theme_cache.tab_selected_style; - col = theme_cache.font_selected_color; } else { sb = theme_cache.tab_unselected_style; col = theme_cache.font_unselected_color; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 56f7281721..cce9fa4f34 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -4234,7 +4234,7 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_ if (!p_allow_out_of_bounds) { return Point2i(-1, -1); } - return Point2i(text[row].size(), row); + return Point2i(text[row].length(), row); } int col = 0; diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index ad12757921..ccdf56c1d7 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -250,11 +250,11 @@ void TextureButton::_notification(int p_what) { } void TextureButton::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_normal_texture", "texture"), &TextureButton::set_normal_texture); - ClassDB::bind_method(D_METHOD("set_pressed_texture", "texture"), &TextureButton::set_pressed_texture); - ClassDB::bind_method(D_METHOD("set_hover_texture", "texture"), &TextureButton::set_hover_texture); - ClassDB::bind_method(D_METHOD("set_disabled_texture", "texture"), &TextureButton::set_disabled_texture); - ClassDB::bind_method(D_METHOD("set_focused_texture", "texture"), &TextureButton::set_focused_texture); + ClassDB::bind_method(D_METHOD("set_texture_normal", "texture"), &TextureButton::set_texture_normal); + ClassDB::bind_method(D_METHOD("set_texture_pressed", "texture"), &TextureButton::set_texture_pressed); + ClassDB::bind_method(D_METHOD("set_texture_hover", "texture"), &TextureButton::set_texture_hover); + ClassDB::bind_method(D_METHOD("set_texture_disabled", "texture"), &TextureButton::set_texture_disabled); + ClassDB::bind_method(D_METHOD("set_texture_focused", "texture"), &TextureButton::set_texture_focused); ClassDB::bind_method(D_METHOD("set_click_mask", "mask"), &TextureButton::set_click_mask); ClassDB::bind_method(D_METHOD("set_ignore_texture_size", "ignore"), &TextureButton::set_ignore_texture_size); ClassDB::bind_method(D_METHOD("set_stretch_mode", "mode"), &TextureButton::set_stretch_mode); @@ -263,21 +263,21 @@ void TextureButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_flip_v", "enable"), &TextureButton::set_flip_v); ClassDB::bind_method(D_METHOD("is_flipped_v"), &TextureButton::is_flipped_v); - ClassDB::bind_method(D_METHOD("get_normal_texture"), &TextureButton::get_normal_texture); - ClassDB::bind_method(D_METHOD("get_pressed_texture"), &TextureButton::get_pressed_texture); - ClassDB::bind_method(D_METHOD("get_hover_texture"), &TextureButton::get_hover_texture); - ClassDB::bind_method(D_METHOD("get_disabled_texture"), &TextureButton::get_disabled_texture); - ClassDB::bind_method(D_METHOD("get_focused_texture"), &TextureButton::get_focused_texture); + ClassDB::bind_method(D_METHOD("get_texture_normal"), &TextureButton::get_texture_normal); + ClassDB::bind_method(D_METHOD("get_texture_pressed"), &TextureButton::get_texture_pressed); + ClassDB::bind_method(D_METHOD("get_texture_hover"), &TextureButton::get_texture_hover); + ClassDB::bind_method(D_METHOD("get_texture_disabled"), &TextureButton::get_texture_disabled); + ClassDB::bind_method(D_METHOD("get_texture_focused"), &TextureButton::get_texture_focused); ClassDB::bind_method(D_METHOD("get_click_mask"), &TextureButton::get_click_mask); ClassDB::bind_method(D_METHOD("get_ignore_texture_size"), &TextureButton::get_ignore_texture_size); ClassDB::bind_method(D_METHOD("get_stretch_mode"), &TextureButton::get_stretch_mode); ADD_GROUP("Textures", "texture_"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_texture", "get_normal_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_pressed_texture", "get_pressed_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_hover", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_hover_texture", "get_hover_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_disabled", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_disabled_texture", "get_disabled_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_focused", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_focused_texture", "get_focused_texture"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_normal", "get_texture_normal"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_pressed", "get_texture_pressed"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_hover", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_hover", "get_texture_hover"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_disabled", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_disabled", "get_texture_disabled"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_focused", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_focused", "get_texture_focused"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_click_mask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_click_mask", "get_click_mask"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_texture_size", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_ignore_texture_size", "get_ignore_texture_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode"); @@ -293,7 +293,7 @@ void TextureButton::_bind_methods() { BIND_ENUM_CONSTANT(STRETCH_KEEP_ASPECT_COVERED); } -void TextureButton::set_normal_texture(const Ref<Texture2D> &p_normal) { +void TextureButton::set_texture_normal(const Ref<Texture2D> &p_normal) { if (normal == p_normal) { return; } @@ -303,7 +303,7 @@ void TextureButton::set_normal_texture(const Ref<Texture2D> &p_normal) { update_minimum_size(); } -void TextureButton::set_pressed_texture(const Ref<Texture2D> &p_pressed) { +void TextureButton::set_texture_pressed(const Ref<Texture2D> &p_pressed) { if (pressed == p_pressed) { return; } @@ -313,7 +313,7 @@ void TextureButton::set_pressed_texture(const Ref<Texture2D> &p_pressed) { update_minimum_size(); } -void TextureButton::set_hover_texture(const Ref<Texture2D> &p_hover) { +void TextureButton::set_texture_hover(const Ref<Texture2D> &p_hover) { if (hover == p_hover) { return; } @@ -323,7 +323,7 @@ void TextureButton::set_hover_texture(const Ref<Texture2D> &p_hover) { update_minimum_size(); } -void TextureButton::set_disabled_texture(const Ref<Texture2D> &p_disabled) { +void TextureButton::set_texture_disabled(const Ref<Texture2D> &p_disabled) { if (disabled == p_disabled) { return; } @@ -341,19 +341,19 @@ void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) { update_minimum_size(); } -Ref<Texture2D> TextureButton::get_normal_texture() const { +Ref<Texture2D> TextureButton::get_texture_normal() const { return normal; } -Ref<Texture2D> TextureButton::get_pressed_texture() const { +Ref<Texture2D> TextureButton::get_texture_pressed() const { return pressed; } -Ref<Texture2D> TextureButton::get_hover_texture() const { +Ref<Texture2D> TextureButton::get_texture_hover() const { return hover; } -Ref<Texture2D> TextureButton::get_disabled_texture() const { +Ref<Texture2D> TextureButton::get_texture_disabled() const { return disabled; } @@ -361,11 +361,11 @@ Ref<BitMap> TextureButton::get_click_mask() const { return click_mask; } -Ref<Texture2D> TextureButton::get_focused_texture() const { +Ref<Texture2D> TextureButton::get_texture_focused() const { return focused; }; -void TextureButton::set_focused_texture(const Ref<Texture2D> &p_focused) { +void TextureButton::set_texture_focused(const Ref<Texture2D> &p_focused) { focused = p_focused; }; diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h index 9f6f7c1515..4b6d5b5bec 100644 --- a/scene/gui/texture_button.h +++ b/scene/gui/texture_button.h @@ -71,18 +71,18 @@ protected: static void _bind_methods(); public: - void set_normal_texture(const Ref<Texture2D> &p_normal); - void set_pressed_texture(const Ref<Texture2D> &p_pressed); - void set_hover_texture(const Ref<Texture2D> &p_hover); - void set_disabled_texture(const Ref<Texture2D> &p_disabled); - void set_focused_texture(const Ref<Texture2D> &p_focused); + void set_texture_normal(const Ref<Texture2D> &p_normal); + void set_texture_pressed(const Ref<Texture2D> &p_pressed); + void set_texture_hover(const Ref<Texture2D> &p_hover); + void set_texture_disabled(const Ref<Texture2D> &p_disabled); + void set_texture_focused(const Ref<Texture2D> &p_focused); void set_click_mask(const Ref<BitMap> &p_click_mask); - Ref<Texture2D> get_normal_texture() const; - Ref<Texture2D> get_pressed_texture() const; - Ref<Texture2D> get_hover_texture() const; - Ref<Texture2D> get_disabled_texture() const; - Ref<Texture2D> get_focused_texture() const; + Ref<Texture2D> get_texture_normal() const; + Ref<Texture2D> get_texture_pressed() const; + Ref<Texture2D> get_texture_hover() const; + Ref<Texture2D> get_texture_disabled() const; + Ref<Texture2D> get_texture_focused() const; Ref<BitMap> get_click_mask() const; bool get_ignore_texture_size() const; diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 2c395ec07d..62f362553f 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -276,10 +276,10 @@ bool HTTPRequest::_handle_response(bool *ret_value) { } if (content_encoding == "gzip") { decompressor.instantiate(); - decompressor->start_decompression(false, get_download_chunk_size() * 2); + decompressor->start_decompression(false, get_download_chunk_size()); } else if (content_encoding == "deflate") { decompressor.instantiate(); - decompressor->start_decompression(true, get_download_chunk_size() * 2); + decompressor->start_decompression(true, get_download_chunk_size()); } return false; @@ -390,19 +390,38 @@ bool HTTPRequest::_update_connection() { return false; } - PackedByteArray chunk = client->read_response_body_chunk(); - downloaded.add(chunk.size()); - - // Decompress chunk if needed. - if (decompressor.is_valid()) { - Error err = decompressor->put_data(chunk.ptr(), chunk.size()); - if (err == OK) { - chunk.resize(decompressor->get_available_bytes()); - err = decompressor->get_data(chunk.ptrw(), chunk.size()); - } - if (err != OK) { - _defer_done(RESULT_BODY_DECOMPRESS_FAILED, response_code, response_headers, PackedByteArray()); - return true; + PackedByteArray chunk; + if (decompressor.is_null()) { + // Chunk can be read directly. + chunk = client->read_response_body_chunk(); + downloaded.add(chunk.size()); + } else { + // Chunk is the result of decompression. + PackedByteArray compressed = client->read_response_body_chunk(); + downloaded.add(compressed.size()); + + int pos = 0; + int left = compressed.size(); + while (left) { + int w = 0; + Error err = decompressor->put_partial_data(compressed.ptr() + pos, left, w); + if (err == OK) { + PackedByteArray dc; + dc.resize(decompressor->get_available_bytes()); + err = decompressor->get_data(dc.ptrw(), dc.size()); + chunk.append_array(dc); + } + if (err != OK) { + _defer_done(RESULT_BODY_DECOMPRESS_FAILED, response_code, response_headers, PackedByteArray()); + return true; + } + // We need this check here because a "zip bomb" could result in a chunk of few kilos decompressing into gigabytes of data. + if (body_size_limit >= 0 && final_body_size.get() + chunk.size() > body_size_limit) { + _defer_done(RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray()); + return true; + } + pos += w; + left -= w; } } final_body_size.add(chunk.size()); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 5dd0911694..07dce9fbec 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -349,7 +349,7 @@ void Node::move_child(Node *p_child, int p_index) { } void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) { - ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup)."); + ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `move_child()` failed. Consider using `move_child.call_deferred(child, index)` instead (or `popup.call_deferred()` if this is from a popup)."); // Specifying one place beyond the end // means the same as moving to the last index @@ -1130,7 +1130,7 @@ void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_i #ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(p_child->is_ancestor_of(this), vformat("Can't add child '%s' to '%s' as it would result in a cyclic dependency since '%s' is already a parent of '%s'.", p_child->get_name(), get_name(), p_child->get_name(), get_name())); #endif - ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_node() failed. Consider using call_deferred(\"add_child\", child) instead."); + ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_child()` failed. Consider using `add_child.call_deferred(child)` instead."); _validate_child_name(p_child, p_force_readable_name); _add_child_nocheck(p_child, p_child->data.name); @@ -1150,7 +1150,7 @@ void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) { ERR_FAIL_NULL(p_sibling); ERR_FAIL_NULL(data.parent); ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself! - ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_sibling() failed. Consider using call_deferred(\"add_sibling\", sibling) instead."); + ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_sibling()` failed. Consider using `add_sibling.call_deferred(sibling)` instead."); InternalMode internal = INTERNAL_MODE_DISABLED; if (_is_internal_front()) { // The sibling will have the same internal status. @@ -1165,7 +1165,7 @@ void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) { void Node::remove_child(Node *p_child) { ERR_FAIL_NULL(p_child); - ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, remove_node() failed. Consider using call_deferred(\"remove_child\", child) instead."); + ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `remove_child()` failed. Consider using `remove_child.call_deferred(child)` instead."); int child_count = data.children.size(); Node **children = data.children.ptrw(); @@ -2060,7 +2060,7 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c nip->set_instance_path(ip->get_instance_path()); node = nip; - } else if ((p_flags & DUPLICATE_USE_INSTANCING) && !get_scene_file_path().is_empty()) { + } else if ((p_flags & DUPLICATE_USE_INSTANTIATION) && !get_scene_file_path().is_empty()) { Ref<PackedScene> res = ResourceLoader::load(get_scene_file_path()); ERR_FAIL_COND_V(res.is_null(), nullptr); PackedScene::GenEditState ges = PackedScene::GEN_EDIT_STATE_DISABLED; @@ -2246,7 +2246,7 @@ Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) con } Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const { - Node *dupe = _duplicate(DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANCING | DUPLICATE_FROM_EDITOR, &r_duplimap); + Node *dupe = _duplicate(DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR, &r_duplimap); // This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated. if (!p_resource_remap.is_empty()) { @@ -2816,7 +2816,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tree"), &Node::get_tree); ClassDB::bind_method(D_METHOD("create_tween"), &Node::create_tween); - ClassDB::bind_method(D_METHOD("duplicate", "flags"), &Node::duplicate, DEFVAL(DUPLICATE_USE_INSTANCING | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS)); + ClassDB::bind_method(D_METHOD("duplicate", "flags"), &Node::duplicate, DEFVAL(DUPLICATE_USE_INSTANTIATION | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS)); ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups"), &Node::replace_by, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_scene_instance_load_placeholder", "load_placeholder"), &Node::set_scene_instance_load_placeholder); @@ -2922,7 +2922,7 @@ void Node::_bind_methods() { BIND_ENUM_CONSTANT(DUPLICATE_SIGNALS); BIND_ENUM_CONSTANT(DUPLICATE_GROUPS); BIND_ENUM_CONSTANT(DUPLICATE_SCRIPTS); - BIND_ENUM_CONSTANT(DUPLICATE_USE_INSTANCING); + BIND_ENUM_CONSTANT(DUPLICATE_USE_INSTANTIATION); BIND_ENUM_CONSTANT(INTERNAL_MODE_DISABLED); BIND_ENUM_CONSTANT(INTERNAL_MODE_FRONT); diff --git a/scene/main/node.h b/scene/main/node.h index 4a3ec253b1..5e51ec6b0e 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -57,7 +57,7 @@ public: DUPLICATE_SIGNALS = 1, DUPLICATE_GROUPS = 2, DUPLICATE_SCRIPTS = 4, - DUPLICATE_USE_INSTANCING = 8, + DUPLICATE_USE_INSTANTIATION = 8, #ifdef TOOLS_ENABLED DUPLICATE_FROM_EDITOR = 16, #endif diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 4c2a761138..345d5de937 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -362,6 +362,7 @@ void Viewport::_notification(int p_what) { current_canvas = find_world_2d()->get_canvas(); RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas); + RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, current_canvas, canvas_transform); RenderingServer::get_singleton()->viewport_set_canvas_cull_mask(viewport, canvas_cull_mask); _update_audio_listener_2d(); #ifndef _3D_DISABLED @@ -1623,7 +1624,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Control *control = Object::cast_to<Control>(ci); if (control) { gui.dragging = true; - gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos) - gui.drag_accum); + gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos - gui.drag_accum)); if (gui.drag_data.get_type() != Variant::NIL) { gui.mouse_focus = nullptr; gui.forced_mouse_focus = false; diff --git a/scene/property_utils.h b/scene/property_utils.h index 5ada35fdd7..5b0200b491 100644 --- a/scene/property_utils.h +++ b/scene/property_utils.h @@ -42,7 +42,7 @@ public: // Gets the instance/inheritance states of this node, in order of precedence, // that is, from the topmost (the most able to override values) to the lowermost - // (Note that in nested instancing the one with the greatest precedence is the furthest + // (Note that in nested instantiation, the one with the greatest precedence is the furthest // in the tree, since every owner found while traversing towards the root gets a chance // to override property values.) static Vector<SceneState::PackState> get_node_states_stack(const Node *p_node, const Node *p_owner = nullptr, bool *r_instantiated_by_owner = nullptr); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index ef619c9893..da73a479ce 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -888,7 +888,6 @@ int Animation::add_track(TrackType p_type, int p_at_pos) { } } emit_changed(); - emit_signal(SceneStringNames::get_singleton()->tracks_changed); return p_at_pos; } @@ -951,7 +950,6 @@ void Animation::remove_track(int p_track) { memdelete(t); tracks.remove_at(p_track); emit_changed(); - emit_signal(SceneStringNames::get_singleton()->tracks_changed); } int Animation::get_track_count() const { @@ -967,7 +965,6 @@ void Animation::track_set_path(int p_track, const NodePath &p_path) { ERR_FAIL_INDEX(p_track, tracks.size()); tracks[p_track]->path = p_path; emit_changed(); - emit_signal(SceneStringNames::get_singleton()->tracks_changed); } NodePath Animation::track_get_path(int p_track) const { @@ -2467,7 +2464,6 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol ERR_FAIL_COND_V(idx == -2, T()); - bool result = true; int next = 0; real_t c = 0.0; // prepare for all cases of interpolation @@ -2599,10 +2595,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol } if (p_ok) { - *p_ok = result; - } - if (!result) { - return T(); + *p_ok = true; } real_t tr = p_keys[idx].transition; @@ -3834,7 +3827,6 @@ void Animation::track_move_up(int p_track) { } emit_changed(); - emit_signal(SceneStringNames::get_singleton()->tracks_changed); } void Animation::track_move_down(int p_track) { @@ -3843,7 +3835,6 @@ void Animation::track_move_down(int p_track) { } emit_changed(); - emit_signal(SceneStringNames::get_singleton()->tracks_changed); } void Animation::track_move_to(int p_track, int p_to_index) { @@ -3859,7 +3850,6 @@ void Animation::track_move_to(int p_track, int p_to_index) { tracks.insert(p_to_index > p_track ? p_to_index - 1 : p_to_index, track); emit_changed(); - emit_signal(SceneStringNames::get_singleton()->tracks_changed); } void Animation::track_swap(int p_track, int p_with_track) { @@ -3871,7 +3861,6 @@ void Animation::track_swap(int p_track, int p_with_track) { SWAP(tracks.write[p_track], tracks.write[p_with_track]); emit_changed(); - emit_signal(SceneStringNames::get_singleton()->tracks_changed); } void Animation::set_step(real_t p_step) { @@ -4001,8 +3990,6 @@ void Animation::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Ping-Pong"), "set_loop_mode", "get_loop_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step", PROPERTY_HINT_RANGE, "0,4096,0.001,suffix:s"), "set_step", "get_step"); - ADD_SIGNAL(MethodInfo("tracks_changed")); - BIND_ENUM_CONSTANT(TYPE_VALUE); BIND_ENUM_CONSTANT(TYPE_POSITION_3D); BIND_ENUM_CONSTANT(TYPE_ROTATION_3D); @@ -4041,7 +4028,6 @@ void Animation::clear() { compression.pages.clear(); compression.fps = 120; emit_changed(); - emit_signal(SceneStringNames::get_singleton()->tracks_changed); } bool Animation::_float_track_optimize_key(const TKey<float> t0, const TKey<float> t1, const TKey<float> t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) { diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index 1b06e09bb8..0df61871d8 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -169,7 +169,7 @@ Dictionary BitMap::_get_data() const { return d; } -Vector<Vector2> BitMap::_march_square(const Rect2i &p_rect, const Point2i &p_start) const { +Vector<Vector<Vector2>> BitMap::_march_square(const Rect2i &p_rect, const Point2i &p_start) const { int stepx = 0; int stepy = 0; int prevx = 0; @@ -179,9 +179,17 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &p_rect, const Point2i &p_sta int curx = startx; int cury = starty; unsigned int count = 0; - HashSet<Point2i> case9s; - HashSet<Point2i> case6s; + + HashMap<Point2i, int> cross_map; + Vector<Vector2> _points; + int points_size = 0; + + Vector<Vector<Vector2>> ret; + + // Add starting entry at start of return. + ret.resize(1); + do { int sv = 0; { // Square value @@ -202,7 +210,7 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &p_rect, const Point2i &p_sta sv += (p_rect.has_point(bl) && get_bitv(bl)) ? 4 : 0; Point2i br = Point2i(curx, cury); sv += (p_rect.has_point(br) && get_bitv(br)) ? 8 : 0; - ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector<Vector2>()); + ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector<Vector<Vector2>>()); } switch (sv) { @@ -266,70 +274,95 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &p_rect, const Point2i &p_sta stepy = 0; break; case 9: - /* + /* Going DOWN if coming from the LEFT, otherwise go UP. + 9 +---+---+ | 1 | | +---+---+ | | 8 | +---+---+ - this should normally go UP, but if we already been here, we go down */ - if (case9s.has(Point2i(curx, cury))) { - //found, so we go down, and delete from case9s; + + if (prevx == 1) { stepx = 0; stepy = 1; - case9s.erase(Point2i(curx, cury)); } else { - //not found, we go up, and add to case9s; stepx = 0; stepy = -1; - case9s.insert(Point2i(curx, cury)); } break; case 6: - /* + /* Going RIGHT if coming from BELOW, otherwise go LEFT. 6 +---+---+ | | 2 | +---+---+ | 4 | | +---+---+ - this normally go RIGHT, but if it's coming from RIGHT, it should go LEFT */ - if (case6s.has(Point2i(curx, cury))) { - //found, so we go left, and delete from case6s; - stepx = -1; + + if (prevy == -1) { + stepx = 1; stepy = 0; - case6s.erase(Point2i(curx, cury)); } else { - //not found, we go right, and add to case6s; - stepx = 1; + stepx = -1; stepy = 0; - case6s.insert(Point2i(curx, cury)); } break; default: ERR_PRINT("this shouldn't happen."); } + + // Handle crossing points. + if (sv == 6 || sv == 9) { + const Point2i cur_pos(curx, cury); + + // Find if this point has occured before. + if (HashMap<Point2i, int>::Iterator found = cross_map.find(cur_pos)) { + // Add points after the previous crossing to the result. + ret.push_back(_points.slice(found->value + 1, points_size)); + + // Remove points after crossing point. + points_size = found->value + 1; + + // Erase trailing map elements. + while (cross_map.last() != found) { + cross_map.remove(cross_map.last()); + } + + cross_map.erase(cur_pos); + } else { + // Add crossing point to map. + cross_map.insert(cur_pos, points_size - 1); + } + } + // Small optimization: // If the previous direction is same as the current direction, // then we should modify the last vector to current. curx += stepx; cury += stepy; if (stepx == prevx && stepy == prevy) { - _points.write[_points.size() - 1].x = (float)(curx - p_rect.position.x); - _points.write[_points.size() - 1].y = (float)(cury + p_rect.position.y); + _points.set(points_size - 1, Vector2(curx, cury) - p_rect.position); } else { - _points.push_back(Vector2((float)(curx - p_rect.position.x), (float)(cury + p_rect.position.y))); + _points.resize(MAX(points_size + 1, _points.size())); + _points.set(points_size, Vector2(curx, cury) - p_rect.position); + points_size++; } count++; prevx = stepx; prevy = stepy; - ERR_FAIL_COND_V((int)count > width * height, _points); + ERR_FAIL_COND_V((int)count > width * height, Vector<Vector<Vector2>>()); } while (curx != startx || cury != starty); - return _points; + + // Add remaining points to result. + _points.resize(points_size); + + ret.set(0, _points); + + return ret; } static float perpendicular_distance(const Vector2 &i, const Vector2 &start, const Vector2 &end) { @@ -442,7 +475,7 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_ for (int j = next_j; j <= pos.y + 1; j++) { if (popped) { // The next loop over j must start normally. - next_j = pos.y; + next_j = pos.y - 1; popped = false; // Skip because an iteration was already executed with current counter values. continue; @@ -486,13 +519,10 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_ } } } while (reenter || popped); - - print_verbose("BitMap: Max stack size: " + itos(stack.size())); } Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2i &p_rect, float p_epsilon) const { Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect); - print_verbose("BitMap: Rect: " + r); Point2i from; Ref<BitMap> fill; @@ -505,17 +535,16 @@ Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2i &p_rect, fl if (!fill->get_bit(j, i) && get_bit(j, i)) { fill_bits(this, fill, Point2i(j, i), r); - Vector<Vector2> polygon = _march_square(r, Point2i(j, i)); - print_verbose("BitMap: Pre reduce: " + itos(polygon.size())); - polygon = reduce(polygon, r, p_epsilon); - print_verbose("BitMap: Post reduce: " + itos(polygon.size())); + for (Vector<Vector2> polygon : _march_square(r, Point2i(j, i))) { + polygon = reduce(polygon, r, p_epsilon); - if (polygon.size() < 3) { - print_verbose("Invalid polygon, skipped"); - continue; - } + if (polygon.size() < 3) { + print_verbose("Invalid polygon, skipped"); + continue; + } - polygons.push_back(polygon); + polygons.push_back(polygon); + } } } } diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h index 291ed8c4d0..0ec5772fd1 100644 --- a/scene/resources/bit_map.h +++ b/scene/resources/bit_map.h @@ -46,7 +46,7 @@ class BitMap : public Resource { int width = 0; int height = 0; - Vector<Vector2> _march_square(const Rect2i &p_rect, const Point2i &p_start) const; + Vector<Vector<Vector2>> _march_square(const Rect2i &p_rect, const Point2i &p_start) const; TypedArray<PackedVector2Array> _opaque_to_polygons_bind(const Rect2i &p_rect, float p_epsilon) const; diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index eda9af9dde..9289c5da4a 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -31,6 +31,7 @@ #include "curve.h" #include "core/core_string_names.h" +#include "core/math/math_funcs.h" const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed"; @@ -1402,6 +1403,22 @@ void Curve3D::_bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, re } } +void Curve3D::_bake_segment3d_even_length(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_length) const { + Vector3 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin); + Vector3 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end); + + size_t length = beg.distance_to(end); + + if (length > p_length && p_depth < p_max_depth) { + real_t mp = (p_begin + p_end) * 0.5; + Vector3 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp); + r_bake[mp] = mid; + + _bake_segment3d(r_bake, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_length); + _bake_segment3d(r_bake, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_length); + } +} + void Curve3D::_bake() const { if (!baked_cache_dirty) { return; @@ -1413,8 +1430,10 @@ void Curve3D::_bake() const { if (points.size() == 0) { baked_point_cache.clear(); baked_tilt_cache.clear(); - baked_up_vector_cache.clear(); baked_dist_cache.clear(); + + baked_forward_vector_cache.clear(); + baked_up_vector_cache.clear(); return; } @@ -1425,10 +1444,12 @@ void Curve3D::_bake() const { baked_tilt_cache.set(0, points[0].tilt); baked_dist_cache.resize(1); baked_dist_cache.set(0, 0.0); + baked_forward_vector_cache.resize(1); + baked_forward_vector_cache.set(0, Vector3(0.0, 0.0, 1.0)); if (up_vector_enabled) { baked_up_vector_cache.resize(1); - baked_up_vector_cache.set(0, Vector3(0, 1, 0)); + baked_up_vector_cache.set(0, Vector3(0.0, 1.0, 0.0)); } else { baked_up_vector_cache.clear(); } @@ -1436,136 +1457,135 @@ void Curve3D::_bake() const { return; } - Vector3 position = points[0].position; - real_t dist = 0.0; - List<Plane> pointlist; - List<real_t> distlist; + // Step 1: Tesselate curve to (almost) even length segments + { + Vector<RBMap<real_t, Vector3>> midpoints = _tessellate_even_length(10, bake_interval); - // Start always from origin. - pointlist.push_back(Plane(position, points[0].tilt)); - distlist.push_back(0.0); - - for (int i = 0; i < points.size() - 1; i++) { - real_t step = 0.1; // at least 10 substeps ought to be enough? - real_t p = 0.0; + int pc = 1; + for (int i = 0; i < points.size() - 1; i++) { + pc++; + pc += midpoints[i].size(); + } - while (p < 1.0) { - real_t np = p + step; - if (np > 1.0) { - np = 1.0; + baked_point_cache.resize(pc); + baked_tilt_cache.resize(pc); + baked_dist_cache.resize(pc); + baked_forward_vector_cache.resize(pc); + + Vector3 *bpw = baked_point_cache.ptrw(); + real_t *btw = baked_tilt_cache.ptrw(); + Vector3 *bfw = baked_forward_vector_cache.ptrw(); + + // Collect positions and sample tilts and tangents for each baked points. + bpw[0] = points[0].position; + bfw[0] = points[0].position.bezier_derivative(points[0].position + points[0].out, points[1].position + points[1].in, points[1].position, 0.0).normalized(); + btw[0] = points[0].tilt; + int pidx = 0; + + for (int i = 0; i < points.size() - 1; i++) { + for (const KeyValue<real_t, Vector3> &E : midpoints[i]) { + pidx++; + bpw[pidx] = E.value; + bfw[pidx] = points[i].position.bezier_derivative(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key).normalized(); + btw[pidx] = Math::lerp(points[i].tilt, points[i + 1].tilt, E.key); } - Vector3 npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, np); - real_t d = position.distance_to(npp); - - if (d > bake_interval) { - // OK! between P and NP there _has_ to be Something, let's go searching! - - int iterations = 10; //lots of detail! - - real_t low = p; - real_t hi = np; - real_t mid = low + (hi - low) * 0.5; - - for (int j = 0; j < iterations; j++) { - npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, mid); - d = position.distance_to(npp); - - if (bake_interval < d) { - hi = mid; - } else { - low = mid; - } - mid = low + (hi - low) * 0.5; - } - - position = npp; - p = mid; - Plane post; - post.normal = position; - post.d = Math::lerp(points[i].tilt, points[i + 1].tilt, mid); - dist += d; - - pointlist.push_back(post); - distlist.push_back(dist); - } else { - p = np; - } + pidx++; + bpw[pidx] = points[i + 1].position; + bfw[pidx] = points[i].position.bezier_derivative(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0).normalized(); + btw[pidx] = points[i + 1].tilt; } - Vector3 npp = points[i + 1].position; - real_t d = position.distance_to(npp); - - position = npp; - Plane post; - post.normal = position; - post.d = points[i + 1].tilt; - - dist += d; - - pointlist.push_back(post); - distlist.push_back(dist); + // Recalculate the baked distances. + real_t *bdw = baked_dist_cache.ptrw(); + bdw[0] = 0.0; + for (int i = 0; i < pc - 1; i++) { + bdw[i + 1] = bdw[i] + bpw[i].distance_to(bpw[i + 1]); + } + baked_max_ofs = bdw[pc - 1]; } - baked_max_ofs = dist; - - baked_point_cache.resize(pointlist.size()); - Vector3 *w = baked_point_cache.ptrw(); - int idx = 0; + if (!up_vector_enabled) { + baked_up_vector_cache.resize(0); + return; + } - baked_tilt_cache.resize(pointlist.size()); - real_t *wt = baked_tilt_cache.ptrw(); + // Step 2: Calculate the up vectors and the whole local reference frame + // + // See Dougan, Carl. "The parallel transport frame." Game Programming Gems 2 (2001): 215-219. + // for an example discussing about why not the Frenet frame. + { + int point_count = baked_point_cache.size(); - baked_up_vector_cache.resize(up_vector_enabled ? pointlist.size() : 0); - Vector3 *up_write = baked_up_vector_cache.ptrw(); + baked_up_vector_cache.resize(point_count); + Vector3 *up_write = baked_up_vector_cache.ptrw(); - baked_dist_cache.resize(pointlist.size()); - real_t *wd = baked_dist_cache.ptrw(); + const Vector3 *forward_ptr = baked_forward_vector_cache.ptr(); + const Vector3 *points_ptr = baked_point_cache.ptr(); - Vector3 sideways; - Vector3 up; - Vector3 forward; + Basis frame; // X-right, Y-up, Z-forward. + Basis frame_prev; - Vector3 prev_sideways = Vector3(1, 0, 0); - Vector3 prev_up = Vector3(0, 1, 0); - Vector3 prev_forward = Vector3(0, 0, 1); + // Set the initial frame based on Y-up rule. + { + Vector3 forward = forward_ptr[0]; - for (const Plane &E : pointlist) { - w[idx] = E.normal; - wt[idx] = E.d; - wd[idx] = distlist[idx]; + if (abs(forward.dot(Vector3(0, 1, 0))) > 1.0 - UNIT_EPSILON) { + frame_prev = Basis::looking_at(-forward, Vector3(1, 0, 0)); + } else { + frame_prev = Basis::looking_at(-forward, Vector3(0, 1, 0)); + } - if (!up_vector_enabled) { - idx++; - continue; + up_write[0] = frame_prev.get_column(1); } - forward = idx > 0 ? (w[idx] - w[idx - 1]).normalized() : prev_forward; + // Calculate the Parallel Transport Frame. + for (int idx = 1; idx < point_count; idx++) { + Vector3 forward = forward_ptr[idx]; - real_t y_dot = prev_up.dot(forward); + Basis rotate; + rotate.rotate_to_align(frame_prev.get_column(2), forward); + frame = rotate * frame_prev; + frame.orthonormalize(); // guard against float error accumulation - if (y_dot > (1.0f - CMP_EPSILON)) { - sideways = prev_sideways; - up = -prev_forward; - } else if (y_dot < -(1.0f - CMP_EPSILON)) { - sideways = prev_sideways; - up = prev_forward; - } else { - sideways = prev_up.cross(forward).normalized(); - up = forward.cross(sideways).normalized(); + up_write[idx] = frame.get_column(1); + frame_prev = frame; } - if (idx == 1) { - up_write[0] = up; + bool is_loop = true; + // Loop smoothing only applies when the curve is a loop, which means two ends meet, and share forward directions. + { + if (!points_ptr[0].is_equal_approx(points_ptr[point_count - 1])) { + is_loop = false; + } + + real_t dot = forward_ptr[0].dot(forward_ptr[point_count - 1]); + if (dot < 1.0 - UNIT_EPSILON) { // Alignment should not be too tight, or it dosen't work for coarse bake interval. + is_loop = false; + } } - up_write[idx] = up; + // Twist up vectors, so that they align at two ends of the curve. + if (is_loop) { + const Vector3 up_start = up_write[0]; + const Vector3 up_end = up_write[point_count - 1]; + + real_t sign = SIGN(up_end.cross(up_start).dot(forward_ptr[0])); + real_t full_angle = Quaternion(up_end, up_start).get_angle(); - prev_sideways = sideways; - prev_up = up; - prev_forward = forward; + if (abs(full_angle) < CMP_EPSILON) { + return; + } else { + const real_t *dists = baked_dist_cache.ptr(); + for (int idx = 1; idx < point_count; idx++) { + const real_t frac = dists[idx] / baked_max_ofs; + const real_t angle = Math::lerp((real_t)0.0, full_angle, frac); + Basis twist(forward_ptr[idx] * sign, angle); - idx++; + up_write[idx] = twist.xform(up_write[idx]); + } + } + } } } @@ -1577,27 +1597,15 @@ real_t Curve3D::get_baked_length() const { return baked_max_ofs; } -Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const { - if (baked_cache_dirty) { - _bake(); - } +Curve3D::Interval Curve3D::_find_interval(real_t p_offset) const { + Interval interval = { + -1, + 0.0 + }; + ERR_FAIL_COND_V_MSG(baked_cache_dirty, interval, "Backed cache is dirty"); - // Validate: Curve may not have baked points. int pc = baked_point_cache.size(); - ERR_FAIL_COND_V_MSG(pc == 0, Vector3(), "No points in Curve3D."); - - if (pc == 1) { - return baked_point_cache.get(0); - } - - const Vector3 *r = baked_point_cache.ptr(); - - if (p_offset < 0) { - return r[0]; - } - if (p_offset >= baked_max_ofs) { - return r[pc - 1]; - } + ERR_FAIL_COND_V_MSG(pc < 2, interval, "Less than two points in cache"); int start = 0; int end = pc; @@ -1617,9 +1625,27 @@ Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const { real_t offset_end = baked_dist_cache[idx + 1]; real_t idx_interval = offset_end - offset_begin; - ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(), "Couldn't find baked segment."); + ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, interval, "Offset out of range."); - real_t frac = (p_offset - offset_begin) / idx_interval; + interval.idx = idx; + if (idx_interval < FLT_EPSILON) { + interval.frac = 0.5; // For a very short interval, 0.5 is a reasonable choice. + ERR_FAIL_V_MSG(interval, "Zero length interval."); + } + + interval.frac = (p_offset - offset_begin) / idx_interval; + return interval; +} + +Vector3 Curve3D::_sample_baked(Interval p_interval, bool p_cubic) const { + // Assuming p_interval is valid. + ERR_FAIL_INDEX_V_MSG(p_interval.idx, baked_point_cache.size(), Vector3(), "Invalid interval"); + + int idx = p_interval.idx; + real_t frac = p_interval.frac; + + const Vector3 *r = baked_point_cache.ptr(); + int pc = baked_point_cache.size(); if (p_cubic) { Vector3 pre = idx > 0 ? r[idx - 1] : r[idx]; @@ -1630,114 +1656,142 @@ Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const { } } -real_t Curve3D::sample_baked_tilt(real_t p_offset) const { - if (baked_cache_dirty) { - _bake(); - } +real_t Curve3D::_sample_baked_tilt(Interval p_interval) const { + // Assuming that p_interval is valid. + ERR_FAIL_INDEX_V_MSG(p_interval.idx, baked_tilt_cache.size(), 0.0, "Invalid interval"); - // Validate: Curve may not have baked tilts. - int pc = baked_tilt_cache.size(); - ERR_FAIL_COND_V_MSG(pc == 0, 0, "No tilts in Curve3D."); + int idx = p_interval.idx; + real_t frac = p_interval.frac; - if (pc == 1) { - return baked_tilt_cache.get(0); + const real_t *r = baked_tilt_cache.ptr(); + + return Math::lerp(r[idx], r[idx + 1], frac); +} + +Basis Curve3D::_sample_posture(Interval p_interval, bool p_apply_tilt) const { + // Assuming that p_interval is valid. + ERR_FAIL_INDEX_V_MSG(p_interval.idx, baked_point_cache.size(), Basis(), "Invalid interval"); + if (up_vector_enabled) { + ERR_FAIL_INDEX_V_MSG(p_interval.idx, baked_up_vector_cache.size(), Basis(), "Invalid interval"); } - const real_t *r = baked_tilt_cache.ptr(); + int idx = p_interval.idx; + real_t frac = p_interval.frac; - if (p_offset < 0) { - return r[0]; + Vector3 forward_begin = baked_forward_vector_cache[idx]; + Vector3 forward_end = baked_forward_vector_cache[idx + 1]; + + Vector3 up_begin; + Vector3 up_end; + if (up_vector_enabled) { + up_begin = baked_up_vector_cache[idx]; + up_end = baked_up_vector_cache[idx + 1]; + } else { + up_begin = Vector3(0.0, 1.0, 0.0); + up_end = Vector3(0.0, 1.0, 0.0); } - if (p_offset >= baked_max_ofs) { - return r[pc - 1]; + + // Build frames at both ends of the interval, then interpolate. + const Basis frame_begin = Basis::looking_at(-forward_begin, up_begin); + const Basis frame_end = Basis::looking_at(-forward_end, up_end); + const Basis frame = frame_begin.slerp(frame_end, frac).orthonormalized(); + + if (!p_apply_tilt) { + return frame; } - int start = 0; - int end = pc; - int idx = (end + start) / 2; - // Binary search to find baked points. - while (start < idx) { - real_t offset = baked_dist_cache[idx]; - if (p_offset <= offset) { - end = idx; - } else { - start = idx; - } - idx = (end + start) / 2; + // Applying tilt. + const real_t tilt = _sample_baked_tilt(p_interval); + Vector3 forward = frame.get_column(2); + + const Basis twist(forward, tilt); + return twist * frame; +} + +Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const { + if (baked_cache_dirty) { + _bake(); } - real_t offset_begin = baked_dist_cache[idx]; - real_t offset_end = baked_dist_cache[idx + 1]; + // Validate: Curve may not have baked points. + int pc = baked_point_cache.size(); + ERR_FAIL_COND_V_MSG(pc == 0, Vector3(), "No points in Curve3D."); - real_t idx_interval = offset_end - offset_begin; - ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, 0, "Couldn't find baked segment."); + if (pc == 1) { + return baked_point_cache[0]; + } - real_t frac = (p_offset - offset_begin) / idx_interval; + p_offset = CLAMP(p_offset, 0.0, get_baked_length()); // PathFollower implement wrapping logic. - return Math::lerp(r[idx], r[idx + 1], (real_t)frac); + Curve3D::Interval interval = _find_interval(p_offset); + return _sample_baked(interval, p_cubic); } -Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) const { +Transform3D Curve3D::sample_baked_with_rotation(real_t p_offset, bool p_cubic, bool p_apply_tilt) const { if (baked_cache_dirty) { _bake(); } - // Validate: Curve may not have baked up vectors. - int count = baked_up_vector_cache.size(); - ERR_FAIL_COND_V_MSG(count == 0, Vector3(0, 1, 0), "No up vectors in Curve3D."); + // Validate: Curve may not have baked points. + const int point_count = baked_point_cache.size(); + ERR_FAIL_COND_V_MSG(point_count == 0, Transform3D(), "No points in Curve3D."); - if (count == 1) { - return baked_up_vector_cache.get(0); + if (point_count == 1) { + Transform3D t; + t.origin = baked_point_cache.get(0); + ERR_FAIL_V_MSG(t, "Only 1 point in Curve3D."); } - const Vector3 *r = baked_up_vector_cache.ptr(); - const Vector3 *rp = baked_point_cache.ptr(); - const real_t *rt = baked_tilt_cache.ptr(); + p_offset = CLAMP(p_offset, 0.0, get_baked_length()); // PathFollower implement wrapping logic. - int start = 0; - int end = count; - int idx = (end + start) / 2; - // Binary search to find baked points. - while (start < idx) { - real_t offset = baked_dist_cache[idx]; - if (p_offset <= offset) { - end = idx; - } else { - start = idx; - } - idx = (end + start) / 2; - } + // 0. Find interval for all sampling steps. + Curve3D::Interval interval = _find_interval(p_offset); + + // 1. Sample position. + Vector3 pos = _sample_baked(interval, p_cubic); + + // 2. Sample rotation frame. + Basis frame = _sample_posture(interval, p_apply_tilt); + + return Transform3D(frame, pos); +} - if (idx == count - 1) { - return p_apply_tilt ? r[idx].rotated((rp[idx] - rp[idx - 1]).normalized(), rt[idx]) : r[idx]; +real_t Curve3D::sample_baked_tilt(real_t p_offset) const { + if (baked_cache_dirty) { + _bake(); } - real_t offset_begin = baked_dist_cache[idx]; - real_t offset_end = baked_dist_cache[idx + 1]; + // Validate: Curve may not have baked tilts. + int pc = baked_tilt_cache.size(); + ERR_FAIL_COND_V_MSG(pc == 0, 0, "No tilts in Curve3D."); - real_t idx_interval = offset_end - offset_begin; - ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(0, 1, 0), "Couldn't find baked segment."); + if (pc == 1) { + return baked_tilt_cache.get(0); + } - real_t frac = (p_offset - offset_begin) / idx_interval; + p_offset = CLAMP(p_offset, 0.0, get_baked_length()); // PathFollower implement wrapping logic - Vector3 forward = (rp[idx + 1] - rp[idx]).normalized(); - Vector3 up = r[idx]; - Vector3 up1 = r[idx + 1]; + Curve3D::Interval interval = _find_interval(p_offset); + return _sample_baked_tilt(interval); +} - if (p_apply_tilt) { - up.rotate(forward, rt[idx]); - up1.rotate(idx + 2 >= count ? forward : (rp[idx + 2] - rp[idx + 1]).normalized(), rt[idx + 1]); +Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) const { + if (baked_cache_dirty) { + _bake(); } - Vector3 axis = up.cross(up1); + // Validate: Curve may not have baked up vectors. + ERR_FAIL_COND_V_MSG(!up_vector_enabled, Vector3(0, 1, 0), "No up vectors in Curve3D."); - if (axis.length_squared() < CMP_EPSILON2) { - axis = forward; - } else { - axis.normalize(); + int count = baked_up_vector_cache.size(); + if (count == 1) { + return baked_up_vector_cache.get(0); } - return up.rotated(axis, up.angle_to(up1) * frac); + p_offset = CLAMP(p_offset, 0.0, get_baked_length()); // PathFollower implement wrapping logic. + + Curve3D::Interval interval = _find_interval(p_offset); + return _sample_posture(interval, p_apply_tilt).get_column(1); } PackedVector3Array Curve3D::get_baked_points() const { @@ -1942,6 +1996,50 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con return tess; } +Vector<RBMap<real_t, Vector3>> Curve3D::_tessellate_even_length(int p_max_stages, real_t p_length) const { + Vector<RBMap<real_t, Vector3>> midpoints; + ERR_FAIL_COND_V_MSG(points.size() < 2, midpoints, "Curve must have at least 2 control point"); + + midpoints.resize(points.size() - 1); + + for (int i = 0; i < points.size() - 1; i++) { + _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_length); + } + return midpoints; +} + +PackedVector3Array Curve3D::tessellate_even_length(int p_max_stages, real_t p_length) const { + PackedVector3Array tess; + + Vector<RBMap<real_t, Vector3>> midpoints = _tessellate_even_length(p_max_stages, p_length); + if (midpoints.size() == 0) { + return tess; + } + + int pc = 1; + for (int i = 0; i < points.size() - 1; i++) { + pc++; + pc += midpoints[i].size(); + } + + tess.resize(pc); + Vector3 *bpw = tess.ptrw(); + bpw[0] = points[0].position; + int pidx = 0; + + for (int i = 0; i < points.size() - 1; i++) { + for (const KeyValue<real_t, Vector3> &E : midpoints[i]) { + pidx++; + bpw[pidx] = E.value; + } + + pidx++; + bpw[pidx] = points[i + 1].position; + } + + return tess; +} + bool Curve3D::_set(const StringName &p_name, const Variant &p_value) { Vector<String> components = String(p_name).split("/", true, 2); if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) { @@ -2034,6 +2132,7 @@ void Curve3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve3D::get_baked_length); ClassDB::bind_method(D_METHOD("sample_baked", "offset", "cubic"), &Curve3D::sample_baked, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("sample_baked_with_rotation", "offset", "cubic", "apply_tilt"), &Curve3D::sample_baked_with_rotation, DEFVAL(false), DEFVAL(false)); ClassDB::bind_method(D_METHOD("sample_baked_up_vector", "offset", "apply_tilt"), &Curve3D::sample_baked_up_vector, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve3D::get_baked_points); ClassDB::bind_method(D_METHOD("get_baked_tilts"), &Curve3D::get_baked_tilts); @@ -2041,6 +2140,7 @@ void Curve3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve3D::get_closest_point); ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve3D::get_closest_offset); ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve3D::tessellate, DEFVAL(5), DEFVAL(4)); + ClassDB::bind_method(D_METHOD("tessellate_even_length", "max_stages", "tolerance_length"), &Curve3D::tessellate_even_length, DEFVAL(5), DEFVAL(0.2)); ClassDB::bind_method(D_METHOD("_get_data"), &Curve3D::_get_data); ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve3D::_set_data); diff --git a/scene/resources/curve.h b/scene/resources/curve.h index fa1d35aab1..88c3cf3ae6 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -238,15 +238,11 @@ class Curve3D : public Resource { Vector<Point> points; - struct BakedPoint { - real_t ofs = 0.0; - Vector3 point; - }; - mutable bool baked_cache_dirty = false; mutable PackedVector3Array baked_point_cache; mutable Vector<real_t> baked_tilt_cache; mutable PackedVector3Array baked_up_vector_cache; + mutable PackedVector3Array baked_forward_vector_cache; mutable Vector<real_t> baked_dist_cache; mutable real_t baked_max_ofs = 0.0; @@ -254,10 +250,20 @@ class Curve3D : public Resource { void _bake() const; + struct Interval { + int idx; + real_t frac; + }; + Interval _find_interval(real_t p_offset) const; + Vector3 _sample_baked(Interval p_interval, bool p_cubic) const; + real_t _sample_baked_tilt(Interval p_interval) const; + Basis _sample_posture(Interval p_interval, bool p_apply_tilt = false) const; + real_t bake_interval = 0.2; bool up_vector_enabled = true; void _bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const; + void _bake_segment3d_even_length(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_length) const; Dictionary _get_data() const; void _set_data(const Dictionary &p_data); @@ -268,6 +274,8 @@ class Curve3D : public Resource { void _add_point(const Vector3 &p_position, const Vector3 &p_in = Vector3(), const Vector3 &p_out = Vector3(), int p_atpos = -1); void _remove_point(int p_index); + Vector<RBMap<real_t, Vector3>> _tessellate_even_length(int p_max_stages = 5, real_t p_length = 0.2) const; + protected: static void _bind_methods(); @@ -296,15 +304,17 @@ public: real_t get_baked_length() const; Vector3 sample_baked(real_t p_offset, bool p_cubic = false) const; + Transform3D sample_baked_with_rotation(real_t p_offset, bool p_cubic = false, bool p_apply_tilt = false) const; real_t sample_baked_tilt(real_t p_offset) const; Vector3 sample_baked_up_vector(real_t p_offset, bool p_apply_tilt = false) const; - PackedVector3Array get_baked_points() const; //useful for going through + PackedVector3Array get_baked_points() const; // Useful for going through. Vector<real_t> get_baked_tilts() const; //useful for going through PackedVector3Array get_baked_up_vectors() const; Vector3 get_closest_point(const Vector3 &p_to_point) const; real_t get_closest_offset(const Vector3 &p_to_point) const; - PackedVector3Array tessellate(int p_max_stages = 5, real_t p_tolerance = 4) const; //useful for display + PackedVector3Array tessellate(int p_max_stages = 5, real_t p_tolerance = 4) const; // Useful for display. + PackedVector3Array tessellate_even_length(int p_max_stages = 5, real_t p_length = 0.2) const; // Useful for baking. Curve3D(); }; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 894936acd7..f179b4b818 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -84,7 +84,8 @@ static Ref<ImageTexture> generate_icon(int p_index) { // with integer scales. const bool upsample = !Math::is_equal_approx(Math::round(scale), scale); ImageLoaderSVG img_loader; - img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, HashMap<Color, Color>()); + Error err = img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, HashMap<Color, Color>()); + ERR_FAIL_COND_V_MSG(err != OK, Ref<ImageTexture>(), "Failed generating icon, unsupported or invalid SVG data in default theme."); #endif return ImageTexture::create_from_image(img); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 1c99fa5554..f46faa1013 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -71,7 +71,7 @@ static Array _sanitize_node_pinned_properties(Node *p_node) { } Node *SceneState::instantiate(GenEditState p_edit_state) const { - // nodes where instancing failed (because something is missing) + // Nodes where instantiation failed (because something is missing.) List<Node *> stray_instances; #define NODE_FROM_ID(p_name, p_id) \ @@ -122,7 +122,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { NODE_FROM_ID(nparent, n.parent); #ifdef DEBUG_ENABLED if (!nparent && (n.parent & FLAG_ID_IS_PATH)) { - WARN_PRINT(String("Parent path '" + String(node_paths[n.parent & FLAG_MASK]) + "' for node '" + String(snames[n.name]) + "' has vanished when instancing: '" + get_path() + "'.").ascii().get_data()); + WARN_PRINT(String("Parent path '" + String(node_paths[n.parent & FLAG_MASK]) + "' for node '" + String(snames[n.name]) + "' has vanished when instantiating: '" + get_path() + "'.").ascii().get_data()); old_parent_path = String(node_paths[n.parent & FLAG_MASK]).trim_prefix("./").replace("/", "@"); nparent = ret_nodes[0]; } @@ -131,7 +131,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { } else { // i == 0 is root node. ERR_FAIL_COND_V_MSG(n.parent != -1, nullptr, vformat("Invalid scene: root node %s cannot specify a parent node.", snames[n.name])); - ERR_FAIL_COND_V_MSG(n.type == TYPE_INSTANCED && base_scene_idx < 0, nullptr, vformat("Invalid scene: root node %s in an instance, but there's no base scene.", snames[n.name])); + ERR_FAIL_COND_V_MSG(n.type == TYPE_INSTANTIATED && base_scene_idx < 0, nullptr, vformat("Invalid scene: root node %s in an instance, but there's no base scene.", snames[n.name])); } Node *node = nullptr; @@ -169,7 +169,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { ERR_FAIL_COND_V(!node, nullptr); } - } else if (n.type == TYPE_INSTANCED) { + } else if (n.type == TYPE_INSTANTIATED) { //get the node from somewhere, it likely already exists from another instance if (parent) { node = parent->_get_child_by_name(snames[n.name]); @@ -345,7 +345,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { node->add_to_group(snames[n.groups[j]], true); } - if (n.instance >= 0 || n.type != TYPE_INSTANCED || i == 0) { + if (n.instance >= 0 || n.type != TYPE_INSTANTIATED || i == 0) { //if node was not part of instance, must set its name, parenthood and ownership if (i > 0) { if (parent) { @@ -382,7 +382,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { } } - // we only want to deal with pinned flag if instancing as pure main (no instance, no inheriting) + // We only want to deal with pinned flag if instantiating as pure main (no instance, no inheriting.) if (p_edit_state == GEN_EDIT_STATE_MAIN) { _sanitize_node_pinned_properties(node); } else { @@ -665,7 +665,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has // Save the right type. If this node was created by an instance // then flag that the node should not be created but reused if (states_stack.is_empty() && !is_editable_instance) { - //this node is not part of an instancing process, so save the type + //This node is not part of an instantiation process, so save the type. if (missing_node != nullptr) { // It's a missing node (type non existent on load). nd.type = _nm_get_string(missing_node->get_original_class(), name_map); @@ -675,7 +675,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has } else { // this node is part of an instantiated process, so do not save the type. // instead, save that it was instantiated - nd.type = TYPE_INSTANCED; + nd.type = TYPE_INSTANTIATED; } // determine whether to save this node or not @@ -1351,7 +1351,7 @@ int SceneState::get_node_count() const { StringName SceneState::get_node_type(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, nodes.size(), StringName()); - if (nodes[p_idx].type == TYPE_INSTANCED) { + if (nodes[p_idx].type == TYPE_INSTANTIATED) { return StringName(); } return names[nodes[p_idx].type]; diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index c6f82ddd5e..a30ec54d85 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -108,7 +108,7 @@ protected: public: enum { FLAG_ID_IS_PATH = (1 << 30), - TYPE_INSTANCED = 0x7FFFFFFF, + TYPE_INSTANTIATED = 0x7FFFFFFF, FLAG_INSTANCE_IS_PLACEHOLDER = (1 << 30), FLAG_PATH_PROPERTY_IS_NODE = (1 << 30), FLAG_PROP_NAME_MASK = FLAG_PATH_PROPERTY_IS_NODE - 1, diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 4c6d533c72..2e8fcb3717 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -2779,13 +2779,7 @@ void TextMesh::_generate_glyph_mesh_data(const GlyphMeshKey &p_key, const Glyph real_t step = CLAMP(curve_step / (p0 - p3).length(), 0.01, 0.5); real_t t = step; while (t < 1.0) { - real_t omt = (1.0 - t); - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = t * t; - real_t t3 = t2 * t; - - Vector2 point = p0 * omt3 + p1 * omt2 * t * 3.0 + p2 * omt * t2 * 3.0 + p3 * t3; + Vector2 point = p0.bezier_interpolate(p1, p2, p3, t); Vector2 p = point * pixel_size + origin; polygon.push_back(ContourPoint(p, false)); t += step; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 98a4909599..8b2b7e118c 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -217,7 +217,7 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars if (next_tag.fields.has("type")) { type = packed_scene->get_state()->add_name(next_tag.fields["type"]); } else { - type = SceneState::TYPE_INSTANCED; //no type? assume this was instantiated + type = SceneState::TYPE_INSTANTIATED; //no type? assume this was instantiated } HashSet<StringName> path_properties; @@ -256,7 +256,7 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars if (next_tag.fields.has("owner")) { owner = packed_scene->get_state()->add_node_path(next_tag.fields["owner"]); } else { - if (parent != -1 && !(type == SceneState::TYPE_INSTANCED && instance == -1)) { + if (parent != -1 && !(type == SceneState::TYPE_INSTANTIATED && instance == -1)) { owner = 0; //if no owner, owner is root } } @@ -601,9 +601,13 @@ Error ResourceLoaderText::load() { resource_current++; int_resources[id] = res; //always assign int resources - if (do_assign && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { - res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); - res->set_scene_unique_id(id); + if (do_assign) { + if (cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE) { + res->set_path(path); + } else { + res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); + res->set_scene_unique_id(id); + } } Dictionary missing_resource_properties; diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp index af84144591..413670d23e 100644 --- a/scene/resources/shape_2d.cpp +++ b/scene/resources/shape_2d.cpp @@ -124,5 +124,7 @@ Shape2D::Shape2D(const RID &p_rid) { } Shape2D::~Shape2D() { - PhysicsServer2D::get_singleton()->free(shape); + if (PhysicsServer2D::get_singleton() != nullptr) { + PhysicsServer2D::get_singleton()->free(shape); + } } diff --git a/scene/resources/shape_3d.cpp b/scene/resources/shape_3d.cpp index 4423c1d7bb..44f21d2a48 100644 --- a/scene/resources/shape_3d.cpp +++ b/scene/resources/shape_3d.cpp @@ -128,5 +128,7 @@ Shape3D::Shape3D(RID p_shape) : shape(p_shape) {} Shape3D::~Shape3D() { - PhysicsServer3D::get_singleton()->free(shape); + if (PhysicsServer3D::get_singleton() != nullptr) { + PhysicsServer3D::get_singleton()->free(shape); + } } diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index a15c03d675..bc7918c662 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -206,8 +206,6 @@ SceneStringNames::SceneStringNames() { theme_changed = StaticCString::create("theme_changed"); parameters_base_path = "parameters/"; - tracks_changed = "tracks_changed"; - shader_overrides_group = StaticCString::create("_shader_overrides_group_"); shader_overrides_group_active = StaticCString::create("_shader_overrides_group_active_"); diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 5589ab327f..7ff866cacd 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -209,8 +209,6 @@ public: StringName parameters_base_path; - StringName tracks_changed; - StringName _window_group; StringName _window_input; StringName _window_unhandled_input; diff --git a/servers/audio/effects/audio_effect_distortion.cpp b/servers/audio/effects/audio_effect_distortion.cpp index 95156d8d66..25ca0cfdfe 100644 --- a/servers/audio/effects/audio_effect_distortion.cpp +++ b/servers/audio/effects/audio_effect_distortion.cpp @@ -160,10 +160,10 @@ void AudioEffectDistortion::_bind_methods() { ClassDB::bind_method(D_METHOD("get_post_gain"), &AudioEffectDistortion::get_post_gain); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Clip,ATan,LoFi,Overdrive,Wave Shape"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pre_gain", PROPERTY_HINT_RANGE, "-60,60,0.01"), "set_pre_gain", "get_pre_gain"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pre_gain", PROPERTY_HINT_RANGE, "-60,60,0.01,suffix:dB"), "set_pre_gain", "get_pre_gain"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "keep_hf_hz", PROPERTY_HINT_RANGE, "1,20500,1,suffix:Hz"), "set_keep_hf_hz", "get_keep_hf_hz"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drive", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drive", "get_drive"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "post_gain", PROPERTY_HINT_RANGE, "-80,24,0.01"), "set_post_gain", "get_post_gain"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "post_gain", PROPERTY_HINT_RANGE, "-80,24,0.01,suffix:dB"), "set_post_gain", "get_post_gain"); BIND_ENUM_CONSTANT(MODE_CLIP); BIND_ENUM_CONSTANT(MODE_ATAN); diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/servers/physics_3d/godot_soft_body_3d.cpp index 77110c5fbc..31b6b9e12f 100644 --- a/servers/physics_3d/godot_soft_body_3d.cpp +++ b/servers/physics_3d/godot_soft_body_3d.cpp @@ -1011,7 +1011,6 @@ void GodotSoftBody3D::predict_motion(real_t p_delta) { } break; case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { - gravity = Vector3(0, 0, 0); gravity = area_gravity; gravity_done = area_gravity_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE; } break; diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 21be311637..c5a93cc390 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -479,8 +479,8 @@ void PhysicsTestMotionParameters2D::set_exclude_bodies(const TypedArray<RID> &p_ } } -Array PhysicsTestMotionParameters2D::get_exclude_objects() const { - Array exclude; +TypedArray<uint64_t> PhysicsTestMotionParameters2D::get_exclude_objects() const { + TypedArray<uint64_t> exclude; exclude.resize(parameters.exclude_objects.size()); int object_index = 0; @@ -491,7 +491,7 @@ Array PhysicsTestMotionParameters2D::get_exclude_objects() const { return exclude; } -void PhysicsTestMotionParameters2D::set_exclude_objects(const Array &p_exclude) { +void PhysicsTestMotionParameters2D::set_exclude_objects(const TypedArray<uint64_t> &p_exclude) { for (int i = 0; i < p_exclude.size(); ++i) { ObjectID object_id = p_exclude[i]; ERR_CONTINUE(object_id.is_null()); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 95425e72e8..8b4b5ae4de 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -732,8 +732,8 @@ public: TypedArray<RID> get_exclude_bodies() const; void set_exclude_bodies(const TypedArray<RID> &p_exclude); - Array get_exclude_objects() const; - void set_exclude_objects(const Array &p_exclude); + TypedArray<uint64_t> get_exclude_objects() const; + void set_exclude_objects(const TypedArray<uint64_t> &p_exclude); bool is_recovery_as_collision_enabled() const { return parameters.recovery_as_collision; } void set_recovery_as_collision_enabled(bool p_enabled) { parameters.recovery_as_collision = p_enabled; } diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index db21e1db06..aecb687d5f 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -169,25 +169,25 @@ PhysicsDirectBodyState3D::PhysicsDirectBodyState3D() {} /////////////////////////////////////////////////////// -void PhysicsRayQueryParameters3D::set_exclude(const Vector<RID> &p_exclude) { +void PhysicsRayQueryParameters3D::set_exclude(const TypedArray<RID> &p_exclude) { parameters.exclude.clear(); for (int i = 0; i < p_exclude.size(); i++) { parameters.exclude.insert(p_exclude[i]); } } -Vector<RID> PhysicsRayQueryParameters3D::get_exclude() const { - Vector<RID> ret; +TypedArray<RID> PhysicsRayQueryParameters3D::get_exclude() const { + TypedArray<RID> ret; ret.resize(parameters.exclude.size()); int idx = 0; for (const RID &E : parameters.exclude) { - ret.write[idx++] = E; + ret[idx++] = E; } return ret; } void PhysicsRayQueryParameters3D::_bind_methods() { - ClassDB::bind_static_method("PhysicsRayQueryParameters3D", D_METHOD("create", "from", "to", "collision_mask", "exclude"), &PhysicsRayQueryParameters3D::create, DEFVAL(UINT32_MAX), DEFVAL(Vector<RID>())); + ClassDB::bind_static_method("PhysicsRayQueryParameters3D", D_METHOD("create", "from", "to", "collision_mask", "exclude"), &PhysicsRayQueryParameters3D::create, DEFVAL(UINT32_MAX), DEFVAL(TypedArray<RID>())); ClassDB::bind_method(D_METHOD("set_from", "from"), &PhysicsRayQueryParameters3D::set_from); ClassDB::bind_method(D_METHOD("get_from"), &PhysicsRayQueryParameters3D::get_from); @@ -225,7 +225,7 @@ void PhysicsRayQueryParameters3D::_bind_methods() { /////////////////////////////////////////////////////// -Ref<PhysicsRayQueryParameters3D> PhysicsRayQueryParameters3D::create(Vector3 p_from, Vector3 p_to, uint32_t p_mask, const Vector<RID> &p_exclude) { +Ref<PhysicsRayQueryParameters3D> PhysicsRayQueryParameters3D::create(Vector3 p_from, Vector3 p_to, uint32_t p_mask, const TypedArray<RID> &p_exclude) { Ref<PhysicsRayQueryParameters3D> params; params.instantiate(); params->set_from(p_from); @@ -235,19 +235,19 @@ Ref<PhysicsRayQueryParameters3D> PhysicsRayQueryParameters3D::create(Vector3 p_f return params; } -void PhysicsPointQueryParameters3D::set_exclude(const Vector<RID> &p_exclude) { +void PhysicsPointQueryParameters3D::set_exclude(const TypedArray<RID> &p_exclude) { parameters.exclude.clear(); for (int i = 0; i < p_exclude.size(); i++) { parameters.exclude.insert(p_exclude[i]); } } -Vector<RID> PhysicsPointQueryParameters3D::get_exclude() const { - Vector<RID> ret; +TypedArray<RID> PhysicsPointQueryParameters3D::get_exclude() const { + TypedArray<RID> ret; ret.resize(parameters.exclude.size()); int idx = 0; for (const RID &E : parameters.exclude) { - ret.write[idx++] = E; + ret[idx++] = E; } return ret; } @@ -290,19 +290,19 @@ void PhysicsShapeQueryParameters3D::set_shape_rid(const RID &p_shape) { } } -void PhysicsShapeQueryParameters3D::set_exclude(const Vector<RID> &p_exclude) { +void PhysicsShapeQueryParameters3D::set_exclude(const TypedArray<RID> &p_exclude) { parameters.exclude.clear(); for (int i = 0; i < p_exclude.size(); i++) { parameters.exclude.insert(p_exclude[i]); } } -Vector<RID> PhysicsShapeQueryParameters3D::get_exclude() const { - Vector<RID> ret; +TypedArray<RID> PhysicsShapeQueryParameters3D::get_exclude() const { + TypedArray<RID> ret; ret.resize(parameters.exclude.size()); int idx = 0; for (const RID &E : parameters.exclude) { - ret.write[idx++] = E; + ret[idx++] = E; } return ret; } @@ -482,37 +482,37 @@ void PhysicsDirectSpaceState3D::_bind_methods() { /////////////////////////////// -Vector<RID> PhysicsTestMotionParameters3D::get_exclude_bodies() const { - Vector<RID> exclude; +TypedArray<RID> PhysicsTestMotionParameters3D::get_exclude_bodies() const { + TypedArray<RID> exclude; exclude.resize(parameters.exclude_bodies.size()); int body_index = 0; - for (RID body : parameters.exclude_bodies) { - exclude.write[body_index++] = body; + for (const RID &body : parameters.exclude_bodies) { + exclude[body_index++] = body; } return exclude; } -void PhysicsTestMotionParameters3D::set_exclude_bodies(const Vector<RID> &p_exclude) { - for (RID body : p_exclude) { - parameters.exclude_bodies.insert(body); +void PhysicsTestMotionParameters3D::set_exclude_bodies(const TypedArray<RID> &p_exclude) { + for (int i = 0; i < p_exclude.size(); i++) { + parameters.exclude_bodies.insert(p_exclude[i]); } } -Array PhysicsTestMotionParameters3D::get_exclude_objects() const { - Array exclude; +TypedArray<uint64_t> PhysicsTestMotionParameters3D::get_exclude_objects() const { + TypedArray<uint64_t> exclude; exclude.resize(parameters.exclude_objects.size()); int object_index = 0; - for (ObjectID object_id : parameters.exclude_objects) { + for (const ObjectID &object_id : parameters.exclude_objects) { exclude[object_index++] = object_id; } return exclude; } -void PhysicsTestMotionParameters3D::set_exclude_objects(const Array &p_exclude) { +void PhysicsTestMotionParameters3D::set_exclude_objects(const TypedArray<uint64_t> &p_exclude) { for (int i = 0; i < p_exclude.size(); ++i) { ObjectID object_id = p_exclude[i]; ERR_CONTINUE(object_id.is_null()); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 87877ad52d..5335bc3109 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -822,7 +822,7 @@ protected: static void _bind_methods(); public: - static Ref<PhysicsRayQueryParameters3D> create(Vector3 p_from, Vector3 p_to, uint32_t p_mask, const Vector<RID> &p_exclude); + static Ref<PhysicsRayQueryParameters3D> create(Vector3 p_from, Vector3 p_to, uint32_t p_mask, const TypedArray<RID> &p_exclude); const PhysicsDirectSpaceState3D::RayParameters &get_parameters() const { return parameters; } void set_from(const Vector3 &p_from) { parameters.from = p_from; } @@ -846,8 +846,8 @@ public: void set_hit_back_faces(bool p_enable) { parameters.hit_back_faces = p_enable; } bool is_hit_back_faces_enabled() const { return parameters.hit_back_faces; } - void set_exclude(const Vector<RID> &p_exclude); - Vector<RID> get_exclude() const; + void set_exclude(const TypedArray<RID> &p_exclude); + TypedArray<RID> get_exclude() const; }; class PhysicsPointQueryParameters3D : public RefCounted { @@ -873,8 +873,8 @@ public: void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; } bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; } - void set_exclude(const Vector<RID> &p_exclude); - Vector<RID> get_exclude() const; + void set_exclude(const TypedArray<RID> &p_exclude); + TypedArray<RID> get_exclude() const; }; class PhysicsShapeQueryParameters3D : public RefCounted { @@ -914,8 +914,8 @@ public: void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; } bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; } - void set_exclude(const Vector<RID> &p_exclude); - Vector<RID> get_exclude() const; + void set_exclude(const TypedArray<RID> &p_exclude); + TypedArray<RID> get_exclude() const; }; class PhysicsTestMotionParameters3D : public RefCounted { @@ -944,11 +944,11 @@ public: bool is_collide_separation_ray_enabled() const { return parameters.collide_separation_ray; } void set_collide_separation_ray_enabled(bool p_enabled) { parameters.collide_separation_ray = p_enabled; } - Vector<RID> get_exclude_bodies() const; - void set_exclude_bodies(const Vector<RID> &p_exclude); + TypedArray<RID> get_exclude_bodies() const; + void set_exclude_bodies(const TypedArray<RID> &p_exclude); - Array get_exclude_objects() const; - void set_exclude_objects(const Array &p_exclude); + TypedArray<uint64_t> get_exclude_objects() const; + void set_exclude_objects(const TypedArray<uint64_t> &p_exclude); bool is_recovery_as_collision_enabled() const { return parameters.recovery_as_collision; } void set_recovery_as_collision_enabled(bool p_enabled) { parameters.recovery_as_collision = p_enabled; } diff --git a/servers/rendering/dummy/storage/mesh_storage.cpp b/servers/rendering/dummy/storage/mesh_storage.cpp index adf736eee3..52de998835 100644 --- a/servers/rendering/dummy/storage/mesh_storage.cpp +++ b/servers/rendering/dummy/storage/mesh_storage.cpp @@ -56,3 +56,10 @@ void MeshStorage::mesh_free(RID p_rid) { mesh_owner.free(p_rid); } + +void MeshStorage::mesh_clear(RID p_mesh) { + DummyMesh *m = mesh_owner.get_or_null(p_mesh); + ERR_FAIL_COND(!m); + + m->surfaces.clear(); +} diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h index 4399f4ab66..28fe8cb80d 100644 --- a/servers/rendering/dummy/storage/mesh_storage.h +++ b/servers/rendering/dummy/storage/mesh_storage.h @@ -116,7 +116,7 @@ public: virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override { return AABB(); } virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override {} - virtual void mesh_clear(RID p_mesh) override {} + virtual void mesh_clear(RID p_mesh) override; /* MESH INSTANCE */ diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index a17d734e10..dd89504f38 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -80,6 +80,7 @@ public: virtual void texture_free(RID p_rid) override { // delete the texture DummyTexture *texture = texture_owner.get_or_null(p_rid); + ERR_FAIL_COND(!texture); texture_owner.free(p_rid); memdelete(texture); }; diff --git a/servers/rendering/renderer_canvas_render.cpp b/servers/rendering/renderer_canvas_render.cpp index 623f0c647b..07394b49a3 100644 --- a/servers/rendering/renderer_canvas_render.cpp +++ b/servers/rendering/renderer_canvas_render.cpp @@ -32,7 +32,7 @@ #include "servers/rendering/rendering_server_globals.h" const Rect2 &RendererCanvasRender::Item::get_rect() const { - if (custom_rect || (!rect_dirty && !update_when_visible)) { + if (custom_rect || (!rect_dirty && !update_when_visible && skeleton == RID())) { return rect; } @@ -80,7 +80,7 @@ const Rect2 &RendererCanvasRender::Item::get_rect() const { } break; case Item::Command::TYPE_MESH: { const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c); - AABB aabb = RSG::mesh_storage->mesh_get_aabb(mesh->mesh, RID()); + AABB aabb = RSG::mesh_storage->mesh_get_aabb(mesh->mesh, skeleton); r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index 0ab21bc4ef..a05db8c563 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -510,16 +510,18 @@ void CopyEffects::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuff memset(©_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant)); - copy_to_fb.push_constant.use_section = true; + copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_USE_SECTION; copy_to_fb.push_constant.section[0] = p_uv_rect.position.x; copy_to_fb.push_constant.section[1] = p_uv_rect.position.y; copy_to_fb.push_constant.section[2] = p_uv_rect.size.x; copy_to_fb.push_constant.section[3] = p_uv_rect.size.y; if (p_flip_y) { - copy_to_fb.push_constant.flip_y = true; + copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_FLIP_Y; } + copy_to_fb.push_constant.luminance_multiplier = 1.0; + // setup our uniforms RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); @@ -537,28 +539,35 @@ void CopyEffects::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuff RD::get_singleton()->draw_list_draw(draw_list, true); } -void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview, bool p_alpha_to_one) { +void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview, bool p_alpha_to_one, bool p_linear) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); ERR_FAIL_NULL(material_storage); memset(©_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant)); + copy_to_fb.push_constant.luminance_multiplier = 1.0; if (p_flip_y) { - copy_to_fb.push_constant.flip_y = true; + copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_FLIP_Y; } if (p_force_luminance) { - copy_to_fb.push_constant.force_luminance = true; + copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_FORCE_LUMINANCE; } if (p_alpha_to_zero) { - copy_to_fb.push_constant.alpha_to_zero = true; + copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_ALPHA_TO_ZERO; } if (p_srgb) { - copy_to_fb.push_constant.srgb = true; + copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_SRGB; } if (p_alpha_to_one) { - copy_to_fb.push_constant.alpha_to_one = true; + copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_ALPHA_TO_ONE; + } + if (p_linear) { + // Used for copying to a linear buffer. In the mobile renderer we divide the contents of the linear buffer + // to allow for a wider effective range. + copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_LINEAR; + copy_to_fb.push_constant.luminance_multiplier = prefer_raster_effects ? 2.0 : 1.0; } // setup our uniforms diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h index cda4f70730..83f7a51a36 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.h +++ b/servers/rendering/renderer_rd/effects/copy_effects.h @@ -181,16 +181,21 @@ private: COPY_TO_FB_MAX, }; + enum CopyToFBFlags { + COPY_TO_FB_FLAG_FLIP_Y = (1 << 0), + COPY_TO_FB_FLAG_USE_SECTION = (1 << 1), + COPY_TO_FB_FLAG_FORCE_LUMINANCE = (1 << 2), + COPY_TO_FB_FLAG_ALPHA_TO_ZERO = (1 << 3), + COPY_TO_FB_FLAG_SRGB = (1 << 4), + COPY_TO_FB_FLAG_ALPHA_TO_ONE = (1 << 5), + COPY_TO_FB_FLAG_LINEAR = (1 << 6), + }; + struct CopyToFbPushConstant { float section[4]; float pixel_size[2]; - uint32_t flip_y; - uint32_t use_section; - - uint32_t force_luminance; - uint32_t alpha_to_zero; - uint32_t srgb; - uint32_t alpha_to_one; + float luminance_multiplier; + uint32_t flags; float set_color[4]; }; @@ -322,7 +327,7 @@ public: void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array); void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false); void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far); - void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false, bool alpha_to_one = false); + void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false, bool alpha_to_one = false, bool p_linear = false); void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false); void copy_raster(RID p_source_texture, RID p_dest_framebuffer); diff --git a/servers/rendering/renderer_rd/effects/resolve.h b/servers/rendering/renderer_rd/effects/resolve.h index 2a4cd06827..49fba921d5 100644 --- a/servers/rendering/renderer_rd/effects/resolve.h +++ b/servers/rendering/renderer_rd/effects/resolve.h @@ -65,8 +65,8 @@ public: Resolve(); ~Resolve(); - void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL); - void resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL); + void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); + void resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); }; } // namespace RendererRD diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp index 9653382e96..8e43869b4d 100644 --- a/servers/rendering/renderer_rd/effects/ss_effects.cpp +++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp @@ -1332,7 +1332,6 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu for (int pass = 0; pass < blur_passes; pass++) { int blur_pipeline = SSAO_BLUR_PASS; if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { - blur_pipeline = SSAO_BLUR_PASS_SMART; if (pass < blur_passes - 2) { blur_pipeline = SSAO_BLUR_PASS_WIDE; } else { diff --git a/servers/rendering/renderer_rd/effects/vrs.cpp b/servers/rendering/renderer_rd/effects/vrs.cpp index 5ff00aa94c..701d53b41d 100644 --- a/servers/rendering/renderer_rd/effects/vrs.cpp +++ b/servers/rendering/renderer_rd/effects/vrs.cpp @@ -92,18 +92,15 @@ void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multi } Size2i VRS::get_vrs_texture_size(const Size2i p_base_size) const { - // TODO we should find some way to store this properly, we're assuming 16x16 as this seems to be the standard but in our vrs_capacities we - // obtain a minimum and maximum size, and we should choose something within this range and then make sure that is consistently set when creating - // our frame buffer. Also it is important that we make the resulting size we calculate down below available to the end user so they know the size - // of the VRS buffer to supply. - Size2i texel_size = Size2i(16, 16); - - int width = p_base_size.x / texel_size.x; - if (p_base_size.x % texel_size.x != 0) { + int32_t texel_width = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_WIDTH); + int32_t texel_height = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_HEIGHT); + + int width = p_base_size.x / texel_width; + if (p_base_size.x % texel_width != 0) { width++; } - int height = p_base_size.y / texel_size.y; - if (p_base_size.y % texel_size.y != 0) { + int height = p_base_size.y / texel_height; + if (p_base_size.y % texel_height != 0) { height++; } return Size2i(width, height); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 2d1d0e0951..3d1e04fe99 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1446,7 +1446,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } //full barrier here, we need raster, transfer and compute and it depends from the previous work - RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL); + RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL_BARRIERS, RD::BARRIER_MASK_ALL_BARRIERS); if (current_cluster_builder) { current_cluster_builder->begin(p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, !p_render_data->reflection_probe.is_valid()); @@ -1765,6 +1765,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co draw_sky = true; } break; case RS::ENV_BG_CANVAS: { + if (rb.is_valid()) { + RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target()); + copy_effects->copy_to_fb_rect(texture, color_only_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, true); + } keep_color = true; } break; case RS::ENV_BG_KEEP: { diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 670eb93e20..d9145b5818 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -210,10 +210,10 @@ class RenderForwardClustered : public RendererSceneRenderRD { float screen_mesh_lod_threshold = 0.0; RD::FramebufferFormatID framebuffer_format = 0; uint32_t element_offset = 0; - uint32_t barrier = RD::BARRIER_MASK_ALL; + uint32_t barrier = RD::BARRIER_MASK_ALL_BARRIERS; bool use_directional_soft_shadow = false; - RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) { + RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS) { elements = p_elements; element_info = p_element_info; element_count = p_element_count; @@ -596,7 +596,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { void _render_shadow_begin(); void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr); void _render_shadow_process(); - void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL); + void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); /* Render Scene */ void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 558aba62e1..f860bab15e 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -612,7 +612,7 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { } //full barrier here, we need raster, transfer and compute and it depends from the previous work - RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL); + RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL_BARRIERS, RD::BARRIER_MASK_ALL_BARRIERS); bool using_shadows = true; @@ -796,6 +796,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color draw_sky = true; } break; case RS::ENV_BG_CANVAS: { + if (rb.is_valid()) { + RID dest_framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS); + RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target()); + copy_effects->copy_to_fb_rect(texture, dest_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, true); + } keep_color = true; } break; case RS::ENV_BG_KEEP: { @@ -960,7 +965,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (!using_subpass_transparent) { // We're done with our subpasses so end our container pass - RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL); + RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS); RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass } @@ -1012,7 +1017,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass - RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL); + RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS); } else { RENDER_TIMESTAMP("Render Transparent"); @@ -1032,12 +1037,12 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &RenderForwardMobile::_render_list_thread_function, &render_list_params, thread_draw_lists.size(), -1, true, SNAME("ForwardMobileRenderSubpass")); WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); - RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL); + RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS); } else { //single threaded RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count); - RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL); + RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL_BARRIERS); } RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index ce64d805b7..6c85e1cffc 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -168,10 +168,10 @@ private: float screen_mesh_lod_threshold = 0.0; RD::FramebufferFormatID framebuffer_format = 0; uint32_t element_offset = 0; - uint32_t barrier = RD::BARRIER_MASK_ALL; + uint32_t barrier = RD::BARRIER_MASK_ALL_BARRIERS; uint32_t subpass = 0; - RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) { + RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS) { elements = p_elements; element_info = p_element_info; element_count = p_element_count; @@ -196,7 +196,7 @@ private: void _render_shadow_begin(); void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr); void _render_shadow_process(); - void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL); + void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); /* Render Scene */ diff --git a/servers/rendering/renderer_rd/framebuffer_cache_rd.h b/servers/rendering/renderer_rd/framebuffer_cache_rd.h index f50d6baa30..8cf25cf44a 100644 --- a/servers/rendering/renderer_rd/framebuffer_cache_rd.h +++ b/servers/rendering/renderer_rd/framebuffer_cache_rd.h @@ -254,11 +254,11 @@ public: RID get_cache_multipass(const Vector<RID> &p_textures, const Vector<RD::FramebufferPass> &p_passes, uint32_t p_views = 1) { uint32_t h = hash_murmur3_one_32(p_views); - h = hash_murmur3_one_32(p_textures.size()); + h = hash_murmur3_one_32(p_textures.size(), h); for (int i = 0; i < p_textures.size(); i++) { h = hash_murmur3_one_64(p_textures[i].get_id(), h); } - h = hash_murmur3_one_32(p_passes.size()); + h = hash_murmur3_one_32(p_passes.size(), h); for (int i = 0; i < p_passes.size(); i++) { h = _hash_pass(p_passes[i], h); } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 7e0070f8b7..cc8238a8dd 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -796,7 +796,6 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend RenderingServerDefault::redraw_request(); // active particles means redraw request - bool local_coords = true; int dpc = particles_storage->particles_get_draw_passes(pt->particles); if (dpc == 0) { break; //nothing to draw @@ -818,12 +817,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend if (particles_storage->particles_has_collision(pt->particles) && texture_storage->render_target_is_sdf_enabled(p_render_target)) { //pass collision information - Transform2D xform; - if (local_coords) { - xform = p_item->final_transform; - } else { - xform = p_canvas_transform_inverse; - } + Transform2D xform = p_item->final_transform; RID sdf_texture = texture_storage->render_target_get_sdf_texture(p_render_target); @@ -2681,16 +2675,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { primitive_arrays.index_array[3] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 6); } - { //default skeleton buffer - - shader.default_skeleton_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkeletonUniform)); - SkeletonUniform su; - _update_transform_2d_to_mat4(Transform2D(), su.skeleton_inverse); - _update_transform_2d_to_mat4(Transform2D(), su.skeleton_transform); - RD::get_singleton()->buffer_update(shader.default_skeleton_uniform_buffer, 0, sizeof(SkeletonUniform), &su); - - shader.default_skeleton_texture_buffer = RD::get_singleton()->texture_buffer_create(32, RD::DATA_FORMAT_R32G32B32A32_SFLOAT); - } { //default shadow texture to keep uniform set happy RD::TextureFormat tf; @@ -2834,8 +2818,6 @@ RendererCanvasRenderRD::~RendererCanvasRenderRD() { memdelete_arr(state.light_uniforms); RD::get_singleton()->free(state.lights_uniform_buffer); - RD::get_singleton()->free(shader.default_skeleton_uniform_buffer); - RD::get_singleton()->free(shader.default_skeleton_texture_buffer); } //shadow rendering diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index d1f3c9ec6a..3fff574098 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -144,10 +144,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender { RID quad_index_array; PipelineVariants pipeline_variants; - // default_skeleton uniform set - RID default_skeleton_uniform_buffer; - RID default_skeleton_texture_buffer; - ShaderCompiler compiler; } shader; @@ -409,11 +405,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender { uint32_t lights[4]; }; - struct SkeletonUniform { - float skeleton_transform[16]; - float skeleton_inverse[16]; - }; - Item *items[MAX_RENDER_ITEMS]; bool using_directional_lights = false; diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 8593e6b265..eb5f68849e 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -191,48 +191,6 @@ void main() { uv += 1e-5; } -#ifdef USE_ATTRIBUTES -#if 0 - if (bool(draw_data.flags & FLAGS_USE_SKELETON) && bone_weights != vec4(0.0)) { //must be a valid bone - //skeleton transform - ivec4 bone_indicesi = ivec4(bone_indices); - - uvec2 tex_ofs = bone_indicesi.x * 2; - - mat2x4 m; - m = mat2x4( - texelFetch(skeleton_buffer, tex_ofs + 0), - texelFetch(skeleton_buffer, tex_ofs + 1)) * - bone_weights.x; - - tex_ofs = bone_indicesi.y * 2; - - m += mat2x4( - texelFetch(skeleton_buffer, tex_ofs + 0), - texelFetch(skeleton_buffer, tex_ofs + 1)) * - bone_weights.y; - - tex_ofs = bone_indicesi.z * 2; - - m += mat2x4( - texelFetch(skeleton_buffer, tex_ofs + 0), - texelFetch(skeleton_buffer, tex_ofs + 1)) * - bone_weights.z; - - tex_ofs = bone_indicesi.w * 2; - - m += mat2x4( - texelFetch(skeleton_buffer, tex_ofs + 0), - texelFetch(skeleton_buffer, tex_ofs + 1)) * - bone_weights.w; - - mat4 bone_matrix = skeleton_data.skeleton_transform * transpose(mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))) * skeleton_data.skeleton_transform_inverse; - - //outvec = bone_matrix * outvec; - } -#endif -#endif - vertex = (canvas_data.canvas_transform * vec4(vertex, 0.0, 1.0)).xy; vertex_interp = vertex; diff --git a/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl index 4d4e983b7f..46bb99794d 100644 --- a/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl @@ -13,6 +13,14 @@ #endif // has_VK_KHR_multiview #endif //MULTIVIEW +#define FLAG_FLIP_Y (1 << 0) +#define FLAG_USE_SECTION (1 << 1) +#define FLAG_FORCE_LUMINANCE (1 << 2) +#define FLAG_ALPHA_TO_ZERO (1 << 3) +#define FLAG_SRGB (1 << 4) +#define FLAG_ALPHA_TO_ONE (1 << 5) +#define FLAG_LINEAR (1 << 6) + #ifdef MULTIVIEW layout(location = 0) out vec3 uv_interp; #else @@ -22,13 +30,8 @@ layout(location = 0) out vec2 uv_interp; layout(push_constant, std430) uniform Params { vec4 section; vec2 pixel_size; - bool flip_y; - bool use_section; - - bool force_luminance; - bool alpha_to_zero; - bool srgb; - bool alpha_to_one; + float luminance_multiplier; + uint flags; vec4 color; } @@ -41,13 +44,13 @@ void main() { uv_interp.z = ViewIndex; #endif vec2 vpos = uv_interp.xy; - if (params.use_section) { + if (bool(params.flags & FLAG_USE_SECTION)) { vpos = params.section.xy + vpos * params.section.zw; } gl_Position = vec4(vpos * 2.0 - 1.0, 0.0, 1.0); - if (params.flip_y) { + if (bool(params.flags & FLAG_FLIP_Y)) { uv_interp.y = 1.0 - uv_interp.y; } } @@ -67,16 +70,19 @@ void main() { #endif // has_VK_KHR_multiview #endif //MULTIVIEW +#define FLAG_FLIP_Y (1 << 0) +#define FLAG_USE_SECTION (1 << 1) +#define FLAG_FORCE_LUMINANCE (1 << 2) +#define FLAG_ALPHA_TO_ZERO (1 << 3) +#define FLAG_SRGB (1 << 4) +#define FLAG_ALPHA_TO_ONE (1 << 5) +#define FLAG_LINEAR (1 << 6) + layout(push_constant, std430) uniform Params { vec4 section; vec2 pixel_size; - bool flip_y; - bool use_section; - - bool force_luminance; - bool alpha_to_zero; - bool srgb; - bool alpha_to_one; + float luminance_multiplier; + uint flags; vec4 color; } @@ -110,6 +116,10 @@ vec3 linear_to_srgb(vec3 color) { return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f))); } +vec3 srgb_to_linear(vec3 color) { + return mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), color.rgb * (1.0 / 12.92), lessThan(color.rgb, vec3(0.04045))); +} + void main() { #ifdef MODE_SET_COLOR frag_color = params.color; @@ -165,19 +175,22 @@ void main() { #endif /* MODE_TWO_SOURCES */ #endif /* MULTIVIEW */ - if (params.force_luminance) { + if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { color.rgb = vec3(max(max(color.r, color.g), color.b)); } - if (params.alpha_to_zero) { + if (bool(params.flags & FLAG_ALPHA_TO_ZERO)) { color.rgb *= color.a; } - if (params.srgb) { + if (bool(params.flags & FLAG_SRGB)) { color.rgb = linear_to_srgb(color.rgb); } - if (params.alpha_to_one) { + if (bool(params.flags & FLAG_ALPHA_TO_ONE)) { color.a = 1.0; } + if (bool(params.flags & FLAG_LINEAR)) { + color.rgb = srgb_to_linear(color.rgb); + } - frag_color = color; + frag_color = color / params.luminance_multiplier; #endif // MODE_SET_COLOR } diff --git a/servers/rendering/renderer_rd/shaders/effects/vrs.glsl b/servers/rendering/renderer_rd/shaders/effects/vrs.glsl index 5ef83c0b44..b450bb9fe9 100644 --- a/servers/rendering/renderer_rd/shaders/effects/vrs.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/vrs.glsl @@ -63,10 +63,18 @@ void main() { #ifdef MULTIVIEW vec4 color = textureLod(source_color, uv, 0.0); + frag_color = uint(color.r * 255.0); #else /* MULTIVIEW */ vec4 color = textureLod(source_color, uv, 0.0); -#endif /* MULTIVIEW */ - // See if we can change the sampler to one that returns int... - frag_color = uint(color.r * 256.0); + // for user supplied VRS map we do a color mapping + color.r *= 3.0; + frag_color = int(color.r) << 2; + + color.g *= 3.0; + frag_color += int(color.g); + + // note 1x4, 4x1, 1x8, 8x1, 2x8 and 8x2 are not supported + // 4x8, 8x4 and 8x8 are only available on some GPUs +#endif /* MULTIVIEW */ } diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 7440c5748b..896f51ca01 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -62,7 +62,7 @@ vec3 oct_to_vec3(vec2 e) { vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); float t = max(-v.z, 0.0); v.xy += t * -sign(v.xy); - return v; + return normalize(v); } /* Varyings */ diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index cc44cff799..d50749306e 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -63,7 +63,7 @@ vec3 oct_to_vec3(vec2 e) { vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); float t = max(-v.z, 0.0); v.xy += t * -sign(v.xy); - return v; + return normalize(v); } /* Varyings */ diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl index 75bea9300b..f5b233cca0 100644 --- a/servers/rendering/renderer_rd/shaders/skeleton.glsl +++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl @@ -63,7 +63,7 @@ vec3 oct_to_vec3(vec2 oct) { vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y)); float t = max(-v.z, 0.0); v.xy += t * -sign(v.xy); - return v; + return normalize(v); } vec3 decode_uint_oct_to_norm(uint base) { @@ -143,8 +143,8 @@ void main() { uint skin_offset = params.skin_stride * index; uvec2 bones = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); - uvec2 bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 3; //pre-add xform offset - uvec2 bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 3; + uvec2 bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 2; //pre-add xform offset + uvec2 bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 2; skin_offset += params.skin_weight_offset; @@ -161,6 +161,13 @@ void main() { //reverse order because its transposed vertex = (vec4(vertex, 0.0, 1.0) * m).xy; } + + uint dst_offset = index * params.vertex_stride; + + uvec2 uvertex = floatBitsToUint(vertex); + dst_vertices.data[dst_offset + 0] = uvertex.x; + dst_vertices.data[dst_offset + 1] = uvertex.y; + #else vec3 vertex; vec3 normal; diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h index fb25e56ed3..a96fc847e1 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h @@ -79,7 +79,7 @@ public: virtual ~MaterialData(); //to be used internally by update_parameters, in the most common configuration of material parameters - bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, uint32_t p_barrier = RD::BARRIER_MASK_ALL); + bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, uint32_t p_barrier = RD::BARRIER_MASK_ALL_BARRIERS); void free_parameters_uniform_set(RID p_uniform_set); private: diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 1e74d31383..71f4f3ad11 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -616,7 +616,7 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) { Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); - if (!skeleton || skeleton->size == 0) { + if (!skeleton || skeleton->size == 0 || mesh->skeleton_aabb_version == skeleton->version) { return mesh->aabb; } @@ -708,6 +708,7 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) { } } + mesh->skeleton_aabb_version = skeleton->version; return aabb; } @@ -1841,7 +1842,7 @@ void MeshStorage::_update_dirty_multimeshes() { RD::get_singleton()->buffer_update(multimesh->buffer, buffer_offset * sizeof(float) + offset, MIN(region_size, size - offset), &data[region_start_index], RD::BARRIER_MASK_NO_BARRIER); } } - RD::get_singleton()->barrier(RD::BARRIER_MASK_NO_BARRIER, RD::BARRIER_MASK_ALL); + RD::get_singleton()->barrier(RD::BARRIER_MASK_NO_BARRIER, RD::BARRIER_MASK_ALL_BARRIERS); } memcpy(multimesh->previous_data_cache_dirty_regions, multimesh->data_cache_dirty_regions, data_cache_dirty_region_count * sizeof(bool)); diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h index 6a7400631d..4765475804 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h @@ -144,6 +144,7 @@ private: AABB aabb; AABB custom_aabb; + uint64_t skeleton_aabb_version = 0; Vector<RID> material_cache; diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index bea2a80890..15c5687665 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -560,6 +560,7 @@ void TextureStorage::canvas_texture_set_texture_filter(RID p_canvas_texture, RS: void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture); ERR_FAIL_NULL(ct); + ct->texture_repeat = p_repeat; ct->clear_sets(); } diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 348f6e4695..4ee355ee9f 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -3319,7 +3319,7 @@ void RendererSceneCull::render_empty_scene(const Ref<RenderSceneBuffers> &p_rend RendererSceneRender::CameraData camera_data; camera_data.set_camera(Transform3D(), Projection(), true, false); - scene_render->render_scene(p_render_buffers, &camera_data, &camera_data, PagedArray<RenderGeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); + scene_render->render_scene(p_render_buffers, &camera_data, &camera_data, PagedArray<RenderGeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), environment, RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); #endif } diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 2836889de5..8cec531393 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -550,6 +550,9 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { if (!can_draw_3d) { RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas); } else { + // There may be an outstanding clear request if a clear was requested, but no 2D elements were drawn. + // Clear now otherwise we copy over garbage from the render target. + RSG::texture_storage->render_target_do_clear_request(p_viewport->render_target); _draw_3d(p_viewport); } } diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index bb4c41df52..c09b185137 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -170,10 +170,16 @@ RenderingDevice::VertexFormatID RenderingDevice::_vertex_format_create(const Typ return vertex_format_create(descriptions); } -RID RenderingDevice::_vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers) { +RID RenderingDevice::_vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers, const Vector<int64_t> &p_offsets) { Vector<RID> buffers = Variant(p_src_buffers); - return vertex_array_create(p_vertex_count, p_vertex_format, buffers); + Vector<uint64_t> offsets; + offsets.resize(p_offsets.size()); + for (int i = 0; i < p_offsets.size(); i++) { + offsets.write[i] = p_offsets[i]; + } + + return vertex_array_create(p_vertex_count, p_vertex_format, buffers, offsets); } Ref<RDShaderSPIRV> RenderingDevice::_shader_compile_spirv_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache) { @@ -246,7 +252,7 @@ RID RenderingDevice::_uniform_set_create(const TypedArray<RDUniform> &p_uniforms return uniform_set_create(uniforms, p_shader, p_shader_set); } -Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier) { +Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) { return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier); } @@ -367,7 +373,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_create_shared", "view", "with_texture"), &RenderingDevice::_texture_create_shared); ClassDB::bind_method(D_METHOD("texture_create_shared_from_slice", "view", "with_texture", "layer", "mipmap", "mipmaps", "slice_type"), &RenderingDevice::_texture_create_shared_from_slice, DEFVAL(1), DEFVAL(TEXTURE_SLICE_2D)); - ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data", "post_barrier"), &RenderingDevice::texture_update, DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data", "post_barrier"), &RenderingDevice::texture_update, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "layer"), &RenderingDevice::texture_get_data); ClassDB::bind_method(D_METHOD("texture_is_format_supported_for_usage", "format", "usage_flags"), &RenderingDevice::texture_is_format_supported_for_usage); @@ -375,9 +381,9 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_is_shared", "texture"), &RenderingDevice::texture_is_shared); ClassDB::bind_method(D_METHOD("texture_is_valid", "texture"), &RenderingDevice::texture_is_valid); - ClassDB::bind_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "post_barrier"), &RenderingDevice::texture_copy, DEFVAL(BARRIER_MASK_ALL)); - ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::texture_clear, DEFVAL(BARRIER_MASK_ALL)); - ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::texture_resolve_multisample, DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "post_barrier"), &RenderingDevice::texture_copy, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); + ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::texture_clear, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); + ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::texture_resolve_multisample, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments", "view_count"), &RenderingDevice::_framebuffer_format_create, DEFVAL(1)); ClassDB::bind_method(D_METHOD("framebuffer_format_create_multipass", "attachments", "passes", "view_count"), &RenderingDevice::_framebuffer_format_create_multipass, DEFVAL(1)); @@ -393,7 +399,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data", "use_as_storage"), &RenderingDevice::vertex_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("vertex_format_create", "vertex_descriptions"), &RenderingDevice::_vertex_format_create); - ClassDB::bind_method(D_METHOD("vertex_array_create", "vertex_count", "vertex_format", "src_buffers"), &RenderingDevice::_vertex_array_create); + ClassDB::bind_method(D_METHOD("vertex_array_create", "vertex_count", "vertex_format", "src_buffers", "offsets"), &RenderingDevice::_vertex_array_create, DEFVAL(Vector<int64_t>())); ClassDB::bind_method(D_METHOD("index_buffer_create", "size_indices", "format", "data", "use_restart_indices"), &RenderingDevice::index_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("index_array_create", "index_buffer", "index_offset", "index_count"), &RenderingDevice::index_array_create); @@ -411,8 +417,8 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("uniform_set_create", "uniforms", "shader", "shader_set"), &RenderingDevice::_uniform_set_create); ClassDB::bind_method(D_METHOD("uniform_set_is_valid", "uniform_set"), &RenderingDevice::uniform_set_is_valid); - ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update, DEFVAL(BARRIER_MASK_ALL)); - ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); + ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer"), &RenderingDevice::buffer_get_data); ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass", "specialization_constants"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0), DEFVAL(TypedArray<RDPipelineSpecializationConstant>())); @@ -445,7 +451,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass"), &RenderingDevice::draw_list_switch_to_next_pass); ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass_split", "splits"), &RenderingDevice::_draw_list_switch_to_next_pass_split); - ClassDB::bind_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::draw_list_end, DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::draw_list_end, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); ClassDB::bind_method(D_METHOD("compute_list_begin", "allow_draw_overlap"), &RenderingDevice::compute_list_begin, DEFVAL(false)); ClassDB::bind_method(D_METHOD("compute_list_bind_compute_pipeline", "compute_list", "compute_pipeline"), &RenderingDevice::compute_list_bind_compute_pipeline); @@ -453,7 +459,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("compute_list_bind_uniform_set", "compute_list", "uniform_set", "set_index"), &RenderingDevice::compute_list_bind_uniform_set); ClassDB::bind_method(D_METHOD("compute_list_dispatch", "compute_list", "x_groups", "y_groups", "z_groups"), &RenderingDevice::compute_list_dispatch); ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier); - ClassDB::bind_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::compute_list_end, DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::compute_list_end, DEFVAL(BARRIER_MASK_ALL_BARRIERS)); ClassDB::bind_method(D_METHOD("free_rid", "rid"), &RenderingDevice::free); @@ -469,7 +475,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("submit"), &RenderingDevice::submit); ClassDB::bind_method(D_METHOD("sync"), &RenderingDevice::sync); - ClassDB::bind_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::barrier, DEFVAL(BARRIER_MASK_ALL), DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::barrier, DEFVAL(BARRIER_MASK_ALL_BARRIERS), DEFVAL(BARRIER_MASK_ALL_BARRIERS)); ClassDB::bind_method(D_METHOD("full_barrier"), &RenderingDevice::full_barrier); ClassDB::bind_method(D_METHOD("create_local_device"), &RenderingDevice::create_local_device); @@ -488,12 +494,6 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("get_driver_resource", "resource", "rid", "index"), &RenderingDevice::get_driver_resource); - BIND_CONSTANT(BARRIER_MASK_RASTER); - BIND_CONSTANT(BARRIER_MASK_COMPUTE); - BIND_CONSTANT(BARRIER_MASK_TRANSFER); - BIND_CONSTANT(BARRIER_MASK_ALL); - BIND_CONSTANT(BARRIER_MASK_NO_BARRIER); - BIND_ENUM_CONSTANT(DEVICE_TYPE_OTHER); BIND_ENUM_CONSTANT(DEVICE_TYPE_INTEGRATED_GPU); BIND_ENUM_CONSTANT(DEVICE_TYPE_DISCRETE_GPU); @@ -735,6 +735,12 @@ void RenderingDevice::_bind_methods() { BIND_ENUM_CONSTANT(DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM); BIND_ENUM_CONSTANT(DATA_FORMAT_MAX); + BIND_BITFIELD_FLAG(BARRIER_MASK_RASTER); + BIND_BITFIELD_FLAG(BARRIER_MASK_COMPUTE); + BIND_BITFIELD_FLAG(BARRIER_MASK_TRANSFER); + BIND_BITFIELD_FLAG(BARRIER_MASK_ALL_BARRIERS); + BIND_BITFIELD_FLAG(BARRIER_MASK_NO_BARRIER); + BIND_ENUM_CONSTANT(TEXTURE_TYPE_1D); BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D); BIND_ENUM_CONSTANT(TEXTURE_TYPE_3D); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index d0b85d8220..abdd07844a 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -396,8 +396,8 @@ public: BARRIER_MASK_RASTER = 1, BARRIER_MASK_COMPUTE = 2, BARRIER_MASK_TRANSFER = 4, + BARRIER_MASK_ALL_BARRIERS = BARRIER_MASK_RASTER | BARRIER_MASK_COMPUTE | BARRIER_MASK_TRANSFER, // 7 BARRIER_MASK_NO_BARRIER = 8, - BARRIER_MASK_ALL = BARRIER_MASK_RASTER | BARRIER_MASK_COMPUTE | BARRIER_MASK_TRANSFER }; /*****************/ @@ -532,7 +532,7 @@ public: virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D) = 0; - virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer) = 0; // CPU textures will return immediately, while GPU textures will most likely force a flush virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0; @@ -540,9 +540,9 @@ public: virtual bool texture_is_valid(RID p_texture) = 0; virtual Size2i texture_size(RID p_texture) = 0; - virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; - virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; - virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; + virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; + virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; /*********************/ /**** FRAMEBUFFER ****/ @@ -683,7 +683,7 @@ public: // This ID is warranted to be unique for the same formats, does not need to be freed virtual VertexFormatID vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats) = 0; - virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers) = 0; + virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers, const Vector<uint64_t> &p_offsets = Vector<uint64_t>()) = 0; enum IndexBufferFormat { INDEX_BUFFER_FORMAT_UINT16, @@ -826,8 +826,8 @@ public: virtual bool uniform_set_is_valid(RID p_uniform_set) = 0; virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) = 0; - virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; - virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; + virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; virtual Vector<uint8_t> buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving /******************************************/ @@ -1173,7 +1173,7 @@ public: virtual DrawListID draw_list_switch_to_next_pass() = 0; virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) = 0; - virtual void draw_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual void draw_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; /***********************/ /**** COMPUTE LISTS ****/ @@ -1190,9 +1190,9 @@ public: virtual void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) = 0; virtual void compute_list_add_barrier(ComputeListID p_list) = 0; - virtual void compute_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual void compute_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS) = 0; - virtual void barrier(uint32_t p_from = BARRIER_MASK_ALL, uint32_t p_to = BARRIER_MASK_ALL) = 0; + virtual void barrier(BitField<BarrierMask> p_from = BARRIER_MASK_ALL_BARRIERS, BitField<BarrierMask> p_to = BARRIER_MASK_ALL_BARRIERS) = 0; virtual void full_barrier() = 0; /***************/ @@ -1257,6 +1257,8 @@ public: LIMIT_SUBGROUP_SIZE, LIMIT_SUBGROUP_IN_SHADERS, // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc. LIMIT_SUBGROUP_OPERATIONS, + LIMIT_VRS_TEXEL_WIDTH, + LIMIT_VRS_TEXEL_HEIGHT, }; virtual uint64_t limit_get(Limit p_limit) const = 0; @@ -1310,7 +1312,7 @@ protected: RID _framebuffer_create_multipass(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); RID _sampler_create(const Ref<RDSamplerState> &p_state); VertexFormatID _vertex_format_create(const TypedArray<RDVertexAttribute> &p_vertex_formats); - RID _vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers); + RID _vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers, const Vector<int64_t> &p_offsets = Vector<int64_t>()); Ref<RDShaderSPIRV> _shader_compile_spirv_from_source(const Ref<RDShaderSource> &p_source, bool p_allow_cache = true); Vector<uint8_t> _shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_bytecode, const String &p_shader_name = ""); @@ -1318,7 +1320,7 @@ protected: RID _uniform_set_create(const TypedArray<RDUniform> &p_uniforms, RID p_shader, uint32_t p_shader_set); - Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); + Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants); RID _compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants); @@ -1335,6 +1337,7 @@ VARIANT_ENUM_CAST(RenderingDevice::ShaderStage) VARIANT_ENUM_CAST(RenderingDevice::ShaderLanguage) VARIANT_ENUM_CAST(RenderingDevice::CompareOperator) VARIANT_ENUM_CAST(RenderingDevice::DataFormat) +VARIANT_BITFIELD_CAST(RenderingDevice::BarrierMask); VARIANT_ENUM_CAST(RenderingDevice::TextureType) VARIANT_ENUM_CAST(RenderingDevice::TextureSamples) VARIANT_ENUM_CAST(RenderingDevice::TextureUsageBits) diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 497e4476d0..92b8d7350e 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -4110,43 +4110,41 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform case ShaderLanguage::TYPE_USAMPLER2D: { if (p_uniform.array_size > 0) { pi.type = Variant::ARRAY; + pi.hint = PROPERTY_HINT_ARRAY_TYPE; + pi.hint_string = vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"); } else { pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "Texture2D"; } - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "Texture2D"; } break; case ShaderLanguage::TYPE_SAMPLER2DARRAY: case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: { + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLERCUBE: + case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: { if (p_uniform.array_size > 0) { pi.type = Variant::ARRAY; + pi.hint = PROPERTY_HINT_ARRAY_TYPE; + pi.hint_string = vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered"); } else { pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "TextureLayered"; } - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "TextureLayered"; } break; case ShaderLanguage::TYPE_SAMPLER3D: case ShaderLanguage::TYPE_ISAMPLER3D: case ShaderLanguage::TYPE_USAMPLER3D: { if (p_uniform.array_size > 0) { pi.type = Variant::ARRAY; + pi.hint = PROPERTY_HINT_ARRAY_TYPE; + pi.hint_string = vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"); } else { pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "Texture3D"; } - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "Texture3D"; - } break; - case ShaderLanguage::TYPE_SAMPLERCUBE: - case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: { - if (p_uniform.array_size > 0) { - pi.type = Variant::ARRAY; - } else { - pi.type = Variant::OBJECT; - } - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "TextureLayered"; } break; case ShaderLanguage::TYPE_STRUCT: { // FIXME: Implement this. @@ -7590,7 +7588,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_BUG; } - if (b && b->parent_function && p_function_info.main_function) { + if (b->parent_function && p_function_info.main_function) { _set_error(vformat(RTR("Using '%s' in the '%s' processor function is incorrect."), "return", b->parent_function->name)); return ERR_PARSE_ERROR; } @@ -8190,25 +8188,27 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f }; [[fallthrough]]; case TK_INSTANCE: { + if (tk.type == TK_INSTANCE) { #ifdef DEBUG_ENABLED - keyword_completion_context = CF_UNIFORM_KEYWORD; - if (_lookup_next(next)) { - if (next.type == TK_UNIFORM) { - keyword_completion_context ^= CF_UNIFORM_KEYWORD; + keyword_completion_context = CF_UNIFORM_KEYWORD; + if (_lookup_next(next)) { + if (next.type == TK_UNIFORM) { + keyword_completion_context ^= CF_UNIFORM_KEYWORD; + } } - } #endif // DEBUG_ENABLED - if (String(shader_type_identifier) != "spatial") { - _set_error(vformat(RTR("Uniform instances are not yet implemented for '%s' shaders."), shader_type_identifier)); - return ERR_PARSE_ERROR; - } - if (uniform_scope == ShaderNode::Uniform::SCOPE_LOCAL) { - tk = _get_token(); - if (tk.type != TK_UNIFORM) { - _set_expected_after_error("uniform", "instance"); + if (String(shader_type_identifier) != "spatial") { + _set_error(vformat(RTR("Uniform instances are not yet implemented for '%s' shaders."), shader_type_identifier)); return ERR_PARSE_ERROR; } - uniform_scope = ShaderNode::Uniform::SCOPE_INSTANCE; + if (uniform_scope == ShaderNode::Uniform::SCOPE_LOCAL) { + tk = _get_token(); + if (tk.type != TK_UNIFORM) { + _set_expected_after_error("uniform", "instance"); + return ERR_PARSE_ERROR; + } + uniform_scope = ShaderNode::Uniform::SCOPE_INSTANCE; + } } }; [[fallthrough]]; @@ -8878,7 +8878,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f _set_error(RTR("Expected an uniform group identifier or `;`.")); } return ERR_PARSE_ERROR; - } else if (tk.type == TK_SEMICOLON && current_uniform_group_name.is_empty()) { + } else if (current_uniform_group_name.is_empty()) { _set_error(RTR("Group needs to be opened before.")); return ERR_PARSE_ERROR; } else { diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index a18a9d7460..9551b983fc 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -625,7 +625,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const int *src = indices.ptr(); for (int i = 0; i < p_index_array_len; i++) { - if (p_vertex_array_len < (1 << 16) && p_vertex_array_len > 0) { + if (p_vertex_array_len <= (1 << 16) && p_vertex_array_len > 0) { uint16_t v = src[i]; memcpy(&iw[i * 2], &v, 2); @@ -835,10 +835,10 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i break; } /* determine whether using 16 or 32 bits indices */ - if (p_vertex_len >= (1 << 16) || p_vertex_len == 0) { - elem_size = 4; - } else { + if (p_vertex_len <= (1 << 16) && p_vertex_len > 0) { elem_size = 2; + } else { + elem_size = 4; } r_offsets[i] = elem_size; continue; @@ -1280,7 +1280,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector<int> arr; arr.resize(p_index_len); - if (p_vertex_len < (1 << 16)) { + if (p_vertex_len <= (1 << 16)) { int *w = arr.ptrw(); for (int j = 0; j < p_index_len; j++) { @@ -1476,7 +1476,11 @@ RenderingDevice *RenderingServer::get_rendering_device() const { } RenderingDevice *RenderingServer::create_local_rendering_device() const { - return RenderingDevice::get_singleton()->create_local_device(); + RenderingDevice *device = RenderingDevice::get_singleton(); + if (!device) { + return nullptr; + } + return device->create_local_device(); } static Vector<Ref<Image>> _get_imgvec(const TypedArray<Image> &p_layers) { diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index 4d58d24405..ec4ae98397 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -167,11 +167,12 @@ RID XRInterface::get_vrs_texture() { // Default logic will return a standard VRS image based on our target size and default projections. // Note that this only gets called if VRS is supported on the hardware. - Size2 texel_size = Size2(16.0, 16.0); // For now we assume we always use 16x16 texels, seems to be the standard. + int32_t texel_width = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_WIDTH); + int32_t texel_height = RD::get_singleton()->limit_get(RD::LIMIT_VRS_TEXEL_HEIGHT); int view_count = get_view_count(); Size2 target_size = get_render_target_size(); real_t aspect = target_size.x / target_size.y; // is this y/x ? - Size2 vrs_size = Size2(round(0.5 + target_size.x / texel_size.x), round(0.5 + target_size.y / texel_size.y)); + Size2 vrs_size = Size2(round(0.5 + target_size.x / texel_width), round(0.5 + target_size.y / texel_height)); real_t radius = vrs_size.length() * 0.5; Size2 vrs_sizei = vrs_size; @@ -179,6 +180,8 @@ RID XRInterface::get_vrs_texture() { const uint8_t densities[] = { 0, // 1x1 1, // 1x2 + // 2, // 1x4 - not supported + // 3, // 1x8 - not supported // 4, // 2x1 5, // 2x2 6, // 2x4 diff --git a/tests/core/math/test_math_funcs.h b/tests/core/math/test_math_funcs.h index c468e73b74..c9d14bbd21 100644 --- a/tests/core/math/test_math_funcs.h +++ b/tests/core/math/test_math_funcs.h @@ -88,290 +88,280 @@ TEST_CASE("[Math] Power of two functions") { CHECK(nearest_shift(65535) == 16); } -TEST_CASE("[Math] abs") { - // int - CHECK(Math::abs(-1) == 1); - CHECK(Math::abs(0) == 0); - CHECK(Math::abs(1) == 1); - - // double - CHECK(Math::abs(-0.1) == 0.1); - CHECK(Math::abs(0.0) == 0.0); - CHECK(Math::abs(0.1) == 0.1); - - // float - CHECK(Math::abs(-0.1f) == 0.1f); - CHECK(Math::abs(0.0f) == 0.0f); - CHECK(Math::abs(0.1f) == 0.1f); -} - -TEST_CASE("[Math] round/floor/ceil") { - CHECK(Math::round(1.5) == 2.0); - CHECK(Math::round(1.6) == 2.0); - CHECK(Math::round(-1.5) == -2.0); - CHECK(Math::round(-1.1) == -1.0); - - CHECK(Math::floor(1.5) == 1.0); - CHECK(Math::floor(-1.5) == -2.0); - - CHECK(Math::ceil(1.5) == 2.0); - CHECK(Math::ceil(-1.9) == -1.0); -} - -TEST_CASE("[Math] sin/cos/tan") { - CHECK(Math::sin(-0.1) == doctest::Approx(-0.0998334166)); - CHECK(Math::sin(0.1) == doctest::Approx(0.0998334166)); - CHECK(Math::sin(0.5) == doctest::Approx(0.4794255386)); - CHECK(Math::sin(1.0) == doctest::Approx(0.8414709848)); - CHECK(Math::sin(1.5) == doctest::Approx(0.9974949866)); - CHECK(Math::sin(450.0) == doctest::Approx(-0.683283725)); - - CHECK(Math::cos(-0.1) == doctest::Approx(0.99500416530)); - CHECK(Math::cos(0.1) == doctest::Approx(0.9950041653)); - CHECK(Math::cos(0.5) == doctest::Approx(0.8775825619)); - CHECK(Math::cos(1.0) == doctest::Approx(0.5403023059)); - CHECK(Math::cos(1.5) == doctest::Approx(0.0707372017)); - CHECK(Math::cos(450.0) == doctest::Approx(-0.7301529642)); - - CHECK(Math::tan(-0.1) == doctest::Approx(-0.1003346721)); - CHECK(Math::tan(0.1) == doctest::Approx(0.1003346721)); - CHECK(Math::tan(0.5) == doctest::Approx(0.5463024898)); - CHECK(Math::tan(1.0) == doctest::Approx(1.5574077247)); - CHECK(Math::tan(1.5) == doctest::Approx(14.1014199472)); - CHECK(Math::tan(450.0) == doctest::Approx(0.9358090134)); -} - -TEST_CASE("[Math] sinh/cosh/tanh") { - CHECK(Math::sinh(-0.1) == doctest::Approx(-0.10016675)); - CHECK(Math::sinh(0.1) == doctest::Approx(0.10016675)); - CHECK(Math::sinh(0.5) == doctest::Approx(0.5210953055)); - CHECK(Math::sinh(1.0) == doctest::Approx(1.1752011936)); - CHECK(Math::sinh(1.5) == doctest::Approx(2.1292794551)); - - CHECK(Math::cosh(-0.1) == doctest::Approx(1.0050041681)); - CHECK(Math::cosh(0.1) == doctest::Approx(1.0050041681)); - CHECK(Math::cosh(0.5) == doctest::Approx(1.1276259652)); - CHECK(Math::cosh(1.0) == doctest::Approx(1.5430806348)); - CHECK(Math::cosh(1.5) == doctest::Approx(2.3524096152)); - - CHECK(Math::tanh(-0.1) == doctest::Approx(-0.0996679946)); - CHECK(Math::tanh(0.1) == doctest::Approx(0.0996679946)); - CHECK(Math::tanh(0.5) == doctest::Approx(0.4621171573)); - CHECK(Math::tanh(1.0) == doctest::Approx(0.761594156)); - CHECK(Math::tanh(1.5) == doctest::Approx(0.9051482536)); - CHECK(Math::tanh(450.0) == doctest::Approx(1.0)); -} - -TEST_CASE("[Math] asin/acos/atan") { - CHECK(Math::asin(-0.1) == doctest::Approx(-0.1001674212)); - CHECK(Math::asin(0.1) == doctest::Approx(0.1001674212)); - CHECK(Math::asin(0.5) == doctest::Approx(0.5235987756)); - CHECK(Math::asin(1.0) == doctest::Approx(1.5707963268)); - CHECK(Math::is_nan(Math::asin(1.5))); - CHECK(Math::is_nan(Math::asin(450.0))); - - CHECK(Math::acos(-0.1) == doctest::Approx(1.670963748)); - CHECK(Math::acos(0.1) == doctest::Approx(1.4706289056)); - CHECK(Math::acos(0.5) == doctest::Approx(1.0471975512)); - CHECK(Math::acos(1.0) == doctest::Approx(0.0)); - CHECK(Math::is_nan(Math::acos(1.5))); - CHECK(Math::is_nan(Math::acos(450.0))); - - CHECK(Math::atan(-0.1) == doctest::Approx(-0.0996686525)); - CHECK(Math::atan(0.1) == doctest::Approx(0.0996686525)); - CHECK(Math::atan(0.5) == doctest::Approx(0.463647609)); - CHECK(Math::atan(1.0) == doctest::Approx(0.7853981634)); - CHECK(Math::atan(1.5) == doctest::Approx(0.9827937232)); - CHECK(Math::atan(450.0) == doctest::Approx(1.5685741082)); -} - -TEST_CASE("[Math] sinc/sincn/atan2") { - CHECK(Math::sinc(-0.1) == doctest::Approx(0.9983341665)); - CHECK(Math::sinc(0.1) == doctest::Approx(0.9983341665)); - CHECK(Math::sinc(0.5) == doctest::Approx(0.9588510772)); - CHECK(Math::sinc(1.0) == doctest::Approx(0.8414709848)); - CHECK(Math::sinc(1.5) == doctest::Approx(0.6649966577)); - CHECK(Math::sinc(450.0) == doctest::Approx(-0.0015184083)); - - CHECK(Math::sincn(-0.1) == doctest::Approx(0.9836316431)); - CHECK(Math::sincn(0.1) == doctest::Approx(0.9836316431)); - CHECK(Math::sincn(0.5) == doctest::Approx(0.6366197724)); - CHECK(Math::sincn(1.0) == doctest::Approx(0.0)); - CHECK(Math::sincn(1.5) == doctest::Approx(-0.2122065908)); - CHECK(Math::sincn(450.0) == doctest::Approx(0.0)); - - CHECK(Math::atan2(-0.1, 0.5) == doctest::Approx(-0.1973955598)); - CHECK(Math::atan2(0.1, -0.5) == doctest::Approx(2.9441970937)); - CHECK(Math::atan2(0.5, 1.5) == doctest::Approx(0.3217505544)); - CHECK(Math::atan2(1.0, 2.5) == doctest::Approx(0.3805063771)); - CHECK(Math::atan2(1.5, 1.0) == doctest::Approx(0.9827937232)); - CHECK(Math::atan2(450.0, 1.0) == doctest::Approx(1.5685741082)); -} - -TEST_CASE("[Math] pow/log/log2/exp/sqrt") { - CHECK(Math::pow(-0.1, 2.0) == doctest::Approx(0.01)); - CHECK(Math::pow(0.1, 2.5) == doctest::Approx(0.0031622777)); - CHECK(Math::pow(0.5, 0.5) == doctest::Approx(0.7071067812)); - CHECK(Math::pow(1.0, 1.0) == doctest::Approx(1.0)); - CHECK(Math::pow(1.5, -1.0) == doctest::Approx(0.6666666667)); - CHECK(Math::pow(450.0, -2.0) == doctest::Approx(0.0000049383)); - CHECK(Math::pow(450.0, 0.0) == doctest::Approx(1.0)); - - CHECK(Math::is_nan(Math::log(-0.1))); - CHECK(Math::log(0.1) == doctest::Approx(-2.302585093)); - CHECK(Math::log(0.5) == doctest::Approx(-0.6931471806)); - CHECK(Math::log(1.0) == doctest::Approx(0.0)); - CHECK(Math::log(1.5) == doctest::Approx(0.4054651081)); - CHECK(Math::log(450.0) == doctest::Approx(6.1092475828)); - - CHECK(Math::is_nan(Math::log2(-0.1))); - CHECK(Math::log2(0.1) == doctest::Approx(-3.3219280949)); - CHECK(Math::log2(0.5) == doctest::Approx(-1.0)); - CHECK(Math::log2(1.0) == doctest::Approx(0.0)); - CHECK(Math::log2(1.5) == doctest::Approx(0.5849625007)); - CHECK(Math::log2(450.0) == doctest::Approx(8.8137811912)); - - CHECK(Math::exp(-0.1) == doctest::Approx(0.904837418)); - CHECK(Math::exp(0.1) == doctest::Approx(1.1051709181)); - CHECK(Math::exp(0.5) == doctest::Approx(1.6487212707)); - CHECK(Math::exp(1.0) == doctest::Approx(2.7182818285)); - CHECK(Math::exp(1.5) == doctest::Approx(4.4816890703)); - - CHECK(Math::is_nan(Math::sqrt(-0.1))); - CHECK(Math::sqrt(0.1) == doctest::Approx(0.316228)); - CHECK(Math::sqrt(0.5) == doctest::Approx(0.707107)); - CHECK(Math::sqrt(1.0) == doctest::Approx(1.0)); - CHECK(Math::sqrt(1.5) == doctest::Approx(1.224745)); -} - -TEST_CASE("[Math] is_nan/is_inf") { - CHECK(!Math::is_nan(0.0)); - CHECK(Math::is_nan(NAN)); - - CHECK(!Math::is_inf(0.0)); - CHECK(Math::is_inf(INFINITY)); -} - -TEST_CASE("[Math] linear_to_db") { - CHECK(Math::linear_to_db(1.0) == doctest::Approx(0.0)); - CHECK(Math::linear_to_db(20.0) == doctest::Approx(26.0206)); - CHECK(Math::is_inf(Math::linear_to_db(0.0))); - CHECK(Math::is_nan(Math::linear_to_db(-20.0))); -} - -TEST_CASE("[Math] db_to_linear") { - CHECK(Math::db_to_linear(0.0) == doctest::Approx(1.0)); - CHECK(Math::db_to_linear(1.0) == doctest::Approx(1.122018)); - CHECK(Math::db_to_linear(20.0) == doctest::Approx(10.0)); - CHECK(Math::db_to_linear(-20.0) == doctest::Approx(0.1)); -} - -TEST_CASE("[Math] step_decimals") { - CHECK(Math::step_decimals(-0.5) == 1); - CHECK(Math::step_decimals(0) == 0); - CHECK(Math::step_decimals(1) == 0); - CHECK(Math::step_decimals(0.1) == 1); - CHECK(Math::step_decimals(0.01) == 2); - CHECK(Math::step_decimals(0.001) == 3); - CHECK(Math::step_decimals(0.0001) == 4); - CHECK(Math::step_decimals(0.00001) == 5); - CHECK(Math::step_decimals(0.000001) == 6); - CHECK(Math::step_decimals(0.0000001) == 7); - CHECK(Math::step_decimals(0.00000001) == 8); - CHECK(Math::step_decimals(0.000000001) == 9); +TEST_CASE_TEMPLATE("[Math] abs", T, int, float, double) { + CHECK(Math::abs((T)-1) == (T)1); + CHECK(Math::abs((T)0) == (T)0); + CHECK(Math::abs((T)1) == (T)1); + CHECK(Math::abs((T)0.1) == (T)0.1); +} + +TEST_CASE_TEMPLATE("[Math] round/floor/ceil", T, float, double) { + CHECK(Math::round((T)1.5) == (T)2.0); + CHECK(Math::round((T)1.6) == (T)2.0); + CHECK(Math::round((T)-1.5) == (T)-2.0); + CHECK(Math::round((T)-1.1) == (T)-1.0); + + CHECK(Math::floor((T)1.5) == (T)1.0); + CHECK(Math::floor((T)-1.5) == (T)-2.0); + + CHECK(Math::ceil((T)1.5) == (T)2.0); + CHECK(Math::ceil((T)-1.9) == (T)-1.0); +} + +TEST_CASE_TEMPLATE("[Math] sin/cos/tan", T, float, double) { + CHECK(Math::sin((T)-0.1) == doctest::Approx((T)-0.0998334166)); + CHECK(Math::sin((T)0.1) == doctest::Approx((T)0.0998334166)); + CHECK(Math::sin((T)0.5) == doctest::Approx((T)0.4794255386)); + CHECK(Math::sin((T)1.0) == doctest::Approx((T)0.8414709848)); + CHECK(Math::sin((T)1.5) == doctest::Approx((T)0.9974949866)); + CHECK(Math::sin((T)450.0) == doctest::Approx((T)-0.683283725)); + + CHECK(Math::cos((T)-0.1) == doctest::Approx((T)0.99500416530)); + CHECK(Math::cos((T)0.1) == doctest::Approx((T)0.9950041653)); + CHECK(Math::cos((T)0.5) == doctest::Approx((T)0.8775825619)); + CHECK(Math::cos((T)1.0) == doctest::Approx((T)0.5403023059)); + CHECK(Math::cos((T)1.5) == doctest::Approx((T)0.0707372017)); + CHECK(Math::cos((T)450.0) == doctest::Approx((T)-0.7301529642)); + + CHECK(Math::tan((T)-0.1) == doctest::Approx((T)-0.1003346721)); + CHECK(Math::tan((T)0.1) == doctest::Approx((T)0.1003346721)); + CHECK(Math::tan((T)0.5) == doctest::Approx((T)0.5463024898)); + CHECK(Math::tan((T)1.0) == doctest::Approx((T)1.5574077247)); + CHECK(Math::tan((T)1.5) == doctest::Approx((T)14.1014199472)); + CHECK(Math::tan((T)450.0) == doctest::Approx((T)0.9358090134)); +} + +TEST_CASE_TEMPLATE("[Math] sinh/cosh/tanh", T, float, double) { + CHECK(Math::sinh((T)-0.1) == doctest::Approx((T)-0.10016675)); + CHECK(Math::sinh((T)0.1) == doctest::Approx((T)0.10016675)); + CHECK(Math::sinh((T)0.5) == doctest::Approx((T)0.5210953055)); + CHECK(Math::sinh((T)1.0) == doctest::Approx((T)1.1752011936)); + CHECK(Math::sinh((T)1.5) == doctest::Approx((T)2.1292794551)); + + CHECK(Math::cosh((T)-0.1) == doctest::Approx((T)1.0050041681)); + CHECK(Math::cosh((T)0.1) == doctest::Approx((T)1.0050041681)); + CHECK(Math::cosh((T)0.5) == doctest::Approx((T)1.1276259652)); + CHECK(Math::cosh((T)1.0) == doctest::Approx((T)1.5430806348)); + CHECK(Math::cosh((T)1.5) == doctest::Approx((T)2.3524096152)); + + CHECK(Math::tanh((T)-0.1) == doctest::Approx((T)-0.0996679946)); + CHECK(Math::tanh((T)0.1) == doctest::Approx((T)0.0996679946)); + CHECK(Math::tanh((T)0.5) == doctest::Approx((T)0.4621171573)); + CHECK(Math::tanh((T)1.0) == doctest::Approx((T)0.761594156)); + CHECK(Math::tanh((T)1.5) == doctest::Approx((T)0.9051482536)); + CHECK(Math::tanh((T)450.0) == doctest::Approx((T)1.0)); +} + +TEST_CASE_TEMPLATE("[Math] asin/acos/atan", T, float, double) { + CHECK(Math::asin((T)-0.1) == doctest::Approx((T)-0.1001674212)); + CHECK(Math::asin((T)0.1) == doctest::Approx((T)0.1001674212)); + CHECK(Math::asin((T)0.5) == doctest::Approx((T)0.5235987756)); + CHECK(Math::asin((T)1.0) == doctest::Approx((T)1.5707963268)); + CHECK(Math::is_nan(Math::asin((T)1.5))); + CHECK(Math::is_nan(Math::asin((T)450.0))); + + CHECK(Math::acos((T)-0.1) == doctest::Approx((T)1.670963748)); + CHECK(Math::acos((T)0.1) == doctest::Approx((T)1.4706289056)); + CHECK(Math::acos((T)0.5) == doctest::Approx((T)1.0471975512)); + CHECK(Math::acos((T)1.0) == doctest::Approx((T)0.0)); + CHECK(Math::is_nan(Math::acos((T)1.5))); + CHECK(Math::is_nan(Math::acos((T)450.0))); + + CHECK(Math::atan((T)-0.1) == doctest::Approx((T)-0.0996686525)); + CHECK(Math::atan((T)0.1) == doctest::Approx((T)0.0996686525)); + CHECK(Math::atan((T)0.5) == doctest::Approx((T)0.463647609)); + CHECK(Math::atan((T)1.0) == doctest::Approx((T)0.7853981634)); + CHECK(Math::atan((T)1.5) == doctest::Approx((T)0.9827937232)); + CHECK(Math::atan((T)450.0) == doctest::Approx((T)1.5685741082)); +} + +TEST_CASE_TEMPLATE("[Math] sinc/sincn/atan2", T, float, double) { + CHECK(Math::sinc((T)-0.1) == doctest::Approx((T)0.9983341665)); + CHECK(Math::sinc((T)0.1) == doctest::Approx((T)0.9983341665)); + CHECK(Math::sinc((T)0.5) == doctest::Approx((T)0.9588510772)); + CHECK(Math::sinc((T)1.0) == doctest::Approx((T)0.8414709848)); + CHECK(Math::sinc((T)1.5) == doctest::Approx((T)0.6649966577)); + CHECK(Math::sinc((T)450.0) == doctest::Approx((T)-0.0015184083)); + + CHECK(Math::sincn((T)-0.1) == doctest::Approx((T)0.9836316431)); + CHECK(Math::sincn((T)0.1) == doctest::Approx((T)0.9836316431)); + CHECK(Math::sincn((T)0.5) == doctest::Approx((T)0.6366197724)); + CHECK(Math::sincn((T)1.0) == doctest::Approx((T)0.0)); + CHECK(Math::sincn((T)1.5) == doctest::Approx((T)-0.2122065908)); + CHECK(Math::sincn((T)450.0) == doctest::Approx((T)0.0)); + + CHECK(Math::atan2((T)-0.1, (T)0.5) == doctest::Approx((T)-0.1973955598)); + CHECK(Math::atan2((T)0.1, (T)-0.5) == doctest::Approx((T)2.9441970937)); + CHECK(Math::atan2((T)0.5, (T)1.5) == doctest::Approx((T)0.3217505544)); + CHECK(Math::atan2((T)1.0, (T)2.5) == doctest::Approx((T)0.3805063771)); + CHECK(Math::atan2((T)1.5, (T)1.0) == doctest::Approx((T)0.9827937232)); + CHECK(Math::atan2((T)450.0, (T)1.0) == doctest::Approx((T)1.5685741082)); +} + +TEST_CASE_TEMPLATE("[Math] pow/log/log2/exp/sqrt", T, float, double) { + CHECK(Math::pow((T)-0.1, (T)2.0) == doctest::Approx((T)0.01)); + CHECK(Math::pow((T)0.1, (T)2.5) == doctest::Approx((T)0.0031622777)); + CHECK(Math::pow((T)0.5, (T)0.5) == doctest::Approx((T)0.7071067812)); + CHECK(Math::pow((T)1.0, (T)1.0) == doctest::Approx((T)1.0)); + CHECK(Math::pow((T)1.5, (T)-1.0) == doctest::Approx((T)0.6666666667)); + CHECK(Math::pow((T)450.0, (T)-2.0) == doctest::Approx((T)0.0000049383)); + CHECK(Math::pow((T)450.0, (T)0.0) == doctest::Approx((T)1.0)); + + CHECK(Math::is_nan(Math::log((T)-0.1))); + CHECK(Math::log((T)0.1) == doctest::Approx((T)-2.302585093)); + CHECK(Math::log((T)0.5) == doctest::Approx((T)-0.6931471806)); + CHECK(Math::log((T)1.0) == doctest::Approx((T)0.0)); + CHECK(Math::log((T)1.5) == doctest::Approx((T)0.4054651081)); + CHECK(Math::log((T)450.0) == doctest::Approx((T)6.1092475828)); + + CHECK(Math::is_nan(Math::log2((T)-0.1))); + CHECK(Math::log2((T)0.1) == doctest::Approx((T)-3.3219280949)); + CHECK(Math::log2((T)0.5) == doctest::Approx((T)-1.0)); + CHECK(Math::log2((T)1.0) == doctest::Approx((T)0.0)); + CHECK(Math::log2((T)1.5) == doctest::Approx((T)0.5849625007)); + CHECK(Math::log2((T)450.0) == doctest::Approx((T)8.8137811912)); + + CHECK(Math::exp((T)-0.1) == doctest::Approx((T)0.904837418)); + CHECK(Math::exp((T)0.1) == doctest::Approx((T)1.1051709181)); + CHECK(Math::exp((T)0.5) == doctest::Approx((T)1.6487212707)); + CHECK(Math::exp((T)1.0) == doctest::Approx((T)2.7182818285)); + CHECK(Math::exp((T)1.5) == doctest::Approx((T)4.4816890703)); + + CHECK(Math::is_nan(Math::sqrt((T)-0.1))); + CHECK(Math::sqrt((T)0.1) == doctest::Approx((T)0.316228)); + CHECK(Math::sqrt((T)0.5) == doctest::Approx((T)0.707107)); + CHECK(Math::sqrt((T)1.0) == doctest::Approx((T)1.0)); + CHECK(Math::sqrt((T)1.5) == doctest::Approx((T)1.224745)); +} + +TEST_CASE_TEMPLATE("[Math] is_nan/is_inf", T, float, double) { + CHECK(!Math::is_nan((T)0.0)); + CHECK(Math::is_nan((T)NAN)); + + CHECK(!Math::is_inf((T)0.0)); + CHECK(Math::is_inf((T)INFINITY)); +} + +TEST_CASE_TEMPLATE("[Math] linear_to_db", T, float, double) { + CHECK(Math::linear_to_db((T)1.0) == doctest::Approx((T)0.0)); + CHECK(Math::linear_to_db((T)20.0) == doctest::Approx((T)26.0206)); + CHECK(Math::is_inf(Math::linear_to_db((T)0.0))); + CHECK(Math::is_nan(Math::linear_to_db((T)-20.0))); +} + +TEST_CASE_TEMPLATE("[Math] db_to_linear", T, float, double) { + CHECK(Math::db_to_linear((T)0.0) == doctest::Approx((T)1.0)); + CHECK(Math::db_to_linear((T)1.0) == doctest::Approx((T)1.122018)); + CHECK(Math::db_to_linear((T)20.0) == doctest::Approx((T)10.0)); + CHECK(Math::db_to_linear((T)-20.0) == doctest::Approx((T)0.1)); +} + +TEST_CASE_TEMPLATE("[Math] step_decimals", T, float, double) { + CHECK(Math::step_decimals((T)-0.5) == 1); + CHECK(Math::step_decimals((T)0) == 0); + CHECK(Math::step_decimals((T)1) == 0); + CHECK(Math::step_decimals((T)0.1) == 1); + CHECK(Math::step_decimals((T)0.01) == 2); + CHECK(Math::step_decimals((T)0.001) == 3); + CHECK(Math::step_decimals((T)0.0001) == 4); + CHECK(Math::step_decimals((T)0.00001) == 5); + CHECK(Math::step_decimals((T)0.000001) == 6); + CHECK(Math::step_decimals((T)0.0000001) == 7); + CHECK(Math::step_decimals((T)0.00000001) == 8); + CHECK(Math::step_decimals((T)0.000000001) == 9); // Too many decimals to handle. - CHECK(Math::step_decimals(0.0000000001) == 0); + CHECK(Math::step_decimals((T)0.0000000001) == 0); } -TEST_CASE("[Math] range_step_decimals") { - CHECK(Math::range_step_decimals(0.000000001) == 9); +TEST_CASE_TEMPLATE("[Math] range_step_decimals", T, float, double) { + CHECK(Math::range_step_decimals((T)0.000000001) == 9); // Too many decimals to handle. - CHECK(Math::range_step_decimals(0.0000000001) == 0); + CHECK(Math::range_step_decimals((T)0.0000000001) == 0); // Should be treated as a step of 0 for use by the editor. - CHECK(Math::range_step_decimals(0.0) == 16); - CHECK(Math::range_step_decimals(-0.5) == 16); + CHECK(Math::range_step_decimals((T)0.0) == 16); + CHECK(Math::range_step_decimals((T)-0.5) == 16); } -TEST_CASE("[Math] lerp") { - CHECK(Math::lerp(2.0, 5.0, -0.1) == doctest::Approx(1.7)); - CHECK(Math::lerp(2.0, 5.0, 0.0) == doctest::Approx(2.0)); - CHECK(Math::lerp(2.0, 5.0, 0.1) == doctest::Approx(2.3)); - CHECK(Math::lerp(2.0, 5.0, 1.0) == doctest::Approx(5.0)); - CHECK(Math::lerp(2.0, 5.0, 2.0) == doctest::Approx(8.0)); +TEST_CASE_TEMPLATE("[Math] lerp", T, float, double) { + CHECK(Math::lerp((T)2.0, (T)5.0, (T)-0.1) == doctest::Approx((T)1.7)); + CHECK(Math::lerp((T)2.0, (T)5.0, (T)0.0) == doctest::Approx((T)2.0)); + CHECK(Math::lerp((T)2.0, (T)5.0, (T)0.1) == doctest::Approx((T)2.3)); + CHECK(Math::lerp((T)2.0, (T)5.0, (T)1.0) == doctest::Approx((T)5.0)); + CHECK(Math::lerp((T)2.0, (T)5.0, (T)2.0) == doctest::Approx((T)8.0)); - CHECK(Math::lerp(-2.0, -5.0, -0.1) == doctest::Approx(-1.7)); - CHECK(Math::lerp(-2.0, -5.0, 0.0) == doctest::Approx(-2.0)); - CHECK(Math::lerp(-2.0, -5.0, 0.1) == doctest::Approx(-2.3)); - CHECK(Math::lerp(-2.0, -5.0, 1.0) == doctest::Approx(-5.0)); - CHECK(Math::lerp(-2.0, -5.0, 2.0) == doctest::Approx(-8.0)); + CHECK(Math::lerp((T)-2.0, (T)-5.0, (T)-0.1) == doctest::Approx((T)-1.7)); + CHECK(Math::lerp((T)-2.0, (T)-5.0, (T)0.0) == doctest::Approx((T)-2.0)); + CHECK(Math::lerp((T)-2.0, (T)-5.0, (T)0.1) == doctest::Approx((T)-2.3)); + CHECK(Math::lerp((T)-2.0, (T)-5.0, (T)1.0) == doctest::Approx((T)-5.0)); + CHECK(Math::lerp((T)-2.0, (T)-5.0, (T)2.0) == doctest::Approx((T)-8.0)); } -TEST_CASE("[Math] inverse_lerp") { - CHECK(Math::inverse_lerp(2.0, 5.0, 1.7) == doctest::Approx(-0.1)); - CHECK(Math::inverse_lerp(2.0, 5.0, 2.0) == doctest::Approx(0.0)); - CHECK(Math::inverse_lerp(2.0, 5.0, 2.3) == doctest::Approx(0.1)); - CHECK(Math::inverse_lerp(2.0, 5.0, 5.0) == doctest::Approx(1.0)); - CHECK(Math::inverse_lerp(2.0, 5.0, 8.0) == doctest::Approx(2.0)); +TEST_CASE_TEMPLATE("[Math] inverse_lerp", T, float, double) { + CHECK(Math::inverse_lerp((T)2.0, (T)5.0, (T)1.7) == doctest::Approx((T)-0.1)); + CHECK(Math::inverse_lerp((T)2.0, (T)5.0, (T)2.0) == doctest::Approx((T)0.0)); + CHECK(Math::inverse_lerp((T)2.0, (T)5.0, (T)2.3) == doctest::Approx((T)0.1)); + CHECK(Math::inverse_lerp((T)2.0, (T)5.0, (T)5.0) == doctest::Approx((T)1.0)); + CHECK(Math::inverse_lerp((T)2.0, (T)5.0, (T)8.0) == doctest::Approx((T)2.0)); - CHECK(Math::inverse_lerp(-2.0, -5.0, -1.7) == doctest::Approx(-0.1)); - CHECK(Math::inverse_lerp(-2.0, -5.0, -2.0) == doctest::Approx(0.0)); - CHECK(Math::inverse_lerp(-2.0, -5.0, -2.3) == doctest::Approx(0.1)); - CHECK(Math::inverse_lerp(-2.0, -5.0, -5.0) == doctest::Approx(1.0)); - CHECK(Math::inverse_lerp(-2.0, -5.0, -8.0) == doctest::Approx(2.0)); + CHECK(Math::inverse_lerp((T)-2.0, (T)-5.0, (T)-1.7) == doctest::Approx((T)-0.1)); + CHECK(Math::inverse_lerp((T)-2.0, (T)-5.0, (T)-2.0) == doctest::Approx((T)0.0)); + CHECK(Math::inverse_lerp((T)-2.0, (T)-5.0, (T)-2.3) == doctest::Approx((T)0.1)); + CHECK(Math::inverse_lerp((T)-2.0, (T)-5.0, (T)-5.0) == doctest::Approx((T)1.0)); + CHECK(Math::inverse_lerp((T)-2.0, (T)-5.0, (T)-8.0) == doctest::Approx((T)2.0)); } -TEST_CASE("[Math] remap") { - CHECK(Math::remap(50.0, 100.0, 200.0, 0.0, 1000.0) == doctest::Approx(-500.0)); - CHECK(Math::remap(100.0, 100.0, 200.0, 0.0, 1000.0) == doctest::Approx(0.0)); - CHECK(Math::remap(200.0, 100.0, 200.0, 0.0, 1000.0) == doctest::Approx(1000.0)); - CHECK(Math::remap(250.0, 100.0, 200.0, 0.0, 1000.0) == doctest::Approx(1500.0)); +TEST_CASE_TEMPLATE("[Math] remap", T, float, double) { + CHECK(Math::remap((T)50.0, (T)100.0, (T)200.0, (T)0.0, (T)1000.0) == doctest::Approx((T)-500.0)); + CHECK(Math::remap((T)100.0, (T)100.0, (T)200.0, (T)0.0, (T)1000.0) == doctest::Approx((T)0.0)); + CHECK(Math::remap((T)200.0, (T)100.0, (T)200.0, (T)0.0, (T)1000.0) == doctest::Approx((T)1000.0)); + CHECK(Math::remap((T)250.0, (T)100.0, (T)200.0, (T)0.0, (T)1000.0) == doctest::Approx((T)1500.0)); - CHECK(Math::remap(-50.0, -100.0, -200.0, 0.0, 1000.0) == doctest::Approx(-500.0)); - CHECK(Math::remap(-100.0, -100.0, -200.0, 0.0, 1000.0) == doctest::Approx(0.0)); - CHECK(Math::remap(-200.0, -100.0, -200.0, 0.0, 1000.0) == doctest::Approx(1000.0)); - CHECK(Math::remap(-250.0, -100.0, -200.0, 0.0, 1000.0) == doctest::Approx(1500.0)); + CHECK(Math::remap((T)-50.0, (T)-100.0, (T)-200.0, (T)0.0, (T)1000.0) == doctest::Approx((T)-500.0)); + CHECK(Math::remap((T)-100.0, (T)-100.0, (T)-200.0, (T)0.0, (T)1000.0) == doctest::Approx((T)0.0)); + CHECK(Math::remap((T)-200.0, (T)-100.0, (T)-200.0, (T)0.0, (T)1000.0) == doctest::Approx((T)1000.0)); + CHECK(Math::remap((T)-250.0, (T)-100.0, (T)-200.0, (T)0.0, (T)1000.0) == doctest::Approx((T)1500.0)); - CHECK(Math::remap(-50.0, -100.0, -200.0, 0.0, -1000.0) == doctest::Approx(500.0)); - CHECK(Math::remap(-100.0, -100.0, -200.0, 0.0, -1000.0) == doctest::Approx(0.0)); - CHECK(Math::remap(-200.0, -100.0, -200.0, 0.0, -1000.0) == doctest::Approx(-1000.0)); - CHECK(Math::remap(-250.0, -100.0, -200.0, 0.0, -1000.0) == doctest::Approx(-1500.0)); + CHECK(Math::remap((T)-50.0, (T)-100.0, (T)-200.0, (T)0.0, (T)-1000.0) == doctest::Approx((T)500.0)); + CHECK(Math::remap((T)-100.0, (T)-100.0, (T)-200.0, (T)0.0, (T)-1000.0) == doctest::Approx((T)0.0)); + CHECK(Math::remap((T)-200.0, (T)-100.0, (T)-200.0, (T)0.0, (T)-1000.0) == doctest::Approx((T)-1000.0)); + CHECK(Math::remap((T)-250.0, (T)-100.0, (T)-200.0, (T)0.0, (T)-1000.0) == doctest::Approx((T)-1500.0)); } -TEST_CASE("[Math] lerp_angle") { +TEST_CASE_TEMPLATE("[Math] lerp_angle", T, float, double) { // Counter-clockwise rotation. - CHECK(Math::lerp_angle(0.24 * Math_TAU, 0.75 * Math_TAU, 0.5) == doctest::Approx(-0.005 * Math_TAU)); + CHECK(Math::lerp_angle((T)0.24 * Math_TAU, 0.75 * Math_TAU, 0.5) == doctest::Approx((T)-0.005 * Math_TAU)); // Counter-clockwise rotation. - CHECK(Math::lerp_angle(0.25 * Math_TAU, 0.75 * Math_TAU, 0.5) == doctest::Approx(0.0)); + CHECK(Math::lerp_angle((T)0.25 * Math_TAU, 0.75 * Math_TAU, 0.5) == doctest::Approx((T)0.0)); // Clockwise rotation. - CHECK(Math::lerp_angle(0.26 * Math_TAU, 0.75 * Math_TAU, 0.5) == doctest::Approx(0.505 * Math_TAU)); + CHECK(Math::lerp_angle((T)0.26 * Math_TAU, 0.75 * Math_TAU, 0.5) == doctest::Approx((T)0.505 * Math_TAU)); - CHECK(Math::lerp_angle(-0.25 * Math_TAU, 1.25 * Math_TAU, 0.5) == doctest::Approx(-0.5 * Math_TAU)); - CHECK(Math::lerp_angle(0.72 * Math_TAU, 1.44 * Math_TAU, 0.96) == doctest::Approx(0.4512 * Math_TAU)); - CHECK(Math::lerp_angle(0.72 * Math_TAU, 1.44 * Math_TAU, 1.04) == doctest::Approx(0.4288 * Math_TAU)); + CHECK(Math::lerp_angle((T)-0.25 * Math_TAU, 1.25 * Math_TAU, 0.5) == doctest::Approx((T)-0.5 * Math_TAU)); + CHECK(Math::lerp_angle((T)0.72 * Math_TAU, 1.44 * Math_TAU, 0.96) == doctest::Approx((T)0.4512 * Math_TAU)); + CHECK(Math::lerp_angle((T)0.72 * Math_TAU, 1.44 * Math_TAU, 1.04) == doctest::Approx((T)0.4288 * Math_TAU)); // Initial and final angles are effectively identical, so the value returned // should always be the same regardless of the `weight` parameter. - CHECK(Math::lerp_angle(-4 * Math_TAU, 4 * Math_TAU, -1.0) == doctest::Approx(-4.0 * Math_TAU)); - CHECK(Math::lerp_angle(-4 * Math_TAU, 4 * Math_TAU, 0.0) == doctest::Approx(-4.0 * Math_TAU)); - CHECK(Math::lerp_angle(-4 * Math_TAU, 4 * Math_TAU, 0.5) == doctest::Approx(-4.0 * Math_TAU)); - CHECK(Math::lerp_angle(-4 * Math_TAU, 4 * Math_TAU, 1.0) == doctest::Approx(-4.0 * Math_TAU)); - CHECK(Math::lerp_angle(-4 * Math_TAU, 4 * Math_TAU, 500.0) == doctest::Approx(-4.0 * Math_TAU)); + CHECK(Math::lerp_angle((T)-4 * Math_TAU, 4 * Math_TAU, -1.0) == doctest::Approx((T)-4.0 * Math_TAU)); + CHECK(Math::lerp_angle((T)-4 * Math_TAU, 4 * Math_TAU, 0.0) == doctest::Approx((T)-4.0 * Math_TAU)); + CHECK(Math::lerp_angle((T)-4 * Math_TAU, 4 * Math_TAU, 0.5) == doctest::Approx((T)-4.0 * Math_TAU)); + CHECK(Math::lerp_angle((T)-4 * Math_TAU, 4 * Math_TAU, 1.0) == doctest::Approx((T)-4.0 * Math_TAU)); + CHECK(Math::lerp_angle((T)-4 * Math_TAU, 4 * Math_TAU, 500.0) == doctest::Approx((T)-4.0 * Math_TAU)); } -TEST_CASE("[Math] move_toward") { - CHECK(Math::move_toward(2.0, 5.0, -1.0) == doctest::Approx(1.0)); - CHECK(Math::move_toward(2.0, 5.0, 2.5) == doctest::Approx(4.5)); - CHECK(Math::move_toward(2.0, 5.0, 4.0) == doctest::Approx(5.0)); - CHECK(Math::move_toward(-2.0, -5.0, -1.0) == doctest::Approx(-1.0)); - CHECK(Math::move_toward(-2.0, -5.0, 2.5) == doctest::Approx(-4.5)); - CHECK(Math::move_toward(-2.0, -5.0, 4.0) == doctest::Approx(-5.0)); +TEST_CASE_TEMPLATE("[Math] move_toward", T, float, double) { + CHECK(Math::move_toward(2.0, 5.0, -1.0) == doctest::Approx((T)1.0)); + CHECK(Math::move_toward(2.0, 5.0, 2.5) == doctest::Approx((T)4.5)); + CHECK(Math::move_toward(2.0, 5.0, 4.0) == doctest::Approx((T)5.0)); + CHECK(Math::move_toward(-2.0, -5.0, -1.0) == doctest::Approx((T)-1.0)); + CHECK(Math::move_toward(-2.0, -5.0, 2.5) == doctest::Approx((T)-4.5)); + CHECK(Math::move_toward(-2.0, -5.0, 4.0) == doctest::Approx((T)-5.0)); } -TEST_CASE("[Math] smoothstep") { - CHECK(Math::smoothstep(0.0, 2.0, -5.0) == doctest::Approx(0.0)); - CHECK(Math::smoothstep(0.0, 2.0, 0.5) == doctest::Approx(0.15625)); - CHECK(Math::smoothstep(0.0, 2.0, 1.0) == doctest::Approx(0.5)); - CHECK(Math::smoothstep(0.0, 2.0, 2.0) == doctest::Approx(1.0)); +TEST_CASE_TEMPLATE("[Math] smoothstep", T, float, double) { + CHECK(Math::smoothstep((T)0.0, (T)2.0, (T)-5.0) == doctest::Approx((T)0.0)); + CHECK(Math::smoothstep((T)0.0, (T)2.0, (T)0.5) == doctest::Approx((T)0.15625)); + CHECK(Math::smoothstep((T)0.0, (T)2.0, (T)1.0) == doctest::Approx((T)0.5)); + CHECK(Math::smoothstep((T)0.0, (T)2.0, (T)2.0) == doctest::Approx((T)1.0)); } TEST_CASE("[Math] ease") { @@ -429,34 +419,34 @@ TEST_CASE("[Math] larger_prime") { ERR_PRINT_ON; } -TEST_CASE("[Math] fmod") { - CHECK(Math::fmod(-2.0, 0.3) == doctest::Approx(-0.2)); - CHECK(Math::fmod(0.0, 0.3) == doctest::Approx(0.0)); - CHECK(Math::fmod(2.0, 0.3) == doctest::Approx(0.2)); +TEST_CASE_TEMPLATE("[Math] fmod", T, float, double) { + CHECK(Math::fmod((T)-2.0, (T)0.3) == doctest::Approx((T)-0.2)); + CHECK(Math::fmod((T)0.0, (T)0.3) == doctest::Approx((T)0.0)); + CHECK(Math::fmod((T)2.0, (T)0.3) == doctest::Approx((T)0.2)); - CHECK(Math::fmod(-2.0, -0.3) == doctest::Approx(-0.2)); - CHECK(Math::fmod(0.0, -0.3) == doctest::Approx(0.0)); - CHECK(Math::fmod(2.0, -0.3) == doctest::Approx(0.2)); + CHECK(Math::fmod((T)-2.0, (T)-0.3) == doctest::Approx((T)-0.2)); + CHECK(Math::fmod((T)0.0, (T)-0.3) == doctest::Approx((T)0.0)); + CHECK(Math::fmod((T)2.0, (T)-0.3) == doctest::Approx((T)0.2)); } -TEST_CASE("[Math] fposmod") { - CHECK(Math::fposmod(-2.0, 0.3) == doctest::Approx(0.1)); - CHECK(Math::fposmod(0.0, 0.3) == doctest::Approx(0.0)); - CHECK(Math::fposmod(2.0, 0.3) == doctest::Approx(0.2)); +TEST_CASE_TEMPLATE("[Math] fposmod", T, float, double) { + CHECK(Math::fposmod((T)-2.0, (T)0.3) == doctest::Approx((T)0.1)); + CHECK(Math::fposmod((T)0.0, (T)0.3) == doctest::Approx((T)0.0)); + CHECK(Math::fposmod((T)2.0, (T)0.3) == doctest::Approx((T)0.2)); - CHECK(Math::fposmod(-2.0, -0.3) == doctest::Approx(-0.2)); - CHECK(Math::fposmod(0.0, -0.3) == doctest::Approx(0.0)); - CHECK(Math::fposmod(2.0, -0.3) == doctest::Approx(-0.1)); + CHECK(Math::fposmod((T)-2.0, (T)-0.3) == doctest::Approx((T)-0.2)); + CHECK(Math::fposmod((T)0.0, (T)-0.3) == doctest::Approx((T)0.0)); + CHECK(Math::fposmod((T)2.0, (T)-0.3) == doctest::Approx((T)-0.1)); } -TEST_CASE("[Math] fposmodp") { - CHECK(Math::fposmodp(-2.0, 0.3) == doctest::Approx(0.1)); - CHECK(Math::fposmodp(0.0, 0.3) == doctest::Approx(0.0)); - CHECK(Math::fposmodp(2.0, 0.3) == doctest::Approx(0.2)); +TEST_CASE_TEMPLATE("[Math] fposmodp", T, float, double) { + CHECK(Math::fposmodp((T)-2.0, (T)0.3) == doctest::Approx((T)0.1)); + CHECK(Math::fposmodp((T)0.0, (T)0.3) == doctest::Approx((T)0.0)); + CHECK(Math::fposmodp((T)2.0, (T)0.3) == doctest::Approx((T)0.2)); - CHECK(Math::fposmodp(-2.0, -0.3) == doctest::Approx(-0.5)); - CHECK(Math::fposmodp(0.0, -0.3) == doctest::Approx(0.0)); - CHECK(Math::fposmodp(2.0, -0.3) == doctest::Approx(0.2)); + CHECK(Math::fposmodp((T)-2.0, (T)-0.3) == doctest::Approx((T)-0.5)); + CHECK(Math::fposmodp((T)0.0, (T)-0.3) == doctest::Approx((T)0.0)); + CHECK(Math::fposmodp((T)2.0, (T)-0.3) == doctest::Approx((T)0.2)); } TEST_CASE("[Math] posmod") { @@ -475,80 +465,83 @@ TEST_CASE("[Math] wrapi") { CHECK(Math::wrapi(300'000'000'000, -20, 160) == 120); } -TEST_CASE("[Math] wrapf") { - CHECK(Math::wrapf(-30.0, -20.0, 160.0) == doctest::Approx(150.0)); - CHECK(Math::wrapf(30.0, -2.0, 160.0) == doctest::Approx(30.0)); - CHECK(Math::wrapf(300.0, -20.0, 160.0) == doctest::Approx(120.0)); - CHECK(Math::wrapf(300'000'000'000.0, -20.0, 160.0) == doctest::Approx(120.0)); +TEST_CASE_TEMPLATE("[Math] wrapf", T, float, double) { + CHECK(Math::wrapf((T)-30.0, (T)-20.0, (T)160.0) == doctest::Approx((T)150.0)); + CHECK(Math::wrapf((T)30.0, (T)-2.0, (T)160.0) == doctest::Approx((T)30.0)); + CHECK(Math::wrapf((T)300.0, (T)-20.0, (T)160.0) == doctest::Approx((T)120.0)); + + CHECK(Math::wrapf(300'000'000'000.0, -20.0, 160.0) == doctest::Approx((T)120.0)); + // float's precision is too low for 300'000'000'000.0, so we reduce it by a factor of 1000. + CHECK(Math::wrapf((float)300'000'000.0, (float)-20.0, (float)160.0) == doctest::Approx((T)128.0)); } -TEST_CASE("[Math] fract") { - CHECK(Math::fract(1.0) == doctest::Approx(0.0)); - CHECK(Math::fract(77.8) == doctest::Approx(0.8)); - CHECK(Math::fract(-10.1) == doctest::Approx(0.9)); +TEST_CASE_TEMPLATE("[Math] fract", T, float, double) { + CHECK(Math::fract((T)1.0) == doctest::Approx((T)0.0)); + CHECK(Math::fract((T)77.8) == doctest::Approx((T)0.8)); + CHECK(Math::fract((T)-10.1) == doctest::Approx((T)0.9)); } -TEST_CASE("[Math] pingpong") { - CHECK(Math::pingpong(0.0, 0.0) == doctest::Approx(0.0)); - CHECK(Math::pingpong(1.0, 1.0) == doctest::Approx(1.0)); - CHECK(Math::pingpong(0.5, 2.0) == doctest::Approx(0.5)); - CHECK(Math::pingpong(3.5, 2.0) == doctest::Approx(0.5)); - CHECK(Math::pingpong(11.5, 2.0) == doctest::Approx(0.5)); - CHECK(Math::pingpong(-2.5, 2.0) == doctest::Approx(1.5)); +TEST_CASE_TEMPLATE("[Math] pingpong", T, float, double) { + CHECK(Math::pingpong((T)0.0, (T)0.0) == doctest::Approx((T)0.0)); + CHECK(Math::pingpong((T)1.0, (T)1.0) == doctest::Approx((T)1.0)); + CHECK(Math::pingpong((T)0.5, (T)2.0) == doctest::Approx((T)0.5)); + CHECK(Math::pingpong((T)3.5, (T)2.0) == doctest::Approx((T)0.5)); + CHECK(Math::pingpong((T)11.5, (T)2.0) == doctest::Approx((T)0.5)); + CHECK(Math::pingpong((T)-2.5, (T)2.0) == doctest::Approx((T)1.5)); } -TEST_CASE("[Math] deg_to_rad/rad_to_deg") { - CHECK(Math::deg_to_rad(180.0) == doctest::Approx(Math_PI)); - CHECK(Math::deg_to_rad(-27.0) == doctest::Approx(-0.471239)); +TEST_CASE_TEMPLATE("[Math] deg_to_rad/rad_to_deg", T, float, double) { + CHECK(Math::deg_to_rad((T)180.0) == doctest::Approx((T)Math_PI)); + CHECK(Math::deg_to_rad((T)-27.0) == doctest::Approx((T)-0.471239)); - CHECK(Math::rad_to_deg(Math_PI) == doctest::Approx(180.0)); - CHECK(Math::rad_to_deg(-1.5) == doctest::Approx(-85.94366927)); + CHECK(Math::rad_to_deg((T)Math_PI) == doctest::Approx((T)180.0)); + CHECK(Math::rad_to_deg((T)-1.5) == doctest::Approx((T)-85.94366927)); } -TEST_CASE("[Math] cubic_interpolate") { - CHECK(Math::cubic_interpolate(0.2, 0.8, 0.0, 1.0, 0.0) == doctest::Approx(0.2)); - CHECK(Math::cubic_interpolate(0.2, 0.8, 0.0, 1.0, 0.25) == doctest::Approx(0.33125)); - CHECK(Math::cubic_interpolate(0.2, 0.8, 0.0, 1.0, 0.5) == doctest::Approx(0.5)); - CHECK(Math::cubic_interpolate(0.2, 0.8, 0.0, 1.0, 0.75) == doctest::Approx(0.66875)); - CHECK(Math::cubic_interpolate(0.2, 0.8, 0.0, 1.0, 1.0) == doctest::Approx(0.8)); +TEST_CASE_TEMPLATE("[Math] cubic_interpolate", T, float, double) { + CHECK(Math::cubic_interpolate((T)0.2, (T)0.8, (T)0.0, (T)1.0, (T)0.0) == doctest::Approx((T)0.2)); + CHECK(Math::cubic_interpolate((T)0.2, (T)0.8, (T)0.0, (T)1.0, (T)0.25) == doctest::Approx((T)0.33125)); + CHECK(Math::cubic_interpolate((T)0.2, (T)0.8, (T)0.0, (T)1.0, (T)0.5) == doctest::Approx((T)0.5)); + CHECK(Math::cubic_interpolate((T)0.2, (T)0.8, (T)0.0, (T)1.0, (T)0.75) == doctest::Approx((T)0.66875)); + CHECK(Math::cubic_interpolate((T)0.2, (T)0.8, (T)0.0, (T)1.0, (T)1.0) == doctest::Approx((T)0.8)); - CHECK(Math::cubic_interpolate(20.2, 30.1, -100.0, 32.0, -50.0) == doctest::Approx(-6662732.3)); - CHECK(Math::cubic_interpolate(20.2, 30.1, -100.0, 32.0, -5.0) == doctest::Approx(-9356.3)); - CHECK(Math::cubic_interpolate(20.2, 30.1, -100.0, 32.0, 0.0) == doctest::Approx(20.2)); - CHECK(Math::cubic_interpolate(20.2, 30.1, -100.0, 32.0, 1.0) == doctest::Approx(30.1)); - CHECK(Math::cubic_interpolate(20.2, 30.1, -100.0, 32.0, 4.0) == doctest::Approx(1853.2)); + CHECK(Math::cubic_interpolate((T)20.2, (T)30.1, (T)-100.0, (T)32.0, (T)-50.0) == doctest::Approx((T)-6662732.3)); + CHECK(Math::cubic_interpolate((T)20.2, (T)30.1, (T)-100.0, (T)32.0, (T)-5.0) == doctest::Approx((T)-9356.3)); + CHECK(Math::cubic_interpolate((T)20.2, (T)30.1, (T)-100.0, (T)32.0, (T)0.0) == doctest::Approx((T)20.2)); + CHECK(Math::cubic_interpolate((T)20.2, (T)30.1, (T)-100.0, (T)32.0, (T)1.0) == doctest::Approx((T)30.1)); + CHECK(Math::cubic_interpolate((T)20.2, (T)30.1, (T)-100.0, (T)32.0, (T)4.0) == doctest::Approx((T)1853.2)); } -TEST_CASE("[Math] cubic_interpolate_angle") { - CHECK(Math::cubic_interpolate_angle(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.0) == doctest::Approx(Math_PI * (1.0 / 6.0))); - CHECK(Math::cubic_interpolate_angle(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.25) == doctest::Approx(0.973566)); - CHECK(Math::cubic_interpolate_angle(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.5) == doctest::Approx(Math_PI / 2.0)); - CHECK(Math::cubic_interpolate_angle(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.75) == doctest::Approx(2.16803)); - CHECK(Math::cubic_interpolate_angle(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 1.0) == doctest::Approx(Math_PI * (5.0 / 6.0))); +TEST_CASE_TEMPLATE("[Math] cubic_interpolate_angle", T, float, double) { + CHECK(Math::cubic_interpolate_angle((T)(Math_PI * (1.0 / 6.0)), (T)(Math_PI * (5.0 / 6.0)), (T)0.0, (T)Math_PI, (T)0.0) == doctest::Approx((T)Math_PI * (1.0 / 6.0))); + CHECK(Math::cubic_interpolate_angle((T)(Math_PI * (1.0 / 6.0)), (T)(Math_PI * (5.0 / 6.0)), (T)0.0, (T)Math_PI, (T)0.25) == doctest::Approx((T)0.973566)); + CHECK(Math::cubic_interpolate_angle((T)(Math_PI * (1.0 / 6.0)), (T)(Math_PI * (5.0 / 6.0)), (T)0.0, (T)Math_PI, (T)0.5) == doctest::Approx((T)Math_PI / 2.0)); + CHECK(Math::cubic_interpolate_angle((T)(Math_PI * (1.0 / 6.0)), (T)(Math_PI * (5.0 / 6.0)), (T)0.0, (T)Math_PI, (T)0.75) == doctest::Approx((T)2.16803)); + CHECK(Math::cubic_interpolate_angle((T)(Math_PI * (1.0 / 6.0)), (T)(Math_PI * (5.0 / 6.0)), (T)0.0, (T)Math_PI, (T)1.0) == doctest::Approx((T)Math_PI * (5.0 / 6.0))); } -TEST_CASE("[Math] cubic_interpolate_in_time") { - CHECK(Math::cubic_interpolate_in_time(0.2, 0.8, 0.0, 1.0, 0.0, 0.5, 0.0, 1.0) == doctest::Approx(0.0)); - CHECK(Math::cubic_interpolate_in_time(0.2, 0.8, 0.0, 1.0, 0.25, 0.5, 0.0, 1.0) == doctest::Approx(0.1625)); - CHECK(Math::cubic_interpolate_in_time(0.2, 0.8, 0.0, 1.0, 0.5, 0.5, 0.0, 1.0) == doctest::Approx(0.4)); - CHECK(Math::cubic_interpolate_in_time(0.2, 0.8, 0.0, 1.0, 0.75, 0.5, 0.0, 1.0) == doctest::Approx(0.6375)); - CHECK(Math::cubic_interpolate_in_time(0.2, 0.8, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0) == doctest::Approx(0.8)); +TEST_CASE_TEMPLATE("[Math] cubic_interpolate_in_time", T, float, double) { + CHECK(Math::cubic_interpolate_in_time((T)0.2, (T)0.8, (T)0.0, (T)1.0, (T)0.0, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)0.0)); + CHECK(Math::cubic_interpolate_in_time((T)0.2, (T)0.8, (T)0.0, (T)1.0, (T)0.25, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)0.1625)); + CHECK(Math::cubic_interpolate_in_time((T)0.2, (T)0.8, (T)0.0, (T)1.0, (T)0.5, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)0.4)); + CHECK(Math::cubic_interpolate_in_time((T)0.2, (T)0.8, (T)0.0, (T)1.0, (T)0.75, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)0.6375)); + CHECK(Math::cubic_interpolate_in_time((T)0.2, (T)0.8, (T)0.0, (T)1.0, (T)1.0, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)0.8)); } -TEST_CASE("[Math] cubic_interpolate_angle_in_time") { - CHECK(Math::cubic_interpolate_angle_in_time(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.0, 0.5, 0.0, 1.0) == doctest::Approx(0.0)); - CHECK(Math::cubic_interpolate_angle_in_time(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.25, 0.5, 0.0, 1.0) == doctest::Approx(0.494964)); - CHECK(Math::cubic_interpolate_angle_in_time(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.5, 0.5, 0.0, 1.0) == doctest::Approx(1.27627)); - CHECK(Math::cubic_interpolate_angle_in_time(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 0.75, 0.5, 0.0, 1.0) == doctest::Approx(2.07394)); - CHECK(Math::cubic_interpolate_angle_in_time(Math_PI * (1.0 / 6.0), Math_PI * (5.0 / 6.0), 0.0, Math_PI, 1.0, 0.5, 0.0, 1.0) == doctest::Approx(Math_PI * (5.0 / 6.0))); +TEST_CASE_TEMPLATE("[Math] cubic_interpolate_angle_in_time", T, float, double) { + CHECK(Math::cubic_interpolate_angle_in_time((T)(Math_PI * (1.0 / 6.0)), (T)(Math_PI * (5.0 / 6.0)), (T)0.0, (T)Math_PI, (T)0.0, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)0.0)); + CHECK(Math::cubic_interpolate_angle_in_time((T)(Math_PI * (1.0 / 6.0)), (T)(Math_PI * (5.0 / 6.0)), (T)0.0, (T)Math_PI, (T)0.25, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)0.494964)); + CHECK(Math::cubic_interpolate_angle_in_time((T)(Math_PI * (1.0 / 6.0)), (T)(Math_PI * (5.0 / 6.0)), (T)0.0, (T)Math_PI, (T)0.5, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)1.27627)); + CHECK(Math::cubic_interpolate_angle_in_time((T)(Math_PI * (1.0 / 6.0)), (T)(Math_PI * (5.0 / 6.0)), (T)0.0, (T)Math_PI, (T)0.75, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)2.07394)); + CHECK(Math::cubic_interpolate_angle_in_time((T)(Math_PI * (1.0 / 6.0)), (T)(Math_PI * (5.0 / 6.0)), (T)0.0, (T)Math_PI, (T)1.0, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)Math_PI * (5.0 / 6.0))); } -TEST_CASE("[Math] bezier_interpolate") { - CHECK(Math::bezier_interpolate(0.0, 0.2, 0.8, 1.0, 0.0) == doctest::Approx(0.0)); - CHECK(Math::bezier_interpolate(0.0, 0.2, 0.8, 1.0, 0.25) == doctest::Approx(0.2125)); - CHECK(Math::bezier_interpolate(0.0, 0.2, 0.8, 1.0, 0.5) == doctest::Approx(0.5)); - CHECK(Math::bezier_interpolate(0.0, 0.2, 0.8, 1.0, 0.75) == doctest::Approx(0.7875)); - CHECK(Math::bezier_interpolate(0.0, 0.2, 0.8, 1.0, 1.0) == doctest::Approx(1.0)); +TEST_CASE_TEMPLATE("[Math] bezier_interpolate", T, float, double) { + CHECK(Math::bezier_interpolate((T)0.0, (T)0.2, (T)0.8, (T)1.0, (T)0.0) == doctest::Approx((T)0.0)); + CHECK(Math::bezier_interpolate((T)0.0, (T)0.2, (T)0.8, (T)1.0, (T)0.25) == doctest::Approx((T)0.2125)); + CHECK(Math::bezier_interpolate((T)0.0, (T)0.2, (T)0.8, (T)1.0, (T)0.5) == doctest::Approx((T)0.5)); + CHECK(Math::bezier_interpolate((T)0.0, (T)0.2, (T)0.8, (T)1.0, (T)0.75) == doctest::Approx((T)0.7875)); + CHECK(Math::bezier_interpolate((T)0.0, (T)0.2, (T)0.8, (T)1.0, (T)1.0) == doctest::Approx((T)1.0)); } } // namespace TestMath diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index 7e4e3aa9f0..659d451d76 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -226,6 +226,12 @@ TEST_CASE("[String] Comparisons (equal)") { CHECK(s == U"Test Compare"); CHECK(s == L"Test Compare"); CHECK(s == String("Test Compare")); + + CharString empty = ""; + CharString cs = "Test Compare"; + CHECK(!(empty == cs)); + CHECK(!(cs == empty)); + CHECK(cs == CharString("Test Compare")); } TEST_CASE("[String] Comparisons (not equal)") { @@ -516,21 +522,22 @@ TEST_CASE("[String] Splitting") { s = "1.2;2.3 4.5"; const double slices_d[3] = { 1.2, 2.3, 4.5 }; - Vector<float> f; - f = s.split_floats(";"); - CHECK(f.size() == 2); - for (int i = 0; i < f.size(); i++) { - CHECK(ABS(f[i] - slices_d[i]) <= 0.00001); + Vector<double> d_arr; + d_arr = s.split_floats(";"); + CHECK(d_arr.size() == 2); + for (int i = 0; i < d_arr.size(); i++) { + CHECK(ABS(d_arr[i] - slices_d[i]) <= 0.00001); } Vector<String> keys; keys.push_back(";"); keys.push_back(" "); - f = s.split_floats_mk(keys); - CHECK(f.size() == 3); - for (int i = 0; i < f.size(); i++) { - CHECK(ABS(f[i] - slices_d[i]) <= 0.00001); + Vector<float> f_arr; + f_arr = s.split_floats_mk(keys); + CHECK(f_arr.size() == 3); + for (int i = 0; i < f_arr.size(); i++) { + CHECK(ABS(f_arr[i] - slices_d[i]) <= 0.00001); } s = "1;2 4"; diff --git a/tests/scene/test_bit_map.h b/tests/scene/test_bit_map.h index aca7e5fe22..dc47bd7863 100644 --- a/tests/scene/test_bit_map.h +++ b/tests/scene/test_bit_map.h @@ -434,6 +434,37 @@ TEST_CASE("[BitMap] Clip to polygon") { polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 128, 128)); CHECK_MESSAGE(polygons.size() == 1, "We should have exactly 1 polygon"); CHECK_MESSAGE(polygons[0].size() == 6, "The polygon should have exactly 6 points"); + + reset_bit_map(bit_map); + bit_map.set_bit_rect(Rect2i(0, 0, 64, 64), true); + bit_map.set_bit_rect(Rect2i(64, 64, 64, 64), true); + bit_map.set_bit_rect(Rect2i(192, 128, 64, 64), true); + bit_map.set_bit_rect(Rect2i(128, 192, 64, 64), true); + polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 256, 256)); + CHECK_MESSAGE(polygons.size() == 4, "We should have exactly 4 polygons"); + CHECK_MESSAGE(polygons[0].size() == 4, "The polygon should have exactly 4 points"); + CHECK_MESSAGE(polygons[1].size() == 4, "The polygon should have exactly 4 points"); + CHECK_MESSAGE(polygons[2].size() == 4, "The polygon should have exactly 4 points"); + CHECK_MESSAGE(polygons[3].size() == 4, "The polygon should have exactly 4 points"); + + reset_bit_map(bit_map); + bit_map.set_bit(0, 0, true); + bit_map.set_bit(2, 0, true); + bit_map.set_bit_rect(Rect2i(1, 1, 1, 2), true); + polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 3, 3)); + CHECK_MESSAGE(polygons.size() == 3, "We should have exactly 3 polygons"); + CHECK_MESSAGE(polygons[0].size() == 4, "The polygon should have exactly 4 points"); + CHECK_MESSAGE(polygons[1].size() == 4, "The polygon should have exactly 4 points"); + CHECK_MESSAGE(polygons[2].size() == 4, "The polygon should have exactly 4 points"); + + reset_bit_map(bit_map); + bit_map.set_bit_rect(Rect2i(0, 0, 2, 1), true); + bit_map.set_bit_rect(Rect2i(0, 2, 3, 1), true); + bit_map.set_bit(0, 1, true); + bit_map.set_bit(2, 1, true); + polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 4, 4)); + CHECK_MESSAGE(polygons.size() == 1, "We should have exactly 1 polygon"); + CHECK_MESSAGE(polygons[0].size() == 6, "The polygon should have exactly 6 points"); } } // namespace TestBitmap diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h index 5dad7d06e1..6d1c2f4f2e 100644 --- a/tests/scene/test_text_edit.h +++ b/tests/scene/test_text_edit.h @@ -3261,8 +3261,8 @@ TEST_CASE("[SceneTree][TextEdit] mouse") { CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x - 100, end_pos.y - 100), false) == Point2i(90, 0)); CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x - 100, end_pos.y)) == Point2i(90, 0)); - CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x, end_pos.y + 100)) == Point2i(141, 0)); - CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x - 100, end_pos.y + 100)) == Point2i(141, 0)); + CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x, end_pos.y + 100)) == Point2i(140, 0)); + CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x - 100, end_pos.y + 100)) == Point2i(140, 0)); CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x, end_pos.y - 100)) == Point2i(104, 0)); CHECK(text_edit->get_line_column_at_pos(Point2i(end_pos.x - 100, end_pos.y - 100)) == Point2i(90, 0)); diff --git a/thirdparty/README.md b/thirdparty/README.md index 84ed095fd9..9a58c928cc 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -51,7 +51,7 @@ Files extracted from upstream source: ## cvtt - Upstream: https://github.com/elasota/ConvectionKernels -- Version: git (dc2dbbe0ae2cf2be06ef56d1021e2222a56c7fe2, 2021) +- Version: git (350416daa4e98f1c17ffc273b134d0120a2ef230, 2022) - License: MIT Files extracted from upstream source: diff --git a/thirdparty/cvtt/ConvectionKernels_BC67.cpp b/thirdparty/cvtt/ConvectionKernels_BC67.cpp index 791859b232..021d658c08 100644 --- a/thirdparty/cvtt/ConvectionKernels_BC67.cpp +++ b/thirdparty/cvtt/ConvectionKernels_BC67.cpp @@ -726,10 +726,10 @@ namespace cvtt if (carry) { uint32_t bitMask = (1 << carry) - 1; - for (int i = 0; i < 4; i++) + for (int i = 0; i < entriesRemaining; i++) { m_vector[i] >>= carry; - if (i != 3) + if (i != entriesRemaining - 1) m_vector[i] |= (m_vector[i + 1] & bitMask) << (32 - carry); } } @@ -3058,14 +3058,11 @@ void cvtt::Internal::BC6HComputer::SignExtendSingle(int &v, int bits) void cvtt::Internal::BC6HComputer::UnpackOne(PixelBlockF16 &output, const uint8_t *pBC, bool isSigned) { - UnpackingVector pv; - pv.Init(pBC); - int numModeBits = 2; - int modeBits = pv.Unpack(2); + int modeBits = pBC[0] & 0x3; if (modeBits != 0 && modeBits != 1) { - modeBits |= pv.Unpack(3) << 2; + modeBits = pBC[0] & 0x1f; numModeBits += 3; } @@ -3102,6 +3099,9 @@ void cvtt::Internal::BC6HComputer::UnpackOne(PixelBlockF16 &output, const uint8_ for (int ch = 0; ch < 3; ch++) eps[subset][epi][ch] = 0; + UnpackingVector pv; + pv.Init(pBC); + { uint32_t header[3]; uint16_t codedEPs[2][2][3]; |