diff options
407 files changed, 4683 insertions, 2407 deletions
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index 81c7042663..fea82791ed 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -27,16 +27,12 @@ jobs: sudo apt-get install -qq dos2unix recode clang-format-13 libxml2-utils sudo update-alternatives --remove-all clang-format sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-13 100 - sudo pip3 install black==22.3.0 pygments + sudo pip3 install black==22.3.0 pygments pytest - name: File formatting checks (file_format.sh) run: | bash ./misc/scripts/file_format.sh - - name: Style checks via clang-format (clang_format.sh) - run: | - bash ./misc/scripts/clang_format.sh - - name: Header guards formatting checks (header_guards.sh) run: | bash ./misc/scripts/header_guards.sh @@ -45,6 +41,10 @@ jobs: run: | bash ./misc/scripts/black_format.sh + - name: Python builders checks via pytest (pytest_builders.sh) + run: | + bash ./misc/scripts/pytest_builders.sh + - name: JavaScript style and documentation checks via ESLint and JSDoc run: | cd platform/javascript @@ -59,3 +59,7 @@ jobs: - name: Documentation checks run: | doc/tools/make_rst.py --dry-run --color doc/classes modules + + - name: Style checks via clang-format (clang_format.sh) + run: | + bash ./misc/scripts/clang_format.sh diff --git a/core/config/engine.cpp b/core/config/engine.cpp index e1da9eb44e..6606557fce 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -33,7 +33,9 @@ #include "core/authors.gen.h" #include "core/config/project_settings.h" #include "core/donors.gen.h" +#include "core/io/json.h" #include "core/license.gen.h" +#include "core/os/os.h" #include "core/version.h" void Engine::set_physics_ticks_per_second(int p_ips) { @@ -307,6 +309,43 @@ Engine::Engine() { singleton = this; } +void Engine::startup_begin() { + startup_benchmark_total_from = OS::get_singleton()->get_ticks_usec(); +} + +void Engine::startup_benchmark_begin_measure(const String &p_what) { + startup_benchmark_section = p_what; + startup_benchmark_from = OS::get_singleton()->get_ticks_usec(); +} +void Engine::startup_benchmark_end_measure() { + uint64_t total = OS::get_singleton()->get_ticks_usec() - startup_benchmark_from; + double total_f = double(total) / double(1000000); + + startup_benchmark_json[startup_benchmark_section] = total_f; +} + +void Engine::startup_dump(const String &p_to_file) { + uint64_t total = OS::get_singleton()->get_ticks_usec() - startup_benchmark_total_from; + double total_f = double(total) / double(1000000); + startup_benchmark_json["total_time"] = total_f; + + if (!p_to_file.is_empty()) { + Ref<FileAccess> f = FileAccess::open(p_to_file, FileAccess::WRITE); + if (f.is_valid()) { + Ref<JSON> json; + json.instantiate(); + f->store_string(json->stringify(startup_benchmark_json, "\t", false, true)); + } + } else { + List<Variant> keys; + startup_benchmark_json.get_key_list(&keys); + print_line("STARTUP BENCHMARK:"); + for (const Variant &K : keys) { + print_line("\t-", K, ": ", startup_benchmark_json[K], +" sec."); + } + } +} + Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr, const StringName &p_class_name) : name(p_name), ptr(p_ptr), diff --git a/core/config/engine.h b/core/config/engine.h index 649be23717..b4364dbda4 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -79,6 +79,11 @@ private: String write_movie_path; String shader_cache_path; + Dictionary startup_benchmark_json; + String startup_benchmark_section; + uint64_t startup_benchmark_from = 0; + uint64_t startup_benchmark_total_from = 0; + public: static Engine *get_singleton(); @@ -151,6 +156,11 @@ public: bool is_validation_layers_enabled() const; int32_t get_gpu_index() const; + void startup_begin(); + void startup_benchmark_begin_measure(const String &p_what); + void startup_benchmark_end_measure(); + void startup_dump(const String &p_to_file); + Engine(); virtual ~Engine() {} }; diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 8ad2193fca..3f02d80c26 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -274,24 +274,24 @@ void InputEventWithModifiers::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command_pressed"), "set_command_pressed", "is_command_pressed"); } -void InputEventWithModifiers::_validate_property(PropertyInfo &property) const { +void InputEventWithModifiers::_validate_property(PropertyInfo &p_property) const { if (store_command) { // If we only want to Store "Command". #ifdef APPLE_STYLE_KEYS // Don't store "Meta" on Mac. - if (property.name == "meta_pressed") { - property.usage ^= PROPERTY_USAGE_STORAGE; + if (p_property.name == "meta_pressed") { + p_property.usage ^= PROPERTY_USAGE_STORAGE; } #else // Don't store "Ctrl". - if (property.name == "ctrl_pressed") { - property.usage ^= PROPERTY_USAGE_STORAGE; + if (p_property.name == "ctrl_pressed") { + p_property.usage ^= PROPERTY_USAGE_STORAGE; } #endif } else { // We don't want to store command, only ctrl or meta (on mac). - if (property.name == "command_pressed") { - property.usage ^= PROPERTY_USAGE_STORAGE; + if (p_property.name == "command_pressed") { + p_property.usage ^= PROPERTY_USAGE_STORAGE; } } } diff --git a/core/input/input_event.h b/core/input/input_event.h index 59a2df497c..6cfc031c8a 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -128,7 +128,7 @@ class InputEventWithModifiers : public InputEventFromWindow { protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_store_command(bool p_enabled); diff --git a/core/io/json.cpp b/core/io/json.cpp index 4c4d91f851..91500ff3d5 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -528,11 +528,6 @@ Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_st return err; } -String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) { - HashSet<const void *> markers; - return _stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision); -} - Error JSON::parse(const String &p_json_string) { Error err = _parse_string(p_json_string, data, err_str, err_line); if (err == Error::OK) { @@ -541,8 +536,24 @@ Error JSON::parse(const String &p_json_string) { return err; } +String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) { + Ref<JSON> jason; + jason.instantiate(); + HashSet<const void *> markers; + return jason->_stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision); +} + +Variant JSON::parse_string(const String &p_json_string) { + Ref<JSON> jason; + jason.instantiate(); + Error error = jason->parse(p_json_string); + ERR_FAIL_COND_V_MSG(error != Error::OK, Variant(), vformat("Parse JSON failed. Error at line %d: %s", jason->get_error_line(), jason->get_error_message())); + return jason->get_data(); +} + void JSON::_bind_methods() { - ClassDB::bind_method(D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false)); + ClassDB::bind_static_method("JSON", D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false)); + ClassDB::bind_static_method("JSON", D_METHOD("parse_string", "json_string"), &JSON::parse_string); ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse); ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data); diff --git a/core/io/json.h b/core/io/json.h index 6ba0a8c76b..840b1cc08a 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -81,8 +81,9 @@ protected: static void _bind_methods(); public: - String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false); Error parse(const String &p_json_string); + static String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false); + static Variant parse_string(const String &p_json_string); inline Variant get_data() const { return data; } inline int get_error_line() const { return err_line; } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index f8e7c47107..bc50d0e64c 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -749,67 +749,6 @@ Quaternion Basis::get_quaternion() const { return Quaternion(temp[0], temp[1], temp[2], temp[3]); } -static const Basis _ortho_bases[24] = { - Basis(1, 0, 0, 0, 1, 0, 0, 0, 1), - Basis(0, -1, 0, 1, 0, 0, 0, 0, 1), - Basis(-1, 0, 0, 0, -1, 0, 0, 0, 1), - Basis(0, 1, 0, -1, 0, 0, 0, 0, 1), - Basis(1, 0, 0, 0, 0, -1, 0, 1, 0), - Basis(0, 0, 1, 1, 0, 0, 0, 1, 0), - Basis(-1, 0, 0, 0, 0, 1, 0, 1, 0), - Basis(0, 0, -1, -1, 0, 0, 0, 1, 0), - Basis(1, 0, 0, 0, -1, 0, 0, 0, -1), - Basis(0, 1, 0, 1, 0, 0, 0, 0, -1), - Basis(-1, 0, 0, 0, 1, 0, 0, 0, -1), - Basis(0, -1, 0, -1, 0, 0, 0, 0, -1), - Basis(1, 0, 0, 0, 0, 1, 0, -1, 0), - Basis(0, 0, -1, 1, 0, 0, 0, -1, 0), - Basis(-1, 0, 0, 0, 0, -1, 0, -1, 0), - Basis(0, 0, 1, -1, 0, 0, 0, -1, 0), - Basis(0, 0, 1, 0, 1, 0, -1, 0, 0), - Basis(0, -1, 0, 0, 0, 1, -1, 0, 0), - Basis(0, 0, -1, 0, -1, 0, -1, 0, 0), - Basis(0, 1, 0, 0, 0, -1, -1, 0, 0), - Basis(0, 0, 1, 0, -1, 0, 1, 0, 0), - Basis(0, 1, 0, 0, 0, 1, 1, 0, 0), - Basis(0, 0, -1, 0, 1, 0, 1, 0, 0), - Basis(0, -1, 0, 0, 0, -1, 1, 0, 0) -}; - -int Basis::get_orthogonal_index() const { - //could be sped up if i come up with a way - Basis orth = *this; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - real_t v = orth[i][j]; - if (v > 0.5f) { - v = 1.0f; - } else if (v < -0.5f) { - v = -1.0f; - } else { - v = 0; - } - - orth[i][j] = v; - } - } - - for (int i = 0; i < 24; i++) { - if (_ortho_bases[i] == orth) { - return i; - } - } - - return 0; -} - -void Basis::set_orthogonal_index(int p_index) { - //there only exist 24 orthogonal bases in r3 - ERR_FAIL_INDEX(p_index, 24); - - *this = _ortho_bases[p_index]; -} - void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { /* checking this is a bad idea, because obtaining from scaled transform is a valid use case #ifdef MATH_CHECKS diff --git a/core/math/basis.h b/core/math/basis.h index 4be325cdd2..2853947ba7 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -149,9 +149,6 @@ struct _NO_DISCARD_ Basis { _FORCE_INLINE_ void operator*=(const real_t p_val); _FORCE_INLINE_ Basis operator*(const real_t p_val) const; - int get_orthogonal_index() const; - void set_orthogonal_index(int p_index); - bool is_orthogonal() const; bool is_diagonal() const; bool is_rotation() const; diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 53deb9bd42..463e119add 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -253,6 +253,29 @@ public: (-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight)); } + static _ALWAYS_INLINE_ double cubic_interpolate_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight, + double p_to_t, double p_pre_t, double p_post_t) { + /* Barry-Goldman method */ + double t = Math::lerp(0.0, p_to_t, p_weight); + double a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0 : (t - p_pre_t) / -p_pre_t); + double a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5 : t / p_to_t); + double a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0 : (t - p_to_t) / (p_post_t - p_to_t)); + double b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0 : (t - p_pre_t) / (p_to_t - p_pre_t)); + double b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t); + return Math::lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t); + } + static _ALWAYS_INLINE_ float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight, + float p_to_t, float p_pre_t, float p_post_t) { + /* Barry-Goldman method */ + float t = Math::lerp(0.0f, p_to_t, p_weight); + float a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0f : (t - p_pre_t) / -p_pre_t); + float a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5f : t / p_to_t); + float a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0f : (t - p_to_t) / (p_post_t - p_to_t)); + float b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0f : (t - p_pre_t) / (p_to_t - p_pre_t)); + float b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0f : t / p_post_t); + return Math::lerp(b1, b2, p_to_t == 0 ? 0.5f : t / p_to_t); + } + static _ALWAYS_INLINE_ double bezier_interpolate(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); diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp index c681c60694..36358f6feb 100644 --- a/core/math/quaternion.cpp +++ b/core/math/quaternion.cpp @@ -233,6 +233,57 @@ Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const return q1.slerp(q2, p_weight); } +Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &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 { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized."); +#endif + Quaternion from_q = *this; + Quaternion pre_q = p_pre_a; + Quaternion to_q = p_b; + Quaternion post_q = p_post_b; + + // Align flip phases. + from_q = Basis(from_q).get_rotation_quaternion(); + pre_q = Basis(pre_q).get_rotation_quaternion(); + to_q = Basis(to_q).get_rotation_quaternion(); + post_q = Basis(post_q).get_rotation_quaternion(); + + // Flip quaternions to shortest path if necessary. + bool flip1 = signbit(from_q.dot(pre_q)); + pre_q = flip1 ? -pre_q : pre_q; + bool flip2 = signbit(from_q.dot(to_q)); + to_q = flip2 ? -to_q : to_q; + bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : signbit(to_q.dot(post_q)); + post_q = flip3 ? -post_q : post_q; + + // Calc by Expmap in from_q space. + Quaternion ln_from = Quaternion(0, 0, 0, 0); + Quaternion ln_to = (from_q.inverse() * to_q).log(); + Quaternion ln_pre = (from_q.inverse() * pre_q).log(); + Quaternion ln_post = (from_q.inverse() * post_q).log(); + Quaternion ln = Quaternion(0, 0, 0, 0); + ln.x = Math::cubic_interpolate_in_time(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + ln.y = Math::cubic_interpolate_in_time(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + ln.z = Math::cubic_interpolate_in_time(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + Quaternion q1 = from_q * ln.exp(); + + // Calc by Expmap in to_q space. + ln_from = (to_q.inverse() * from_q).log(); + ln_to = Quaternion(0, 0, 0, 0); + ln_pre = (to_q.inverse() * pre_q).log(); + ln_post = (to_q.inverse() * post_q).log(); + ln = Quaternion(0, 0, 0, 0); + ln.x = Math::cubic_interpolate_in_time(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + ln.y = Math::cubic_interpolate_in_time(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + ln.z = Math::cubic_interpolate_in_time(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + Quaternion q2 = to_q * ln.exp(); + + // To cancel error made by Expmap ambiguity, do blends. + return q1.slerp(q2, p_weight); +} + Quaternion::operator String() const { return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")"; } diff --git a/core/math/quaternion.h b/core/math/quaternion.h index cb54a6f540..43d7bffcfc 100644 --- a/core/math/quaternion.h +++ b/core/math/quaternion.h @@ -72,6 +72,7 @@ struct _NO_DISCARD_ Quaternion { Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const; Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const; Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const; + Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &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; Vector3 get_axis() const; real_t get_angle() const; diff --git a/core/math/vector2.h b/core/math/vector2.h index 91d3d3a56b..caa6b226e7 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -114,6 +114,7 @@ struct _NO_DISCARD_ Vector2 { _FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, const real_t p_weight) const; _FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, const real_t p_weight) const; _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; Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const; @@ -270,6 +271,13 @@ Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, c return res; } +Vector2 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 { + Vector2 res = *this; + res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + return res; +} + 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; diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index d71d365053..fdbbb8cb5c 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -117,6 +117,22 @@ Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) { return n.normalized(); } +Vector2 Vector3::octahedron_tangent_encode(const float sign) const { + Vector2 res = this->octahedron_encode(); + res.y = res.y * 0.5f + 0.5f; + res.y = sign >= 0.0f ? res.y : 1 - res.y; + return res; +} + +Vector3 Vector3::octahedron_tangent_decode(const Vector2 &p_oct, float *sign) { + Vector2 oct_compressed = p_oct; + oct_compressed.y = oct_compressed.y * 2 - 1; + *sign = oct_compressed.y >= 0.0f ? 1.0f : -1.0f; + oct_compressed.y = Math::abs(oct_compressed.y); + Vector3 res = Vector3::octahedron_decode(oct_compressed); + return res; +} + Basis Vector3::outer(const Vector3 &p_with) const { Vector3 row0(x * p_with.x, x * p_with.y, x * p_with.z); Vector3 row1(y * p_with.x, y * p_with.y, y * p_with.z); diff --git a/core/math/vector3.h b/core/math/vector3.h index 4ce01da60e..7cae6e2481 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -105,12 +105,15 @@ struct _NO_DISCARD_ Vector3 { _FORCE_INLINE_ Vector3 lerp(const Vector3 &p_to, const real_t p_weight) const; _FORCE_INLINE_ Vector3 slerp(const Vector3 &p_to, const real_t p_weight) const; _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; Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const; Vector2 octahedron_encode() const; static Vector3 octahedron_decode(const Vector2 &p_oct); + Vector2 octahedron_tangent_encode(const float sign) const; + static Vector3 octahedron_tangent_decode(const Vector2 &p_oct, float *sign); _FORCE_INLINE_ Vector3 cross(const Vector3 &p_with) const; _FORCE_INLINE_ real_t dot(const Vector3 &p_with) const; @@ -246,6 +249,14 @@ Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, c return res; } +Vector3 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 { + Vector3 res = *this; + res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + res.z = Math::cubic_interpolate_in_time(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + return res; +} + 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; diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp index 1dd5adad2b..273a111891 100644 --- a/core/math/vector4.cpp +++ b/core/math/vector4.cpp @@ -138,6 +138,15 @@ Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, c return res; } +Vector4 Vector4::cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &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 { + Vector4 res = *this; + res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + res.z = Math::cubic_interpolate_in_time(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + res.w = Math::cubic_interpolate_in_time(res.w, p_b.w, p_pre_a.w, p_post_b.w, p_weight, p_b_t, p_pre_a_t, p_post_b_t); + return res; +} + Vector4 Vector4::posmod(const real_t p_mod) const { return Vector4(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod), Math::fposmod(w, p_mod)); } diff --git a/core/math/vector4.h b/core/math/vector4.h index d26fe15941..17d0de18e1 100644 --- a/core/math/vector4.h +++ b/core/math/vector4.h @@ -89,6 +89,7 @@ struct _NO_DISCARD_ Vector4 { Vector4 round() const; Vector4 lerp(const Vector4 &p_to, const real_t p_weight) const; Vector4 cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const; + Vector4 cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &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; Vector4 posmod(const real_t p_mod) const; Vector4 posmodv(const Vector4 &p_modv) const; diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 9790cc44e3..99b20560da 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -981,7 +981,7 @@ void ClassDB::get_property_list(const StringName &p_class, List<PropertyInfo> *p if (p_validator) { // Making a copy as we may modify it. PropertyInfo pi_mut = pi; - p_validator->_validate_property(pi_mut); + p_validator->validate_property(pi_mut); p_list->push_back(pi_mut); } else { p_list->push_back(pi); @@ -1022,7 +1022,7 @@ bool ClassDB::get_property_info(const StringName &p_class, const StringName &p_p if (check->property_map.has(p_property)) { PropertyInfo pinfo = check->property_map[p_property]; if (p_validator) { - p_validator->_validate_property(pinfo); + p_validator->validate_property(pinfo); } if (r_info) { *r_info = pinfo; diff --git a/core/object/object.cpp b/core/object/object.cpp index a95ba7992b..5203685c7f 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -515,7 +515,8 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons } } -void Object::_validate_property(PropertyInfo &property) const { +void Object::validate_property(PropertyInfo &p_property) const { + _validate_propertyv(p_property); } bool Object::property_can_revert(const String &p_name) const { diff --git a/core/object/object.h b/core/object/object.h index 154ef176d3..093b104664 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -471,6 +471,15 @@ protected: m_inherits::_get_property_listv(p_list, p_reversed); \ } \ } \ + _FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo & p_property) const { \ + return (void(Object::*)(PropertyInfo &) const) & m_class::_validate_property; \ + } \ + virtual void _validate_propertyv(PropertyInfo &p_property) const override { \ + m_inherits::_validate_propertyv(p_property); \ + if (m_class::_get_validate_property() != m_inherits::_get_validate_property()) { \ + _validate_property(p_property); \ + } \ + } \ _FORCE_INLINE_ bool (Object::*_get_property_can_revert() const)(const StringName &p_name) const { \ return (bool(Object::*)(const StringName &) const) & m_class::_property_can_revert; \ } \ @@ -637,6 +646,7 @@ protected: virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; }; virtual bool _getv(const StringName &p_name, Variant &r_property) const { return false; }; virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const {}; + virtual void _validate_propertyv(PropertyInfo &p_property) const {}; virtual bool _property_can_revertv(const StringName &p_name) const { return false; }; virtual bool _property_get_revertv(const StringName &p_name, Variant &r_property) const { return false; }; virtual void _notificationv(int p_notification, bool p_reversed) {} @@ -645,6 +655,7 @@ protected: bool _set(const StringName &p_name, const Variant &p_property) { return false; }; bool _get(const StringName &p_name, Variant &r_property) const { return false; }; void _get_property_list(List<PropertyInfo> *p_list) const {}; + void _validate_property(PropertyInfo &p_property) const {}; bool _property_can_revert(const StringName &p_name) const { return false; }; bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; }; void _notification(int p_notification) {} @@ -661,6 +672,9 @@ protected: _FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List<PropertyInfo> *p_list) const { return &Object::_get_property_list; } + _FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo &p_property) const { + return &Object::_validate_property; + } _FORCE_INLINE_ bool (Object::*_get_property_can_revert() const)(const StringName &p_name) const { return &Object::_property_can_revert; } @@ -690,7 +704,6 @@ protected: void _clear_internal_resource_paths(const Variant &p_var); friend class ClassDB; - virtual void _validate_property(PropertyInfo &property) const; void _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false); @@ -791,6 +804,7 @@ public: Variant get_indexed(const Vector<StringName> &p_names, bool *r_valid = nullptr) const; void get_property_list(List<PropertyInfo> *p_list, bool p_reversed = false) const; + void validate_property(PropertyInfo &p_property) const; bool property_can_revert(const String &p_name) const; Variant property_get_revert(const String &p_name) const; diff --git a/core/os/os.cpp b/core/os/os.cpp index 1358c926d1..6091079241 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -166,10 +166,6 @@ bool OS::is_stdout_verbose() const { return _verbose_stdout; } -bool OS::is_single_window() const { - return _single_window; -} - bool OS::is_stdout_debug_enabled() const { return _debug_stdout; } diff --git a/core/os/os.h b/core/os/os.h index 9152b797ef..be9d73c22d 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -52,7 +52,6 @@ class OS { int low_processor_usage_mode_sleep_usec = 10000; bool _verbose_stdout = false; bool _debug_stdout = false; - bool _single_window = false; String _local_clipboard; int _exit_code = EXIT_FAILURE; // unexpected exit is marked as failure bool _allow_hidpi = false; @@ -243,8 +242,6 @@ public: void set_stdout_enabled(bool p_enabled); void set_stderr_enabled(bool p_enabled); - virtual bool is_single_window() const; - virtual void disable_crash_handler() {} virtual bool is_disable_crash_handler() const { return false; } virtual void initialize_debugging() {} diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index e93375bff7..13be7516d5 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -531,10 +531,12 @@ String &String::operator+=(const String &p_str) { resize(lhs_len + rhs_len + 1); - const char32_t *src = p_str.get_data(); + const char32_t *src = p_str.ptr(); char32_t *dst = ptrw() + lhs_len; - memcpy(dst, src, (rhs_len + 1) * sizeof(char32_t)); + // Don't copy the terminating null with `memcpy` to avoid undefined behavior when string is being added to itself (it would overlap the destination). + memcpy(dst, src, rhs_len * sizeof(char32_t)); + *(dst + rhs_len) = _null; return *this; } diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index eba12b68bb..9b7dc5012b 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1608,6 +1608,7 @@ static void _register_variant_builtin_methods() { bind_method(Vector2, lerp, sarray("to", "weight"), varray()); bind_method(Vector2, slerp, sarray("to", "weight"), varray()); 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, max_axis_index, sarray(), varray()); bind_method(Vector2, min_axis_index, sarray(), varray()); @@ -1696,6 +1697,7 @@ static void _register_variant_builtin_methods() { bind_method(Vector3, lerp, sarray("to", "weight"), varray()); bind_method(Vector3, slerp, sarray("to", "weight"), varray()); 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, move_toward, sarray("to", "delta"), varray()); bind_method(Vector3, dot, sarray("with"), varray()); @@ -1738,6 +1740,7 @@ static void _register_variant_builtin_methods() { bind_method(Vector4, round, sarray(), varray()); bind_method(Vector4, lerp, sarray("to", "weight"), varray()); bind_method(Vector4, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray()); + bind_method(Vector4, cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray()); bind_method(Vector4, posmod, sarray("mod"), varray()); bind_method(Vector4, posmodv, sarray("modv"), varray()); bind_method(Vector4, snapped, sarray("step"), varray()); @@ -1789,6 +1792,7 @@ static void _register_variant_builtin_methods() { bind_method(Quaternion, slerp, sarray("to", "weight"), varray()); bind_method(Quaternion, slerpni, sarray("to", "weight"), varray()); bind_method(Quaternion, spherical_cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray()); + bind_method(Quaternion, spherical_cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray()); bind_method(Quaternion, get_euler, sarray(), varray()); bind_method(Quaternion, get_axis, sarray(), varray()); bind_method(Quaternion, get_angle, sarray(), varray()); @@ -1916,7 +1920,6 @@ static void _register_variant_builtin_methods() { bind_method(Basis, tdotx, sarray("with"), varray()); bind_method(Basis, tdoty, sarray("with"), varray()); bind_method(Basis, tdotz, sarray("with"), varray()); - bind_method(Basis, get_orthogonal_index, sarray(), varray()); bind_method(Basis, slerp, sarray("to", "weight"), varray()); bind_method(Basis, is_equal_approx, sarray("b"), varray()); bind_method(Basis, get_rotation_quaternion, sarray(), varray()); diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 1f1439ab24..21c9c483a5 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -367,6 +367,11 @@ struct VariantUtilityFunctions { return Math::cubic_interpolate(from, to, pre, post, weight); } + static inline double cubic_interpolate_in_time(double from, double to, double pre, double post, double weight, + double to_t, double pre_t, double post_t) { + return Math::cubic_interpolate_in_time(from, to, pre, post, weight, to_t, pre_t, post_t); + } + static inline double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) { return Math::bezier_interpolate(p_start, p_control_1, p_control_2, p_end, p_t); } @@ -1414,6 +1419,7 @@ void Variant::_register_variant_utility_functions() { FUNCBINDVR3(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(lerpf, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(cubic_interpolate, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(cubic_interpolate_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(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 5b3f4d4e7b..722177c9e8 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -260,6 +260,21 @@ Cubic interpolates between two values by the factor defined in [param weight] with pre and post values. </description> </method> + <method name="cubic_interpolate_in_time"> + <return type="float" /> + <param index="0" name="from" type="float" /> + <param index="1" name="to" type="float" /> + <param index="2" name="pre" type="float" /> + <param index="3" name="post" type="float" /> + <param index="4" name="weight" type="float" /> + <param index="5" name="to_t" type="float" /> + <param index="6" name="pre_t" type="float" /> + <param index="7" name="post_t" type="float" /> + <description> + Cubic interpolates between two values by the factor defined in [param weight] with pre and post values. + It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values. + </description> + </method> <method name="db2linear"> <return type="float" /> <param index="0" name="db" type="float" /> diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index 859b4a8a5f..fef65181ae 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -619,6 +619,9 @@ <constant name="INTERPOLATION_CUBIC" value="2" enum="InterpolationType"> Cubic interpolation. </constant> + <constant name="INTERPOLATION_CUBIC_IN_TIME" value="3" enum="InterpolationType"> + Cubic interpolation with uniformed time. + </constant> <constant name="UPDATE_CONTINUOUS" value="0" enum="UpdateMode"> Update between keyframes. </constant> diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml index 0badb831de..beb259b12b 100644 --- a/doc/classes/AnimationNodeStateMachineTransition.xml +++ b/doc/classes/AnimationNodeStateMachineTransition.xml @@ -37,6 +37,9 @@ <member name="switch_mode" type="int" setter="set_switch_mode" getter="get_switch_mode" enum="AnimationNodeStateMachineTransition.SwitchMode" default="0"> The transition type. </member> + <member name="xfade_curve" type="Curve" setter="set_xfade_curve" getter="get_xfade_curve"> + Ease curve for better control over cross-fade between this state and the next. + </member> <member name="xfade_time" type="float" setter="set_xfade_time" getter="get_xfade_time" default="0.0"> The time to cross-fade between this state and the next. </member> diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml index a5de170ccd..d574bc044d 100644 --- a/doc/classes/AnimationNodeTransition.xml +++ b/doc/classes/AnimationNodeTransition.xml @@ -46,7 +46,9 @@ <member name="input_count" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs" default="0"> The number of available input ports for this node. </member> - <member name="xfade_time" type="float" setter="set_cross_fade_time" getter="get_cross_fade_time" default="0.0"> + <member name="xfade_curve" type="Curve" setter="set_xfade_curve" getter="get_xfade_curve"> + </member> + <member name="xfade_time" type="float" setter="set_xfade_time" getter="get_xfade_time" default="0.0"> Cross-fading time (in seconds) between each animation connected to the inputs. </member> </members> diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index d2425313f7..fcdf59e36e 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -398,6 +398,7 @@ </member> <member name="uv1_triplanar_sharpness" type="float" setter="set_uv1_triplanar_blend_sharpness" getter="get_uv1_triplanar_blend_sharpness" default="1.0"> A lower number blends the texture more softly while a higher number blends the texture more sharply. + [b]Note:[/b] [member uv1_triplanar_sharpness] is clamped between [code]0.0[/code] and [code]150.0[/code] (inclusive) as values outside that range can look broken depending on the mesh. </member> <member name="uv1_world_triplanar" type="bool" setter="set_flag" getter="get_flag" default="false"> If [code]true[/code], triplanar mapping for [code]UV[/code] is calculated in world space rather than object local space. See also [member uv1_triplanar]. @@ -413,6 +414,7 @@ </member> <member name="uv2_triplanar_sharpness" type="float" setter="set_uv2_triplanar_blend_sharpness" getter="get_uv2_triplanar_blend_sharpness" default="1.0"> A lower number blends the texture more softly while a higher number blends the texture more sharply. + [b]Note:[/b] [member uv2_triplanar_sharpness] is clamped between [code]0.0[/code] and [code]150.0[/code] (inclusive) as values outside that range can look broken depending on the mesh. </member> <member name="uv2_world_triplanar" type="bool" setter="set_flag" getter="get_flag" default="false"> If [code]true[/code], triplanar mapping for [code]UV2[/code] is calculated in world space rather than object local space. See also [member uv2_triplanar]. @@ -496,10 +498,10 @@ The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps. Use this for most cases as mipmaps are important to smooth out pixels that are far from the camera. </constant> <constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="4" enum="TextureFilter"> - The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. + The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level]. </constant> <constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="TextureFilter"> - The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. + The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level]. </constant> <constant name="TEXTURE_FILTER_MAX" value="6" enum="TextureFilter"> Represents the size of the [enum TextureFilter] enum. diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index 8aa6278296..d62f704528 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -87,12 +87,6 @@ Consider using the [method get_rotation_quaternion] method instead, which returns a [Quaternion] quaternion instead of Euler angles. </description> </method> - <method name="get_orthogonal_index" qualifiers="const"> - <return type="int" /> - <description> - This function considers a discretization of rotations into 24 points on unit sphere, lying along the vectors (x,y,z) with each component being either -1, 0, or 1, and returns the index of the point best representing the orientation of the object. It is mainly used by the [GridMap] editor. For further details, refer to the Godot source code. - </description> - </method> <method name="get_rotation_quaternion" qualifiers="const"> <return type="Quaternion" /> <description> diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml index 1cd9ca0afb..e78cdfc951 100644 --- a/doc/classes/Button.xml +++ b/doc/classes/Button.xml @@ -114,7 +114,7 @@ Icon modulate [Color] used when the [Button] is being pressed. </theme_item> <theme_item name="h_separation" data_type="constant" type="int" default="2"> - The horizontal space between [Button]'s icon and text. + The horizontal space between [Button]'s icon and text. Negative values will be treated as [code]0[/code] when used. </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index a230806c08..fe1fe498d1 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -603,11 +603,11 @@ The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps. Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels. </constant> <constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="TextureFilter"> - The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. + The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level]. [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] is usually more appropriate. </constant> <constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="6" enum="TextureFilter"> - The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. + The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level]. [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_LINEAR_WITH_MIPMAPS] is usually more appropriate. </constant> <constant name="TEXTURE_FILTER_MAX" value="7" enum="TextureFilter"> diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml index 6483faf763..d39b75ae52 100644 --- a/doc/classes/CheckBox.xml +++ b/doc/classes/CheckBox.xml @@ -39,7 +39,7 @@ The vertical offset used when rendering the check icons (in pixels). </theme_item> <theme_item name="h_separation" data_type="constant" type="int" default="4"> - The separation between the check icon and the text (in pixels). + The separation between the check icon and the text (in pixels). Negative values will be treated as [code]0[/code] when used. </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml index 51b0411f4e..f49da69926 100644 --- a/doc/classes/CheckButton.xml +++ b/doc/classes/CheckButton.xml @@ -39,7 +39,7 @@ The vertical offset used when rendering the toggle icons (in pixels). </theme_item> <theme_item name="h_separation" data_type="constant" type="int" default="4"> - The separation between the toggle icon and the text (in pixels). + The separation between the toggle icon and the text (in pixels). Negative values will be treated as [code]0[/code] when used. </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml index 4353d97597..832f47e2bb 100644 --- a/doc/classes/CollisionObject2D.xml +++ b/doc/classes/CollisionObject2D.xml @@ -206,6 +206,9 @@ The physics layers this CollisionObject2D scans. Collision objects can scan one or more of 32 different layers. See also [member collision_layer]. [b]Note:[/b] Object A can detect a contact with object B only if object B is in any of the layers that object A scans. 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="collision_priority" type="float" setter="set_collision_priority" getter="get_collision_priority" default="1.0"> + The priority used to solve colliding when occurring penetration. The higher the priority is, the lower the penetration into the object will be. This can for example be used to prevent the player from breaking through the boundaries of a level. + </member> <member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="CollisionObject2D.DisableMode" default="0"> Defines the behavior in physics when [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED]. See [enum DisableMode] for more details about the different modes. </member> diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml index f9e28824df..04ccf3fc62 100644 --- a/doc/classes/CollisionObject3D.xml +++ b/doc/classes/CollisionObject3D.xml @@ -177,6 +177,9 @@ The physics layers this CollisionObject3D [b]scans[/b]. Collision objects can scan one or more of 32 different layers. See also [member collision_layer]. [b]Note:[/b] Object A can detect a contact with object B only if object B is in any of the layers that object A scans. 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="collision_priority" type="float" setter="set_collision_priority" getter="get_collision_priority" default="1.0"> + The priority used to solve colliding when occurring penetration. The higher the priority is, the lower the penetration into the object will be. This can for example be used to prevent the player from breaking through the boundaries of a level. + </member> <member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="CollisionObject3D.DisableMode" default="0"> Defines the behavior in physics when [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED]. See [enum DisableMode] for more details about the different modes. </member> diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml index 1dd53e1394..beed364974 100644 --- a/doc/classes/EditorInterface.xml +++ b/doc/classes/EditorInterface.xml @@ -206,6 +206,13 @@ Reloads the scene at the given path. </description> </method> + <method name="restart_editor"> + <return type="void" /> + <param index="0" name="save" type="bool" default="true" /> + <description> + Restarts the editor. This closes the editor and then opens the same project. If [param save] is [code]true[/code], the project will be saved before restarting. + </description> + </method> <method name="save_scene"> <return type="int" enum="Error" /> <description> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 5a1037aebe..fdd3807b69 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -532,7 +532,7 @@ </description> </method> <method name="get_undo_redo"> - <return type="UndoRedo" /> + <return type="EditorUndoRedoManager" /> <description> Gets the undo/redo object. Most actions in the editor can be undoable, so use this object to make sure this happens when it's worth it. </description> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 652b834f98..033f63c5ce 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -856,7 +856,7 @@ </member> <member name="text_editor/theme/highlighting/function_color" type="Color" setter="" getter=""> The script editor's function call color. - [b]Note:[/b] When using the GDScript syntax highlighter, this is replaced by the function declaration color configured in the syntax theme for function declarations (e.g. [code]func _ready():[/code]). + [b]Note:[/b] When using the GDScript syntax highlighter, this is replaced by the function definition color configured in the syntax theme for function definitions (e.g. [code]func _ready():[/code]). </member> <member name="text_editor/theme/highlighting/keyword_color" type="Color" setter="" getter=""> The script editor's non-control flow keyword color (used for keywords like [code]var[/code], [code]func[/code], some built-in methods, ...). diff --git a/doc/classes/EditorUndoRedoManager.xml b/doc/classes/EditorUndoRedoManager.xml new file mode 100644 index 0000000000..1350e4487c --- /dev/null +++ b/doc/classes/EditorUndoRedoManager.xml @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="EditorUndoRedoManager" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Manages undo history of scenes opened in the editor. + </brief_description> + <description> + [EditorUndoRedoManager] is a manager for [UndoRedo] objects associated with edited scenes. Each scene has its own undo history and [EditorUndoRedoManager] ensures that each action performed in the editor gets associated with a proper scene. For actions not related to scenes ([ProjectSettings] edits, external resources, etc.), a separate global history is used. + The usage is mostly the same as [UndoRedo]. You create and commit actions and the manager automatically decides under-the-hood what scenes it belongs to. The scene is deduced based on the first operation in an action, using the object from the operation. The rules are as follows: + - If the object is a [Node], use the currently edited scene; + - If the object is a built-in resource, use the scene from its path; + - If the object is external resource or anything else, use global history. + This guessing can sometimes yield false results, so you can provide a custom context object when creating an action. + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_do_method" qualifiers="vararg"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <param index="1" name="method" type="StringName" /> + <description> + Register a method that will be called when the action is committed (i.e. the "do" action). + If this is the first operation, the [param object] will be used to deduce target undo history. + </description> + </method> + <method name="add_do_property"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <param index="1" name="property" type="StringName" /> + <param index="2" name="value" type="Variant" /> + <description> + Register a property value change for "do". + If this is the first operation, the [param object] will be used to deduce target undo history. + </description> + </method> + <method name="add_do_reference"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <description> + Register a reference for "do" that will be erased if the "do" history is lost. This is useful mostly for new nodes created for the "do" call. Do not use for resources. + </description> + </method> + <method name="add_undo_method" qualifiers="vararg"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <param index="1" name="method" type="StringName" /> + <description> + Register a method that will be called when the action is undone (i.e. the "undo" action). + If this is the first operation, the [param object] will be used to deduce target undo history. + </description> + </method> + <method name="add_undo_property"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <param index="1" name="property" type="StringName" /> + <param index="2" name="value" type="Variant" /> + <description> + Register a property value change for "undo". + If this is the first operation, the [param object] will be used to deduce target undo history. + </description> + </method> + <method name="add_undo_reference"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <description> + Register a reference for "undo" that will be erased if the "undo" history is lost. This is useful mostly for nodes removed with the "do" call (not the "undo" call!). + </description> + </method> + <method name="commit_action"> + <return type="void" /> + <param index="0" name="execute" type="bool" default="true" /> + <description> + Commit the action. If [param execute] is true (default), all "do" methods/properties are called/set when this function is called. + </description> + </method> + <method name="create_action"> + <return type="void" /> + <param index="0" name="name" type="String" /> + <param index="1" name="merge_mode" type="int" enum="UndoRedo.MergeMode" default="0" /> + <param index="2" name="custom_context" type="Object" default="null" /> + <description> + Create a new action. After this is called, do all your calls to [method add_do_method], [method add_undo_method], [method add_do_property], and [method add_undo_property], then commit the action with [method commit_action]. + The way actions are merged is dictated by the [param merge_mode] argument. See [enum UndoRedo.MergeMode] for details. + If [param custom_context] object is provided, it will be used for deducing target history (instead of using the first operation). + </description> + </method> + <method name="get_history_undo_redo" qualifiers="const"> + <return type="UndoRedo" /> + <param index="0" name="id" type="int" /> + <description> + Returns the [UndoRedo] object associated with the given history [param id]. + [param id] above [code]0[/code] are mapped to the opened scene tabs (but it doesn't match their order). [param id] of [code]0[/code] or lower have special meaning (see [enum SpecialHistory]). + Best used with [method get_object_history_id]. This method is only provided in case you need some more advanced methods of [UndoRedo] (but keep in mind that directly operating on the [UndoRedo] object might affect editor's stability). + </description> + </method> + <method name="get_object_history_id" qualifiers="const"> + <return type="int" /> + <param index="0" name="object" type="Object" /> + <description> + Returns the history ID deduced from the given [param object]. It can be used with [method get_history_undo_redo]. + </description> + </method> + <method name="is_committing_action" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if the [EditorUndoRedoManager] is currently committing the action, i.e. running its "do" method or property change (see [method commit_action]). + </description> + </method> + </methods> + <constants> + <constant name="GLOBAL_HISTORY" value="0" enum="SpecialHistory"> + Global history not associated with any scene, but with external resources etc. + </constant> + <constant name="INVALID_HISTORY" value="-99" enum="SpecialHistory"> + Invalid "null" history. It's a special value, not associated with any object. + </constant> + </constants> +</class> diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index 49ebb55a52..46e46cc164 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -10,8 +10,7 @@ [b]Example[/b] [codeblock] var data_to_send = ["a", "b", "c"] - var json = JSON.new() - var json_string = json.stringify(data_to_send) + var json_string = JSON.stringify(data_to_send) # Save data # ... # Retrieve data @@ -25,6 +24,10 @@ else: print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line()) [/codeblock] + Alternatively, you can parse string using the static [method parse_string] method, but it doesn't allow to handle errors. + [codeblock] + var data = JSON.parse_string(json_string) # Returns null if parsing failed. + [/codeblock] </description> <tutorials> </tutorials> @@ -54,9 +57,17 @@ <description> Attempts to parse the [param json_string] provided. Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [method get_data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure. + Non-static variant of [method parse_string], if you want custom error handling. + </description> + </method> + <method name="parse_string" qualifiers="static"> + <return type="Variant" /> + <param index="0" name="json_string" type="String" /> + <description> + Attempts to parse the [param json_string] provided and returns the parsed data. Returns [code]null[/code] if parse failed. </description> </method> - <method name="stringify"> + <method name="stringify" qualifiers="static"> <return type="String" /> <param index="0" name="data" type="Variant" /> <param index="1" name="indent" type="String" default="""" /> diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml index 8baa724292..1f38510e83 100644 --- a/doc/classes/MenuButton.xml +++ b/doc/classes/MenuButton.xml @@ -65,7 +65,7 @@ Text [Color] used when the [MenuButton] is being pressed. </theme_item> <theme_item name="h_separation" data_type="constant" type="int" default="3"> - The horizontal space between [MenuButton]'s icon and text. + The horizontal space between [MenuButton]'s icon and text. Negative values will be treated as [code]0[/code] when used. </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml index a552a2c16c..f10c096c1b 100644 --- a/doc/classes/OptionButton.xml +++ b/doc/classes/OptionButton.xml @@ -246,7 +246,7 @@ The horizontal space between the arrow icon and the right edge of the button. </theme_item> <theme_item name="h_separation" data_type="constant" type="int" default="2"> - The horizontal space between [OptionButton]'s icon and text. + The horizontal space between [OptionButton]'s icon and text. Negative values will be treated as [code]0[/code] when used. </theme_item> <theme_item name="modulate_arrow" data_type="constant" type="int" default="0"> If different than [code]0[/code], the arrow icon will be modulated to the font color. diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml index 920b56c8c6..7ba52c40c6 100644 --- a/doc/classes/PhysicsServer2D.xml +++ b/doc/classes/PhysicsServer2D.xml @@ -358,6 +358,13 @@ Returns the physics layer or layers a body can collide with. </description> </method> + <method name="body_get_collision_priority" qualifiers="const"> + <return type="float" /> + <param index="0" name="body" type="RID" /> + <description> + Returns the body's collision priority. + </description> + </method> <method name="body_get_constant_force" qualifiers="const"> <return type="Vector2" /> <param index="0" name="body" type="RID" /> @@ -509,6 +516,14 @@ Sets the physics layer or layers a body can collide with. </description> </method> + <method name="body_set_collision_priority"> + <return type="void" /> + <param index="0" name="body" type="RID" /> + <param index="1" name="priority" type="float" /> + <description> + Sets the body's collision priority. + </description> + </method> <method name="body_set_constant_force"> <return type="void" /> <param index="0" name="body" type="RID" /> diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index b2456c69ec..d4796fe2cf 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -338,6 +338,13 @@ Returns the physics layer or layers a body can collide with. </description> </method> + <method name="body_get_collision_priority" qualifiers="const"> + <return type="float" /> + <param index="0" name="body" type="RID" /> + <description> + Returns the body's collision priority. + </description> + </method> <method name="body_get_constant_force" qualifiers="const"> <return type="Vector3" /> <param index="0" name="body" type="RID" /> @@ -505,6 +512,14 @@ Sets the physics layer or layers a body can collide with. </description> </method> + <method name="body_set_collision_priority"> + <return type="void" /> + <param index="0" name="body" type="RID" /> + <param index="1" name="priority" type="float" /> + <description> + Sets the body's collision priority. + </description> + </method> <method name="body_set_constant_force"> <return type="void" /> <param index="0" name="body" type="RID" /> diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml index 4188b04e4a..200065de54 100644 --- a/doc/classes/PhysicsServer3DExtension.xml +++ b/doc/classes/PhysicsServer3DExtension.xml @@ -286,6 +286,12 @@ <description> </description> </method> + <method name="_body_get_collision_priority" qualifiers="virtual const"> + <return type="float" /> + <param index="0" name="body" type="RID" /> + <description> + </description> + </method> <method name="_body_get_constant_force" qualifiers="virtual const"> <return type="Vector3" /> <param index="0" name="body" type="RID" /> @@ -430,6 +436,13 @@ <description> </description> </method> + <method name="_body_set_collision_priority" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="body" type="RID" /> + <param index="1" name="priority" type="float" /> + <description> + </description> + </method> <method name="_body_set_constant_force" qualifiers="virtual"> <return type="void" /> <param index="0" name="body" type="RID" /> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 9e2c3440c7..0cee71b613 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1948,6 +1948,7 @@ <member name="rendering/textures/default_filters/anisotropic_filtering_level" type="int" setter="" getter="" default="2"> Sets the maximum number of samples to take when using anisotropic filtering on textures (as a power of two). A higher sample count will result in sharper textures at oblique angles, but is more expensive to compute. A value of [code]0[/code] forcibly disables anisotropic filtering, even on materials where it is enabled. The anisotropic filtering level also affects decals and light projectors if they are configured to use anisotropic filtering. See [member rendering/textures/decals/filter] and [member rendering/textures/light_projectors/filter]. + [b]Note:[/b] For performance reasons, anisotropic filtering [i]is not enabled by default[/i] on 2D and 3D materials. For this setting to have an effect in 3D, set [member BaseMaterial3D.texture_filter] to [constant BaseMaterial3D.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC] or [constant BaseMaterial3D.TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC] on materials. For this setting to have an effect in 2D, set [member CanvasItem.texture_filter] to [constant CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC] or [constant CanvasItem.TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC] on the [CanvasItem] node displaying the texture (or in [CanvasTexture]). However, anisotropic filtering is rarely useful in 2D, so only enable it for textures in 2D if it makes a meaningful visual difference. [b]Note:[/b] This property is only read when the project starts. There is currently no way to change this setting at run-time. </member> <member name="rendering/textures/default_filters/texture_mipmap_bias" type="float" setter="" getter="" default="0.0"> diff --git a/doc/classes/Quaternion.xml b/doc/classes/Quaternion.xml index bc0ffbefe2..a521af5709 100644 --- a/doc/classes/Quaternion.xml +++ b/doc/classes/Quaternion.xml @@ -171,6 +171,20 @@ Performs a spherical cubic interpolation between quaternions [param pre_a], this vector, [param b], and [param post_b], by the given amount [param weight]. </description> </method> + <method name="spherical_cubic_interpolate_in_time" qualifiers="const"> + <return type="Quaternion" /> + <param index="0" name="b" type="Quaternion" /> + <param index="1" name="pre_a" type="Quaternion" /> + <param index="2" name="post_b" type="Quaternion" /> + <param index="3" name="weight" type="float" /> + <param index="4" name="b_t" type="float" /> + <param index="5" name="pre_a_t" type="float" /> + <param index="6" name="post_b_t" type="float" /> + <description> + Performs a spherical cubic interpolation between quaternions [param pre_a], this vector, [param b], and [param post_b], by the given amount [param weight]. + It can perform smoother interpolation than [code]spherical_cubic_interpolate()[/code] by the time values. + </description> + </method> </methods> <members> <member name="w" type="float" setter="" getter="" default="1.0"> diff --git a/doc/classes/RayCast2D.xml b/doc/classes/RayCast2D.xml index 4f4395a433..08627b0bd5 100644 --- a/doc/classes/RayCast2D.xml +++ b/doc/classes/RayCast2D.xml @@ -47,6 +47,12 @@ Returns the first object that the ray intersects, or [code]null[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]). </description> </method> + <method name="get_collider_rid" qualifiers="const"> + <return type="RID" /> + <description> + Returns the [RID] of the first object that the ray intersects, or an empty [RID] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]). + </description> + </method> <method name="get_collider_shape" qualifiers="const"> <return type="int" /> <description> diff --git a/doc/classes/RayCast3D.xml b/doc/classes/RayCast3D.xml index 7cc6fc55cd..1bcd6f1f31 100644 --- a/doc/classes/RayCast3D.xml +++ b/doc/classes/RayCast3D.xml @@ -48,6 +48,12 @@ Returns the first object that the ray intersects, or [code]null[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]). </description> </method> + <method name="get_collider_rid" qualifiers="const"> + <return type="RID" /> + <description> + Returns the [RID] of the first object that the ray intersects, or an empty [RID] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]). + </description> + </method> <method name="get_collider_shape" qualifiers="const"> <return type="int" /> <description> diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index 62142fce8b..1d4304bd99 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -481,7 +481,7 @@ If [code]true[/code], the label uses the custom font color. </member> <member name="percent_visible" type="float" setter="set_percent_visible" getter="get_percent_visible" default="1.0"> - The range of characters to display, as a [float] between 0.0 and 1.0. When assigned an out of range value, it's the same as assigning 1.0. + The range of characters to display, as a [float] between 0.0 and 1.0. [b]Note:[/b] Setting this property updates [member visible_characters] based on current [method get_total_character_count]. </member> <member name="progress_bar_delay" type="int" setter="set_progress_bar_delay" getter="get_progress_bar_delay" default="1000"> diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml index e332618e9f..69b9988641 100644 --- a/doc/classes/Skeleton3D.xml +++ b/doc/classes/Skeleton3D.xml @@ -281,6 +281,19 @@ [b]Note:[/b] This does not remove the child bone, but instead it removes the connection it has to the parent bone. </description> </method> + <method name="reset_bone_pose"> + <return type="void" /> + <param index="0" name="bone_idx" type="int" /> + <description> + Sets the bone pose to rest for [param bone_idx]. + </description> + </method> + <method name="reset_bone_poses"> + <return type="void" /> + <description> + Sets all bone poses to rests. + </description> + </method> <method name="set_bone_children"> <return type="void" /> <param index="0" name="bone_idx" type="int" /> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index 0191bdc0e1..5530759628 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -84,7 +84,7 @@ <return type="int" /> <param index="0" name="layer" type="int" /> <param index="1" name="coords" type="Vector2i" /> - <param index="2" name="use_proxies" type="bool" /> + <param index="2" name="use_proxies" type="bool" default="false" /> <description> Returns the tile alternative ID of the cell on layer [param layer] at [param coords]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. </description> @@ -93,7 +93,7 @@ <return type="Vector2i" /> <param index="0" name="layer" type="int" /> <param index="1" name="coords" type="Vector2i" /> - <param index="2" name="use_proxies" type="bool" /> + <param index="2" name="use_proxies" type="bool" default="false" /> <description> Returns the tile atlas coordinates ID of the cell on layer [param layer] at coordinates [param coords]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. </description> @@ -102,11 +102,21 @@ <return type="int" /> <param index="0" name="layer" type="int" /> <param index="1" name="coords" type="Vector2i" /> - <param index="2" name="use_proxies" type="bool" /> + <param index="2" name="use_proxies" type="bool" default="false" /> <description> Returns the tile source ID of the cell on layer [param layer] at coordinates [param coords]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. </description> </method> + <method name="get_cell_tile_data" qualifiers="const"> + <return type="TileData" /> + <param index="0" name="layer" type="int" /> + <param index="1" name="coords" type="Vector2i" /> + <param index="2" name="use_proxies" type="bool" default="false" /> + <description> + Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell is not a [TileSetAtlasSource]. + If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. + </description> + </method> <method name="get_coords_for_body_rid"> <return type="Vector2i" /> <param index="0" name="body" type="RID" /> diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index 904fc6d9e9..19fe2e2bfc 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -135,6 +135,20 @@ Cubically interpolates between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation. </description> </method> + <method name="cubic_interpolate_in_time" qualifiers="const"> + <return type="Vector2" /> + <param index="0" name="b" type="Vector2" /> + <param index="1" name="pre_a" type="Vector2" /> + <param index="2" name="post_b" type="Vector2" /> + <param index="3" name="weight" type="float" /> + <param index="4" name="b_t" type="float" /> + <param index="5" name="pre_a_t" type="float" /> + <param index="6" name="post_b_t" type="float" /> + <description> + Cubically interpolates between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation. + It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values. + </description> + </method> <method name="direction_to" qualifiers="const"> <return type="Vector2" /> <param index="0" name="to" type="Vector2" /> diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index 208e9935e3..150d53845c 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -109,6 +109,20 @@ Performs a cubic interpolation between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation. </description> </method> + <method name="cubic_interpolate_in_time" qualifiers="const"> + <return type="Vector3" /> + <param index="0" name="b" type="Vector3" /> + <param index="1" name="pre_a" type="Vector3" /> + <param index="2" name="post_b" type="Vector3" /> + <param index="3" name="weight" type="float" /> + <param index="4" name="b_t" type="float" /> + <param index="5" name="pre_a_t" type="float" /> + <param index="6" name="post_b_t" type="float" /> + <description> + Performs a cubic interpolation between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation. + It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values. + </description> + </method> <method name="direction_to" qualifiers="const"> <return type="Vector3" /> <param index="0" name="to" type="Vector3" /> diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml index 538cdd4138..b9f509cfe7 100644 --- a/doc/classes/Vector4.xml +++ b/doc/classes/Vector4.xml @@ -73,6 +73,20 @@ Performs a cubic interpolation between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation. </description> </method> + <method name="cubic_interpolate_in_time" qualifiers="const"> + <return type="Vector4" /> + <param index="0" name="b" type="Vector4" /> + <param index="1" name="pre_a" type="Vector4" /> + <param index="2" name="post_b" type="Vector4" /> + <param index="3" name="weight" type="float" /> + <param index="4" name="b_t" type="float" /> + <param index="5" name="pre_a_t" type="float" /> + <param index="6" name="post_b_t" type="float" /> + <description> + Performs a cubic interpolation between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation. + It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values. + </description> + </method> <method name="direction_to" qualifiers="const"> <return type="Vector4" /> <param index="0" name="to" type="Vector4" /> diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 84daf839e9..c7fdd6ebd8 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -35,8 +35,8 @@ USE_RADIANCE_MAP = true /* from RenderingServer: ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit) -ARRAY_NORMAL = 1, // A2B10G10R10, A is ignored. -ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal. +ARRAY_NORMAL = 1, // RG16 octahedral compression +ARRAY_TANGENT = 2, // RG16 octahedral compression, sign stored in sign of G ARRAY_COLOR = 3, // RGBA8 ARRAY_TEX_UV = 4, // RG32F ARRAY_TEX_UV2 = 5, // RG32F @@ -54,11 +54,11 @@ layout(location = 0) in highp vec3 vertex_attrib; /* clang-format on */ #ifdef NORMAL_USED -layout(location = 1) in vec3 normal_attrib; +layout(location = 1) in vec2 normal_attrib; #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) -layout(location = 2) in vec4 tangent_attrib; +layout(location = 2) in vec2 tangent_attrib; #endif #if defined(COLOR_USED) @@ -97,6 +97,13 @@ layout(location = 10) in uvec4 bone_attrib; layout(location = 11) in vec4 weight_attrib; #endif +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; +} + #ifdef USE_INSTANCING layout(location = 12) in highp vec4 instance_xform0; layout(location = 13) in highp vec4 instance_xform1; @@ -209,13 +216,14 @@ void main() { #endif #ifdef NORMAL_USED - vec3 normal = normal_attrib * 2.0 - 1.0; + vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0); #endif highp mat3 model_normal_matrix = mat3(model_matrix); #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0; - float binormalf = tangent_attrib.a * 2.0 - 1.0; + vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0; + vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); + float binormalf = sign(signed_tangent_attrib.y); vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index 38de0220e3..ddf94af5b8 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -124,11 +124,11 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) } break; case RS::ARRAY_NORMAL: { - stride += sizeof(int32_t); + stride += sizeof(uint16_t) * 2; } break; case RS::ARRAY_TANGENT: { - stride += sizeof(int32_t); + stride += sizeof(uint16_t) * 2; } break; case RS::ARRAY_COLOR: { @@ -604,17 +604,16 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V } break; case RS::ARRAY_NORMAL: { attribs[i].offset = vertex_stride; - // Will need to change to accommodate octahedral compression - attribs[i].size = 4; - attribs[i].type = GL_UNSIGNED_INT_2_10_10_10_REV; - vertex_stride += sizeof(float); + attribs[i].size = 2; + attribs[i].type = GL_UNSIGNED_SHORT; + vertex_stride += sizeof(uint16_t) * 2; attribs[i].normalized = GL_TRUE; } break; case RS::ARRAY_TANGENT: { attribs[i].offset = vertex_stride; - attribs[i].size = 4; - attribs[i].type = GL_UNSIGNED_INT_2_10_10_10_REV; - vertex_stride += sizeof(float); + attribs[i].size = 2; + attribs[i].type = GL_UNSIGNED_SHORT; + vertex_stride += sizeof(uint16_t) * 2; attribs[i].normalized = GL_TRUE; } break; case RS::ARRAY_COLOR: { diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index e10ed7e976..11e46152ef 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/view_panner.h" #include "scene/resources/text_line.h" @@ -649,7 +650,7 @@ Size2 AnimationBezierTrackEdit::get_minimum_size() const { return Vector2(1, 1); } -void AnimationBezierTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) { +void AnimationBezierTrackEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { undo_redo = p_undo_redo; } diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h index 070a6589ad..3e94b4fa84 100644 --- a/editor/animation_bezier_editor.h +++ b/editor/animation_bezier_editor.h @@ -34,6 +34,7 @@ #include "animation_track_editor.h" #include "core/templates/rb_set.h" +class EditorUndoRedoManager; class ViewPanner; class AnimationBezierTrackEdit : public Control { @@ -48,7 +49,7 @@ class AnimationBezierTrackEdit : public Control { }; AnimationTimelineEdit *timeline = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Node *root = nullptr; Control *play_position = nullptr; //separate control used to draw so updates for only position changed are much faster float play_position_pos = 0; @@ -180,7 +181,7 @@ public: void set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only); virtual Size2 get_minimum_size() const override; - void set_undo_redo(UndoRedo *p_undo_redo); + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_timeline(AnimationTimelineEdit *p_timeline); void set_editor(AnimationTrackEditor *p_editor); void set_root(Node *p_root); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 0db82551cb..3df3a3b76a 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -35,6 +35,7 @@ #include "editor/animation_bezier_editor.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "scene/animation/animation_player.h" #include "scene/gui/separator.h" @@ -680,7 +681,7 @@ public: } } - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Ref<Animation> animation; int track = -1; float key_ofs = 0; @@ -1374,7 +1375,7 @@ public: bool use_fps = false; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void notify_change() { notify_property_list_changed(); @@ -1708,7 +1709,7 @@ Size2 AnimationTimelineEdit::get_minimum_size() const { return ms; } -void AnimationTimelineEdit::set_undo_redo(UndoRedo *p_undo_redo) { +void AnimationTimelineEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { undo_redo = p_undo_redo; } @@ -2114,11 +2115,11 @@ void AnimationTrackEdit::_notification(int p_what) { get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")), get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), }; - - Ref<Texture2D> interp_icon[3] = { + Ref<Texture2D> interp_icon[4] = { get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), - get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")) + get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), + get_theme_icon(SNAME("InterpCubicInTime"), SNAME("EditorIcons")) }; Ref<Texture2D> cont_icon[4] = { get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), @@ -2507,10 +2508,14 @@ Size2 AnimationTrackEdit::get_minimum_size() const { return Vector2(1, max_h + separation); } -void AnimationTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) { +void AnimationTrackEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { undo_redo = p_undo_redo; } +Ref<EditorUndoRedoManager> AnimationTrackEdit::get_undo_redo() const { + return undo_redo; +} + void AnimationTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) { timeline = p_timeline; timeline->set_track_edit(this); @@ -2831,6 +2836,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { menu->add_icon_item(get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST); menu->add_icon_item(get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), TTR("Linear"), MENU_INTERPOLATION_LINEAR); menu->add_icon_item(get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), TTR("Cubic"), MENU_INTERPOLATION_CUBIC); + menu->add_icon_item(get_theme_icon(SNAME("InterpCubicInTime"), SNAME("EditorIcons")), TTR("CubicInTime"), MENU_INTERPOLATION_CUBIC_IN_TIME); menu->reset_size(); Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height); @@ -3171,7 +3177,8 @@ void AnimationTrackEdit::_menu_selected(int p_index) { } break; case MENU_INTERPOLATION_NEAREST: case MENU_INTERPOLATION_LINEAR: - case MENU_INTERPOLATION_CUBIC: { + case MENU_INTERPOLATION_CUBIC: + case MENU_INTERPOLATION_CUBIC_IN_TIME: { Animation::InterpolationType interp_mode = Animation::InterpolationType(p_index - MENU_INTERPOLATION_NEAREST); undo_redo->create_action(TTR("Change Animation Interpolation Mode")); undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track, interp_mode); @@ -6061,9 +6068,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } break; case EDIT_OPTIMIZE_ANIMATION_CONFIRM: { - animation->optimize(optimize_linear_error->get_value(), optimize_angular_error->get_value(), optimize_max_angle->get_value()); + animation->optimize(optimize_velocity_error->get_value(), optimize_angular_error->get_value(), optimize_precision_error->get_value()); _update_tracks(); - undo_redo->clear_history(); + undo_redo->clear_history(true, undo_redo->get_history_for_object(animation.ptr()).id); } break; case EDIT_CLEAN_UP_ANIMATION: { @@ -6131,7 +6138,7 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) { } } - undo_redo->clear_history(); + undo_redo->clear_history(true, undo_redo->get_history_for_object(animation.ptr()).id); _update_tracks(); } @@ -6301,7 +6308,7 @@ void AnimationTrackEditor::_pick_track_filter_input(const Ref<InputEvent> &p_ie) } AnimationTrackEditor::AnimationTrackEditor() { - undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo = EditorNode::get_undo_redo(); main_panel = memnew(PanelContainer); main_panel->set_focus_mode(FOCUS_ALL); // Allow panel to have focus so that shortcuts work as expected. @@ -6536,25 +6543,24 @@ AnimationTrackEditor::AnimationTrackEditor() { VBoxContainer *optimize_vb = memnew(VBoxContainer); optimize_dialog->add_child(optimize_vb); - optimize_linear_error = memnew(SpinBox); - optimize_linear_error->set_max(1.0); - optimize_linear_error->set_min(0.001); - optimize_linear_error->set_step(0.001); - optimize_linear_error->set_value(0.05); - optimize_vb->add_margin_child(TTR("Max. Linear Error:"), optimize_linear_error); + optimize_velocity_error = memnew(SpinBox); + optimize_velocity_error->set_max(1.0); + optimize_velocity_error->set_min(0.001); + optimize_velocity_error->set_step(0.001); + optimize_velocity_error->set_value(0.01); + optimize_vb->add_margin_child(TTR("Max. Velocity Error:"), optimize_velocity_error); optimize_angular_error = memnew(SpinBox); optimize_angular_error->set_max(1.0); optimize_angular_error->set_min(0.001); optimize_angular_error->set_step(0.001); optimize_angular_error->set_value(0.01); - optimize_vb->add_margin_child(TTR("Max. Angular Error:"), optimize_angular_error); - optimize_max_angle = memnew(SpinBox); - optimize_vb->add_margin_child(TTR("Max Optimizable Angle:"), optimize_max_angle); - optimize_max_angle->set_max(360.0); - optimize_max_angle->set_min(0.0); - optimize_max_angle->set_step(0.1); - optimize_max_angle->set_value(22); + optimize_precision_error = memnew(SpinBox); + optimize_precision_error->set_max(6); + optimize_precision_error->set_min(1); + optimize_precision_error->set_step(1); + optimize_precision_error->set_value(3); + optimize_vb->add_margin_child(TTR("Max. Precision Error:"), optimize_precision_error); optimize_dialog->set_ok_button_text(TTR("Optimize")); optimize_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_OPTIMIZE_ANIMATION_CONFIRM)); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index b0553c54a5..806d3ffb14 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -78,7 +78,7 @@ class AnimationTimelineEdit : public Range { void _anim_loop_pressed(); void _play_position_draw(); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Rect2 hsize_rect; bool editing = false; @@ -112,7 +112,7 @@ public: void set_track_edit(AnimationTrackEdit *p_track_edit); void set_zoom(Range *p_zoom); Range *get_zoom() const { return zoom; } - void set_undo_redo(UndoRedo *p_undo_redo); + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_play_position(float p_pos); float get_play_position() const; @@ -143,6 +143,7 @@ class AnimationTrackEdit : public Control { MENU_INTERPOLATION_NEAREST, MENU_INTERPOLATION_LINEAR, MENU_INTERPOLATION_CUBIC, + MENU_INTERPOLATION_CUBIC_IN_TIME, MENU_LOOP_WRAP, MENU_LOOP_CLAMP, MENU_KEY_INSERT, @@ -152,7 +153,7 @@ class AnimationTrackEdit : public Control { }; AnimationTimelineEdit *timeline = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Popup *path_popup = nullptr; LineEdit *path = nullptr; Node *root = nullptr; @@ -233,12 +234,12 @@ public: Ref<Animation> get_animation() const; AnimationTimelineEdit *get_timeline() const { return timeline; } AnimationTrackEditor *get_editor() const { return editor; } - UndoRedo *get_undo_redo() const { return undo_redo; } + Ref<EditorUndoRedoManager> get_undo_redo() const; NodePath get_path() const; void set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only); virtual Size2 get_minimum_size() const override; - void set_undo_redo(UndoRedo *p_undo_redo); + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_timeline(AnimationTimelineEdit *p_timeline); void set_editor(AnimationTrackEditor *p_editor); void set_root(Node *p_root); @@ -333,7 +334,7 @@ class AnimationTrackEditor : public VBoxContainer { void _animation_track_remove_request(int p_track, Ref<Animation> p_from_animation); void _track_grab_focus(int p_track); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _update_scroll(double); void _update_step(double p_new_step); @@ -451,9 +452,9 @@ class AnimationTrackEditor : public VBoxContainer { ////////////// edit menu stuff ConfirmationDialog *optimize_dialog = nullptr; - SpinBox *optimize_linear_error = nullptr; + SpinBox *optimize_velocity_error = nullptr; SpinBox *optimize_angular_error = nullptr; - SpinBox *optimize_max_angle = nullptr; + SpinBox *optimize_precision_error = nullptr; ConfirmationDialog *cleanup_dialog = nullptr; CheckBox *cleanup_keys = nullptr; @@ -486,9 +487,9 @@ class AnimationTrackEditor : public VBoxContainer { NodePath full_path; NodePath base_path; Animation::TrackType track_type = Animation::TYPE_ANIMATION; - Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC; + Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC_IN_TIME; Animation::UpdateMode update_mode = Animation::UPDATE_CAPTURE; - Animation::LoopMode loop_mode = Animation::LOOP_LINEAR; + Animation::LoopMode loop_mode = Animation::LOOP_PINGPONG; bool loop_wrap = false; bool enabled = false; diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index cd40b53919..ab64aaa24d 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -33,6 +33,7 @@ #include "editor/audio_stream_preview.h" #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/2d/animated_sprite_2d.h" #include "scene/2d/sprite_2d.h" #include "scene/3d/sprite_3d.h" diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp index 58527ee4d1..ab0e801c88 100644 --- a/editor/array_property_edit.cpp +++ b/editor/array_property_edit.cpp @@ -32,6 +32,7 @@ #include "core/io/marshalls.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #define ITEMS_PER_PAGE 100 @@ -87,7 +88,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { return true; } - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Resize Array")); ur->add_do_method(this, "_set_size", newsize); ur->add_undo_method(this, "_set_size", size); @@ -134,7 +135,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { Callable::CallError ce; Variant new_value; Variant::construct(Variant::Type(type), new_value, nullptr, 0, ce); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Array Value Type")); ur->add_do_method(this, "_set_value", idx, new_value); @@ -150,7 +151,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { Variant arr = get_array(); Variant value = arr.get(idx); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Array Value")); ur->add_do_method(this, "_set_value", idx, p_value); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 6fdd9563fb..6c86b341da 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -34,6 +34,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "plugins/script_editor_plugin.h" @@ -924,6 +925,10 @@ void ConnectionsDock::_bind_methods() { ClassDB::bind_method("update_tree", &ConnectionsDock::update_tree); } +void ConnectionsDock::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void ConnectionsDock::set_node(Node *p_node) { selected_node = p_node; update_tree(); diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index d141d1a880..7e7192019b 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -31,7 +31,6 @@ #ifndef CONNECTIONS_DIALOG_H #define CONNECTIONS_DIALOG_H -#include "core/object/undo_redo.h" #include "editor/editor_inspector.h" #include "editor/scene_tree_editor.h" #include "scene/gui/button.h" @@ -48,6 +47,7 @@ #include "scene/gui/tree.h" class ConnectDialogBinds; +class EditorUndoRedoManager; class ConnectDialog : public ConfirmationDialog { GDCLASS(ConnectDialog, ConfirmationDialog); @@ -194,7 +194,7 @@ class ConnectionsDock : public VBoxContainer { Button *connect_button = nullptr; PopupMenu *signal_menu = nullptr; PopupMenu *slot_menu = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; LineEdit *search_box = nullptr; HashMap<StringName, HashMap<StringName, String>> descr_cache; @@ -225,7 +225,7 @@ protected: static void _bind_methods(); public: - void set_undoredo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_node(Node *p_node); void update_tree(); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index e6168f4924..c84e8ec48f 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -38,7 +38,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" -void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const String &p_select_type) { +void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const String &p_select_type, const String &p_select_name) { _fill_type_list(); icon_fallback = search_options->has_theme_icon(base_type, SNAME("EditorIcons")) ? base_type : "Object"; @@ -57,7 +57,11 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const St _update_search(); if (p_replace_mode) { - set_title(vformat(TTR("Change %s Type"), base_type)); + if (!p_select_name.is_empty()) { + set_title(vformat(TTR("Convert %s from %s"), p_select_name, p_select_type)); + } else { + set_title(vformat(TTR("Convert %s"), p_select_type)); + } set_ok_button_text(TTR("Change")); } else { set_title(vformat(TTR("Create New %s"), base_type)); diff --git a/editor/create_dialog.h b/editor/create_dialog.h index 04094108ad..f7731d2726 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -120,7 +120,7 @@ public: void set_preferred_search_result_type(const String &p_preferred_type) { preferred_search_result_type = p_preferred_type; } String get_preferred_search_result_type() { return preferred_search_result_type; } - void popup_create(bool p_dont_clear, bool p_replace_mode = false, const String &p_select_type = "Node"); + void popup_create(bool p_dont_clear, bool p_replace_mode = false, const String &p_select_type = "Node", const String &p_select_name = ""); CreateDialog(); }; diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 472e53c0e8..9fd7fa578f 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -30,6 +30,7 @@ #include "editor_debugger_node.h" +#include "core/object/undo_redo.h" #include "editor/debugger/editor_debugger_tree.h" #include "editor/debugger/script_editor_debugger.h" #include "editor/editor_log.h" @@ -83,8 +84,6 @@ EditorDebuggerNode::EditorDebuggerNode() { inspect_edited_object_timeout = EDITOR_DEF("debugger/remote_inspect_refresh_interval", 0.2); EditorNode *editor = EditorNode::get_singleton(); - editor->get_undo_redo()->set_method_notify_callback(_method_changeds, this); - editor->get_undo_redo()->set_property_notify_callback(_property_changeds, this); editor->get_pause_button()->connect("pressed", callable_mp(this, &EditorDebuggerNode::_paused)); } @@ -181,6 +180,11 @@ void EditorDebuggerNode::_bind_methods() { ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::BOOL, "enabled"))); } +void EditorDebuggerNode::register_undo_redo(UndoRedo *p_undo_redo) { + p_undo_redo->set_method_notify_callback(_method_changeds, this); + p_undo_redo->set_property_notify_callback(_property_changeds, this); +} + EditorDebuggerRemoteObject *EditorDebuggerNode::get_inspected_remote_object() { return Object::cast_to<EditorDebuggerRemoteObject>(ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_current())); } diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h index 4c9ad49ac4..e79e60b180 100644 --- a/editor/debugger/editor_debugger_node.h +++ b/editor/debugger/editor_debugger_node.h @@ -41,6 +41,7 @@ class EditorDebuggerRemoteObject; class MenuButton; class ScriptEditorDebugger; class TabContainer; +class UndoRedo; class EditorDebuggerNode : public MarginContainer { GDCLASS(EditorDebuggerNode, MarginContainer); @@ -152,6 +153,7 @@ protected: public: static EditorDebuggerNode *get_singleton() { return singleton; } + void register_undo_redo(UndoRedo *p_undo_redo); ScriptEditorDebugger *get_current_debugger() const; ScriptEditorDebugger *get_default_debugger() const; diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index ac2e958c5b..1bee0513ca 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -1959,15 +1959,18 @@ ScriptEditorDebugger::ScriptEditorDebugger() { info_left->set_columns(2); misc->add_child(info_left); clicked_ctrl = memnew(LineEdit); + clicked_ctrl->set_editable(false); clicked_ctrl->set_h_size_flags(SIZE_EXPAND_FILL); info_left->add_child(memnew(Label(TTR("Clicked Control:")))); info_left->add_child(clicked_ctrl); clicked_ctrl_type = memnew(LineEdit); + clicked_ctrl_type->set_editable(false); info_left->add_child(memnew(Label(TTR("Clicked Control Type:")))); info_left->add_child(clicked_ctrl_type); scene_tree = memnew(SceneDebuggerTree); live_edit_root = memnew(LineEdit); + live_edit_root->set_editable(false); live_edit_root->set_h_size_flags(SIZE_EXPAND_FILL); { diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp index 630265e268..f16c5402ad 100644 --- a/editor/dictionary_property_edit.cpp +++ b/editor/dictionary_property_edit.cpp @@ -30,6 +30,7 @@ #include "dictionary_property_edit.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" void DictionaryPropertyEdit::_notif_change() { notify_property_list_changed(); @@ -118,7 +119,7 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val int index = pn.substr(0, slash).to_int(); if (type == "key" && index < keys.size()) { const Variant &key = keys[index]; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Dictionary Key")); ur->add_do_method(this, "_set_key", key, p_value); @@ -130,7 +131,7 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val const Variant &key = keys[index]; if (dict.has(key)) { Variant value = dict[key]; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Dictionary Value")); ur->add_do_method(this, "_set_value", key, p_value); diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index b6d7bbc45f..f1add65b7c 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -38,6 +38,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "filesystem_dock.h" #include "scene/resources/font.h" #include "servers/audio_server.h" @@ -280,7 +281,7 @@ void EditorAudioBus::_name_changed(const String &p_new_name) { } updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); StringName current = AudioServer::get_singleton()->get_bus_name(get_index()); ur->create_action(TTR("Rename Audio Bus")); @@ -321,7 +322,7 @@ void EditorAudioBus::_volume_changed(float p_normalized) { slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db))); } - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Audio Bus Volume"), UndoRedo::MERGE_ENDS); ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), p_db); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), AudioServer::get_singleton()->get_bus_volume_db(get_index())); @@ -415,7 +416,7 @@ void EditorAudioBus::_hide_value_preview() { void EditorAudioBus::_solo_toggled() { updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Toggle Audio Bus Solo")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), solo->is_pressed()); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), AudioServer::get_singleton()->is_bus_solo(get_index())); @@ -429,7 +430,7 @@ void EditorAudioBus::_solo_toggled() { void EditorAudioBus::_mute_toggled() { updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Toggle Audio Bus Mute")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), mute->is_pressed()); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), AudioServer::get_singleton()->is_bus_mute(get_index())); @@ -443,7 +444,7 @@ void EditorAudioBus::_mute_toggled() { void EditorAudioBus::_bypass_toggled() { updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Toggle Audio Bus Bypass Effects")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), bypass->is_pressed()); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), AudioServer::get_singleton()->is_bus_bypassing_effects(get_index())); @@ -457,7 +458,7 @@ void EditorAudioBus::_bypass_toggled() { void EditorAudioBus::_send_selected(int p_which) { updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Select Audio Bus Send")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", get_index(), send->get_item_text(p_which)); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", get_index(), AudioServer::get_singleton()->get_bus_send(get_index())); @@ -507,7 +508,7 @@ void EditorAudioBus::_effect_edited() { int index = effect->get_metadata(0); updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Select Audio Bus Send")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, effect->is_checked(0)); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index)); @@ -534,7 +535,7 @@ void EditorAudioBus::_effect_add(int p_which) { afxr->set_name(effect_options->get_item_text(p_which)); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Add Audio Bus Effect")); ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), afxr, -1); ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect_count(get_index())); @@ -688,7 +689,7 @@ void EditorAudioBus::drop_data_fw(const Point2 &p_point, const Variant &p_data, bool enabled = AudioServer::get_singleton()->is_bus_effect_enabled(bus, effect); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Move Bus Effect")); ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", bus, effect); ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(bus, effect), paste_at); @@ -730,7 +731,7 @@ void EditorAudioBus::_delete_effect_pressed(int p_option) { int index = item->get_metadata(0); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Delete Bus Effect")); ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), index); ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(get_index(), index), index); @@ -1063,7 +1064,7 @@ void EditorAudioBuses::_notification(int p_what) { } void EditorAudioBuses::_add_bus() { - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Add Audio Bus")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count() + 1); @@ -1095,7 +1096,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) { return; } - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Delete Audio Bus")); ur->add_do_method(AudioServer::get_singleton(), "remove_bus", index); @@ -1117,7 +1118,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) { void EditorAudioBuses::_duplicate_bus(int p_which) { int add_at_pos = p_which + 1; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Duplicate Audio Bus")); ur->add_do_method(AudioServer::get_singleton(), "add_bus", add_at_pos); ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", add_at_pos, AudioServer::get_singleton()->get_bus_name(p_which) + " Copy"); @@ -1140,7 +1141,7 @@ void EditorAudioBuses::_reset_bus_volume(Object *p_which) { EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which); int index = bus->get_index(); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Reset Bus Volume")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", index, 0.f); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index)); @@ -1160,7 +1161,7 @@ void EditorAudioBuses::_request_drop_end() { } void EditorAudioBuses::_drop_at_index(int p_bus, int p_index) { - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Move Audio Bus")); ur->add_do_method(AudioServer::get_singleton(), "move_bus", p_bus, p_index); @@ -1219,7 +1220,7 @@ void EditorAudioBuses::_load_default_layout() { file->set_text(String(TTR("Layout:")) + " " + layout_path.get_file()); AudioServer::get_singleton()->set_bus_layout(state); _update_buses(); - EditorNode::get_singleton()->get_undo_redo()->clear_history(); + EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); call_deferred(SNAME("_select_layout")); } @@ -1235,7 +1236,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) { file->set_text(String(TTR("Layout:")) + " " + p_string.get_file()); AudioServer::get_singleton()->set_bus_layout(state); _update_buses(); - EditorNode::get_singleton()->get_undo_redo()->clear_history(); + EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); call_deferred(SNAME("_select_layout")); } else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) { @@ -1255,7 +1256,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) { edited_path = p_string; file->set_text(String(TTR("Layout:")) + " " + p_string.get_file()); _update_buses(); - EditorNode::get_singleton()->get_undo_redo()->clear_history(); + EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); call_deferred(SNAME("_select_layout")); } } @@ -1354,7 +1355,7 @@ void EditorAudioBuses::open_layout(const String &p_path) { file->set_text(p_path.get_file()); AudioServer::get_singleton()->set_bus_layout(state); _update_buses(); - EditorNode::get_singleton()->get_undo_redo()->clear_history(); + EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); call_deferred(SNAME("_select_layout")); } diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index ee4955d0a0..120ac5b984 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -35,6 +35,7 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/filesystem_dock.h" #include "project_settings_editor.h" #include "scene/main/window.h" @@ -193,7 +194,7 @@ void EditorAutoloadSettings::_autoload_edited() { TreeItem *ti = tree->get_edited(); int column = tree->get_edited_column(); - UndoRedo *undo_redo = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); if (column == 0) { String name = ti->get_text(0); @@ -288,7 +289,7 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu String name = "autoload/" + ti->get_text(0); - UndoRedo *undo_redo = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); switch (p_button) { case BUTTON_OPEN: { @@ -713,7 +714,7 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant & orders.sort(); - UndoRedo *undo_redo = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Rearrange Autoloads")); @@ -757,7 +758,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_ name = "autoload/" + name; - UndoRedo *undo_redo = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Add Autoload")); // Singleton autoloads are represented with a leading "*" in their path. @@ -783,7 +784,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_ void EditorAutoloadSettings::autoload_remove(const String &p_name) { String name = "autoload/" + p_name; - UndoRedo *undo_redo = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); int order = ProjectSettings::get_singleton()->get_order(name); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 2d4945db14..64bdac1e77 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -35,6 +35,7 @@ #include "core/io/resource_loader.h" #include "editor/editor_node.h" #include "editor/editor_plugin.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/script_editor_plugin.h" #include "scene/resources/packed_scene.h" @@ -364,13 +365,13 @@ void EditorData::restore_editor_global_states() { void EditorData::paste_object_params(Object *p_object) { ERR_FAIL_NULL(p_object); - undo_redo.create_action(TTR("Paste Params")); + undo_redo_manager->create_action(TTR("Paste Params")); for (const PropertyData &E : clipboard) { String name = E.name; - undo_redo.add_do_property(p_object, name, E.value); - undo_redo.add_undo_property(p_object, name, p_object->get(name)); + undo_redo_manager->add_do_property(p_object, name, E.value); + undo_redo_manager->add_undo_property(p_object, name, p_object->get(name)); } - undo_redo.commit_action(); + undo_redo_manager->commit_action(); } bool EditorData::call_build() { @@ -383,8 +384,49 @@ bool EditorData::call_build() { return result; } -UndoRedo &EditorData::get_undo_redo() { - return undo_redo; +void EditorData::set_scene_as_saved(int p_idx) { + if (p_idx == -1) { + p_idx = current_edited_scene; + } + ERR_FAIL_INDEX(p_idx, edited_scene.size()); + + get_undo_redo()->set_history_as_saved(edited_scene[p_idx].history_id); +} + +bool EditorData::is_scene_changed(int p_idx) { + if (p_idx == -1) { + p_idx = current_edited_scene; + } + ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), false); + + uint64_t current_scene_version = get_undo_redo()->get_or_create_history(edited_scene[p_idx].history_id).undo_redo->get_version(); + bool is_changed = edited_scene[p_idx].last_checked_version != current_scene_version; + edited_scene.write[p_idx].last_checked_version = current_scene_version; + return is_changed; +} + +int EditorData::get_scene_history_id_from_path(const String &p_path) const { + for (const EditedScene &E : edited_scene) { + if (E.path == p_path) { + return E.history_id; + } + } + return 0; +} + +int EditorData::get_current_edited_scene_history_id() const { + if (current_edited_scene != -1) { + return edited_scene[current_edited_scene].history_id; + } + return 0; +} + +int EditorData::get_scene_history_id(int p_idx) const { + return edited_scene[p_idx].history_id; +} + +Ref<EditorUndoRedoManager> &EditorData::get_undo_redo() { + return undo_redo_manager; } void EditorData::add_undo_redo_inspector_hook_callback(Callable p_callable) { @@ -415,12 +457,12 @@ Callable EditorData::get_move_array_element_function(const StringName &p_class) } void EditorData::remove_editor_plugin(EditorPlugin *p_plugin) { - p_plugin->undo_redo = nullptr; + p_plugin->undo_redo = Ref<EditorUndoRedoManager>(); editor_plugins.erase(p_plugin); } void EditorData::add_editor_plugin(EditorPlugin *p_plugin) { - p_plugin->undo_redo = &undo_redo; + p_plugin->undo_redo = undo_redo_manager; editor_plugins.push_back(p_plugin); } @@ -505,8 +547,8 @@ int EditorData::add_edited_scene(int p_at_pos) { es.path = String(); es.file_modified_time = 0; es.history_current = -1; - es.version = 0; es.live_edit_root = NodePath(String("/root")); + es.history_id = last_created_scene++; if (p_at_pos == edited_scene.size()) { edited_scene.push_back(es); @@ -547,6 +589,7 @@ void EditorData::remove_scene(int p_idx) { ScriptEditor::get_singleton()->close_builtin_scripts_from_scene(edited_scene[p_idx].path); } + undo_redo_manager->discard_history(edited_scene[p_idx].history_id); edited_scene.remove_at(p_idx); } @@ -679,26 +722,10 @@ Vector<EditorData::EditedScene> EditorData::get_edited_scenes() const { return out_edited_scenes_list; } -void EditorData::set_edited_scene_version(uint64_t version, int p_scene_idx) { - ERR_FAIL_INDEX(current_edited_scene, edited_scene.size()); - if (p_scene_idx < 0) { - edited_scene.write[current_edited_scene].version = version; - } else { - ERR_FAIL_INDEX(p_scene_idx, edited_scene.size()); - edited_scene.write[p_scene_idx].version = version; - } -} - -uint64_t EditorData::get_scene_version(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), 0); - return edited_scene[p_idx].version; -} - void EditorData::set_scene_modified_time(int p_idx, uint64_t p_time) { if (p_idx == -1) { p_idx = current_edited_scene; } - ERR_FAIL_INDEX(p_idx, edited_scene.size()); edited_scene.write[p_idx].file_modified_time = p_time; @@ -991,6 +1018,7 @@ void EditorData::script_class_load_icon_paths() { EditorData::EditorData() { current_edited_scene = -1; + undo_redo_manager.instantiate(); script_class_load_icon_paths(); } diff --git a/editor/editor_data.h b/editor/editor_data.h index 351c63f4b9..655a62a9ae 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -31,12 +31,12 @@ #ifndef EDITOR_DATA_H #define EDITOR_DATA_H -#include "core/object/undo_redo.h" #include "core/templates/list.h" #include "scene/resources/texture.h" class ConfigFile; class EditorPlugin; +class EditorUndoRedoManager; /** * Stores the history of objects which have been selected for editing in the Editor & the Inspector. @@ -118,8 +118,9 @@ public: Vector<EditorSelectionHistory::HistoryElement> history_stored; int history_current = 0; Dictionary custom_state; - uint64_t version = 0; NodePath live_edit_root; + int history_id = 0; + uint64_t last_checked_version = 0; }; private: @@ -132,12 +133,13 @@ private: HashMap<String, Vector<CustomType>> custom_types; List<PropertyData> clipboard; - UndoRedo undo_redo; + Ref<EditorUndoRedoManager> undo_redo_manager; Vector<Callable> undo_redo_callbacks; HashMap<StringName, Callable> move_element_functions; Vector<EditedScene> edited_scene; - int current_edited_scene; + int current_edited_scene = -1; + int last_created_scene = 1; bool _find_updated_instances(Node *p_root, Node *p_node, HashSet<String> &checked_paths); @@ -166,7 +168,7 @@ public: int get_editor_plugin_count() const; EditorPlugin *get_editor_plugin(int p_idx); - UndoRedo &get_undo_redo(); + Ref<EditorUndoRedoManager> &get_undo_redo(); void add_undo_redo_inspector_hook_callback(Callable p_callable); // Callbacks should have this signature: void (Object* undo_redo, Object *modified_object, String property, Variant new_value) void remove_undo_redo_inspector_hook_callback(Callable p_callable); const Vector<Callable> get_undo_redo_inspector_hook_callback(); @@ -200,7 +202,6 @@ public: void set_scene_path(int p_idx, const String &p_path); Ref<Script> get_scene_root_script(int p_idx) const; void set_edited_scene_version(uint64_t version, int p_scene_idx = -1); - uint64_t get_scene_version(int p_idx) const; void set_scene_modified_time(int p_idx, uint64_t p_time); uint64_t get_scene_modified_time(int p_idx) const; void clear_edited_scenes(); @@ -210,6 +211,13 @@ public: void move_edited_scene_to_index(int p_idx); bool call_build(); + void set_scene_as_saved(int p_idx); + bool is_scene_changed(int p_idx); + + int get_scene_history_id_from_path(const String &p_path) const; + int get_current_edited_scene_history_id() const; + int get_scene_history_id(int p_idx) const; + void set_plugin_window_layout(Ref<ConfigFile> p_layout); void get_plugin_window_layout(Ref<ConfigFile> p_layout); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 1a105c7fe8..bda2e283ef 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1192,11 +1192,6 @@ void EditorFileSystem::scan_changes() { void EditorFileSystem::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - call_deferred(SNAME("scan")); //this should happen after every editor node entered the tree - - } break; - case NOTIFICATION_EXIT_TREE: { Thread &active_thread = thread.is_started() ? thread : thread_sources; if (use_threads && active_thread.is_started()) { diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index e954f06f08..855f4b1366 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1701,7 +1701,7 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) { // Call the function. Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name()); if (move_function.is_valid()) { - Variant args[] = { (Object *)undo_redo, object, array_element_prefix, p_element_index, p_to_pos }; + Variant args[] = { undo_redo.ptr(), object, array_element_prefix, p_element_index, p_to_pos }; const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] }; Variant return_value; Callable::CallError call_error; @@ -1845,7 +1845,7 @@ void EditorInspectorArray::_clear_array() { // Call the function. Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name()); if (move_function.is_valid()) { - Variant args[] = { (Object *)undo_redo, object, array_element_prefix, i, -1 }; + Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 }; const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] }; Variant return_value; Callable::CallError call_error; @@ -1898,7 +1898,7 @@ void EditorInspectorArray::_resize_array(int p_size) { // Call the function. Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name()); if (move_function.is_valid()) { - Variant args[] = { (Object *)undo_redo, object, array_element_prefix, -1, -1 }; + Variant args[] = { undo_redo.ptr(), object, array_element_prefix, -1, -1 }; const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] }; Variant return_value; Callable::CallError call_error; @@ -1917,7 +1917,7 @@ void EditorInspectorArray::_resize_array(int p_size) { // Call the function. Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name()); if (move_function.is_valid()) { - Variant args[] = { (Object *)undo_redo, object, array_element_prefix, i, -1 }; + Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 }; const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] }; Variant return_value; Callable::CallError call_error; @@ -2240,7 +2240,7 @@ void EditorInspectorArray::_bind_methods() { ADD_SIGNAL(MethodInfo("page_change_request")); } -void EditorInspectorArray::set_undo_redo(UndoRedo *p_undo_redo) { +void EditorInspectorArray::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { undo_redo = p_undo_redo; } @@ -2502,7 +2502,7 @@ Button *EditorInspector::create_inspector_action_button(const String &p_text) { return button; } -void EditorInspector::set_undo_redo(UndoRedo *p_undo_redo) { +void EditorInspector::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { undo_redo = p_undo_redo; } @@ -3525,7 +3525,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo } } - if (!undo_redo || bool(object->call("_dont_undo_redo"))) { + if (!undo_redo.is_valid() || bool(object->call("_dont_undo_redo"))) { object->set(p_name, p_value); if (p_refresh_all) { _edit_request_change(object, ""); @@ -3568,7 +3568,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo } } - Variant v_undo_redo = (Object *)undo_redo; + Variant v_undo_redo = undo_redo; Variant v_object = object; Variant v_name = p_name; for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_undo_redo_inspector_hook_callback().size(); i++) { @@ -3744,7 +3744,7 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) { Node *node = Object::cast_to<Node>(object); ERR_FAIL_COND(!node); - if (undo_redo) { + if (undo_redo.is_valid()) { undo_redo->create_action(vformat(p_pinned ? TTR("Pinned %s") : TTR("Unpinned %s"), p_path)); undo_redo->add_do_method(node, "_set_property_pinned", p_path, p_pinned); undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned); @@ -4026,7 +4026,6 @@ void EditorInspector::_bind_methods() { EditorInspector::EditorInspector() { object = nullptr; - undo_redo = nullptr; main_vbox = memnew(VBoxContainer); main_vbox->set_h_size_flags(SIZE_EXPAND_FILL); main_vbox->add_theme_constant_override("separation", 0); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index baba9ec1f4..905e13b3a9 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -31,6 +31,7 @@ #ifndef EDITOR_INSPECTOR_H #define EDITOR_INSPECTOR_H +#include "editor/editor_undo_redo_manager.h" #include "editor_property_name_processor.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" @@ -42,8 +43,6 @@ #include "scene/gui/spin_box.h" #include "scene/gui/texture_rect.h" -class UndoRedo; - class EditorPropertyRevert { public: static bool get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value, bool p_check_class_default = true); @@ -313,7 +312,7 @@ public: class EditorInspectorArray : public EditorInspectorSection { GDCLASS(EditorInspectorArray, EditorInspectorSection); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; enum Mode { MODE_NONE, @@ -408,7 +407,7 @@ protected: static void _bind_methods(); public: - void set_undo_redo(UndoRedo *p_undo_redo); + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = ""); void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = ""); @@ -448,7 +447,7 @@ public: class EditorInspector : public ScrollContainer { GDCLASS(EditorInspector, ScrollContainer); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; enum { MAX_PLUGINS = 1024 }; @@ -562,7 +561,7 @@ public: static EditorProperty *instantiate_property_editor(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 = false); - void set_undo_redo(UndoRedo *p_undo_redo); + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); String get_selected_path() const; diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp index cd8150d235..0cf7f7df2a 100644 --- a/editor/editor_locale_dialog.cpp +++ b/editor/editor_locale_dialog.cpp @@ -33,6 +33,7 @@ #include "core/config/project_settings.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/check_button.h" #include "scene/gui/line_edit.h" #include "scene/gui/option_button.h" diff --git a/editor/editor_locale_dialog.h b/editor/editor_locale_dialog.h index 7a4828e83a..8ac642a038 100644 --- a/editor/editor_locale_dialog.h +++ b/editor/editor_locale_dialog.h @@ -40,7 +40,7 @@ class VBoxContainer; class LineEdit; class Tree; class OptionButton; -class UndoRedo; +class EditorUndoRedoManager; class EditorLocaleDialog : public ConfirmationDialog { GDCLASS(EditorLocaleDialog, ConfirmationDialog); @@ -63,7 +63,7 @@ class EditorLocaleDialog : public ConfirmationDialog { Tree *script_list = nullptr; Tree *cnt_list = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool locale_set = false; bool updating_lists = false; diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 8aa099ddff..dc03a1f270 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -224,6 +224,10 @@ void EditorLog::set_tool_button(Button *p_tool_button) { tool_button = p_tool_button; } +void EditorLog::register_undo_redo(UndoRedo *p_undo_redo) { + p_undo_redo->set_commit_notify_callback(_undo_redo_cbk, this); +} + void EditorLog::_undo_redo_cbk(void *p_self, const String &p_name) { EditorLog *self = static_cast<EditorLog *>(p_self); self->add_message(p_name, EditorLog::MSG_TYPE_EDITOR); @@ -458,8 +462,6 @@ EditorLog::EditorLog() { add_error_handler(&eh); current = Thread::get_caller_id(); - - EditorNode::get_undo_redo()->set_commit_notify_callback(_undo_redo_cbk, this); } void EditorLog::deinit() { diff --git a/editor/editor_log.h b/editor/editor_log.h index c225e6d8c5..3bdfd936c1 100644 --- a/editor/editor_log.h +++ b/editor/editor_log.h @@ -41,6 +41,8 @@ #include "scene/gui/texture_button.h" #include "scene/gui/texture_rect.h" +class UndoRedo; + class EditorLog : public HBoxContainer { GDCLASS(EditorLog, HBoxContainer); @@ -182,6 +184,7 @@ protected: public: void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD); void set_tool_button(Button *p_tool_button); + void register_undo_redo(UndoRedo *p_undo_redo); void deinit(); void clear(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 2941ae6695..362159cb56 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -105,6 +105,7 @@ #include "editor/editor_themes.h" #include "editor/editor_toaster.h" #include "editor/editor_translation_parser.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/export/editor_export.h" #include "editor/export/export_template_manager.h" #include "editor/export/project_export.h" @@ -349,8 +350,7 @@ void EditorNode::_update_scene_tabs() { icon = EditorNode::get_singleton()->get_object_icon(type_node, "Node"); } - int current = editor_data.get_edited_scene(); - bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0; + bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i)); scene_tabs->add_tab(disambiguated_scene_names[i] + (unsaved ? "(*)" : ""), icon); if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) { @@ -597,15 +597,15 @@ void EditorNode::_notification(int p_what) { opening_prev = false; } - bool unsaved_cache_changed = false; - if (unsaved_cache != (saved_version != editor_data.get_undo_redo().get_version())) { - unsaved_cache = (saved_version != editor_data.get_undo_redo().get_version()); - unsaved_cache_changed = true; + bool global_unsaved = get_undo_redo()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY); + bool scene_or_global_unsaved = global_unsaved || get_undo_redo()->is_history_unsaved(editor_data.get_current_edited_scene_history_id()); + if (unsaved_cache != scene_or_global_unsaved) { + unsaved_cache = scene_or_global_unsaved; + _update_title(); } - if (last_checked_version != editor_data.get_undo_redo().get_version()) { + if (editor_data.is_scene_changed(-1)) { _update_scene_tabs(); - last_checked_version = editor_data.get_undo_redo().get_version(); } // Update the animation frame of the update spinner. @@ -631,7 +631,7 @@ void EditorNode::_notification(int p_what) { ResourceImporterTexture::get_singleton()->update_imports(); - if (settings_changed || unsaved_cache_changed) { + if (settings_changed) { _update_title(); } @@ -661,6 +661,7 @@ void EditorNode::_notification(int p_what) { command_palette->register_shortcuts_as_command(); + MessageQueue::get_singleton()->push_callable(callable_mp(this, &EditorNode::_begin_first_scan)); /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } break; @@ -1043,6 +1044,8 @@ void EditorNode::_sources_changed(bool p_exist) { if (waiting_for_first_scan) { waiting_for_first_scan = false; + Engine::get_singleton()->startup_benchmark_end_measure(); // editor_scan_and_reimport + // Reload the global shader variables, but this time // loading textures, as they are now properly imported. RenderingServer::get_singleton()->global_shader_uniforms_load_settings(true); @@ -1055,8 +1058,16 @@ void EditorNode::_sources_changed(bool p_exist) { _load_docks(); if (!defer_load_scene.is_empty()) { + Engine::get_singleton()->startup_benchmark_begin_measure("editor_load_scene"); load_scene(defer_load_scene); defer_load_scene = ""; + Engine::get_singleton()->startup_benchmark_end_measure(); + + if (use_startup_benchmark) { + Engine::get_singleton()->startup_dump(startup_benchmark_file); + startup_benchmark_file = String(); + use_startup_benchmark = false; + } } } } @@ -1127,7 +1138,6 @@ void EditorNode::_reload_modified_scenes() { } } - get_undo_redo()->clear_history(false); set_current_scene(current_idx); _update_scene_tabs(); disk_changed->hide(); @@ -1681,6 +1691,8 @@ int EditorNode::_save_external_resources() { saved++; } + get_undo_redo()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY); + return saved; } @@ -1762,11 +1774,7 @@ void EditorNode::_save_scene(String p_file, int idx) { if (err == OK) { scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(p_file)); - if (idx < 0 || idx == editor_data.get_edited_scene()) { - set_current_version(editor_data.get_undo_redo().get_version()); - } else { - editor_data.set_edited_scene_version(0, idx); - } + editor_data.set_scene_as_saved(idx); editor_data.set_scene_modified_time(idx, FileAccess::get_modified_time(p_file)); editor_folding.save_scene_folding(scene, p_file); @@ -1811,15 +1819,15 @@ void EditorNode::restart_editor() { List<String> args; + for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) { + args.push_back(a); + } + args.push_back("--path"); args.push_back(ProjectSettings::get_singleton()->get_resource_path()); args.push_back("-e"); - if (OS::get_singleton()->is_disable_crash_handler()) { - args.push_back("--disable-crash-handler"); - } - if (!to_reopen.is_empty()) { args.push_back(to_reopen); } @@ -1858,12 +1866,9 @@ void EditorNode::_mark_unsaved_scenes() { } String path = node->get_scene_file_path(); - if (!(path.is_empty() || FileAccess::exists(path))) { - if (i == editor_data.get_edited_scene()) { - set_current_version(-1); - } else { - editor_data.set_edited_scene_version(-1, i); - } + if (!path.is_empty() && !FileAccess::exists(path)) { + // Mark scene tab as unsaved if the file is gone. + get_undo_redo()->set_history_as_unsaved(editor_data.get_scene_history_id(i)); } } @@ -2721,9 +2726,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) { log->add_message(TTR("Can't undo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR); } else { - String action = editor_data.get_undo_redo().get_current_action_name(); + String action = editor_data.get_undo_redo()->get_current_action_name(); - if (!editor_data.get_undo_redo().undo()) { + if (!editor_data.get_undo_redo()->undo()) { log->add_message(TTR("Nothing to undo."), EditorLog::MSG_TYPE_EDITOR); } else if (!action.is_empty()) { log->add_message(vformat(TTR("Undo: %s"), action), EditorLog::MSG_TYPE_EDITOR); @@ -2734,10 +2739,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) { log->add_message(TTR("Can't redo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR); } else { - if (!editor_data.get_undo_redo().redo()) { + if (!editor_data.get_undo_redo()->redo()) { log->add_message(TTR("Nothing to redo."), EditorLog::MSG_TYPE_EDITOR); } else { - String action = editor_data.get_undo_redo().get_current_action_name(); + String action = editor_data.get_undo_redo()->get_current_action_name(); log->add_message(vformat(TTR("Redo: %s"), action), EditorLog::MSG_TYPE_EDITOR); } } @@ -2772,7 +2777,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { ERR_PRINT("Failed to load scene"); } editor_data.move_edited_scene_to_index(cur_idx); - get_undo_redo()->clear_history(false); + get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id()); scene_tabs->set_current_tab(cur_idx); } break; @@ -3085,8 +3090,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) { if (!editor_data.get_edited_scene_root(i)) { continue; } - int current = editor_data.get_edited_scene(); - bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0; + bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i)); if (unsaved) { String scene_filename = editor_data.get_edited_scene_root(i)->get_scene_file_path(); if (p_valid_filename && scene_filename.length() == 0) { @@ -3172,6 +3176,9 @@ void EditorNode::_discard_changes(const String &p_str) { String exec = OS::get_singleton()->get_executable_path(); List<String> args; + for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) { + args.push_back(a); + } args.push_back("--path"); args.push_back(exec.get_base_dir()); args.push_back("--project-manager"); @@ -3193,9 +3200,9 @@ void EditorNode::_update_file_menu_opened() { file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty()); - const UndoRedo &undo_redo = editor_data.get_undo_redo(); - file_menu->set_item_disabled(file_menu->get_item_index(EDIT_UNDO), !undo_redo.has_undo()); - file_menu->set_item_disabled(file_menu->get_item_index(EDIT_REDO), !undo_redo.has_redo()); + Ref<EditorUndoRedoManager> undo_redo = editor_data.get_undo_redo(); + file_menu->set_item_disabled(file_menu->get_item_index(EDIT_UNDO), !undo_redo->has_undo()); + file_menu->set_item_disabled(file_menu->get_item_index(EDIT_REDO), !undo_redo->has_redo()); } void EditorNode::_update_file_menu_closed() { @@ -3451,7 +3458,6 @@ void EditorNode::_remove_edited_scene(bool p_change_tab) { _scene_tab_changed(new_index); } editor_data.remove_scene(old_index); - editor_data.get_undo_redo().clear_history(false); _update_title(); _update_scene_tabs(); } @@ -3507,7 +3513,6 @@ Dictionary EditorNode::_get_main_scene_state() { state["main_tab"] = _get_current_main_editor(); state["scene_tree_offset"] = SceneTreeDock::get_singleton()->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->get_value(); state["property_edit_offset"] = InspectorDock::get_inspector_singleton()->get_scroll_offset(); - state["saved_version"] = saved_version; state["node_filter"] = SceneTreeDock::get_singleton()->get_filter(); return state; } @@ -3567,11 +3572,6 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) { editor_data.notify_edited_scene_changed(); } -void EditorNode::set_current_version(uint64_t p_version) { - saved_version = p_version; - editor_data.set_edited_scene_version(p_version); -} - bool EditorNode::is_changing_scene() const { return changing_scene; } @@ -3591,7 +3591,7 @@ void EditorNode::set_current_scene(int p_idx) { editor_folding.load_scene_folding(editor_data.get_edited_scene_root(p_idx), editor_data.get_scene_path(p_idx)); } - call_deferred(SNAME("_clear_undo_history")); + get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(p_idx)); } changing_scene = true; @@ -3608,8 +3608,8 @@ void EditorNode::set_current_scene(int p_idx) { Node *new_scene = editor_data.get_edited_scene_root(); - if (Object::cast_to<Popup>(new_scene)) { - Object::cast_to<Popup>(new_scene)->show(); + if (Popup *p = Object::cast_to<Popup>(new_scene)) { + p->show(); } SceneTreeDock::get_singleton()->set_edited_scene(new_scene); @@ -3627,6 +3627,7 @@ void EditorNode::set_current_scene(int p_idx) { _edit_current(true); _update_title(); + _update_scene_tabs(); call_deferred(SNAME("_set_main_scene_state"), state, get_edited_scene()); // Do after everything else is done setting up. } @@ -3785,7 +3786,6 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b set_edited_scene(new_scene); _get_scene_metadata(p_scene); - saved_version = editor_data.get_undo_redo().get_version(); _update_title(); _update_scene_tabs(); _add_to_recent_scenes(lpath); @@ -3836,6 +3836,10 @@ void EditorNode::request_instantiate_scenes(const Vector<String> &p_files) { SceneTreeDock::get_singleton()->instantiate_scenes(p_files); } +Ref<EditorUndoRedoManager> &EditorNode::get_undo_redo() { + return singleton->editor_data.get_undo_redo(); +} + void EditorNode::_inherit_request(String p_file) { current_menu_option = FILE_NEW_INHERITED_SCENE; _dialog_action(p_file); @@ -3996,6 +4000,7 @@ void EditorNode::register_editor_types() { GDREGISTER_CLASS(EditorSpinSlider); GDREGISTER_CLASS(EditorResourcePicker); GDREGISTER_CLASS(EditorScriptPicker); + GDREGISTER_ABSTRACT_CLASS(EditorUndoRedoManager); GDREGISTER_ABSTRACT_CLASS(FileSystemDock); GDREGISTER_VIRTUAL_CLASS(EditorFileSystemImportFormatSupportQuery); @@ -4318,6 +4323,15 @@ void EditorNode::_editor_file_dialog_unregister(EditorFileDialog *p_dialog) { Vector<EditorNodeInitCallback> EditorNode::_init_callbacks; +void EditorNode::_begin_first_scan() { + Engine::get_singleton()->startup_benchmark_begin_measure("editor_scan_and_import"); + EditorFileSystem::get_singleton()->scan(); +} +void EditorNode::set_use_startup_benchmark(bool p_use_startup_benchmark, const String &p_startup_benchmark_file) { + use_startup_benchmark = p_use_startup_benchmark; + startup_benchmark_file = p_startup_benchmark_file; +} + Error EditorNode::export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only) { export_defer.preset = p_preset; export_defer.path = p_path; @@ -5128,9 +5142,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) { return; } - bool unsaved = (p_tab == editor_data.get_edited_scene()) - ? saved_version != editor_data.get_undo_redo().get_version() - : editor_data.get_scene_version(p_tab) != 0; + bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(p_tab)); if (unsaved) { save_confirmation->set_ok_button_text(TTR("Save & Close")); save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene->get_scene_file_path().is_empty() ? scene->get_scene_file_path() : "unsaved scene")); @@ -5242,23 +5254,10 @@ void EditorNode::_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_p void EditorNode::_scene_tab_changed(int p_tab) { tab_preview_panel->hide(); - bool unsaved = (saved_version != editor_data.get_undo_redo().get_version()); - if (p_tab == editor_data.get_edited_scene()) { return; // Pointless. } - - uint64_t next_scene_version = editor_data.get_scene_version(p_tab); - - editor_data.get_undo_redo().create_action(TTR("Switch Scene Tab")); - editor_data.get_undo_redo().add_do_method(this, "set_current_version", unsaved ? saved_version : 0); - editor_data.get_undo_redo().add_do_method(this, "set_current_scene", p_tab); - editor_data.get_undo_redo().add_do_method(this, "set_current_version", next_scene_version == 0 ? editor_data.get_undo_redo().get_version() + 1 : next_scene_version); - - editor_data.get_undo_redo().add_undo_method(this, "set_current_version", next_scene_version); - editor_data.get_undo_redo().add_undo_method(this, "set_current_scene", editor_data.get_edited_scene()); - editor_data.get_undo_redo().add_undo_method(this, "set_current_version", saved_version); - editor_data.get_undo_redo().commit_action(); + set_current_scene(p_tab); } Button *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) { @@ -5644,7 +5643,7 @@ void EditorNode::reload_scene(const String &p_path) { if (scene_idx == -1) { if (get_edited_scene()) { // Scene is not open, so at it might be instantiated. We'll refresh the whole scene later. - editor_data.get_undo_redo().clear_history(); + editor_data.get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id()); } return; } @@ -5660,7 +5659,7 @@ void EditorNode::reload_scene(const String &p_path) { // Adjust index so tab is back a the previous position. editor_data.move_edited_scene_to_index(scene_idx); - get_undo_redo()->clear_history(); + get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(scene_idx)); // Recover the tab. scene_tabs->set_current_tab(current_tab); @@ -5844,7 +5843,6 @@ void EditorNode::_bind_methods() { ClassDB::bind_method("stop_child_process", &EditorNode::stop_child_process); ClassDB::bind_method("set_current_scene", &EditorNode::set_current_scene); - ClassDB::bind_method("set_current_version", &EditorNode::set_current_version); ClassDB::bind_method("_thumbnail_done", &EditorNode::_thumbnail_done); ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state); ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes); diff --git a/editor/editor_node.h b/editor/editor_node.h index f7a102b4c7..7400bcd422 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -72,6 +72,7 @@ class EditorRun; class EditorRunNative; class EditorSettingsDialog; class EditorToaster; +class EditorUndoRedoManager; class ExportTemplateManager; class FileDialog; class FileSystemDock; @@ -471,9 +472,6 @@ private: String open_navigate; String run_custom_filename; - uint64_t saved_version = 1; - uint64_t last_checked_version = 0; - DynamicFontImportSettings *fontdata_import_settings = nullptr; SceneImportSettings *scene_import_settings = nullptr; AudioStreamImportSettings *audio_stream_import_settings = nullptr; @@ -682,6 +680,10 @@ private: void _bottom_panel_switch(bool p_enable, int p_idx); void _bottom_panel_raise_toggled(bool); + void _begin_first_scan(); + bool use_startup_benchmark = false; + String startup_benchmark_file; + protected: friend class FileSystemDock; @@ -705,7 +707,7 @@ public: static EditorLog *get_log() { return singleton->log; } static EditorData &get_editor_data() { return singleton->editor_data; } static EditorFolding &get_editor_folding() { return singleton->editor_folding; } - static UndoRedo *get_undo_redo() { return &singleton->editor_data.get_undo_redo(); } + static Ref<EditorUndoRedoManager> &get_undo_redo(); static HBoxContainer *get_menu_hb() { return singleton->menu_hb; } static VSplitContainer *get_top_split() { return singleton->top_split; } @@ -789,7 +791,6 @@ public: bool is_scene_open(const String &p_path); - void set_current_version(uint64_t p_version); void set_current_scene(int p_idx); void setup_color_picker(ColorPicker *picker); @@ -816,6 +817,7 @@ public: void _copy_warning(const String &p_str); + void set_use_startup_benchmark(bool p_use_startup_benchmark, const String &p_startup_benchmark_file); Error export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only); Control *get_gui_base() { return gui_base; } diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 400ad1ebac..2e64e46519 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -35,6 +35,7 @@ #include "editor/editor_paths.h" #include "editor/editor_resource_preview.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/export/editor_export.h" #include "editor/filesystem_dock.h" #include "editor/plugins/canvas_item_editor_plugin.h" @@ -312,6 +313,13 @@ void EditorInterface::set_distraction_free_mode(bool p_enter) { EditorNode::get_singleton()->set_distraction_free_mode(p_enter); } +void EditorInterface::restart_editor(bool p_save) { + if (p_save) { + EditorNode::get_singleton()->save_all_scenes(); + } + EditorNode::get_singleton()->restart_editor(); +} + bool EditorInterface::is_distraction_free_mode_enabled() const { return EditorNode::get_singleton()->is_distraction_free_mode_enabled(); } @@ -360,6 +368,7 @@ void EditorInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("save_scene"), &EditorInterface::save_scene); ClassDB::bind_method(D_METHOD("save_scene_as", "path", "with_preview"), &EditorInterface::save_scene_as, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("restart_editor", "save"), &EditorInterface::restart_editor, DEFVAL(true)); ClassDB::bind_method(D_METHOD("set_main_screen_editor", "name"), &EditorInterface::set_main_screen_editor); ClassDB::bind_method(D_METHOD("set_distraction_free_mode", "enter"), &EditorInterface::set_distraction_free_mode); @@ -885,7 +894,7 @@ void EditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("make_bottom_panel_item_visible", "item"), &EditorPlugin::make_bottom_panel_item_visible); ClassDB::bind_method(D_METHOD("hide_bottom_panel"), &EditorPlugin::hide_bottom_panel); - ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::_get_undo_redo); + ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::get_undo_redo); ClassDB::bind_method(D_METHOD("add_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::add_undo_redo_inspector_hook_callback); ClassDB::bind_method(D_METHOD("remove_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::remove_undo_redo_inspector_hook_callback); ClassDB::bind_method(D_METHOD("queue_save_layout"), &EditorPlugin::queue_save_layout); @@ -965,6 +974,10 @@ void EditorPlugin::_bind_methods() { BIND_ENUM_CONSTANT(DOCK_SLOT_MAX); } +Ref<EditorUndoRedoManager> EditorPlugin::get_undo_redo() { + return undo_redo; +} + EditorPluginCreateFunc EditorPlugins::creation_funcs[MAX_CREATE_FUNCS]; int EditorPlugins::creation_func_count = 0; diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 3f9d276b6a..201c7790a3 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -53,6 +53,7 @@ class EditorImportPlugin; class EditorExportPlugin; class EditorNode3DGizmoPlugin; class EditorResourcePreview; +class EditorUndoRedoManager; class EditorFileSystem; class EditorToolAddons; class EditorPaths; @@ -116,6 +117,7 @@ public: Error save_scene(); void save_scene_as(const String &p_scene, bool p_with_preview = true); + void restart_editor(bool p_save = true); Vector<Ref<Texture2D>> make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size); @@ -129,9 +131,7 @@ public: class EditorPlugin : public Node { GDCLASS(EditorPlugin, Node); friend class EditorData; - UndoRedo *undo_redo = nullptr; - - UndoRedo *_get_undo_redo() { return undo_redo; } + Ref<EditorUndoRedoManager> undo_redo; bool input_event_forwarding_always_enabled = false; bool force_draw_over_forwarding_enabled = false; @@ -144,7 +144,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - UndoRedo &get_undo_redo() { return *undo_redo; } + Ref<EditorUndoRedoManager> get_undo_redo(); void add_custom_type(const String &p_type, const String &p_base, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon); void remove_custom_type(const String &p_type); diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp index 6ce8625daa..3b828951e4 100644 --- a/editor/editor_run.cpp +++ b/editor/editor_run.cpp @@ -33,6 +33,7 @@ #include "core/config/project_settings.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "main/main.h" #include "servers/display_server.h" EditorRun::Status EditorRun::get_status() const { @@ -46,6 +47,10 @@ String EditorRun::get_running_scene() const { Error EditorRun::run(const String &p_scene, const String &p_write_movie) { List<String> args; + for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_PROJECT)) { + args.push_back(a); + } + String resource_path = ProjectSettings::get_singleton()->get_resource_path(); if (!resource_path.is_empty()) { args.push_back("--path"); @@ -105,10 +110,6 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) { screen -= 3; } - if (OS::get_singleton()->is_disable_crash_handler()) { - args.push_back("--disable-crash-handler"); - } - Rect2 screen_rect; screen_rect.position = DisplayServer::get_singleton()->screen_get_position(screen); screen_rect.size = DisplayServer::get_singleton()->screen_get_size(screen); diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index 08ff63551f..67c602ad2d 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -40,6 +40,7 @@ #include "editor/editor_property_name_processor.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/margin_container.h" void EditorSettingsDialog::ok_pressed() { @@ -124,9 +125,9 @@ void EditorSettingsDialog::_notification(int p_what) { } break; case NOTIFICATION_READY: { - undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, nullptr); - undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, nullptr); - undo_redo->set_commit_notify_callback(_undo_redo_callback, this); + undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, nullptr); + undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, nullptr); + undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_commit_notify_callback(_undo_redo_callback, this); } break; case NOTIFICATION_ENTER_TREE: { @@ -680,7 +681,7 @@ void EditorSettingsDialog::_bind_methods() { EditorSettingsDialog::EditorSettingsDialog() { set_title(TTR("Editor Settings")); - undo_redo = memnew(UndoRedo); + undo_redo = EditorNode::get_undo_redo(); tabs = memnew(TabContainer); tabs->set_theme_type_variation("TabContainerOdd"); @@ -776,5 +777,4 @@ EditorSettingsDialog::EditorSettingsDialog() { } EditorSettingsDialog::~EditorSettingsDialog() { - memdelete(undo_redo); } diff --git a/editor/editor_settings_dialog.h b/editor/editor_settings_dialog.h index a1ea54c6fb..87ed6a77eb 100644 --- a/editor/editor_settings_dialog.h +++ b/editor/editor_settings_dialog.h @@ -40,6 +40,8 @@ #include "scene/gui/tab_container.h" #include "scene/gui/texture_rect.h" +class EditorUndoRedoManager; + class EditorSettingsDialog : public AcceptDialog { GDCLASS(EditorSettingsDialog, AcceptDialog); @@ -73,7 +75,7 @@ class EditorSettingsDialog : public AcceptDialog { Timer *timer = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; virtual void cancel_pressed() override; virtual void ok_pressed() override; diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp new file mode 100644 index 0000000000..eca2b3143b --- /dev/null +++ b/editor/editor_undo_redo_manager.cpp @@ -0,0 +1,442 @@ +/*************************************************************************/ +/* editor_undo_redo_manager.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 "editor_undo_redo_manager.h" + +#include "core/io/resource.h" +#include "core/os/os.h" +#include "core/templates/local_vector.h" +#include "editor/editor_log.h" +#include "editor/editor_node.h" +#include "scene/main/node.h" + +EditorUndoRedoManager::History &EditorUndoRedoManager::get_or_create_history(int p_idx) { + if (!history_map.has(p_idx)) { + History history; + history.undo_redo = memnew(UndoRedo); + history.id = p_idx; + history_map[p_idx] = history; + + EditorNode::get_singleton()->get_log()->register_undo_redo(history.undo_redo); + EditorDebuggerNode::get_singleton()->register_undo_redo(history.undo_redo); + } + return history_map[p_idx]; +} + +UndoRedo *EditorUndoRedoManager::get_history_undo_redo(int p_idx) const { + ERR_FAIL_COND_V(!history_map.has(p_idx), nullptr); + return history_map[p_idx].undo_redo; +} + +int EditorUndoRedoManager::get_history_id_for_object(Object *p_object) const { + int history_id = INVALID_HISTORY; + + if (Node *node = Object::cast_to<Node>(p_object)) { + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); + + if (edited_scene && (node == edited_scene || edited_scene->is_ancestor_of(node))) { + int idx = EditorNode::get_singleton()->get_editor_data().get_current_edited_scene_history_id(); + if (idx > 0) { + history_id = idx; + } + } + } + + if (Resource *res = Object::cast_to<Resource>(p_object)) { + if (res->is_built_in()) { + if (res->get_path().is_empty()) { + int idx = EditorNode::get_singleton()->get_editor_data().get_current_edited_scene_history_id(); + if (idx > 0) { + history_id = idx; + } + } else { + int idx = EditorNode::get_singleton()->get_editor_data().get_scene_history_id_from_path(res->get_path().get_slice("::", 0)); + if (idx > 0) { + history_id = idx; + } + } + } + } + + if (history_id == INVALID_HISTORY) { + if (pending_action.history_id != INVALID_HISTORY) { + history_id = pending_action.history_id; + } else { + history_id = GLOBAL_HISTORY; + } + } + return history_id; +} + +EditorUndoRedoManager::History &EditorUndoRedoManager::get_history_for_object(Object *p_object) { + int history_id = get_history_id_for_object(p_object); + ERR_FAIL_COND_V_MSG(pending_action.history_id != INVALID_HISTORY && history_id != pending_action.history_id, get_or_create_history(pending_action.history_id), vformat("UndoRedo history mismatch: expected %d, got %d.", pending_action.history_id, history_id)); + + History &history = get_or_create_history(history_id); + if (pending_action.history_id == INVALID_HISTORY) { + pending_action.history_id = history_id; + history.undo_redo->create_action(pending_action.action_name, pending_action.merge_mode); + } + + return history; +} + +void EditorUndoRedoManager::create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode) { + pending_action.action_name = p_name; + pending_action.timestamp = OS::get_singleton()->get_unix_time(); + pending_action.merge_mode = p_mode; + + if (p_history_id != INVALID_HISTORY) { + pending_action.history_id = p_history_id; + History &history = get_or_create_history(p_history_id); + history.undo_redo->create_action(pending_action.action_name, pending_action.merge_mode); + } +} + +void EditorUndoRedoManager::create_action(const String &p_name, UndoRedo::MergeMode p_mode, Object *p_custom_context) { + create_action_for_history(p_name, INVALID_HISTORY, p_mode); + + if (p_custom_context) { + // This assigns context to pending action. + get_history_for_object(p_custom_context); + } +} + +void EditorUndoRedoManager::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_do_methodp(p_object, p_method, p_args, p_argcount); +} + +void EditorUndoRedoManager::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_undo_methodp(p_object, p_method, p_args, p_argcount); +} + +void EditorUndoRedoManager::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + if (p_argcount < 2) { + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = 0; + return; + } + + if (p_args[0]->get_type() != Variant::OBJECT) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + return; + } + + if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::STRING_NAME; + return; + } + + r_error.error = Callable::CallError::CALL_OK; + + Object *object = *p_args[0]; + StringName method = *p_args[1]; + + add_do_methodp(object, method, p_args + 2, p_argcount - 2); +} + +void EditorUndoRedoManager::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + if (p_argcount < 2) { + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = 0; + return; + } + + if (p_args[0]->get_type() != Variant::OBJECT) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + return; + } + + if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::STRING_NAME; + return; + } + + r_error.error = Callable::CallError::CALL_OK; + + Object *object = *p_args[0]; + StringName method = *p_args[1]; + + add_undo_methodp(object, method, p_args + 2, p_argcount - 2); +} + +void EditorUndoRedoManager::add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_do_property(p_object, p_property, p_value); +} + +void EditorUndoRedoManager::add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_undo_property(p_object, p_property, p_value); +} + +void EditorUndoRedoManager::add_do_reference(Object *p_object) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_do_reference(p_object); +} + +void EditorUndoRedoManager::add_undo_reference(Object *p_object) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_undo_reference(p_object); +} + +void EditorUndoRedoManager::commit_action(bool p_execute) { + ERR_FAIL_COND(pending_action.history_id == INVALID_HISTORY); + is_committing = true; + + History &history = get_or_create_history(pending_action.history_id); + history.undo_redo->commit_action(p_execute); + history.redo_stack.clear(); + + if (!history.undo_stack.is_empty()) { + const Action &prev_action = history.undo_stack.back()->get(); + if (pending_action.merge_mode != UndoRedo::MERGE_DISABLE && pending_action.merge_mode == prev_action.merge_mode && pending_action.action_name == prev_action.action_name) { + // Discard action if it should be merged (UndoRedo handles merging internally). + pending_action = Action(); + is_committing = false; + return; + } + } + + history.undo_stack.push_back(pending_action); + pending_action = Action(); + is_committing = false; +} + +bool EditorUndoRedoManager::is_committing_action() const { + return is_committing; +} + +bool EditorUndoRedoManager::undo() { + if (!has_undo()) { + return false; + } + + History *selected_history = nullptr; + double global_timestamp = 0; + + // Pick the history with greatest last action timestamp (either global or current scene). + { + History &history = get_or_create_history(GLOBAL_HISTORY); + if (!history.undo_stack.is_empty()) { + selected_history = &history; + global_timestamp = history.undo_stack.back()->get().timestamp; + } + } + + { + History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id()); + if (!history.undo_stack.is_empty() && history.undo_stack.back()->get().timestamp > global_timestamp) { + selected_history = &history; + } + } + + if (selected_history) { + Action action = selected_history->undo_stack.back()->get(); + selected_history->undo_stack.pop_back(); + selected_history->redo_stack.push_back(action); + return selected_history->undo_redo->undo(); + } + return false; +} + +bool EditorUndoRedoManager::redo() { + if (!has_redo()) { + return false; + } + + History *selected_history = nullptr; + double global_timestamp = INFINITY; + + // Pick the history with lowest last action timestamp (either global or current scene). + { + History &history = get_or_create_history(GLOBAL_HISTORY); + if (!history.redo_stack.is_empty()) { + selected_history = &history; + global_timestamp = history.redo_stack.back()->get().timestamp; + } + } + + { + History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id()); + if (!history.redo_stack.is_empty() && history.redo_stack.back()->get().timestamp < global_timestamp) { + selected_history = &history; + } + } + + if (selected_history) { + Action action = selected_history->redo_stack.back()->get(); + selected_history->redo_stack.pop_back(); + selected_history->undo_stack.push_back(action); + return selected_history->undo_redo->redo(); + } + return false; +} + +void EditorUndoRedoManager::set_history_as_saved(int p_id) { + History &history = get_or_create_history(p_id); + history.saved_version = history.undo_redo->get_version(); +} + +void EditorUndoRedoManager::set_history_as_unsaved(int p_id) { + History &history = get_or_create_history(p_id); + history.saved_version = -1; +} + +bool EditorUndoRedoManager::is_history_unsaved(int p_id) { + History &history = get_or_create_history(p_id); + return history.undo_redo->get_version() != history.saved_version; +} + +bool EditorUndoRedoManager::has_undo() { + for (const KeyValue<int, History> &E : history_map) { + if ((E.key == GLOBAL_HISTORY || E.key == EditorNode::get_editor_data().get_current_edited_scene_history_id()) && !E.value.undo_stack.is_empty()) { + return true; + } + } + return false; +} + +bool EditorUndoRedoManager::has_redo() { + for (const KeyValue<int, History> &E : history_map) { + if ((E.key == GLOBAL_HISTORY || E.key == EditorNode::get_editor_data().get_current_edited_scene_history_id()) && !E.value.redo_stack.is_empty()) { + return true; + } + } + return false; +} + +void EditorUndoRedoManager::clear_history(bool p_increase_version, int p_idx) { + if (p_idx != INVALID_HISTORY) { + get_or_create_history(p_idx).undo_redo->clear_history(p_increase_version); + if (!p_increase_version) { + set_history_as_saved(p_idx); + } + return; + } + + for (const KeyValue<int, History> &E : history_map) { + E.value.undo_redo->clear_history(p_increase_version); + set_history_as_saved(E.key); + } +} + +String EditorUndoRedoManager::get_current_action_name() { + if (has_undo()) { + History *selected_history = nullptr; + double global_timestamp = 0; + + // Pick the history with greatest last action timestamp (either global or current scene). + { + History &history = get_or_create_history(GLOBAL_HISTORY); + if (!history.undo_stack.is_empty()) { + selected_history = &history; + global_timestamp = history.undo_stack.back()->get().timestamp; + } + } + + { + History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id()); + if (!history.undo_stack.is_empty() && history.undo_stack.back()->get().timestamp > global_timestamp) { + selected_history = &history; + } + } + + if (selected_history) { + return selected_history->undo_redo->get_current_action_name(); + } + } + return ""; +} + +void EditorUndoRedoManager::discard_history(int p_idx, bool p_erase_from_map) { + ERR_FAIL_COND(!history_map.has(p_idx)); + History &history = history_map[p_idx]; + + if (history.undo_redo) { + memdelete(history.undo_redo); + history.undo_redo = nullptr; + } + + if (p_erase_from_map) { + history_map.erase(p_idx); + } +} + +void EditorUndoRedoManager::_bind_methods() { + ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode", "custom_context"), &EditorUndoRedoManager::create_action, DEFVAL(UndoRedo::MERGE_DISABLE), DEFVAL((Object *)nullptr)); + ClassDB::bind_method(D_METHOD("commit_action", "execute"), &EditorUndoRedoManager::commit_action, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("is_committing_action"), &EditorUndoRedoManager::is_committing_action); + + { + MethodInfo mi; + mi.name = "add_do_method"; + mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object")); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); + + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_do_method", &EditorUndoRedoManager::_add_do_method, mi, varray(), false); + } + + { + MethodInfo mi; + mi.name = "add_undo_method"; + mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object")); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); + + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_undo_method", &EditorUndoRedoManager::_add_undo_method, mi, varray(), false); + } + + ClassDB::bind_method(D_METHOD("add_do_property", "object", "property", "value"), &EditorUndoRedoManager::add_do_property); + ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &EditorUndoRedoManager::add_undo_property); + ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &EditorUndoRedoManager::add_do_reference); + ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &EditorUndoRedoManager::add_undo_reference); + + ClassDB::bind_method(D_METHOD("get_object_history_id", "object"), &EditorUndoRedoManager::get_history_id_for_object); + ClassDB::bind_method(D_METHOD("get_history_undo_redo", "id"), &EditorUndoRedoManager::get_history_undo_redo); + + BIND_ENUM_CONSTANT(GLOBAL_HISTORY); + BIND_ENUM_CONSTANT(INVALID_HISTORY); +} + +EditorUndoRedoManager::~EditorUndoRedoManager() { + for (const KeyValue<int, History> &E : history_map) { + discard_history(E.key, false); + } +} diff --git a/editor/editor_undo_redo_manager.h b/editor/editor_undo_redo_manager.h new file mode 100644 index 0000000000..c4d85daa22 --- /dev/null +++ b/editor/editor_undo_redo_manager.h @@ -0,0 +1,134 @@ +/*************************************************************************/ +/* editor_undo_redo_manager.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 EDITOR_UNDO_REDO_MANAGER_H +#define EDITOR_UNDO_REDO_MANAGER_H + +#include "core/object/class_db.h" +#include "core/object/ref_counted.h" +#include "core/object/undo_redo.h" + +class EditorUndoRedoManager : public RefCounted { + GDCLASS(EditorUndoRedoManager, RefCounted); + +public: + enum SpecialHistory { + GLOBAL_HISTORY = 0, + INVALID_HISTORY = -99, + }; + +private: + struct Action { + int history_id = INVALID_HISTORY; + double timestamp = 0; + String action_name; + UndoRedo::MergeMode merge_mode = UndoRedo::MERGE_DISABLE; + }; + + struct History { + int id = INVALID_HISTORY; + UndoRedo *undo_redo = nullptr; + uint64_t saved_version = 1; + List<Action> undo_stack; + List<Action> redo_stack; + }; + + HashMap<int, History> history_map; + Action pending_action; + + bool is_committing = false; + +protected: + static void _bind_methods(); + +public: + History &get_or_create_history(int p_idx); + UndoRedo *get_history_undo_redo(int p_idx) const; + int get_history_id_for_object(Object *p_object) const; + History &get_history_for_object(Object *p_object); + + void create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE); + void create_action(const String &p_name = "", UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE, Object *p_custom_context = nullptr); + + void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount); + void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount); + + template <typename... VarArgs> + void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + + add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + + template <typename... VarArgs> + void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + + add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + + void _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error); + void _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error); + + void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value); + void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value); + void add_do_reference(Object *p_object); + void add_undo_reference(Object *p_object); + + void commit_action(bool p_execute = true); + bool is_committing_action() const; + + bool undo(); + bool redo(); + void clear_history(bool p_increase_version = true, int p_idx = INVALID_HISTORY); + + void set_history_as_saved(int p_idx); + void set_history_as_unsaved(int p_idx); + bool is_history_unsaved(int p_idx); + bool has_undo(); + bool has_redo(); + + String get_current_action_name(); + + void discard_history(int p_idx, bool p_erase_from_map = true); + ~EditorUndoRedoManager(); +}; + +VARIANT_ENUM_CAST(EditorUndoRedoManager::SpecialHistory); + +#endif // EDITOR_UNDO_REDO_MANAGER_H diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index f16097f109..15add50fd4 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "editor/scene_tree_editor.h" #include "scene/gui/box_container.h" @@ -397,6 +398,10 @@ void GroupDialog::_notification(int p_what) { } } +void GroupDialog::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void GroupDialog::edit() { popup_centered(); @@ -696,6 +701,10 @@ void GroupsEditor::update_tree() { } } +void GroupsEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void GroupsEditor::set_current(Node *p_node) { node = p_node; update_tree(); diff --git a/editor/groups_editor.h b/editor/groups_editor.h index fec8913e31..8bbea4e652 100644 --- a/editor/groups_editor.h +++ b/editor/groups_editor.h @@ -31,7 +31,6 @@ #ifndef GROUPS_EDITOR_H #define GROUPS_EDITOR_H -#include "core/object/undo_redo.h" #include "editor/scene_tree_editor.h" #include "scene/gui/button.h" #include "scene/gui/dialogs.h" @@ -40,6 +39,8 @@ #include "scene/gui/popup.h" #include "scene/gui/tree.h" +class EditorUndoRedoManager; + class GroupDialog : public AcceptDialog { GDCLASS(GroupDialog, AcceptDialog); @@ -68,7 +69,7 @@ class GroupDialog : public AcceptDialog { String selected_group; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _group_selected(); @@ -103,7 +104,7 @@ public: }; void edit(); - void set_undo_redo(UndoRedo *p_undoredo) { undo_redo = p_undoredo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); GroupDialog(); }; @@ -119,7 +120,7 @@ class GroupsEditor : public VBoxContainer { Button *add = nullptr; Tree *tree = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void update_tree(); void _add_group(const String &p_group = ""); @@ -137,7 +138,7 @@ public: COPY_GROUP, }; - void set_undo_redo(UndoRedo *p_undoredo) { undo_redo = p_undoredo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_current(Node *p_node); GroupsEditor(); diff --git a/editor/icons/InterpCubicInTime.svg b/editor/icons/InterpCubicInTime.svg new file mode 100644 index 0000000000..81027f798a --- /dev/null +++ b/editor/icons/InterpCubicInTime.svg @@ -0,0 +1 @@ +<svg enable-background="new -595.5 420.5 16 8" height="8" viewBox="-595.5 420.5 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m-593.5 426.5c1-4 3.5-5.5 6-2s5 2 6-2" fill="none" stroke="#ff92cb" stroke-linecap="round" stroke-width="2"/></svg> diff --git a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp index 4f00bd120a..2fa602846c 100644 --- a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp +++ b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp @@ -38,6 +38,7 @@ void PostImportPluginSkeletonRestFixer::get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) { if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) { + r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/apply_node_transforms"), true)); r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/normalize_position_tracks"), true)); r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/overwrite_axis"), true)); @@ -67,6 +68,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory if (!src_skeleton) { return; } + bool is_renamed = bool(p_options["retarget/bone_renamer/rename_bones"]); Array filter = p_options["retarget/rest_fixer/fix_silhouette/filter"]; bool is_rest_changed = false; @@ -89,6 +91,107 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } } + // Apply node transforms. + if (bool(p_options["retarget/rest_fixer/apply_node_transforms"])) { + LocalVector<Transform3D> old_skeleton_rest; + LocalVector<Transform3D> old_skeleton_global_rest; + for (int i = 0; i < src_skeleton->get_bone_count(); i++) { + old_skeleton_rest.push_back(src_skeleton->get_bone_rest(i)); + old_skeleton_global_rest.push_back(src_skeleton->get_bone_global_rest(i)); + } + + Transform3D global_transform; + Node *pr = src_skeleton; + while (pr) { + Node3D *pr3d = Object::cast_to<Node3D>(pr); + if (pr3d) { + global_transform = pr3d->get_transform() * global_transform; + pr3d->set_transform(Transform3D()); + } + pr = pr->get_parent(); + } + Vector3 scl = global_transform.basis.get_scale_local(); + + Vector<int> bones_to_process = src_skeleton->get_parentless_bones(); + for (int i = 0; i < bones_to_process.size(); i++) { + src_skeleton->set_bone_rest(bones_to_process[i], global_transform.orthonormalized() * src_skeleton->get_bone_rest(bones_to_process[i])); + } + + while (bones_to_process.size() > 0) { + int src_idx = bones_to_process[0]; + bones_to_process.erase(src_idx); + Vector<int> src_children = src_skeleton->get_bone_children(src_idx); + for (int i = 0; i < src_children.size(); i++) { + bones_to_process.push_back(src_children[i]); + } + src_skeleton->set_bone_rest(src_idx, Transform3D(src_skeleton->get_bone_rest(src_idx).basis, src_skeleton->get_bone_rest(src_idx).origin * scl)); + } + + // Fix animation. + bones_to_process = src_skeleton->get_parentless_bones(); + { + TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer"); + while (nodes.size()) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back()); + List<StringName> anims; + ap->get_animation_list(&anims); + for (const StringName &name : anims) { + Ref<Animation> anim = ap->get_animation(name); + int track_len = anim->get_track_count(); + for (int i = 0; i < track_len; i++) { + if (anim->track_get_path(i).get_subname_count() != 1 || !(anim->track_get_type(i) == Animation::TYPE_POSITION_3D || anim->track_get_type(i) == Animation::TYPE_ROTATION_3D || anim->track_get_type(i) == Animation::TYPE_SCALE_3D)) { + continue; + } + + if (anim->track_is_compressed(i)) { + continue; // Shouldn't occur in internal_process(). + } + + String track_path = String(anim->track_get_path(i).get_concatenated_names()); + Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); + if (node) { + Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); + if (track_skeleton && track_skeleton == src_skeleton) { + StringName bn = anim->track_get_path(i).get_subname(0); + if (bn) { + int bone_idx = src_skeleton->find_bone(bn); + int key_len = anim->track_get_key_count(i); + if (anim->track_get_type(i) == Animation::TYPE_POSITION_3D) { + if (bones_to_process.has(bone_idx)) { + for (int j = 0; j < key_len; j++) { + Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j)); + anim->track_set_key_value(i, j, global_transform.basis.xform(ps) + global_transform.origin); + } + } else { + for (int j = 0; j < key_len; j++) { + Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j)); + anim->track_set_key_value(i, j, ps * scl); + } + } + } else if (bones_to_process.has(bone_idx)) { + if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) { + for (int j = 0; j < key_len; j++) { + Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j)); + anim->track_set_key_value(i, j, global_transform.basis.get_rotation_quaternion() * qt); + } + } else { + for (int j = 0; j < key_len; j++) { + Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j))); + anim->track_set_key_value(i, j, (global_transform.basis * sc).get_scale()); + } + } + } + } + } + } + } + } + } + } + + is_rest_changed = true; + } + // Set motion scale to Skeleton if normalize position tracks. if (bool(p_options["retarget/rest_fixer/normalize_position_tracks"])) { int src_bone_idx = src_skeleton->find_bone(profile->get_scale_base_bone()); @@ -367,32 +470,6 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory src_skeleton->set_bone_rest(src_idx, Transform3D(tgt_rot, diff.xform(src_skeleton->get_bone_rest(src_idx).origin))); } - // Fix skin. - { - TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D"); - while (nodes.size()) { - ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back()); - Ref<Skin> skin = mi->get_skin(); - if (skin.is_valid()) { - Node *node = mi->get_node(mi->get_skeleton_path()); - if (node) { - Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node); - if (mesh_skeleton && node == src_skeleton) { - int skin_len = skin->get_bind_count(); - for (int i = 0; i < skin_len; i++) { - StringName bn = skin->get_bind_name(i); - int bone_idx = src_skeleton->find_bone(bn); - if (bone_idx >= 0) { - Transform3D new_rest = silhouette_diff[i] * src_skeleton->get_bone_global_rest(bone_idx); - skin->set_bind_pose(i, new_rest.inverse()); - } - } - } - } - } - } - } - // Fix animation. { TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer"); @@ -471,8 +548,34 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory is_rest_changed = true; } - // Init skeleton pose to new rest. if (is_rest_changed) { + // Fix skin. + { + TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D"); + while (nodes.size()) { + ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back()); + Ref<Skin> skin = mi->get_skin(); + if (skin.is_valid()) { + Node *node = mi->get_node(mi->get_skeleton_path()); + if (node) { + Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node); + if (mesh_skeleton && node == src_skeleton) { + int skin_len = skin->get_bind_count(); + for (int i = 0; i < skin_len; i++) { + StringName bn = skin->get_bind_name(i); + int bone_idx = src_skeleton->find_bone(bn); + if (bone_idx >= 0) { + Transform3D new_rest = silhouette_diff[i] * src_skeleton->get_bone_global_rest(bone_idx); + skin->set_bind_pose(i, new_rest.inverse()); + } + } + } + } + } + } + } + + // Init skeleton pose to new rest. for (int i = 0; i < src_skeleton->get_bone_count(); i++) { Transform3D fixed_rest = src_skeleton->get_bone_rest(i); src_skeleton->set_bone_pose_position(i, fixed_rest.origin); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 3c0de61d24..85dda24f8e 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -850,12 +850,12 @@ Node *ResourceImporterScene::_post_fix_animations(Node *p_node, Node *p_root, co AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node); bool use_optimizer = node_settings["optimizer/enabled"]; - float anim_optimizer_linerr = node_settings["optimizer/max_linear_error"]; + float anim_optimizer_linerr = node_settings["optimizer/max_velocity_error"]; float anim_optimizer_angerr = node_settings["optimizer/max_angular_error"]; - float anim_optimizer_maxang = node_settings["optimizer/max_angle"]; + int anim_optimizer_preerr = node_settings["optimizer/max_precision_error"]; if (use_optimizer) { - _optimize_animations(ap, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_maxang); + _optimize_animations(ap, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_preerr); } bool use_compression = node_settings["compression/enabled"]; @@ -1386,12 +1386,12 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_ al->remove_animation("default"); // Remove default (no longer needed). } -void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle) { +void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error) { List<StringName> anim_names; anim->get_animation_list(&anim_names); for (const StringName &E : anim_names) { Ref<Animation> a = anim->get_animation(E); - a->optimize(p_max_lin_error, p_max_ang_error, Math::deg2rad(p_max_angle)); + a->optimize(p_max_vel_error, p_max_ang_error, p_prc_error); } } @@ -1467,9 +1467,9 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: { r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_linear_error"), 0.05)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angular_error"), 0.01)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angle"), 22)); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_velocity_error", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.01)); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angular_error", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.01)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "optimizer/max_precision_error", PROPERTY_HINT_NONE, "1,6,1"), 3)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compression/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compression/page_size", PROPERTY_HINT_RANGE, "4,512,1,suffix:kb"), 8)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/position", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1)); diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index b336931476..da37893cc5 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -280,7 +280,7 @@ public: Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks); void _create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all); - void _optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle); + void _optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error); void _compress_animations(AnimationPlayer *anim, int p_page_size_kb); Node *pre_import(const String &p_source_file, const HashMap<StringName, Variant> &p_options); diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp index bae1b903c6..9171f04f42 100644 --- a/editor/import/resource_importer_texture_atlas.cpp +++ b/editor/import/resource_importer_texture_atlas.cpp @@ -382,7 +382,6 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file mesh_texture->set_mesh(mesh); texture = mesh_texture; - //mesh } String save_path = p_base_paths[E.key] + ".res"; diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 79d94246ad..1bcbd2fe00 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -178,7 +178,8 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) { } } - editor_data->get_undo_redo().clear_history(); + int history_id = editor_data->get_undo_redo()->get_history_for_object(current).id; + editor_data->get_undo_redo()->clear_history(true, history_id); EditorNode::get_singleton()->get_editor_plugins_over()->edit(nullptr); EditorNode::get_singleton()->get_editor_plugins_over()->edit(current); @@ -755,7 +756,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { inspector->set_property_name_style(EditorPropertyNameProcessor::get_default_inspector_style()); inspector->set_use_folding(!bool(EDITOR_GET("interface/inspector/disable_folding"))); inspector->register_text_enter(search); - inspector->set_undo_redo(&editor_data->get_undo_redo()); + inspector->set_undo_redo(editor_data->get_undo_redo()); inspector->set_use_filter(true); // TODO: check me diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp index e8fb80eb57..77a1700ebf 100644 --- a/editor/localization_editor.cpp +++ b/editor/localization_editor.cpp @@ -36,6 +36,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_translation_parser.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/filesystem_dock.h" #include "editor/pot_generator.h" #include "scene/gui/control.h" diff --git a/editor/localization_editor.h b/editor/localization_editor.h index 10ccdfdc13..ecac171fe3 100644 --- a/editor/localization_editor.h +++ b/editor/localization_editor.h @@ -56,7 +56,7 @@ class LocalizationEditor : public VBoxContainer { EditorFileDialog *pot_file_open_dialog = nullptr; EditorFileDialog *pot_generate_dialog = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool updating_translations = false; String localization_changed; diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp index a694b8d754..70cc54668d 100644 --- a/editor/multi_node_edit.cpp +++ b/editor/multi_node_edit.cpp @@ -32,6 +32,7 @@ #include "core/math/math_fieldwise.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" bool MultiNodeEdit::_set(const StringName &p_name, const Variant &p_value) { return _set_impl(p_name, p_value, ""); @@ -54,7 +55,7 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value, node_path_target = es->get_node(p_value); } - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("MultiNode Set") + " " + String(name), UndoRedo::MERGE_ENDS); for (const NodePath &E : nodes) { diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp index 986370f537..55fa2f22dd 100644 --- a/editor/node_dock.cpp +++ b/editor/node_dock.cpp @@ -117,7 +117,7 @@ NodeDock::NodeDock() { groups_button->connect("pressed", callable_mp(this, &NodeDock::show_groups)); connections = memnew(ConnectionsDock); - connections->set_undoredo(EditorNode::get_undo_redo()); + connections->set_undo_redo(EditorNode::get_undo_redo()); add_child(connections); connections->set_v_size_flags(SIZE_EXPAND_FILL); connections->hide(); diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index a7d7c0145a..275859f528 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -36,6 +36,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/separator.h" bool AbstractPolygon2DEditor::Vertex::operator==(const AbstractPolygon2DEditor::Vertex &p_vertex) const { diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h index 696fd7b637..1fbbe67c8d 100644 --- a/editor/plugins/abstract_polygon_2d_editor.h +++ b/editor/plugins/abstract_polygon_2d_editor.h @@ -36,6 +36,7 @@ #include "scene/gui/box_container.h" class CanvasItemEditor; +class EditorUndoRedoManager; class AbstractPolygon2DEditor : public HBoxContainer { GDCLASS(AbstractPolygon2DEditor, HBoxContainer); @@ -99,7 +100,7 @@ protected: int mode = MODE_EDIT; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; virtual void _menu_option(int p_option); void _wip_changed(); diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index 32d97c65a9..2578099a9f 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_blend_tree.h" StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const { diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h index 9b06f3248f..125a3382fa 100644 --- a/editor/plugins/animation_blend_space_1d_editor.h +++ b/editor/plugins/animation_blend_space_1d_editor.h @@ -40,6 +40,8 @@ #include "scene/gui/separator.h" #include "scene/gui/tree.h" +class EditorUndoRedoManager; + class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin { GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin); @@ -76,7 +78,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin { bool updating = false; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; static AnimationNodeBlendSpace1DEditor *singleton; diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index dc764725dd..c0723cef87 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -39,6 +39,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_blend_tree.h" #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h index 26471df051..df2bcf254d 100644 --- a/editor/plugins/animation_blend_space_2d_editor.h +++ b/editor/plugins/animation_blend_space_2d_editor.h @@ -40,6 +40,8 @@ #include "scene/gui/separator.h" #include "scene/gui/tree.h" +class EditorUndoRedoManager; + class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin { GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin); @@ -82,7 +84,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin { bool updating; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; static AnimationNodeBlendSpace2DEditor *singleton; diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 79be2d04b3..e4f5576d66 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -39,6 +39,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" #include "scene/gui/panel.h" diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h index 18199676b8..af43da6197 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.h +++ b/editor/plugins/animation_blend_tree_editor_plugin.h @@ -41,6 +41,7 @@ class ProgressBar; class EditorFileDialog; +class EditorUndoRedoManager; class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin); @@ -54,7 +55,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { PanelContainer *error_panel = nullptr; Label *error_label = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; AcceptDialog *filter_dialog = nullptr; Tree *filters = nullptr; diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index c36ae1c521..f9e5aa799a 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -32,6 +32,7 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" void AnimationLibraryEditor::set_animation_player(Object *p_player) { player = p_player; @@ -92,7 +93,7 @@ void AnimationLibraryEditor::_add_library_validate(const String &p_name) { void AnimationLibraryEditor::_add_library_confirm() { if (adding_animation) { String anim_name = add_library_name->get_text(); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library); ERR_FAIL_COND(!al.is_valid()); @@ -109,7 +110,7 @@ void AnimationLibraryEditor::_add_library_confirm() { } else { String lib_name = add_library_name->get_text(); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); Ref<AnimationLibrary> al; al.instantiate(); @@ -203,7 +204,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { // TODO: should probably make all foreign animations assigned to this library // unique too. - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name)); undo_redo->add_do_method(player, "remove_animation_library", lib_name); undo_redo->add_do_method(player, "add_animation_library", lib_name, ald); @@ -272,7 +273,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { Ref<Animation> animd = anim->duplicate(); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Make Animation Unique: %s"), anim_name)); undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name); undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, animd); @@ -320,7 +321,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { name = p_path.get_file().get_basename() + " " + itos(attempt); } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), name)); undo_redo->add_do_method(player, "add_animation_library", name, al); @@ -358,7 +359,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { name = p_path.get_file().get_basename() + " " + itos(attempt); } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Load Animation into Library: %s"), name)); undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); @@ -374,7 +375,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { EditorNode::get_singleton()->save_resource_in_path(al, p_path); if (al->get_path() != prev_path) { // Save successful. - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Save Animation library to File: %s"), file_dialog_library)); undo_redo->add_do_method(al.ptr(), "set_path", al->get_path()); @@ -395,7 +396,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { String prev_path = anim->get_path(); EditorNode::get_singleton()->save_resource_in_path(anim, p_path); if (anim->get_path() != prev_path) { // Save successful. - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Save Animation to File: %s"), file_dialog_animation)); undo_redo->add_do_method(anim.ptr(), "set_path", anim->get_path()); @@ -413,7 +414,7 @@ void AnimationLibraryEditor::_item_renamed() { String text = ti->get_text(0); String old_text = ti->get_metadata(0); bool restore_text = false; - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); if (String(text).contains("/") || String(text).contains(":") || String(text).contains(",") || String(text).contains("[")) { restore_text = true; @@ -527,7 +528,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int name = base_name + " (" + itos(attempt) + ")"; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), name)); undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); @@ -553,7 +554,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int file_dialog_library = lib_name; } break; case LIB_BUTTON_DELETE: { - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Remove Animation Library: %s"), lib_name)); undo_redo->add_do_method(player, "remove_animation_library", lib_name); undo_redo->add_undo_method(player, "add_animation_library", lib_name, al); @@ -594,7 +595,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int } break; case ANIM_BUTTON_DELETE: { - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Remove Animation from Library: %s"), anim_name)); undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name); undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 516079673d..f374f48fb2 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -1045,6 +1045,10 @@ void AnimationPlayerEditor::_update_name_dialog_library_dropdown() { } } +void AnimationPlayerEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void AnimationPlayerEditor::edit(AnimationPlayer *p_player) { if (player && pin->is_pressed()) { return; // Ignore, pinned. @@ -1925,7 +1929,7 @@ void AnimationPlayerEditorPlugin::_update_keying() { } void AnimationPlayerEditorPlugin::edit(Object *p_object) { - anim_editor->set_undo_redo(&get_undo_redo()); + anim_editor->set_undo_redo(get_undo_redo()); if (!p_object) { return; } diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 3b1de070fa..a37a9debef 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -41,6 +41,7 @@ #include "scene/gui/texture_button.h" #include "scene/gui/tree.h" +class EditorUndoRedoManager; class AnimationPlayerEditorPlugin; class AnimationPlayerEditor : public VBoxContainer { @@ -100,7 +101,7 @@ class AnimationPlayerEditor : public VBoxContainer { LineEdit *name = nullptr; OptionButton *library = nullptr; Label *name_title = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Ref<Texture2D> autoplay_icon; Ref<Texture2D> reset_icon; @@ -233,7 +234,7 @@ public: void ensure_visibility(); - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void edit(AnimationPlayer *p_player); void forward_force_draw_over_viewport(Control *p_overlay); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 473450b292..ef4ae3dca4 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -39,6 +39,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_blend_tree.h" #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index 165940e639..fdd1af0f6d 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -40,6 +40,7 @@ #include "scene/gui/tree.h" class EditorFileDialog; +class EditorUndoRedoManager; class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { GDCLASS(AnimationNodeStateMachineEditor, AnimationTreeNodeEditorPlugin); @@ -76,7 +77,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { bool updating = false; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; static AnimationNodeStateMachineEditor *singleton; diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp index 9e551ae0ed..d670197c53 100644 --- a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp +++ b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp @@ -31,6 +31,7 @@ #include "audio_stream_randomizer_editor_plugin.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" void AudioStreamRandomizerEditorPlugin::edit(Object *p_object) { } @@ -43,8 +44,8 @@ void AudioStreamRandomizerEditorPlugin::make_visible(bool p_visible) { } void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - ERR_FAIL_COND(!undo_redo); + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(undo_redo.is_null()); AudioStreamRandomizer *randomizer = Object::cast_to<AudioStreamRandomizer>(p_edited); if (!randomizer) { diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index fc70ace331..5682df845e 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -40,6 +40,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_toaster.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" @@ -3988,6 +3989,10 @@ void CanvasItemEditor::_selection_changed() { selected_from_canvas = false; } +void CanvasItemEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void CanvasItemEditor::edit(CanvasItem *p_canvas_item) { Array selection = editor_selection->get_selected_nodes(); if (selection.size() != 1 || Object::cast_to<Node>(selection[0]) != p_canvas_item) { @@ -5419,7 +5424,7 @@ CanvasItemEditor::CanvasItemEditor() { CanvasItemEditor *CanvasItemEditor::singleton = nullptr; void CanvasItemEditorPlugin::edit(Object *p_object) { - canvas_item_editor->set_undo_redo(&get_undo_redo()); + canvas_item_editor->set_undo_redo(EditorNode::get_undo_redo()); canvas_item_editor->edit(Object::cast_to<CanvasItem>(p_object)); } @@ -5572,34 +5577,34 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & Ref<Texture2D> texture = ResourceCache::get_ref(path); if (parent) { - editor_data->get_undo_redo().add_do_method(parent, "add_child", child, true); - editor_data->get_undo_redo().add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene()); - editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child); + editor_data->get_undo_redo()->add_do_method(parent, "add_child", child, true); + editor_data->get_undo_redo()->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene()); + editor_data->get_undo_redo()->add_do_reference(child); + editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", child); } else { // If no parent is selected, set as root node of the scene. - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", child); - editor_data->get_undo_redo().add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene()); - editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child); + editor_data->get_undo_redo()->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene()); + editor_data->get_undo_redo()->add_do_reference(child); + editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); } if (parent) { String new_name = parent->validate_child_name(child); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo().add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); } if (Object::cast_to<TouchScreenButton>(child) || Object::cast_to<TextureButton>(child)) { - editor_data->get_undo_redo().add_do_property(child, "texture_normal", texture); + editor_data->get_undo_redo()->add_do_property(child, "texture_normal", texture); } else { - editor_data->get_undo_redo().add_do_property(child, "texture", texture); + editor_data->get_undo_redo()->add_do_property(child, "texture", texture); } // make visible for certain node type if (Object::cast_to<Control>(child)) { Size2 texture_size = texture->get_size(); - editor_data->get_undo_redo().add_do_property(child, "rect_size", texture_size); + editor_data->get_undo_redo()->add_do_property(child, "rect_size", texture_size); } else if (Object::cast_to<Polygon2D>(child)) { Size2 texture_size = texture->get_size(); Vector<Vector2> list = { @@ -5608,7 +5613,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & Vector2(texture_size.width, texture_size.height), Vector2(0, texture_size.height) }; - editor_data->get_undo_redo().add_do_property(child, "polygon", list); + editor_data->get_undo_redo()->add_do_property(child, "polygon", list); } // Compute the global position @@ -5617,7 +5622,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & // there's nothing to be used as source position so snapping will work as absolute if enabled target_position = canvas_item_editor->snap_point(target_position); - editor_data->get_undo_redo().add_do_method(child, "set_global_position", target_position); + editor_data->get_undo_redo()->add_do_method(child, "set_global_position", target_position); } bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) { @@ -5642,15 +5647,15 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path)); - editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true); - editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", edited_scene); - editor_data->get_undo_redo().add_do_reference(instantiated_scene); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); + editor_data->get_undo_redo()->add_do_method(parent, "add_child", instantiated_scene, true); + editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_owner", edited_scene); + editor_data->get_undo_redo()->add_do_reference(instantiated_scene); + editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", instantiated_scene); 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), path, new_name); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name)); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), path, new_name); + editor_data->get_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); if (instance_ci) { @@ -5664,7 +5669,7 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons // Preserve instance position of the original scene. target_pos += instance_ci->_edit_get_position(); - editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_position", target_pos); + editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_position", target_pos); } return true; @@ -5682,7 +5687,7 @@ void CanvasItemEditorViewport::_perform_drop_data() { Vector<String> error_files; - editor_data->get_undo_redo().create_action(TTR("Create Node")); + editor_data->get_undo_redo()->create_action(TTR("Create Node")); for (int i = 0; i < selected_files.size(); i++) { String path = selected_files[i]; @@ -5713,7 +5718,7 @@ void CanvasItemEditorViewport::_perform_drop_data() { } } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); if (error_files.size() > 0) { String files_str; diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 04fd819dec..2ca495e5d6 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -45,6 +45,7 @@ class EditorData; class CanvasItemEditorViewport; class ViewPanner; +class EditorUndoRedoManager; class CanvasItemEditorSelectedItem : public Object { GDCLASS(CanvasItemEditorSelectedItem, Object); @@ -400,7 +401,7 @@ private: void _prepare_grid_menu(); void _on_grid_menu_id_pressed(int p_id); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true); Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list); @@ -547,7 +548,7 @@ public: Tool get_current_tool() { return tool; } void set_current_tool(Tool p_tool); - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void edit(CanvasItem *p_canvas_item); void focus_selection(); diff --git a/editor/plugins/cast_2d_editor_plugin.cpp b/editor/plugins/cast_2d_editor_plugin.cpp index 18c38e7ab8..a8d255f997 100644 --- a/editor/plugins/cast_2d_editor_plugin.cpp +++ b/editor/plugins/cast_2d_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "canvas_item_editor_plugin.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/2d/ray_cast_2d.h" #include "scene/2d/shape_cast_2d.h" diff --git a/editor/plugins/cast_2d_editor_plugin.h b/editor/plugins/cast_2d_editor_plugin.h index d9c0cc4a06..85ff497bc7 100644 --- a/editor/plugins/cast_2d_editor_plugin.h +++ b/editor/plugins/cast_2d_editor_plugin.h @@ -35,11 +35,12 @@ #include "scene/2d/node_2d.h" class CanvasItemEditor; +class EditorUndoRedoManager; class Cast2DEditor : public Control { GDCLASS(Cast2DEditor, Control); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; CanvasItemEditor *canvas_item_editor = nullptr; Node2D *node; diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index af20064a8d..11992ad10e 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "canvas_item_editor_plugin.h" #include "core/os/keyboard.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/resources/capsule_shape_2d.h" #include "scene/resources/circle_shape_2d.h" #include "scene/resources/concave_polygon_shape_2d.h" diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h index f7de05ddd1..49e0820ae9 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.h +++ b/editor/plugins/collision_shape_2d_editor_plugin.h @@ -35,6 +35,7 @@ #include "scene/2d/collision_shape_2d.h" class CanvasItemEditor; +class EditorUndoRedoManager; class CollisionShape2DEditor : public Control { GDCLASS(CollisionShape2DEditor, Control); @@ -61,7 +62,7 @@ class CollisionShape2DEditor : public Control { Point2(1, -1), }; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; CanvasItemEditor *canvas_item_editor = nullptr; CollisionShape2D *node = nullptr; diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp index ff5d112956..2a12dc0e89 100644 --- a/editor/plugins/control_editor_plugin.cpp +++ b/editor/plugins/control_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/gui/separator.h" diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h index f1b9190a0b..584d05aab0 100644 --- a/editor/plugins/control_editor_plugin.h +++ b/editor/plugins/control_editor_plugin.h @@ -44,6 +44,8 @@ #include "scene/gui/separator.h" #include "scene/gui/texture_rect.h" +class EditorUndoRedoManager; + // Inspector controls. class ControlPositioningWarning : public MarginContainer { GDCLASS(ControlPositioningWarning, MarginContainer); @@ -203,7 +205,7 @@ public: class ControlEditorToolbar : public HBoxContainer { GDCLASS(ControlEditorToolbar, HBoxContainer); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; EditorSelection *editor_selection = nullptr; ControlEditorPopupButton *anchors_button = nullptr; diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index a7c3c32120..e20d298195 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "core/io/image_loader.h" #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/2d/cpu_particles_2d.h" #include "scene/gui/separator.h" #include "scene/resources/particles_material.h" diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h index cc59bc924f..06ca208463 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.h +++ b/editor/plugins/cpu_particles_2d_editor_plugin.h @@ -39,6 +39,7 @@ class EditorPlugin; class SpinBox; class EditorFileDialog; +class EditorUndoRedoManager; class CPUParticles2DEditorPlugin : public EditorPlugin { GDCLASS(CPUParticles2DEditorPlugin, EditorPlugin); @@ -70,7 +71,7 @@ class CPUParticles2DEditorPlugin : public EditorPlugin { String source_emission_file; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _file_selected(const String &p_file); void _menu_callback(int p_idx); void _generate_emission_mask(); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 8aeab684e3..013a9f10a4 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -139,14 +139,14 @@ void CurveEditor::gui_input(const Ref<InputEvent> &p_event) { if (!mb.is_pressed() && _dragging && mb.get_button_index() == MouseButton::LEFT) { _dragging = false; if (_has_undo_data) { - UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); - ur.create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent")); - ur.add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data()); - ur.add_undo_method(*_curve_ref, "_set_data", _undo_data); + ur->create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent")); + ur->add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data()); + ur->add_undo_method(*_curve_ref, "_set_data", _undo_data); // Note: this will trigger one more "changed" signal even if nothing changes, // but it's ok since it would have fired every frame during the drag anyways - ur.commit_action(); + ur->commit_action(); _has_undo_data = false; } @@ -301,13 +301,13 @@ void CurveEditor::on_preset_item_selected(int preset_id) { break; } - UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); - ur.create_action(TTR("Load Curve Preset")); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + ur->create_action(TTR("Load Curve Preset")); - ur.add_do_method(&curve, "_set_data", curve.get_data()); - ur.add_undo_method(&curve, "_set_data", previous_data); + ur->add_do_method(&curve, "_set_data", curve.get_data()); + ur->add_undo_method(&curve, "_set_data", previous_data); - ur.commit_action(); + ur->commit_action(); } void CurveEditor::_curve_changed() { @@ -435,8 +435,8 @@ CurveEditor::TangentIndex CurveEditor::get_tangent_at(Vector2 pos) const { void CurveEditor::add_point(Vector2 pos) { ERR_FAIL_COND(_curve_ref.is_null()); - UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); - ur.create_action(TTR("Remove Curve Point")); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + ur->create_action(TTR("Remove Curve Point")); Vector2 point_pos = get_world_pos(pos); if (point_pos.y < 0.0) { @@ -449,22 +449,22 @@ void CurveEditor::add_point(Vector2 pos) { int i = _curve_ref->add_point(point_pos); _curve_ref->remove_point(i); - ur.add_do_method(*_curve_ref, "add_point", point_pos); - ur.add_undo_method(*_curve_ref, "remove_point", i); + ur->add_do_method(*_curve_ref, "add_point", point_pos); + ur->add_undo_method(*_curve_ref, "remove_point", i); - ur.commit_action(); + ur->commit_action(); } void CurveEditor::remove_point(int index) { ERR_FAIL_COND(_curve_ref.is_null()); - UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); - ur.create_action(TTR("Remove Curve Point")); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + ur->create_action(TTR("Remove Curve Point")); Curve::Point p = _curve_ref->get_point(index); - ur.add_do_method(*_curve_ref, "remove_point", index); - ur.add_undo_method(*_curve_ref, "add_point", p.position, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode); + ur->add_do_method(*_curve_ref, "remove_point", index); + ur->add_undo_method(*_curve_ref, "add_point", p.position, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode); if (index == _selected_point) { set_selected_point(-1); @@ -474,14 +474,14 @@ void CurveEditor::remove_point(int index) { set_hover_point_index(-1); } - ur.commit_action(); + ur->commit_action(); } void CurveEditor::toggle_linear(TangentIndex tangent) { ERR_FAIL_COND(_curve_ref.is_null()); - UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); - ur.create_action(TTR("Toggle Curve Linear Tangent")); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + ur->create_action(TTR("Toggle Curve Linear Tangent")); if (tangent == TANGENT_NONE) { tangent = _selected_tangent; @@ -493,8 +493,8 @@ void CurveEditor::toggle_linear(TangentIndex tangent) { Curve::TangentMode prev_mode = _curve_ref->get_point_left_mode(_selected_point); Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR; - ur.add_do_method(*_curve_ref, "set_point_left_mode", _selected_point, mode); - ur.add_undo_method(*_curve_ref, "set_point_left_mode", _selected_point, prev_mode); + ur->add_do_method(*_curve_ref, "set_point_left_mode", _selected_point, mode); + ur->add_undo_method(*_curve_ref, "set_point_left_mode", _selected_point, prev_mode); } else { bool is_linear = _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR; @@ -502,11 +502,11 @@ void CurveEditor::toggle_linear(TangentIndex tangent) { Curve::TangentMode prev_mode = _curve_ref->get_point_right_mode(_selected_point); Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR; - ur.add_do_method(*_curve_ref, "set_point_right_mode", _selected_point, mode); - ur.add_undo_method(*_curve_ref, "set_point_right_mode", _selected_point, prev_mode); + ur->add_do_method(*_curve_ref, "set_point_right_mode", _selected_point, mode); + ur->add_undo_method(*_curve_ref, "set_point_right_mode", _selected_point, prev_mode); } - ur.commit_action(); + ur->commit_action(); } void CurveEditor::set_selected_point(int index) { diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index 8e6687c836..1487f8b7bc 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "core/io/image_loader.h" #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "scene/2d/cpu_particles_2d.h" #include "scene/gui/separator.h" @@ -111,7 +112,7 @@ void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) { cpu_particles->set_process_mode(particles->get_process_mode()); cpu_particles->set_z_index(particles->get_z_index()); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Convert to CPUParticles2D")); ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", particles, cpu_particles, true, false); ur->add_do_reference(cpu_particles); diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.h b/editor/plugins/gpu_particles_2d_editor_plugin.h index bf49a82166..0229b57c10 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.h +++ b/editor/plugins/gpu_particles_2d_editor_plugin.h @@ -38,6 +38,7 @@ #include "scene/gui/spin_box.h" class EditorFileDialog; +class EditorUndoRedoManager; class GPUParticles2DEditorPlugin : public EditorPlugin { GDCLASS(GPUParticles2DEditorPlugin, EditorPlugin); @@ -75,7 +76,7 @@ class GPUParticles2DEditorPlugin : public EditorPlugin { String source_emission_file; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _file_selected(const String &p_file); void _menu_callback(int p_idx); void _generate_visibility_rect(); diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index 6750f1aa9c..335efd6949 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "core/io/resource_loader.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/scene_tree_dock.h" #include "scene/3d/cpu_particles_3d.h" @@ -271,7 +272,7 @@ void GPUParticles3DEditor::_menu_option(int p_option) { cpu_particles->set_visible(node->is_visible()); cpu_particles->set_process_mode(node->get_process_mode()); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Convert to CPUParticles3D")); ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, cpu_particles, true, false); ur->add_do_reference(cpu_particles); @@ -321,7 +322,7 @@ void GPUParticles3DEditor::_generate_aabb() { node->set_emitting(false); } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Generate Visibility AABB")); ur->add_do_method(node, "set_visibility_aabb", rect); ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb()); diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp index 542aee879b..460178490e 100644 --- a/editor/plugins/gradient_editor_plugin.cpp +++ b/editor/plugins/gradient_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" Size2 GradientEditor::get_minimum_size() const { @@ -55,7 +56,7 @@ void GradientEditor::_gradient_changed() { void GradientEditor::_ramp_changed() { editing = true; - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Gradient Edited"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets()); undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors()); diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp index df45d6c290..6c463f71cf 100644 --- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp +++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/box_container.h" #include "scene/gui/flow_container.h" #include "scene/gui/separator.h" @@ -175,7 +176,7 @@ void GradientTexture2DEditorRect::_notification(int p_what) { } GradientTexture2DEditorRect::GradientTexture2DEditorRect() { - undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo = EditorNode::get_undo_redo(); checkerboard = memnew(TextureRect); checkerboard->set_stretch_mode(TextureRect::STRETCH_TILE); @@ -222,7 +223,7 @@ void GradientTexture2DEditor::_notification(int p_what) { } GradientTexture2DEditor::GradientTexture2DEditor() { - undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo = EditorNode::get_undo_redo(); HFlowContainer *toolbar = memnew(HFlowContainer); add_child(toolbar); diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.h b/editor/plugins/gradient_texture_2d_editor_plugin.h index 93c49b1e6f..9faf33152a 100644 --- a/editor/plugins/gradient_texture_2d_editor_plugin.h +++ b/editor/plugins/gradient_texture_2d_editor_plugin.h @@ -34,6 +34,8 @@ #include "editor/editor_plugin.h" #include "editor/editor_spin_slider.h" +class EditorUndoRedoManager; + class GradientTexture2DEditorRect : public Control { GDCLASS(GradientTexture2DEditorRect, Control); @@ -44,7 +46,7 @@ class GradientTexture2DEditorRect : public Control { }; Ref<GradientTexture2D> texture; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool snap_enabled = false; float snap_size = 0; @@ -74,7 +76,7 @@ class GradientTexture2DEditor : public VBoxContainer { GDCLASS(GradientTexture2DEditor, VBoxContainer); Ref<GradientTexture2D> texture; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Button *reverse_button = nullptr; Button *snap_button = nullptr; diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index 1b4d98fc3f..5d59f62f05 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/subviewport_container.h" #include "scene/resources/fog_material.h" #include "scene/resources/particles_material.h" @@ -261,10 +262,8 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) { } void EditorInspectorPluginMaterial::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - if (!undo_redo) { - return; - } + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(!undo_redo.is_valid()); // For BaseMaterial3D, if a roughness or metallic textures is being assigned to an empty slot, // set the respective metallic or roughness factor to 1.0 as a convenience feature diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 5fb885ad1f..7bd406b869 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" #include "scene/3d/collision_shape_3d.h" #include "scene/3d/navigation_region_3d.h" @@ -60,7 +61,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { switch (p_option) { case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY: { EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); List<Node *> selection = editor_selection->get_selected_node_list(); @@ -147,7 +148,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { Node *owner = get_tree()->get_edited_scene_root(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Create Trimesh Static Shape")); @@ -177,7 +178,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); if (simplify) { ur->create_action(TTR("Create Simplified Convex Shape")); @@ -217,7 +218,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Create Multiple Convex Shapes")); @@ -254,7 +255,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { Node *owner = get_tree()->get_edited_scene_root(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Create Navigation Mesh")); ur->add_do_method(node, "add_child", nmi, true); @@ -311,7 +312,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Unwrap UV2")); ur->add_do_method(node, "set_mesh", unwrapped_mesh); @@ -470,7 +471,7 @@ void MeshInstance3DEditor::_create_outline_mesh() { mi->set_mesh(mesho); Node *owner = get_tree()->get_edited_scene_root(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Create Outline")); diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index e8f143a637..8f1e6c9ec2 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -35,6 +35,7 @@ #include "core/math/geometry_3d.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "scene/3d/audio_listener_3d.h" #include "scene/3d/audio_stream_player_3d.h" @@ -1347,13 +1348,13 @@ void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i light->set_param(p_id == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore); } else if (p_id == 0) { - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Light Radius")); ur->add_do_method(light, "set_param", Light3D::PARAM_RANGE, light->get_param(Light3D::PARAM_RANGE)); ur->add_undo_method(light, "set_param", Light3D::PARAM_RANGE, p_restore); ur->commit_action(); } else if (p_id == 1) { - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Light Radius")); ur->add_do_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, light->get_param(Light3D::PARAM_SPOT_ANGLE)); ur->add_undo_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, p_restore); @@ -1571,7 +1572,7 @@ void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gi player->set_emission_angle(p_restore); } else { - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change AudioStreamPlayer3D Emission Angle")); ur->add_do_method(player, "set_emission_angle", player->get_emission_angle()); ur->add_undo_method(player, "set_emission_angle", p_restore); @@ -1814,7 +1815,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_ if (p_cancel) { camera->set("fov", p_restore); } else { - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Camera FOV")); ur->add_do_property(camera, "fov", camera->get_fov()); ur->add_undo_property(camera, "fov", p_restore); @@ -1825,7 +1826,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_ if (p_cancel) { camera->set("size", p_restore); } else { - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Camera Size")); ur->add_do_property(camera, "size", camera->get_size()); ur->add_undo_property(camera, "size", p_restore); @@ -2141,7 +2142,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Sphere Shape Radius")); ur->add_do_method(so.ptr(), "set_radius", so->get_radius()); ur->add_undo_method(so.ptr(), "set_radius", p_restore); @@ -2155,7 +2156,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Box Shape Size")); ur->add_do_method(bo.ptr(), "set_size", bo->get_size()); ur->add_undo_method(bo.ptr(), "set_size", p_restore); @@ -2169,7 +2170,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Box Shape Size")); ur->add_do_method(qo.ptr(), "set_size", qo->get_size()); ur->add_undo_method(qo.ptr(), "set_size", p_restore); @@ -2870,7 +2871,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Notifier AABB")); ur->add_do_method(notifier, "set_aabb", notifier->get_aabb()); ur->add_undo_method(notifier, "set_aabb", p_restore); @@ -3061,7 +3062,7 @@ void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Particles AABB")); ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb()); ur->add_undo_method(particles, "set_visibility_aabb", p_restore); @@ -3227,7 +3228,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo * return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Radius")); ur->add_do_method(sn, "set_radius", sn->call("get_radius")); ur->add_undo_method(sn, "set_radius", p_restore); @@ -3240,7 +3241,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo * return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Box Shape Extents")); ur->add_do_method(sn, "set_extents", sn->call("get_extents")); ur->add_undo_method(sn, "set_extents", p_restore); @@ -3499,7 +3500,7 @@ void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Probe Extents")); ur->add_do_method(probe, "set_extents", probe->get_extents()); ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset()); @@ -3651,7 +3652,7 @@ void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Decal Extents")); ur->add_do_method(decal, "set_extents", decal->get_extents()); ur->add_undo_method(decal, "set_extents", restore); @@ -3791,7 +3792,7 @@ void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Probe Extents")); ur->add_do_method(probe, "set_extents", probe->get_extents()); ur->add_undo_method(probe, "set_extents", restore); @@ -4406,7 +4407,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Sphere Shape Radius")); ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); ur->add_undo_method(ss.ptr(), "set_radius", p_restore); @@ -4420,7 +4421,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Box Shape Size")); ur->add_do_method(ss.ptr(), "set_size", ss->get_size()); ur->add_undo_method(ss.ptr(), "set_size", p_restore); @@ -4437,7 +4438,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (p_id == 0) { ur->create_action(TTR("Change Capsule Shape Radius")); ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); @@ -4462,7 +4463,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (p_id == 0) { ur->create_action(TTR("Change Cylinder Shape Radius")); ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); @@ -4487,7 +4488,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Separation Ray Shape Length")); ur->add_do_method(ss.ptr(), "set_length", ss->get_length()); ur->add_undo_method(ss.ptr(), "set_length", p_restore); @@ -5745,7 +5746,7 @@ void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Fog Volume Extents")); ur->add_do_method(sn, "set_extents", sn->call("get_extents")); ur->add_undo_method(sn, "set_extents", p_restore); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 6afc6798d0..2798f3d93e 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -4003,15 +4003,15 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path)); } - editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true); - editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene()); - editor_data->get_undo_redo().add_do_reference(instantiated_scene); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); + editor_data->get_undo_redo()->add_do_method(parent, "add_child", instantiated_scene, true); + editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene()); + editor_data->get_undo_redo()->add_do_reference(instantiated_scene); + editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", instantiated_scene); 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", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name); + editor_data->get_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); if (node3d) { @@ -4024,7 +4024,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point)); global_transform.basis *= node3d->get_transform().basis; - editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_global_transform", global_transform); + editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_global_transform", global_transform); } return true; @@ -4035,15 +4035,15 @@ void Node3DEditorViewport::_perform_drop_data() { GeometryInstance3D *geometry_instance = Object::cast_to<GeometryInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target())); MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target())); if (mesh_instance && spatial_editor->get_preview_material_surface() != -1) { - editor_data->get_undo_redo().create_action(vformat(TTR("Set Surface %d Override Material"), spatial_editor->get_preview_material_surface())); - editor_data->get_undo_redo().add_do_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_material()); - editor_data->get_undo_redo().add_undo_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_reset_material()); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(vformat(TTR("Set Surface %d Override Material"), spatial_editor->get_preview_material_surface())); + editor_data->get_undo_redo()->add_do_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_material()); + editor_data->get_undo_redo()->add_undo_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_reset_material()); + editor_data->get_undo_redo()->commit_action(); } else if (geometry_instance) { - editor_data->get_undo_redo().create_action(TTR("Set Material Override")); - editor_data->get_undo_redo().add_do_method(geometry_instance, "set_material_override", spatial_editor->get_preview_material()); - editor_data->get_undo_redo().add_undo_method(geometry_instance, "set_material_override", spatial_editor->get_preview_reset_material()); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(TTR("Set Material Override")); + editor_data->get_undo_redo()->add_do_method(geometry_instance, "set_material_override", spatial_editor->get_preview_material()); + editor_data->get_undo_redo()->add_undo_method(geometry_instance, "set_material_override", spatial_editor->get_preview_reset_material()); + editor_data->get_undo_redo()->commit_action(); } _remove_preview_material(); @@ -4054,7 +4054,7 @@ void Node3DEditorViewport::_perform_drop_data() { Vector<String> error_files; - editor_data->get_undo_redo().create_action(TTR("Create Node")); + editor_data->get_undo_redo()->create_action(TTR("Create Node")); for (int i = 0; i < selected_files.size(); i++) { String path = selected_files[i]; @@ -4072,7 +4072,7 @@ void Node3DEditorViewport::_perform_drop_data() { } } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); if (error_files.size() > 0) { String files_str; @@ -7247,6 +7247,14 @@ Vector<int> Node3DEditor::get_subgizmo_selection() { return ret; } +void Node3DEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + +Ref<EditorUndoRedoManager> Node3DEditor::get_undo_redo() { + return undo_redo; +} + void Node3DEditor::add_control_to_menu_panel(Control *p_control) { context_menu_hbox->add_child(p_control); } diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 4469271a38..e0298ebd5f 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -53,6 +53,7 @@ class Node3DEditorViewport; class SubViewportContainer; class DirectionalLight3D; class WorldEnvironment; +class EditorUndoRedoManager; class ViewportRotationControl : public Control { GDCLASS(ViewportRotationControl, Control); @@ -201,7 +202,7 @@ private: EditorData *editor_data = nullptr; EditorSelection *editor_selection = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; CheckBox *preview_camera = nullptr; SubViewportContainer *subviewport_container = nullptr; @@ -682,7 +683,7 @@ private: HBoxContainer *context_menu_hbox = nullptr; void _generate_selection_boxes(); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; int camera_override_viewport_id; @@ -820,13 +821,13 @@ public: void select_gizmo_highlight_axis(int p_axis); void set_custom_camera(Node *p_camera) { custom_camera = p_camera; } - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } Dictionary get_state() const; void set_state(const Dictionary &p_state); Ref<Environment> get_viewport_environment() { return viewport_environment; } - UndoRedo *get_undo_redo() { return undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); + Ref<EditorUndoRedoManager> get_undo_redo(); void add_control_to_menu_panel(Control *p_control); void remove_control_from_menu_panel(Control *p_control); diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index fd331c4127..1d8a3f5c81 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -36,6 +36,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" void Path2DEditor::_notification(int p_what) { switch (p_what) { diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h index 720f5c090f..13eca79010 100644 --- a/editor/plugins/path_2d_editor_plugin.h +++ b/editor/plugins/path_2d_editor_plugin.h @@ -36,11 +36,12 @@ #include "scene/gui/separator.h" class CanvasItemEditor; +class EditorUndoRedoManager; class Path2DEditor : public HBoxContainer { GDCLASS(Path2DEditor, HBoxContainer); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; CanvasItemEditor *canvas_item_editor = nullptr; Panel *panel = nullptr; diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index 65b15a6001..084c0c2bb0 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -35,6 +35,7 @@ #include "core/os/keyboard.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" #include "scene/resources/curve.h" @@ -172,7 +173,7 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (!p_secondary) { if (p_cancel) { @@ -385,7 +386,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera } } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (closest_seg != -1) { //subdivide @@ -427,21 +428,21 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera // Find the offset and point index of the place to break up. // Also check for the control points. if (dist_to_p < click_dist) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Path Point")); ur->add_do_method(c.ptr(), "remove_point", i); ur->add_undo_method(c.ptr(), "add_point", c->get_point_position(i), c->get_point_in(i), c->get_point_out(i), i); ur->commit_action(); return EditorPlugin::AFTER_GUI_INPUT_STOP; } else if (dist_to_p_out < click_dist) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Out-Control Point")); ur->add_do_method(c.ptr(), "set_point_out", i, Vector3()); ur->add_undo_method(c.ptr(), "set_point_out", i, c->get_point_out(i)); ur->commit_action(); return EditorPlugin::AFTER_GUI_INPUT_STOP; } else if (dist_to_p_in < click_dist) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove In-Control Point")); ur->add_do_method(c.ptr(), "set_point_in", i, Vector3()); ur->add_undo_method(c.ptr(), "set_point_in", i, c->get_point_in(i)); @@ -520,7 +521,7 @@ void Path3DEditorPlugin::_close_curve() { if (c->get_point_position(0) == c->get_point_position(c->get_point_count() - 1)) { return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Close Curve")); ur->add_do_method(c.ptr(), "add_point", c->get_point_position(0), c->get_point_in(0), c->get_point_out(0), -1); ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count()); diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp index 83092f990f..2b3a5c3e23 100644 --- a/editor/plugins/polygon_3d_editor_plugin.cpp +++ b/editor/plugins/polygon_3d_editor_plugin.cpp @@ -38,6 +38,7 @@ #include "core/os/keyboard.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" #include "scene/3d/camera_3d.h" diff --git a/editor/plugins/polygon_3d_editor_plugin.h b/editor/plugins/polygon_3d_editor_plugin.h index e1e1261250..0eb02a39e2 100644 --- a/editor/plugins/polygon_3d_editor_plugin.h +++ b/editor/plugins/polygon_3d_editor_plugin.h @@ -37,11 +37,12 @@ #include "scene/resources/immediate_mesh.h" class CanvasItemEditor; +class EditorUndoRedoManager; class Polygon3DEditor : public HBoxContainer { GDCLASS(Polygon3DEditor, HBoxContainer); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; enum Mode { MODE_CREATE, MODE_EDIT, diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index 4e528ef066..201a3af539 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -234,6 +234,10 @@ void ResourcePreloaderEditor::_cell_button_pressed(Object *p_item, int p_column, } } +void ResourcePreloaderEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void ResourcePreloaderEditor::edit(ResourcePreloader *p_preloader) { preloader = p_preloader; @@ -387,7 +391,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() { } void ResourcePreloaderEditorPlugin::edit(Object *p_object) { - preloader_editor->set_undo_redo(&get_undo_redo()); + preloader_editor->set_undo_redo(EditorNode::get_undo_redo()); ResourcePreloader *s = Object::cast_to<ResourcePreloader>(p_object); if (!s) { return; diff --git a/editor/plugins/resource_preloader_editor_plugin.h b/editor/plugins/resource_preloader_editor_plugin.h index 96cef3de21..ef80283dae 100644 --- a/editor/plugins/resource_preloader_editor_plugin.h +++ b/editor/plugins/resource_preloader_editor_plugin.h @@ -37,6 +37,7 @@ #include "scene/main/resource_preloader.h" class EditorFileDialog; +class EditorUndoRedoManager; class ResourcePreloaderEditor : public PanelContainer { GDCLASS(ResourcePreloaderEditor, PanelContainer); @@ -66,7 +67,7 @@ class ResourcePreloaderEditor : public PanelContainer { void _cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button); void _item_edited(); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; @@ -78,7 +79,7 @@ protected: static void _bind_methods(); public: - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void edit(ResourcePreloader *p_preloader); ResourcePreloaderEditor(); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index c53ac59c11..de13c77e1a 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1408,8 +1408,6 @@ void ScriptEditor::_menu_option(int p_option) { es->set_editor(EditorNode::get_singleton()); es->_run(); - - EditorNode::get_undo_redo()->clear_history(); } break; case FILE_CLOSE: { if (current->is_unsaved()) { diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index 5a1505c232..3dc068a72a 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "canvas_item_editor_plugin.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/2d/mesh_instance_2d.h" #include "scene/gui/box_container.h" #include "thirdparty/misc/clipper.hpp" @@ -59,7 +60,7 @@ void Skeleton2DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Rest Pose to Bones")); for (int i = 0; i < node->get_bone_count(); i++) { Bone2D *bone = node->get_bone(i); @@ -75,7 +76,7 @@ void Skeleton2DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Create Rest Pose from Bones")); for (int i = 0; i < node->get_bone_count(); i++) { Bone2D *bone = node->get_bone(i); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index c453ed26aa..1e4ef217f0 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "node_3d_editor_plugin.h" #include "scene/3d/collision_shape_3d.h" @@ -221,7 +222,7 @@ void Skeleton3DEditor::set_keyable(const bool p_keyable) { }; void Skeleton3DEditor::set_bone_options_enabled(const bool p_bone_options_enabled) { - skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_INIT_SELECTED_POSES, !p_bone_options_enabled); + skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_RESET_SELECTED_POSES, !p_bone_options_enabled); skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_SELECTED_POSES_TO_RESTS, !p_bone_options_enabled); }; @@ -231,12 +232,12 @@ void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) { } switch (p_skeleton_option) { - case SKELETON_OPTION_INIT_ALL_POSES: { - init_pose(true); + case SKELETON_OPTION_RESET_ALL_POSES: { + reset_pose(true); break; } - case SKELETON_OPTION_INIT_SELECTED_POSES: { - init_pose(false); + case SKELETON_OPTION_RESET_SELECTED_POSES: { + reset_pose(false); break; } case SKELETON_OPTION_ALL_POSES_TO_RESTS: { @@ -258,7 +259,7 @@ void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) { } } -void Skeleton3DEditor::init_pose(const bool p_all_bones) { +void Skeleton3DEditor::reset_pose(const bool p_all_bones) { if (!skeleton) { return; } @@ -267,31 +268,25 @@ void Skeleton3DEditor::init_pose(const bool p_all_bones) { return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS); if (p_all_bones) { for (int i = 0; i < bone_len; i++) { - Transform3D rest = skeleton->get_bone_rest(i); - ur->add_do_method(skeleton, "set_bone_pose_position", i, rest.origin); - ur->add_do_method(skeleton, "set_bone_pose_rotation", i, rest.basis.get_rotation_quaternion()); - ur->add_do_method(skeleton, "set_bone_pose_scale", i, rest.basis.get_scale()); ur->add_undo_method(skeleton, "set_bone_pose_position", i, skeleton->get_bone_pose_position(i)); ur->add_undo_method(skeleton, "set_bone_pose_rotation", i, skeleton->get_bone_pose_rotation(i)); ur->add_undo_method(skeleton, "set_bone_pose_scale", i, skeleton->get_bone_pose_scale(i)); } + ur->add_do_method(skeleton, "reset_bone_poses"); } else { // Todo: Do method with multiple bone selection. if (selected_bone == -1) { ur->commit_action(); return; } - Transform3D rest = skeleton->get_bone_rest(selected_bone); - ur->add_do_method(skeleton, "set_bone_pose_position", selected_bone, rest.origin); - ur->add_do_method(skeleton, "set_bone_pose_rotation", selected_bone, rest.basis.get_rotation_quaternion()); - ur->add_do_method(skeleton, "set_bone_pose_scale", selected_bone, rest.basis.get_scale()); ur->add_undo_method(skeleton, "set_bone_pose_position", selected_bone, skeleton->get_bone_pose_position(selected_bone)); ur->add_undo_method(skeleton, "set_bone_pose_rotation", selected_bone, skeleton->get_bone_pose_rotation(selected_bone)); ur->add_undo_method(skeleton, "set_bone_pose_scale", selected_bone, skeleton->get_bone_pose_scale(selected_bone)); + ur->add_do_method(skeleton, "reset_bone_pose", selected_bone); } ur->commit_action(); } @@ -340,7 +335,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) { return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Bone Rest"), UndoRedo::MERGE_ENDS); if (p_all_bones) { for (int i = 0; i < bone_len; i++) { @@ -360,7 +355,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) { } void Skeleton3DEditor::create_physical_skeleton() { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ERR_FAIL_COND(!get_tree()); Node *owner = get_tree()->get_edited_scene_root(); @@ -593,7 +588,7 @@ void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_se Node *node = get_node_or_null(p_skeleton_path); Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); ERR_FAIL_NULL(skeleton); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Bone Parentage")); // If the target is a child of ourselves, we move only *us* and not our children. if (skeleton->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) { @@ -721,8 +716,8 @@ void Skeleton3DEditor::create_editors() { // Skeleton options. PopupMenu *p = skeleton_options->get_popup(); - p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/init_all_poses", TTR("Init all Poses")), SKELETON_OPTION_INIT_ALL_POSES); - p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/init_selected_poses", TTR("Init selected Poses")), SKELETON_OPTION_INIT_SELECTED_POSES); + 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); @@ -1315,7 +1310,7 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c Skeleton3DEditor *se = Skeleton3DEditor::get_singleton(); Node3DEditor *ne = Node3DEditor::get_singleton(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Bone Transform")); if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || ne->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { for (int i = 0; i < p_ids.size(); i++) { diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index 975b54fa77..f51d4e60e8 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -40,6 +40,7 @@ #include "scene/resources/immediate_mesh.h" class EditorInspectorPluginSkeleton; +class EditorUndoRedoManager; class Joint; class PhysicalBone3D; class Skeleton3DEditorPlugin; @@ -63,7 +64,7 @@ class BoneTransformEditor : public VBoxContainer { Skeleton3D *skeleton = nullptr; // String property; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool toggle_enabled = false; bool updating = false; @@ -96,8 +97,8 @@ class Skeleton3DEditor : public VBoxContainer { friend class Skeleton3DEditorPlugin; enum SkeletonOption { - SKELETON_OPTION_INIT_ALL_POSES, - SKELETON_OPTION_INIT_SELECTED_POSES, + SKELETON_OPTION_RESET_ALL_POSES, + SKELETON_OPTION_RESET_SELECTED_POSES, SKELETON_OPTION_ALL_POSES_TO_RESTS, SKELETON_OPTION_SELECTED_POSES_TO_RESTS, SKELETON_OPTION_CREATE_PHYSICAL_SKELETON, @@ -148,7 +149,7 @@ class Skeleton3DEditor : public VBoxContainer { void create_editors(); - void init_pose(const bool p_all_bones); + void reset_pose(const bool p_all_bones); void pose_to_rest(const bool p_all_bones); void insert_keys(const bool p_all_bones); diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index 7d350fd46f..e45c907e86 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "core/math/geometry_2d.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "scene/2d/collision_polygon_2d.h" #include "scene/2d/light_occluder_2d.h" @@ -342,7 +343,7 @@ void Sprite2DEditor::_convert_to_mesh_2d_node() { MeshInstance2D *mesh_instance = memnew(MeshInstance2D); mesh_instance->set_mesh(mesh); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Convert to MeshInstance2D")); ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, mesh_instance, true, false); ur->add_do_reference(mesh_instance); @@ -400,7 +401,7 @@ void Sprite2DEditor::_convert_to_polygon_2d_node() { polygon_2d_instance->set_polygon(polygon); polygon_2d_instance->set_polygons(polys); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Convert to Polygon2D")); ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, polygon_2d_instance, true, false); ur->add_do_reference(polygon_2d_instance); @@ -422,7 +423,7 @@ void Sprite2DEditor::_create_collision_polygon_2d_node() { CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D); collision_polygon_2d_instance->set_polygon(outline); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Create CollisionPolygon2D Sibling")); ur->add_do_method(this, "_add_as_sibling_or_child", node, collision_polygon_2d_instance); ur->add_do_reference(collision_polygon_2d_instance); @@ -455,7 +456,7 @@ void Sprite2DEditor::_create_light_occluder_2d_node() { LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D); light_occluder_2d_instance->set_occluder_polygon(polygon); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Create LightOccluder2D Sibling")); ur->add_do_method(this, "_add_as_sibling_or_child", node, light_occluder_2d_instance); ur->add_do_reference(light_occluder_2d_instance); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index a39d24a167..205fed48b4 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -37,6 +37,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "scene/3d/sprite_3d.h" #include "scene/gui/center_container.h" @@ -1010,6 +1011,10 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) { } } +void SpriteFramesEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { if (!frames->has_animation(edited_anim)) { return false; @@ -1471,7 +1476,7 @@ SpriteFramesEditor::SpriteFramesEditor() { } void SpriteFramesEditorPlugin::edit(Object *p_object) { - frames_editor->set_undo_redo(&get_undo_redo()); + frames_editor->set_undo_redo(get_undo_redo()); SpriteFrames *s; AnimatedSprite2D *animated_sprite = Object::cast_to<AnimatedSprite2D>(p_object); diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index 6352259b73..f2530b732f 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -45,6 +45,7 @@ #include "scene/gui/tree.h" class EditorFileDialog; +class EditorUndoRedoManager; class SpriteFramesEditor : public HSplitContainer { GDCLASS(SpriteFramesEditor, HSplitContainer); @@ -151,7 +152,7 @@ class SpriteFramesEditor : public HSplitContainer { bool updating; bool updating_split_settings = false; // Skip SpinBox/Range callback when setting value by code. - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; @@ -176,7 +177,7 @@ protected: static void _bind_methods(); public: - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void edit(SpriteFrames *p_frames); SpriteFramesEditor(); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 0bd8a8a484..772bae6544 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -36,6 +36,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/check_box.h" #include "scene/gui/separator.h" #include "scene/gui/view_panner.h" diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index a18c87f153..e3bbaf49fc 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -40,6 +40,7 @@ #include "scene/resources/texture.h" class ViewPanner; +class EditorUndoRedoManager; class TextureRegionEditor : public AcceptDialog { GDCLASS(TextureRegionEditor, AcceptDialog); @@ -68,7 +69,7 @@ class TextureRegionEditor : public AcceptDialog { VScrollBar *vscroll = nullptr; HScrollBar *hscroll = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Vector2 draw_ofs; float draw_zoom = 0.0; diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index bbc22c8622..af3959d47c 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_resource_picker.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/progress_dialog.h" #include "scene/gui/color_picker.h" @@ -796,7 +797,7 @@ void ThemeItemImportTree::_import_selected() { ProgressDialog::get_singleton()->end_task("import_theme_items"); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Import Theme Items")); ur->add_do_method(*edited_theme, "clear"); @@ -1494,7 +1495,7 @@ void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_colu String item_name = item->get_text(0); int data_type = item->get_parent()->get_metadata(0); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Theme Item")); ur->add_do_method(*edited_theme, "clear_theme_item", (Theme::DataType)data_type, item_name, edited_item_type); ur->add_undo_method(*edited_theme, "set_theme_item", (Theme::DataType)data_type, item_name, edited_item_type, edited_theme->get_theme_item((Theme::DataType)data_type, item_name, edited_item_type)); @@ -1513,7 +1514,7 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) { const String new_type = edit_add_type_value->get_text().strip_edges(); edit_add_type_value->clear(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Add Theme Type")); ur->add_do_method(*edited_theme, "add_type", new_type); @@ -1525,7 +1526,7 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) { } void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Create Theme Item")); switch (p_data_type) { @@ -1570,7 +1571,7 @@ void ThemeItemEditorDialog::_remove_theme_type(const String &p_theme_type) { Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Theme Type")); new_snapshot->remove_type(p_theme_type); @@ -1593,7 +1594,7 @@ void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type, Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Data Type Items From Theme")); new_snapshot->get_theme_item_list(p_data_type, p_item_type, &names); @@ -1622,7 +1623,7 @@ void ThemeItemEditorDialog::_remove_class_items() { Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Class Items From Theme")); for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { @@ -1658,7 +1659,7 @@ void ThemeItemEditorDialog::_remove_custom_items() { Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Custom Items From Theme")); for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { @@ -1694,7 +1695,7 @@ void ThemeItemEditorDialog::_remove_all_items() { Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove All Items From Theme")); for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { @@ -1798,7 +1799,7 @@ void ThemeItemEditorDialog::_confirm_edit_theme_item() { if (item_popup_mode == CREATE_THEME_ITEM) { _add_theme_item(edit_item_data_type, theme_item_name->get_text(), edited_item_type); } else if (item_popup_mode == RENAME_THEME_ITEM) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Rename Theme Item")); ur->add_do_method(*edited_theme, "rename_theme_item", edit_item_data_type, edit_item_old_name, theme_item_name->get_text(), edited_item_type); @@ -2824,7 +2825,7 @@ void ThemeTypeEditor::_add_default_type_items() { updating = false; - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Override All Default Theme Items")); ur->add_do_method(*edited_theme, "merge_with", new_snapshot); @@ -2844,7 +2845,7 @@ void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) { } String item_name = le->get_text().strip_edges(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Add Theme Item")); switch (p_data_type) { @@ -2889,7 +2890,7 @@ void ThemeTypeEditor::_item_add_lineedit_cbk(String p_value, int p_data_type, Co } void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Override Theme Item")); switch (p_data_type) { @@ -2928,7 +2929,7 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) { } void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Theme Item")); switch (p_data_type) { @@ -3002,7 +3003,7 @@ void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Rename Theme Item")); switch (p_data_type) { @@ -3058,7 +3059,7 @@ void ThemeTypeEditor::_item_rename_canceled(int p_data_type, String p_item_name, } void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Color Item in Theme"), UndoRedo::MERGE_ENDS); ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, p_value); ur->add_undo_method(*edited_theme, "set_color", p_item_name, edited_type, edited_theme->get_color(p_item_name, edited_type)); @@ -3066,7 +3067,7 @@ void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) { } void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Constant Item in Theme")); ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, p_value); ur->add_undo_method(*edited_theme, "set_constant", p_item_name, edited_type, edited_theme->get_constant(p_item_name, edited_type)); @@ -3074,7 +3075,7 @@ void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) } void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Font Size Item in Theme")); ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, p_value); ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type)); @@ -3086,7 +3087,7 @@ void ThemeTypeEditor::_edit_resource_item(Ref<Resource> p_resource, bool p_edit) } void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Font Item in Theme")); ur->add_do_method(*edited_theme, "set_font", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Font>()); @@ -3103,7 +3104,7 @@ void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) } void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Icon Item in Theme")); ur->add_do_method(*edited_theme, "set_icon", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Texture2D>()); @@ -3120,7 +3121,7 @@ void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_n } void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Stylebox Item in Theme")); ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<StyleBox>()); @@ -3163,7 +3164,7 @@ void ThemeTypeEditor::_on_pin_leader_button_pressed(Control *p_editor, String p_ stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource(); } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Pin Stylebox")); ur->add_do_method(this, "_pin_leading_stylebox", p_item_name, stylebox); @@ -3196,7 +3197,7 @@ void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_ } void ThemeTypeEditor::_on_unpin_leader_button_pressed() { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Unpin Stylebox")); ur->add_do_method(this, "_unpin_leading_stylebox"); ur->add_undo_method(this, "_pin_leading_stylebox", leading_stylebox.item_name, leading_stylebox.stylebox); @@ -3265,7 +3266,7 @@ void ThemeTypeEditor::_update_stylebox_from_leading() { } void ThemeTypeEditor::_type_variation_changed(const String p_value) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Theme Type Variation")); if (p_value.is_empty()) { diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp index 3fe6778f48..de4f3f7989 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.cpp +++ b/editor/plugins/tiles/atlas_merging_dialog.cpp @@ -33,6 +33,7 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/control.h" #include "scene/gui/split_container.h" diff --git a/editor/plugins/tiles/atlas_merging_dialog.h b/editor/plugins/tiles/atlas_merging_dialog.h index c54e259594..c7e4635d16 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.h +++ b/editor/plugins/tiles/atlas_merging_dialog.h @@ -38,6 +38,7 @@ #include "scene/resources/tile_set.h" class EditorFileDialog; +class EditorUndoRedoManager; class AtlasMergingDialog : public ConfirmationDialog { GDCLASS(AtlasMergingDialog, ConfirmationDialog); @@ -49,7 +50,7 @@ private: LocalVector<HashMap<Vector2i, Vector2i>> merged_mapping; Ref<TileSet> tile_set; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; // Settings. int next_line_after_column = 30; diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index a00e1ed9e8..b44b6fcc53 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -38,6 +38,7 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" void TileDataEditor::_tile_set_changed_plan_update() { _tile_set_changed_update_needed = true; @@ -248,7 +249,14 @@ void GenericTilePolygonEditor::_zoom_changed() { } void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { - UndoRedo *undo_redo = use_undo_redo ? editor_undo_redo : memnew(UndoRedo); + Ref<EditorUndoRedoManager> undo_redo; + if (use_undo_redo) { + undo_redo = editor_undo_redo; + } else { + // This nice hack allows for discarding undo actions without making code too complex. + undo_redo.instantiate(); + } + switch (p_item_pressed) { case RESET_TO_DEFAULT_TILE: { undo_redo->create_action(TTR("Reset Polygons")); @@ -322,9 +330,6 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { default: break; } - if (!use_undo_redo) { - memdelete(undo_redo); - } } void GenericTilePolygonEditor::_grab_polygon_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_point_index) { @@ -409,7 +414,14 @@ void GenericTilePolygonEditor::_snap_to_half_pixel(Point2 &r_point) { } void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) { - UndoRedo *undo_redo = use_undo_redo ? editor_undo_redo : memnew(UndoRedo); + Ref<EditorUndoRedoManager> undo_redo; + if (use_undo_redo) { + undo_redo = editor_undo_redo; + } else { + // This nice hack allows for discarding undo actions without making code too complex. + undo_redo.instantiate(); + } + real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius"); hovered_polygon_index = -1; @@ -600,10 +612,6 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) } base_control->update(); - - if (!use_undo_redo) { - memdelete(undo_redo); - } } void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) { diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index f9b8948d0a..c1560138b2 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -39,6 +39,8 @@ #include "scene/gui/control.h" #include "scene/gui/label.h" +class EditorUndoRedoManager; + class TileDataEditor : public VBoxContainer { GDCLASS(TileDataEditor, VBoxContainer); @@ -93,7 +95,7 @@ private: bool multiple_polygon_mode = false; bool use_undo_redo = true; - UndoRedo *editor_undo_redo = nullptr; + Ref<EditorUndoRedoManager> editor_undo_redo; // UI int hovered_polygon_index = -1; @@ -214,7 +216,7 @@ private: protected: DummyObject *dummy_object = memnew(DummyObject); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; StringName type; String property; @@ -279,7 +281,7 @@ private: virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override; protected: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; virtual void _tile_set_changed() override; @@ -314,7 +316,7 @@ class TileDataCollisionEditor : public TileDataDefaultEditor { virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override; protected: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; virtual void _tile_set_changed() override; @@ -366,7 +368,7 @@ protected: void _notification(int p_what); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; public: virtual Control *get_toolbar() override { return toolbar; }; @@ -399,7 +401,7 @@ private: virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override; protected: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; virtual void _tile_set_changed() override; diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 1bf24a7393..3f355a1ed2 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/2d/camera_2d.h" @@ -3697,8 +3698,8 @@ void TileMapEditor::_update_layers_selection() { } void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - ERR_FAIL_COND(!undo_redo); + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(undo_redo.is_null()); TileMap *tile_map = Object::cast_to<TileMap>(p_edited); if (!tile_map) { diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h index 605fbe4823..9a47d8bbc4 100644 --- a/editor/plugins/tiles/tile_map_editor.h +++ b/editor/plugins/tiles/tile_map_editor.h @@ -47,7 +47,7 @@ #include "scene/gui/tab_bar.h" #include "scene/gui/tree.h" -class UndoRedo; +class EditorUndoRedoManager; class TileMapEditorPlugin : public Object { public: @@ -70,7 +70,7 @@ class TileMapEditorTilesPlugin : public TileMapEditorPlugin { GDCLASS(TileMapEditorTilesPlugin, TileMapEditorPlugin); private: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; ObjectID tile_map_id; int tile_map_layer = -1; virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override; @@ -223,7 +223,7 @@ class TileMapEditorTerrainsPlugin : public TileMapEditorPlugin { GDCLASS(TileMapEditorTerrainsPlugin, TileMapEditorPlugin); private: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; ObjectID tile_map_id; int tile_map_layer = -1; virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override; @@ -317,7 +317,7 @@ class TileMapEditor : public VBoxContainer { GDCLASS(TileMapEditor, VBoxContainer); private: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool tileset_changed_needs_update = false; ObjectID tile_map_id; int tile_map_layer = -1; diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp index 12e1615484..9e4c29fa79 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, Object *p_item_list, MouseButton p_mouse_button_index) { if (p_mouse_button_index != MouseButton::RIGHT) { diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.h b/editor/plugins/tiles/tile_proxies_manager_dialog.h index 44de708898..511e442a10 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.h +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.h @@ -43,7 +43,7 @@ private: int commited_actions_count = 0; Ref<TileSet> tile_set; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; TileMapCell from; TileMapCell to; diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 6950f57a00..09722d3d65 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -2058,14 +2058,16 @@ void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what) } void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - ERR_FAIL_COND(!undo_redo); + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(!undo_redo.is_valid()); #define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property)); - undo_redo->start_force_keep_in_merge_ends(); AtlasTileProxyObject *tile_data_proxy = Object::cast_to<AtlasTileProxyObject>(p_edited); if (tile_data_proxy) { + UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(tile_data_proxy).undo_redo; + internal_undo_redo->start_force_keep_in_merge_ends(); + Vector<String> components = String(p_property).split("/", true, 2); if (components.size() == 2 && components[1] == "polygons_count") { int layer_index = components[0].trim_prefix("physics_layer_").to_int(); @@ -2088,6 +2090,7 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo } } } + internal_undo_redo->end_force_keep_in_merge_ends(); } TileSetAtlasSourceProxyObject *atlas_source_proxy = Object::cast_to<TileSetAtlasSourceProxyObject>(p_edited); @@ -2095,6 +2098,9 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo TileSetAtlasSource *atlas_source = atlas_source_proxy->get_edited(); ERR_FAIL_COND(!atlas_source); + UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(atlas_source).undo_redo; + internal_undo_redo->start_force_keep_in_merge_ends(); + PackedVector2Array arr; if (p_property == "texture") { arr = atlas_source->get_tiles_to_be_removed_on_change(p_new_value, atlas_source->get_margins(), atlas_source->get_separation(), atlas_source->get_texture_region_size()); @@ -2121,8 +2127,8 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo } } } + internal_undo_redo->end_force_keep_in_merge_ends(); } - undo_redo->end_force_keep_in_merge_ends(); #undef ADD_UNDO } diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h index 738fe1044d..badb702e29 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.h +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h @@ -114,7 +114,7 @@ private: TileSetAtlasSource *tile_set_atlas_source = nullptr; int tile_set_atlas_source_id = TileSet::INVALID_SOURCE; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool tile_set_changed_needs_update = false; diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 81804710b4..8d04dd3121 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -36,6 +36,7 @@ #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/box_container.h" #include "scene/gui/control.h" @@ -405,8 +406,8 @@ void TileSetEditor::_tab_changed(int p_tab_changed) { } void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - ERR_FAIL_COND(!undo_redo); + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(undo_redo.is_null()); TileSet *tile_set = Object::cast_to<TileSet>(p_edited); if (!tile_set) { @@ -586,8 +587,8 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_ } void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - ERR_FAIL_COND(!undo_redo); + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(undo_redo.is_null()); #define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property)); TileSet *tile_set = Object::cast_to<TileSet>(p_edited); diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h index c45240043e..3b9b80dac4 100644 --- a/editor/plugins/tiles/tile_set_editor.h +++ b/editor/plugins/tiles/tile_set_editor.h @@ -39,6 +39,8 @@ #include "tile_set_atlas_source_editor.h" #include "tile_set_scenes_collection_source_editor.h" +class EditorUndoRedoManager; + class TileSetEditor : public VBoxContainer { GDCLASS(TileSetEditor, VBoxContainer); @@ -58,7 +60,7 @@ private: TileSetAtlasSourceEditor *tile_set_atlas_source_editor = nullptr; TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h index 77a583e522..0284b45c0f 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h @@ -97,7 +97,7 @@ private: TileSetScenesCollectionSource *tile_set_scenes_collection_source = nullptr; int tile_set_source_id = -1; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool tile_set_scenes_collection_source_changed_needs_update = false; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index cf24095582..961f092650 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -40,6 +40,7 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/curve_editor_plugin.h" #include "editor/plugins/shader_editor_plugin.h" #include "scene/animation/animation_player.h" @@ -4063,7 +4064,7 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, bool type_changed = next_input_type != prev_input_type; - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Visual Shader Input Type Changed")); undo_redo->add_do_method(p_input.ptr(), "set_input_name", p_name); @@ -4132,7 +4133,7 @@ void VisualShaderEditor::_uniform_select_item(Ref<VisualShaderNodeUniformRef> p_ bool type_changed = p_uniform_ref->get_uniform_type_by_name(p_name) != p_uniform_ref->get_uniform_type_by_name(prev_name); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("UniformRef Name Changed")); undo_redo->add_do_method(p_uniform_ref.ptr(), "set_uniform_name", p_name); @@ -4176,7 +4177,7 @@ void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_var bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid(); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Varying Name Changed")); undo_redo->add_do_method(p_varying.ptr(), "set_varying_name", p_name); @@ -5668,7 +5669,7 @@ VisualShaderEditor::VisualShaderEditor() { _update_options_menu(); - undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo = EditorNode::get_undo_redo(); Ref<VisualShaderNodePluginDefault> default_plugin; default_plugin.instantiate(); @@ -5876,7 +5877,7 @@ public: return; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); updating = true; undo_redo->create_action(TTR("Edit Visual Property:") + " " + p_property, UndoRedo::MERGE_ENDS); @@ -6078,7 +6079,7 @@ void EditorPropertyVisualShaderMode::_option_selected(int p_which) { return; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Visual Shader Mode Changed")); //do is easy undo_redo->add_do_method(visual_shader.ptr(), "set_mode", p_which); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index b6a3b43754..ede6513b83 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -48,6 +48,7 @@ class TextEdit; class Tree; class VisualShaderEditor; +class EditorUndoRedoManager; class VisualShaderNodePlugin : public RefCounted { GDCLASS(VisualShaderNodePlugin, RefCounted); @@ -192,7 +193,7 @@ class VisualShaderEditor : public VBoxContainer { PanelContainer *error_panel = nullptr; Label *error_label = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Point2 saved_node_pos; bool saved_node_pos_dirty = false; diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index 924b735012..a302adc34e 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -1606,8 +1606,8 @@ public: RegEx reg_is_empty = RegEx("\\bempty\\("); RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])"); RegEx reg_json_to = RegEx("\\bto_json\\b"); - RegEx reg_json_parse = RegEx("([\t]{0,})([^\n]+)parse_json\\(([^\n]+)"); - RegEx reg_json_non_new = RegEx("([\t]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)"); + RegEx reg_json_parse = RegEx("([\t ]{0,})([^\n]+)parse_json\\(([^\n]+)"); + RegEx reg_json_non_new = RegEx("([\t ]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)"); RegEx reg_export = RegEx("export\\(([a-zA-Z0-9_]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)"); RegEx reg_export_advanced = RegEx("export\\(([^)^\n]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)([^\n]+)"); RegEx reg_setget_setget = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*,[ \t]*([a-zA-Z0-9_]+)"); @@ -2102,6 +2102,8 @@ bool ProjectConverter3To4::test_conversion(const RegExContainer ®_container) valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,D) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,[D,E]) != OK):", "(connect(A,Callable(B,C).bind(D,E)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,[D,E],F) != OK):", "(connect(A,Callable(B,C).bind(D,E),F) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid & test_conversion_single_additional_builtin("(start(A,B) != OK):", "(start(Callable(A,B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); @@ -2441,6 +2443,21 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) { } break; }; + case '[': { + parts_counter++; + if (parts_counter == 1 && !is_inside_string) { + start_part = current_index; + } + break; + }; + case ']': { + parts_counter--; + if (parts_counter == 0 && !is_inside_string) { + parts.append(line.substr(start_part, current_index - start_part)); + start_part = current_index; + } + break; + }; case ',': { if (parts_counter == 1 && !is_inside_string) { parts.append(line.substr(start_part + 1, current_index - start_part - 1)); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 9d2dcd129c..46eb7ac17c 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -47,6 +47,7 @@ #include "editor/editor_settings.h" #include "editor/editor_themes.h" #include "editor/editor_vcs_interface.h" +#include "main/main.h" #include "scene/gui/center_container.h" #include "scene/gui/line_edit.h" #include "scene/gui/margin_container.h" @@ -2115,27 +2116,15 @@ void ProjectManager::_open_selected_projects() { List<String> args; + for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) { + args.push_back(a); + } + args.push_back("--path"); args.push_back(path); args.push_back("--editor"); - if (OS::get_singleton()->is_stdout_debug_enabled()) { - args.push_back("--debug"); - } - - if (OS::get_singleton()->is_stdout_verbose()) { - args.push_back("--verbose"); - } - - if (OS::get_singleton()->is_disable_crash_handler()) { - args.push_back("--disable-crash-handler"); - } - - if (OS::get_singleton()->is_single_window()) { - args.push_back("--single-window"); - } - Error err = OS::get_singleton()->create_instance(args); ERR_FAIL_COND(err); } @@ -2248,13 +2237,13 @@ void ProjectManager::_run_project_confirm() { List<String> args; + for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_PROJECT)) { + args.push_back(a); + } + args.push_back("--path"); args.push_back(path); - if (OS::get_singleton()->is_disable_crash_handler()) { - args.push_back("--disable-crash-handler"); - } - Error err = OS::get_singleton()->create_instance(args); ERR_FAIL_COND(err); } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index ca5eeaa787..581315d512 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "servers/movie_writer/movie_writer.h" ProjectSettingsEditor *ProjectSettingsEditor::singleton = nullptr; @@ -566,7 +567,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { set_title(TTR("Project Settings (project.godot)")); ps = ProjectSettings::get_singleton(); - undo_redo = &p_data->get_undo_redo(); + undo_redo = p_data->get_undo_redo(); data = p_data; tab_container = memnew(TabContainer); @@ -625,7 +626,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { custom_properties->add_child(del_button); general_settings_inspector = memnew(SectionedInspector); - general_settings_inspector->get_inspector()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo()); + general_settings_inspector->get_inspector()->set_undo_redo(EditorNode::get_undo_redo()); general_settings_inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL); general_settings_inspector->register_search_box(search_box); general_settings_inspector->get_inspector()->set_use_filter(true); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index c2d2c2d8f4..040d992e40 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -32,7 +32,6 @@ #define PROJECT_SETTINGS_EDITOR_H #include "core/config/project_settings.h" -#include "core/object/undo_redo.h" #include "editor/action_map_editor.h" #include "editor/editor_autoload_settings.h" #include "editor/editor_data.h" @@ -43,6 +42,7 @@ #include "editor/shader_globals_editor.h" #include "scene/gui/tab_container.h" +class EditorUndoRedoManager; class FileSystemDock; class ProjectSettingsEditor : public AcceptDialog { @@ -77,7 +77,7 @@ class ProjectSettingsEditor : public AcceptDialog { ImportDefaultsEditor *import_defaults_editor = nullptr; EditorData *data = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _advanced_toggled(bool p_button_pressed); void _update_advanced(bool p_is_advanced); diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 665aca6a37..84923a94a2 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -38,6 +38,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_themes.h" +#include "editor/editor_undo_redo_manager.h" #include "modules/regex/regex.h" #include "plugins/script_editor_plugin.h" #include "scene/gui/control.h" @@ -45,7 +46,7 @@ #include "scene/gui/separator.h" #include "scene/gui/tab_container.h" -RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_undo_redo) { +RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoRedoManager> p_undo_redo) { scene_tree_editor = p_scene_tree_editor; undo_redo = p_undo_redo; preview_node = nullptr; @@ -581,7 +582,7 @@ void RenameDialog::rename() { // Forward recursive as opposed to the actual renaming. _iterate_scene(root_node, selected_node_list, &global_count); - if (undo_redo && !to_rename.is_empty()) { + if (undo_redo.is_valid() && !to_rename.is_empty()) { undo_redo->create_action(TTR("Batch Rename")); // Make sure to iterate reversed so that child nodes will find parents. diff --git a/editor/rename_dialog.h b/editor/rename_dialog.h index f3a850045e..dac73b13b8 100644 --- a/editor/rename_dialog.h +++ b/editor/rename_dialog.h @@ -34,7 +34,6 @@ #include "modules/modules_enabled.gen.h" // For regex. #ifdef MODULE_REGEX_ENABLED -#include "core/object/undo_redo.h" #include "editor/scene_tree_editor.h" #include "scene/gui/check_box.h" #include "scene/gui/check_button.h" @@ -43,6 +42,8 @@ #include "scene/gui/spin_box.h" #include "scene/gui/tab_container.h" +class EditorUndoRedoManager; + class RenameDialog : public ConfirmationDialog { GDCLASS(RenameDialog, ConfirmationDialog); @@ -63,7 +64,7 @@ class RenameDialog : public ConfirmationDialog { static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type); SceneTreeEditor *scene_tree_editor = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; int global_count = 0; LineEdit *lne_search = nullptr; @@ -109,7 +110,7 @@ public: void reset(); void rename(); - RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_undo_redo = nullptr); + RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoRedoManager> p_undo_redo = Ref<EditorUndoRedoManager>()); ~RenameDialog() {} }; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 0f4f3dcfcf..9f80119c35 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -222,28 +222,28 @@ 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("Instance Scene(s)")); for (int i = 0; i < instances.size(); i++) { Node *instantiated_scene = instances[i]; - editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true); + editor_data->get_undo_redo()->add_do_method(parent, "add_child", instantiated_scene, true); if (p_pos >= 0) { - editor_data->get_undo_redo().add_do_method(parent, "move_child", instantiated_scene, p_pos + i); + editor_data->get_undo_redo()->add_do_method(parent, "move_child", instantiated_scene, p_pos + i); } - editor_data->get_undo_redo().add_do_method(instantiated_scene, "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", instantiated_scene); - editor_data->get_undo_redo().add_do_reference(instantiated_scene); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); + editor_data->get_undo_redo()->add_do_method(instantiated_scene, "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", instantiated_scene); + editor_data->get_undo_redo()->add_do_reference(instantiated_scene); + editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", instantiated_scene); 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_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name))); + 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_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name))); } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); _push_item(instances[instances.size() - 1]); for (int i = 0; i < instances.size(); i++) { emit_signal(SNAME("node_created"), instances[i]); @@ -265,7 +265,7 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) return; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Replace with Branch Scene")); Node *parent = base->get_parent(); @@ -510,9 +510,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } if (selected) { - create_dialog->popup_create(false, true, selected->get_class()); + create_dialog->popup_create(false, true, selected->get_class(), selected->get_name()); } - } break; case TOOL_EXTEND_SCRIPT: { attach_script_to_selected(true); @@ -531,23 +530,23 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { return; } - editor_data->get_undo_redo().create_action(TTR("Detach Script")); - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "push_item", (Script *)nullptr); + editor_data->get_undo_redo()->create_action(TTR("Detach Script"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "push_item", (Script *)nullptr); for (int i = 0; i < selection.size(); i++) { Node *n = Object::cast_to<Node>(selection[i]); Ref<Script> existing = n->get_script(); Ref<Script> empty = EditorNode::get_singleton()->get_object_custom_type_base(n); if (existing != empty) { - editor_data->get_undo_redo().add_do_method(n, "set_script", empty); - editor_data->get_undo_redo().add_undo_method(n, "set_script", existing); + editor_data->get_undo_redo()->add_do_method(n, "set_script", empty); + editor_data->get_undo_redo()->add_undo_method(n, "set_script", existing); } } - editor_data->get_undo_redo().add_do_method(this, "_update_script_button"); - editor_data->get_undo_redo().add_undo_method(this, "_update_script_button"); + editor_data->get_undo_redo()->add_do_method(this, "_update_script_button"); + editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button"); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); } break; case TOOL_MOVE_UP: case TOOL_MOVE_DOWN: { @@ -602,10 +601,10 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } if (selection.size() == 1) { - editor_data->get_undo_redo().create_action(TTR("Move Node In Parent")); + editor_data->get_undo_redo()->create_action(TTR("Move Node In Parent")); } if (selection.size() > 1) { - editor_data->get_undo_redo().create_action(TTR("Move Nodes In Parent")); + editor_data->get_undo_redo()->create_action(TTR("Move Nodes In Parent")); } for (int i = 0; i < selection.size(); i++) { @@ -618,11 +617,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { int bottom_node_pos = bottom_node->get_index(); int top_node_pos_next = top_node->get_index() + (MOVING_DOWN ? 1 : -1); - editor_data->get_undo_redo().add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next); - editor_data->get_undo_redo().add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos); + editor_data->get_undo_redo()->add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next); + editor_data->get_undo_redo()->add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos); } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); } break; case TOOL_DUPLICATE: { @@ -650,8 +649,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; } - editor_data->get_undo_redo().create_action(TTR("Duplicate Node(s)")); - editor_data->get_undo_redo().add_do_method(editor_selection, "clear"); + editor_data->get_undo_redo()->create_action(TTR("Duplicate Node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get()); + editor_data->get_undo_redo()->add_do_method(editor_selection, "clear"); Node *dupsingle = nullptr; @@ -676,28 +675,28 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { dup->set_name(parent->validate_child_name(dup)); - editor_data->get_undo_redo().add_do_method(add_below_node, "add_sibling", dup, true); + editor_data->get_undo_redo()->add_do_method(add_below_node, "add_sibling", dup, true); for (Node *F : owned) { if (!duplimap.has(F)) { continue; } Node *d = duplimap[F]; - editor_data->get_undo_redo().add_do_method(d, "set_owner", node->get_owner()); + editor_data->get_undo_redo()->add_do_method(d, "set_owner", node->get_owner()); } - editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", dup); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", dup); - editor_data->get_undo_redo().add_do_reference(dup); + editor_data->get_undo_redo()->add_do_method(editor_selection, "add_node", dup); + editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", dup); + editor_data->get_undo_redo()->add_do_reference(dup); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo().add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name()); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(dup->get_name()))); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name()); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(dup->get_name()))); add_below_node = dup; } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); if (dupsingle) { _push_item(dupsingle); @@ -766,29 +765,29 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { return; } - editor_data->get_undo_redo().create_action(TTR("Make node as Root")); - editor_data->get_undo_redo().add_do_method(node->get_parent(), "remove_child", node); - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", node); - editor_data->get_undo_redo().add_do_method(node, "add_child", root, true); - editor_data->get_undo_redo().add_do_method(node, "set_scene_file_path", root->get_scene_file_path()); - editor_data->get_undo_redo().add_do_method(root, "set_scene_file_path", String()); - editor_data->get_undo_redo().add_do_method(node, "set_owner", (Object *)nullptr); - editor_data->get_undo_redo().add_do_method(root, "set_owner", node); + editor_data->get_undo_redo()->create_action(TTR("Make node as Root")); + editor_data->get_undo_redo()->add_do_method(node->get_parent(), "remove_child", node); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", node); + editor_data->get_undo_redo()->add_do_method(node, "add_child", root, true); + editor_data->get_undo_redo()->add_do_method(node, "set_scene_file_path", root->get_scene_file_path()); + editor_data->get_undo_redo()->add_do_method(root, "set_scene_file_path", String()); + editor_data->get_undo_redo()->add_do_method(node, "set_owner", (Object *)nullptr); + editor_data->get_undo_redo()->add_do_method(root, "set_owner", node); _node_replace_owner(root, root, node, MODE_DO); - editor_data->get_undo_redo().add_undo_method(root, "set_scene_file_path", root->get_scene_file_path()); - editor_data->get_undo_redo().add_undo_method(node, "set_scene_file_path", String()); - editor_data->get_undo_redo().add_undo_method(node, "remove_child", root); - editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", root); - editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node, true); - editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, node->get_index()); - editor_data->get_undo_redo().add_undo_method(root, "set_owner", (Object *)nullptr); - editor_data->get_undo_redo().add_undo_method(node, "set_owner", root); + editor_data->get_undo_redo()->add_undo_method(root, "set_scene_file_path", root->get_scene_file_path()); + editor_data->get_undo_redo()->add_undo_method(node, "set_scene_file_path", String()); + editor_data->get_undo_redo()->add_undo_method(node, "remove_child", root); + editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", root); + editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "add_child", node, true); + editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "move_child", node, node->get_index()); + editor_data->get_undo_redo()->add_undo_method(root, "set_owner", (Object *)nullptr); + editor_data->get_undo_redo()->add_undo_method(node, "set_owner", root); _node_replace_owner(root, root, root, MODE_UNDO); - editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().add_undo_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree"); + editor_data->get_undo_redo()->add_undo_method(scene_tree, "update_tree"); + editor_data->get_undo_redo()->commit_action(); } break; case TOOL_MULTI_EDIT: { if (!profile_allow_editing) { @@ -1009,7 +1008,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Node *node = e->get(); if (node) { Node *root = EditorNode::get_singleton()->get_edited_scene(); - UndoRedo *undo_redo = &editor_data->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo(); if (!root) { break; } @@ -1072,7 +1071,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { List<Node *> selection = editor_selection->get_selected_node_list(); List<Node *>::Element *e = selection.front(); if (e) { - UndoRedo *undo_redo = &editor_data->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo(); Node *node = e->get(); bool enabled = node->is_unique_name_in_owner(); if (!enabled && get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(node->get_name())) != nullptr) { @@ -1161,19 +1160,19 @@ void SceneTreeDock::_property_selected(int p_idx) { } void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, Ref<Resource> p_res) { - editor_data->get_undo_redo().create_action(vformat(TTR("Set %s"), p_property)); - editor_data->get_undo_redo().add_do_property(p_node, p_property, p_res); - editor_data->get_undo_redo().add_undo_property(p_node, p_property, p_node->get(p_property)); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(vformat(TTR("Set %s"), p_property)); + editor_data->get_undo_redo()->add_do_property(p_node, p_property, p_res); + editor_data->get_undo_redo()->add_undo_property(p_node, p_property, p_node->get(p_property)); + editor_data->get_undo_redo()->commit_action(); } void SceneTreeDock::add_root_node(Node *p_node) { - editor_data->get_undo_redo().create_action(TTR("New Scene Root")); - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node); - editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().add_do_reference(p_node); - editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action_for_history(TTR("New Scene Root"), editor_data->get_current_edited_scene_history_id()); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node); + editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree"); + editor_data->get_undo_redo()->add_do_reference(p_node); + editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); + editor_data->get_undo_redo()->commit_action(); } void SceneTreeDock::_node_collapsed(Object *p_obj) { @@ -1335,7 +1334,7 @@ void SceneTreeDock::_notification(int p_what) { void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root, ReplaceOwnerMode p_mode) { if (p_node->get_owner() == p_base && p_node != p_root) { - UndoRedo *undo_redo = &editor_data->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo(); switch (p_mode) { case MODE_BIDI: { bool disable_unique = p_node->is_unique_name_in_owner() && p_root->get_node_or_null(UNIQUE_NODE_PREFIX + String(p_node->get_name())) != nullptr; @@ -1568,8 +1567,8 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath> Variant old_variant = p_base->get(propertyname); Variant updated_variant = old_variant; if (_check_node_path_recursive(p_base, updated_variant, p_renames)) { - editor_data->get_undo_redo().add_do_property(p_base, propertyname, updated_variant); - editor_data->get_undo_redo().add_undo_property(p_base, propertyname, old_variant); + editor_data->get_undo_redo()->add_do_property(p_base, propertyname, updated_variant); + editor_data->get_undo_redo()->add_undo_property(p_base, propertyname, old_variant); p_base->set(propertyname, updated_variant); } } @@ -1627,12 +1626,12 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath> ERR_FAIL_COND(!EI); //another bug } - editor_data->get_undo_redo().add_do_method(anim.ptr(), "remove_track", idx); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", idx, track_np); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i)); + editor_data->get_undo_redo()->add_do_method(anim.ptr(), "remove_track", idx); + editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx); + editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_path", idx, track_np); + editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i)); for (int j = 0; j < anim->track_get_key_count(i); j++) { - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j)); + editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j)); } ran.erase(i); //byebye channel @@ -1645,8 +1644,8 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath> if (new_path == track_np) { continue; //bleh } - editor_data->get_undo_redo().add_do_method(anim.ptr(), "track_set_path", i, new_path); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", i, track_np); + editor_data->get_undo_redo()->add_do_method(anim.ptr(), "track_set_path", i, new_path); + editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_path", i, track_np); } } } @@ -1780,7 +1779,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V // Sort by tree order, so re-adding is easy. p_nodes.sort_custom<Node::Comparator>(); - editor_data->get_undo_redo().create_action(TTR("Reparent Node")); + editor_data->get_undo_redo()->create_action(TTR("Reparent Node")); HashMap<Node *, NodePath> path_renames; Vector<StringName> former_names; @@ -1805,11 +1804,11 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V inc--; // If the child will generate a gap when moved, adjust. } - editor_data->get_undo_redo().add_do_method(node->get_parent(), "remove_child", node); - editor_data->get_undo_redo().add_do_method(new_parent, "add_child", node, true); + editor_data->get_undo_redo()->add_do_method(node->get_parent(), "remove_child", node); + editor_data->get_undo_redo()->add_do_method(new_parent, "add_child", node, true); if (p_position_in_parent >= 0) { - editor_data->get_undo_redo().add_do_method(new_parent, "move_child", node, p_position_in_parent + inc); + editor_data->get_undo_redo()->add_do_method(new_parent, "move_child", node, p_position_in_parent + inc); } EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); @@ -1839,29 +1838,29 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V } } - editor_data->get_undo_redo().add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).plus_file(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index()); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).plus_file(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index()); if (p_keep_global_xform) { if (Object::cast_to<Node2D>(node)) { - editor_data->get_undo_redo().add_do_method(node, "set_global_transform", Object::cast_to<Node2D>(node)->get_global_transform()); + editor_data->get_undo_redo()->add_do_method(node, "set_global_transform", Object::cast_to<Node2D>(node)->get_global_transform()); } if (Object::cast_to<Node3D>(node)) { - editor_data->get_undo_redo().add_do_method(node, "set_global_transform", Object::cast_to<Node3D>(node)->get_global_transform()); + editor_data->get_undo_redo()->add_do_method(node, "set_global_transform", Object::cast_to<Node3D>(node)->get_global_transform()); } if (Object::cast_to<Control>(node)) { - editor_data->get_undo_redo().add_do_method(node, "set_global_position", Object::cast_to<Control>(node)->get_global_position()); + editor_data->get_undo_redo()->add_do_method(node, "set_global_position", Object::cast_to<Control>(node)->get_global_position()); } } - editor_data->get_undo_redo().add_do_method(this, "_set_owners", edited_scene, owners); + editor_data->get_undo_redo()->add_do_method(this, "_set_owners", edited_scene, owners); if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) { - editor_data->get_undo_redo().add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node); + editor_data->get_undo_redo()->add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node); } - editor_data->get_undo_redo().add_undo_method(new_parent, "remove_child", node); - editor_data->get_undo_redo().add_undo_method(node, "set_name", former_names[ni]); + editor_data->get_undo_redo()->add_undo_method(new_parent, "remove_child", node); + editor_data->get_undo_redo()->add_undo_method(node, "set_name", former_names[ni]); inc++; } @@ -1879,29 +1878,29 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V int child_pos = node->get_index(); - editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node, true); - editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, child_pos); - editor_data->get_undo_redo().add_undo_method(this, "_set_owners", edited_scene, owners); + editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "add_child", node, true); + editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "move_child", node, child_pos); + editor_data->get_undo_redo()->add_undo_method(this, "_set_owners", edited_scene, owners); if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) { - editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node); + editor_data->get_undo_redo()->add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node); } if (p_keep_global_xform) { if (Object::cast_to<Node2D>(node)) { - editor_data->get_undo_redo().add_undo_method(node, "set_transform", Object::cast_to<Node2D>(node)->get_transform()); + editor_data->get_undo_redo()->add_undo_method(node, "set_transform", Object::cast_to<Node2D>(node)->get_transform()); } if (Object::cast_to<Node3D>(node)) { - editor_data->get_undo_redo().add_undo_method(node, "set_transform", Object::cast_to<Node3D>(node)->get_transform()); + editor_data->get_undo_redo()->add_undo_method(node, "set_transform", Object::cast_to<Node3D>(node)->get_transform()); } if (Object::cast_to<Control>(node)) { - editor_data->get_undo_redo().add_undo_method(node, "set_position", Object::cast_to<Control>(node)->get_position()); + editor_data->get_undo_redo()->add_undo_method(node, "set_position", Object::cast_to<Control>(node)->get_position()); } } } perform_node_renames(nullptr, &path_renames); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); } bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const { @@ -1957,30 +1956,30 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) { Node *node = selected.front()->get(); Ref<Script> existing = node->get_script(); - editor_data->get_undo_redo().create_action(TTR("Attach Script")); - editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "store_script_properties", node); - editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "store_script_properties", node); - editor_data->get_undo_redo().add_do_method(node, "set_script", p_script); - editor_data->get_undo_redo().add_undo_method(node, "set_script", existing); - editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", node); - editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", node); - editor_data->get_undo_redo().add_do_method(this, "_update_script_button"); - editor_data->get_undo_redo().add_undo_method(this, "_update_script_button"); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(TTR("Attach Script")); + editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", node); + editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", node); + editor_data->get_undo_redo()->add_do_method(node, "set_script", p_script); + editor_data->get_undo_redo()->add_undo_method(node, "set_script", existing); + editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", node); + editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", node); + editor_data->get_undo_redo()->add_do_method(this, "_update_script_button"); + editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button"); + editor_data->get_undo_redo()->commit_action(); } else { - editor_data->get_undo_redo().create_action(TTR("Attach Script")); - for (List<Node *>::Element *E = selected.front(); E; E = E->next()) { - Ref<Script> existing = E->get()->get_script(); - editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "store_script_properties", E->get()); - editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E->get()); - editor_data->get_undo_redo().add_do_method(E->get(), "set_script", p_script); - editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing); - editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E->get()); - editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E->get()); - editor_data->get_undo_redo().add_do_method(this, "_update_script_button"); - editor_data->get_undo_redo().add_undo_method(this, "_update_script_button"); + editor_data->get_undo_redo()->create_action(TTR("Attach Script")); + for (Node *E : selected) { + Ref<Script> existing = E->get_script(); + editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", E); + editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E); + editor_data->get_undo_redo()->add_do_method(E, "set_script", p_script); + editor_data->get_undo_redo()->add_undo_method(E, "set_script", existing); + editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E); + editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E); + editor_data->get_undo_redo()->add_do_method(this, "_update_script_button"); + editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button"); } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); } _push_item(p_script.operator->()); @@ -1994,10 +1993,10 @@ void SceneTreeDock::_shader_created(Ref<Shader> p_shader) { Ref<Shader> existing = selected_shader_material->get_shader(); - editor_data->get_undo_redo().create_action(TTR("Set Shader")); - editor_data->get_undo_redo().add_do_method(selected_shader_material.ptr(), "set_shader", p_shader); - editor_data->get_undo_redo().add_undo_method(selected_shader_material.ptr(), "set_shader", existing); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(TTR("Set Shader")); + editor_data->get_undo_redo()->add_do_method(selected_shader_material.ptr(), "set_shader", p_shader); + editor_data->get_undo_redo()->add_undo_method(selected_shader_material.ptr(), "set_shader", existing); + editor_data->get_undo_redo()->commit_action(); } void SceneTreeDock::_script_creation_closed() { @@ -2063,9 +2062,9 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { EditorNode::get_singleton()->get_editor_plugins_over()->make_visible(false); if (p_cut) { - editor_data->get_undo_redo().create_action(TTR("Cut Node(s)")); + editor_data->get_undo_redo()->create_action(TTR("Cut Node(s)")); } else { - editor_data->get_undo_redo().create_action(TTR("Remove Node(s)")); + editor_data->get_undo_redo()->create_action(TTR("Remove Node(s)")); } bool entire_scene = false; @@ -2077,11 +2076,11 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { } if (entire_scene) { - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); - editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", edited_scene); - editor_data->get_undo_redo().add_undo_method(edited_scene, "set_owner", edited_scene->get_owner()); - editor_data->get_undo_redo().add_undo_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().add_undo_reference(edited_scene); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); + editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", edited_scene); + editor_data->get_undo_redo()->add_undo_method(edited_scene, "set_owner", edited_scene->get_owner()); + editor_data->get_undo_redo()->add_undo_method(scene_tree, "update_tree"); + editor_data->get_undo_redo()->add_undo_reference(edited_scene); } else { remove_list.sort_custom<Node::Comparator>(); //sort nodes to keep positions @@ -2110,21 +2109,21 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { owners.push_back(F); } - editor_data->get_undo_redo().add_do_method(n->get_parent(), "remove_child", n); - editor_data->get_undo_redo().add_undo_method(n->get_parent(), "add_child", n, true); - editor_data->get_undo_redo().add_undo_method(n->get_parent(), "move_child", n, n->get_index()); + editor_data->get_undo_redo()->add_do_method(n->get_parent(), "remove_child", n); + editor_data->get_undo_redo()->add_undo_method(n->get_parent(), "add_child", n, true); + editor_data->get_undo_redo()->add_undo_method(n->get_parent(), "move_child", n, n->get_index()); if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == n) { - editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", n); + editor_data->get_undo_redo()->add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", n); } - editor_data->get_undo_redo().add_undo_method(this, "_set_owners", edited_scene, owners); - editor_data->get_undo_redo().add_undo_reference(n); + editor_data->get_undo_redo()->add_undo_method(this, "_set_owners", edited_scene, owners); + editor_data->get_undo_redo()->add_undo_reference(n); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo().add_do_method(ed, "live_debug_remove_and_keep_node", edited_scene->get_path_to(n), n->get_instance_id()); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_restore_node", n->get_instance_id(), edited_scene->get_path_to(n->get_parent()), n->get_index()); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_remove_and_keep_node", edited_scene->get_path_to(n), n->get_instance_id()); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_restore_node", n->get_instance_id(), edited_scene->get_path_to(n->get_parent()), n->get_index()); } } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); // hack, force 2d editor viewport to refresh after deletion if (CanvasItemEditor *editor = CanvasItemEditor::get_singleton()) { @@ -2190,29 +2189,29 @@ void SceneTreeDock::_do_create(Node *p_parent) { Node *child = Object::cast_to<Node>(c); ERR_FAIL_COND(!child); - editor_data->get_undo_redo().create_action(TTR("Create Node")); + editor_data->get_undo_redo()->create_action(TTR("Create Node")); if (edited_scene) { - editor_data->get_undo_redo().add_do_method(p_parent, "add_child", child, true); - editor_data->get_undo_redo().add_do_method(child, "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", child); - editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(p_parent, "remove_child", child); + editor_data->get_undo_redo()->add_do_method(p_parent, "add_child", child, true); + editor_data->get_undo_redo()->add_do_method(child, "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", child); + editor_data->get_undo_redo()->add_do_reference(child); + editor_data->get_undo_redo()->add_undo_method(p_parent, "remove_child", child); String new_name = p_parent->validate_child_name(child); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo().add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).plus_file(new_name))); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).plus_file(new_name))); } else { - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", child); - editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child); + editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree"); + editor_data->get_undo_redo()->add_do_reference(child); + editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); _push_item(c); editor_selection->clear(); editor_selection->add_node(child); @@ -2259,8 +2258,8 @@ void SceneTreeDock::_create() { List<Node *> selection = editor_selection->get_selected_node_list(); ERR_FAIL_COND(selection.size() <= 0); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change type of node(s)")); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + ur->create_action(TTR("Change type of node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get()); for (Node *n : selection) { ERR_FAIL_COND(!n); @@ -2393,7 +2392,7 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop } //p_remove_old was added to support undo if (p_remove_old) { - editor_data->get_undo_redo().clear_history(); + editor_data->get_undo_redo()->clear_history(); } newnode->set_name(newname); @@ -2607,16 +2606,16 @@ 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)) { - editor_data->get_undo_redo().create_action(TTR("Attach Script")); - 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); - editor_data->get_undo_redo().add_do_method(n, "set_script", scr); - editor_data->get_undo_redo().add_undo_method(n, "set_script", n->get_script()); - editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", n); - editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", n); - editor_data->get_undo_redo().add_do_method(this, "_update_script_button"); - editor_data->get_undo_redo().add_undo_method(this, "_update_script_button"); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(TTR("Attach Script")); + 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); + editor_data->get_undo_redo()->add_do_method(n, "set_script", scr); + editor_data->get_undo_redo()->add_undo_method(n, "set_script", n->get_script()); + editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", n); + editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", n); + editor_data->get_undo_redo()->add_do_method(this, "_update_script_button"); + editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button"); + editor_data->get_undo_redo()->commit_action(); } } @@ -3064,9 +3063,9 @@ List<Node *> SceneTreeDock::paste_nodes() { owner = paste_parent; } - UndoRedo &ur = editor_data->get_undo_redo(); - ur.create_action(TTR("Paste Node(s)")); - ur.add_do_method(editor_selection, "clear"); + Ref<EditorUndoRedoManager> &ur = editor_data->get_undo_redo(); + ur->create_action(TTR("Paste Node(s)"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + ur->add_do_method(editor_selection, "clear"); HashMap<Ref<Resource>, Ref<Resource>> resource_remap; String target_scene; @@ -3095,36 +3094,36 @@ List<Node *> SceneTreeDock::paste_nodes() { if (!paste_parent) { paste_parent = dup; owner = dup; - ur.add_do_method(EditorNode::get_singleton(), "set_edited_scene", dup); + ur->add_do_method(EditorNode::get_singleton(), "set_edited_scene", dup); } else { - ur.add_do_method(paste_parent, "add_child", dup, true); + ur->add_do_method(paste_parent, "add_child", dup, true); } for (KeyValue<const Node *, Node *> &E2 : duplimap) { Node *d = E2.value; if (d != dup) { - ur.add_do_method(d, "set_owner", owner); + ur->add_do_method(d, "set_owner", owner); } } if (dup != owner) { - ur.add_do_method(dup, "set_owner", owner); + ur->add_do_method(dup, "set_owner", owner); } - ur.add_do_method(editor_selection, "add_node", dup); + ur->add_do_method(editor_selection, "add_node", dup); if (dup == paste_parent) { - ur.add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); + ur->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); } else { - ur.add_undo_method(paste_parent, "remove_child", dup); + ur->add_undo_method(paste_parent, "remove_child", dup); } - ur.add_do_reference(dup); + ur->add_do_reference(dup); if (node_clipboard.size() == 1) { - ur.add_do_method(EditorNode::get_singleton(), "push_item", dup); + ur->add_do_method(EditorNode::get_singleton(), "push_item", dup); } } - ur.commit_action(); + ur->commit_action(); return pasted_nodes; } @@ -3492,7 +3491,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed)); - scene_tree->set_undo_redo(&editor_data->get_undo_redo()); + scene_tree->set_undo_redo(editor_data->get_undo_redo()); scene_tree->set_editor_selection(editor_selection); create_dialog = memnew(CreateDialog); @@ -3502,7 +3501,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec create_dialog->connect("favorites_updated", callable_mp(this, &SceneTreeDock::_update_create_root_dialog)); #ifdef MODULE_REGEX_ENABLED - rename_dialog = memnew(RenameDialog(scene_tree, &editor_data->get_undo_redo())); + rename_dialog = memnew(RenameDialog(scene_tree, editor_data->get_undo_redo())); add_child(rename_dialog); #endif // MODULE_REGEX_ENABLED diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index ad83db9b60..b977b012a8 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -35,6 +35,7 @@ #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/node_dock.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" @@ -365,7 +366,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { item->set_tooltip(0, tooltip); } - if (can_open_instance && undo_redo) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes + if (can_open_instance && undo_redo.is_valid()) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes if (!p_node->is_connected("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed))) { p_node->connect("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed).bind(p_node)); @@ -602,7 +603,9 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select } if (!keep) { - keep = filter.is_subsequence_ofn(p_parent->get_text(0)); + StringName node_type = get_node(p_parent->get_metadata(0))->get_class(); + bool is_kept_by_type = (filter.begins_with("type:") && filter.trim_prefix("type:").is_subsequence_ofn(node_type)) || (filter.begins_with("t:") && filter.trim_prefix("t:").is_subsequence_ofn(node_type)); + keep = (filter.is_subsequence_ofn(p_parent->get_text(0)) || is_kept_by_type); } p_parent->set_visible(keep); @@ -883,7 +886,7 @@ void SceneTreeEditor::_renamed() { return; } - if (!undo_redo) { + if (!undo_redo.is_valid()) { n->set_name(new_name); which->set_metadata(0, n->get_path()); emit_signal(SNAME("node_renamed")); @@ -927,6 +930,10 @@ String SceneTreeEditor::get_filter() const { return filter; } +void SceneTreeEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void SceneTreeEditor::set_display_foreign_nodes(bool p_display) { display_foreign = p_display; _update_tree(); @@ -1258,7 +1265,6 @@ void SceneTreeEditor::_bind_methods() { } SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_open_instance) { - undo_redo = nullptr; selected = nullptr; can_rename = p_can_rename; diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index 31772e55b5..0c13ad96cd 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -31,13 +31,14 @@ #ifndef SCENE_TREE_EDITOR_H #define SCENE_TREE_EDITOR_H -#include "core/object/undo_redo.h" #include "editor/editor_data.h" #include "editor/editor_settings.h" #include "scene/gui/button.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" +class EditorUndoRedoManager; + class SceneTreeEditor : public Control { GDCLASS(SceneTreeEditor, Control); @@ -98,7 +99,7 @@ class SceneTreeEditor : public Control { bool show_enabled_subscene = false; void _renamed(); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; HashSet<Node *> marked; bool marked_selectable = false; @@ -139,7 +140,7 @@ public: void set_filter(const String &p_filter); String get_filter() const; - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }; + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_display_foreign_nodes(bool p_display); void set_marked(const HashSet<Node *> &p_marked, bool p_selectable = false, bool p_children_selectable = true); diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp index 1cd1b4ea00..9058596830 100644 --- a/editor/shader_globals_editor.cpp +++ b/editor/shader_globals_editor.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "servers/rendering/shader_language.h" static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = { @@ -85,7 +86,7 @@ protected: return false; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Set Shader Global Variable")); undo_redo->add_do_method(RS::get_singleton(), "global_shader_uniform_set", p_name, p_value); @@ -393,7 +394,7 @@ void ShaderGlobalsEditor::_variable_added() { return; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); Variant value = create_var(RS::GlobalShaderUniformType(variable_type->get_selected())); @@ -412,7 +413,7 @@ void ShaderGlobalsEditor::_variable_added() { } void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) { - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(TTR("Add Shader Global Uniform")); undo_redo->add_do_method(RS::get_singleton(), "global_shader_uniform_remove", p_variable); diff --git a/editor/shader_globals_editor.h b/editor/shader_globals_editor.h index d29052eaee..1e2f1dd828 100644 --- a/editor/shader_globals_editor.h +++ b/editor/shader_globals_editor.h @@ -31,7 +31,6 @@ #ifndef SHADER_GLOBALS_EDITOR_H #define SHADER_GLOBALS_EDITOR_H -#include "core/object/undo_redo.h" #include "editor/editor_autoload_settings.h" #include "editor/editor_data.h" #include "editor/editor_plugin_settings.h" diff --git a/gles3_builders.py b/gles3_builders.py index a9fabd93ce..eafe503dd5 100644 --- a/gles3_builders.py +++ b/gles3_builders.py @@ -182,8 +182,8 @@ def include_file_in_gles3_header(filename, header_data, depth): return header_data -def build_gles3_header(filename, include, class_suffix, output_attribs): - header_data = GLES3HeaderStruct() +def build_gles3_header(filename, include, class_suffix, header_data=None): + header_data = header_data or GLES3HeaderStruct() include_file_in_gles3_header(filename, header_data, 0) out_file = filename + ".gen.h" @@ -191,8 +191,6 @@ def build_gles3_header(filename, include, class_suffix, output_attribs): defspec = 0 defvariant = "" - enum_constants = [] - fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n") out_file_base = out_file @@ -552,7 +550,7 @@ def build_gles3_header(filename, include, class_suffix, output_attribs): def build_gles3_headers(target, source, env): for x in source: - build_gles3_header(str(x), include="drivers/gles3/shader_gles3.h", class_suffix="GLES3", output_attribs=True) + build_gles3_header(str(x), include="drivers/gles3/shader_gles3.h", class_suffix="GLES3") if __name__ == "__main__": diff --git a/glsl_builders.py b/glsl_builders.py index 0926212e50..8cb5807f21 100644 --- a/glsl_builders.py +++ b/glsl_builders.py @@ -3,9 +3,26 @@ All such functions are invoked in a subprocess on Windows to prevent build flakiness. """ +import os.path from platform_methods import subprocess_main +def generate_inline_code(input_lines, insert_newline=True): + """Take header data and generate inline code + + :param: list input_lines: values for shared inline code + :return: str - generated inline value + """ + output = [] + for line in input_lines: + if line: + output.append(",".join(str(ord(c)) for c in line)) + if insert_newline: + output.append("%s" % ord("\n")) + output.append("0") + return ",".join(output) + + class RDHeaderStruct: def __init__(self): self.vertex_lines = [] @@ -57,10 +74,6 @@ def include_file_in_rd_header(filename, header_data, depth): while line.find("#include ") != -1: includeline = line.replace("#include ", "").strip()[1:-1] - import os.path - - included_file = "" - if includeline.startswith("thirdparty/"): included_file = os.path.relpath(includeline) @@ -82,8 +95,7 @@ def include_file_in_rd_header(filename, header_data, depth): line = fs.readline() - line = line.replace("\r", "") - line = line.replace("\n", "") + line = line.replace("\r", "").replace("\n", "") if header_data.reading == "vertex": header_data.vertex_lines += [line] @@ -100,65 +112,53 @@ def include_file_in_rd_header(filename, header_data, depth): return header_data -def build_rd_header(filename): - header_data = RDHeaderStruct() +def build_rd_header(filename, header_data=None): + header_data = header_data or RDHeaderStruct() include_file_in_rd_header(filename, header_data, 0) out_file = filename + ".gen.h" - fd = open(out_file, "w") - - fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n") - out_file_base = out_file out_file_base = out_file_base[out_file_base.rfind("/") + 1 :] out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :] out_file_ifdef = out_file_base.replace(".", "_").upper() - fd.write("#ifndef " + out_file_ifdef + "_RD\n") - fd.write("#define " + out_file_ifdef + "_RD\n") - out_file_class = out_file_base.replace(".glsl.gen.h", "").title().replace("_", "").replace(".", "") + "ShaderRD" - fd.write("\n") - fd.write('#include "servers/rendering/renderer_rd/shader_rd.h"\n\n') - fd.write("class " + out_file_class + " : public ShaderRD {\n\n") - fd.write("public:\n\n") - fd.write("\t" + out_file_class + "() {\n\n") + if header_data.compute_lines: + body_parts = [ + "static const char _compute_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.compute_lines), + f'setup(nullptr, nullptr, _compute_code, "{out_file_class}");', + ] + else: + body_parts = [ + "static const char _vertex_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.vertex_lines), + "static const char _fragment_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.fragment_lines), + f'setup(_vertex_code, _fragment_code, nullptr, "{out_file_class}");', + ] - if len(header_data.compute_lines): + body_content = "\n\t\t".join(body_parts) - fd.write("\t\tstatic const char _compute_code[] = {\n") - for x in header_data.compute_lines: - for c in x: - fd.write(str(ord(c)) + ",") - fd.write(str(ord("\n")) + ",") - fd.write("\t\t0};\n\n") + # Intended curly brackets are doubled so f-string doesn't eat them up. + shader_template = f"""/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */ +#ifndef {out_file_ifdef}_RD +#define {out_file_ifdef}_RD - fd.write('\t\tsetup(nullptr, nullptr, _compute_code, "' + out_file_class + '");\n') - fd.write("\t}\n") +#include "servers/rendering/renderer_rd/shader_rd.h" - else: +class {out_file_class} : public ShaderRD {{ - fd.write("\t\tstatic const char _vertex_code[] = {\n") - for x in header_data.vertex_lines: - for c in x: - fd.write(str(ord(c)) + ",") - fd.write(str(ord("\n")) + ",") - fd.write("\t\t0};\n\n") +public: - fd.write("\t\tstatic const char _fragment_code[]={\n") - for x in header_data.fragment_lines: - for c in x: - fd.write(str(ord(c)) + ",") - fd.write(str(ord("\n")) + ",") - fd.write("\t\t0};\n\n") + {out_file_class}() {{ - fd.write('\t\tsetup(_vertex_code, _fragment_code, nullptr, "' + out_file_class + '");\n') - fd.write("\t}\n") + {body_content} + }} +}}; - fd.write("};\n\n") +#endif +""" - fd.write("#endif\n") - fd.close() + with open(out_file, "w") as fd: + fd.write(shader_template) def build_rd_headers(target, source, env): @@ -180,8 +180,6 @@ def include_file_in_raw_header(filename, header_data, depth): while line.find("#include ") != -1: includeline = line.replace("#include ", "").strip()[1:-1] - import os.path - included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline) include_file_in_raw_header(included_file, header_data, depth + 1) @@ -193,28 +191,28 @@ def include_file_in_raw_header(filename, header_data, depth): fs.close() -def build_raw_header(filename): - header_data = RAWHeaderStruct() +def build_raw_header(filename, header_data=None): + header_data = header_data or RAWHeaderStruct() include_file_in_raw_header(filename, header_data, 0) out_file = filename + ".gen.h" - fd = open(out_file, "w") - - fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n") - out_file_base = out_file.replace(".glsl.gen.h", "_shader_glsl") out_file_base = out_file_base[out_file_base.rfind("/") + 1 :] out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :] out_file_ifdef = out_file_base.replace(".", "_").upper() - fd.write("#ifndef " + out_file_ifdef + "_RAW_H\n") - fd.write("#define " + out_file_ifdef + "_RAW_H\n") - fd.write("\n") - fd.write("static const char " + out_file_base + "[] = {\n") - for c in header_data.code: - fd.write(str(ord(c)) + ",") - fd.write("\t\t0};\n\n") - fd.write("#endif\n") - fd.close() + + shader_template = f"""/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */ +#ifndef {out_file_ifdef}_RAW_H +#define {out_file_ifdef}_RAW_H + +static const char {out_file_base}[] = {{ + {generate_inline_code(header_data.code, insert_newline=False)} +}}; +#endif +""" + + with open(out_file, "w") as f: + f.write(shader_template) def build_raw_headers(target, source, env): diff --git a/main/main.cpp b/main/main.cpp index 740e3cc69d..8a25827e02 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -143,6 +143,7 @@ static int audio_driver_idx = -1; // Engine config/tools +static bool single_window = false; static bool editor = false; static bool project_manager = false; static bool cmdline_tool = false; @@ -153,7 +154,11 @@ static OS::ProcessID editor_pid = 0; #ifdef TOOLS_ENABLED static bool auto_build_solutions = false; static String debug_server_uri; + +HashMap<Main::CLIScope, Vector<String>> forwardable_cli_arguments; #endif +bool use_startup_benchmark = false; +String startup_benchmark_file; // Display @@ -196,6 +201,12 @@ bool Main::is_cmdline_tool() { return cmdline_tool; } +#ifdef TOOLS_ENABLED +const Vector<String> &Main::get_forwardable_cli_arguments(Main::CLIScope p_scope) { + return forwardable_cli_arguments[p_scope]; +} +#endif + static String unescape_cmdline(const String &p_str) { return p_str.replace("%20", " "); } @@ -386,6 +397,8 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print(" --no-docbase Disallow dumping the base types (used with --doctool).\n"); OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n"); OS::get_singleton()->print(" --dump-extension-api Generate JSON dump of the Godot API for GDExtension bindings named 'extension_api.json' in the current folder.\n"); + OS::get_singleton()->print(" --startup-benchmark Benchmark the startup time and print it to console.\n"); + OS::get_singleton()->print(" --startup-benchmark-file <path> Benchmark the startup time and save it to a given file in JSON format.\n"); #ifdef TESTS_ENABLED OS::get_singleton()->print(" --test [--help] Run unit tests. Use --test --help for more information.\n"); #endif @@ -594,6 +607,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph engine = memnew(Engine); MAIN_PRINT("Main: Initialize CORE"); + engine->startup_begin(); + engine->startup_benchmark_begin_measure("core"); register_core_types(); register_core_driver_types(); @@ -703,6 +718,21 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph List<String>::Element *N = I->next(); +#ifdef TOOLS_ENABLED + if (I->get() == "--debug" || + I->get() == "--verbose" || + I->get() == "--disable-crash-handler") { + forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get()); + forwardable_cli_arguments[CLI_SCOPE_PROJECT].push_back(I->get()); + } + if (I->get() == "--single-window" || + I->get() == "--audio-driver" || + I->get() == "--display-driver" || + I->get() == "--rendering-driver") { + forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get()); + } +#endif + if (adding_user_args) { user_args.push_back(I->get()); } else if (I->get() == "-h" || I->get() == "--help" || I->get() == "/?") { // display help @@ -881,7 +911,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } } else if (I->get() == "--single-window") { // force single window - OS::get_singleton()->_single_window = true; + single_window = true; } else if (I->get() == "-t" || I->get() == "--always-on-top") { // force always-on-top window init_always_on_top = true; @@ -1208,6 +1238,19 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->print("Missing --xr-mode argument, aborting.\n"); goto error; } + + } else if (I->get() == "--startup-benchmark") { + use_startup_benchmark = true; + } else if (I->get() == "--startup-benchmark-file") { + if (I->next()) { + use_startup_benchmark = true; + startup_benchmark_file = I->next()->get(); + N = I->next()->next(); + } else { + OS::get_singleton()->print("Missing <path> argument for --startup-benchmark-file <path>.\n"); + goto error; + } + } else if (I->get() == "--") { adding_user_args = true; } else { @@ -1624,6 +1667,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph message_queue = memnew(MessageQueue); + engine->startup_benchmark_end_measure(); // core + if (p_second_phase) { return setup2(); } @@ -1690,6 +1735,8 @@ error: } Error Main::setup2(Thread::ID p_main_tid_override) { + engine->startup_benchmark_begin_measure("servers"); + tsman = memnew(TextServerManager); if (tsman) { @@ -2047,8 +2094,12 @@ Error Main::setup2(Thread::ID p_main_tid_override) { ERR_FAIL_V_MSG(ERR_CANT_CREATE, "TextServer: Unable to create TextServer interface."); } + engine->startup_benchmark_end_measure(); // servers + MAIN_PRINT("Main: Load Scene Types"); + engine->startup_benchmark_begin_measure("scene"); + register_scene_types(); register_driver_types(); @@ -2124,6 +2175,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) { print_verbose("EDITOR API HASH: " + uitos(ClassDB::get_api_hash(ClassDB::API_EDITOR))); MAIN_PRINT("Main: Done"); + engine->startup_benchmark_end_measure(); // scene + return OK; } @@ -2440,7 +2493,7 @@ bool Main::start() { bool embed_subwindows = GLOBAL_DEF("display/window/subwindows/embed_subwindows", true); - if (OS::get_singleton()->is_single_window() || (!project_manager && !editor && embed_subwindows) || !DisplayServer::get_singleton()->has_feature(DisplayServer::Feature::FEATURE_SUBWINDOWS)) { + if (single_window || (!project_manager && !editor && embed_subwindows) || !DisplayServer::get_singleton()->has_feature(DisplayServer::Feature::FEATURE_SUBWINDOWS)) { sml->get_root()->set_embedding_subwindows(true); } @@ -2450,6 +2503,7 @@ bool Main::start() { if (!project_manager && !editor) { // game if (!game_path.is_empty() || !script.is_empty()) { //autoload + Engine::get_singleton()->startup_benchmark_begin_measure("load_autoloads"); HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); //first pass, add the constants so they exist before any script is loaded @@ -2504,12 +2558,14 @@ bool Main::start() { for (Node *E : to_add) { sml->get_root()->add_child(E); } + Engine::get_singleton()->startup_benchmark_end_measure(); // load autoloads } } #ifdef TOOLS_ENABLED EditorNode *editor_node = nullptr; if (editor) { + Engine::get_singleton()->startup_benchmark_begin_measure("editor"); editor_node = memnew(EditorNode); sml->get_root()->add_child(editor_node); @@ -2517,6 +2573,13 @@ bool Main::start() { editor_node->export_preset(_export_preset, positional_arg, export_debug, export_pack_only); game_path = ""; // Do not load anything. } + + Engine::get_singleton()->startup_benchmark_end_measure(); + + editor_node->set_use_startup_benchmark(use_startup_benchmark, startup_benchmark_file); + // Editor takes over + use_startup_benchmark = false; + startup_benchmark_file = String(); } #endif @@ -2681,6 +2744,8 @@ bool Main::start() { if (!project_manager && !editor) { // game + Engine::get_singleton()->startup_benchmark_begin_measure("game_load"); + // Load SSL Certificates from Project Settings (or builtin). Crypto::load_default_certificates(GLOBAL_DEF("network/ssl/certificate_bundle_override", "")); @@ -2720,16 +2785,20 @@ bool Main::start() { } } } + + Engine::get_singleton()->startup_benchmark_end_measure(); // game_load } #ifdef TOOLS_ENABLED if (project_manager) { + Engine::get_singleton()->startup_benchmark_begin_measure("project_manager"); Engine::get_singleton()->set_editor_hint(true); ProjectManager *pmanager = memnew(ProjectManager); ProgressDialog *progress_dialog = memnew(ProgressDialog); pmanager->add_child(progress_dialog); sml->get_root()->add_child(pmanager); DisplayServer::get_singleton()->set_context(DisplayServer::CONTEXT_PROJECTMAN); + Engine::get_singleton()->startup_benchmark_end_measure(); } if (project_manager || editor) { @@ -2759,6 +2828,11 @@ bool Main::start() { } } + if (use_startup_benchmark) { + Engine::get_singleton()->startup_dump(startup_benchmark_file); + startup_benchmark_file = String(); + } + return true; } diff --git a/main/main.h b/main/main.h index d1870ab8df..f0bfe69b34 100644 --- a/main/main.h +++ b/main/main.h @@ -35,6 +35,9 @@ #include "core/os/thread.h" #include "core/typedefs.h" +template <class T> +class Vector; + class Main { static void print_help(const char *p_binary); static uint64_t last_ticks; @@ -47,6 +50,14 @@ class Main { public: static bool is_cmdline_tool(); +#ifdef TOOLS_ENABLED + enum CLIScope { + CLI_SCOPE_TOOL, // Editor and project manager. + CLI_SCOPE_PROJECT, + }; + static const Vector<String> &get_forwardable_cli_arguments(CLIScope p_scope); +#endif + static int test_entrypoint(int argc, char *argv[], bool &tests_need_run); static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true); static Error setup2(Thread::ID p_main_tid_override = 0); diff --git a/main/performance.h b/main/performance.h index 2837d8f512..00e00886ef 100644 --- a/main/performance.h +++ b/main/performance.h @@ -85,7 +85,6 @@ public: PHYSICS_3D_ACTIVE_OBJECTS, PHYSICS_3D_COLLISION_PAIRS, PHYSICS_3D_ISLAND_COUNT, - //physics AUDIO_OUTPUT_LATENCY, MONITOR_MAX }; diff --git a/misc/scripts/clang_format.sh b/misc/scripts/clang_format.sh index 2b7179f5be..b7c577d5fb 100755 --- a/misc/scripts/clang_format.sh +++ b/misc/scripts/clang_format.sh @@ -7,7 +7,8 @@ set -uo pipefail # Loops through all code files tracked by Git. git ls-files -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.m' '*.mm' '*.inc' '*.java' '*.glsl' \ - ':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' | + ':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' \ + ':!:tests/python_build/*' | while read -r f; do # Run clang-format. clang-format --Wno-error=unknown -i "$f" diff --git a/misc/scripts/pytest_builders.sh b/misc/scripts/pytest_builders.sh new file mode 100755 index 0000000000..eb2ddbcddc --- /dev/null +++ b/misc/scripts/pytest_builders.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -uo pipefail + +echo "Running Python checks for builder system" +pytest ./tests/python_build diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 56be4e65f0..243c23342e 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -53,6 +53,7 @@ void CSGShape3D::set_use_collision(bool p_enable) { PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); set_collision_layer(collision_layer); set_collision_mask(collision_mask); + set_collision_priority(collision_priority); _make_dirty(); //force update } else { PhysicsServer3D::get_singleton()->free(root_collision_instance); @@ -124,6 +125,17 @@ bool CSGShape3D::get_collision_mask_value(int p_layer_number) const { return get_collision_mask() & (1 << (p_layer_number - 1)); } +void CSGShape3D::set_collision_priority(real_t p_priority) { + collision_priority = p_priority; + if (root_collision_instance.is_valid()) { + PhysicsServer3D::get_singleton()->body_set_collision_priority(root_collision_instance, p_priority); + } +} + +real_t CSGShape3D::get_collision_priority() const { + return collision_priority; +} + bool CSGShape3D::is_root_shape() const { return !parent_shape; } @@ -545,6 +557,7 @@ void CSGShape3D::_notification(int p_what) { PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); set_collision_layer(collision_layer); set_collision_mask(collision_mask); + set_collision_priority(collision_priority); _update_collision_faces(); } } break; @@ -584,15 +597,14 @@ bool CSGShape3D::is_calculating_tangents() const { return calculate_tangents; } -void CSGShape3D::_validate_property(PropertyInfo &property) const { - bool is_collision_prefixed = property.name.begins_with("collision_"); - if ((is_collision_prefixed || property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) { +void CSGShape3D::_validate_property(PropertyInfo &p_property) const { + bool is_collision_prefixed = p_property.name.begins_with("collision_"); + if ((is_collision_prefixed || p_property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) { //hide collision if not root - property.usage = PROPERTY_USAGE_NO_EDITOR; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } else if (is_collision_prefixed && !bool(get("use_collision"))) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - GeometryInstance3D::_validate_property(property); } Array CSGShape3D::get_meshes() const { @@ -632,6 +644,9 @@ void CSGShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &CSGShape3D::set_collision_layer_value); ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CSGShape3D::get_collision_layer_value); + ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &CSGShape3D::set_collision_priority); + ClassDB::bind_method(D_METHOD("get_collision_priority"), &CSGShape3D::get_collision_priority); + ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape3D::set_calculate_tangents); ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape3D::is_calculating_tangents); @@ -645,6 +660,7 @@ void CSGShape3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_collision"), "set_use_collision", "is_using_collision"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority"); BIND_ENUM_CONSTANT(OPERATION_UNION); BIND_ENUM_CONSTANT(OPERATION_INTERSECTION); @@ -2058,18 +2074,16 @@ void CSGPolygon3D::_notification(int p_what) { } } -void CSGPolygon3D::_validate_property(PropertyInfo &property) const { - if (property.name.begins_with("spin") && mode != MODE_SPIN) { - property.usage = PROPERTY_USAGE_NONE; +void CSGPolygon3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name.begins_with("spin") && mode != MODE_SPIN) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("path") && mode != MODE_PATH) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("path") && mode != MODE_PATH) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "depth" && mode != MODE_DEPTH) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "depth" && mode != MODE_DEPTH) { + p_property.usage = PROPERTY_USAGE_NONE; } - - CSGShape3D::_validate_property(property); } void CSGPolygon3D::_path_changed() { diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index 0b49dc4609..7db5477b10 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -65,6 +65,7 @@ private: bool use_collision = false; uint32_t collision_layer = 1; uint32_t collision_mask = 1; + real_t collision_priority = 1.0; Ref<ConcavePolygonShape3D> root_collision_shape; RID root_collision_instance; @@ -117,7 +118,7 @@ protected: friend class CSGCombiner3D; CSGBrush *_get_brush(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: Array get_meshes() const; @@ -144,6 +145,9 @@ public: void set_collision_mask_value(int p_layer_number, bool p_value); bool get_collision_mask_value(int p_layer_number) const; + void set_collision_priority(real_t p_priority); + real_t get_collision_priority() const; + void set_snap(float p_snap); float get_snap() const; @@ -383,7 +387,7 @@ private: protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); public: diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml index 4fd4a12a1d..7e92d667b3 100644 --- a/modules/csg/doc_classes/CSGShape3D.xml +++ b/modules/csg/doc_classes/CSGShape3D.xml @@ -66,6 +66,8 @@ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1"> The physics layers this CSG shape scans for collisions. 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="collision_priority" type="float" setter="set_collision_priority" getter="get_collision_priority" default="1.0"> + </member> <member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape3D.Operation" default="0"> The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent. </member> diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp index 6442ff71fc..ba9b96db74 100644 --- a/modules/csg/editor/csg_gizmos.cpp +++ b/modules/csg/editor/csg_gizmos.cpp @@ -32,7 +32,9 @@ #ifdef TOOLS_ENABLED +#include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "scene/3d/camera_3d.h" @@ -215,7 +217,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Sphere Shape Radius")); ur->add_do_method(s, "set_radius", s->get_radius()); ur->add_undo_method(s, "set_radius", p_restore); @@ -229,7 +231,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Box Shape Size")); ur->add_do_method(s, "set_size", s->get_size()); ur->add_undo_method(s, "set_size", p_restore); @@ -247,7 +249,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (p_id == 0) { ur->create_action(TTR("Change Cylinder Radius")); ur->add_do_method(s, "set_radius", s->get_radius()); @@ -272,7 +274,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (p_id == 0) { ur->create_action(TTR("Change Torus Inner Radius")); ur->add_do_method(s, "set_inner_radius", s->get_inner_radius()); diff --git a/modules/gltf/doc_classes/GLTFCamera.xml b/modules/gltf/doc_classes/GLTFCamera.xml index 9b9eff6141..b90abd105d 100644 --- a/modules/gltf/doc_classes/GLTFCamera.xml +++ b/modules/gltf/doc_classes/GLTFCamera.xml @@ -1,19 +1,30 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="GLTFCamera" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> + Represents a GLTF camera. </brief_description> <description> + Represents a camera as defined by the base GLTF spec. </description> <tutorials> + <link title="GLTF camera detailed specification">https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-camera</link> + <link title="GLTF camera spec and example file">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_015_SimpleCameras.md</link> </tutorials> <members> <member name="depth_far" type="float" setter="set_depth_far" getter="get_depth_far" default="4000.0"> + The distance to the far culling boundary for this camera relative to its local Z axis, in meters. This maps to GLTF's [code]zfar[/code] property. </member> <member name="depth_near" type="float" setter="set_depth_near" getter="get_depth_near" default="0.05"> + The distance to the near culling boundary for this camera relative to its local Z axis, in meters. This maps to GLTF's [code]znear[/code] property. </member> - <member name="fov_size" type="float" setter="set_fov_size" getter="get_fov_size" default="75.0"> + <member name="fov" type="float" setter="set_fov" getter="get_fov" default="1.309"> + The FOV of the camera. This class and GLTF define the camera FOV in radians, while Godot uses degrees. This maps to GLTF's [code]yfov[/code] property. This value is only used for perspective cameras, when [member perspective] is true. </member> <member name="perspective" type="bool" setter="set_perspective" getter="get_perspective" default="true"> + Whether or not the camera is in perspective mode. If false, the camera is in orthographic/orthogonal mode. This maps to GLTF's camera [code]type[/code] property. See [member Camera3D.projection] and the GLTF spec for more information. + </member> + <member name="size_mag" type="float" setter="set_size_mag" getter="get_size_mag" default="0.5"> + The size of the camera. This class and GLTF define the camera size magnitude as a radius in meters, while Godot defines it as a diameter in meters. This maps to GLTF's [code]ymag[/code] property. This value is only used for orthographic/orthogonal cameras, when [member perspective] is false. </member> </members> </class> diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index d102970932..b913a771e1 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -50,7 +50,6 @@ #include "core/version.h" #include "drivers/png/png_driver_common.h" #include "scene/2d/node_2d.h" -#include "scene/3d/camera_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/multimesh_instance_3d.h" #include "scene/3d/node_3d.h" @@ -4582,22 +4581,21 @@ Error GLTFDocument::_serialize_cameras(Ref<GLTFState> state) { Ref<GLTFCamera> camera = state->cameras[i]; - if (camera->get_perspective() == false) { - Dictionary og; - og["ymag"] = Math::deg2rad(camera->get_fov_size()); - og["xmag"] = Math::deg2rad(camera->get_fov_size()); - og["zfar"] = camera->get_depth_far(); - og["znear"] = camera->get_depth_near(); - d["orthographic"] = og; - d["type"] = "orthographic"; - } else if (camera->get_perspective()) { - Dictionary ppt; - // GLTF spec is in radians, Godot's camera is in degrees. - ppt["yfov"] = Math::deg2rad(camera->get_fov_size()); - ppt["zfar"] = camera->get_depth_far(); - ppt["znear"] = camera->get_depth_near(); - d["perspective"] = ppt; + if (camera->get_perspective()) { + Dictionary persp; + persp["yfov"] = camera->get_fov(); + persp["zfar"] = camera->get_depth_far(); + persp["znear"] = camera->get_depth_near(); + d["perspective"] = persp; d["type"] = "perspective"; + } else { + Dictionary ortho; + ortho["ymag"] = camera->get_size_mag(); + ortho["xmag"] = camera->get_size_mag(); + ortho["zfar"] = camera->get_depth_far(); + ortho["znear"] = camera->get_depth_near(); + d["orthographic"] = ortho; + d["type"] = "orthographic"; } cameras[i] = d; } @@ -4680,27 +4678,23 @@ Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) { camera.instantiate(); ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); const String &type = d["type"]; - if (type == "orthographic") { - camera->set_perspective(false); - if (d.has("orthographic")) { - const Dictionary &og = d["orthographic"]; - // GLTF spec is in radians, Godot's camera is in degrees. - camera->set_fov_size(Math::rad2deg(real_t(og["ymag"]))); - camera->set_depth_far(og["zfar"]); - camera->set_depth_near(og["znear"]); - } else { - camera->set_fov_size(10); - } - } else if (type == "perspective") { + if (type == "perspective") { camera->set_perspective(true); if (d.has("perspective")) { - const Dictionary &ppt = d["perspective"]; - // GLTF spec is in radians, Godot's camera is in degrees. - camera->set_fov_size(Math::rad2deg(real_t(ppt["yfov"]))); - camera->set_depth_far(ppt["zfar"]); - camera->set_depth_near(ppt["znear"]); - } else { - camera->set_fov_size(10); + const Dictionary &persp = d["perspective"]; + camera->set_fov(persp["yfov"]); + if (persp.has("zfar")) { + camera->set_depth_far(persp["zfar"]); + } + camera->set_depth_near(persp["znear"]); + } + } else if (type == "orthographic") { + camera->set_perspective(false); + if (d.has("orthographic")) { + const Dictionary &ortho = d["orthographic"]; + camera->set_size_mag(ortho["ymag"]); + camera->set_depth_far(ortho["zfar"]); + camera->set_depth_near(ortho["znear"]); } } else { ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Camera3D should be in 'orthographic' or 'perspective'"); @@ -5204,12 +5198,13 @@ Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, const GLTFNodeInd print_verbose("glTF: Creating camera for: " + gltf_node->get_name()); Ref<GLTFCamera> c = state->cameras[gltf_node->camera]; - if (c->get_perspective()) { - camera->set_perspective(c->get_fov_size(), c->get_depth_near(), c->get_depth_far()); - } else { - camera->set_orthogonal(c->get_fov_size(), c->get_depth_near(), c->get_depth_far()); - } - + camera->set_projection(c->get_perspective() ? Camera3D::PROJECTION_PERSPECTIVE : Camera3D::PROJECTION_ORTHOGONAL); + // GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees. + camera->set_fov(Math::rad2deg(c->get_fov())); + // GLTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters. + camera->set_size(c->get_size_mag() * 2.0f); + camera->set_near(c->get_depth_near()); + camera->set_far(c->get_depth_far()); return camera; } @@ -5218,11 +5213,11 @@ GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_ Ref<GLTFCamera> c; c.instantiate(); - - if (p_camera->get_projection() == Camera3D::ProjectionType::PROJECTION_PERSPECTIVE) { - c->set_perspective(true); - } - c->set_fov_size(p_camera->get_fov()); + c->set_perspective(p_camera->get_projection() == Camera3D::ProjectionType::PROJECTION_PERSPECTIVE); + // GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees. + c->set_fov(Math::deg2rad(p_camera->get_fov())); + // GLTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters. + c->set_size_mag(p_camera->get_size() * 0.5f); c->set_depth_far(p_camera->get_far()); c->set_depth_near(p_camera->get_near()); GLTFCameraIndex camera_index = state->cameras.size(); @@ -5442,7 +5437,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex int32_t cell = p_grid_map->get_cell_item( Vector3(cell_location.x, cell_location.y, cell_location.z)); Transform3D cell_xform; - cell_xform.basis.set_orthogonal_index( + cell_xform.basis = p_grid_map->get_basis_with_orthogonal_index( p_grid_map->get_cell_item_orientation( Vector3(cell_location.x, cell_location.y, cell_location.z))); cell_xform.basis.scale(Vector3(p_grid_map->get_cell_scale(), diff --git a/modules/gltf/structures/gltf_camera.cpp b/modules/gltf/structures/gltf_camera.cpp index f3ea6a1c4c..c492913ea7 100644 --- a/modules/gltf/structures/gltf_camera.cpp +++ b/modules/gltf/structures/gltf_camera.cpp @@ -33,15 +33,18 @@ void GLTFCamera::_bind_methods() { ClassDB::bind_method(D_METHOD("get_perspective"), &GLTFCamera::get_perspective); ClassDB::bind_method(D_METHOD("set_perspective", "perspective"), &GLTFCamera::set_perspective); - ClassDB::bind_method(D_METHOD("get_fov_size"), &GLTFCamera::get_fov_size); - ClassDB::bind_method(D_METHOD("set_fov_size", "fov_size"), &GLTFCamera::set_fov_size); + ClassDB::bind_method(D_METHOD("get_fov"), &GLTFCamera::get_fov); + ClassDB::bind_method(D_METHOD("set_fov", "fov"), &GLTFCamera::set_fov); + ClassDB::bind_method(D_METHOD("get_size_mag"), &GLTFCamera::get_size_mag); + ClassDB::bind_method(D_METHOD("set_size_mag", "size_mag"), &GLTFCamera::set_size_mag); ClassDB::bind_method(D_METHOD("get_depth_far"), &GLTFCamera::get_depth_far); ClassDB::bind_method(D_METHOD("set_depth_far", "zdepth_far"), &GLTFCamera::set_depth_far); ClassDB::bind_method(D_METHOD("get_depth_near"), &GLTFCamera::get_depth_near); ClassDB::bind_method(D_METHOD("set_depth_near", "zdepth_near"), &GLTFCamera::set_depth_near); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "perspective"), "set_perspective", "get_perspective"); // bool - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov_size"), "set_fov_size", "get_fov_size"); // float - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_far"), "set_depth_far", "get_depth_far"); // float - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_near"), "set_depth_near", "get_depth_near"); // float + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "perspective"), "set_perspective", "get_perspective"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov"), "set_fov", "get_fov"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size_mag"), "set_size_mag", "get_size_mag"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_far"), "set_depth_far", "get_depth_far"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_near"), "set_depth_near", "get_depth_near"); } diff --git a/modules/gltf/structures/gltf_camera.h b/modules/gltf/structures/gltf_camera.h index b7df741825..714ec21693 100644 --- a/modules/gltf/structures/gltf_camera.h +++ b/modules/gltf/structures/gltf_camera.h @@ -32,15 +32,22 @@ #define GLTF_CAMERA_H #include "core/io/resource.h" +#include "scene/3d/camera_3d.h" + +// Reference and test file: +// https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_015_SimpleCameras.md class GLTFCamera : public Resource { GDCLASS(GLTFCamera, Resource); private: + // GLTF has no default camera values, they should always be specified in + // the GLTF file. Here we default to Godot's default camera settings. bool perspective = true; - float fov_size = 75.0; - float depth_far = 4000.0; - float depth_near = 0.05; + real_t fov = Math::deg2rad(75.0); + real_t size_mag = 0.5; + real_t depth_far = 4000.0; + real_t depth_near = 0.05; protected: static void _bind_methods(); @@ -48,12 +55,14 @@ protected: public: bool get_perspective() const { return perspective; } void set_perspective(bool p_val) { perspective = p_val; } - float get_fov_size() const { return fov_size; } - void set_fov_size(float p_val) { fov_size = p_val; } - float get_depth_far() const { return depth_far; } - void set_depth_far(float p_val) { depth_far = p_val; } - float get_depth_near() const { return depth_near; } - void set_depth_near(float p_val) { depth_near = p_val; } + real_t get_fov() const { return fov; } + void set_fov(real_t p_val) { fov = p_val; } + real_t get_size_mag() const { return size_mag; } + void set_size_mag(real_t p_val) { size_mag = p_val; } + real_t get_depth_far() const { return depth_far; } + void set_depth_far(real_t p_val) { depth_far = p_val; } + real_t get_depth_near() const { return depth_near; } + void set_depth_near(real_t p_val) { depth_near = p_val; } }; #endif // GLTF_CAMERA_H diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 5552b5b009..209890a333 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -39,6 +39,13 @@ Returns an array of [ArrayMesh]es and [Transform3D] references of all bake meshes that exist within the current GridMap. </description> </method> + <method name="get_basis_with_orthogonal_index" qualifiers="const"> + <return type="Basis" /> + <param index="0" name="index" type="int" /> + <description> + Returns one of 24 possible rotations that lie along the vectors (x,y,z) with each component being either -1, 0, or 1. For further details, refer to the Godot source code. + </description> + </method> <method name="get_cell_item" qualifiers="const"> <return type="int" /> <param index="0" name="position" type="Vector3i" /> @@ -46,6 +53,13 @@ The [MeshLibrary] item index located at the given grid coordinates. If the cell is empty, [constant INVALID_CELL_ITEM] will be returned. </description> </method> + <method name="get_cell_item_basis" qualifiers="const"> + <return type="Basis" /> + <param index="0" name="position" type="Vector3i" /> + <description> + Returns the basis that gives the specificed cell its orientation. + </description> + </method> <method name="get_cell_item_orientation" qualifiers="const"> <return type="int" /> <param index="0" name="position" type="Vector3i" /> @@ -80,6 +94,13 @@ Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32. </description> </method> + <method name="get_orthogonal_index_from_basis" qualifiers="const"> + <return type="int" /> + <param index="0" name="basis" type="Basis" /> + <description> + This function considers a discretization of rotations into 24 points on unit sphere, lying along the vectors (x,y,z) with each component being either -1, 0, or 1, and returns the index (in the range from 0 to 23) of the point best representing the orientation of the object. For further details, refer to the Godot source code. + </description> + </method> <method name="get_used_cells" qualifiers="const"> <return type="Array" /> <description> @@ -121,7 +142,7 @@ <description> Sets the mesh index for the cell referenced by its grid coordinates. A negative item index such as [constant INVALID_CELL_ITEM] will clear the cell. - Optionally, the item's orientation can be passed. For valid orientation values, see [method Basis.get_orthogonal_index]. + Optionally, the item's orientation can be passed. For valid orientation values, see [method get_orthogonal_index_from_basis]. </description> </method> <method name="set_collision_layer_value"> diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index 518e2cf97d..17f9832096 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -37,6 +37,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "scene/3d/camera_3d.h" #include "scene/main/window.h" @@ -94,91 +95,91 @@ void GridMapEditor::_menu_option(int p_option) { case MENU_OPTION_CURSOR_ROTATE_Y: { Basis r; if (input_action == INPUT_PASTE) { - r.set_orthogonal_index(paste_indicator.orientation); + r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); r.rotate(Vector3(0, 1, 0), -Math_PI / 2.0); - paste_indicator.orientation = r.get_orthogonal_index(); + paste_indicator.orientation = node->get_orthogonal_index_from_basis(r); _update_paste_indicator(); break; } - r.set_orthogonal_index(cursor_rot); + r = node->get_basis_with_orthogonal_index(cursor_rot); r.rotate(Vector3(0, 1, 0), -Math_PI / 2.0); - cursor_rot = r.get_orthogonal_index(); + cursor_rot = node->get_orthogonal_index_from_basis(r); _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_ROTATE_X: { Basis r; if (input_action == INPUT_PASTE) { - r.set_orthogonal_index(paste_indicator.orientation); + r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); r.rotate(Vector3(1, 0, 0), -Math_PI / 2.0); - paste_indicator.orientation = r.get_orthogonal_index(); + paste_indicator.orientation = node->get_orthogonal_index_from_basis(r); _update_paste_indicator(); break; } - r.set_orthogonal_index(cursor_rot); + r = node->get_basis_with_orthogonal_index(cursor_rot); r.rotate(Vector3(1, 0, 0), -Math_PI / 2.0); - cursor_rot = r.get_orthogonal_index(); + cursor_rot = node->get_orthogonal_index_from_basis(r); _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_ROTATE_Z: { Basis r; if (input_action == INPUT_PASTE) { - r.set_orthogonal_index(paste_indicator.orientation); + r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); r.rotate(Vector3(0, 0, 1), -Math_PI / 2.0); - paste_indicator.orientation = r.get_orthogonal_index(); + paste_indicator.orientation = node->get_orthogonal_index_from_basis(r); _update_paste_indicator(); break; } - r.set_orthogonal_index(cursor_rot); + r = node->get_basis_with_orthogonal_index(cursor_rot); r.rotate(Vector3(0, 0, 1), -Math_PI / 2.0); - cursor_rot = r.get_orthogonal_index(); + cursor_rot = node->get_orthogonal_index_from_basis(r); _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_BACK_ROTATE_Y: { Basis r; if (input_action == INPUT_PASTE) { - r.set_orthogonal_index(paste_indicator.orientation); + r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); r.rotate(Vector3(0, 1, 0), Math_PI / 2.0); - paste_indicator.orientation = r.get_orthogonal_index(); + paste_indicator.orientation = node->get_orthogonal_index_from_basis(r); _update_paste_indicator(); break; } - r.set_orthogonal_index(cursor_rot); + r = node->get_basis_with_orthogonal_index(cursor_rot); r.rotate(Vector3(0, 1, 0), Math_PI / 2.0); - cursor_rot = r.get_orthogonal_index(); + cursor_rot = node->get_orthogonal_index_from_basis(r); _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_BACK_ROTATE_X: { Basis r; if (input_action == INPUT_PASTE) { - r.set_orthogonal_index(paste_indicator.orientation); + r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); r.rotate(Vector3(1, 0, 0), Math_PI / 2.0); - paste_indicator.orientation = r.get_orthogonal_index(); + paste_indicator.orientation = node->get_orthogonal_index_from_basis(r); _update_paste_indicator(); break; } - r.set_orthogonal_index(cursor_rot); + r = node->get_basis_with_orthogonal_index(cursor_rot); r.rotate(Vector3(1, 0, 0), Math_PI / 2.0); - cursor_rot = r.get_orthogonal_index(); + cursor_rot = node->get_orthogonal_index_from_basis(r); _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_BACK_ROTATE_Z: { Basis r; if (input_action == INPUT_PASTE) { - r.set_orthogonal_index(paste_indicator.orientation); + r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); r.rotate(Vector3(0, 0, 1), Math_PI / 2.0); - paste_indicator.orientation = r.get_orthogonal_index(); + paste_indicator.orientation = node->get_orthogonal_index_from_basis(r); _update_paste_indicator(); break; } - r.set_orthogonal_index(cursor_rot); + r = node->get_basis_with_orthogonal_index(cursor_rot); r.rotate(Vector3(0, 0, 1), Math_PI / 2.0); - cursor_rot = r.get_orthogonal_index(); + cursor_rot = node->get_orthogonal_index_from_basis(r); _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_CLEAR_ROTATION: { @@ -242,7 +243,7 @@ void GridMapEditor::_menu_option(int p_option) { void GridMapEditor::_update_cursor_transform() { cursor_transform = Transform3D(); cursor_transform.origin = cursor_origin; - cursor_transform.basis.set_orthogonal_index(cursor_rot); + cursor_transform.basis = node->get_basis_with_orthogonal_index(cursor_rot); cursor_transform.basis *= node->get_cell_scale(); cursor_transform = node->get_global_transform() * cursor_transform; @@ -543,7 +544,7 @@ void GridMapEditor::_update_paste_indicator() { xf.scale(scale); xf.origin = (paste_indicator.begin + (paste_indicator.current - paste_indicator.click) + center) * node->get_cell_size(); Basis rot; - rot.set_orthogonal_index(paste_indicator.orientation); + rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation); xf.basis = rot * xf.basis; xf.translate_local((-center * node->get_cell_size()) / scale); @@ -556,7 +557,7 @@ void GridMapEditor::_update_paste_indicator() { xf.translate_local(item.grid_offset * node->get_cell_size()); Basis item_rot; - item_rot.set_orthogonal_index(item.orientation); + item_rot = node->get_basis_with_orthogonal_index(item.orientation); xf.basis = item_rot * xf.basis * node->get_cell_scale(); RenderingServer::get_singleton()->instance_set_transform(item.instance, node->get_global_transform() * xf); @@ -568,7 +569,7 @@ void GridMapEditor::_do_paste() { bool reselect = options->get_popup()->is_item_checked(idx); Basis rot; - rot.set_orthogonal_index(paste_indicator.orientation); + rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation); Vector3 ofs = paste_indicator.current - paste_indicator.click; undo_redo->create_action(TTR("GridMap Paste Selection")); @@ -577,10 +578,10 @@ void GridMapEditor::_do_paste() { Vector3 position = rot.xform(item.grid_offset) + paste_indicator.begin + ofs; Basis orm; - orm.set_orthogonal_index(item.orientation); + orm = node->get_basis_with_orthogonal_index(item.orientation); orm = rot * orm; - undo_redo->add_do_method(node, "set_cell_item", position, item.cell_item, orm.get_orthogonal_index()); + undo_redo->add_do_method(node, "set_cell_item", position, item.cell_item, node->get_orthogonal_index_from_basis(orm)); undo_redo->add_undo_method(node, "set_cell_item", position, node->get_cell_item(position), node->get_cell_item_orientation(position)); } diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h index 3b29397502..a64dc4a80b 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.h +++ b/modules/gridmap/editor/grid_map_editor_plugin.h @@ -39,6 +39,7 @@ #include "scene/gui/slider.h" #include "scene/gui/spin_box.h" +class EditorUndoRedoManager; class Node3DEditorPlugin; class GridMapEditor : public VBoxContainer { @@ -62,7 +63,7 @@ class GridMapEditor : public VBoxContainer { DISPLAY_LIST }; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; InputAction input_action = INPUT_NONE; Panel *panel = nullptr; MenuButton *options = nullptr; diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 7d80cbef7c..6384446bce 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -428,6 +428,75 @@ int GridMap::get_cell_item_orientation(const Vector3i &p_position) const { return cell_map[key].rot; } +static const Basis _ortho_bases[24] = { + Basis(1, 0, 0, 0, 1, 0, 0, 0, 1), + Basis(0, -1, 0, 1, 0, 0, 0, 0, 1), + Basis(-1, 0, 0, 0, -1, 0, 0, 0, 1), + Basis(0, 1, 0, -1, 0, 0, 0, 0, 1), + Basis(1, 0, 0, 0, 0, -1, 0, 1, 0), + Basis(0, 0, 1, 1, 0, 0, 0, 1, 0), + Basis(-1, 0, 0, 0, 0, 1, 0, 1, 0), + Basis(0, 0, -1, -1, 0, 0, 0, 1, 0), + Basis(1, 0, 0, 0, -1, 0, 0, 0, -1), + Basis(0, 1, 0, 1, 0, 0, 0, 0, -1), + Basis(-1, 0, 0, 0, 1, 0, 0, 0, -1), + Basis(0, -1, 0, -1, 0, 0, 0, 0, -1), + Basis(1, 0, 0, 0, 0, 1, 0, -1, 0), + Basis(0, 0, -1, 1, 0, 0, 0, -1, 0), + Basis(-1, 0, 0, 0, 0, -1, 0, -1, 0), + Basis(0, 0, 1, -1, 0, 0, 0, -1, 0), + Basis(0, 0, 1, 0, 1, 0, -1, 0, 0), + Basis(0, -1, 0, 0, 0, 1, -1, 0, 0), + Basis(0, 0, -1, 0, -1, 0, -1, 0, 0), + Basis(0, 1, 0, 0, 0, -1, -1, 0, 0), + Basis(0, 0, 1, 0, -1, 0, 1, 0, 0), + Basis(0, 1, 0, 0, 0, 1, 1, 0, 0), + Basis(0, 0, -1, 0, 1, 0, 1, 0, 0), + Basis(0, -1, 0, 0, 0, -1, 1, 0, 0) +}; + +Basis GridMap::get_cell_item_basis(const Vector3i &p_position) const { + int orientation = get_cell_item_orientation(p_position); + + if (orientation == -1) { + return Basis(); + } + + return get_basis_with_orthogonal_index(orientation); +} + +Basis GridMap::get_basis_with_orthogonal_index(int p_index) const { + ERR_FAIL_INDEX_V(p_index, 24, Basis()); + + return _ortho_bases[p_index]; +} + +int GridMap::get_orthogonal_index_from_basis(const Basis &p_basis) const { + Basis orth = p_basis; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + real_t v = orth[i][j]; + if (v > 0.5) { + v = 1.0; + } else if (v < -0.5) { + v = -1.0; + } else { + v = 0; + } + + orth[i][j] = v; + } + } + + for (int i = 0; i < 24; i++) { + if (_ortho_bases[i] == orth) { + return i; + } + } + + return 0; +} + Vector3i GridMap::world_to_map(const Vector3 &p_world_position) const { Vector3 map_position = (p_world_position / cell_size).floor(); return Vector3i(map_position); @@ -529,7 +598,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { Transform3D xform; - xform.basis.set_orthogonal_index(c.rot); + xform.basis = _ortho_bases[c.rot]; xform.set_origin(cellpos * cell_size + ofs); xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale)); if (baked_meshes.size() == 0) { @@ -921,6 +990,9 @@ void GridMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cell_item", "position", "item", "orientation"), &GridMap::set_cell_item, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_cell_item", "position"), &GridMap::get_cell_item); ClassDB::bind_method(D_METHOD("get_cell_item_orientation", "position"), &GridMap::get_cell_item_orientation); + ClassDB::bind_method(D_METHOD("get_cell_item_basis", "position"), &GridMap::get_cell_item_basis); + ClassDB::bind_method(D_METHOD("get_basis_with_orthogonal_index", "index"), &GridMap::get_basis_with_orthogonal_index); + ClassDB::bind_method(D_METHOD("get_orthogonal_index_from_basis", "basis"), &GridMap::get_orthogonal_index_from_basis); ClassDB::bind_method(D_METHOD("world_to_map", "world_position"), &GridMap::world_to_map); ClassDB::bind_method(D_METHOD("map_to_world", "map_position"), &GridMap::map_to_world); @@ -1025,7 +1097,7 @@ Array GridMap::get_meshes() const { Transform3D xform; - xform.basis.set_orthogonal_index(E.value.rot); + xform.basis = _ortho_bases[E.value.rot]; xform.set_origin(cellpos * cell_size + ofs); xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale)); @@ -1079,7 +1151,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe Transform3D xform; - xform.basis.set_orthogonal_index(E.value.rot); + xform.basis = _ortho_bases[E.value.rot]; xform.set_origin(cellpos * cell_size + ofs); xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale)); diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 078a1d9de5..00cebd35e9 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -263,6 +263,9 @@ public: void set_cell_item(const Vector3i &p_position, int p_item, int p_rot = 0); int get_cell_item(const Vector3i &p_position) const; int get_cell_item_orientation(const Vector3i &p_position) const; + Basis get_cell_item_basis(const Vector3i &p_position) const; + Basis get_basis_with_orthogonal_index(int p_index) const; + int get_orthogonal_index_from_basis(const Basis &p_basis) const; Vector3i world_to_map(const Vector3 &p_world_position) const; Vector3 map_to_world(const Vector3i &p_map_position) const; diff --git a/modules/multiplayer/editor/replication_editor_plugin.cpp b/modules/multiplayer/editor/replication_editor_plugin.cpp index 50f1434ad8..f045018f25 100644 --- a/modules/multiplayer/editor/replication_editor_plugin.cpp +++ b/modules/multiplayer/editor/replication_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/inspector_dock.h" #include "editor/scene_tree_editor.h" #include "modules/multiplayer/multiplayer_synchronizer.h" @@ -139,7 +140,7 @@ void ReplicationEditor::_add_sync_property(String p_path) { return; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(TTR("Add property to synchronizer")); if (config.is_null()) { @@ -354,7 +355,7 @@ void ReplicationEditor::_tree_item_edited() { int column = tree->get_edited_column(); ERR_FAIL_COND(column < 1 || column > 2); const NodePath prop = ti->get_metadata(0); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); bool value = ti->is_checked(column); String method; if (column == 1) { @@ -394,7 +395,7 @@ void ReplicationEditor::_dialog_closed(bool p_confirmed) { int idx = config->property_get_index(prop); bool spawn = config->property_get_spawn(prop); bool sync = config->property_get_sync(prop); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Remove Property")); undo_redo->add_do_method(config.ptr(), "remove_property", prop); undo_redo->add_undo_method(config.ptr(), "add_property", prop, idx); diff --git a/modules/noise/fastnoise_lite.cpp b/modules/noise/fastnoise_lite.cpp index b21e3247d7..06d97838f6 100644 --- a/modules/noise/fastnoise_lite.cpp +++ b/modules/noise/fastnoise_lite.cpp @@ -476,24 +476,24 @@ void FastNoiseLite::_bind_methods() { BIND_ENUM_CONSTANT(DOMAIN_WARP_FRACTAL_INDEPENDENT); } -void FastNoiseLite::_validate_property(PropertyInfo &property) const { - if (property.name.begins_with("cellular") && get_noise_type() != TYPE_CELLULAR) { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void FastNoiseLite::_validate_property(PropertyInfo &p_property) const { + if (p_property.name.begins_with("cellular") && get_noise_type() != TYPE_CELLULAR) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; return; } - if (property.name != "fractal_type" && property.name.begins_with("fractal") && get_fractal_type() == FRACTAL_NONE) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (p_property.name != "fractal_type" && p_property.name.begins_with("fractal") && get_fractal_type() == FRACTAL_NONE) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; return; } - if (property.name == "fractal_ping_pong_strength" && get_fractal_type() != FRACTAL_PING_PONG) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (p_property.name == "fractal_ping_pong_strength" && get_fractal_type() != FRACTAL_PING_PONG) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; return; } - if (property.name != "domain_warp_enabled" && property.name.begins_with("domain_warp") && !domain_warp_enabled) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (p_property.name != "domain_warp_enabled" && p_property.name.begins_with("domain_warp") && !domain_warp_enabled) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; return; } } diff --git a/modules/noise/fastnoise_lite.h b/modules/noise/fastnoise_lite.h index fe8cd7ce6e..50c633b923 100644 --- a/modules/noise/fastnoise_lite.h +++ b/modules/noise/fastnoise_lite.h @@ -92,7 +92,7 @@ public: protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; private: _FastNoiseLite _noise; diff --git a/modules/noise/noise_texture.cpp b/modules/noise/noise_texture.cpp index ca55d3b96d..923b420581 100644 --- a/modules/noise/noise_texture.cpp +++ b/modules/noise/noise_texture.cpp @@ -94,16 +94,16 @@ void NoiseTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "Noise"), "set_noise", "get_noise"); } -void NoiseTexture::_validate_property(PropertyInfo &property) const { - if (property.name == "bump_strength") { +void NoiseTexture::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "bump_strength") { if (!as_normal_map) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - if (property.name == "seamless_blend_skirt") { + if (p_property.name == "seamless_blend_skirt") { if (!seamless) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } } diff --git a/modules/noise/noise_texture.h b/modules/noise/noise_texture.h index 6c088562a1..83fbcc2d10 100644 --- a/modules/noise/noise_texture.h +++ b/modules/noise/noise_texture.h @@ -75,7 +75,7 @@ private: protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_noise(Ref<Noise> p_noise); diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp index 7f8e9d8254..a5eb09f786 100644 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ b/modules/visual_script/editor/visual_script_editor.cpp @@ -43,6 +43,7 @@ #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/check_button.h" #include "scene/gui/graph_edit.h" #include "scene/gui/separator.h" @@ -74,7 +75,7 @@ class VisualScriptEditorSignalEdit : public Object { StringName sig; public: - UndoRedo *undo_redo; + Ref<EditorUndoRedoManager> undo_redo; Ref<VisualScript> script; protected: @@ -197,8 +198,6 @@ public: sig = p_sig; notify_property_list_changed(); } - - VisualScriptEditorSignalEdit() { undo_redo = nullptr; } }; class VisualScriptEditorVariableEdit : public Object { @@ -207,7 +206,7 @@ class VisualScriptEditorVariableEdit : public Object { StringName var; public: - UndoRedo *undo_redo; + Ref<EditorUndoRedoManager> undo_redo; Ref<VisualScript> script; protected: @@ -355,8 +354,6 @@ public: var = p_var; notify_property_list_changed(); } - - VisualScriptEditorVariableEdit() { undo_redo = nullptr; } }; static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { @@ -2936,7 +2933,7 @@ Control *VisualScriptEditor::get_edit_menu() { } void VisualScriptEditor::_change_base_type() { - select_base_type->popup_create(true, true); + select_base_type->popup_create(true, true, script->get_instance_base_type()); } void VisualScriptEditor::_toggle_tool_script() { diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h index 6b337e52f6..306f71ecf8 100644 --- a/modules/visual_script/editor/visual_script_editor.h +++ b/modules/visual_script/editor/visual_script_editor.h @@ -38,6 +38,7 @@ class GraphEdit; +class EditorUndoRedoManager; class VisualScriptEditorSignalEdit; class VisualScriptEditorVariableEdit; @@ -135,8 +136,7 @@ class VisualScriptEditor : public ScriptEditorBase { EditorProperty *default_property_editor = nullptr; Ref<VisualScriptEditedProperty> edited_default_property_holder; - UndoRedo *undo_redo = nullptr; - + Ref<EditorUndoRedoManager> undo_redo; Tree *members = nullptr; AcceptDialog *function_name_edit = nullptr; LineEdit *function_name_box = nullptr; diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index b16358ae38..e79d3bae8a 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -512,32 +512,32 @@ Dictionary VisualScriptFunctionCall::_get_argument_cache() const { return method_cache; } -void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const { - if (property.name == "base_type") { +void VisualScriptFunctionCall::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - if (property.name == "base_script") { + if (p_property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } - if (property.name == "basic_type") { + if (p_property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } - if (property.name == "singleton") { + if (p_property.name == "singleton") { if (call_mode != CALL_MODE_SINGLETON) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } else { List<Engine::Singleton> names; Engine::get_singleton()->get_singletons(&names); - property.hint = PROPERTY_HINT_ENUM; + p_property.hint = PROPERTY_HINT_ENUM; String sl; for (const Engine::Singleton &E : names) { if (!sl.is_empty()) { @@ -545,41 +545,41 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } sl += E.name; } - property.hint_string = sl; + p_property.hint_string = sl; } } - if (property.name == "node_path") { + if (p_property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { - property.hint_string = bnode->get_path(); //convert to long string + p_property.hint_string = bnode->get_path(); //convert to long string } } } - if (property.name == "function") { + if (p_property.name == "function") { if (call_mode == CALL_MODE_BASIC_TYPE) { - property.hint = PROPERTY_HINT_METHOD_OF_VARIANT_TYPE; - property.hint_string = Variant::get_type_name(basic_type); + p_property.hint = PROPERTY_HINT_METHOD_OF_VARIANT_TYPE; + p_property.hint_string = Variant::get_type_name(basic_type); } else if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) { - property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT; - property.hint_string = itos(get_visual_script()->get_instance_id()); + p_property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT; + p_property.hint_string = itos(get_visual_script()->get_instance_id()); } else if (call_mode == CALL_MODE_SINGLETON) { Object *obj = Engine::get_singleton()->get_singleton_object(singleton); if (obj) { - property.hint = PROPERTY_HINT_METHOD_OF_INSTANCE; - property.hint_string = itos(obj->get_instance_id()); + p_property.hint = PROPERTY_HINT_METHOD_OF_INSTANCE; + p_property.hint_string = itos(obj->get_instance_id()); } else { - property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE; - property.hint_string = base_type; //should be cached + p_property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE; + p_property.hint_string = base_type; //should be cached } } else if (call_mode == CALL_MODE_INSTANCE) { - property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE; - property.hint_string = base_type; + p_property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE; + p_property.hint_string = base_type; if (!base_script.is_empty()) { if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { @@ -589,8 +589,8 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const if (ResourceCache::has(base_script)) { Ref<Script> script = ResourceCache::get_ref(base_script); if (script.is_valid()) { - property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT; - property.hint_string = itos(script->get_instance_id()); + p_property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT; + p_property.hint_string = itos(script->get_instance_id()); } } } @@ -598,17 +598,17 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } else if (call_mode == CALL_MODE_NODE_PATH) { Node *node = _get_base_node(); if (node) { - property.hint = PROPERTY_HINT_METHOD_OF_INSTANCE; - property.hint_string = itos(node->get_instance_id()); + p_property.hint = PROPERTY_HINT_METHOD_OF_INSTANCE; + p_property.hint_string = itos(node->get_instance_id()); } else { - property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE; - property.hint_string = get_base_type(); + p_property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE; + p_property.hint_string = get_base_type(); } } } - if (property.name == "use_default_args") { - property.hint = PROPERTY_HINT_RANGE; + if (p_property.name == "use_default_args") { + p_property.hint = PROPERTY_HINT_RANGE; int mc = 0; @@ -622,15 +622,15 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } if (mc == 0) { - property.usage = PROPERTY_USAGE_NONE; //do not show + p_property.usage = PROPERTY_USAGE_NONE; //do not show } else { - property.hint_string = "0," + itos(mc) + ",1"; + p_property.hint_string = "0," + itos(mc) + ",1"; } } - if (property.name == "rpc_call_mode") { + if (p_property.name == "rpc_call_mode") { if (call_mode == CALL_MODE_BASIC_TYPE) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } } @@ -1290,47 +1290,47 @@ VisualScriptPropertySet::AssignOp VisualScriptPropertySet::get_assign_op() const return assign_op; } -void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { - if (property.name == "base_type") { +void VisualScriptPropertySet::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - if (property.name == "base_script") { + if (p_property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } - if (property.name == "basic_type") { + if (p_property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } - if (property.name == "node_path") { + if (p_property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { - property.hint_string = bnode->get_path(); //convert to long string + p_property.hint_string = bnode->get_path(); //convert to long string } } } - if (property.name == "property") { + if (p_property.name == "property") { if (call_mode == CALL_MODE_BASIC_TYPE) { - property.hint = PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE; - property.hint_string = Variant::get_type_name(basic_type); + p_property.hint = PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE; + p_property.hint_string = Variant::get_type_name(basic_type); } else if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) { - property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; - property.hint_string = itos(get_visual_script()->get_instance_id()); + p_property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; + p_property.hint_string = itos(get_visual_script()->get_instance_id()); } else if (call_mode == CALL_MODE_INSTANCE) { - property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; - property.hint_string = base_type; + p_property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; + p_property.hint_string = base_type; if (!base_script.is_empty()) { if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { @@ -1340,8 +1340,8 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { if (ResourceCache::has(base_script)) { Ref<Script> script = ResourceCache::get_ref(base_script); if (script.is_valid()) { - property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; - property.hint_string = itos(script->get_instance_id()); + p_property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; + p_property.hint_string = itos(script->get_instance_id()); } } } @@ -1349,16 +1349,16 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { } else if (call_mode == CALL_MODE_NODE_PATH) { Node *node = _get_base_node(); if (node) { - property.hint = PROPERTY_HINT_PROPERTY_OF_INSTANCE; - property.hint_string = itos(node->get_instance_id()); + p_property.hint = PROPERTY_HINT_PROPERTY_OF_INSTANCE; + p_property.hint_string = itos(node->get_instance_id()); } else { - property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; - property.hint_string = get_base_type(); + p_property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; + p_property.hint_string = get_base_type(); } } } - if (property.name == "index") { + if (p_property.name == "index") { Callable::CallError ce; Variant v; Variant::construct(type_cache.type, v, nullptr, 0, ce); @@ -1369,11 +1369,11 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { options += "," + E.name; } - property.hint = PROPERTY_HINT_ENUM; - property.hint_string = options; - property.type = Variant::STRING; + p_property.hint = PROPERTY_HINT_ENUM; + p_property.hint_string = options; + p_property.type = Variant::STRING; if (options.is_empty()) { - property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index + p_property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index } } } @@ -1996,47 +1996,47 @@ StringName VisualScriptPropertyGet::get_index() const { return index; } -void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { - if (property.name == "base_type") { +void VisualScriptPropertyGet::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - if (property.name == "base_script") { + if (p_property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } - if (property.name == "basic_type") { + if (p_property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } - if (property.name == "node_path") { + if (p_property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { - property.hint_string = bnode->get_path(); //convert to long string + p_property.hint_string = bnode->get_path(); //convert to long string } } } - if (property.name == "property") { + if (p_property.name == "property") { if (call_mode == CALL_MODE_BASIC_TYPE) { - property.hint = PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE; - property.hint_string = Variant::get_type_name(basic_type); + p_property.hint = PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE; + p_property.hint_string = Variant::get_type_name(basic_type); } else if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) { - property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; - property.hint_string = itos(get_visual_script()->get_instance_id()); + p_property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; + p_property.hint_string = itos(get_visual_script()->get_instance_id()); } else if (call_mode == CALL_MODE_INSTANCE) { - property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; - property.hint_string = base_type; + p_property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; + p_property.hint_string = base_type; if (!base_script.is_empty()) { if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { @@ -2046,24 +2046,24 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { if (ResourceCache::has(base_script)) { Ref<Script> script = ResourceCache::get_ref(base_script); if (script.is_valid()) { - property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; - property.hint_string = itos(script->get_instance_id()); + p_property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; + p_property.hint_string = itos(script->get_instance_id()); } } } } else if (call_mode == CALL_MODE_NODE_PATH) { Node *node = _get_base_node(); if (node) { - property.hint = PROPERTY_HINT_PROPERTY_OF_INSTANCE; - property.hint_string = itos(node->get_instance_id()); + p_property.hint = PROPERTY_HINT_PROPERTY_OF_INSTANCE; + p_property.hint_string = itos(node->get_instance_id()); } else { - property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; - property.hint_string = get_base_type(); + p_property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; + p_property.hint_string = get_base_type(); } } } - if (property.name == "index") { + if (p_property.name == "index") { Callable::CallError ce; Variant v; Variant::construct(type_cache, v, nullptr, 0, ce); @@ -2074,11 +2074,11 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { options += "," + E.name; } - property.hint = PROPERTY_HINT_ENUM; - property.hint_string = options; - property.type = Variant::STRING; + p_property.hint = PROPERTY_HINT_ENUM; + p_property.hint_string = options; + p_property.type = Variant::STRING; if (options.is_empty()) { - property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index + p_property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index } } } @@ -2322,9 +2322,9 @@ StringName VisualScriptEmitSignal::get_signal() const { return name; } -void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { - if (property.name == "signal") { - property.hint = PROPERTY_HINT_ENUM; +void VisualScriptEmitSignal::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "signal") { + p_property.hint = PROPERTY_HINT_ENUM; List<StringName> sigs; List<MethodInfo> base_sigs; @@ -2349,7 +2349,7 @@ void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { ml += E.name; } - property.hint_string = ml; + p_property.hint_string = ml; } } diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h index 886ed7bc81..70f601307b 100644 --- a/modules/visual_script/visual_script_func_nodes.h +++ b/modules/visual_script/visual_script_func_nodes.h @@ -75,7 +75,7 @@ private: Dictionary _get_argument_cache() const; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); @@ -187,7 +187,7 @@ private: void _adjust_input_index(PropertyInfo &pinfo) const; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); @@ -275,7 +275,7 @@ private: void _adjust_input_index(PropertyInfo &pinfo) const; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); @@ -330,7 +330,7 @@ private: StringName name; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 5907e6a489..f02a79a617 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -1299,8 +1299,8 @@ StringName VisualScriptVariableGet::get_variable() const { return variable; } -void VisualScriptVariableGet::_validate_property(PropertyInfo &property) const { - if (property.name == "var_name" && get_visual_script().is_valid()) { +void VisualScriptVariableGet::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "var_name" && get_visual_script().is_valid()) { Ref<VisualScript> vs = get_visual_script(); List<StringName> vars; vs->get_variable_list(&vars); @@ -1314,8 +1314,8 @@ void VisualScriptVariableGet::_validate_property(PropertyInfo &property) const { vhint += E.operator String(); } - property.hint = PROPERTY_HINT_ENUM; - property.hint_string = vhint; + p_property.hint = PROPERTY_HINT_ENUM; + p_property.hint_string = vhint; } } @@ -1409,8 +1409,8 @@ StringName VisualScriptVariableSet::get_variable() const { return variable; } -void VisualScriptVariableSet::_validate_property(PropertyInfo &property) const { - if (property.name == "var_name" && get_visual_script().is_valid()) { +void VisualScriptVariableSet::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "var_name" && get_visual_script().is_valid()) { Ref<VisualScript> vs = get_visual_script(); List<StringName> vars; vs->get_variable_list(&vars); @@ -1424,8 +1424,8 @@ void VisualScriptVariableSet::_validate_property(PropertyInfo &property) const { vhint += E.operator String(); } - property.hint = PROPERTY_HINT_ENUM; - property.hint_string = vhint; + p_property.hint = PROPERTY_HINT_ENUM; + p_property.hint_string = vhint; } } @@ -1533,11 +1533,11 @@ Variant VisualScriptConstant::get_constant_value() const { return value; } -void VisualScriptConstant::_validate_property(PropertyInfo &property) const { - if (property.name == "value") { - property.type = type; +void VisualScriptConstant::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "value") { + p_property.type = type; if (type == Variant::NIL) { - property.usage = PROPERTY_USAGE_NONE; //do not save if nil + p_property.usage = PROPERTY_USAGE_NONE; //do not save if nil } } } @@ -1982,17 +1982,17 @@ VisualScriptNodeInstance *VisualScriptClassConstant::instantiate(VisualScriptIns return instance; } -void VisualScriptClassConstant::_validate_property(PropertyInfo &property) const { - if (property.name == "constant") { +void VisualScriptClassConstant::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "constant") { List<String> constants; ClassDB::get_integer_constant_list(base_type, &constants, true); - property.hint_string = ""; + p_property.hint_string = ""; for (const String &E : constants) { - if (!property.hint_string.is_empty()) { - property.hint_string += ","; + if (!p_property.hint_string.is_empty()) { + p_property.hint_string += ","; } - property.hint_string += E; + p_property.hint_string += E; } } } @@ -2115,21 +2115,21 @@ VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instantiate(VisualScrip return instance; } -void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &property) const { - if (property.name == "constant") { +void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "constant") { List<StringName> constants; Variant::get_constants_for_type(type, &constants); if (constants.size() == 0) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; return; } - property.hint_string = ""; + p_property.hint_string = ""; for (const StringName &E : constants) { - if (!property.hint_string.is_empty()) { - property.hint_string += ","; + if (!p_property.hint_string.is_empty()) { + p_property.hint_string += ","; } - property.hint_string += String(E); + p_property.hint_string += String(E); } } } @@ -2344,7 +2344,7 @@ VisualScriptEngineSingleton::TypeGuess VisualScriptEngineSingleton::guess_output return tg; } -void VisualScriptEngineSingleton::_validate_property(PropertyInfo &property) const { +void VisualScriptEngineSingleton::_validate_property(PropertyInfo &p_property) const { String cc; List<Engine::Singleton> singletons; @@ -2362,8 +2362,8 @@ void VisualScriptEngineSingleton::_validate_property(PropertyInfo &property) con cc += E.name; } - property.hint = PROPERTY_HINT_ENUM; - property.hint_string = cc; + p_property.hint = PROPERTY_HINT_ENUM; + p_property.hint_string = cc; } void VisualScriptEngineSingleton::_bind_methods() { @@ -2525,9 +2525,9 @@ VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGu return tg; } -void VisualScriptSceneNode::_validate_property(PropertyInfo &property) const { +void VisualScriptSceneNode::_validate_property(PropertyInfo &p_property) const { #ifdef TOOLS_ENABLED - if (property.name == "node_path") { + if (p_property.name == "node_path") { Ref<Script> script = get_visual_script(); if (!script.is_valid()) { return; @@ -2552,7 +2552,7 @@ void VisualScriptSceneNode::_validate_property(PropertyInfo &property) const { return; } - property.hint_string = script_node->get_path(); + p_property.hint_string = script_node->get_path(); } #endif } @@ -2646,7 +2646,7 @@ VisualScriptSceneTree::TypeGuess VisualScriptSceneTree::guess_output_type(TypeGu return tg; } -void VisualScriptSceneTree::_validate_property(PropertyInfo &property) const { +void VisualScriptSceneTree::_validate_property(PropertyInfo &p_property) const { } void VisualScriptSceneTree::_bind_methods() { @@ -3757,9 +3757,9 @@ VisualScriptNodeInstance *VisualScriptInputAction::instantiate(VisualScriptInsta return instance; } -void VisualScriptInputAction::_validate_property(PropertyInfo &property) const { - if (property.name == "action") { - property.hint = PROPERTY_HINT_ENUM; +void VisualScriptInputAction::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "action") { + p_property.hint = PROPERTY_HINT_ENUM; String actions; List<PropertyInfo> pinfo; @@ -3785,7 +3785,7 @@ void VisualScriptInputAction::_validate_property(PropertyInfo &property) const { actions += al[i]; } - property.hint_string = actions; + p_property.hint_string = actions; } } @@ -3935,7 +3935,7 @@ VisualScriptNodeInstance *VisualScriptDeconstruct::instantiate(VisualScriptInsta return instance; } -void VisualScriptDeconstruct::_validate_property(PropertyInfo &property) const { +void VisualScriptDeconstruct::_validate_property(PropertyInfo &p_property) const { } void VisualScriptDeconstruct::_bind_methods() { diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h index 35e3c490cd..72a99b9fd2 100644 --- a/modules/visual_script/visual_script_nodes.h +++ b/modules/visual_script/visual_script_nodes.h @@ -269,7 +269,7 @@ class VisualScriptVariableGet : public VisualScriptNode { StringName variable; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: @@ -301,7 +301,7 @@ class VisualScriptVariableSet : public VisualScriptNode { StringName variable; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: @@ -334,7 +334,7 @@ class VisualScriptConstant : public VisualScriptNode { Variant value; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: @@ -478,7 +478,7 @@ class VisualScriptClassConstant : public VisualScriptNode { protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: virtual int get_output_sequence_port_count() const override; @@ -514,7 +514,7 @@ class VisualScriptBasicTypeConstant : public VisualScriptNode { protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: virtual int get_output_sequence_port_count() const override; @@ -598,7 +598,7 @@ class VisualScriptEngineSingleton : public VisualScriptNode { String singleton; protected: - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); @@ -633,7 +633,7 @@ class VisualScriptSceneNode : public VisualScriptNode { NodePath path; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: @@ -665,7 +665,7 @@ class VisualScriptSceneTree : public VisualScriptNode { GDCLASS(VisualScriptSceneTree, VisualScriptNode); protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: @@ -1010,7 +1010,7 @@ public: Mode mode; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); @@ -1058,7 +1058,7 @@ class VisualScriptDeconstruct : public VisualScriptNode { void _set_elem_cache(const Array &p_elements); Array _get_elem_cache() const; - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; protected: static void _bind_methods(); diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index 96e91a0baf..05dbe102f5 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -171,10 +171,10 @@ double VisualScriptYield::get_wait_time() { return wait_time; } -void VisualScriptYield::_validate_property(PropertyInfo &property) const { - if (property.name == "wait_time") { +void VisualScriptYield::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "wait_time") { if (yield_mode != YIELD_WAIT) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } } @@ -417,26 +417,26 @@ VisualScriptYieldSignal::CallMode VisualScriptYieldSignal::get_call_mode() const return call_mode; } -void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const { - if (property.name == "base_type") { +void VisualScriptYieldSignal::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - if (property.name == "node_path") { + if (p_property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { - property.hint_string = bnode->get_path(); //convert to long string + p_property.hint_string = bnode->get_path(); //convert to long string } } } - if (property.name == "signal") { - property.hint = PROPERTY_HINT_ENUM; + if (p_property.name == "signal") { + p_property.hint = PROPERTY_HINT_ENUM; List<MethodInfo> methods; @@ -460,7 +460,7 @@ void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const { ml += E; } - property.hint_string = ml; + p_property.hint_string = ml; } } diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h index a7bf4e8a78..248f2b6e94 100644 --- a/modules/visual_script/visual_script_yield_nodes.h +++ b/modules/visual_script/visual_script_yield_nodes.h @@ -50,7 +50,7 @@ private: double wait_time; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); @@ -103,7 +103,7 @@ private: StringName _get_base_type() const; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 35e13c94fc..d932745177 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -98,7 +98,6 @@ public: String get_user_data_dir() const override; bool is_userfs_persistent() const override; - bool is_single_window() const override { return true; } void alert(const String &p_alert, const String &p_title = "ALERT!") override; diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index d56c7b8811..177f587f4f 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -104,12 +104,12 @@ Rect2 AnimatedSprite2D::_get_rect() const { return Rect2(ofs, s); } -void AnimatedSprite2D::_validate_property(PropertyInfo &property) const { +void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const { if (!frames.is_valid()) { return; } - if (property.name == "animation") { - property.hint = PROPERTY_HINT_ENUM; + if (p_property.name == "animation") { + p_property.hint = PROPERTY_HINT_ENUM; List<StringName> names; frames->get_animation_list(&names); names.sort_custom<StringName::AlphCompare>(); @@ -118,33 +118,33 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &property) const { for (List<StringName>::Element *E = names.front(); E; E = E->next()) { if (E->prev()) { - property.hint_string += ","; + p_property.hint_string += ","; } - property.hint_string += String(E->get()); + p_property.hint_string += String(E->get()); if (animation == E->get()) { current_found = true; } } if (!current_found) { - if (property.hint_string.is_empty()) { - property.hint_string = String(animation); + if (p_property.hint_string.is_empty()) { + p_property.hint_string = String(animation); } else { - property.hint_string = String(animation) + "," + property.hint_string; + p_property.hint_string = String(animation) + "," + p_property.hint_string; } } } - if (property.name == "frame") { - property.hint = PROPERTY_HINT_RANGE; + if (p_property.name == "frame") { + p_property.hint = PROPERTY_HINT_RANGE; if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) { - property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1"; + p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1"; } else { // Avoid an error, `hint_string` is required for `PROPERTY_HINT_RANGE`. - property.hint_string = "0,0,1"; + p_property.hint_string = "0,0,1"; } - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; + p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } } diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h index ec38795a1a..0a19e250d8 100644 --- a/scene/2d/animated_sprite_2d.h +++ b/scene/2d/animated_sprite_2d.h @@ -62,7 +62,7 @@ class AnimatedSprite2D : public Node2D { protected: static void _bind_methods(); void _notification(int p_what); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: #ifdef TOOLS_ENABLED diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index 7890348314..75f1497edc 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -498,8 +498,8 @@ StringName Area2D::get_audio_bus_name() const { return "Master"; } -void Area2D::_validate_property(PropertyInfo &property) const { - if (property.name == "audio_bus_name") { +void Area2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "audio_bus_name") { String options; for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { if (i > 0) { @@ -509,28 +509,28 @@ void Area2D::_validate_property(PropertyInfo &property) const { options += name; } - property.hint_string = options; - } else if (property.name.begins_with("gravity") && property.name != "gravity_space_override") { + p_property.hint_string = options; + } else if (p_property.name.begins_with("gravity") && p_property.name != "gravity_space_override") { if (gravity_space_override == SPACE_OVERRIDE_DISABLED) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } else { if (gravity_is_point) { - if (property.name == "gravity_direction") { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name == "gravity_direction") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } else { - if (property.name.begins_with("gravity_point_")) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name.begins_with("gravity_point_")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } } - } else if (property.name.begins_with("linear_damp") && property.name != "linear_damp_space_override") { + } else if (p_property.name.begins_with("linear_damp") && p_property.name != "linear_damp_space_override") { if (linear_damp_space_override == SPACE_OVERRIDE_DISABLED) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - } else if (property.name.begins_with("angular_damp") && property.name != "angular_damp_space_override") { + } else if (p_property.name.begins_with("angular_damp") && p_property.name != "angular_damp_space_override") { if (angular_damp_space_override == SPACE_OVERRIDE_DISABLED) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } } diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h index a584420ced..3d8d77eabb 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/area_2d.h @@ -135,7 +135,7 @@ private: protected: void _notification(int p_what); static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_gravity_space_override_mode(SpaceOverride p_mode); diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 94d22111ea..fa49552085 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -323,8 +323,8 @@ bool AudioStreamPlayer2D::_is_active() const { return active.is_set(); } -void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const { - if (property.name == "bus") { +void AudioStreamPlayer2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "bus") { String options; for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { if (i > 0) { @@ -334,7 +334,7 @@ void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const { options += name; } - property.hint_string = options; + p_property.hint_string = options; } } diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h index d1c4dc4fdf..616d7fdb60 100644 --- a/scene/2d/audio_stream_player_2d.h +++ b/scene/2d/audio_stream_player_2d.h @@ -85,7 +85,7 @@ private: float cached_global_panning_strength = 1.0f; protected: - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index c43a796170..88f9c2a4a6 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -655,9 +655,9 @@ bool Camera2D::is_margin_drawing_enabled() const { return margin_drawing_enabled; } -void Camera2D::_validate_property(PropertyInfo &property) const { - if (!smoothing_enabled && property.name == "smoothing_speed") { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void Camera2D::_validate_property(PropertyInfo &p_property) const { + if (!smoothing_enabled && p_property.name == "smoothing_speed") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 294a6fcb80..78654ee606 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -100,7 +100,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_offset(const Vector2 &p_offset); diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index a8c12f4893..7f991df36c 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -186,6 +186,17 @@ bool CollisionObject2D::get_collision_mask_value(int p_layer_number) const { return get_collision_mask() & (1 << (p_layer_number - 1)); } +void CollisionObject2D::set_collision_priority(real_t p_priority) { + collision_priority = p_priority; + if (!area) { + PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), p_priority); + } +} + +real_t CollisionObject2D::get_collision_priority() const { + return collision_priority; +} + void CollisionObject2D::set_disable_mode(DisableMode p_mode) { if (disable_mode == p_mode) { return; @@ -574,6 +585,8 @@ void CollisionObject2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CollisionObject2D::get_collision_layer_value); ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CollisionObject2D::set_collision_mask_value); ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CollisionObject2D::get_collision_mask_value); + ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &CollisionObject2D::set_collision_priority); + ClassDB::bind_method(D_METHOD("get_collision_priority"), &CollisionObject2D::get_collision_priority); ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject2D::set_disable_mode); ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject2D::get_disable_mode); ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable); @@ -611,6 +624,7 @@ void CollisionObject2D::_bind_methods() { ADD_GROUP("Collision", "collision_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority"); ADD_GROUP("Input", "input_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_pickable"), "set_pickable", "is_pickable"); diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index 997afee6c4..f03c6fc72e 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -49,6 +49,7 @@ public: private: uint32_t collision_layer = 1; uint32_t collision_mask = 1; + real_t collision_priority = 1.0; bool area = false; RID rid; @@ -115,6 +116,9 @@ public: void set_collision_mask_value(int p_layer_number, bool p_value); bool get_collision_mask_value(int p_layer_number) const; + void set_collision_priority(real_t p_priority); + real_t get_collision_priority() const; + void set_disable_mode(DisableMode p_mode); DisableMode get_disable_mode() const; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 26204a3b1a..40f74d3f50 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -503,32 +503,32 @@ bool CPUParticles2D::get_split_scale() { return split_scale; } -void CPUParticles2D::_validate_property(PropertyInfo &property) const { - if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { - property.usage = PROPERTY_USAGE_NONE; +void CPUParticles2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_rect_extents" && emission_shape != EMISSION_SHAPE_RECTANGLE) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_rect_extents" && emission_shape != EMISSION_SHAPE_RECTANGLE) { + p_property.usage = PROPERTY_USAGE_NONE; } - if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { - property.usage = PROPERTY_USAGE_NONE; + if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_points" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_points" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("scale_curve_") && !split_scale) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("scale_curve_") && !split_scale) { + p_property.usage = PROPERTY_USAGE_NONE; } } diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 51d58723b4..8f1671d280 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -193,7 +193,7 @@ private: protected: static void _bind_methods(); void _notification(int p_what); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_emitting(bool p_emitting); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index 075421a26d..e4354a69e2 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -340,7 +340,7 @@ Ref<Texture2D> GPUParticles2D::get_texture() const { return texture; } -void GPUParticles2D::_validate_property(PropertyInfo &property) const { +void GPUParticles2D::_validate_property(PropertyInfo &p_property) const { } void GPUParticles2D::emit_particle(const Transform2D &p_transform2d, const Vector2 &p_velocity2d, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index a4231cc45d..7eece32898 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -84,7 +84,7 @@ private: protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); void _update_collision_size(); diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 0481a58431..7eb6b43af7 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -227,9 +227,9 @@ real_t Light2D::get_shadow_smooth() const { return shadow_smooth; } -void Light2D::_validate_property(PropertyInfo &property) const { - if (!shadow && (property.name == "shadow_color" || property.name == "shadow_filter" || property.name == "shadow_filter_smooth" || property.name == "shadow_item_cull_mask")) { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void Light2D::_validate_property(PropertyInfo &p_property) const { + if (!shadow && (p_property.name == "shadow_color" || p_property.name == "shadow_filter" || p_property.name == "shadow_filter_smooth" || p_property.name == "shadow_item_cull_mask")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index a84b6516c0..373cfe59fd 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -79,7 +79,7 @@ protected: _FORCE_INLINE_ RID _get_light() const { return canvas_light; } void _notification(int p_what); static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_enabled(bool p_enabled); diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h index afda05956a..5795c6c94f 100644 --- a/scene/2d/navigation_obstacle_2d.h +++ b/scene/2d/navigation_obstacle_2d.h @@ -46,7 +46,7 @@ class NavigationObstacle2D : public Node { protected: static void _bind_methods(); - void _validate_property(PropertyInfo &p_property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); public: diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 9862c4bfb1..3c393f9752 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -245,14 +245,14 @@ bool PathFollow2D::get_cubic_interpolation() const { return cubic; } -void PathFollow2D::_validate_property(PropertyInfo &property) const { - if (property.name == "offset") { +void PathFollow2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "offset") { real_t max = 10000.0; if (path && path->get_curve().is_valid()) { max = path->get_curve()->get_baked_length(); } - property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater"; + p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater"; } } diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index bc55f84831..1f3ee08a2b 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -76,7 +76,7 @@ private: void _update_transform(); protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp index 2999736d64..62f4d855ef 100644 --- a/scene/2d/physical_bone_2d.cpp +++ b/scene/2d/physical_bone_2d.cpp @@ -158,6 +158,7 @@ void PhysicalBone2D::_start_physics_simulation() { // Apply the layers and masks. PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority()); // Apply the correct mode. _apply_body_mode(); @@ -176,6 +177,7 @@ void PhysicalBone2D::_stop_physics_simulation() { set_physics_process_internal(false); PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0); PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0); + PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), 1.0); PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC); } } diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 2ead48c889..797f08058f 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1062,10 +1062,10 @@ void RigidDynamicBody2D::_bind_methods() { BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE); } -void RigidDynamicBody2D::_validate_property(PropertyInfo &property) const { +void RigidDynamicBody2D::_validate_property(PropertyInfo &p_property) const { if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) { - if (property.name == "center_of_mass") { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name == "center_of_mass") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } } @@ -1776,14 +1776,14 @@ void CharacterBody2D::_bind_methods() { BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER); } -void CharacterBody2D::_validate_property(PropertyInfo &property) const { +void CharacterBody2D::_validate_property(PropertyInfo &p_property) const { if (motion_mode == MOTION_MODE_FLOATING) { - if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name.begins_with("floor_") || p_property.name == "up_direction" || p_property.name == "slide_on_ceiling") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } else { - if (property.name == "wall_min_slide_angle") { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name == "wall_min_slide_angle") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } } diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index c762a832c4..75ea535424 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -216,7 +216,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *) @@ -450,7 +450,7 @@ private: protected: void _notification(int p_what); static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; }; VARIANT_ENUM_CAST(CharacterBody2D::MotionMode); diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index ba62941d3a..cb918ecb8b 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -90,9 +90,9 @@ bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toler } #endif -void Polygon2D::_validate_property(PropertyInfo &property) const { - if (!invert && property.name == "invert_border") { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void Polygon2D::_validate_property(PropertyInfo &p_property) const { + if (!invert && p_property.name == "invert_border") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index d6a1be0f6d..d333152f62 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -77,7 +77,7 @@ class Polygon2D : public Node2D { protected: void _notification(int p_what); static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: #ifdef TOOLS_ENABLED diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index 68e5ffdcf9..c4036faa79 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -82,6 +82,10 @@ Object *RayCast2D::get_collider() const { return ObjectDB::get_instance(against); } +RID RayCast2D::get_collider_rid() const { + return against_rid; +} + int RayCast2D::get_collider_shape() const { return against_shape; } @@ -203,12 +207,14 @@ void RayCast2D::_update_raycast_state() { if (dss->intersect_ray(ray_params, rr)) { collided = true; against = rr.collider_id; + against_rid = rr.rid; collision_point = rr.position; collision_normal = rr.normal; against_shape = rr.shape; } else { collided = false; against = ObjectID(); + against_rid = RID(); against_shape = 0; } @@ -321,6 +327,7 @@ void RayCast2D::_bind_methods() { ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast2D::force_raycast_update); ClassDB::bind_method(D_METHOD("get_collider"), &RayCast2D::get_collider); + ClassDB::bind_method(D_METHOD("get_collider_rid"), &RayCast2D::get_collider_rid); ClassDB::bind_method(D_METHOD("get_collider_shape"), &RayCast2D::get_collider_shape); ClassDB::bind_method(D_METHOD("get_collision_point"), &RayCast2D::get_collision_point); ClassDB::bind_method(D_METHOD("get_collision_normal"), &RayCast2D::get_collision_normal); diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h index 1fb97d89fe..57f993fe8d 100644 --- a/scene/2d/ray_cast_2d.h +++ b/scene/2d/ray_cast_2d.h @@ -41,6 +41,7 @@ class RayCast2D : public Node2D { bool enabled = true; bool collided = false; ObjectID against; + RID against_rid; int against_shape = 0; Vector2 collision_point; Vector2 collision_normal; @@ -91,6 +92,7 @@ public: bool is_colliding() const; Object *get_collider() const; + RID get_collider_rid() const; int get_collider_shape() const; Vector2 get_collision_point() const; Vector2 get_collision_normal() const; diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index b3062ca02a..e1983f9cb9 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -368,19 +368,19 @@ Rect2 Sprite2D::get_rect() const { return Rect2(ofs, s); } -void Sprite2D::_validate_property(PropertyInfo &property) const { - if (property.name == "frame") { - property.hint = PROPERTY_HINT_RANGE; - property.hint_string = "0," + itos(vframes * hframes - 1) + ",1"; - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; +void Sprite2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "frame") { + p_property.hint = PROPERTY_HINT_RANGE; + p_property.hint_string = "0," + itos(vframes * hframes - 1) + ",1"; + p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } - if (property.name == "frame_coords") { - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; + if (p_property.name == "frame_coords") { + p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } - if (!region_enabled && (property.name == "region_rect" || property.name == "region_filter_clip")) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (!region_enabled && (p_property.name == "region_rect" || p_property.name == "region_filter_clip")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h index 5b33bb6802..60f5940cfe 100644 --- a/scene/2d/sprite_2d.h +++ b/scene/2d/sprite_2d.h @@ -64,7 +64,7 @@ protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: #ifdef TOOLS_ENABLED diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 5ba8c95a06..13bdd2bd5f 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -2063,6 +2063,18 @@ int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bo return E->value.alternative_tile; } +TileData *TileMap::get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const { + int source_id = get_cell_source_id(p_layer, p_coords, p_use_proxies); + ERR_FAIL_COND_V_MSG(source_id == TileSet::INVALID_SOURCE, nullptr, vformat("Invalid TileSetSource at cell %s. Make sure a tile exists at this cell.", p_coords)); + + Ref<TileSetAtlasSource> source = tile_set->get_source(source_id); + if (source.is_valid()) { + return source->get_tile_data(get_cell_atlas_coords(p_layer, p_coords, p_use_proxies), get_cell_alternative_tile(p_layer, p_coords, p_use_proxies)); + } + + return nullptr; +} + Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) { ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr); ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr); @@ -3846,9 +3858,10 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cell", "layer", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0)); ClassDB::bind_method(D_METHOD("erase_cell", "layer", "coords"), &TileMap::erase_cell); - ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id); - ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "layer", "coords", "use_proxies"), &TileMap::get_cell_atlas_coords); - ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "layer", "coords", "use_proxies"), &TileMap::get_cell_alternative_tile); + ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "layer", "coords", "use_proxies"), &TileMap::get_cell_atlas_coords, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "layer", "coords", "use_proxies"), &TileMap::get_cell_alternative_tile, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_cell_tile_data", "layer", "coords", "use_proxies"), &TileMap::get_cell_tile_data, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_coords_for_body_rid", "body"), &TileMap::get_coords_for_body_rid); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 012bf01df9..ecc6ee1d59 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -343,6 +343,8 @@ public: int get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; int get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; + // Helper method to make accessing the data easier. + TileData *get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; // Patterns. Ref<TileMapPattern> get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array); diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index e9e19488e9..db7c3233f6 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -598,8 +598,8 @@ float Area3D::get_reverb_uniformity() const { return reverb_uniformity; } -void Area3D::_validate_property(PropertyInfo &property) const { - if (property.name == "audio_bus_name" || property.name == "reverb_bus_name") { +void Area3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "audio_bus_name" || p_property.name == "reverb_bus_name") { String options; for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { if (i > 0) { @@ -609,32 +609,30 @@ void Area3D::_validate_property(PropertyInfo &property) const { options += name; } - property.hint_string = options; - } else if (property.name.begins_with("gravity") && property.name != "gravity_space_override") { + p_property.hint_string = options; + } else if (p_property.name.begins_with("gravity") && p_property.name != "gravity_space_override") { if (gravity_space_override == SPACE_OVERRIDE_DISABLED) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } else { if (gravity_is_point) { - if (property.name == "gravity_direction") { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name == "gravity_direction") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } else { - if (property.name.begins_with("gravity_point_")) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name.begins_with("gravity_point_")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } } - } else if (property.name.begins_with("linear_damp") && property.name != "linear_damp_space_override") { + } else if (p_property.name.begins_with("linear_damp") && p_property.name != "linear_damp_space_override") { if (linear_damp_space_override == SPACE_OVERRIDE_DISABLED) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - } else if (property.name.begins_with("angular_damp") && property.name != "angular_damp_space_override") { + } else if (p_property.name.begins_with("angular_damp") && p_property.name != "angular_damp_space_override") { if (angular_damp_space_override == SPACE_OVERRIDE_DISABLED) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - - CollisionObject3D::_validate_property(property); } void Area3D::_bind_methods() { diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h index 3b892baf57..48364739b7 100644 --- a/scene/3d/area_3d.h +++ b/scene/3d/area_3d.h @@ -141,7 +141,7 @@ private: float reverb_amount = 0.0; float reverb_uniformity = 0.0; - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _initialize_wind(); diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 65b00742ee..93e91f9b5b 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -648,8 +648,8 @@ bool AudioStreamPlayer3D::_is_active() const { return active.is_set(); } -void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const { - if (property.name == "bus") { +void AudioStreamPlayer3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "bus") { String options; for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { if (i > 0) { @@ -659,10 +659,8 @@ void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const { options += name; } - property.hint_string = options; + p_property.hint_string = options; } - - Node3D::_validate_property(property); } void AudioStreamPlayer3D::_bus_layout_changed() { diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 647b18a4a7..ef48269544 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -120,7 +120,7 @@ private: float cached_global_panning_strength = 1.0f; protected: - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index fbd5b5b65b..b3ff6497a7 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -30,8 +30,8 @@ #include "bone_attachment_3d.h" -void BoneAttachment3D::_validate_property(PropertyInfo &property) const { - if (property.name == "bone_name") { +void BoneAttachment3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "bone_name") { // Because it is a constant function, we cannot use the _get_skeleton_3d function. const Skeleton3D *parent = nullptr; if (use_external_skeleton) { @@ -51,15 +51,13 @@ void BoneAttachment3D::_validate_property(PropertyInfo &property) const { names += parent->get_bone_name(i); } - property.hint = PROPERTY_HINT_ENUM; - property.hint_string = names; + p_property.hint = PROPERTY_HINT_ENUM; + p_property.hint_string = names; } else { - property.hint = PROPERTY_HINT_NONE; - property.hint_string = ""; + p_property.hint = PROPERTY_HINT_NONE; + p_property.hint_string = ""; } } - - Node3D::_validate_property(property); } bool BoneAttachment3D::_set(const StringName &p_path, const Variant &p_value) { diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h index 3224361a25..f85053e614 100644 --- a/scene/3d/bone_attachment_3d.h +++ b/scene/3d/bone_attachment_3d.h @@ -64,7 +64,7 @@ class BoneAttachment3D : public Node3D { Skeleton3D *_get_skeleton3d(); protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; bool _get(const StringName &p_path, Variant &r_ret) const; bool _set(const StringName &p_path, const Variant &p_value); void _get_property_list(List<PropertyInfo> *p_list) const; diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index f654373ee5..e07f89fc65 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -71,8 +71,6 @@ void Camera3D::_validate_property(PropertyInfo &p_property) const { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - - Node3D::_validate_property(p_property); } void Camera3D::_update_camera() { diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index cedd976890..1a00017b0b 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -99,7 +99,7 @@ protected: void _update_camera_mode(); void _notification(int p_what); - virtual void _validate_property(PropertyInfo &p_property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index 9a5d4f5480..22de9a47a2 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -183,6 +183,17 @@ bool CollisionObject3D::get_collision_mask_value(int p_layer_number) const { return get_collision_mask() & (1 << (p_layer_number - 1)); } +void CollisionObject3D::set_collision_priority(real_t p_priority) { + collision_priority = p_priority; + if (!area) { + PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), p_priority); + } +} + +real_t CollisionObject3D::get_collision_priority() const { + return collision_priority; +} + void CollisionObject3D::set_disable_mode(DisableMode p_mode) { if (disable_mode == p_mode) { return; @@ -432,6 +443,8 @@ void CollisionObject3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CollisionObject3D::get_collision_layer_value); ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CollisionObject3D::set_collision_mask_value); ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CollisionObject3D::get_collision_mask_value); + ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &CollisionObject3D::set_collision_priority); + ClassDB::bind_method(D_METHOD("get_collision_priority"), &CollisionObject3D::get_collision_priority); ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject3D::set_disable_mode); ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject3D::get_disable_mode); ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &CollisionObject3D::set_ray_pickable); @@ -466,6 +479,7 @@ void CollisionObject3D::_bind_methods() { ADD_GROUP("Collision", "collision_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority"); ADD_GROUP("Input", "input_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_ray_pickable"), "set_ray_pickable", "is_ray_pickable"); diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index 3ec3aa0fc1..3f0d070db4 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -47,6 +47,7 @@ public: private: uint32_t collision_layer = 1; uint32_t collision_mask = 1; + real_t collision_priority = 1.0; bool area = false; @@ -125,6 +126,9 @@ public: void set_collision_mask_value(int p_layer_number, bool p_value); bool get_collision_mask_value(int p_layer_number) const; + void set_collision_priority(real_t p_priority); + real_t get_collision_priority() const; + void set_disable_mode(DisableMode p_mode); DisableMode get_disable_mode() const; diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index 4df0c37ad6..a79fd15b1a 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -516,36 +516,34 @@ bool CPUParticles3D::get_split_scale() { return split_scale; } -void CPUParticles3D::_validate_property(PropertyInfo &property) const { - if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { - property.usage = PROPERTY_USAGE_NONE; +void CPUParticles3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { + p_property.usage = PROPERTY_USAGE_NONE; } - if ((property.name == "emission_point_texture" || property.name == "emission_color_texture" || property.name == "emission_points") && (emission_shape != EMISSION_SHAPE_POINTS && (emission_shape != EMISSION_SHAPE_DIRECTED_POINTS))) { - property.usage = PROPERTY_USAGE_NONE; + if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture" || p_property.name == "emission_points") && (emission_shape != EMISSION_SHAPE_POINTS && (emission_shape != EMISSION_SHAPE_DIRECTED_POINTS))) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("scale_curve_") && !split_scale) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("scale_curve_") && !split_scale) { + p_property.usage = PROPERTY_USAGE_NONE; } - - Node3D::_validate_property(property); } static uint32_t idhash(uint32_t x) { diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index e26c301038..d84b0aedd2 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -198,7 +198,7 @@ private: protected: static void _bind_methods(); void _notification(int p_what); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: AABB get_aabb() const override; diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index 0112f24e0c..460402ad1d 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -152,11 +152,10 @@ AABB Decal::get_aabb() const { return aabb; } -void Decal::_validate_property(PropertyInfo &property) const { - if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_length")) { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void Decal::_validate_property(PropertyInfo &p_property) const { + if (!distance_fade_enabled && (p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_length")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - VisualInstance3D::_validate_property(property); } TypedArray<String> Decal::get_configuration_warnings() const { diff --git a/scene/3d/decal.h b/scene/3d/decal.h index 38da4c14e3..1a7d55b108 100644 --- a/scene/3d/decal.h +++ b/scene/3d/decal.h @@ -62,7 +62,7 @@ private: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: virtual TypedArray<String> get_configuration_warnings() const override; diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp index 1b329143b6..319129603e 100644 --- a/scene/3d/fog_volume.cpp +++ b/scene/3d/fog_volume.cpp @@ -45,12 +45,11 @@ void FogVolume::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "FogMaterial,ShaderMaterial"), "set_material", "get_material"); } -void FogVolume::_validate_property(PropertyInfo &property) const { - if (property.name == "extents" && shape == RS::FOG_VOLUME_SHAPE_WORLD) { - property.usage = PROPERTY_USAGE_NONE; +void FogVolume::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "extents" && shape == RS::FOG_VOLUME_SHAPE_WORLD) { + p_property.usage = PROPERTY_USAGE_NONE; return; } - VisualInstance3D::_validate_property(property); } void FogVolume::set_extents(const Vector3 &p_extents) { diff --git a/scene/3d/fog_volume.h b/scene/3d/fog_volume.h index 556a92ad3f..fcdc1e2807 100644 --- a/scene/3d/fog_volume.h +++ b/scene/3d/fog_volume.h @@ -49,7 +49,7 @@ class FogVolume : public VisualInstance3D { protected: _FORCE_INLINE_ RID _get_volume() { return volume; } static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_extents(const Vector3 &p_extents); diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index 2ee126e161..b46e6a8b71 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -376,16 +376,14 @@ AABB GPUParticles3D::capture_aabb() const { return RS::get_singleton()->particles_get_current_aabb(particles); } -void GPUParticles3D::_validate_property(PropertyInfo &property) const { - if (property.name.begins_with("draw_pass_")) { - int index = property.name.get_slicec('_', 2).to_int() - 1; +void GPUParticles3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name.begins_with("draw_pass_")) { + int index = p_property.name.get_slicec('_', 2).to_int() - 1; if (index >= draw_passes.size()) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; return; } } - - GeometryInstance3D::_validate_property(property); } void GPUParticles3D::emit_particle(const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index 0c745dd734..2ad9672474 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -94,7 +94,7 @@ private: protected: static void _bind_methods(); void _notification(int p_what); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: AABB get_aabb() const override; diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp index ed2bce253a..f2d3dda792 100644 --- a/scene/3d/label_3d.cpp +++ b/scene/3d/label_3d.cpp @@ -162,19 +162,19 @@ void Label3D::_bind_methods() { BIND_ENUM_CONSTANT(ALPHA_CUT_OPAQUE_PREPASS); } -void Label3D::_validate_property(PropertyInfo &property) const { +void Label3D::_validate_property(PropertyInfo &p_property) const { if ( - property.name == "material_override" || - property.name == "material_overlay" || - property.name == "lod_bias" || - property.name == "gi_mode" || - property.name == "gi_lightmap_scale") { - property.usage = PROPERTY_USAGE_NO_EDITOR; + p_property.name == "material_override" || + p_property.name == "material_overlay" || + p_property.name == "lod_bias" || + p_property.name == "gi_mode" || + p_property.name == "gi_lightmap_scale") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (property.name == "cast_shadow" && alpha_cut == ALPHA_CUT_DISABLED) { + if (p_property.name == "cast_shadow" && alpha_cut == ALPHA_CUT_DISABLED) { // Alpha-blended materials can't cast shadows. - property.usage = PROPERTY_USAGE_NO_EDITOR; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h index d4bfe743a6..3c9a758e6e 100644 --- a/scene/3d/label_3d.h +++ b/scene/3d/label_3d.h @@ -149,7 +149,7 @@ protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _im_update(); void _font_changed(); diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 53c072c318..0581544e07 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -223,21 +223,19 @@ bool Light3D::is_editor_only() const { return editor_only; } -void Light3D::_validate_property(PropertyInfo &property) const { - if (!shadow && (property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_opacity" || property.name == "shadow_blur" || property.name == "distance_fade_shadow")) { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void Light3D::_validate_property(PropertyInfo &p_property) const { + if (!shadow && (p_property.name == "shadow_bias" || p_property.name == "shadow_normal_bias" || p_property.name == "shadow_reverse_cull_face" || p_property.name == "shadow_transmittance_bias" || p_property.name == "shadow_fog_fade" || p_property.name == "shadow_opacity" || p_property.name == "shadow_blur" || p_property.name == "distance_fade_shadow")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (get_light_type() != RS::LIGHT_DIRECTIONAL && property.name == "light_angular_distance") { + if (get_light_type() != RS::LIGHT_DIRECTIONAL && p_property.name == "light_angular_distance") { // Angular distance is only used in DirectionalLight3D. - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } - if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length")) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (!distance_fade_enabled && (p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_shadow" || p_property.name == "distance_fade_length")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - - VisualInstance3D::_validate_property(property); } void Light3D::_bind_methods() { @@ -429,29 +427,27 @@ DirectionalLight3D::SkyMode DirectionalLight3D::get_sky_mode() const { return sky_mode; } -void DirectionalLight3D::_validate_property(PropertyInfo &property) const { - if (shadow_mode == SHADOW_ORTHOGONAL && (property.name == "directional_shadow_split_1" || property.name == "directional_shadow_blend_splits")) { +void DirectionalLight3D::_validate_property(PropertyInfo &p_property) const { + if (shadow_mode == SHADOW_ORTHOGONAL && (p_property.name == "directional_shadow_split_1" || p_property.name == "directional_shadow_blend_splits")) { // Split 2 and split blending are only used with the PSSM 2 Splits and PSSM 4 Splits shadow modes. - property.usage = PROPERTY_USAGE_NO_EDITOR; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if ((shadow_mode == SHADOW_ORTHOGONAL || shadow_mode == SHADOW_PARALLEL_2_SPLITS) && (property.name == "directional_shadow_split_2" || property.name == "directional_shadow_split_3")) { + if ((shadow_mode == SHADOW_ORTHOGONAL || shadow_mode == SHADOW_PARALLEL_2_SPLITS) && (p_property.name == "directional_shadow_split_2" || p_property.name == "directional_shadow_split_3")) { // Splits 3 and 4 are only used with the PSSM 4 Splits shadow mode. - property.usage = PROPERTY_USAGE_NO_EDITOR; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (property.name == "light_size" || property.name == "light_projector" || property.name == "light_specular") { + if (p_property.name == "light_size" || p_property.name == "light_projector" || p_property.name == "light_specular") { // Not implemented in DirectionalLight3D (`light_size` is replaced by `light_angular_distance`). - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "distance_fade_enabled" || property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length") { + if (p_property.name == "distance_fade_enabled" || p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_shadow" || p_property.name == "distance_fade_length") { // Not relevant for DirectionalLight3D, as the light LOD system only pertains to point lights. // For DirectionalLight3D, `directional_shadow_max_distance` can be used instead. - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } - - Light3D::_validate_property(property); } void DirectionalLight3D::_bind_methods() { diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index ef003e133d..035ba50e42 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -93,7 +93,7 @@ protected: static void _bind_methods(); void _notification(int p_what); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; Light3D(RenderingServer::LightType p_type); @@ -171,7 +171,7 @@ private: protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_shadow_mode(ShadowMode p_mode); diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 6b6a2eff9e..7efda6db32 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -1410,17 +1410,16 @@ LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const { return gen_probes; } -void LightmapGI::_validate_property(PropertyInfo &property) const { - if (property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { - property.usage = PROPERTY_USAGE_NONE; +void LightmapGI::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "environment_custom_color" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "environment_custom_color" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "environment_custom_energy" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "environment_custom_energy" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { + p_property.usage = PROPERTY_USAGE_NONE; } - VisualInstance3D::_validate_property(property); } void LightmapGI::_bind_methods() { diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index 85150b833f..87add9facc 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -216,7 +216,7 @@ private: void _gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool> &positions_used, const AABB &p_bounds); protected: - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); void _notification(int p_what); diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h index 0316fc37a8..7f6af668b6 100644 --- a/scene/3d/navigation_obstacle_3d.h +++ b/scene/3d/navigation_obstacle_3d.h @@ -45,7 +45,7 @@ class NavigationObstacle3D : public Node { protected: static void _bind_methods(); - void _validate_property(PropertyInfo &p_property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); public: diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 4ae834cf7a..ec60c8fdc2 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -879,21 +879,21 @@ NodePath Node3D::get_visibility_parent() const { return visibility_parent_path; } -void Node3D::_validate_property(PropertyInfo &property) const { - if (data.rotation_edit_mode != ROTATION_EDIT_MODE_BASIS && property.name == "basis") { - property.usage = 0; +void Node3D::_validate_property(PropertyInfo &p_property) const { + if (data.rotation_edit_mode != ROTATION_EDIT_MODE_BASIS && p_property.name == "basis") { + p_property.usage = 0; } - if (data.rotation_edit_mode == ROTATION_EDIT_MODE_BASIS && property.name == "scale") { - property.usage = 0; + if (data.rotation_edit_mode == ROTATION_EDIT_MODE_BASIS && p_property.name == "scale") { + p_property.usage = 0; } - if (data.rotation_edit_mode != ROTATION_EDIT_MODE_QUATERNION && property.name == "quaternion") { - property.usage = 0; + if (data.rotation_edit_mode != ROTATION_EDIT_MODE_QUATERNION && p_property.name == "quaternion") { + p_property.usage = 0; } - if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && property.name == "rotation") { - property.usage = 0; + if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && p_property.name == "rotation") { + p_property.usage = 0; } - if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && property.name == "rotation_order") { - property.usage = 0; + if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && p_property.name == "rotation_order") { + p_property.usage = 0; } } diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index 3d1c59445b..2757f9e9ed 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -155,7 +155,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; bool _property_can_revert(const StringName &p_name) const; bool _property_get_revert(const StringName &p_name, Variant &r_property) const; diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 25226ad384..8c4e5c5275 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -330,16 +330,15 @@ bool PathFollow3D::get_cubic_interpolation() const { return cubic; } -void PathFollow3D::_validate_property(PropertyInfo &property) const { - if (property.name == "offset") { +void PathFollow3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "offset") { real_t max = 10000; if (path && path->get_curve().is_valid()) { max = path->get_curve()->get_baked_length(); } - property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater"; + p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater"; } - Node3D::_validate_property(property); } TypedArray<String> PathFollow3D::get_configuration_warnings() const { diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h index b4cc6db7e3..bc4db61a01 100644 --- a/scene/3d/path_3d.h +++ b/scene/3d/path_3d.h @@ -85,7 +85,7 @@ private: void _update_transform(bool p_update_xyz_rot = true); protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index cbdef02826..515665bde6 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -1124,13 +1124,12 @@ void RigidDynamicBody3D::_bind_methods() { BIND_ENUM_CONSTANT(DAMP_MODE_REPLACE); } -void RigidDynamicBody3D::_validate_property(PropertyInfo &property) const { +void RigidDynamicBody3D::_validate_property(PropertyInfo &p_property) const { if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) { - if (property.name == "center_of_mass") { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name == "center_of_mass") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - PhysicsBody3D::_validate_property(property); } RigidDynamicBody3D::RigidDynamicBody3D() : @@ -2022,13 +2021,12 @@ void CharacterBody3D::_bind_methods() { BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER); } -void CharacterBody3D::_validate_property(PropertyInfo &property) const { +void CharacterBody3D::_validate_property(PropertyInfo &p_property) const { if (motion_mode == MOTION_MODE_FLOATING) { - if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name.begins_with("floor_") || p_property.name == "up_direction" || p_property.name == "slide_on_ceiling") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - PhysicsBody3D::_validate_property(property); } CharacterBody3D::CharacterBody3D() : @@ -3417,6 +3415,7 @@ void PhysicalBone3D::_start_physics_simulation() { set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC); PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority()); PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback); set_as_top_level(true); _internal_simulate_physics = true; @@ -3430,10 +3429,12 @@ void PhysicalBone3D::_stop_physics_simulation() { set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority()); } else { set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), 0); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0); + PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), 1.0); } if (_internal_simulate_physics) { PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr); diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index b9baba4d96..5d466f7e3c 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -226,7 +226,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *) @@ -483,7 +483,7 @@ private: protected: void _notification(int p_what); static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; }; VARIANT_ENUM_CAST(CharacterBody3D::MotionMode); diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp index 2db5ab2d4e..a45ef52452 100644 --- a/scene/3d/ray_cast_3d.cpp +++ b/scene/3d/ray_cast_3d.cpp @@ -88,6 +88,10 @@ Object *RayCast3D::get_collider() const { return ObjectDB::get_instance(against); } +RID RayCast3D::get_collider_rid() const { + return against_rid; +} + int RayCast3D::get_collider_shape() const { return against_shape; } @@ -224,12 +228,14 @@ void RayCast3D::_update_raycast_state() { if (dss->intersect_ray(ray_params, rr)) { collided = true; against = rr.collider_id; + against_rid = rr.rid; collision_point = rr.position; collision_normal = rr.normal; against_shape = rr.shape; } else { collided = false; against = ObjectID(); + against_rid = RID(); against_shape = 0; } } @@ -302,6 +308,7 @@ void RayCast3D::_bind_methods() { ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast3D::force_raycast_update); ClassDB::bind_method(D_METHOD("get_collider"), &RayCast3D::get_collider); + ClassDB::bind_method(D_METHOD("get_collider_rid"), &RayCast3D::get_collider_rid); ClassDB::bind_method(D_METHOD("get_collider_shape"), &RayCast3D::get_collider_shape); ClassDB::bind_method(D_METHOD("get_collision_point"), &RayCast3D::get_collision_point); ClassDB::bind_method(D_METHOD("get_collision_normal"), &RayCast3D::get_collision_normal); diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h index aa62f6927e..eb5c3ee90a 100644 --- a/scene/3d/ray_cast_3d.h +++ b/scene/3d/ray_cast_3d.h @@ -41,6 +41,7 @@ class RayCast3D : public Node3D { bool enabled = true; bool collided = false; ObjectID against; + RID against_rid; int against_shape = 0; Vector3 collision_point; Vector3 collision_normal; @@ -113,6 +114,7 @@ public: void force_raycast_update(); bool is_colliding() const; Object *get_collider() const; + RID get_collider_rid() const; int get_collider_shape() const; Vector3 get_collision_point() const; Vector3 get_collision_normal() const; diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp index 0a9d6cbbeb..bc3cc31963 100644 --- a/scene/3d/reflection_probe.cpp +++ b/scene/3d/reflection_probe.cpp @@ -178,13 +178,12 @@ AABB ReflectionProbe::get_aabb() const { return aabb; } -void ReflectionProbe::_validate_property(PropertyInfo &property) const { - if (property.name == "interior/ambient_color" || property.name == "interior/ambient_color_energy") { +void ReflectionProbe::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "ambient_color" || p_property.name == "ambient_color_energy") { if (ambient_mode != AMBIENT_COLOR) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - VisualInstance3D::_validate_property(property); } void ReflectionProbe::_bind_methods() { diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h index a161717ece..5a5a3fe0bb 100644 --- a/scene/3d/reflection_probe.h +++ b/scene/3d/reflection_probe.h @@ -67,7 +67,7 @@ private: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_intensity(float p_intensity); diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 4c38fccc8b..0cd7188c23 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -176,39 +176,37 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const { } } -void Skeleton3D::_validate_property(PropertyInfo &property) const { - PackedStringArray split = property.name.split("/"); +void Skeleton3D::_validate_property(PropertyInfo &p_property) const { + PackedStringArray split = p_property.name.split("/"); if (split.size() == 3 && split[0] == "bones") { if (split[2] == "rest") { - property.usage |= PROPERTY_USAGE_READ_ONLY; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } if (is_show_rest_only()) { if (split[2] == "enabled") { - property.usage |= PROPERTY_USAGE_READ_ONLY; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } if (split[2] == "position") { - property.usage |= PROPERTY_USAGE_READ_ONLY; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } if (split[2] == "rotation") { - property.usage |= PROPERTY_USAGE_READ_ONLY; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } if (split[2] == "scale") { - property.usage |= PROPERTY_USAGE_READ_ONLY; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } } else if (!is_bone_enabled(split[1].to_int())) { if (split[2] == "position") { - property.usage |= PROPERTY_USAGE_READ_ONLY; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } if (split[2] == "rotation") { - property.usage |= PROPERTY_USAGE_READ_ONLY; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } if (split[2] == "scale") { - property.usage |= PROPERTY_USAGE_READ_ONLY; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } } } - - Node3D::_validate_property(property); } void Skeleton3D::_update_process_order() { @@ -762,6 +760,20 @@ Vector3 Skeleton3D::get_bone_pose_scale(int p_bone) const { return bones[p_bone].pose_scale; } +void Skeleton3D::reset_bone_pose(int p_bone) { + const int bone_size = bones.size(); + ERR_FAIL_INDEX(p_bone, bone_size); + set_bone_pose_position(p_bone, bones[p_bone].rest.origin); + set_bone_pose_rotation(p_bone, bones[p_bone].rest.basis.get_rotation_quaternion()); + set_bone_pose_scale(p_bone, bones[p_bone].rest.basis.get_scale()); +} + +void Skeleton3D::reset_bone_poses() { + for (int i = 0; i < bones.size(); i++) { + reset_bone_pose(i); + } +} + Transform3D Skeleton3D::get_bone_pose(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); @@ -1252,6 +1264,9 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bone_pose_rotation", "bone_idx"), &Skeleton3D::get_bone_pose_rotation); ClassDB::bind_method(D_METHOD("get_bone_pose_scale", "bone_idx"), &Skeleton3D::get_bone_pose_scale); + ClassDB::bind_method(D_METHOD("reset_bone_pose", "bone_idx"), &Skeleton3D::reset_bone_pose); + ClassDB::bind_method(D_METHOD("reset_bone_poses"), &Skeleton3D::reset_bone_poses); + ClassDB::bind_method(D_METHOD("is_bone_enabled", "bone_idx"), &Skeleton3D::is_bone_enabled); ClassDB::bind_method(D_METHOD("set_bone_enabled", "bone_idx", "enabled"), &Skeleton3D::set_bone_enabled, DEFVAL(true)); diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index 8b69410a39..79feadf44f 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -156,7 +156,7 @@ protected: bool _get(const StringName &p_path, Variant &r_ret) const; bool _set(const StringName &p_path, const Variant &p_value); void _get_property_list(List<PropertyInfo> *p_list) const; - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); static void _bind_methods(); @@ -227,6 +227,9 @@ public: Quaternion get_bone_pose_rotation(int p_bone) const; Vector3 get_bone_pose_scale(int p_bone) const; + void reset_bone_pose(int p_bone); + void reset_bone_poses(); + void clear_bones_global_pose_override(); Transform3D get_bone_global_pose_override(int p_bone) const; void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false); diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp index 2182c5ba11..f0534c8099 100644 --- a/scene/3d/skeleton_ik_3d.cpp +++ b/scene/3d/skeleton_ik_3d.cpp @@ -329,8 +329,8 @@ void FabrikInverseKinematic::_update_chain(const Skeleton3D *p_sk, ChainItem *p_ } } -void SkeletonIK3D::_validate_property(PropertyInfo &property) const { - if (property.name == "root_bone" || property.name == "tip_bone") { +void SkeletonIK3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "root_bone" || p_property.name == "tip_bone") { if (skeleton) { String names("--,"); for (int i = 0; i < skeleton->get_bone_count(); i++) { @@ -340,15 +340,13 @@ void SkeletonIK3D::_validate_property(PropertyInfo &property) const { names += skeleton->get_bone_name(i); } - property.hint = PROPERTY_HINT_ENUM; - property.hint_string = names; + p_property.hint = PROPERTY_HINT_ENUM; + p_property.hint_string = names; } else { - property.hint = PROPERTY_HINT_NONE; - property.hint_string = ""; + p_property.hint = PROPERTY_HINT_NONE; + p_property.hint_string = ""; } } - - Node::_validate_property(property); } void SkeletonIK3D::_bind_methods() { diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h index 6ae86a2bf6..097df2c400 100644 --- a/scene/3d/skeleton_ik_3d.h +++ b/scene/3d/skeleton_ik_3d.h @@ -137,7 +137,7 @@ class SkeletonIK3D : public Node { FabrikInverseKinematic::Task *task = nullptr; protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); virtual void _notification(int p_what); diff --git a/scene/3d/soft_dynamic_body_3d.cpp b/scene/3d/soft_dynamic_body_3d.cpp index 15f050defb..c9eafc77e0 100644 --- a/scene/3d/soft_dynamic_body_3d.cpp +++ b/scene/3d/soft_dynamic_body_3d.cpp @@ -88,10 +88,10 @@ void SoftDynamicBodyRenderingServerHandler::set_normal(int p_vertex_id, const vo memcpy(&n, p_vector3, sizeof(Vector3)); n *= Vector3(0.5, 0.5, 0.5); n += Vector3(0.5, 0.5, 0.5); + Vector2 res = n.octahedron_encode(); uint32_t value = 0; - value |= CLAMP(int(n.x * 1023.0), 0, 1023); - value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; - value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; + value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); + value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; memcpy(&write_buffer[p_vertex_id * stride + offset_normal], &value, sizeof(uint32_t)); } diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index ef2b9e1ce5..212d220ace 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -562,23 +562,21 @@ void Sprite3D::_draw() { { Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + Vector2 res = n.octahedron_encode(); uint32_t value = 0; - value |= CLAMP(int(n.x * 1023.0), 0, 1023); - value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; - value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; + value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); + value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; v_normal = value; } uint32_t v_tangent; { Plane t = tangent; + Vector2 res = t.normal.octahedron_tangent_encode(t.d); uint32_t value = 0; - value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023); - value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; - value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; - if (t.d > 0) { - value |= 3UL << 30; - } + value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); + value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; + v_tangent = value; } @@ -751,18 +749,16 @@ Rect2 Sprite3D::get_item_rect() const { return Rect2(ofs, s); } -void Sprite3D::_validate_property(PropertyInfo &property) const { - if (property.name == "frame") { - property.hint = PROPERTY_HINT_RANGE; - property.hint_string = "0," + itos(vframes * hframes - 1) + ",1"; - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; +void Sprite3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "frame") { + p_property.hint = PROPERTY_HINT_RANGE; + p_property.hint_string = "0," + itos(vframes * hframes - 1) + ",1"; + p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } - if (property.name == "frame_coords") { - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; + if (p_property.name == "frame_coords") { + p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } - - SpriteBase3D::_validate_property(property); } void Sprite3D::_bind_methods() { @@ -929,23 +925,20 @@ void AnimatedSprite3D::_draw() { { Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + Vector2 res = n.octahedron_encode(); uint32_t value = 0; - value |= CLAMP(int(n.x * 1023.0), 0, 1023); - value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; - value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; + value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); + value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; v_normal = value; } uint32_t v_tangent; { Plane t = tangent; + Vector2 res = t.normal.octahedron_tangent_encode(t.d); uint32_t value = 0; - value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023); - value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; - value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; - if (t.d > 0) { - value |= 3UL << 30; - } + value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); + value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; v_tangent = value; } @@ -1000,12 +993,12 @@ void AnimatedSprite3D::_draw() { } } -void AnimatedSprite3D::_validate_property(PropertyInfo &property) const { +void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const { if (!frames.is_valid()) { return; } - if (property.name == "animation") { - property.hint = PROPERTY_HINT_ENUM; + if (p_property.name == "animation") { + p_property.hint = PROPERTY_HINT_ENUM; List<StringName> names; frames->get_animation_list(&names); names.sort_custom<StringName::AlphCompare>(); @@ -1014,36 +1007,34 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &property) const { for (List<StringName>::Element *E = names.front(); E; E = E->next()) { if (E->prev()) { - property.hint_string += ","; + p_property.hint_string += ","; } - property.hint_string += String(E->get()); + p_property.hint_string += String(E->get()); if (animation == E->get()) { current_found = true; } } if (!current_found) { - if (property.hint_string.is_empty()) { - property.hint_string = String(animation); + if (p_property.hint_string.is_empty()) { + p_property.hint_string = String(animation); } else { - property.hint_string = String(animation) + "," + property.hint_string; + p_property.hint_string = String(animation) + "," + p_property.hint_string; } } } - if (property.name == "frame") { - property.hint = PROPERTY_HINT_RANGE; + if (p_property.name == "frame") { + p_property.hint = PROPERTY_HINT_RANGE; if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) { - property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1"; + p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1"; } else { // Avoid an error, `hint_string` is required for `PROPERTY_HINT_RANGE`. - property.hint_string = "0,0,1"; + p_property.hint_string = "0,0,1"; } - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; + p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } - - SpriteBase3D::_validate_property(property); } void AnimatedSprite3D::_notification(int p_what) { diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index 6ac85a7bbc..03688cf787 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -174,7 +174,7 @@ protected: virtual void _draw() override; static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_texture(const Ref<Texture2D> &p_texture); @@ -229,7 +229,7 @@ protected: virtual void _draw() override; static void _bind_methods(); void _notification(int p_what); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_sprite_frames(const Ref<SpriteFrames> &p_frames); diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index 40a43043c6..de765d7ccb 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -244,27 +244,25 @@ void XRNode3D::_bind_methods() { ClassDB::bind_method(D_METHOD("trigger_haptic_pulse", "action_name", "frequency", "amplitude", "duration_sec", "delay_sec"), &XRNode3D::trigger_haptic_pulse); }; -void XRNode3D::_validate_property(PropertyInfo &property) const { +void XRNode3D::_validate_property(PropertyInfo &p_property) const { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); - if (property.name == "tracker") { + if (p_property.name == "tracker") { PackedStringArray names = xr_server->get_suggested_tracker_names(); String hint_string; for (const String &name : names) { hint_string += name + ","; } - property.hint_string = hint_string; - } else if (property.name == "pose") { + p_property.hint_string = hint_string; + } else if (p_property.name == "pose") { PackedStringArray names = xr_server->get_suggested_pose_names(tracker_name); String hint_string; for (const String &name : names) { hint_string += name + ","; } - property.hint_string = hint_string; + p_property.hint_string = hint_string; } - - Node3D::_validate_property(property); } void XRNode3D::set_tracker(const StringName p_tracker_name) { diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index 3079e20dc7..312bef7856 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -93,7 +93,7 @@ protected: void _pose_changed(const Ref<XRPose> &p_pose); public: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void set_tracker(const StringName p_tracker_name); StringName get_tracker() const; diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index b42e426f51..f30aea3bdd 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -42,15 +42,14 @@ Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName return get_blend_point_node(p_name.operator String().to_int()); } -void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const { - if (property.name.begins_with("blend_point_")) { - String left = property.name.get_slicec('/', 0); +void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name.begins_with("blend_point_")) { + String left = p_property.name.get_slicec('/', 0); int idx = left.get_slicec('_', 2).to_int(); if (idx >= blend_points_used) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } - AnimationRootNode::_validate_property(property); } void AnimationNodeBlendSpace1D::_tree_changed() { diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h index 346e8a3a2f..1876ccebc7 100644 --- a/scene/animation/animation_blend_space_1d.h +++ b/scene/animation/animation_blend_space_1d.h @@ -65,7 +65,7 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode { protected: bool sync = false; - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index 6b5851a977..2dc61efb94 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -566,18 +566,17 @@ String AnimationNodeBlendSpace2D::get_caption() const { return "BlendSpace2D"; } -void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &property) const { - if (auto_triangles && property.name == "triangles") { - property.usage = PROPERTY_USAGE_NONE; +void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &p_property) const { + if (auto_triangles && p_property.name == "triangles") { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("blend_point_")) { - String left = property.name.get_slicec('/', 0); + if (p_property.name.begins_with("blend_point_")) { + String left = p_property.name.get_slicec('/', 0); int idx = left.get_slicec('_', 2).to_int(); if (idx >= blend_points_used) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } - AnimationRootNode::_validate_property(property); } void AnimationNodeBlendSpace2D::set_auto_triangles(bool p_enable) { diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h index 689b96e356..250189f202 100644 --- a/scene/animation/animation_blend_space_2d.h +++ b/scene/animation/animation_blend_space_2d.h @@ -90,7 +90,7 @@ protected: protected: bool sync = false; - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index fe2fb1b7a1..61f068408c 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -47,8 +47,8 @@ void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) cons r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); } -void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const { - if (property.name == "animation" && get_editable_animation_list) { +void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "animation" && get_editable_animation_list) { Vector<String> names = get_editable_animation_list(); String anims; for (int i = 0; i < names.size(); i++) { @@ -58,8 +58,8 @@ void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const { anims += String(names[i]); } if (!anims.is_empty()) { - property.hint = PROPERTY_HINT_ENUM; - property.hint_string = anims; + p_property.hint = PROPERTY_HINT_ENUM; + p_property.hint_string = anims; } } } @@ -676,12 +676,20 @@ String AnimationNodeTransition::get_input_caption(int p_input) const { return inputs[p_input].name; } -void AnimationNodeTransition::set_cross_fade_time(float p_fade) { - xfade = p_fade; +void AnimationNodeTransition::set_xfade_time(float p_fade) { + xfade_time = p_fade; } -float AnimationNodeTransition::get_cross_fade_time() const { - return xfade; +float AnimationNodeTransition::get_xfade_time() const { + return xfade_time; +} + +void AnimationNodeTransition::set_xfade_curve(const Ref<Curve> &p_curve) { + xfade_curve = p_curve; +} + +Ref<Curve> AnimationNodeTransition::get_xfade_curve() const { + return xfade_curve; } void AnimationNodeTransition::set_from_start(bool p_from_start) { @@ -707,7 +715,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_ set_parameter(this->prev, prev_current); prev = prev_current; - prev_xfading = xfade; + prev_xfading = xfade_time; time = 0; switched = true; } @@ -734,13 +742,16 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_ time += p_time; } - if (inputs[current].auto_advance && rem <= xfade) { + if (inputs[current].auto_advance && rem <= xfade_time) { set_parameter(this->current, (current + 1) % enabled_inputs); } } else { // cross-fading from prev to current - float blend = xfade == 0 ? 0 : (prev_xfading / xfade); + float blend = xfade_time == 0 ? 0 : (prev_xfading / xfade_time); + if (xfade_curve.is_valid()) { + blend = xfade_curve->interpolate(blend); + } if (from_start && !p_seek && switched) { //just switched, seek to start of current @@ -768,18 +779,16 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_ return rem; } -void AnimationNodeTransition::_validate_property(PropertyInfo &property) const { - if (property.name.begins_with("input_")) { - String n = property.name.get_slicec('/', 0).get_slicec('_', 1); +void AnimationNodeTransition::_validate_property(PropertyInfo &p_property) const { + if (p_property.name.begins_with("input_")) { + String n = p_property.name.get_slicec('/', 0).get_slicec('_', 1); if (n != "count") { int idx = n.to_int(); if (idx >= enabled_inputs) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } } - - AnimationNode::_validate_property(property); } void AnimationNodeTransition::_bind_methods() { @@ -792,14 +801,18 @@ void AnimationNodeTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption); ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption); - ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time); - ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time); + ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time); + ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time); + + ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeTransition::set_xfade_curve); + ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeTransition::get_xfade_curve); ClassDB::bind_method(D_METHOD("set_from_start", "from_start"), &AnimationNodeTransition::set_from_start); ClassDB::bind_method(D_METHOD("is_from_start"), &AnimationNodeTransition::is_from_start); ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_cross_fade_time", "get_cross_fade_time"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "from_start"), "set_from_start", "is_from_start"); for (int i = 0; i < MAX_INPUTS; i++) { diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index d35ff04f30..59c074cc80 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -67,7 +67,7 @@ public: AnimationNodeAnimation(); protected: - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); private: @@ -297,14 +297,15 @@ class AnimationNodeTransition : public AnimationNodeSync { StringName current = PNAME("current"); StringName prev_current = "prev_current"; - float xfade = 0.0; + float xfade_time = 0.0; + Ref<Curve> xfade_curve; bool from_start = true; void _update_inputs(); protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: virtual void get_parameter_list(List<PropertyInfo> *r_list) const override; @@ -321,8 +322,11 @@ public: void set_input_caption(int p_input, const String &p_name); String get_input_caption(int p_input) const; - void set_cross_fade_time(float p_fade); - float get_cross_fade_time() const; + void set_xfade_time(float p_fade); + float get_xfade_time() const; + + void set_xfade_curve(const Ref<Curve> &p_curve); + Ref<Curve> get_xfade_curve() const; void set_from_start(bool p_from_start); bool is_from_start() const; diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 793967d9ad..4b3d7fd0a6 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -98,12 +98,20 @@ NodePath AnimationNodeStateMachineTransition::get_advance_expression_base_node() void AnimationNodeStateMachineTransition::set_xfade_time(float p_xfade) { ERR_FAIL_COND(p_xfade < 0); - xfade = p_xfade; + xfade_time = p_xfade; emit_changed(); } float AnimationNodeStateMachineTransition::get_xfade_time() const { - return xfade; + return xfade_time; +} + +void AnimationNodeStateMachineTransition::set_xfade_curve(const Ref<Curve> &p_curve) { + xfade_curve = p_curve; +} + +Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const { + return xfade_curve; } void AnimationNodeStateMachineTransition::set_disabled(bool p_disabled) { @@ -137,6 +145,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("set_xfade_time", "secs"), &AnimationNodeStateMachineTransition::set_xfade_time); ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeStateMachineTransition::get_xfade_time); + ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeStateMachineTransition::set_xfade_curve); + ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeStateMachineTransition::get_xfade_curve); + ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &AnimationNodeStateMachineTransition::set_disabled); ClassDB::bind_method(D_METHOD("is_disabled"), &AnimationNodeStateMachineTransition::is_disabled); @@ -150,6 +161,7 @@ void AnimationNodeStateMachineTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("get_advance_expression_base_node"), &AnimationNodeStateMachineTransition::get_advance_expression_base_node); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01,suffix:s"), "set_xfade_time", "get_xfade_time"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve"); ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority"); ADD_GROUP("Switch", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,At End"), "set_switch_mode", "get_switch_mode"); @@ -420,6 +432,9 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s } } + if (current_curve.is_valid()) { + fade_blend = current_curve->interpolate(fade_blend); + } float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_seek_root, fade_blend, AnimationNode::FILTER_IGNORE, true); if (fading_from != StringName()) { @@ -450,6 +465,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s if (p_state_machine->transitions[i].local_from == current && p_state_machine->transitions[i].local_to == path[0]) { next_xfade = p_state_machine->transitions[i].transition->get_xfade_time(); + current_curve = p_state_machine->transitions[i].transition->get_xfade_curve(); switch_mode = p_state_machine->transitions[i].transition->get_switch_mode(); next = path[0]; } @@ -504,6 +520,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s tr.to = String(p_state_machine->transitions[auto_advance_to].to).replace_first("../", ""); tr.next = p_state_machine->transitions[auto_advance_to].to; current_transition = tr; + current_curve = p_state_machine->transitions[auto_advance_to].transition->get_xfade_curve(); next_xfade = p_state_machine->transitions[auto_advance_to].transition->get_xfade_time(); switch_mode = p_state_machine->transitions[auto_advance_to].transition->get_switch_mode(); } diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index ead914db7a..ab78b1afe8 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -49,7 +49,8 @@ private: bool auto_advance = false; StringName advance_condition; StringName advance_condition_name; - float xfade = 0.0; + float xfade_time = 0.0; + Ref<Curve> xfade_curve; bool disabled = false; int priority = 1; String advance_expression; @@ -82,6 +83,9 @@ public: void set_xfade_time(float p_xfade); float get_xfade_time() const; + void set_xfade_curve(const Ref<Curve> &p_curve); + Ref<Curve> get_xfade_curve() const; + void set_disabled(bool p_disabled); bool is_disabled() const; @@ -117,6 +121,7 @@ class AnimationNodeStateMachinePlayback : public Resource { StringName current; Transition current_transition; + Ref<Curve> current_curve; bool force_auto_advance = false; StringName fading_from; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 09ec086564..48626ccc1b 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -37,6 +37,7 @@ #ifdef TOOLS_ENABLED #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/2d/skeleton_2d.h" void AnimatedValuesBackup::update_skeletons() { @@ -174,8 +175,8 @@ bool AnimationPlayer::_get(const StringName &p_name, Variant &r_ret) const { return true; } -void AnimationPlayer::_validate_property(PropertyInfo &property) const { - if (property.name == "current_animation") { +void AnimationPlayer::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "current_animation") { List<String> names; for (const KeyValue<StringName, AnimationData> &E : animation_set) { @@ -191,10 +192,8 @@ void AnimationPlayer::_validate_property(PropertyInfo &property) const { hint += E->get(); } - property.hint_string = hint; + p_property.hint_string = hint; } - - Node::_validate_property(property); } void AnimationPlayer::_get_property_list(List<PropertyInfo> *p_list) const { @@ -323,10 +322,8 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov #endif // _3D_DISABLED - { - if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) { - child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONESHOT); - } + if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) { + child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONESHOT); } TrackNodeCacheKey key; @@ -375,7 +372,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov node_cache->init_rot = rest.basis.get_rotation_quaternion(); node_cache->init_scale = rest.basis.get_scale(); } else { - // no property, just use spatialnode + // Not a skeleton, the node can be accessed with the node_3d member. node_cache->skeleton = nullptr; } } @@ -2048,7 +2045,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) { Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values(); old_values->restore(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Anim Apply Reset")); ur->add_do_method(new_values.ptr(), "restore"); ur->add_undo_method(old_values.ptr(), "restore"); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index b6d8dab1ed..caf1387ff0 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -311,7 +311,7 @@ private: protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _get_property_list(List<PropertyInfo> *p_list) const; void _notification(int p_what); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 14cf64afad..7dbe892299 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -399,9 +399,9 @@ void AnimationNode::_set_filters(const Array &p_filters) { } } -void AnimationNode::_validate_property(PropertyInfo &property) const { - if (!has_filter() && (property.name == "filter_enabled" || property.name == "filters")) { - property.usage = PROPERTY_USAGE_NONE; +void AnimationNode::_validate_property(PropertyInfo &p_property) const { + if (!has_filter() && (p_property.name == "filter_enabled" || p_property.name == "filters")) { + p_property.usage = PROPERTY_USAGE_NONE; } } diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 99851d140e..ee51a54557 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -111,7 +111,7 @@ protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; GDVIRTUAL0RC(Dictionary, _get_child_nodes) GDVIRTUAL0RC(Array, _get_parameter_list) diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 04debcab05..7c85b650bf 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -283,8 +283,8 @@ Vector<AudioFrame> AudioStreamPlayer::_get_volume_vector() { return volume_vector; } -void AudioStreamPlayer::_validate_property(PropertyInfo &property) const { - if (property.name == "bus") { +void AudioStreamPlayer::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "bus") { String options; for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { if (i > 0) { @@ -294,10 +294,8 @@ void AudioStreamPlayer::_validate_property(PropertyInfo &property) const { options += name; } - property.hint_string = options; + p_property.hint_string = options; } - - Node::_validate_property(property); } void AudioStreamPlayer::_bus_layout_changed() { diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h index 67e616312a..45a6d7663e 100644 --- a/scene/audio/audio_stream_player.h +++ b/scene/audio/audio_stream_player.h @@ -72,7 +72,7 @@ private: Vector<AudioFrame> _get_volume_vector(); protected: - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 0a163b65ff..e163f4355c 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -34,11 +34,9 @@ #include "servers/rendering_server.h" Size2 Button::get_minimum_size() const { - Ref<Texture2D> _icon; - if (icon.is_null() && has_theme_icon(SNAME("icon"))) { + Ref<Texture2D> _icon = icon; + if (_icon.is_null() && has_theme_icon(SNAME("icon"))) { _icon = Control::get_theme_icon(SNAME("icon")); - } else { - _icon = icon; } return get_minimum_size_for_text_and_icon("", _icon); @@ -342,13 +340,13 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu minsize.width = 0; } - if (!expand_icon && !p_icon.is_null()) { + if (!expand_icon && p_icon.is_valid()) { minsize.height = MAX(minsize.height, p_icon->get_height()); if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) { minsize.width += p_icon->get_width(); if (!xl_text.is_empty() || !p_text.is_empty()) { - minsize.width += get_theme_constant(SNAME("hseparation")); + minsize.width += MAX(0, get_theme_constant(SNAME("h_separation"))); } } else { minsize.width = MAX(minsize.width, p_icon->get_width()); diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index cb80f5b5ef..26edc1f1b0 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -75,7 +75,7 @@ Size2 CheckBox::get_minimum_size() const { Size2 tex_size = get_icon_size(); minsize.width += tex_size.width; if (get_text().length() > 0) { - minsize.width += get_theme_constant(SNAME("h_separation")); + minsize.width += MAX(0, get_theme_constant(SNAME("h_separation"))); } Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal")); minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM)); diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index a09873ea4f..b9674ca41e 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -52,7 +52,7 @@ Size2 CheckButton::get_minimum_size() const { Size2 tex_size = get_icon_size(); minsize.width += tex_size.width; if (get_text().length() > 0) { - minsize.width += get_theme_constant(SNAME("h_separation")); + minsize.width += MAX(0, get_theme_constant(SNAME("h_separation"))); } Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal")); minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM)); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 6d0380c898..545c39a605 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -422,9 +422,9 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const { } } -void Control::_validate_property(PropertyInfo &property) const { +void Control::_validate_property(PropertyInfo &p_property) const { // Update theme type variation options. - if (property.name == "theme_type_variation") { + if (p_property.name == "theme_type_variation") { List<StringName> names; // Only the default theme and the project theme are used for the list of options. @@ -447,18 +447,18 @@ void Control::_validate_property(PropertyInfo &property) const { unique_names.append(E); } - property.hint_string = hint_string; + p_property.hint_string = hint_string; } - if (property.name == "mouse_force_pass_scroll_events") { + if (p_property.name == "mouse_force_pass_scroll_events") { // Disable force pass if the control is not stopping the event. if (data.mouse_filter != MOUSE_FILTER_STOP) { - property.usage |= PROPERTY_USAGE_READ_ONLY; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } } - if (property.name == "scale") { - property.hint = PROPERTY_HINT_LINK; + if (p_property.name == "scale") { + p_property.hint = PROPERTY_HINT_LINK; } // Validate which positioning properties should be displayed depending on the parent and the layout mode. @@ -467,33 +467,33 @@ void Control::_validate_property(PropertyInfo &property) const { // If there is no parent, display both anchor and container options. // Set the layout mode to be disabled with the proper value. - if (property.name == "layout_mode") { - property.hint_string = "Position,Anchors,Container,Uncontrolled"; - property.usage |= PROPERTY_USAGE_READ_ONLY; + if (p_property.name == "layout_mode") { + p_property.hint_string = "Position,Anchors,Container,Uncontrolled"; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } // Use the layout mode to display or hide advanced anchoring properties. bool use_custom_anchors = _get_anchors_layout_preset() == -1; // Custom "preset". - if (!use_custom_anchors && (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_"))) { - property.usage ^= PROPERTY_USAGE_EDITOR; + if (!use_custom_anchors && (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_"))) { + p_property.usage ^= PROPERTY_USAGE_EDITOR; } } else if (Object::cast_to<Container>(parent_node)) { // If the parent is a container, display only container-related properties. - if (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_") || property.name == "anchors_preset" || - property.name == "position" || property.name == "rotation" || property.name == "scale" || property.name == "size" || property.name == "pivot_offset") { - property.usage ^= PROPERTY_USAGE_EDITOR; + if (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_") || p_property.name == "anchors_preset" || + p_property.name == "position" || p_property.name == "rotation" || p_property.name == "scale" || p_property.name == "size" || p_property.name == "pivot_offset") { + p_property.usage ^= PROPERTY_USAGE_EDITOR; - } else if (property.name == "layout_mode") { + } else if (p_property.name == "layout_mode") { // Set the layout mode to be disabled with the proper value. - property.hint_string = "Position,Anchors,Container,Uncontrolled"; - property.usage |= PROPERTY_USAGE_READ_ONLY; - } else if (property.name == "size_flags_horizontal" || property.name == "size_flags_vertical") { + p_property.hint_string = "Position,Anchors,Container,Uncontrolled"; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; + } else if (p_property.name == "size_flags_horizontal" || p_property.name == "size_flags_vertical") { // Filter allowed size flags based on the parent container configuration. Container *parent_container = Object::cast_to<Container>(parent_node); Vector<int> size_flags; - if (property.name == "size_flags_horizontal") { + if (p_property.name == "size_flags_horizontal") { size_flags = parent_container->get_allowed_size_flags_horizontal(); - } else if (property.name == "size_flags_vertical") { + } else if (p_property.name == "size_flags_vertical") { size_flags = parent_container->get_allowed_size_flags_vertical(); } @@ -522,30 +522,30 @@ void Control::_validate_property(PropertyInfo &property) const { } if (hint_string.is_empty()) { - property.hint_string = ""; - property.usage |= PROPERTY_USAGE_READ_ONLY; + p_property.hint_string = ""; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } else { - property.hint_string = hint_string; + p_property.hint_string = hint_string; } } } else { // If the parent is NOT a container or not a control at all, display only anchoring-related properties. - if (property.name.begins_with("size_flags_")) { - property.usage ^= PROPERTY_USAGE_EDITOR; + if (p_property.name.begins_with("size_flags_")) { + p_property.usage ^= PROPERTY_USAGE_EDITOR; - } else if (property.name == "layout_mode") { + } else if (p_property.name == "layout_mode") { // Set the layout mode to be enabled with proper options. - property.hint_string = "Position,Anchors"; + p_property.hint_string = "Position,Anchors"; } // Use the layout mode to display or hide advanced anchoring properties. bool use_anchors = _get_layout_mode() == LayoutMode::LAYOUT_MODE_ANCHORS; - if (!use_anchors && property.name == "anchors_preset") { - property.usage ^= PROPERTY_USAGE_EDITOR; + if (!use_anchors && p_property.name == "anchors_preset") { + p_property.usage ^= PROPERTY_USAGE_EDITOR; } bool use_custom_anchors = use_anchors && _get_anchors_layout_preset() == -1; // Custom "preset". - if (!use_custom_anchors && (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_"))) { - property.usage ^= PROPERTY_USAGE_EDITOR; + if (!use_custom_anchors && (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_"))) { + p_property.usage ^= PROPERTY_USAGE_EDITOR; } } @@ -555,16 +555,36 @@ void Control::_validate_property(PropertyInfo &property) const { } bool property_is_managed_by_container = false; for (unsigned i = 0; i < properties_managed_by_container_count; i++) { - property_is_managed_by_container = properties_managed_by_container[i] == property.name; + property_is_managed_by_container = properties_managed_by_container[i] == p_property.name; if (property_is_managed_by_container) { break; } } if (property_is_managed_by_container) { - property.usage |= PROPERTY_USAGE_READ_ONLY; + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } } +bool Control::_property_can_revert(const StringName &p_name) const { + if (p_name == "layout_mode" || p_name == "anchors_preset") { + return true; + } + + return false; +} + +bool Control::_property_get_revert(const StringName &p_name, Variant &r_property) const { + if (p_name == "layout_mode") { + r_property = _get_default_layout_mode(); + return true; + } else if (p_name == "anchors_preset") { + r_property = LayoutPreset::PRESET_TOP_LEFT; + return true; + } + + return false; +} + // Global relations. bool Control::is_top_level_control() const { @@ -794,24 +814,15 @@ void Control::_compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t ( void Control::_set_layout_mode(LayoutMode p_mode) { bool list_changed = false; - if (p_mode == LayoutMode::LAYOUT_MODE_POSITION || p_mode == LayoutMode::LAYOUT_MODE_ANCHORS) { - if ((int)get_meta("_edit_layout_mode", p_mode) != (int)p_mode) { - list_changed = true; - } - - set_meta("_edit_layout_mode", (int)p_mode); + if (data.stored_layout_mode != p_mode) { + list_changed = true; + data.stored_layout_mode = p_mode; + } - if (p_mode == LayoutMode::LAYOUT_MODE_POSITION) { - remove_meta("_edit_layout_mode"); - remove_meta("_edit_use_custom_anchors"); - set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT, LayoutPresetMode::PRESET_MODE_KEEP_SIZE); - set_grow_direction_preset(LayoutPreset::PRESET_TOP_LEFT); - } - } else { - if (has_meta("_edit_layout_mode")) { - remove_meta("_edit_layout_mode"); - list_changed = true; - } + if (data.stored_layout_mode == LayoutMode::LAYOUT_MODE_POSITION) { + data.stored_use_custom_anchors = false; + set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT, LayoutPresetMode::PRESET_MODE_KEEP_SIZE); + set_grow_direction_preset(LayoutPreset::PRESET_TOP_LEFT); } if (list_changed) { @@ -832,33 +843,43 @@ Control::LayoutMode Control::_get_layout_mode() const { if (_get_anchors_layout_preset() != (int)LayoutPreset::PRESET_TOP_LEFT) { return LayoutMode::LAYOUT_MODE_ANCHORS; } - // Otherwise check what was saved. - if (has_meta("_edit_layout_mode")) { - return (LayoutMode)(int)get_meta("_edit_layout_mode"); + + // Otherwise fallback on what's stored. + return data.stored_layout_mode; +} + +Control::LayoutMode Control::_get_default_layout_mode() const { + Node *parent_node = get_parent_control(); + // In these modes the property is read-only. + if (!parent_node) { + return LayoutMode::LAYOUT_MODE_UNCONTROLLED; + } else if (Object::cast_to<Container>(parent_node)) { + return LayoutMode::LAYOUT_MODE_CONTAINER; } - // Or fallback on default. + + // Otherwise fallback on the position mode. return LayoutMode::LAYOUT_MODE_POSITION; } void Control::_set_anchors_layout_preset(int p_preset) { bool list_changed = false; - if (get_meta("_edit_layout_mode", LayoutMode::LAYOUT_MODE_ANCHORS).operator int() != LayoutMode::LAYOUT_MODE_ANCHORS) { + if (data.stored_layout_mode != LayoutMode::LAYOUT_MODE_ANCHORS) { list_changed = true; - set_meta("_edit_layout_mode", LayoutMode::LAYOUT_MODE_ANCHORS); + data.stored_layout_mode = LayoutMode::LAYOUT_MODE_ANCHORS; } if (p_preset == -1) { - if (!get_meta("_edit_use_custom_anchors", false)) { - set_meta("_edit_use_custom_anchors", true); + if (!data.stored_use_custom_anchors) { + data.stored_use_custom_anchors = true; notify_property_list_changed(); } return; // Keep settings as is. } - if (get_meta("_edit_use_custom_anchors", true)) { + if (data.stored_use_custom_anchors) { list_changed = true; - remove_meta("_edit_use_custom_anchors"); + data.stored_use_custom_anchors = false; } LayoutPreset preset = (LayoutPreset)p_preset; @@ -899,7 +920,7 @@ void Control::_set_anchors_layout_preset(int p_preset) { int Control::_get_anchors_layout_preset() const { // If the custom preset was selected by user, use it. - if ((bool)get_meta("_edit_use_custom_anchors", false)) { + if (data.stored_use_custom_anchors) { return -1; } @@ -3391,7 +3412,7 @@ void Control::_bind_methods() { 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"); ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode"); ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION); const String anchors_presets_options = "Custom:-1,PresetFullRect:15," @@ -3399,7 +3420,7 @@ void Control::_bind_methods() { "PresetCenterLeft:4,PresetCenterTop:5,PresetCenterRight:6,PresetCenterBottom:7,PresetCenter:8," "PresetLeftWide:9,PresetTopWide:10,PresetRightWide:11,PresetBottomWide:12,PresetVCenterWide:13,PresetHCenterWide:14"; - ADD_PROPERTY(PropertyInfo(Variant::INT, "anchors_preset", PROPERTY_HINT_ENUM, anchors_presets_options, PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_anchors_layout_preset", "_get_anchors_layout_preset"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "anchors_preset", PROPERTY_HINT_ENUM, anchors_presets_options, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_anchors_layout_preset", "_get_anchors_layout_preset"); ADD_PROPERTY_DEFAULT("anchors_preset", -1); ADD_SUBGROUP_INDENT("Anchor Points", "anchor_", 1); diff --git a/scene/gui/control.h b/scene/gui/control.h index db19d09b11..a50c66b634 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -170,6 +170,9 @@ private: // Positioning and sizing. + LayoutMode stored_layout_mode = LayoutMode::LAYOUT_MODE_POSITION; + bool stored_use_custom_anchors = false; + real_t offset[4] = { 0.0, 0.0, 0.0, 0.0 }; real_t anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN }; FocusMode focus_mode = FOCUS_NONE; @@ -275,6 +278,7 @@ private: void _set_layout_mode(LayoutMode p_mode); LayoutMode _get_layout_mode() const; + LayoutMode _get_default_layout_mode() const; void _set_anchors_layout_preset(int p_preset); int _get_anchors_layout_preset() const; @@ -317,7 +321,10 @@ protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; + + bool _property_can_revert(const StringName &p_name) const; + bool _property_get_revert(const StringName &p_name, Variant &r_property) const; // Internationalization. diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 112b8c74af..582519e70f 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -446,12 +446,11 @@ void GraphNode::_edit_set_position(const Point2 &p_position) { set_position(p_position); } -void GraphNode::_validate_property(PropertyInfo &property) const { - Control::_validate_property(property); +void GraphNode::_validate_property(PropertyInfo &p_property) const { GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent()); if (graph) { - if (property.name == "position") { - property.usage |= PROPERTY_USAGE_READ_ONLY; + if (p_property.name == "position") { + p_property.usage |= PROPERTY_USAGE_READ_ONLY; } } } diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 0651eb5cc9..6d5bb4361e 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -101,7 +101,7 @@ private: #ifdef TOOLS_ENABLED void _edit_set_position(const Point2 &p_position) override; - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; #endif protected: diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index d0a25972f8..e3e9499705 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -932,11 +932,7 @@ void ItemList::_notification(int p_what) { scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -bg->get_margin(SIDE_BOTTOM)); Size2 size = get_size(); - int width = size.width - bg->get_minimum_size().width; - if (scroll_bar->is_visible()) { - width -= mw; - } draw_style_box(bg, Rect2(Point2(), size)); @@ -1095,6 +1091,10 @@ void ItemList::_notification(int p_what) { shape_changed = false; } + if (scroll_bar->is_visible()) { + width -= mw; + } + //ensure_selected_visible needs to be checked before we draw the list. if (ensure_selected_visible && current >= 0 && current < items.size()) { Rect2 r = items[current].rect_cache; diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index e7f48beb00..4ef1e48a32 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -764,13 +764,17 @@ int Label::get_visible_characters() const { void Label::set_percent_visible(float p_percent) { if (percent_visible != p_percent) { - if (p_percent < 0 || p_percent >= 1) { + if (percent_visible >= 1.0) { visible_chars = -1; - percent_visible = 1; + percent_visible = 1.0; + } else if (percent_visible < 0.0) { + visible_chars = 0; + percent_visible = 0.0; } else { visible_chars = get_total_character_count() * p_percent; percent_visible = p_percent; } + if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) { dirty = true; } diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index f315b2bbf1..b523c2bb8b 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -2224,9 +2224,9 @@ Key LineEdit::_get_menu_action_accelerator(const String &p_action) { } } -void LineEdit::_validate_property(PropertyInfo &property) const { - if (!caret_blink_enabled && property.name == "caret_blink_speed") { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void LineEdit::_validate_property(PropertyInfo &p_property) const { + if (!caret_blink_enabled && p_property.name == "caret_blink_speed") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 4d5ebf441c..254f842b66 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -221,7 +221,7 @@ protected: virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override; virtual void gui_input(const Ref<InputEvent> &p_event) override; - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_horizontal_alignment(HorizontalAlignment p_alignment); diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index ebe833c6e0..f450222130 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -749,7 +749,6 @@ Size2 MenuBar::get_minimum_size() const { } Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - int hsep = get_theme_constant(SNAME("h_separation")); Vector2 size; for (int i = 0; i < menu_cache.size(); i++) { @@ -758,7 +757,10 @@ Size2 MenuBar::get_minimum_size() const { } Size2 sz = menu_cache[i].text_buf->get_size() + style->get_minimum_size(); size.y = MAX(size.y, sz.y); - size.x += sz.x + hsep; + size.x += sz.x; + } + if (menu_cache.size() > 1) { + size.x += get_theme_constant(SNAME("h_separation")) * (menu_cache.size() - 1); } return size; } diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index b26410e318..a5a6240e27 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -47,7 +47,7 @@ Size2 OptionButton::get_minimum_size() const { const Size2 arrow_size = Control::get_theme_icon(SNAME("arrow"))->get_size(); Size2 content_size = minsize - padding; - content_size.width += arrow_size.width + get_theme_constant(SNAME("h_separation")); + content_size.width += arrow_size.width + MAX(0, get_theme_constant(SNAME("h_separation"))); content_size.height = MAX(content_size.height, arrow_size.height); minsize = content_size + padding; @@ -471,9 +471,9 @@ void OptionButton::get_translatable_strings(List<String> *p_strings) const { popup->get_translatable_strings(p_strings); } -void OptionButton::_validate_property(PropertyInfo &property) const { - if (property.name == "text" || property.name == "icon") { - property.usage = PROPERTY_USAGE_NONE; +void OptionButton::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "text" || p_property.name == "icon") { + p_property.usage = PROPERTY_USAGE_NONE; } } diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index 49b5eee910..cd709b8f5f 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -58,7 +58,7 @@ protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 984f20ee58..ab466089a7 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -4912,15 +4912,19 @@ void RichTextLabel::set_percent_visible(float p_percent) { if (percent_visible != p_percent) { _stop_thread(); - if (p_percent < 0 || p_percent >= 1) { + if (percent_visible >= 1.0) { visible_characters = -1; - percent_visible = 1; + percent_visible = 1.0; + } else if (percent_visible < 0.0) { + visible_characters = 0; + percent_visible = 0.0; } else { visible_characters = get_total_character_count() * p_percent; percent_visible = p_percent; } + if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) { - main->first_invalid_line.store(0); //invalidate ALL + main->first_invalid_line.store(0); // Invalidate ALL. _validate_line_caches(); } update(); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 1eb6c5a554..ede7bfb0bf 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -749,6 +749,7 @@ int TreeItem::get_child_count() { } Array TreeItem::get_children() { + // Don't need to explicitly create children cache, because get_child_count creates it. int size = get_child_count(); Array arr; arr.resize(size); @@ -770,6 +771,22 @@ int TreeItem::get_index() { return idx - 1; } +#ifdef DEV_ENABLED +void TreeItem::validate_cache() const { + if (!parent || parent->children_cache.is_empty()) { + return; + } + TreeItem *scan = parent->first_child; + int index = 0; + while (scan) { + DEV_ASSERT(parent->children_cache[index] == scan); + ++index; + scan = scan->get_next(); + } + DEV_ASSERT(index == parent->children_cache.size()); +} +#endif + void TreeItem::move_before(TreeItem *p_item) { ERR_FAIL_NULL(p_item); ERR_FAIL_COND(is_root); @@ -797,7 +814,11 @@ void TreeItem::move_before(TreeItem *p_item) { parent->children_cache.clear(); } else { parent->first_child = this; - parent->children_cache.insert(0, this); + // If the cache is empty, it has not been built but there + // are items in the tree (note p_item != nullptr,) so we cannot update it. + if (!parent->children_cache.is_empty()) { + parent->children_cache.insert(0, this); + } } prev = item_prev; @@ -807,6 +828,8 @@ void TreeItem::move_before(TreeItem *p_item) { if (tree && old_tree == tree) { tree->update(); } + + validate_cache(); } void TreeItem::move_after(TreeItem *p_item) { @@ -839,12 +862,17 @@ void TreeItem::move_after(TreeItem *p_item) { if (next) { parent->children_cache.clear(); } else { - parent->children_cache.append(this); + // If the cache is empty, it has not been built but there + // are items in the tree (note p_item != nullptr,) so we cannot update it. + if (!parent->children_cache.is_empty()) { + parent->children_cache.append(this); + } } if (tree && old_tree == tree) { tree->update(); } + validate_cache(); } void TreeItem::remove_child(TreeItem *p_item) { @@ -859,6 +887,7 @@ void TreeItem::remove_child(TreeItem *p_item) { if (tree) { tree->update(); } + validate_cache(); } void TreeItem::set_selectable(int p_column, bool p_selectable) { @@ -1396,6 +1425,7 @@ TreeItem::TreeItem(Tree *p_tree) { TreeItem::~TreeItem() { _unlink_from_tree(); + validate_cache(); prev = nullptr; clear_children(); _change_tree(nullptr); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index f0819e2980..bcc2419b80 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -342,6 +342,13 @@ public: Array get_children(); int get_index(); +#ifdef DEV_ENABLED + // This debugging code can be removed once the current refactoring of this class is complete. + void validate_cache() const; +#else + void validate_cache() const {} +#endif + void move_before(TreeItem *p_item); void move_after(TreeItem *p_item); diff --git a/scene/gui/video_stream_player.h b/scene/gui/video_stream_player.h index 913e7905b6..9974eb8488 100644 --- a/scene/gui/video_stream_player.h +++ b/scene/gui/video_stream_player.h @@ -79,7 +79,7 @@ class VideoStreamPlayer : public Control { protected: static void _bind_methods(); void _notification(int p_notification); - void _validate_property(PropertyInfo &p_property) const override; + void _validate_property(PropertyInfo &p_property) const; public: Size2 get_minimum_size() const override; diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 3a071ef542..8f40f257f9 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -286,9 +286,9 @@ void CanvasLayer::_update_follow_viewport(bool p_force_exit) { } } -void CanvasLayer::_validate_property(PropertyInfo &property) const { - if (!follow_viewport && property.name == "follow_viewport_scale") { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void CanvasLayer::_validate_property(PropertyInfo &p_property) const { + if (!follow_viewport && p_property.name == "follow_viewport_scale") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index 2493675b31..74b5ebd453 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -64,7 +64,7 @@ class CanvasLayer : public Node { protected: void _notification(int p_what); static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_layer(int p_xform); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 584fad9648..cc356e513c 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3953,9 +3953,9 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(VRS_MAX); } -void Viewport::_validate_property(PropertyInfo &property) const { - if (vrs_mode != VRS_TEXTURE && (property.name == "vrs_texture")) { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void Viewport::_validate_property(PropertyInfo &p_property) const { + if (vrs_mode != VRS_TEXTURE && (p_property.name == "vrs_texture")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 4221baff06..a0ec2d54dd 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -709,7 +709,7 @@ public: bool is_using_xr(); #endif // _3D_DISABLED - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; Viewport(); ~Viewport(); }; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index d40b82f5eb..63cc535e26 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -1510,8 +1510,8 @@ bool Window::is_auto_translating() const { return auto_translate; } -void Window::_validate_property(PropertyInfo &property) const { - if (property.name == "theme_type_variation") { +void Window::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "theme_type_variation") { List<StringName> names; // Only the default theme and the project theme are used for the list of options. @@ -1534,7 +1534,7 @@ void Window::_validate_property(PropertyInfo &property) const { unique_names.append(E); } - property.hint_string = hint_string; + p_property.hint_string = hint_string; } } diff --git a/scene/main/window.h b/scene/main/window.h index c060f1d79d..aa32edbb04 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -158,7 +158,7 @@ protected: virtual Size2 _get_contents_minimum_size() const; static void _bind_methods(); void _notification(int p_what); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; virtual void add_child_notify(Node *p_child) override; virtual void remove_child_notify(Node *p_child) override; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 9979855232..762d9f2a28 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -158,8 +158,8 @@ #include "scene/resources/immediate_mesh.h" #include "scene/resources/label_settings.h" #include "scene/resources/material.h" -#include "scene/resources/mesh.h" #include "scene/resources/mesh_data_tool.h" +#include "scene/resources/multimesh.h" #include "scene/resources/navigation_mesh.h" #include "scene/resources/packed_scene.h" #include "scene/resources/particles_material.h" @@ -260,7 +260,7 @@ #include "scene/resources/fog_material.h" #include "scene/resources/importer_mesh.h" #include "scene/resources/mesh_library.h" -#endif +#endif // _3D_DISABLED static Ref<ResourceFormatSaverText> resource_saver_text; static Ref<ResourceFormatLoaderText> resource_loader_text; @@ -575,7 +575,7 @@ void register_scene_types() { GDREGISTER_CLASS(NavigationObstacle3D); OS::get_singleton()->yield(); // may take time to init -#endif +#endif // _3D_DISABLED /* REGISTER SHADER */ @@ -765,10 +765,6 @@ void register_scene_types() { SceneTree::add_idle_callback(ParticlesMaterial::flush_changes); ParticlesMaterial::init_shaders(); - GDREGISTER_CLASS(ProceduralSkyMaterial); - GDREGISTER_CLASS(PanoramaSkyMaterial); - GDREGISTER_CLASS(PhysicalSkyMaterial); - GDREGISTER_VIRTUAL_CLASS(Mesh); GDREGISTER_CLASS(ArrayMesh); GDREGISTER_CLASS(PlaceholderMesh); @@ -796,6 +792,9 @@ void register_scene_types() { GDREGISTER_CLASS(StandardMaterial3D); GDREGISTER_CLASS(ORMMaterial3D); GDREGISTER_CLASS(PlaceholderMaterial); + GDREGISTER_CLASS(ProceduralSkyMaterial); + GDREGISTER_CLASS(PanoramaSkyMaterial); + GDREGISTER_CLASS(PhysicalSkyMaterial); SceneTree::add_idle_callback(BaseMaterial3D::flush_changes); BaseMaterial3D::init_shaders(); @@ -824,7 +823,7 @@ void register_scene_types() { ClassDB::register_class<SkeletonModification3DStackHolder>(); OS::get_singleton()->yield(); // may take time to init -#endif +#endif // _3D_DISABLED GDREGISTER_CLASS(PhysicsMaterial); GDREGISTER_CLASS(World3D); @@ -1203,11 +1202,10 @@ void unregister_scene_types() { // StandardMaterial3D is not initialised when 3D is disabled, so it shouldn't be cleaned up either #ifndef _3D_DISABLED BaseMaterial3D::finish_shaders(); -#endif // _3D_DISABLED - PhysicalSkyMaterial::cleanup_shader(); PanoramaSkyMaterial::cleanup_shader(); ProceduralSkyMaterial::cleanup_shader(); +#endif // _3D_DISABLED ParticlesMaterial::finish_shaders(); CanvasItemMaterial::finish_shaders(); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 69b30b72b0..0782f779b5 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -967,7 +967,6 @@ int Animation::find_track(const NodePath &p_path, const TrackType p_type) const void Animation::track_set_interpolation_type(int p_track, InterpolationType p_interp) { ERR_FAIL_INDEX(p_track, tracks.size()); - ERR_FAIL_INDEX(p_interp, 3); tracks[p_track]->interpolation = p_interp; emit_changed(); } @@ -2283,6 +2282,8 @@ int Animation::_find(const Vector<K> &p_keys, double p_time, bool p_backward) co return middle; } +// Linear interpolation for anytype. + Vector3 Animation::_interpolate(const Vector3 &p_a, const Vector3 &p_b, real_t p_c) const { return p_a.lerp(p_b, p_c); } @@ -2301,6 +2302,8 @@ real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) return p_a * (1.0 - p_c) + p_b * p_c; } +// Cubic interpolation for anytype. + Vector3 Animation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const { return p_a.cubic_interpolate(p_b, p_pre_a, p_post_b, p_c); } @@ -2389,6 +2392,96 @@ real_t Animation::_cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, c return _interpolate(p_a, p_b, p_c); } +// Cubic interpolation in time for anytype. + +Vector3 Animation::_cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const { + return p_a.cubic_interpolate_in_time(p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t); +} + +Quaternion Animation::_cubic_interpolate_in_time(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const { + return p_a.spherical_cubic_interpolate_in_time(p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t); +} + +Variant Animation::_cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const { + Variant::Type type_a = p_a.get_type(); + Variant::Type type_b = p_b.get_type(); + Variant::Type type_pa = p_pre_a.get_type(); + Variant::Type type_pb = p_post_b.get_type(); + + //make int and real play along + + uint32_t vformat = 1 << type_a; + vformat |= 1 << type_b; + vformat |= 1 << type_pa; + vformat |= 1 << type_pb; + + if (vformat == ((1 << Variant::INT) | (1 << Variant::FLOAT)) || vformat == (1 << Variant::FLOAT)) { + //mix of real and int + real_t a = p_a; + real_t b = p_b; + real_t pa = p_pre_a; + real_t pb = p_post_b; + + return Math::cubic_interpolate_in_time(a, b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t); + } else if ((vformat & (vformat - 1))) { + return p_a; //can't interpolate, mix of types + } + + switch (type_a) { + case Variant::VECTOR2: { + Vector2 a = p_a; + Vector2 b = p_b; + Vector2 pa = p_pre_a; + Vector2 pb = p_post_b; + + return a.cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t); + } + case Variant::RECT2: { + Rect2 a = p_a; + Rect2 b = p_b; + Rect2 pa = p_pre_a; + Rect2 pb = p_post_b; + + return Rect2( + a.position.cubic_interpolate_in_time(b.position, pa.position, pb.position, p_c, p_b_t, p_pre_a_t, p_post_b_t), + a.size.cubic_interpolate_in_time(b.size, pa.size, pb.size, p_c, p_b_t, p_pre_a_t, p_post_b_t)); + } + case Variant::VECTOR3: { + Vector3 a = p_a; + Vector3 b = p_b; + Vector3 pa = p_pre_a; + Vector3 pb = p_post_b; + + return a.cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t); + } + case Variant::QUATERNION: { + Quaternion a = p_a; + Quaternion b = p_b; + Quaternion pa = p_pre_a; + Quaternion pb = p_post_b; + + return a.spherical_cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t); + } + case Variant::AABB: { + AABB a = p_a; + AABB b = p_b; + AABB pa = p_pre_a; + AABB pb = p_post_b; + + return AABB( + a.position.cubic_interpolate_in_time(b.position, pa.position, pb.position, p_c, p_b_t, p_pre_a_t, p_post_b_t), + a.size.cubic_interpolate_in_time(b.size, pa.size, pb.size, p_c, p_b_t, p_pre_a_t, p_post_b_t)); + } + default: { + return _interpolate(p_a, p_b, p_c); + } + } +} + +real_t Animation::_cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const { + return _interpolate(p_a, p_b, p_c); +} + template <class T> T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward) const { int len = _find(p_keys, length) + 1; // try to find last key (there may be more past the end) @@ -2568,26 +2661,65 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol case INTERPOLATION_LINEAR: { return _interpolate(p_keys[idx].value, p_keys[next].value, c); } break; - case INTERPOLATION_CUBIC: { - int pre = idx - 1; - if (pre < 0) { - if (loop_mode == LOOP_LINEAR && p_loop_wrap) { - pre = len - 1; - } else { - pre = 0; + case INTERPOLATION_CUBIC: + case INTERPOLATION_CUBIC_IN_TIME: { + int pre = 0; + int post = 0; + if (!p_backward) { + pre = idx - 1; + if (pre < 0) { + if (loop_mode == LOOP_LINEAR && p_loop_wrap) { + pre = len - 1; + } else { + pre = 0; + } } - } - int post = next + 1; - if (post >= len) { - if (loop_mode == LOOP_LINEAR && p_loop_wrap) { - post = 0; - } else { - post = next; + post = next + 1; + if (post >= len) { + if (loop_mode == LOOP_LINEAR && p_loop_wrap) { + post = 0; + } else { + post = next; + } + } + } else { + pre = idx + 1; + if (pre >= len) { + if (loop_mode == LOOP_LINEAR && p_loop_wrap) { + pre = 0; + } else { + pre = idx; + } + } + post = next - 1; + if (post < 0) { + if (loop_mode == LOOP_LINEAR && p_loop_wrap) { + post = len - 1; + } else { + post = 0; + } } } - return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c); + if (loop_mode == LOOP_LINEAR && p_loop_wrap) { + if (p_interp == INTERPOLATION_CUBIC) { + return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c); + } + return _cubic_interpolate_in_time( + p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c, + pre > idx ? -length + p_keys[pre].time - p_keys[idx].time : p_keys[pre].time - p_keys[idx].time, + next < idx ? length + p_keys[next].time - p_keys[idx].time : p_keys[next].time - p_keys[idx].time, + next < idx || post <= idx ? length + p_keys[post].time - p_keys[idx].time : p_keys[post].time - p_keys[idx].time); + } + if (p_interp == INTERPOLATION_CUBIC) { + return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c); + } + return _cubic_interpolate_in_time( + p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c, + p_keys[pre].time - p_keys[idx].time, + p_keys[next].time - p_keys[idx].time, + p_keys[post].time - p_keys[idx].time); } break; default: return p_keys[idx].value; @@ -3839,6 +3971,7 @@ void Animation::_bind_methods() { BIND_ENUM_CONSTANT(INTERPOLATION_NEAREST); BIND_ENUM_CONSTANT(INTERPOLATION_LINEAR); BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC); + BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC_IN_TIME); BIND_ENUM_CONSTANT(UPDATE_CONTINUOUS); BIND_ENUM_CONSTANT(UPDATE_DISCRETE); @@ -3868,316 +4001,208 @@ void Animation::clear() { emit_signal(SceneStringNames::get_singleton()->tracks_changed); } -bool Animation::_position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm) { - const Vector3 &v0 = t0.value; - const Vector3 &v1 = t1.value; - const Vector3 &v2 = t2.value; - - if (v0.is_equal_approx(v2)) { - //0 and 2 are close, let's see if 1 is close - if (!v0.is_equal_approx(v1)) { - //not close, not optimizable - return false; - } - - } else { - Vector3 pd = (v2 - v0); - real_t d0 = pd.dot(v0); - real_t d1 = pd.dot(v1); - real_t d2 = pd.dot(v2); - if (d1 < d0 || d1 > d2) { - return false; - } - - Vector3 s[2] = { v0, v2 }; - real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); - - if (d > pd.length() * p_allowed_linear_err) { - return false; //beyond allowed error for collinearity - } - - if (p_norm != Vector3() && Math::acos(pd.normalized().dot(p_norm)) > p_allowed_angular_error) { - return false; - } +bool Animation::_vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<Vector3> t1, const TKey<Vector3> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) { + // Remove overlapping keys. + if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) { + return true; } - - return true; -} - -bool Animation::_rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle) { - const Quaternion &q0 = t0.value; - const Quaternion &q1 = t1.value; - const Quaternion &q2 = t2.value; - - //localize both to rotation from q0 - - if (q0.is_equal_approx(q2)) { - if (!q0.is_equal_approx(q1)) { - return false; - } - - } else { - Quaternion r02 = (q0.inverse() * q2).normalized(); - Quaternion r01 = (q0.inverse() * q1).normalized(); - - Vector3 v02, v01; - real_t a02, a01; - - r02.get_axis_angle(v02, a02); - r01.get_axis_angle(v01, a01); - - if (Math::abs(a02) > p_max_optimizable_angle) { - return false; - } - - if (v01.dot(v02) < 0) { - //make sure both rotations go the same way to compare - v02 = -v02; - a02 = -a02; - } - - real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized())) / Math_PI; - if (err_01 > p_allowed_angular_error) { - //not rotating in the same axis - return false; - } - - if (a01 * a02 < 0) { - //not rotating in the same direction - return false; - } - - real_t tr = a01 / a02; - if (tr < 0 || tr > 1) { - return false; //rotating too much or too less + if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) { + return true; + } + // Calc velocities. + Vector3 vc0 = (t1.value - t0.value) / (t1.time - t0.time); + Vector3 vc1 = (t2.value - t1.value) / (t2.time - t1.time); + real_t v0 = vc0.length(); + real_t v1 = vc1.length(); + // Avoid zero div but check equality. + if (abs(v0 - v1) < p_allowed_precision_error) { + return true; + } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) { + return false; + } + // Check axis. + if (vc0.normalized().dot(vc1.normalized()) >= 1.0 - p_allowed_angular_error * 2.0) { + real_t ratio = v0 < v1 ? v0 / v1 : v1 / v0; + if (ratio >= 1.0 - p_allowed_velocity_err) { + return true; } } - - return true; + return false; } -bool Animation::_scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error) { - const Vector3 &v0 = t0.value; - const Vector3 &v1 = t1.value; - const Vector3 &v2 = t2.value; - - if (v0.is_equal_approx(v2)) { - //0 and 2 are close, let's see if 1 is close - if (!v0.is_equal_approx(v1)) { - //not close, not optimizable +bool Animation::_quaternion_track_optimize_key(const TKey<Quaternion> t0, const TKey<Quaternion> t1, const TKey<Quaternion> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) { + // Remove overlapping keys. + if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) { + return true; + } + if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) { + return true; + } + // Check axis. + Quaternion q0 = t0.value * t1.value * t0.value.inverse(); + Quaternion q1 = t1.value * t2.value * t1.value.inverse(); + if (q0.get_axis().dot(q1.get_axis()) >= 1.0 - p_allowed_angular_error * 2.0) { + // Calc velocities. + real_t v0 = Math::acos(t0.value.dot(t1.value)) / (t1.time - t0.time); + real_t v1 = Math::acos(t1.value.dot(t2.value)) / (t2.time - t1.time); + // Avoid zero div but check equality. + if (abs(v0 - v1) < p_allowed_precision_error) { + return true; + } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) { return false; } - - } else { - Vector3 pd = (v2 - v0); - real_t d0 = pd.dot(v0); - real_t d1 = pd.dot(v1); - real_t d2 = pd.dot(v2); - if (d1 < d0 || d1 > d2) { - return false; //beyond segment range - } - - Vector3 s[2] = { v0, v2 }; - real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); - - if (d > pd.length() * p_allowed_linear_error) { - return false; //beyond allowed error for colinearity + real_t ratio = v0 < v1 ? v0 / v1 : v1 / v0; + if (ratio >= 1.0 - p_allowed_velocity_err) { + return true; } } - - return true; + return false; } -bool Animation::_blend_shape_track_optimize_key(const TKey<float> &t0, const TKey<float> &t1, const TKey<float> &t2, real_t p_allowed_unit_error) { - float v0 = t0.value; - float v1 = t1.value; - float v2 = t2.value; - - if (Math::is_equal_approx(v1, v2, (float)p_allowed_unit_error)) { - //0 and 2 are close, let's see if 1 is close - if (!Math::is_equal_approx(v0, v1, (float)p_allowed_unit_error)) { - //not close, not optimizable - return false; - } - } else { - /* - TODO eventually discuss a way to optimize these better. - float pd = (v2 - v0); - real_t d0 = pd.dot(v0); - real_t d1 = pd.dot(v1); - real_t d2 = pd.dot(v2); - if (d1 < d0 || d1 > d2) { - return false; //beyond segment range - } - - float s[2] = { v0, v2 }; - real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); - - if (d > pd.length() * p_allowed_linear_error) { - return false; //beyond allowed error for colinearity +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) { + // Remove overlapping keys. + if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) { + return true; + } + if (abs(t0.value - t1.value) < p_allowed_precision_error && abs(t1.value - t2.value) < p_allowed_precision_error) { + return true; + } + // Calc velocities. + real_t v0 = (t1.value - t0.value) / (t1.time - t0.time); + real_t v1 = (t2.value - t1.value) / (t2.time - t1.time); + // Avoid zero div but check equality. + if (abs(v0 - v1) < p_allowed_precision_error) { + return true; + } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) { + return false; + } + if (!signbit(v0 * v1)) { + real_t ratio = v0 < v1 ? v0 / v1 : v1 / v0; + if (ratio >= 1.0 - p_allowed_velocity_err) { + return true; } -*/ } - - return true; + return false; } -void Animation::_position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err) { +void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) { ERR_FAIL_INDEX(p_idx, tracks.size()); ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D); PositionTrack *tt = static_cast<PositionTrack *>(tracks[p_idx]); - bool prev_erased = false; - TKey<Vector3> first_erased; - - Vector3 norm; - for (int i = 1; i < tt->positions.size() - 1; i++) { - TKey<Vector3> &t0 = tt->positions.write[i - 1]; - TKey<Vector3> &t1 = tt->positions.write[i]; - TKey<Vector3> &t2 = tt->positions.write[i + 1]; - - bool erase = _position_track_optimize_key(t0, t1, t2, p_allowed_linear_err, p_allowed_angular_err, norm); - if (erase && !prev_erased) { - norm = (t2.value - t1.value).normalized(); - } - - if (prev_erased && !_position_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err, p_allowed_angular_err, norm)) { - //avoid error to go beyond first erased key - erase = false; - } + int i = 0; + while (i < tt->positions.size() - 2) { + TKey<Vector3> t0 = tt->positions[i]; + TKey<Vector3> t1 = tt->positions[i + 1]; + TKey<Vector3> t2 = tt->positions[i + 2]; + bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error); if (erase) { - if (!prev_erased) { - first_erased = t1; - prev_erased = true; - } - - tt->positions.remove_at(i); - i--; - + tt->positions.remove_at(i + 1); } else { - prev_erased = false; - norm = Vector3(); + i++; + } + } + + if (tt->positions.size() == 2) { + if ((tt->positions[0].value - tt->positions[1].value).length() < p_allowed_precision_error) { + tt->positions.remove_at(1); } } } -void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) { +void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) { ERR_FAIL_INDEX(p_idx, tracks.size()); ERR_FAIL_COND(tracks[p_idx]->type != TYPE_ROTATION_3D); RotationTrack *tt = static_cast<RotationTrack *>(tracks[p_idx]); - bool prev_erased = false; - TKey<Quaternion> first_erased; - - for (int i = 1; i < tt->rotations.size() - 1; i++) { - TKey<Quaternion> &t0 = tt->rotations.write[i - 1]; - TKey<Quaternion> &t1 = tt->rotations.write[i]; - TKey<Quaternion> &t2 = tt->rotations.write[i + 1]; - bool erase = _rotation_track_optimize_key(t0, t1, t2, p_allowed_angular_err, p_max_optimizable_angle); - - if (prev_erased && !_rotation_track_optimize_key(t0, first_erased, t2, p_allowed_angular_err, p_max_optimizable_angle)) { - //avoid error to go beyond first erased key - erase = false; - } + int i = 0; + while (i < tt->rotations.size() - 2) { + TKey<Quaternion> t0 = tt->rotations[i]; + TKey<Quaternion> t1 = tt->rotations[i + 1]; + TKey<Quaternion> t2 = tt->rotations[i + 2]; + bool erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error); if (erase) { - if (!prev_erased) { - first_erased = t1; - prev_erased = true; - } - - tt->rotations.remove_at(i); - i--; - + tt->rotations.remove_at(i + 1); } else { - prev_erased = false; + i++; + } + } + + if (tt->rotations.size() == 2) { + if ((tt->rotations[0].value - tt->rotations[1].value).length() < p_allowed_precision_error) { + tt->rotations.remove_at(1); } } } -void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_linear_err) { +void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) { ERR_FAIL_INDEX(p_idx, tracks.size()); ERR_FAIL_COND(tracks[p_idx]->type != TYPE_SCALE_3D); ScaleTrack *tt = static_cast<ScaleTrack *>(tracks[p_idx]); - bool prev_erased = false; - TKey<Vector3> first_erased; - - for (int i = 1; i < tt->scales.size() - 1; i++) { - TKey<Vector3> &t0 = tt->scales.write[i - 1]; - TKey<Vector3> &t1 = tt->scales.write[i]; - TKey<Vector3> &t2 = tt->scales.write[i + 1]; - - bool erase = _scale_track_optimize_key(t0, t1, t2, p_allowed_linear_err); - if (prev_erased && !_scale_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err)) { - //avoid error to go beyond first erased key - erase = false; - } + int i = 0; + while (i < tt->scales.size() - 2) { + TKey<Vector3> t0 = tt->scales[i]; + TKey<Vector3> t1 = tt->scales[i + 1]; + TKey<Vector3> t2 = tt->scales[i + 2]; + bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error); if (erase) { - if (!prev_erased) { - first_erased = t1; - prev_erased = true; - } - - tt->scales.remove_at(i); - i--; - + tt->scales.remove_at(i + 1); } else { - prev_erased = false; + i++; + } + } + + if (tt->scales.size() == 2) { + if ((tt->scales[0].value - tt->scales[1].value).length() < p_allowed_precision_error) { + tt->scales.remove_at(1); } } } -void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_linear_err) { +void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) { ERR_FAIL_INDEX(p_idx, tracks.size()); ERR_FAIL_COND(tracks[p_idx]->type != TYPE_BLEND_SHAPE); BlendShapeTrack *tt = static_cast<BlendShapeTrack *>(tracks[p_idx]); - bool prev_erased = false; - TKey<float> first_erased; - first_erased.value = 0.0; - for (int i = 1; i < tt->blend_shapes.size() - 1; i++) { - TKey<float> &t0 = tt->blend_shapes.write[i - 1]; - TKey<float> &t1 = tt->blend_shapes.write[i]; - TKey<float> &t2 = tt->blend_shapes.write[i + 1]; - - bool erase = _blend_shape_track_optimize_key(t0, t1, t2, p_allowed_linear_err); - - if (prev_erased && !_blend_shape_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err)) { - //avoid error to go beyond first erased key - erase = false; - } + int i = 0; + while (i < tt->blend_shapes.size() - 2) { + TKey<float> t0 = tt->blend_shapes[i]; + TKey<float> t1 = tt->blend_shapes[i + 1]; + TKey<float> t2 = tt->blend_shapes[i + 2]; + bool erase = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error); if (erase) { - if (!prev_erased) { - first_erased = t1; - prev_erased = true; - } - - tt->blend_shapes.remove_at(i); - i--; - + tt->blend_shapes.remove_at(i + 1); } else { - prev_erased = false; + i++; + } + } + + if (tt->blend_shapes.size() == 2) { + if (abs(tt->blend_shapes[0].value - tt->blend_shapes[1].value) < p_allowed_precision_error) { + tt->blend_shapes.remove_at(1); } } } -void Animation::optimize(real_t p_allowed_linear_err, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) { +void Animation::optimize(real_t p_allowed_velocity_err, real_t p_allowed_angular_err, int p_precision) { + real_t precision = Math::pow(0.1, p_precision); for (int i = 0; i < tracks.size(); i++) { if (track_is_compressed(i)) { continue; //not possible to optimize compressed track } if (tracks[i]->type == TYPE_POSITION_3D) { - _position_track_optimize(i, p_allowed_linear_err, p_allowed_angular_err); + _position_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision); } else if (tracks[i]->type == TYPE_ROTATION_3D) { - _rotation_track_optimize(i, p_allowed_angular_err, p_max_optimizable_angle); + _rotation_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision); } else if (tracks[i]->type == TYPE_SCALE_3D) { - _scale_track_optimize(i, p_allowed_linear_err); + _scale_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision); } else if (tracks[i]->type == TYPE_BLEND_SHAPE) { - _blend_shape_track_optimize(i, p_allowed_linear_err); + _blend_shape_track_optimize(i, p_allowed_velocity_err, precision); } } } diff --git a/scene/resources/animation.h b/scene/resources/animation.h index bf9f786a0d..367134b94c 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -56,7 +56,8 @@ public: enum InterpolationType { INTERPOLATION_NEAREST, INTERPOLATION_LINEAR, - INTERPOLATION_CUBIC + INTERPOLATION_CUBIC, + INTERPOLATION_CUBIC_IN_TIME, }; enum UpdateMode { @@ -231,6 +232,11 @@ private: _FORCE_INLINE_ Variant _cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c) const; _FORCE_INLINE_ real_t _cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c) const; + _FORCE_INLINE_ Vector3 _cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; + _FORCE_INLINE_ Quaternion _cubic_interpolate_in_time(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; + _FORCE_INLINE_ Variant _cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; + _FORCE_INLINE_ real_t _cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; + template <class T> _FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward = false) const; @@ -351,15 +357,14 @@ private: return idxr; } - bool _position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_alowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm); - bool _rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle); - bool _scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error); - bool _blend_shape_track_optimize_key(const TKey<float> &t0, const TKey<float> &t1, const TKey<float> &t2, real_t p_allowed_unit_error); + bool _vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<Vector3> t1, const TKey<Vector3> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); + bool _quaternion_track_optimize_key(const TKey<Quaternion> t0, const TKey<Quaternion> t1, const TKey<Quaternion> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); + bool _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); - void _position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err); - void _rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle); - void _scale_track_optimize(int p_idx, real_t p_allowed_linear_err); - void _blend_shape_track_optimize(int p_idx, real_t p_allowed_unit_error); + void _position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error); + void _rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); + void _scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error); + void _blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_precision_error); protected: bool _set(const StringName &p_name, const Variant &p_value); @@ -475,7 +480,7 @@ public: void clear(); - void optimize(real_t p_allowed_linear_err = 0.05, real_t p_allowed_angular_err = 0.01, real_t p_max_optimizable_angle = Math_PI * 0.125); + void optimize(real_t p_allowed_velocity_err = 0.01, real_t p_allowed_angular_err = 0.01, int p_precision = 3); void compress(uint32_t p_page_size = 8192, uint32_t p_fps = 120, float p_split_tolerance = 4.0); // 4.0 seems to be the split tolerance sweet spot from many tests Animation(); diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp index aff917b2d4..f4697a09b8 100644 --- a/scene/resources/bone_map.cpp +++ b/scene/resources/bone_map.cpp @@ -167,7 +167,7 @@ void BoneMap::_bind_methods() { ADD_SIGNAL(MethodInfo("profile_updated")); } -void BoneMap::_validate_property(PropertyInfo &property) const { +void BoneMap::_validate_property(PropertyInfo &p_property) const { // } diff --git a/scene/resources/bone_map.h b/scene/resources/bone_map.h index 17452dfc73..e1bb571df9 100644 --- a/scene/resources/bone_map.h +++ b/scene/resources/bone_map.h @@ -45,7 +45,7 @@ class BoneMap : public Resource { protected: bool _get(const StringName &p_path, Variant &r_ret) const; bool _set(const StringName &p_path, const Variant &p_value); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _get_property_list(List<PropertyInfo> *p_list) const; static void _bind_methods(); diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp index 97617adbae..0b11366591 100644 --- a/scene/resources/camera_effects.cpp +++ b/scene/resources/camera_effects.cpp @@ -145,11 +145,11 @@ void CameraEffects::_update_override_exposure() { // Private methods, constructor and destructor -void CameraEffects::_validate_property(PropertyInfo &property) const { - if ((!dof_blur_far_enabled && (property.name == "dof_blur_far_distance" || property.name == "dof_blur_far_transition")) || - (!dof_blur_near_enabled && (property.name == "dof_blur_near_distance" || property.name == "dof_blur_near_transition")) || - (!override_exposure_enabled && property.name == "override_exposure")) { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void CameraEffects::_validate_property(PropertyInfo &p_property) const { + if ((!dof_blur_far_enabled && (p_property.name == "dof_blur_far_distance" || p_property.name == "dof_blur_far_transition")) || + (!dof_blur_near_enabled && (p_property.name == "dof_blur_near_distance" || p_property.name == "dof_blur_near_transition")) || + (!override_exposure_enabled && p_property.name == "override_exposure")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/resources/camera_effects.h b/scene/resources/camera_effects.h index 85ae64cdf5..7353931d16 100644 --- a/scene/resources/camera_effects.h +++ b/scene/resources/camera_effects.h @@ -59,7 +59,7 @@ private: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: virtual RID get_rid() const override; diff --git a/scene/resources/canvas_item_material.cpp b/scene/resources/canvas_item_material.cpp index aa6cc4aded..b16059c218 100644 --- a/scene/resources/canvas_item_material.cpp +++ b/scene/resources/canvas_item_material.cpp @@ -227,9 +227,9 @@ bool CanvasItemMaterial::get_particles_anim_loop() const { return particles_anim_loop; } -void CanvasItemMaterial::_validate_property(PropertyInfo &property) const { - if (property.name.begins_with("particles_anim_") && !particles_animation) { - property.usage = PROPERTY_USAGE_NONE; +void CanvasItemMaterial::_validate_property(PropertyInfo &p_property) const { + if (p_property.name.begins_with("particles_anim_") && !particles_animation) { + p_property.usage = PROPERTY_USAGE_NONE; } } diff --git a/scene/resources/canvas_item_material.h b/scene/resources/canvas_item_material.h index 160c67d6b1..7eaf5051d4 100644 --- a/scene/resources/canvas_item_material.h +++ b/scene/resources/canvas_item_material.h @@ -117,7 +117,7 @@ private: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_blend_mode(BlendMode p_blend_mode); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index d361b34da8..f7a7818b3b 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -1037,46 +1037,46 @@ void Environment::_update_adjustment() { // Private methods, constructor and destructor -void Environment::_validate_property(PropertyInfo &property) const { - if (property.name == "sky" || property.name == "sky_custom_fov" || property.name == "sky_rotation" || property.name == "ambient_light/sky_contribution") { +void Environment::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "sky" || p_property.name == "sky_custom_fov" || p_property.name == "sky_rotation" || p_property.name == "ambient_light_sky_contribution") { if (bg_mode != BG_SKY && ambient_source != AMBIENT_SOURCE_SKY && reflection_source != REFLECTION_SOURCE_SKY) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - if (property.name == "fog_aerial_perspective") { + if (p_property.name == "fog_aerial_perspective") { if (bg_mode != BG_SKY) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - if (property.name == "tonemap_white" && tone_mapper == TONE_MAPPER_LINEAR) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name == "tonemap_white" && tone_mapper == TONE_MAPPER_LINEAR) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (property.name == "background_color") { + if (p_property.name == "background_color") { if (bg_mode != BG_COLOR && ambient_source != AMBIENT_SOURCE_COLOR) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - if (property.name == "background_canvas_max_layer") { + if (p_property.name == "background_canvas_max_layer") { if (bg_mode != BG_CANVAS) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } - if (property.name == "background_camera_feed_id") { + if (p_property.name == "background_camera_feed_id") { if (bg_mode != BG_CAMERA_FEED) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } @@ -1107,8 +1107,8 @@ void Environment::_validate_property(PropertyInfo &property) const { String prefix = String(*prefixes); String enabled = prefix + "enabled"; - if (property.name.begins_with(prefix) && property.name != enabled && !bool(get(enabled))) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name.begins_with(prefix) && p_property.name != enabled && !bool(get(enabled))) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; return; } @@ -1120,8 +1120,8 @@ void Environment::_validate_property(PropertyInfo &property) const { while (*prefixes) { String prefix = String(*prefixes); - if (property.name.begins_with(prefix)) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name.begins_with(prefix)) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; return; } diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 385d815230..d39cb1acd8 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -211,7 +211,7 @@ private: protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; #ifndef DISABLE_DEPRECATED // Kept for compatibility from 3.x to 4.0. bool _set(const StringName &p_name, const Variant &p_value); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 5d887dae17..bd0e470112 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -71,12 +71,12 @@ RID Material::get_rid() const { return material; } -void Material::_validate_property(PropertyInfo &property) const { - if (!_can_do_next_pass() && property.name == "next_pass") { - property.usage = PROPERTY_USAGE_NONE; +void Material::_validate_property(PropertyInfo &p_property) const { + if (!_can_do_next_pass() && p_property.name == "next_pass") { + p_property.usage = PROPERTY_USAGE_NONE; } - if (!_can_use_render_priority() && property.name == "render_priority") { - property.usage = PROPERTY_USAGE_NONE; + if (!_can_use_render_priority() && p_property.name == "render_priority") { + p_property.usage = PROPERTY_USAGE_NONE; } } @@ -1867,61 +1867,61 @@ void BaseMaterial3D::_validate_high_end(const String &text, PropertyInfo &proper } } -void BaseMaterial3D::_validate_property(PropertyInfo &property) const { - _validate_feature("normal", FEATURE_NORMAL_MAPPING, property); - _validate_feature("emission", FEATURE_EMISSION, property); - _validate_feature("rim", FEATURE_RIM, property); - _validate_feature("clearcoat", FEATURE_CLEARCOAT, property); - _validate_feature("anisotropy", FEATURE_ANISOTROPY, property); - _validate_feature("ao", FEATURE_AMBIENT_OCCLUSION, property); - _validate_feature("heightmap", FEATURE_HEIGHT_MAPPING, property); - _validate_feature("subsurf_scatter", FEATURE_SUBSURFACE_SCATTERING, property); - _validate_feature("backlight", FEATURE_BACKLIGHT, property); - _validate_feature("refraction", FEATURE_REFRACTION, property); - _validate_feature("detail", FEATURE_DETAIL, property); +void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const { + _validate_feature("normal", FEATURE_NORMAL_MAPPING, p_property); + _validate_feature("emission", FEATURE_EMISSION, p_property); + _validate_feature("rim", FEATURE_RIM, p_property); + _validate_feature("clearcoat", FEATURE_CLEARCOAT, p_property); + _validate_feature("anisotropy", FEATURE_ANISOTROPY, p_property); + _validate_feature("ao", FEATURE_AMBIENT_OCCLUSION, p_property); + _validate_feature("heightmap", FEATURE_HEIGHT_MAPPING, p_property); + _validate_feature("subsurf_scatter", FEATURE_SUBSURFACE_SCATTERING, p_property); + _validate_feature("backlight", FEATURE_BACKLIGHT, p_property); + _validate_feature("refraction", FEATURE_REFRACTION, p_property); + _validate_feature("detail", FEATURE_DETAIL, p_property); - _validate_high_end("refraction", property); - _validate_high_end("subsurf_scatter", property); - _validate_high_end("heightmap", property); + _validate_high_end("refraction", p_property); + _validate_high_end("subsurf_scatter", p_property); + _validate_high_end("heightmap", p_property); - if (property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (p_property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (property.name == "grow_amount" && !grow_enabled) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (p_property.name == "grow_amount" && !grow_enabled) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (property.name == "point_size" && !flags[FLAG_USE_POINT_SIZE]) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (p_property.name == "point_size" && !flags[FLAG_USE_POINT_SIZE]) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (property.name == "proximity_fade_distance" && !proximity_fade_enabled) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (p_property.name == "proximity_fade_distance" && !proximity_fade_enabled) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (property.name == "msdf_pixel_range" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (p_property.name == "msdf_pixel_range" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (property.name == "msdf_outline_size" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (p_property.name == "msdf_outline_size" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if ((p_property.name == "distance_fade_max_distance" || p_property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if ((property.name == "uv1_triplanar_sharpness" || property.name == "uv1_world_triplanar") && !flags[FLAG_UV1_USE_TRIPLANAR]) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if ((p_property.name == "uv1_triplanar_sharpness" || p_property.name == "uv1_world_triplanar") && !flags[FLAG_UV1_USE_TRIPLANAR]) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if ((property.name == "uv2_triplanar_sharpness" || property.name == "uv2_world_triplanar") && !flags[FLAG_UV2_USE_TRIPLANAR]) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if ((p_property.name == "uv2_triplanar_sharpness" || p_property.name == "uv2_world_triplanar") && !flags[FLAG_UV2_USE_TRIPLANAR]) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } // you can only enable anti-aliasing (in materials) on alpha scissor and alpha hash @@ -1930,96 +1930,96 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { const bool alpha_aa_enabled = (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) && can_select_aa; // alpha scissor slider isn't needed when alpha antialiasing is enabled - if (property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) { + p_property.usage = PROPERTY_USAGE_NONE; } // alpha hash scale slider is only needed if transparency is alpha hash - if (property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "alpha_antialiasing_mode" && !can_select_aa) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "alpha_antialiasing_mode" && !can_select_aa) { + p_property.usage = PROPERTY_USAGE_NONE; } // we can't choose an antialiasing mode if alpha isn't possible - if (property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "blend_mode" && alpha_aa_enabled) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "blend_mode" && alpha_aa_enabled) { + p_property.usage = PROPERTY_USAGE_NONE; } - if ((property.name == "heightmap_min_layers" || property.name == "heightmap_max_layers") && !deep_parallax) { - property.usage = PROPERTY_USAGE_NONE; + if ((p_property.name == "heightmap_min_layers" || p_property.name == "heightmap_max_layers") && !deep_parallax) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (property.name == "subsurf_scatter_transmittance_color" || property.name == "subsurf_scatter_transmittance_texture")) { - property.usage = PROPERTY_USAGE_NONE; + if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (p_property.name == "subsurf_scatter_transmittance_color" || p_property.name == "subsurf_scatter_transmittance_texture")) { + p_property.usage = PROPERTY_USAGE_NONE; } if (orm) { - if (property.name == "shading_mode") { + if (p_property.name == "shading_mode") { // Vertex not supported in ORM mode, since no individual roughness. - property.hint_string = "Unshaded,Per-Pixel"; + p_property.hint_string = "Unshaded,Per-Pixel"; } - if (property.name.begins_with("roughness") || property.name.begins_with("metallic") || property.name.begins_with("ao_texture")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("roughness") || p_property.name.begins_with("metallic") || p_property.name.begins_with("ao_texture")) { + p_property.usage = PROPERTY_USAGE_NONE; } } else { - if (property.name == "orm_texture") { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "orm_texture") { + p_property.usage = PROPERTY_USAGE_NONE; } } if (shading_mode != SHADING_MODE_PER_PIXEL) { if (shading_mode != SHADING_MODE_PER_VERTEX) { //these may still work per vertex - if (property.name.begins_with("ao")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("ao")) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("emission")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("emission")) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("metallic")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("metallic")) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("rim")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("rim")) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("roughness")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("roughness")) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("subsurf_scatter")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("subsurf_scatter")) { + p_property.usage = PROPERTY_USAGE_NONE; } } //these definitely only need per pixel - if (property.name.begins_with("anisotropy")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("anisotropy")) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("clearcoat")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("clearcoat")) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("normal")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("normal")) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("backlight")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("backlight")) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("transmittance")) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("transmittance")) { + p_property.usage = PROPERTY_USAGE_NONE; } } } @@ -2052,8 +2052,9 @@ Vector3 BaseMaterial3D::get_uv1_offset() const { } void BaseMaterial3D::set_uv1_triplanar_blend_sharpness(float p_sharpness) { - uv1_triplanar_sharpness = p_sharpness; - RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, p_sharpness); + // Negative values or values higher than 150 can result in NaNs, leading to broken rendering. + uv1_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0); + RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, uv1_triplanar_sharpness); } float BaseMaterial3D::get_uv1_triplanar_blend_sharpness() const { @@ -2079,8 +2080,9 @@ Vector3 BaseMaterial3D::get_uv2_offset() const { } void BaseMaterial3D::set_uv2_triplanar_blend_sharpness(float p_sharpness) { - uv2_triplanar_sharpness = p_sharpness; - RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, p_sharpness); + // Negative values or values higher than 150 can result in NaNs, leading to broken rendering. + uv2_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0); + RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, uv2_triplanar_sharpness); } float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const { diff --git a/scene/resources/material.h b/scene/resources/material.h index 6049671582..c6be1b8766 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -54,7 +54,7 @@ protected: virtual bool _can_do_next_pass() const; virtual bool _can_use_render_priority() const; - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; GDVIRTUAL0RC(RID, _get_shader_rid) GDVIRTUAL0RC(Shader::Mode, _get_shader_mode) @@ -553,7 +553,7 @@ private: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; virtual bool _can_do_next_pass() const override { return true; } virtual bool _can_use_render_priority() const override { return true; } diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 3f73df2e5d..1f75d4a323 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -32,11 +32,10 @@ #include "core/math/convex_hull.h" #include "core/templates/pair.h" +#include "scene/resources/surface_tool.h" + #include "scene/resources/concave_polygon_shape_3d.h" #include "scene/resources/convex_polygon_shape_3d.h" -#include "surface_tool.h" - -#include <stdlib.h> Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr; @@ -866,27 +865,6 @@ static Mesh::PrimitiveType _old_primitives[7] = { }; #endif // DISABLE_DEPRECATED -// Convert Octahedron-mapped normalized vector back to Cartesian -// Assumes normalized format (elements of v within range [-1, 1]) -Vector3 _oct_to_norm(const Vector2 v) { - Vector3 res(v.x, v.y, 1 - (Math::absf(v.x) + Math::absf(v.y))); - float t = MAX(-res.z, 0.0f); - res.x += t * -SIGN(res.x); - res.y += t * -SIGN(res.y); - return res.normalized(); -} - -// Convert Octahedron-mapped normalized tangent vector back to Cartesian -// out_sign provides the direction for the original cartesian tangent -// Assumes normalized format (elements of v within range [-1, 1]) -Vector3 _oct_to_tangent(const Vector2 v, float *out_sign) { - Vector2 v_decompressed = v; - v_decompressed.y = Math::absf(v_decompressed.y) * 2 - 1; - Vector3 res = _oct_to_norm(v_decompressed); - *out_sign = SIGN(v[1]); - return res; -} - void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_format, uint32_t p_new_format, uint32_t p_elements, Vector<uint8_t> &vertex_data, Vector<uint8_t> &attribute_data, Vector<uint8_t> &skin_data) { uint32_t dst_vertex_stride; uint32_t dst_attribute_stride; @@ -957,127 +935,93 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma if ((p_old_format & OLD_ARRAY_COMPRESS_NORMAL) && (p_old_format & OLD_ARRAY_FORMAT_TANGENT) && (p_old_format & OLD_ARRAY_COMPRESS_TANGENT)) { for (uint32_t i = 0; i < p_elements; i++) { const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; - const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f); - - const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); - *dst = 0; - *dst |= CLAMP(int(res.x * 1023.0f), 0, 1023); - *dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10; - *dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20; + int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + + dst[0] = (int16_t)CLAMP(src[0] / 127.0f * 32767, -32768, 32767); + dst[1] = (int16_t)CLAMP(src[1] / 127.0f * 32767, -32768, 32767); } - src_offset += sizeof(int8_t) * 2; + src_offset += sizeof(int16_t) * 2; } else { for (uint32_t i = 0; i < p_elements; i++) { const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; - const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f); - - const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); - *dst = 0; - *dst |= CLAMP(int(res.x * 1023.0f), 0, 1023); - *dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10; - *dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20; + int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + + dst[0] = src[0]; + dst[1] = src[1]; } src_offset += sizeof(int16_t) * 2; } } else { // No Octahedral compression if (p_old_format & OLD_ARRAY_COMPRESS_NORMAL) { - const float multiplier = 1.f / 127.f * 1023.0f; - for (uint32_t i = 0; i < p_elements; i++) { const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + const Vector3 original_normal(src[0], src[1], src[2]); + Vector2 res = original_normal.octahedron_encode(); - *dst = 0; - *dst |= CLAMP(int(src[0] * multiplier), 0, 1023); - *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10; - *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535); + dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535); } - src_offset += sizeof(uint32_t); + src_offset += sizeof(uint16_t) * 2; } else { for (uint32_t i = 0; i < p_elements; i++) { const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + const Vector3 original_normal(src[0], src[1], src[2]); + Vector2 res = original_normal.octahedron_encode(); - *dst = 0; - *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023); - *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10; - *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535); + dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535); } - src_offset += sizeof(float) * 3; + src_offset += sizeof(uint16_t) * 2; } } } break; case OLD_ARRAY_TANGENT: { if (p_old_format & OLD_ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) { - if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8 + if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8 SNORM -> uint16 UNORM for (uint32_t i = 0; i < p_elements; i++) { const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; - const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f); - float out_sign; - const Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); - - *dst = 0; - *dst |= CLAMP(int(res.x * 1023.0), 0, 1023); - *dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10; - *dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20; - if (out_sign > 0) { - *dst |= 3 << 30; - } + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + + dst[0] = (uint16_t)CLAMP((src[0] / 127.0f * .5f + .5f) * 65535, 0, 65535); + dst[1] = (uint16_t)CLAMP((src[1] / 127.0f * .5f + .5f) * 65535, 0, 65535); } - src_offset += sizeof(int8_t) * 2; - } else { // int16 + src_offset += sizeof(uint16_t) * 2; + } else { // int16 SNORM -> uint16 UNORM for (uint32_t i = 0; i < p_elements; i++) { const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; - const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f); - float out_sign; - Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); - - *dst = 0; - *dst |= CLAMP(int(res.x * 1023.0), 0, 1023); - *dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10; - *dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20; - if (out_sign > 0) { - *dst |= 3 << 30; - } + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + + dst[0] = (uint16_t)CLAMP((src[0] / 32767.0f * .5f + .5f) * 65535, 0, 65535); + dst[1] = (uint16_t)CLAMP((src[1] / 32767.0f * .5f + .5f) * 65535, 0, 65535); } - src_offset += sizeof(int16_t) * 2; + src_offset += sizeof(uint16_t) * 2; } } else { // No Octahedral compression if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { - const float multiplier = 1.f / 127.f * 1023.0f; - for (uint32_t i = 0; i < p_elements; i++) { const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; - - *dst = 0; - *dst |= CLAMP(int(src[0] * multiplier), 0, 1023); - *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10; - *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20; - if (src[3] > 0) { - *dst |= 3 << 30; - } + const Vector3 original_tangent(src[0], src[1], src[2]); + Vector2 res = original_tangent.octahedron_tangent_encode(src[3]); + + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535); + dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535); } - src_offset += sizeof(uint32_t); + src_offset += sizeof(uint16_t) * 2; } else { for (uint32_t i = 0; i < p_elements; i++) { const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; - - *dst = 0; - *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023); - *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10; - *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20; - if (src[3] > 0) { - *dst |= 3 << 30; - } + const Vector3 original_tangent(src[0], src[1], src[2]); + Vector2 res = original_tangent.octahedron_tangent_encode(src[3]); + + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535); + dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535); } - src_offset += sizeof(float) * 4; + src_offset += sizeof(uint16_t) * 2; } } } break; diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 63dbda92d0..491a383416 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -169,9 +169,6 @@ public: void generate_debug_mesh_lines(Vector<Vector3> &r_lines); void generate_debug_mesh_indices(Vector<Vector3> &r_points); - Ref<Shape3D> create_trimesh_shape() const; - Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const; - Ref<Mesh> create_outline(float p_margin) const; void set_lightmap_size_hint(const Size2i &p_size); @@ -214,6 +211,8 @@ public: static ConvexDecompositionFunc convex_decomposition_function; Vector<Ref<Shape3D>> convex_decompose(const ConvexDecompositionSettings &p_settings) const; + Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const; + Ref<Shape3D> create_trimesh_shape() const; virtual int get_builtin_bind_pose_count() const; virtual Transform3D get_builtin_bind_pose(int p_index) const; diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h index 4105bd6960..79acb41c4e 100644 --- a/scene/resources/mesh_library.h +++ b/scene/resources/mesh_library.h @@ -33,8 +33,8 @@ #include "core/io/resource.h" #include "core/templates/rb_map.h" -#include "mesh.h" #include "scene/3d/navigation_region_3d.h" +#include "scene/resources/mesh.h" #include "shape_3d.h" class MeshLibrary : public Resource { diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index ac5493efdc..6c9c8ffdba 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -614,8 +614,10 @@ void NavigationMesh::_bind_methods() { ADD_GROUP("Geometry", "geometry_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type"); ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY_DEFAULT("geometry_collision_mask", 0xFFFFFFFF); ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "NavMesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry_source_group_name"), "set_source_group_name", "get_source_group_name"); + ADD_PROPERTY_DEFAULT("geometry_source_group_name", StringName("navmesh")); ADD_GROUP("Cells", "cell_"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_size", "get_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_height", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_height", "get_cell_height"); @@ -658,17 +660,17 @@ void NavigationMesh::_bind_methods() { BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_MAX); } -void NavigationMesh::_validate_property(PropertyInfo &property) const { - if (property.name == "geometry/collision_mask") { +void NavigationMesh::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "geometry_collision_mask") { if (parsed_geometry_type == PARSED_GEOMETRY_MESH_INSTANCES) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; return; } } - if (property.name == "geometry/source_group_name") { + if (p_property.name == "geometry_source_group_name") { if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; return; } } diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h index 79d8962d24..c66025dc6d 100644 --- a/scene/resources/navigation_mesh.h +++ b/scene/resources/navigation_mesh.h @@ -33,8 +33,6 @@ #include "scene/resources/mesh.h" -class Mesh; - class NavigationMesh : public Resource { GDCLASS(NavigationMesh, Resource); @@ -60,7 +58,7 @@ class NavigationMesh : public Resource { protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; #ifndef DISABLE_DEPRECATED bool _set(const StringName &p_name, const Variant &p_value); diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index 4b2e029f47..0fe5c8f2db 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -1386,54 +1386,54 @@ RID ParticlesMaterial::get_shader_rid() const { return shader_map[current_key].shader; } -void ParticlesMaterial::_validate_property(PropertyInfo &property) const { - if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { - property.usage = PROPERTY_USAGE_NONE; +void ParticlesMaterial::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { + p_property.usage = PROPERTY_USAGE_NONE; } - if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { - property.usage = PROPERTY_USAGE_NONE; + if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture") && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { + p_property.usage = PROPERTY_USAGE_NONE; } if (!turbulence_enabled) { - if (property.name == "turbulence_noise_strength" || - property.name == "turbulence_noise_scale" || - property.name == "turbulence_noise_speed" || - property.name == "turbulence_noise_speed_random" || - property.name == "turbulence_influence_over_life" || - property.name == "turbulence_influence_min" || - property.name == "turbulence_influence_max" || - property.name == "turbulence_initial_displacement_min" || - property.name == "turbulence_initial_displacement_max") { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (p_property.name == "turbulence_noise_strength" || + p_property.name == "turbulence_noise_scale" || + p_property.name == "turbulence_noise_speed" || + p_property.name == "turbulence_noise_speed_random" || + p_property.name == "turbulence_influence_over_life" || + p_property.name == "turbulence_influence_min" || + p_property.name == "turbulence_influence_max" || + p_property.name == "turbulence_initial_displacement_min" || + p_property.name == "turbulence_initial_displacement_max") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } } diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h index 7fb46d6ac5..116d8b7d06 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particles_material.h @@ -307,7 +307,7 @@ private: protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_direction(Vector3 p_direction); diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp index bfb4bb6e2b..875d2dcff7 100644 --- a/scene/resources/skeleton_profile.cpp +++ b/scene/resources/skeleton_profile.cpp @@ -121,26 +121,26 @@ bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const { return true; } -void SkeletonProfile::_validate_property(PropertyInfo &property) const { +void SkeletonProfile::_validate_property(PropertyInfo &p_property) const { if (is_read_only) { - if (property.name == ("group_size") || property.name == ("bone_size") || property.name == ("root_bone") || property.name == ("scale_base_bone")) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (p_property.name == ("group_size") || p_property.name == ("bone_size") || p_property.name == ("root_bone") || p_property.name == ("scale_base_bone")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; return; } } - if (property.name == ("root_bone") || property.name == ("scale_base_bone")) { + if (p_property.name == ("root_bone") || p_property.name == ("scale_base_bone")) { String hint = ""; for (int i = 0; i < bones.size(); i++) { hint += i == 0 ? String(bones[i].bone_name) : "," + String(bones[i].bone_name); } - property.hint_string = hint; + p_property.hint_string = hint; } - PackedStringArray split = property.name.split("/"); + PackedStringArray split = p_property.name.split("/"); if (split.size() == 3 && split[0] == "bones") { if (split[2] == "bone_tail" && get_tail_direction(split[1].to_int()) != TAIL_DIRECTION_SPECIFIC_CHILD) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } } diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h index 84dfca458e..66344d954d 100644 --- a/scene/resources/skeleton_profile.h +++ b/scene/resources/skeleton_profile.h @@ -72,7 +72,7 @@ protected: bool _get(const StringName &p_path, Variant &r_ret) const; bool _set(const StringName &p_path, const Variant &p_value); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _get_property_list(List<PropertyInfo> *p_list) const; static void _bind_methods(); diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index a53c299d00..ff5210f1b3 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -842,9 +842,9 @@ float StyleBoxFlat::get_style_margin(Side p_side) const { return border_width[p_side]; } -void StyleBoxFlat::_validate_property(PropertyInfo &property) const { - if (!anti_aliased && property.name == "anti_aliasing_size") { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void StyleBoxFlat::_validate_property(PropertyInfo &p_property) const { + if (!anti_aliased && p_property.name == "anti_aliasing_size") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 9f4f69d3ba..88db4f5fbd 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -166,7 +166,7 @@ class StyleBoxFlat : public StyleBox { protected: virtual float get_style_margin(Side p_side) const override; static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_bg_color(const Color &p_color); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index e5c4974967..25f5006c4f 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -35,8 +35,8 @@ #include "core/io/marshalls.h" #include "core/math/geometry_2d.h" #include "core/os/os.h" -#include "mesh.h" #include "scene/resources/bit_map.h" +#include "scene/resources/mesh.h" #include "servers/camera/camera_feed.h" int Texture2D::get_width() const { int ret; @@ -1038,7 +1038,7 @@ void CompressedTexture2D::reload_from_file() { load(path); } -void CompressedTexture2D::_validate_property(PropertyInfo &property) const { +void CompressedTexture2D::_validate_property(PropertyInfo &p_property) const { } void CompressedTexture2D::_bind_methods() { @@ -1394,7 +1394,7 @@ void CompressedTexture3D::reload_from_file() { load(path); } -void CompressedTexture3D::_validate_property(PropertyInfo &property) const { +void CompressedTexture3D::_validate_property(PropertyInfo &p_property) const { } void CompressedTexture3D::_bind_methods() { @@ -2789,12 +2789,12 @@ bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const { return true; } -void AnimatedTexture::_validate_property(PropertyInfo &property) const { - String prop = property.name; +void AnimatedTexture::_validate_property(PropertyInfo &p_property) const { + String prop = p_property.name; if (prop.begins_with("frame_")) { int frame = prop.get_slicec('/', 0).get_slicec('_', 1).to_int(); if (frame >= frame_count) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } } @@ -3214,7 +3214,7 @@ void CompressedTextureLayered::reload_from_file() { load(path); } -void CompressedTextureLayered::_validate_property(PropertyInfo &property) const { +void CompressedTextureLayered::_validate_property(PropertyInfo &p_property) const { } void CompressedTextureLayered::_bind_methods() { diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 7c5624bd09..133b312d27 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -251,7 +251,7 @@ private: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: static Ref<Image> load_image_from_file(Ref<FileAccess> p_file, int p_size_limit); @@ -506,7 +506,7 @@ private: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: Image::Format get_format() const override; @@ -651,7 +651,7 @@ private: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: Image::Format get_format() const override; @@ -940,7 +940,7 @@ private: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_frames(int p_frames); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index b0b9f1228f..552d856034 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -3302,11 +3302,11 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { } } -void TileSet::_validate_property(PropertyInfo &property) const { - if (property.name == "tile_layout" && tile_shape == TILE_SHAPE_SQUARE) { - property.usage ^= PROPERTY_USAGE_READ_ONLY; - } else if (property.name == "tile_offset_axis" && tile_shape == TILE_SHAPE_SQUARE) { - property.usage ^= PROPERTY_USAGE_READ_ONLY; +void TileSet::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "tile_layout" && tile_shape == TILE_SHAPE_SQUARE) { + p_property.usage ^= PROPERTY_USAGE_READ_ONLY; + } else if (p_property.name == "tile_offset_axis" && tile_shape == TILE_SHAPE_SQUARE) { + p_property.usage ^= PROPERTY_USAGE_READ_ONLY; } } diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 6ea3889fce..4c0823cdf2 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -295,7 +295,7 @@ protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; private: // --- TileSet data --- diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index fa24a95115..0180b2ffcf 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -3153,8 +3153,8 @@ String VisualShaderNodeInput::get_input_index_name(int p_index) const { return ""; } -void VisualShaderNodeInput::_validate_property(PropertyInfo &property) const { - if (property.name == "input_name") { +void VisualShaderNodeInput::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "input_name") { String port_list; int idx = 0; @@ -3172,7 +3172,7 @@ void VisualShaderNodeInput::_validate_property(PropertyInfo &property) const { if (port_list.is_empty()) { port_list = RTR("None"); } - property.hint_string = port_list; + p_property.hint_string = port_list; } } diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 7ca4e5fc4a..527588b6e6 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -428,7 +428,7 @@ public: protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: virtual int get_input_port_count() const override; diff --git a/servers/audio/effects/audio_effect_chorus.cpp b/servers/audio/effects/audio_effect_chorus.cpp index e5434eac02..54c08ef644 100644 --- a/servers/audio/effects/audio_effect_chorus.cpp +++ b/servers/audio/effects/audio_effect_chorus.cpp @@ -272,11 +272,11 @@ float AudioEffectChorus::get_dry() const { return dry; } -void AudioEffectChorus::_validate_property(PropertyInfo &property) const { - if (property.name.begins_with("voice/")) { - int voice_idx = property.name.get_slice("/", 1).to_int(); +void AudioEffectChorus::_validate_property(PropertyInfo &p_property) const { + if (p_property.name.begins_with("voice/")) { + int voice_idx = p_property.name.get_slice("/", 1).to_int(); if (voice_idx > voice_count) { - property.usage = PROPERTY_USAGE_NONE; + p_property.usage = PROPERTY_USAGE_NONE; } } } diff --git a/servers/audio/effects/audio_effect_chorus.h b/servers/audio/effects/audio_effect_chorus.h index 72b495f7f9..dd4b431e7a 100644 --- a/servers/audio/effects/audio_effect_chorus.h +++ b/servers/audio/effects/audio_effect_chorus.h @@ -96,7 +96,7 @@ private: float dry; protected: - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); diff --git a/servers/audio/effects/audio_effect_compressor.cpp b/servers/audio/effects/audio_effect_compressor.cpp index ee71a6dba7..0e1accba16 100644 --- a/servers/audio/effects/audio_effect_compressor.cpp +++ b/servers/audio/effects/audio_effect_compressor.cpp @@ -184,15 +184,15 @@ StringName AudioEffectCompressor::get_sidechain() const { return sidechain; } -void AudioEffectCompressor::_validate_property(PropertyInfo &property) const { - if (property.name == "sidechain") { +void AudioEffectCompressor::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "sidechain") { String buses = ""; for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { buses += ","; buses += AudioServer::get_singleton()->get_bus_name(i); } - property.hint_string = buses; + p_property.hint_string = buses; } } diff --git a/servers/audio/effects/audio_effect_compressor.h b/servers/audio/effects/audio_effect_compressor.h index 998bd3c978..886255b958 100644 --- a/servers/audio/effects/audio_effect_compressor.h +++ b/servers/audio/effects/audio_effect_compressor.h @@ -61,7 +61,7 @@ class AudioEffectCompressor : public AudioEffect { StringName sidechain; protected: - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: diff --git a/servers/audio/effects/audio_effect_filter.h b/servers/audio/effects/audio_effect_filter.h index a40af2f13c..1510ee2af7 100644 --- a/servers/audio/effects/audio_effect_filter.h +++ b/servers/audio/effects/audio_effect_filter.h @@ -98,9 +98,9 @@ VARIANT_ENUM_CAST(AudioEffectFilter::FilterDB) class AudioEffectLowPassFilter : public AudioEffectFilter { GDCLASS(AudioEffectLowPassFilter, AudioEffectFilter); - void _validate_property(PropertyInfo &property) const override { - if (property.name == "gain") { - property.usage = PROPERTY_USAGE_NONE; + void _validate_property(PropertyInfo &p_property) const { + if (p_property.name == "gain") { + p_property.usage = PROPERTY_USAGE_NONE; } } @@ -111,9 +111,9 @@ public: class AudioEffectHighPassFilter : public AudioEffectFilter { GDCLASS(AudioEffectHighPassFilter, AudioEffectFilter); - void _validate_property(PropertyInfo &property) const override { - if (property.name == "gain") { - property.usage = PROPERTY_USAGE_NONE; + void _validate_property(PropertyInfo &p_property) const { + if (p_property.name == "gain") { + p_property.usage = PROPERTY_USAGE_NONE; } } @@ -124,9 +124,9 @@ public: class AudioEffectBandPassFilter : public AudioEffectFilter { GDCLASS(AudioEffectBandPassFilter, AudioEffectFilter); - void _validate_property(PropertyInfo &property) const override { - if (property.name == "gain") { - property.usage = PROPERTY_USAGE_NONE; + void _validate_property(PropertyInfo &p_property) const { + if (p_property.name == "gain") { + p_property.usage = PROPERTY_USAGE_NONE; } } diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp index 3694dcdb9a..7d797bf611 100644 --- a/servers/extensions/physics_server_3d_extension.cpp +++ b/servers/extensions/physics_server_3d_extension.cpp @@ -196,6 +196,9 @@ void PhysicsServer3DExtension::_bind_methods() { GDVIRTUAL_BIND(_body_set_collision_mask, "body", "mask"); GDVIRTUAL_BIND(_body_get_collision_mask, "body"); + GDVIRTUAL_BIND(_body_set_collision_priority, "body", "priority"); + GDVIRTUAL_BIND(_body_get_collision_priority, "body"); + GDVIRTUAL_BIND(_body_add_shape, "body", "shape", "transform", "disabled"); GDVIRTUAL_BIND(_body_set_shape, "body", "shape_idx", "shape"); GDVIRTUAL_BIND(_body_set_shape_transform, "body", "shape_idx", "transform"); diff --git a/servers/extensions/physics_server_3d_extension.h b/servers/extensions/physics_server_3d_extension.h index c4b4a00eaf..3200438253 100644 --- a/servers/extensions/physics_server_3d_extension.h +++ b/servers/extensions/physics_server_3d_extension.h @@ -319,6 +319,9 @@ public: EXBIND2(body_set_collision_mask, RID, uint32_t) EXBIND1RC(uint32_t, body_get_collision_mask, RID) + EXBIND2(body_set_collision_priority, RID, real_t) + EXBIND1RC(real_t, body_get_collision_priority, RID) + EXBIND2(body_set_user_flags, RID, uint32_t) EXBIND1RC(uint32_t, body_get_user_flags, RID) diff --git a/servers/physics_2d/godot_collision_object_2d.h b/servers/physics_2d/godot_collision_object_2d.h index 1a683a7b0f..7965e8a94d 100644 --- a/servers/physics_2d/godot_collision_object_2d.h +++ b/servers/physics_2d/godot_collision_object_2d.h @@ -70,6 +70,7 @@ private: Transform2D inv_transform; uint32_t collision_mask = 1; uint32_t collision_layer = 1; + real_t collision_priority = 1.0; bool _static = true; SelfList<GodotCollisionObject2D> pending_shape_update_list; @@ -166,6 +167,13 @@ public: } _FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; } + _FORCE_INLINE_ void set_collision_priority(real_t p_priority) { + ERR_FAIL_COND_MSG(p_priority <= 0, "Priority must be greater than 0."); + collision_priority = p_priority; + _shape_changed(); + } + _FORCE_INLINE_ real_t get_collision_priority() const { return collision_priority; } + void remove_shape(GodotShape2D *p_shape) override; void remove_shape(int p_index); diff --git a/servers/physics_2d/godot_physics_server_2d.cpp b/servers/physics_2d/godot_physics_server_2d.cpp index 99e68de07c..c728dccd4f 100644 --- a/servers/physics_2d/godot_physics_server_2d.cpp +++ b/servers/physics_2d/godot_physics_server_2d.cpp @@ -718,6 +718,20 @@ uint32_t GodotPhysicsServer2D::body_get_collision_mask(RID p_body) const { return body->get_collision_mask(); } +void GodotPhysicsServer2D::body_set_collision_priority(RID p_body, real_t p_priority) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_collision_priority(p_priority); +} + +real_t GodotPhysicsServer2D::body_get_collision_priority(RID p_body) const { + const GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_priority(); +} + void GodotPhysicsServer2D::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) { GodotBody2D *body = body_owner.get_or_null(p_body); ERR_FAIL_COND(!body); diff --git a/servers/physics_2d/godot_physics_server_2d.h b/servers/physics_2d/godot_physics_server_2d.h index 2af6e5c97c..20e492d87a 100644 --- a/servers/physics_2d/godot_physics_server_2d.h +++ b/servers/physics_2d/godot_physics_server_2d.h @@ -199,6 +199,9 @@ public: virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override; virtual uint32_t body_get_collision_mask(RID p_body) const override; + virtual void body_set_collision_priority(RID p_body, real_t p_priority) override; + virtual real_t body_get_collision_priority(RID p_body) const override; + virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override; virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override; diff --git a/servers/physics_2d/godot_space_2d.cpp b/servers/physics_2d/godot_space_2d.cpp index 166ec3049e..4166191be8 100644 --- a/servers/physics_2d/godot_space_2d.cpp +++ b/servers/physics_2d/godot_space_2d.cpp @@ -594,6 +594,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: const int max_results = 32; int recover_attempts = 4; Vector2 sr[max_results * 2]; + real_t priorities[max_results]; do { GodotPhysicsServer2D::CollCbkData cbk; @@ -606,6 +607,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: GodotPhysicsServer2D::CollCbkData *cbkptr = &cbk; GodotCollisionSolver2D::CallbackResult cbkres = GodotPhysicsServer2D::_shape_col_cbk; + int priority_amount = 0; bool collided = false; @@ -664,6 +666,10 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: if (GodotCollisionSolver2D::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, margin)) { did_collide = cbk.passed > current_passed; //more passed, so collision actually existed } + while (cbk.amount > priority_amount) { + priorities[priority_amount] = col_obj->get_collision_priority(); + priority_amount++; + } if (!did_collide && cbk.invalid_by_dir > 0) { //this shape must be excluded @@ -686,6 +692,12 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: break; } + real_t inv_total_weight = 0.0; + for (int i = 0; i < cbk.amount; i++) { + inv_total_weight += priorities[i]; + } + inv_total_weight = Math::is_zero_approx(inv_total_weight) ? 1.0 : (real_t)cbk.amount / inv_total_weight; + recovered = true; Vector2 recover_motion; @@ -701,7 +713,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: real_t depth = n.dot(a + recover_motion) - d; if (depth > min_contact_depth + CMP_EPSILON) { // Only recover if there is penetration. - recover_motion -= n * (depth - min_contact_depth) * 0.4; + recover_motion -= n * (depth - min_contact_depth) * 0.4 * priorities[i] * inv_total_weight; } } diff --git a/servers/physics_3d/godot_collision_object_3d.h b/servers/physics_3d/godot_collision_object_3d.h index 0f09f21962..2d342f65f3 100644 --- a/servers/physics_3d/godot_collision_object_3d.h +++ b/servers/physics_3d/godot_collision_object_3d.h @@ -59,6 +59,7 @@ private: ObjectID instance_id; uint32_t collision_layer = 1; uint32_t collision_mask = 1; + real_t collision_priority = 1.0; struct Shape { Transform3D xform; @@ -165,6 +166,13 @@ public: } _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; } + _FORCE_INLINE_ void set_collision_priority(real_t p_priority) { + ERR_FAIL_COND_MSG(p_priority <= 0, "Priority must be greater than 0."); + collision_priority = p_priority; + _shape_changed(); + } + _FORCE_INLINE_ real_t get_collision_priority() const { return collision_priority; } + _FORCE_INLINE_ bool collides_with(GodotCollisionObject3D *p_other) const { return p_other->collision_layer & collision_mask; } diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp index b735283ebe..9c1535f561 100644 --- a/servers/physics_3d/godot_physics_server_3d.cpp +++ b/servers/physics_3d/godot_physics_server_3d.cpp @@ -593,6 +593,20 @@ uint32_t GodotPhysicsServer3D::body_get_collision_mask(RID p_body) const { return body->get_collision_mask(); } +void GodotPhysicsServer3D::body_set_collision_priority(RID p_body, real_t p_priority) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_collision_priority(p_priority); +} + +real_t GodotPhysicsServer3D::body_get_collision_priority(RID p_body) const { + const GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_priority(); +} + void GodotPhysicsServer3D::body_attach_object_instance_id(RID p_body, ObjectID p_id) { GodotBody3D *body = body_owner.get_or_null(p_body); if (body) { diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h index 1d57451925..b429f23a0c 100644 --- a/servers/physics_3d/godot_physics_server_3d.h +++ b/servers/physics_3d/godot_physics_server_3d.h @@ -192,6 +192,9 @@ public: virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override; virtual uint32_t body_get_collision_mask(RID p_body) const override; + virtual void body_set_collision_priority(RID p_body, real_t p_priority) override; + virtual real_t body_get_collision_priority(RID p_body) const override; + virtual void body_set_user_flags(RID p_body, uint32_t p_flags) override; virtual uint32_t body_get_user_flags(RID p_body) const override; diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp index 13e9a89b2e..074232dd66 100644 --- a/servers/physics_3d/godot_space_3d.cpp +++ b/servers/physics_3d/godot_space_3d.cpp @@ -701,6 +701,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D:: const int max_results = 32; int recover_attempts = 4; Vector3 sr[max_results * 2]; + real_t priorities[max_results]; do { GodotPhysicsServer3D::CollCbkData cbk; @@ -710,6 +711,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D:: GodotPhysicsServer3D::CollCbkData *cbkptr = &cbk; GodotCollisionSolver3D::CallbackResult cbkres = GodotPhysicsServer3D::_shape_col_cbk; + int priority_amount = 0; bool collided = false; @@ -737,6 +739,10 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D:: if (GodotCollisionSolver3D::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, margin)) { collided = cbk.amount > 0; } + while (cbk.amount > priority_amount) { + priorities[priority_amount] = col_obj->get_collision_priority(); + priority_amount++; + } } } @@ -744,6 +750,12 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D:: break; } + real_t inv_total_weight = 0.0; + for (int i = 0; i < cbk.amount; i++) { + inv_total_weight += priorities[i]; + } + inv_total_weight = Math::is_zero_approx(inv_total_weight) ? 1.0 : (real_t)cbk.amount / inv_total_weight; + recovered = true; Vector3 recover_motion; @@ -759,7 +771,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D:: real_t depth = n.dot(a + recover_motion) - d; if (depth > min_contact_depth + CMP_EPSILON) { // Only recover if there is penetration. - recover_motion -= n * (depth - min_contact_depth) * 0.4; + recover_motion -= n * (depth - min_contact_depth) * 0.4 * priorities[i] * inv_total_weight; } } diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 26768e300c..ee6764d8e1 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -706,6 +706,9 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer2D::body_set_collision_mask); ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer2D::body_get_collision_mask); + ClassDB::bind_method(D_METHOD("body_set_collision_priority", "body", "priority"), &PhysicsServer2D::body_set_collision_priority); + ClassDB::bind_method(D_METHOD("body_get_collision_priority", "body"), &PhysicsServer2D::body_get_collision_priority); + ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer2D::body_set_param); ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer2D::body_get_param); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 6d95c591c2..df8b641ffc 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -393,6 +393,9 @@ public: virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0; virtual uint32_t body_get_collision_mask(RID p_body) const = 0; + virtual void body_set_collision_priority(RID p_body, real_t p_priority) = 0; + virtual real_t body_get_collision_priority(RID p_body) const = 0; + // common body variables enum BodyParameter { BODY_PARAM_BOUNCE, diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h index ddb071f603..d080aac438 100644 --- a/servers/physics_server_2d_wrap_mt.h +++ b/servers/physics_server_2d_wrap_mt.h @@ -205,6 +205,9 @@ public: FUNC2(body_set_collision_mask, RID, uint32_t); FUNC1RC(uint32_t, body_get_collision_mask, RID); + FUNC2(body_set_collision_priority, RID, real_t); + FUNC1RC(real_t, body_get_collision_priority, RID); + FUNC3(body_set_param, RID, BodyParameter, const Variant &); FUNC2RC(Variant, body_get_param, RID, BodyParameter); diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index f25db22e66..c985df83b2 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -750,6 +750,9 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer3D::body_set_collision_mask); ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer3D::body_get_collision_mask); + ClassDB::bind_method(D_METHOD("body_set_collision_priority", "body", "priority"), &PhysicsServer3D::body_set_collision_priority); + ClassDB::bind_method(D_METHOD("body_get_collision_priority", "body"), &PhysicsServer3D::body_get_collision_priority); + ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer3D::body_add_shape, DEFVAL(Transform3D()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &PhysicsServer3D::body_set_shape); ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &PhysicsServer3D::body_set_shape_transform); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 12497c0bdf..01324be0f5 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -421,6 +421,9 @@ public: virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0; virtual uint32_t body_get_collision_mask(RID p_body) const = 0; + virtual void body_set_collision_priority(RID p_body, real_t p_priority) = 0; + virtual real_t body_get_collision_priority(RID p_body) const = 0; + virtual void body_set_user_flags(RID p_body, uint32_t p_flags) = 0; virtual uint32_t body_get_user_flags(RID p_body) const = 0; diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h index d4a4ad3132..ed4546b240 100644 --- a/servers/physics_server_3d_wrap_mt.h +++ b/servers/physics_server_3d_wrap_mt.h @@ -202,6 +202,9 @@ public: FUNC2(body_set_collision_mask, RID, uint32_t); FUNC1RC(uint32_t, body_get_collision_mask, RID); + FUNC2(body_set_collision_priority, RID, real_t); + FUNC1RC(real_t, body_get_collision_priority, RID); + FUNC2(body_set_user_flags, RID, uint32_t); FUNC1RC(uint32_t, body_get_user_flags, RID); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index e9515c7670..6b4e4a5a16 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -15,11 +15,11 @@ layout(location = 0) in vec3 vertex_attrib; //only for pure render depth when normal is not used #ifdef NORMAL_USED -layout(location = 1) in vec3 normal_attrib; +layout(location = 1) in vec2 normal_attrib; #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) -layout(location = 2) in vec4 tangent_attrib; +layout(location = 2) in vec2 tangent_attrib; #endif #if defined(COLOR_USED) @@ -58,6 +58,13 @@ layout(location = 10) in uvec4 bone_attrib; layout(location = 11) in vec4 weight_attrib; #endif +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; +} + /* Varyings */ layout(location = 0) out vec3 vertex_interp; @@ -231,12 +238,13 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData sc vec3 vertex = vertex_attrib; #ifdef NORMAL_USED - vec3 normal = normal_attrib * 2.0 - 1.0; + vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0); #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0; - float binormalf = tangent_attrib.a * 2.0 - 1.0; + vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0; + vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); + float binormalf = sign(signed_tangent_attrib.y); vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl index 6548793bee..0960533917 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -16,11 +16,11 @@ layout(location = 0) in vec3 vertex_attrib; //only for pure render depth when normal is not used #ifdef NORMAL_USED -layout(location = 1) in vec3 normal_attrib; +layout(location = 1) in vec2 normal_attrib; #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) -layout(location = 2) in vec4 tangent_attrib; +layout(location = 2) in vec2 tangent_attrib; #endif #if defined(COLOR_USED) @@ -59,6 +59,13 @@ layout(location = 10) in uvec4 bone_attrib; layout(location = 11) in vec4 weight_attrib; #endif +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; +} + /* Varyings */ layout(location = 0) highp out vec3 vertex_interp; @@ -229,12 +236,13 @@ void main() { vec3 vertex = vertex_attrib; #ifdef NORMAL_USED - vec3 normal = normal_attrib * 2.0 - 1.0; + vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0); #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0; - float binormalf = tangent_attrib.a * 2.0 - 1.0; + vec3 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0; + vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); + float binormalf = sign(signed_tangent_attrib.y); vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl index a893a66c94..75bea9300b 100644 --- a/servers/rendering/renderer_rd/shaders/skeleton.glsl +++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl @@ -54,14 +54,54 @@ layout(push_constant, std430) uniform Params { } params; -vec4 decode_abgr_2_10_10_10(uint base) { - uvec4 abgr_2_10_10_10 = (uvec4(base) >> uvec4(0, 10, 20, 30)) & uvec4(0x3FF, 0x3FF, 0x3FF, 0x3); - return vec4(abgr_2_10_10_10) / vec4(1023.0, 1023.0, 1023.0, 3.0) * 2.0 - 1.0; +vec2 uint_to_vec2(uint base) { + uvec2 decode = (uvec2(base) >> uvec2(0, 16)) & uvec2(0xFFFF, 0xFFFF); + return vec2(decode) / vec2(65535.0, 65535.0) * 2.0 - 1.0; } -uint encode_abgr_2_10_10_10(vec4 base) { - uvec4 abgr_2_10_10_10 = uvec4(clamp(ivec4((base * 0.5 + 0.5) * vec4(1023.0, 1023.0, 1023.0, 3.0)), ivec4(0), ivec4(0x3FF, 0x3FF, 0x3FF, 0x3))) << uvec4(0, 10, 20, 30); - return abgr_2_10_10_10.x | abgr_2_10_10_10.y | abgr_2_10_10_10.z | abgr_2_10_10_10.w; +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; +} + +vec3 decode_uint_oct_to_norm(uint base) { + return oct_to_vec3(uint_to_vec2(base)); +} + +vec4 decode_uint_oct_to_tang(uint base) { + vec2 oct_sign_encoded = uint_to_vec2(base); + // Binormal sign encoded in y component + vec2 oct = vec2(oct_sign_encoded.x, abs(oct_sign_encoded.y) * 2.0 - 1.0); + return vec4(oct_to_vec3(oct), sign(oct_sign_encoded.y)); +} + +vec2 signNotZero(vec2 v) { + return mix(vec2(-1.0), vec2(1.0), greaterThanEqual(v.xy, vec2(0.0))); +} + +uint vec2_to_uint(vec2 base) { + uvec2 enc = uvec2(clamp(ivec2(base * vec2(65535, 65535)), ivec2(0), ivec2(0xFFFF, 0xFFFF))) << uvec2(0, 16); + return enc.x | enc.y; +} + +vec2 vec3_to_oct(vec3 e) { + e /= abs(e.x) + abs(e.y) + abs(e.z); + vec2 oct = e.z >= 0.0f ? e.xy : (vec2(1.0f) - abs(e.yx)) * signNotZero(e.xy); + return oct * 0.5f + 0.5f; +} + +uint encode_norm_to_uint_oct(vec3 base) { + return vec2_to_uint(vec3_to_oct(base)); +} + +uint encode_tang_to_uint_oct(vec4 base) { + vec2 oct = vec3_to_oct(base.xyz); + // Encode binormal sign in y component + oct.y = oct.y * 0.5f + 0.5f; + oct.y = base.w >= 0.0f ? oct.y : 1 - oct.y; + return vec2_to_uint(oct); } void main() { @@ -131,12 +171,12 @@ void main() { src_offset += 3; if (params.has_normal) { - normal = decode_abgr_2_10_10_10(src_vertices.data[src_offset]).rgb; + normal = decode_uint_oct_to_norm(src_vertices.data[src_offset]); src_offset++; } if (params.has_tangent) { - tangent = decode_abgr_2_10_10_10(src_vertices.data[src_offset]); + tangent = decode_uint_oct_to_tang(src_vertices.data[src_offset]); } if (params.has_blend_shape) { @@ -155,12 +195,12 @@ void main() { base_offset += 3; if (params.has_normal) { - blend_normal += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w; + blend_normal += decode_uint_oct_to_norm(src_blend_shapes.data[base_offset]) * w; base_offset++; } if (params.has_tangent) { - blend_tangent += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w; + blend_tangent += decode_uint_oct_to_tang(src_blend_shapes.data[base_offset]).rgb * w; } blend_total += w; @@ -234,12 +274,12 @@ void main() { dst_offset += 3; if (params.has_normal) { - dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(vec4(normal, 0.0)); + dst_vertices.data[dst_offset] = encode_norm_to_uint_oct(normal); dst_offset++; } if (params.has_tangent) { - dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(tangent); + dst_vertices.data[dst_offset] = encode_tang_to_uint_oct(tangent); } #endif diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 1516e5e4fd..49d7198ec2 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -1073,10 +1073,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V } break; case RS::ARRAY_NORMAL: { vd.offset = stride; + vd.format = RD::DATA_FORMAT_R16G16_UNORM; + stride += sizeof(uint16_t) * 2; - vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32; - - stride += sizeof(uint32_t); if (mis) { buffer = mis->vertex_buffer; } else { @@ -1085,9 +1084,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V } break; case RS::ARRAY_TANGENT: { vd.offset = stride; + vd.format = RD::DATA_FORMAT_R16G16_UNORM; + stride += sizeof(uint16_t) * 2; - vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32; - stride += sizeof(uint32_t); if (mis) { buffer = mis->vertex_buffer; } else { diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index dcdc56d948..bbe78236b5 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -398,16 +398,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const Vector3 *src = array.ptr(); for (int i = 0; i < p_vertex_array_len; i++) { - Vector3 n = src[i] * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); - - uint32_t value = 0; - value |= CLAMP(int(n.x * 1023.0), 0, 1023); - value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; - value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; + Vector2 res = src[i].octahedron_encode(); + int16_t vector[2] = { + (int16_t)CLAMP(res.x * 65535, 0, 65535), + (int16_t)CLAMP(res.y * 65535, 0, 65535), + }; - memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4); } - } break; case RS::ARRAY_TANGENT: { @@ -416,33 +414,32 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint if (type == Variant::PACKED_FLOAT32_ARRAY) { Vector<float> array = p_arrays[ai]; ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); - const float *src = array.ptr(); + const float *src_ptr = array.ptr(); for (int i = 0; i < p_vertex_array_len; i++) { - uint32_t value = 0; - value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023); - value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; - value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; - if (src[i * 4 + 3] > 0) { - value |= 3UL << 30; - } - - memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); + const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]); + Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]); + int16_t vector[2] = { + (int16_t)CLAMP(res.x * 65535, 0, 65535), + (int16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4); } } else { // PACKED_FLOAT64_ARRAY Vector<double> array = p_arrays[ai]; ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); - const double *src = array.ptr(); + const double *src_ptr = array.ptr(); for (int i = 0; i < p_vertex_array_len; i++) { - uint32_t value = 0; - value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023); - value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; - value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; - if (src[i * 4 + 3] > 0) { - value |= 3UL << 30; - } - memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); + const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]); + Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]); + int16_t vector[2] = { + (int16_t)CLAMP(res.x * 65535, 0, 65535), + (int16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4); } } } break; diff --git a/tests/python_build/conftest.py b/tests/python_build/conftest.py new file mode 100644 index 0000000000..617230926a --- /dev/null +++ b/tests/python_build/conftest.py @@ -0,0 +1,26 @@ +import os +import sys +from pathlib import Path + +import pytest + +CWD = Path(__file__).parent +ROOT = CWD.parent.parent +# append directory with build files to sys.path to import them +sys.path.append(str(ROOT)) + + +@pytest.fixture +def shader_files(request): + shader_path = request.param + + res = { + "path_input": str(CWD / "fixtures" / f"{shader_path}.glsl"), + "path_output": str(CWD / "fixtures" / f"{shader_path}.glsl.gen.h"), + "path_expected_full": str(CWD / "fixtures" / f"{shader_path}_expected_full.glsl"), + "path_expected_parts": str(CWD / "fixtures" / f"{shader_path}_expected_parts.json"), + } + yield res + + if not os.getenv("PYTEST_KEEP_GENERATED_FILES"): + os.remove(res["path_output"]) diff --git a/tests/python_build/fixtures/gles3/_included.glsl b/tests/python_build/fixtures/gles3/_included.glsl new file mode 100644 index 0000000000..adf5f702d3 --- /dev/null +++ b/tests/python_build/fixtures/gles3/_included.glsl @@ -0,0 +1 @@ +#define M_PI 3.14159265359 diff --git a/tests/python_build/fixtures/gles3/vertex_fragment.glsl b/tests/python_build/fixtures/gles3/vertex_fragment.glsl new file mode 100644 index 0000000000..3004e22f25 --- /dev/null +++ b/tests/python_build/fixtures/gles3/vertex_fragment.glsl @@ -0,0 +1,34 @@ +#include "_included.glsl" + +#[modes] + +mode_ninepatch = #define USE_NINEPATCH + +#[specializations] + +DISABLE_LIGHTING = false + +#[vertex] + +precision highp float; +precision highp int; + +layout(location = 0) in highp vec3 vertex; + +out highp vec4 position_interp; + +void main() { + position_interp = vec4(vertex.x,1,0,1); +} + +#[fragment] + +precision highp float; +precision highp int; + +in highp vec4 position_interp; + +void main() { + highp float depth = ((position_interp.z / position_interp.w) + 1.0); + frag_color = vec4(depth); +} diff --git a/tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl b/tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl new file mode 100644 index 0000000000..7bf56e73cd --- /dev/null +++ b/tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl @@ -0,0 +1,50 @@ +/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */ +#ifndef VERTEX_FRAGMENT_GLSL_GEN_HGLES3_GLES3 +#define VERTEX_FRAGMENT_GLSL_GEN_HGLES3_GLES3 + + +#include "drivers/gles3/shader_gles3.h" + + +class VertexFragmentShaderGLES3 : public ShaderGLES3 { + +public: + + enum ShaderVariant { + MODE_NINEPATCH, + }; + + enum Specializations { + DISABLE_LIGHTING=1, + }; + + _FORCE_INLINE_ void version_bind_shader(RID p_version,ShaderVariant p_variant,uint64_t p_specialization=0) { _version_bind_shader(p_version,p_variant,p_specialization); } + +protected: + + virtual void _init() override { + + static const char **_uniform_strings=nullptr; + static const char* _variant_defines[]={ + "#define USE_NINEPATCH", + }; + + static TexUnitPair *_texunit_pairs=nullptr; + static UBOPair *_ubo_pairs=nullptr; + static Specialization _spec_pairs[]={ + {"DISABLE_LIGHTING",false}, + }; + + static const char _vertex_code[]={ +10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,102,108,111,97,116,59,10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,105,110,116,59,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,105,110,32,104,105,103,104,112,32,118,101,99,51,32,118,101,114,116,101,120,59,10,10,111,117,116,32,104,105,103,104,112,32,118,101,99,52,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,32,61,32,118,101,99,52,40,118,101,114,116,101,120,46,120,44,49,44,48,44,49,41,59,10,125,10,10, 0}; + + static const char _fragment_code[]={ +10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,102,108,111,97,116,59,10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,105,110,116,59,10,10,105,110,32,104,105,103,104,112,32,118,101,99,52,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,104,105,103,104,112,32,102,108,111,97,116,32,100,101,112,116,104,32,61,32,40,40,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,46,122,32,47,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,46,119,41,32,43,32,49,46,48,41,59,10,9,102,114,97,103,95,99,111,108,111,114,32,61,32,118,101,99,52,40,100,101,112,116,104,41,59,10,125,10, 0}; + + _setup(_vertex_code,_fragment_code,"VertexFragmentShaderGLES3",0,_uniform_strings,0,_ubo_pairs,0,_texunit_pairs,1,_spec_pairs,1,_variant_defines); + } + +}; + +#endif + diff --git a/tests/python_build/fixtures/gles3/vertex_fragment_expected_parts.json b/tests/python_build/fixtures/gles3/vertex_fragment_expected_parts.json new file mode 100644 index 0000000000..eaeb5981c0 --- /dev/null +++ b/tests/python_build/fixtures/gles3/vertex_fragment_expected_parts.json @@ -0,0 +1,52 @@ +{ + "vertex_lines": [ + "", + "precision highp float;", + "precision highp int;", + "", + "layout(location = 0) in highp vec3 vertex;", + "", + "out highp vec4 position_interp;", + "", + "void main() {", + "\tposition_interp = vec4(vertex.x,1,0,1);", + "}", + "" + ], + "fragment_lines": [ + "", + "precision highp float;", + "precision highp int;", + "", + "in highp vec4 position_interp;", + "", + "void main() {", + "\thighp float depth = ((position_interp.z / position_interp.w) + 1.0);", + "\tfrag_color = vec4(depth);", + "}" + ], + "uniforms": [], + "fbos": [], + "texunits": [], + "texunit_names": [], + "ubos": [], + "ubo_names": [], + "vertex_included_files": [], + "fragment_included_files": [], + "reading": "fragment", + "line_offset": 33, + "vertex_offset": 10, + "fragment_offset": 23, + "variant_defines": [ + "#define USE_NINEPATCH" + ], + "variant_names": [ + "MODE_NINEPATCH" + ], + "specialization_names": [ + "DISABLE_LIGHTING" + ], + "specialization_values": [ + " false\n" + ] +} diff --git a/tests/python_build/fixtures/glsl/_included.glsl b/tests/python_build/fixtures/glsl/_included.glsl new file mode 100644 index 0000000000..adf5f702d3 --- /dev/null +++ b/tests/python_build/fixtures/glsl/_included.glsl @@ -0,0 +1 @@ +#define M_PI 3.14159265359 diff --git a/tests/python_build/fixtures/glsl/compute.glsl b/tests/python_build/fixtures/glsl/compute.glsl new file mode 100644 index 0000000000..e81f48d463 --- /dev/null +++ b/tests/python_build/fixtures/glsl/compute.glsl @@ -0,0 +1,12 @@ +#[compute] + +#version 450 + +#VERSION_DEFINES + + +#include "_included.glsl" + +void main() { + vec3 static_light = vec3(0, 1, 0); +} diff --git a/tests/python_build/fixtures/glsl/compute_expected_full.glsl b/tests/python_build/fixtures/glsl/compute_expected_full.glsl new file mode 100644 index 0000000000..b937d732c8 --- /dev/null +++ b/tests/python_build/fixtures/glsl/compute_expected_full.glsl @@ -0,0 +1,8 @@ +/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */ +#ifndef COMPUTE_SHADER_GLSL_RAW_H +#define COMPUTE_SHADER_GLSL_RAW_H + +static const char compute_shader_glsl[] = { + 35,91,99,111,109,112,117,116,101,93,10,10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,118,101,99,51,32,115,116,97,116,105,99,95,108,105,103,104,116,32,61,32,118,101,99,51,40,48,44,32,49,44,32,48,41,59,10,125,10,0 +}; +#endif diff --git a/tests/python_build/fixtures/glsl/compute_expected_parts.json b/tests/python_build/fixtures/glsl/compute_expected_parts.json new file mode 100644 index 0000000000..025c568ae0 --- /dev/null +++ b/tests/python_build/fixtures/glsl/compute_expected_parts.json @@ -0,0 +1,3 @@ +{ + "code": "#[compute]\n\n#version 450\n\n#VERSION_DEFINES\n\n\n#define M_PI 3.14159265359\n\nvoid main() {\n\tvec3 static_light = vec3(0, 1, 0);\n}\n" +} diff --git a/tests/python_build/fixtures/glsl/vertex_fragment.glsl b/tests/python_build/fixtures/glsl/vertex_fragment.glsl new file mode 100644 index 0000000000..0bdce783d7 --- /dev/null +++ b/tests/python_build/fixtures/glsl/vertex_fragment.glsl @@ -0,0 +1,32 @@ +#[versions] + +lines = "#define MODE_LINES"; + +#[vertex] + +#version 450 + +#VERSION_DEFINES + +layout(location = 0) out vec3 uv_interp; + +void main() { + +#ifdef MODE_LINES + uv_interp = vec3(0,0,1); +#endif +} + +#[fragment] + +#version 450 + +#VERSION_DEFINES + +#include "_included.glsl" + +layout(location = 0) out vec4 dst_color; + +void main() { + dst_color = vec4(1,1,0,0); +} diff --git a/tests/python_build/fixtures/glsl/vertex_fragment_expected_full.glsl b/tests/python_build/fixtures/glsl/vertex_fragment_expected_full.glsl new file mode 100644 index 0000000000..3f53a17fac --- /dev/null +++ b/tests/python_build/fixtures/glsl/vertex_fragment_expected_full.glsl @@ -0,0 +1,8 @@ +/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */ +#ifndef VERTEX_FRAGMENT_SHADER_GLSL_RAW_H +#define VERTEX_FRAGMENT_SHADER_GLSL_RAW_H + +static const char vertex_fragment_shader_glsl[] = { + 35,91,118,101,114,115,105,111,110,115,93,10,10,108,105,110,101,115,32,61,32,34,35,100,101,102,105,110,101,32,77,79,68,69,95,76,73,78,69,83,34,59,10,10,35,91,118,101,114,116,101,120,93,10,10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,111,117,116,32,118,101,99,51,32,117,118,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,10,35,105,102,100,101,102,32,77,79,68,69,95,76,73,78,69,83,10,9,117,118,95,105,110,116,101,114,112,32,61,32,118,101,99,51,40,48,44,48,44,49,41,59,10,35,101,110,100,105,102,10,125,10,10,35,91,102,114,97,103,109,101,110,116,93,10,10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,111,117,116,32,118,101,99,52,32,100,115,116,95,99,111,108,111,114,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,100,115,116,95,99,111,108,111,114,32,61,32,118,101,99,52,40,49,44,49,44,48,44,48,41,59,10,125,10,0 +}; +#endif diff --git a/tests/python_build/fixtures/glsl/vertex_fragment_expected_parts.json b/tests/python_build/fixtures/glsl/vertex_fragment_expected_parts.json new file mode 100644 index 0000000000..38312367a0 --- /dev/null +++ b/tests/python_build/fixtures/glsl/vertex_fragment_expected_parts.json @@ -0,0 +1,3 @@ +{ + "code": "#[versions]\n\nlines = \"#define MODE_LINES\";\n\n#[vertex]\n\n#version 450\n\n#VERSION_DEFINES\n\nlayout(location = 0) out vec3 uv_interp;\n\nvoid main() {\n\n#ifdef MODE_LINES\n\tuv_interp = vec3(0,0,1);\n#endif\n}\n\n#[fragment]\n\n#version 450\n\n#VERSION_DEFINES\n\n#define M_PI 3.14159265359\n\nlayout(location = 0) out vec4 dst_color;\n\nvoid main() {\n\tdst_color = vec4(1,1,0,0);\n}\n" +} diff --git a/tests/python_build/fixtures/rd_glsl/_included.glsl b/tests/python_build/fixtures/rd_glsl/_included.glsl new file mode 100644 index 0000000000..adf5f702d3 --- /dev/null +++ b/tests/python_build/fixtures/rd_glsl/_included.glsl @@ -0,0 +1 @@ +#define M_PI 3.14159265359 diff --git a/tests/python_build/fixtures/rd_glsl/compute.glsl b/tests/python_build/fixtures/rd_glsl/compute.glsl new file mode 100644 index 0000000000..66fbbeb401 --- /dev/null +++ b/tests/python_build/fixtures/rd_glsl/compute.glsl @@ -0,0 +1,13 @@ +#[compute] + +#version 450 + +#VERSION_DEFINES + +#define BLOCK_SIZE 8 + +#include "_included.glsl" + +void main() { + uint t = BLOCK_SIZE + 1; +} diff --git a/tests/python_build/fixtures/rd_glsl/compute_expected_full.glsl b/tests/python_build/fixtures/rd_glsl/compute_expected_full.glsl new file mode 100644 index 0000000000..b59923e28a --- /dev/null +++ b/tests/python_build/fixtures/rd_glsl/compute_expected_full.glsl @@ -0,0 +1,20 @@ +/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */ +#ifndef COMPUTE_GLSL_GEN_H_RD +#define COMPUTE_GLSL_GEN_H_RD + +#include "servers/rendering/renderer_rd/shader_rd.h" + +class ComputeShaderRD : public ShaderRD { + +public: + + ComputeShaderRD() { + + static const char _compute_code[] = { +10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,35,100,101,102,105,110,101,32,66,76,79,67,75,95,83,73,90,69,32,56,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,117,105,110,116,32,116,32,61,32,66,76,79,67,75,95,83,73,90,69,32,43,32,49,59,10,125,10,0 + }; + setup(nullptr, nullptr, _compute_code, "ComputeShaderRD"); + } +}; + +#endif diff --git a/tests/python_build/fixtures/rd_glsl/compute_expected_parts.json b/tests/python_build/fixtures/rd_glsl/compute_expected_parts.json new file mode 100644 index 0000000000..26ba9e4fc4 --- /dev/null +++ b/tests/python_build/fixtures/rd_glsl/compute_expected_parts.json @@ -0,0 +1,28 @@ +{ + "vertex_lines": [], + "fragment_lines": [], + "compute_lines": [ + "", + "#version 450", + "", + "#VERSION_DEFINES", + "", + "#define BLOCK_SIZE 8", + "", + "#define M_PI 3.14159265359", + "", + "void main() {", + "\tuint t = BLOCK_SIZE + 1;", + "}" + ], + "vertex_included_files": [], + "fragment_included_files": [], + "compute_included_files": [ + "tests/python_build/fixtures/rd_glsl/_included.glsl" + ], + "reading": "compute", + "line_offset": 13, + "vertex_offset": 0, + "fragment_offset": 0, + "compute_offset": 1 +} diff --git a/tests/python_build/fixtures/rd_glsl/vertex_fragment.glsl b/tests/python_build/fixtures/rd_glsl/vertex_fragment.glsl new file mode 100644 index 0000000000..27be08a857 --- /dev/null +++ b/tests/python_build/fixtures/rd_glsl/vertex_fragment.glsl @@ -0,0 +1,25 @@ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +#include "_included.glsl" + +layout(location = 0) out vec2 uv_interp; + +void main() { + uv_interp = vec2(0, 1); +} + +#[fragment] + +#version 450 + +#VERSION_DEFINES + +layout(location = 0) in vec2 uv_interp; + +void main() { + uv_interp = vec2(1, 0); +} diff --git a/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_full.glsl b/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_full.glsl new file mode 100644 index 0000000000..ff804dbf89 --- /dev/null +++ b/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_full.glsl @@ -0,0 +1,23 @@ +/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */ +#ifndef VERTEX_FRAGMENT_GLSL_GEN_H_RD +#define VERTEX_FRAGMENT_GLSL_GEN_H_RD + +#include "servers/rendering/renderer_rd/shader_rd.h" + +class VertexFragmentShaderRD : public ShaderRD { + +public: + + VertexFragmentShaderRD() { + + static const char _vertex_code[] = { +10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,111,117,116,32,118,101,99,50,32,117,118,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,117,118,95,105,110,116,101,114,112,32,61,32,118,101,99,50,40,48,44,32,49,41,59,10,125,10,10,0 + }; + static const char _fragment_code[] = { +10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,105,110,32,118,101,99,50,32,117,118,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,117,118,95,105,110,116,101,114,112,32,61,32,118,101,99,50,40,49,44,32,48,41,59,10,125,10,0 + }; + setup(_vertex_code, _fragment_code, nullptr, "VertexFragmentShaderRD"); + } +}; + +#endif diff --git a/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_parts.json b/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_parts.json new file mode 100644 index 0000000000..dbf833edea --- /dev/null +++ b/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_parts.json @@ -0,0 +1,40 @@ +{ + "vertex_lines": [ + "", + "#version 450", + "", + "#VERSION_DEFINES", + "", + "#define M_PI 3.14159265359", + "", + "layout(location = 0) out vec2 uv_interp;", + "", + "void main() {", + "\tuv_interp = vec2(0, 1);", + "}", + "" + ], + "fragment_lines": [ + "", + "#version 450", + "", + "#VERSION_DEFINES", + "", + "layout(location = 0) in vec2 uv_interp;", + "", + "void main() {", + "\tuv_interp = vec2(1, 0);", + "}" + ], + "compute_lines": [], + "vertex_included_files": [ + "tests/python_build/fixtures/rd_glsl/_included.glsl" + ], + "fragment_included_files": [], + "compute_included_files": [], + "reading": "fragment", + "line_offset": 25, + "vertex_offset": 1, + "fragment_offset": 15, + "compute_offset": 0 +} diff --git a/tests/python_build/test_gles3_builder.py b/tests/python_build/test_gles3_builder.py new file mode 100644 index 0000000000..861e0b84c4 --- /dev/null +++ b/tests/python_build/test_gles3_builder.py @@ -0,0 +1,31 @@ +import json + +import pytest + +from gles3_builders import build_gles3_header, GLES3HeaderStruct + + +@pytest.mark.parametrize( + ["shader_files", "builder", "header_struct"], + [ + ("gles3/vertex_fragment", build_gles3_header, GLES3HeaderStruct), + ], + indirect=["shader_files"], +) +def test_gles3_builder(shader_files, builder, header_struct): + header = header_struct() + + builder(shader_files["path_input"], "drivers/gles3/shader_gles3.h", "GLES3", header_data=header) + + with open(shader_files["path_expected_parts"], "r") as f: + expected_parts = json.load(f) + assert expected_parts == header.__dict__ + + with open(shader_files["path_output"], "r") as f: + actual_output = f.read() + assert actual_output + + with open(shader_files["path_expected_full"], "r") as f: + expected_output = f.read() + + assert actual_output == expected_output diff --git a/tests/python_build/test_glsl_builder.py b/tests/python_build/test_glsl_builder.py new file mode 100644 index 0000000000..b9dcef48ac --- /dev/null +++ b/tests/python_build/test_glsl_builder.py @@ -0,0 +1,37 @@ +import json + +import pytest + +from glsl_builders import build_raw_header, RAWHeaderStruct, build_rd_header, RDHeaderStruct + + +@pytest.mark.parametrize( + [ + "shader_files", + "builder", + "header_struct", + ], + [ + ("glsl/vertex_fragment", build_raw_header, RAWHeaderStruct), + ("glsl/compute", build_raw_header, RAWHeaderStruct), + ("rd_glsl/vertex_fragment", build_rd_header, RDHeaderStruct), + ("rd_glsl/compute", build_rd_header, RDHeaderStruct), + ], + indirect=["shader_files"], +) +def test_glsl_builder(shader_files, builder, header_struct): + header = header_struct() + builder(shader_files["path_input"], header_data=header) + + with open(shader_files["path_expected_parts"], "r") as f: + expected_parts = json.load(f) + assert expected_parts == header.__dict__ + + with open(shader_files["path_output"], "r") as f: + actual_output = f.read() + assert actual_output + + with open(shader_files["path_expected_full"], "r") as f: + expected_output = f.read() + + assert actual_output == expected_output |