diff options
310 files changed, 3755 insertions, 6984 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index f59c0e645d..de0037d5e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,11 +37,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - [New and improved IK in Skeleton2D](https://github.com/godotengine/godot/pull/40347). - New classes: SkeletonModifier2D, SkeletonModifierStack2D, SkeletonModification2DLookAt, SkeletonModification2DCCDIK, SkeletonModification2DFABRIK, SkeletonModification2DJiggle, SkeletonModification2DTwoBoneIK, PhysicalBone2D, SkeletonModification2DPhysicalBones, SkeletonModification2DStackHolder. - New `Transform2D.looking_at()` function. -- [New and improved IK in Skeleton3D](https://github.com/godotengine/godot/pull/39353). - - New classes: SkeletonModifier3D, SkeletonModifierStack3D, SkeletonModifier3DLookAt, SkeletonModification3DCCDIK, SkeletonModification3DFABRIK, SkeletonModification3DJiggle, SkeletonModification3DTwoBoneIK, SkeletonModification3DStackHolder. - - The Bone struct now includes a local_pose_override. +- [Improvements to Skeleton3D](https://github.com/godotengine/godot/pull/39353). - The Bone struct now keeps track of its children bones, if it has any. - - Added functions to Skeleton3D for getting the forward vector using the information stored in the rest pose for the bones. - New `Basis.rotate_to_align()` function. - Refactored the BoneAttachment3D node. - Removed the `process_list` functions. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 21d6e110ce..aea1c8c5ff 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -122,11 +122,12 @@ recommend that you have a look at it to know what's important to take into account for a PR to be considered for merging. In addition to the following tips, also take a look at the -[Engine development guide](https://docs.godotengine.org/en/latest/development/cpp/) +[Engine development guide](https://docs.godotengine.org/en/latest/contributing/development/index.html) for an introduction to developing on Godot. -The [Contributing docs](https://docs.godotengine.org/en/latest/community/contributing/index.html) -also have important information on the PR workflow and the code style we use. +The [Contributing docs](https://docs.godotengine.org/en/latest/contributing/ways_to_contribute.html) +also have important information on the [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html) +and the [code style](https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html) we use. ### Document your changes @@ -135,10 +136,10 @@ scripting APIs, you **must** update the class reference to document those. This is to ensure the documentation coverage doesn't decrease as contributions are merged. -[Update the documentation template](https://docs.godotengine.org/en/latest/community/contributing/updating_the_class_reference.html#updating-the-documentation-template) +[Update documentation XML files](https://docs.godotengine.org/en/latest/contributing/documentation/updating_the_class_reference.html#updating-class-reference-when-working-on-the-engine) using your compiled binary, then fill in the descriptions. Follow the style guide described in the -[Docs writing guidelines](https://docs.godotengine.org/en/latest/community/contributing/docs_writing_guidelines.html). +[Writing guidelines](https://docs.godotengine.org/en/latest/contributing/documentation/docs_writing_guidelines.html). If your pull request modifies parts of the code in a non-obvious way, make sure to add comments in the code as well. This helps other people understand the @@ -164,7 +165,7 @@ applicable. Feel free to contribute standalone pull requests to add new tests or improve existing tests as well. -See [Unit testing](https://docs.godotengine.org/en/latest/development/cpp/unit_testing.html) +See [Unit testing](https://docs.godotengine.org/en/latest/contributing/development/core_and_modules/unit_testing.html) for information on writing tests in Godot's C++ codebase. ### Be nice to the Git history @@ -186,7 +187,7 @@ Internet). This [Git style guide](https://github.com/agis-/git-style-guide) has some good practices to have in mind. -See our [PR workflow](https://docs.godotengine.org/en/latest/community/contributing/pr_workflow.html) +See our [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html) documentation for tips on using Git, amending commits and rebasing branches. ### Format your commit messages with readability in mind diff --git a/SConstruct b/SConstruct index 1eb6c0adc8..705ef43b3d 100644 --- a/SConstruct +++ b/SConstruct @@ -540,6 +540,9 @@ if selected_platform in platform_list: env.Append(CCFLAGS=["/Od"]) else: if env["debug_symbols"]: + # Adding dwarf-4 explicitly makes stacktraces work with clang builds, + # otherwise addr2line doesn't understand them + env.Append(CCFLAGS=["-gdwarf-4"]) if env.dev_build: env.Append(CCFLAGS=["-g3"]) else: diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 0bf7430d84..de27b6d5ac 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -33,6 +33,7 @@ #include "core/core_bind.h" // For Compression enum. #include "core/core_string_names.h" #include "core/input/input_map.h" +#include "core/io/config_file.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" #include "core/io/file_access_network.h" @@ -291,31 +292,26 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { return true; } - if (!disable_feature_overrides) { + { // Feature overrides. int dot = p_name.operator String().find("."); if (dot != -1) { Vector<String> s = p_name.operator String().split("."); - bool override_valid = false; for (int i = 1; i < s.size(); i++) { String feature = s[i].strip_edges(); - if (OS::get_singleton()->has_feature(feature) || custom_features.has(feature)) { - override_valid = true; - break; + Pair<StringName, StringName> fo(feature, p_name); + + if (!feature_overrides.has(s[0])) { + feature_overrides[s[0]] = LocalVector<Pair<StringName, StringName>>(); } - } - if (override_valid) { - feature_overrides[s[0]] = p_name; + feature_overrides[s[0]].push_back(fo); } } } if (props.has(p_name)) { - if (!props[p_name].overridden) { - props[p_name].variant = p_value; - } - + props[p_name].variant = p_value; } else { props[p_name] = VariantContainer(p_value, last_order++); } @@ -340,16 +336,35 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { bool ProjectSettings::_get(const StringName &p_name, Variant &r_ret) const { _THREAD_SAFE_METHOD_ + if (!props.has(p_name)) { + WARN_PRINT("Property not found: " + String(p_name)); + return false; + } + r_ret = props[p_name].variant; + return true; +} + +Variant ProjectSettings::get_setting_with_override(const StringName &p_name) const { + _THREAD_SAFE_METHOD_ + StringName name = p_name; - if (!disable_feature_overrides && feature_overrides.has(name)) { - name = feature_overrides[name]; + if (feature_overrides.has(name)) { + const LocalVector<Pair<StringName, StringName>> &overrides = feature_overrides[name]; + for (uint32_t i = 0; i < overrides.size(); i++) { + if (OS::get_singleton()->has_feature(overrides[i].first)) { // Custom features are checked in OS.has_feature() already. No need to check twice. + if (props.has(overrides[i].second)) { + name = overrides[i].second; + break; + } + } + } } + if (!props.has(name)) { WARN_PRINT("Property not found: " + String(name)); - return false; + return Variant(); } - r_ret = props[name].variant; - return true; + return props[name].variant; } struct _VCSort { @@ -1101,10 +1116,6 @@ const HashMap<StringName, PropertyInfo> &ProjectSettings::get_custom_property_in return custom_prop_info; } -void ProjectSettings::set_disable_feature_overrides(bool p_disable) { - disable_feature_overrides = p_disable; -} - bool ProjectSettings::is_using_datapack() const { return using_datapack; } @@ -1138,6 +1149,29 @@ Variant ProjectSettings::get_setting(const String &p_setting, const Variant &p_d } } +Array ProjectSettings::get_global_class_list() { + Array script_classes; + + Ref<ConfigFile> cf; + cf.instantiate(); + if (cf->load(get_project_data_path().path_join("global_script_class_cache.cfg")) == OK) { + script_classes = cf->get_value("", "list"); + } else { +#ifndef TOOLS_ENABLED + // Script classes can't be recreated in exported project, so print an error. + ERR_PRINT("Could not load global script cache."); +#endif + } + return script_classes; +} + +void ProjectSettings::store_global_class_list(const Array &p_classes) { + Ref<ConfigFile> cf; + cf.instantiate(); + cf->set_value("", "list", p_classes); + cf->save(get_project_data_path().path_join("global_script_class_cache.cfg")); +} + bool ProjectSettings::has_custom_feature(const String &p_feature) const { return custom_features.has(p_feature); } @@ -1169,6 +1203,7 @@ void ProjectSettings::_bind_methods() { ClassDB::bind_method(D_METHOD("has_setting", "name"), &ProjectSettings::has_setting); ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &ProjectSettings::set_setting); ClassDB::bind_method(D_METHOD("get_setting", "name", "default_value"), &ProjectSettings::get_setting, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("get_setting_with_override", "name"), &ProjectSettings::get_setting_with_override); ClassDB::bind_method(D_METHOD("set_order", "name", "position"), &ProjectSettings::set_order); ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order); ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value); diff --git a/core/config/project_settings.h b/core/config/project_settings.h index 2aca1e7691..29c495c46b 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -34,6 +34,7 @@ #include "core/object/class_db.h" #include "core/os/thread_safe.h" #include "core/templates/hash_map.h" +#include "core/templates/local_vector.h" #include "core/templates/rb_set.h" class ProjectSettings : public Object { @@ -69,7 +70,6 @@ protected: Variant variant; Variant initial; bool hide_from_editor = false; - bool overridden = false; bool restart_if_changed = false; #ifdef DEBUG_METHODS_ENABLED bool ignore_value_in_docs = false; @@ -91,12 +91,11 @@ protected: RBMap<StringName, VariantContainer> props; // NOTE: Key order is used e.g. in the save_custom method. String resource_path; HashMap<StringName, PropertyInfo> custom_prop_info; - bool disable_feature_overrides = false; bool using_datapack = false; List<String> input_presets; HashSet<String> custom_features; - HashMap<StringName, StringName> feature_overrides; + HashMap<StringName, LocalVector<Pair<StringName, StringName>>> feature_overrides; HashMap<StringName, AutoloadInfo> autoloads; @@ -142,6 +141,8 @@ public: void set_setting(const String &p_setting, const Variant &p_value); Variant get_setting(const String &p_setting, const Variant &p_default_value = Variant()) const; + Array get_global_class_list(); + void store_global_class_list(const Array &p_classes); bool has_setting(String p_var) const; String localize_path(const String &p_path) const; @@ -181,7 +182,7 @@ public: List<String> get_input_presets() const { return input_presets; } - void set_disable_feature_overrides(bool p_disable); + Variant get_setting_with_override(const StringName &p_name) const; bool is_using_datapack() const; @@ -205,7 +206,7 @@ Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p #define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true) #define GLOBAL_DEF_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true) #define GLOBAL_DEF_RST_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true) -#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var) +#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var) #define GLOBAL_DEF_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, true) #define GLOBAL_DEF_RST_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, false, true) diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp index 3ac78e0709..c04fe7320d 100644 --- a/core/math/geometry_3d.cpp +++ b/core/math/geometry_3d.cpp @@ -748,7 +748,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes Vector3 right = p.normal.cross(ref).normalized(); Vector3 up = p.normal.cross(right).normalized(); - Vector3 center = p.center(); + Vector3 center = p.get_center(); // make a quad clockwise LocalVector<Vector3> vertices = { diff --git a/core/math/plane.h b/core/math/plane.h index 3bc7c54b9d..8159f25342 100644 --- a/core/math/plane.h +++ b/core/math/plane.h @@ -47,7 +47,7 @@ struct _NO_DISCARD_ Plane { /* Plane-Point operations */ - _FORCE_INLINE_ Vector3 center() const { return normal * d; } + _FORCE_INLINE_ Vector3 get_center() const { return normal * d; } Vector3 get_any_perpendicular_normal() const; _FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 7be3a6c688..c9cfbdd4cb 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -186,6 +186,7 @@ void ScriptServer::unregister_language(const ScriptLanguage *p_language) { void ScriptServer::init_languages() { { // Load global classes. global_classes_clear(); +#ifndef DISABLE_DEPRECATED if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) { Array script_classes = GLOBAL_GET("_global_script_classes"); @@ -196,6 +197,17 @@ void ScriptServer::init_languages() { } add_global_class(c["class"], c["base"], c["language"], c["path"]); } + ProjectSettings::get_singleton()->clear("_global_script_classes"); + } +#endif + + Array script_classes = ProjectSettings::get_singleton()->get_global_class_list(); + for (int i = 0; i < script_classes.size(); i++) { + Dictionary c = script_classes[i]; + if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base")) { + continue; + } + add_global_class(c["class"], c["base"], c["language"], c["path"]); } } @@ -291,6 +303,17 @@ void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) { } void ScriptServer::save_global_classes() { + Dictionary class_icons; + + Array script_classes = ProjectSettings::get_singleton()->get_global_class_list(); + for (int i = 0; i < script_classes.size(); i++) { + Dictionary d = script_classes[i]; + if (!d.has("name") || !d.has("icon")) { + continue; + } + class_icons[d["name"]] = d["icon"]; + } + List<StringName> gc; get_global_class_list(&gc); Array gcarr; @@ -300,25 +323,10 @@ void ScriptServer::save_global_classes() { d["language"] = global_classes[E].language; d["path"] = global_classes[E].path; d["base"] = global_classes[E].base; + d["icon"] = class_icons.get(E, ""); gcarr.push_back(d); } - - Array old; - if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) { - old = GLOBAL_GET("_global_script_classes"); - } - if ((!old.is_empty() || gcarr.is_empty()) && gcarr.hash() == old.hash()) { - return; - } - - if (gcarr.is_empty()) { - if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) { - ProjectSettings::get_singleton()->clear("_global_script_classes"); - } - } else { - ProjectSettings::get_singleton()->set("_global_script_classes", gcarr); - } - ProjectSettings::get_singleton()->save(); + ProjectSettings::get_singleton()->store_global_class_list(gcarr); } //////////////////// diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp index e0231b818f..5183b77cb1 100644 --- a/core/os/keyboard.cpp +++ b/core/os/keyboard.cpp @@ -63,12 +63,15 @@ static const _KeyCodeText _keycodes[] = { {Key::CTRL ,"Ctrl"}, #if defined(MACOS_ENABLED) {Key::META ,"Command"}, + {Key::CMD_OR_CTRL ,"Command"}, {Key::ALT ,"Option"}, #elif defined(WINDOWS_ENABLED) {Key::META ,"Windows"}, + {Key::CMD_OR_CTRL ,"Ctrl"}, {Key::ALT ,"Alt"}, #else {Key::META ,"Meta"}, + {Key::CMD_OR_CTRL ,"Ctrl"}, {Key::ALT ,"Alt"}, #endif {Key::CAPSLOCK ,"CapsLock"}, diff --git a/core/os/keyboard.h b/core/os/keyboard.h index 389baee915..c78fa2a631 100644 --- a/core/os/keyboard.h +++ b/core/os/keyboard.h @@ -65,6 +65,11 @@ enum class Key { SHIFT = SPECIAL | 0x15, CTRL = SPECIAL | 0x16, META = SPECIAL | 0x17, +#if defined(MACOS_ENABLED) + CMD_OR_CTRL = META, +#else + CMD_OR_CTRL = CTRL, +#endif ALT = SPECIAL | 0x18, CAPSLOCK = SPECIAL | 0x19, NUMLOCK = SPECIAL | 0x1A, diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 05fb62ff12..2cc0b3a8d7 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1923,7 +1923,7 @@ static void _register_variant_builtin_methods() { /* Plane */ bind_method(Plane, normalized, sarray(), varray()); - bind_method(Plane, center, sarray(), varray()); + bind_method(Plane, get_center, sarray(), varray()); bind_method(Plane, is_equal_approx, sarray("to_plane"), varray()); bind_method(Plane, is_finite, sarray(), varray()); bind_method(Plane, is_point_over, sarray("point"), varray()); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 41836650cd..7e7cb07cef 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -494,7 +494,7 @@ <return type="bool" /> <param index="0" name="x" type="float" /> <description> - Returns whether [code]x[/code] is a finite value, i.e. it is not [constant @GDScript.NAN], positive infinity, or negative infinity. + Returns whether [param x] is a finite value, i.e. it is not [constant @GDScript.NAN], positive infinity, or negative infinity. </description> </method> <method name="is_inf"> @@ -529,7 +529,7 @@ <return type="bool" /> <param index="0" name="x" type="float" /> <description> - Returns [code]true[/code] if [param x] is zero or almost zero. + Returns [code]true[/code] if [param x] is zero or almost zero. The comparison is done using a tolerance calculation with a small internal epsilon. This function is faster than using [method is_equal_approx] with one value as zero. </description> </method> diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml index aedb8f4420..68f62d1c00 100644 --- a/doc/classes/BaseButton.xml +++ b/doc/classes/BaseButton.xml @@ -70,7 +70,7 @@ [Shortcut] associated to the button. </member> <member name="shortcut_feedback" type="bool" setter="set_shortcut_feedback" getter="is_shortcut_feedback" default="true"> - If [code]true[/code], the button will appear pressed when its shortcut is activated. If [code]false[/code] and [member toggle_mode] is [code]false[/code], the shortcut will activate the button without appearing to press the button. + If [code]true[/code], the button will highlight for a short amount of time when its shortcut is activated. If [code]false[/code] and [member toggle_mode] is [code]false[/code], the shortcut will activate without any visual feedback. </member> <member name="shortcut_in_tooltip" type="bool" setter="set_shortcut_in_tooltip" getter="is_shortcut_in_tooltip_enabled" default="true"> If [code]true[/code], the button will add information about its shortcut in the tooltip. diff --git a/doc/classes/BoneAttachment3D.xml b/doc/classes/BoneAttachment3D.xml index f29525038e..dd01de3607 100644 --- a/doc/classes/BoneAttachment3D.xml +++ b/doc/classes/BoneAttachment3D.xml @@ -16,19 +16,6 @@ Returns the [NodePath] to the external [Skeleton3D] node, if one has been set. </description> </method> - <method name="get_override_mode" qualifiers="const" is_deprecated="true"> - <return type="int" /> - <description> - Deprecated. Local pose overrides will be removed. - Returns the override mode for the BoneAttachment3D node (0=global / 1=local). - </description> - </method> - <method name="get_override_pose" qualifiers="const"> - <return type="bool" /> - <description> - Returns whether the BoneAttachment3D node is overriding the bone pose of the bone it's attached to. - </description> - </method> <method name="get_use_external_skeleton" qualifiers="const"> <return type="bool" /> <description> @@ -49,21 +36,6 @@ Sets the [NodePath] to the external skeleton that the BoneAttachment3D node should use. The external [Skeleton3D] node is only used when [code]use_external_skeleton[/code] is set to [code]true[/code]. </description> </method> - <method name="set_override_mode" is_deprecated="true"> - <return type="void" /> - <param index="0" name="override_mode" type="int" /> - <description> - Deprecated. Local pose overrides will be removed. - Sets the override mode for the BoneAttachment3D node (0=global / 1=local). The override mode defines which of the bone poses the BoneAttachment3D node will override. - </description> - </method> - <method name="set_override_pose"> - <return type="void" /> - <param index="0" name="override_pose" type="bool" /> - <description> - Sets whether the BoneAttachment3D node will override the bone pose of the bone it is attached to. When set to [code]true[/code], the BoneAttachment3D node can change the pose of the bone. - </description> - </method> <method name="set_use_external_skeleton"> <return type="void" /> <param index="0" name="use_external_skeleton" type="bool" /> @@ -79,5 +51,8 @@ <member name="bone_name" type="String" setter="set_bone_name" getter="get_bone_name" default=""""> The name of the attached bone. </member> + <member name="override_pose" type="bool" setter="set_override_pose" getter="get_override_pose" default="false"> + Whether the BoneAttachment3D node will override the bone pose of the bone it is attached to. When set to [code]true[/code], the BoneAttachment3D node can change the pose of the bone. When set to [code]false[/code], the BoneAttachment3D will always be set to the bone's transform. + </member> </members> </class> diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml index d1fdaef29c..79e65f3472 100644 --- a/doc/classes/Callable.xml +++ b/doc/classes/Callable.xml @@ -14,7 +14,7 @@ func test(): var callable = Callable(self, "print_args") callable.call("hello", "world") # Prints "hello world ". - callable.call(Vector2.UP, 42, callable) # Prints "(0, -1) 42 Node(Node.gd)::print_args". + callable.call(Vector2.UP, 42, callable) # Prints "(0, -1) 42 Node(node.gd)::print_args". callable.call("invalid") # Invalid call, should have at least 2 arguments. [/gdscript] [csharp] diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index fbab1d76a0..e79bb97a92 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -95,11 +95,12 @@ <param index="0" name="from" type="Vector2" /> <param index="1" name="to" type="Vector2" /> <param index="2" name="color" type="Color" /> - <param index="3" name="width" type="float" default="1.0" /> + <param index="3" name="width" type="float" default="-1.0" /> <param index="4" name="dash" type="float" default="2.0" /> <param index="5" name="aligned" type="bool" default="true" /> <description> Draws a dashed line from a 2D point to another, with a given color and width. See also [method draw_multiline] and [method draw_polyline]. + If [param width] is negative, then a two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the line parts will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code]. </description> </method> <method name="draw_end_animation"> @@ -130,10 +131,11 @@ <param index="0" name="from" type="Vector2" /> <param index="1" name="to" type="Vector2" /> <param index="2" name="color" type="Color" /> - <param index="3" name="width" type="float" default="1.0" /> + <param index="3" name="width" type="float" default="-1.0" /> <param index="4" name="antialiased" type="bool" default="false" /> <description> Draws a line from a 2D point to another, with a given color and width. It can be optionally antialiased. See also [method draw_multiline] and [method draw_polyline]. + If [param width] is negative, then a two-point primitive will be drawn instead of a four-point one. This means that when the CanvasItem is scaled, the line will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code]. </description> </method> <method name="draw_mesh"> @@ -165,18 +167,20 @@ <return type="void" /> <param index="0" name="points" type="PackedVector2Array" /> <param index="1" name="color" type="Color" /> - <param index="2" name="width" type="float" default="1.0" /> + <param index="2" name="width" type="float" default="-1.0" /> <description> Draws multiple disconnected lines with a uniform [param color]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline] instead. + If [param width] is negative, then two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the lines will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code]. </description> </method> <method name="draw_multiline_colors"> <return type="void" /> <param index="0" name="points" type="PackedVector2Array" /> <param index="1" name="colors" type="PackedColorArray" /> - <param index="2" name="width" type="float" default="1.0" /> + <param index="2" name="width" type="float" default="-1.0" /> <description> Draws multiple disconnected lines with a uniform [param width] and segment-by-segment coloring. Colors assigned to line segments match by index between [param points] and [param colors]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline_colors] instead. + If [param width] is negative, then two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the lines will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code]. </description> </method> <method name="draw_multiline_string" qualifiers="const"> @@ -260,7 +264,6 @@ <param index="1" name="colors" type="PackedColorArray" /> <param index="2" name="uvs" type="PackedVector2Array" /> <param index="3" name="texture" type="Texture2D" default="null" /> - <param index="4" name="width" type="float" default="1.0" /> <description> Draws a custom primitive. 1 point for a point, 2 points for a line, 3 points for a triangle, and 4 points for a quad. If 0 points or more than 4 points are specified, nothing will be drawn and an error message will be printed. See also [method draw_line], [method draw_polyline], [method draw_polygon], and [method draw_rect]. </description> @@ -270,10 +273,12 @@ <param index="0" name="rect" type="Rect2" /> <param index="1" name="color" type="Color" /> <param index="2" name="filled" type="bool" default="true" /> - <param index="3" name="width" type="float" default="1.0" /> + <param index="3" name="width" type="float" default="-1.0" /> <description> Draws a rectangle. If [param filled] is [code]true[/code], the rectangle will be filled with the [param color] specified. If [param filled] is [code]false[/code], the rectangle will be drawn as a stroke with the [param color] and [param width] specified. + If [param width] is negative, then two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the lines will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code]. [b]Note:[/b] [param width] is only effective if [param filled] is [code]false[/code]. + [b]Note:[/b] Unfilled rectangles drawn with a negative [param width] may not display perfectly. For example, corners may be missing or brighter due to overlapping lines (for a translucent [param color]). </description> </method> <method name="draw_set_transform"> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 08964cf21d..75afb0cdbf 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -180,14 +180,14 @@ [codeblocks] [gdscript] func _make_custom_tooltip(for_text): - var tooltip = preload("res://SomeTooltipScene.tscn").instantiate() + var tooltip = preload("res://some_tooltip_scene.tscn").instantiate() tooltip.get_node("Label").text = for_text return tooltip [/gdscript] [csharp] public override Godot.Control _MakeCustomTooltip(String forText) { - Node tooltip = ResourceLoader.Load<PackedScene>("res://SomeTooltipScene.tscn").Instantiate(); + Node tooltip = ResourceLoader.Load<PackedScene>("res://some_tooltip_scene.tscn").Instantiate(); tooltip.GetNode<Label>("Label").Text = forText; return tooltip; } diff --git a/doc/classes/DTLSServer.xml b/doc/classes/DTLSServer.xml index 9af8be99ef..457513b8aa 100644 --- a/doc/classes/DTLSServer.xml +++ b/doc/classes/DTLSServer.xml @@ -8,7 +8,7 @@ Below a small example of how to use it: [codeblocks] [gdscript] - # ServerNode.gd + # server_node.gd extends Node var dtls := DTLSServer.new() @@ -86,7 +86,7 @@ [/codeblocks] [codeblocks] [gdscript] - # ClientNode.gd + # client_node.gd extends Node var dtls := PacketPeerDTLS.new() diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 5da6cf8102..1dc4dd3ff0 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -1694,7 +1694,10 @@ Use [method window_get_safe_title_margins] to determine area under the title bar that is not covered by decorations. [b]Note:[/b] This flag is implemented on macOS. </constant> - <constant name="WINDOW_FLAG_MAX" value="7" enum="WindowFlags"> + <constant name="WINDOW_FLAG_MOUSE_PASSTHROUGH" value="7" enum="WindowFlags"> + All mouse event as passed to the underlying window of the same application. + </constant> + <constant name="WINDOW_FLAG_MAX" value="8" enum="WindowFlags"> Max value of the [enum WindowFlags]. </constant> <constant name="WINDOW_EVENT_MOUSE_ENTER" value="0" enum="WindowEvent"> diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml index e8df6ae7fe..cddf3662aa 100644 --- a/doc/classes/EditorFileSystem.xml +++ b/doc/classes/EditorFileSystem.xml @@ -96,6 +96,11 @@ Emitted if at least one resource is reloaded when the filesystem is scanned. </description> </signal> + <signal name="script_classes_updated"> + <description> + Emitted when the list of global script classes gets updated. + </description> + </signal> <signal name="sources_changed"> <param index="0" name="exist" type="bool" /> <description> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index b44c1d7ffa..2124a97751 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -143,7 +143,7 @@ [gdscript] func _forward_canvas_draw_over_viewport(overlay): # Draw a circle at cursor position. - overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.white) + overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE) func _forward_canvas_gui_input(event): if event is InputEventMouseMotion: @@ -347,7 +347,7 @@ [codeblock] func _set_state(data): zoom = data.get("zoom", 1.0) - preferred_color = data.get("my_color", Color.white) + preferred_color = data.get("my_color", Color.WHITE) [/codeblock] </description> </method> @@ -359,7 +359,7 @@ [codeblock] func _set_window_layout(configuration): $Window.position = configuration.get_value("MyPlugin", "window_position", Vector2()) - $Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.white) + $Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.WHITE) [/codeblock] </description> </method> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 98f4789163..fca87f6a56 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -499,7 +499,7 @@ </member> <member name="interface/editor/editor_language" type="String" setter="" getter=""> The language to use for the editor interface. - Translations are provided by the community. If you spot a mistake, [url=https://docs.godotengine.org/en/latest/community/contributing/editor_and_docs_localization.html]contribute to editor translations on Weblate![/url] + Translations are provided by the community. If you spot a mistake, [url=$DOCS_URL/contributing/documentation/editor_and_docs_localization.html]contribute to editor translations on Weblate![/url] </member> <member name="interface/editor/expand_to_title" type="bool" setter="" getter=""> Expanding main editor window content to the title, if supported by [DisplayServer]. See [constant DisplayServer.WINDOW_FLAG_EXTEND_TO_TITLE]. @@ -741,7 +741,7 @@ </member> <member name="text_editor/behavior/indent/type" type="int" setter="" getter=""> The indentation style to use (tabs or spaces). - [b]Note:[/b] The [url=https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url] recommends using tabs for indentation. It is advised to change this setting only if you need to work on a project that currently uses spaces for indentation. + [b]Note:[/b] The [url=$DOCS_URL/getting_started/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url] recommends using tabs for indentation. It is advised to change this setting only if you need to work on a project that currently uses spaces for indentation. </member> <member name="text_editor/behavior/navigation/drag_and_drop_selection" type="bool" setter="" getter=""> If [code]true[/code], allows drag-and-dropping text in the script editor to move text. Disable this if you find yourself accidentally drag-and-dropping text in the script editor. @@ -782,7 +782,7 @@ If [code]true[/code], the code completion tooltip will appear below the current line unless there is no space on screen below the current line. If [code]false[/code], the code completion tooltip will appear above the current line. </member> <member name="text_editor/completion/use_single_quotes" type="bool" setter="" getter=""> - If [code]true[/code], performs string autocompletion with single quotes. If [code]false[/code], performs string autocompletion with double quotes (which matches the [url=https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url]). + If [code]true[/code], performs string autocompletion with single quotes. If [code]false[/code], performs string autocompletion with double quotes (which matches the [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url]). </member> <member name="text_editor/help/class_reference_examples" type="int" setter="" getter=""> Controls which multi-line code blocks should be displayed in the editor help. This setting does not affect single-line code literals in the editor help. diff --git a/doc/classes/EditorUndoRedoManager.xml b/doc/classes/EditorUndoRedoManager.xml index cd96e740e8..4d6938e6aa 100644 --- a/doc/classes/EditorUndoRedoManager.xml +++ b/doc/classes/EditorUndoRedoManager.xml @@ -1,5 +1,5 @@ <?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"> +<class name="EditorUndoRedoManager" inherits="Object" 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> diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml index 1ae4718536..127c5daf95 100644 --- a/doc/classes/GeometryInstance3D.xml +++ b/doc/classes/GeometryInstance3D.xml @@ -21,7 +21,10 @@ <param index="0" name="name" type="StringName" /> <param index="1" name="value" type="Variant" /> <description> - Set the value of a shader parameter for this instance only. + Set the value of a shader uniform for this instance only ([url=$DOCS_URL/tutorials/shaders/shader_reference/shading_language.html#per-instance-uniforms]per-instance uniform[/url]). See also [method ShaderMaterial.set_shader_parameter] to assign a uniform on all instances using the same [ShaderMaterial]. + [b]Note:[/b] For a shader uniform to be assignable on a per-instance basis, it [i]must[/i] be defined with [code]instance uniform ...[/code] rather than [code]uniform ...[/code] in the shader code. + [b]Note:[/b] [param name] is case-sensitive and must match the name of the uniform in the code exactly (not the capitalized name in the inspector). + [b]Note:[/b] Per-instance shader uniforms are currently only available in 3D, so there is no 2D equivalent of this method. </description> </method> </methods> diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index ed1b40488e..051e087611 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -489,7 +489,7 @@ var img = Image.new() img.create(img_width, img_height, false, Image.FORMAT_RGBA8) - img.set_pixel(1, 2, Color.red) # Sets the color at (1, 2) to red. + img.set_pixel(1, 2, Color.RED) # Sets the color at (1, 2) to red. [/gdscript] [csharp] int imgWidth = 10; @@ -517,7 +517,7 @@ var img = Image.new() img.create(img_width, img_height, false, Image.FORMAT_RGBA8) - img.set_pixelv(Vector2i(1, 2), Color.red) # Sets the color at (1, 2) to red. + img.set_pixelv(Vector2i(1, 2), Color.RED) # Sets the color at (1, 2) to red. [/gdscript] [csharp] int imgWidth = 10; diff --git a/doc/classes/JavaScriptBridge.xml b/doc/classes/JavaScriptBridge.xml index 340c296eef..f79c11b334 100644 --- a/doc/classes/JavaScriptBridge.xml +++ b/doc/classes/JavaScriptBridge.xml @@ -5,7 +5,7 @@ </brief_description> <description> The JavaScriptBridge singleton is implemented only in the Web export. It's used to access the browser's JavaScript context. This allows interaction with embedding pages or calling third-party JavaScript APIs. - [b]Note:[/b] This singleton can be disabled at build-time to improve security. By default, the JavaScriptBridge singleton is enabled. Official export templates also have the JavaScriptBridge singleton enabled. See [url=$DOCS_URL/development/compiling/compiling_for_web.html]Compiling for the Web[/url] in the documentation for more information. + [b]Note:[/b] This singleton can be disabled at build-time to improve security. By default, the JavaScriptBridge singleton is enabled. Official export templates also have the JavaScriptBridge singleton enabled. See [url=$DOCS_URL/contributing/development/compiling/compiling_for_web.html]Compiling for the Web[/url] in the documentation for more information. </description> <tutorials> <link title="Exporting for the Web: Calling JavaScript from script">$DOCS_URL/tutorials/export/exporting_for_web.html#calling-javascript-from-script</link> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index e015bec134..a9e17f4666 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -24,6 +24,7 @@ [b]Note:[/b] The [code]script[/code] is not exposed like most properties. To set or get an object's [Script] in code, use [method set_script] and [method get_script], respectively. </description> <tutorials> + <link title="Object class introduction">$DOCS_URL/contributing/development/core_and_modules/object_class.html</link> <link title="When and how to avoid using nodes for everything">$DOCS_URL/tutorials/best_practices/node_alternatives.html</link> <link title="Object notifications">$DOCS_URL/tutorials/best_practices/godot_notifications.html</link> </tutorials> diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml index fbe8afa8d1..aa09081e3e 100644 --- a/doc/classes/Plane.xml +++ b/doc/classes/Plane.xml @@ -38,6 +38,7 @@ <param index="0" name="normal" type="Vector3" /> <description> Creates a plane from the normal vector. The plane will intersect the origin. + The [param normal] of the plane must be a unit vector. </description> </constructor> <constructor name="Plane"> @@ -46,6 +47,7 @@ <param index="1" name="d" type="float" /> <description> Creates a plane from the normal vector and the plane's distance from the origin. + The [param normal] of the plane must be a unit vector. </description> </constructor> <constructor name="Plane"> @@ -54,6 +56,7 @@ <param index="1" name="point" type="Vector3" /> <description> Creates a plane from the normal vector and a point on the plane. + The [param normal] of the plane must be a unit vector. </description> </constructor> <constructor name="Plane"> @@ -67,12 +70,6 @@ </constructor> </constructors> <methods> - <method name="center" qualifiers="const"> - <return type="Vector3" /> - <description> - Returns the center of the plane. - </description> - </method> <method name="distance_to" qualifiers="const"> <return type="float" /> <param index="0" name="point" type="Vector3" /> @@ -80,6 +77,12 @@ Returns the shortest distance from the plane to the position [param point]. If the point is above the plane, the distance will be positive. If below, the distance will be negative. </description> </method> + <method name="get_center" qualifiers="const"> + <return type="Vector3" /> + <description> + Returns the center of the plane. + </description> + </method> <method name="has_point" qualifiers="const"> <return type="bool" /> <param index="0" name="point" type="Vector3" /> @@ -152,7 +155,7 @@ In the scalar equation of the plane [code]ax + by + cz = d[/code], this is [code]d[/code], while the [code](a, b, c)[/code] coordinates are represented by the [member normal] property. </member> <member name="normal" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)"> - The normal of the plane, which must be normalized. + The normal of the plane, which must be a unit vector. In the scalar equation of the plane [code]ax + by + cz = d[/code], this is the vector [code](a, b, c)[/code], where [code]d[/code] is the [member d] property. </member> <member name="x" type="float" setter="" getter="" default="0.0"> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index cfcfca9880..9e1c751662 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -84,6 +84,25 @@ GD.Print(ProjectSettings.GetSetting("application/config/custom_description", "No description specified.")); [/csharp] [/codeblocks] + [b]Note:[/b] This method doesn't take potential feature overrides into account automatically. Use [method get_setting_with_override] to handle seamlessly. + </description> + </method> + <method name="get_setting_with_override" qualifiers="const"> + <return type="Variant" /> + <param index="0" name="name" type="StringName" /> + <description> + Similar to [method get_setting], but applies feature tag overrides if any exists and is valid. + [b]Example:[/b] + If the following setting override exists "application/config/name.windows", and the following code is executed: + [codeblocks] + [gdscript] + print(ProjectSettings.get_setting_with_override("application/config/name")) + [/gdscript] + [csharp] + GD.Print(ProjectSettings.GetSettingWithOverride("application/config/name")); + [/csharp] + [/codeblocks] + Then the overridden setting will be returned instead if the project is running on the [i]Windows[/i] operating system. </description> </method> <method name="globalize_path" qualifiers="const"> @@ -741,6 +760,9 @@ <member name="gui/theme/lcd_subpixel_layout" type="int" setter="" getter="" default="1"> LCD subpixel layout used for font anti-aliasing. See [enum TextServer.FontLCDSubpixelLayout]. </member> + <member name="gui/timers/button_shortcut_feedback_highlight_time" type="float" setter="" getter="" default="0.2"> + When [member BaseButton.shortcut_feedback] is enabled, this is the time the [BaseButton] will remain highlighted after a shortcut. + </member> <member name="gui/timers/incremental_search_max_interval_msec" type="int" setter="" getter="" default="2000"> Timer setting for incremental search in [Tree], [ItemList], etc. controls (in milliseconds). </member> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 7675a37cbd..32281953b2 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -217,7 +217,7 @@ <param index="1" name="from" type="Vector2" /> <param index="2" name="to" type="Vector2" /> <param index="3" name="color" type="Color" /> - <param index="4" name="width" type="float" default="1.0" /> + <param index="4" name="width" type="float" default="-1.0" /> <param index="5" name="antialiased" type="bool" default="false" /> <description> </description> @@ -303,7 +303,6 @@ <param index="2" name="colors" type="PackedColorArray" /> <param index="3" name="uvs" type="PackedVector2Array" /> <param index="4" name="texture" type="RID" /> - <param index="5" name="width" type="float" default="1.0" /> <description> </description> </method> diff --git a/doc/classes/ResourcePreloader.xml b/doc/classes/ResourcePreloader.xml index 17904697e6..5c0079f408 100644 --- a/doc/classes/ResourcePreloader.xml +++ b/doc/classes/ResourcePreloader.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="ResourcePreloader" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> - Resource Preloader Node. + Preloads a list of resources inside a scene. </brief_description> <description> - This node is used to preload sub-resources inside a scene, so when the scene is loaded, all the resources are ready to use and can be retrieved from the preloader. + This node is used to preload sub-resources inside a scene, so when the scene is loaded, all the resources are ready to use and can be retrieved from the preloader. You can add the resources using the ResourcePreloader tab when the node is selected. GDScript has a simplified [method @GDScript.preload] built-in method which can be used in most situations, leaving the use of [ResourcePreloader] for more advanced scenarios. </description> <tutorials> diff --git a/doc/classes/ShaderMaterial.xml b/doc/classes/ShaderMaterial.xml index 1af7ac4fc5..a2346822e5 100644 --- a/doc/classes/ShaderMaterial.xml +++ b/doc/classes/ShaderMaterial.xml @@ -23,7 +23,8 @@ <param index="1" name="value" type="Variant" /> <description> Changes the value set for this material of a uniform in the shader. - [b]Note:[/b] [param param] must match the name of the uniform in the code exactly. + [b]Note:[/b] [param param] is case-sensitive and must match the name of the uniform in the code exactly (not the capitalized name in the inspector). + [b]Note:[/b] Changes to the shader uniform will be effective on all instances using this [ShaderMaterial]. To prevent this, use per-instance uniforms with [method GeometryInstance3D.set_instance_shader_parameter] or duplicate the [ShaderMaterial] resource using [method Resource.duplicate]. Per-instance uniforms allow for better shader reuse and are therefore faster, so they should be preferred over duplicating the [ShaderMaterial] when possible. </description> </method> </methods> diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml index 3bd0e04b92..70986ba06a 100644 --- a/doc/classes/Skeleton3D.xml +++ b/doc/classes/Skeleton3D.xml @@ -7,6 +7,7 @@ Skeleton3D provides a hierarchical interface for managing bones, including pose, rest and animation (see [Animation]). It can also use ragdoll physics. The overall transform of a bone with respect to the skeleton is determined by the following hierarchical order: rest pose, custom pose and pose. Note that "global pose" below refers to the overall transform of the bone with respect to skeleton, so it not the actual global/world transform of the bone. + To setup different types of inverse kinematics, consider using [SkeletonIK3D], or add a custom IK implementation in [method Node._process] as a child node. </description> <tutorials> <link title="3D Inverse Kinematics Demo">https://godotengine.org/asset-library/asset/523</link> @@ -32,26 +33,11 @@ Removes the global pose override on all bones in the skeleton. </description> </method> - <method name="clear_bones_local_pose_override" is_deprecated="true"> - <return type="void" /> - <description> - Deprecated. Local pose overrides will be removed. - Removes the local pose override on all bones in the skeleton. - </description> - </method> <method name="create_skin_from_rest_transforms"> <return type="Skin" /> <description> </description> </method> - <method name="execute_modifications" is_deprecated="true"> - <return type="void" /> - <param index="0" name="delta" type="float" /> - <param index="1" name="execution_mode" type="int" /> - <description> - Executes all the modifications on the [SkeletonModificationStack3D], if the Skeleton3D has one assigned. - </description> - </method> <method name="find_bone" qualifiers="const"> <return type="int" /> <param index="0" name="name" type="String" /> @@ -113,13 +99,6 @@ Returns the global rest transform for [param bone_idx]. </description> </method> - <method name="get_bone_local_pose_override" qualifiers="const"> - <return type="Transform3D" /> - <param index="0" name="bone_idx" type="int" /> - <description> - Returns the local pose override transform for [param bone_idx]. - </description> - </method> <method name="get_bone_name" qualifiers="const"> <return type="String" /> <param index="0" name="bone_idx" type="int" /> @@ -167,43 +146,18 @@ Returns the rest transform for a bone [param bone_idx]. </description> </method> - <method name="get_modification_stack" is_deprecated="true"> - <return type="SkeletonModificationStack3D" /> - <description> - Returns the modification stack attached to this skeleton, if one exists. - </description> - </method> <method name="get_parentless_bones" qualifiers="const"> <return type="PackedInt32Array" /> <description> Returns an array with all of the bones that are parentless. Another way to look at this is that it returns the indexes of all the bones that are not dependent or modified by other bones in the Skeleton. </description> </method> - <method name="global_pose_to_local_pose" is_deprecated="true"> - <return type="Transform3D" /> - <param index="0" name="bone_idx" type="int" /> - <param index="1" name="global_pose" type="Transform3D" /> - <description> - Takes the passed-in global pose and converts it to local pose transform. - This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform in [method set_bone_local_pose_override]. - </description> - </method> - <method name="global_pose_to_world_transform" is_deprecated="true"> - <return type="Transform3D" /> - <param index="0" name="global_pose" type="Transform3D" /> - <description> - Deprecated. Use [Node3D] apis instead. - Takes the passed-in global pose and converts it to a world transform. - This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform usable with a node's transform, like [member Node3D.global_transform] for example. - </description> - </method> - <method name="global_pose_z_forward_to_bone_forward" is_deprecated="true"> - <return type="Basis" /> - <param index="0" name="bone_idx" type="int" /> - <param index="1" name="basis" type="Basis" /> + <method name="get_version" qualifiers="const"> + <return type="int" /> <description> - Rotates the given [Basis] so that the forward axis of the Basis is facing in the forward direction of the bone at [param bone_idx]. - This is helper function to make using [method Transform3D.looking_at] easier with bone poses. + Returns the number of times the bone hierarchy has changed within this skeleton, including renames. + The Skeleton version is not serialized: only use within a single instance of Skeleton3D. + Use for invalidating caches in IK solvers and other nodes which process bones. </description> </method> <method name="is_bone_enabled" qualifiers="const"> @@ -213,15 +167,6 @@ Returns whether the bone pose for the bone at [param bone_idx] is enabled. </description> </method> - <method name="local_pose_to_global_pose" is_deprecated="true"> - <return type="Transform3D" /> - <param index="0" name="bone_idx" type="int" /> - <param index="1" name="local_pose" type="Transform3D" /> - <description> - Converts the passed-in local pose to a global pose relative to the inputted bone, [param bone_idx]. - This could be used to convert [method get_bone_pose] for use with the [method set_bone_global_pose_override] function. - </description> - </method> <method name="localize_rests"> <return type="void" /> <description> @@ -298,19 +243,6 @@ [b]Note:[/b] The pose transform needs to be a global pose! To convert a world transform from a [Node3D] to a global bone pose, multiply the [method Transform3D.affine_inverse] of the node's [member Node3D.global_transform] by the desired world transform </description> </method> - <method name="set_bone_local_pose_override" is_deprecated="true"> - <return type="void" /> - <param index="0" name="bone_idx" type="int" /> - <param index="1" name="pose" type="Transform3D" /> - <param index="2" name="amount" type="float" /> - <param index="3" name="persistent" type="bool" default="false" /> - <description> - Deprecated. Local pose overrides will be removed. - Sets the local pose transform, [param pose], for the bone at [param bone_idx]. - [param amount] is the interpolation strength that will be used when applying the pose, and [param persistent] determines if the applied pose will remain. - [b]Note:[/b] The pose transform needs to be a local pose! Use [method global_pose_to_local_pose] to convert a global pose to a local pose. - </description> - </method> <method name="set_bone_name"> <return type="void" /> <param index="0" name="bone_idx" type="int" /> @@ -356,13 +288,6 @@ Sets the rest transform for bone [param bone_idx]. </description> </method> - <method name="set_modification_stack" is_deprecated="true"> - <return type="void" /> - <param index="0" name="modification_stack" type="SkeletonModificationStack3D" /> - <description> - Sets the modification stack for this skeleton to the passed-in modification stack, [param modification_stack]. - </description> - </method> <method name="unparent_bone_and_rest"> <return type="void" /> <param index="0" name="bone_idx" type="int" /> @@ -370,15 +295,6 @@ Unparents the bone at [param bone_idx] and sets its rest position to that of its parent prior to being reset. </description> </method> - <method name="world_transform_to_global_pose" is_deprecated="true"> - <return type="Transform3D" /> - <param index="0" name="world_transform" type="Transform3D" /> - <description> - Deprecated. Use [Node3D] apis instead. - Takes the passed-in global transform and converts it to a global pose. - This can be used to easily convert a global transform from [member Node3D.global_transform] to a global pose usable with [method set_bone_global_pose_override], for example. - </description> - </method> </methods> <members> <member name="animate_physical_bones" type="bool" setter="set_animate_physical_bones" getter="get_animate_physical_bones" default="true"> diff --git a/doc/classes/SkeletonModification3D.xml b/doc/classes/SkeletonModification3D.xml deleted file mode 100644 index 25431ea96f..0000000000 --- a/doc/classes/SkeletonModification3D.xml +++ /dev/null @@ -1,66 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="SkeletonModification3D" inherits="Resource" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> - <brief_description> - A resource that operates on bones in a [Skeleton3D]. - </brief_description> - <description> - This resource provides an interface that can be expanded so code that operates on bones in a [Skeleton3D] can be mixed and matched together to create complex interactions. - This is used to provide Godot with a flexible and powerful Inverse Kinematics solution that can be adapted for many different uses. - </description> - <tutorials> - </tutorials> - <methods> - <method name="_execute" qualifiers="virtual"> - <return type="void" /> - <param index="0" name="delta" type="float" /> - <description> - Executes the given modification. This is where the modification performs whatever function it is designed to do. - </description> - </method> - <method name="_setup_modification" qualifiers="virtual"> - <return type="void" /> - <param index="0" name="modification_stack" type="SkeletonModificationStack3D" /> - <description> - Sets up the modification so it can be executed. This function should be called automatically by the [SkeletonModificationStack3D] containing this modification. - If you need to initialize a modification before use, this is the place to do it! - </description> - </method> - <method name="clamp_angle"> - <return type="float" /> - <param index="0" name="angle" type="float" /> - <param index="1" name="min" type="float" /> - <param index="2" name="max" type="float" /> - <param index="3" name="invert" type="bool" /> - <description> - Takes a angle and clamps it so it is within the passed-in [param min] and [param max] range. [param invert] will inversely clamp the angle, clamping it to the range outside of the given bounds. - </description> - </method> - <method name="get_is_setup" qualifiers="const"> - <return type="bool" /> - <description> - Returns whether this modification has been successfully setup or not. - </description> - </method> - <method name="get_modification_stack"> - <return type="SkeletonModificationStack3D" /> - <description> - Returns the [SkeletonModificationStack3D] that this modification is bound to. Through the modification stack, you can access the Skeleton3D the modification is operating on. - </description> - </method> - <method name="set_is_setup"> - <return type="void" /> - <param index="0" name="is_setup" type="bool" /> - <description> - Manually allows you to set the setup state of the modification. This function should only rarely be used, as the [SkeletonModificationStack3D] the modification is bound to should handle setting the modification up. - </description> - </method> - </methods> - <members> - <member name="enabled" type="bool" setter="set_enabled" getter="get_enabled" default="true"> - When true, the modification's [method _execute] function will be called by the [SkeletonModificationStack3D]. - </member> - <member name="execution_mode" type="int" setter="set_execution_mode" getter="get_execution_mode" default="0"> - The execution mode for the modification. This tells the modification stack when to execute the modification. Some modifications have settings that are only available in certain execution modes. - </member> - </members> -</class> diff --git a/doc/classes/SkeletonModification3DCCDIK.xml b/doc/classes/SkeletonModification3DCCDIK.xml deleted file mode 100644 index 90b2e78449..0000000000 --- a/doc/classes/SkeletonModification3DCCDIK.xml +++ /dev/null @@ -1,136 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="SkeletonModification3DCCDIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> - <brief_description> - A modification that uses CCDIK to manipulate a series of bones to reach a target. - </brief_description> - <description> - This [SkeletonModification3D] uses an algorithm called Cyclic Coordinate Descent Inverse Kinematics, or CCDIK, to manipulate a chain of bones in a Skeleton so it reaches a defined target. - CCDIK works by rotating a set of bones, typically called a "bone chain", on a single axis. Each bone is rotated to face the target from the tip (by default), which over a chain of bones allow it to rotate properly to reach the target. Because the bones only rotate on a single axis, CCDIK [i]can[/i] look more robotic than other IK solvers. - [b]Note:[/b] The CCDIK modifier has [code]ccdik_joints[/code], which are the data objects that hold the data for each joint in the CCDIK chain. This is different from a bone! CCDIK joints hold the data needed for each bone in the bone chain used by CCDIK. - CCDIK also fully supports angle constraints, allowing for more control over how a solution is met. - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_ccdik_joint_bone_index" qualifiers="const"> - <return type="int" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the bone index of the bone assigned to the CCDIK joint at [param joint_idx]. - </description> - </method> - <method name="get_ccdik_joint_bone_name" qualifiers="const"> - <return type="String" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the name of the bone that is assigned to the CCDIK joint at [param joint_idx]. - </description> - </method> - <method name="get_ccdik_joint_ccdik_axis" qualifiers="const"> - <return type="int" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the integer representing the joint axis of the CCDIK joint at [param joint_idx]. - </description> - </method> - <method name="get_ccdik_joint_constraint_angle_max" qualifiers="const"> - <return type="float" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the maximum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle is in degrees! - </description> - </method> - <method name="get_ccdik_joint_constraint_angle_min" qualifiers="const"> - <return type="float" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the minimum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle is in degrees! - </description> - </method> - <method name="get_ccdik_joint_constraint_invert" qualifiers="const"> - <return type="bool" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns whether the CCDIK joint at [param joint_idx] uses an inverted joint constraint. See [method set_ccdik_joint_constraint_invert] for details. - </description> - </method> - <method name="get_ccdik_joint_enable_joint_constraint" qualifiers="const"> - <return type="bool" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Enables angle constraints to the CCDIK joint at [param joint_idx]. - </description> - </method> - <method name="set_ccdik_joint_bone_index"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="bone_index" type="int" /> - <description> - Sets the bone index, [param bone_index], of the CCDIK joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the CCDIK joint based on data provided by the linked skeleton. - </description> - </method> - <method name="set_ccdik_joint_bone_name"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="bone_name" type="String" /> - <description> - Sets the bone name, [param bone_name], of the CCDIK joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the CCDIK joint based on data provided by the linked skeleton. - </description> - </method> - <method name="set_ccdik_joint_ccdik_axis"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="axis" type="int" /> - <description> - Sets the joint axis of the CCDIK joint at [param joint_idx] to the passed-in joint axis, [param axis]. - </description> - </method> - <method name="set_ccdik_joint_constraint_angle_max"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="max_angle" type="float" /> - <description> - Sets the maximum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle must be in radians! - </description> - </method> - <method name="set_ccdik_joint_constraint_angle_min"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="min_angle" type="float" /> - <description> - Sets the minimum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle must be in radians! - </description> - </method> - <method name="set_ccdik_joint_constraint_invert"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="invert" type="bool" /> - <description> - Sets whether the CCDIK joint at [param joint_idx] uses an inverted joint constraint. - An inverted joint constraint only constraints the CCDIK joint to the angles [i]outside of[/i] the inputted minimum and maximum angles. For this reason, it is referred to as an inverted joint constraint, as it constraints the joint to the outside of the inputted values. - </description> - </method> - <method name="set_ccdik_joint_enable_joint_constraint"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="enable" type="bool" /> - <description> - Sets whether joint constraints are enabled for the CCDIK joint at [param joint_idx]. - </description> - </method> - </methods> - <members> - <member name="ccdik_data_chain_length" type="int" setter="set_ccdik_data_chain_length" getter="get_ccdik_data_chain_length" default="0"> - The number of CCDIK joints in the CCDIK modification. - </member> - <member name="high_quality_solve" type="bool" setter="set_use_high_quality_solve" getter="get_use_high_quality_solve" default="true"> - When true, the CCDIK algorithm will perform a higher quality solve that returns more natural results. A high quality solve requires more computation power to solve though, and therefore can be disabled to save performance. - </member> - <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath("")"> - The NodePath to the node that is the target for the CCDIK modification. This node is what the CCDIK chain will attempt to rotate the bone chain to. - </member> - <member name="tip_nodepath" type="NodePath" setter="set_tip_node" getter="get_tip_node" default="NodePath("")"> - The end position of the CCDIK chain. Typically, this should be a child of a [BoneAttachment3D] node attached to the final bone in the CCDIK chain, where the child node is offset so it is at the end of the final bone. - </member> - </members> -</class> diff --git a/doc/classes/SkeletonModification3DFABRIK.xml b/doc/classes/SkeletonModification3DFABRIK.xml deleted file mode 100644 index a2bec2b559..0000000000 --- a/doc/classes/SkeletonModification3DFABRIK.xml +++ /dev/null @@ -1,161 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="SkeletonModification3DFABRIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> - <brief_description> - A modification that uses FABRIK to manipulate a series of bones to reach a target. - </brief_description> - <description> - This [SkeletonModification3D] uses an algorithm called Forward And Backward Reaching Inverse Kinematics, or FABRIK, to rotate a bone chain so that it reaches a target. - FABRIK works by knowing the positions and lengths of a series of bones, typically called a "bone chain". It first starts by running a forward pass, which places the final bone at the target's position. Then all other bones are moved towards the tip bone, so they stay at the defined bone length away. Then a backwards pass is performed, where the root/first bone in the FABRIK chain is placed back at the origin. then all other bones are moved so they stay at the defined bone length away. This positions the bone chain so that it reaches the target when possible, but all of the bones stay the correct length away from each other. - Because of how FABRIK works, it often gives more natural results than those seen in [SkeletonModification3DCCDIK], though FABRIK currently does not support joint constraints. - [b]Note:[/b] The FABRIK modifier has [code]fabrik_joints[/code], which are the data objects that hold the data for each joint in the FABRIK chain. This is different from a bone! FABRIK joints hold the data needed for each bone in the bone chain used by FABRIK. - To help control how the FABRIK joints move, a magnet vector can be passed, which can nudge the bones in a certain direction prior to solving, giving a level of control over the final result. - </description> - <tutorials> - </tutorials> - <methods> - <method name="fabrik_joint_auto_calculate_length"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Will attempt to automatically calculate the length of the bone assigned to the FABRIK joint at [param joint_idx]. - </description> - </method> - <method name="get_fabrik_joint_auto_calculate_length" qualifiers="const"> - <return type="bool" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns a boolean that indicates whether this modification will attempt to autocalculate the length of the bone assigned to the FABRIK joint at [param joint_idx]. - </description> - </method> - <method name="get_fabrik_joint_bone_index" qualifiers="const"> - <return type="int" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the bone index of the bone assigned to the FABRIK joint at [param joint_idx]. - </description> - </method> - <method name="get_fabrik_joint_bone_name" qualifiers="const"> - <return type="String" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the name of the bone that is assigned to the FABRIK joint at [param joint_idx]. - </description> - </method> - <method name="get_fabrik_joint_length" qualifiers="const"> - <return type="float" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the length of the FABRIK joint at [param joint_idx]. - </description> - </method> - <method name="get_fabrik_joint_magnet" qualifiers="const"> - <return type="Vector3" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the magnet vector of the FABRIK joint at [param joint_idx]. - </description> - </method> - <method name="get_fabrik_joint_tip_node" qualifiers="const"> - <return type="NodePath" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the [Node3D]-based node placed at the tip of the FABRIK joint at [param joint_idx], if one has been set. - </description> - </method> - <method name="get_fabrik_joint_use_target_basis" qualifiers="const"> - <return type="bool" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns a boolean indicating whether the FABRIK joint uses the target's [Basis] for its rotation. - [b]Note:[/b] This option is only available for the final bone in the FABRIK chain, with this setting being ignored for all other bones. - </description> - </method> - <method name="get_fabrik_joint_use_tip_node" qualifiers="const"> - <return type="bool" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Sets the [Node3D]-based node that will be used as the tip of the FABRIK joint at [param joint_idx]. - </description> - </method> - <method name="set_fabrik_joint_auto_calculate_length"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="auto_calculate_length" type="bool" /> - <description> - When [code]true[/code], this modification will attempt to automatically calculate the length of the bone for the FABRIK joint at [param joint_idx]. It does this by either using the tip node assigned, if there is one assigned, or the distance the of the bone's children, if the bone has any. If the bone has no children and no tip node is assigned, then the modification [b]cannot[/b] autocalculate the joint's length. In this case, the joint length should be entered manually or a tip node assigned. - </description> - </method> - <method name="set_fabrik_joint_bone_index"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="bone_index" type="int" /> - <description> - Sets the bone index, [param bone_index], of the FABRIK joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the FABRIK joint based on data provided by the [Skeleton3D]. - </description> - </method> - <method name="set_fabrik_joint_bone_name"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="bone_name" type="String" /> - <description> - Sets the bone name, [param bone_name], of the FABRIK joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the FABRIK joint based on data provided by the [Skeleton3D]. - </description> - </method> - <method name="set_fabrik_joint_length"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="length" type="float" /> - <description> - Sets the joint length, [param length], of the FABRIK joint at [param joint_idx]. - </description> - </method> - <method name="set_fabrik_joint_magnet"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="magnet_position" type="Vector3" /> - <description> - Sets the magenet position to [param magnet_position] for the joint at [param joint_idx]. The magnet position is used to nudge the joint in that direction when solving, which gives some control over how that joint will bend when being solved. - </description> - </method> - <method name="set_fabrik_joint_tip_node"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="tip_node" type="NodePath" /> - <description> - Sets the nodepath of the FARIK joint at [param joint_idx] to [param tip_node]. The tip node is used to calculate the length of the FABRIK joint when set to automatically calculate joint length. - [b]Note:[/b] The tip node should generally be a child node of a [BoneAttachment3D] node attached to the bone that this FABRIK joint operates on, with the child node being offset so it is at the end of the bone. - </description> - </method> - <method name="set_fabrik_joint_use_target_basis"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="use_target_basis" type="bool" /> - <description> - Sets whether the FABRIK joint at [param joint_idx] uses the target's [Basis] for its rotation. - [b]Note:[/b] This option is only available for the final bone in the FABRIK chain, with this setting being ignored for all other bones. - </description> - </method> - <method name="set_fabrik_joint_use_tip_node"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="use_tip_node" type="bool" /> - <description> - Sets whether the tip node should be used when autocalculating the joint length for the FABRIK joint at [param joint_idx]. This will only work if there is a node assigned to the tip nodepath for this joint. - </description> - </method> - </methods> - <members> - <member name="chain_max_iterations" type="int" setter="set_chain_max_iterations" getter="get_chain_max_iterations" default="10"> - The number of times FABRIK will try to solve each time the [code]execute[/code] function is called. Setting this value to a lower number will be result in better performance, but this can also result in harsher movements and slower solves. - </member> - <member name="chain_tolerance" type="float" setter="set_chain_tolerance" getter="get_chain_tolerance" default="0.01"> - The minimum distance the target has to be from the tip of the final bone in the bone chain. Setting this value to a higher number allows for greater performance, but less accurate solves. - </member> - <member name="fabrik_data_chain_length" type="int" setter="set_fabrik_data_chain_length" getter="get_fabrik_data_chain_length" default="0"> - The amount of FABRIK joints in the FABRIK modification. - </member> - <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath("")"> - The NodePath to the node that is the target for the FABRIK modification. This node is what the FABRIK chain will attempt to rotate the bone chain to. - </member> - </members> -</class> diff --git a/doc/classes/SkeletonModification3DJiggle.xml b/doc/classes/SkeletonModification3DJiggle.xml deleted file mode 100644 index 304f08bb20..0000000000 --- a/doc/classes/SkeletonModification3DJiggle.xml +++ /dev/null @@ -1,199 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="SkeletonModification3DJiggle" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> - <brief_description> - A modification that jiggles bones as they move towards a target. - </brief_description> - <description> - This modification moves a series of bones, typically called a bone chain, towards a target. What makes this modification special is that it calculates the velocity and acceleration for each bone in the bone chain, and runs a very light physics-like calculation using the inputted values. This allows the bones to overshoot the target and "jiggle" around. It can be configured to act more like a spring, or sway around like cloth might. - This modification is useful for adding additional motion to things like hair, the edges of clothing, and more. It has several settings to that allow control over how the joint moves when the target moves. - [b]Note:[/b] The Jiggle modifier has [code]jiggle_joints[/code], which are the data objects that hold the data for each joint in the Jiggle chain. This is different from a bone! Jiggle joints hold the data needed for each bone in the bone chain used by the Jiggle modification. - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_collision_mask" qualifiers="const"> - <return type="int" /> - <description> - Returns the collision mask that the Jiggle modifier will take into account when performing physics calculations. - </description> - </method> - <method name="get_jiggle_joint_bone_index" qualifiers="const"> - <return type="int" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the bone index of the bone assigned to the Jiggle joint at [param joint_idx]. - </description> - </method> - <method name="get_jiggle_joint_bone_name" qualifiers="const"> - <return type="String" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the name of the bone that is assigned to the Jiggle joint at [param joint_idx]. - </description> - </method> - <method name="get_jiggle_joint_damping" qualifiers="const"> - <return type="float" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the amount of dampening of the Jiggle joint at [param joint_idx]. - </description> - </method> - <method name="get_jiggle_joint_gravity" qualifiers="const"> - <return type="Vector3" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns a [Vector3] representign the amount of gravity the Jiggle joint at [param joint_idx] is influenced by. - </description> - </method> - <method name="get_jiggle_joint_mass" qualifiers="const"> - <return type="float" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the amount of mass of the Jiggle joint at [param joint_idx]. - </description> - </method> - <method name="get_jiggle_joint_override" qualifiers="const"> - <return type="bool" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns a boolean that indicates whether the joint at [param joint_idx] is overriding the default jiggle joint data defined in the modification. - </description> - </method> - <method name="get_jiggle_joint_roll" qualifiers="const"> - <return type="float" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the amount of roll/twist applied to the bone that the Jiggle joint is applied to. - </description> - </method> - <method name="get_jiggle_joint_stiffness" qualifiers="const"> - <return type="float" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns the stiffness of the Jiggle joint at [param joint_idx]. - </description> - </method> - <method name="get_jiggle_joint_use_gravity" qualifiers="const"> - <return type="bool" /> - <param index="0" name="joint_idx" type="int" /> - <description> - Returns a boolean that indicates whether the joint at [param joint_idx] is using gravity or not. - </description> - </method> - <method name="get_use_colliders" qualifiers="const"> - <return type="bool" /> - <description> - Returns whether the Jiggle modifier is taking physics colliders into account when solving. - </description> - </method> - <method name="set_collision_mask"> - <return type="void" /> - <param index="0" name="mask" type="int" /> - <description> - Sets the collision mask that the Jiggle modifier takes into account when performing physics calculations. - </description> - </method> - <method name="set_jiggle_joint_bone_index"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="bone_idx" type="int" /> - <description> - Sets the bone index, [param bone_idx], of the Jiggle joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the Jiggle joint based on data provided by the [Skeleton3D]. - </description> - </method> - <method name="set_jiggle_joint_bone_name"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="name" type="String" /> - <description> - Sets the bone name, [param name], of the Jiggle joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the Jiggle joint based on data provided by the [Skeleton3D]. - </description> - </method> - <method name="set_jiggle_joint_damping"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="damping" type="float" /> - <description> - Sets the amount of dampening of the Jiggle joint at [param joint_idx]. - </description> - </method> - <method name="set_jiggle_joint_gravity"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="gravity" type="Vector3" /> - <description> - Sets the gravity vector of the Jiggle joint at [param joint_idx]. - </description> - </method> - <method name="set_jiggle_joint_mass"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="mass" type="float" /> - <description> - Sets the of mass of the Jiggle joint at [param joint_idx]. - </description> - </method> - <method name="set_jiggle_joint_override"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="override" type="bool" /> - <description> - Sets whether the Jiggle joint at [param joint_idx] should override the default Jiggle joint settings. Setting this to true will make the joint use its own settings rather than the default ones attached to the modification. - </description> - </method> - <method name="set_jiggle_joint_roll"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="roll" type="float" /> - <description> - Sets the amount of roll/twist on the bone the Jiggle joint is attached to. - </description> - </method> - <method name="set_jiggle_joint_stiffness"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="stiffness" type="float" /> - <description> - Sets the of stiffness of the Jiggle joint at [param joint_idx]. - </description> - </method> - <method name="set_jiggle_joint_use_gravity"> - <return type="void" /> - <param index="0" name="joint_idx" type="int" /> - <param index="1" name="use_gravity" type="bool" /> - <description> - Sets whether the Jiggle joint at [param joint_idx] should use gravity. - </description> - </method> - <method name="set_use_colliders"> - <return type="void" /> - <param index="0" name="use_colliders" type="bool" /> - <description> - When [code]true[/code], the Jiggle modifier will use raycasting to prevent the Jiggle joints from rotating themselves into collision objects when solving. - </description> - </method> - </methods> - <members> - <member name="damping" type="float" setter="set_damping" getter="get_damping" default="0.75"> - The default amount of dampening applied to the Jiggle joints, if they are not overridden. Higher values lead to more of the calculated velocity being applied. - </member> - <member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3(0, -6, 0)"> - The default amount of gravity applied to the Jiggle joints, if they are not overridden. - </member> - <member name="jiggle_data_chain_length" type="int" setter="set_jiggle_data_chain_length" getter="get_jiggle_data_chain_length" default="0"> - The amount of Jiggle joints in the Jiggle modification. - </member> - <member name="mass" type="float" setter="set_mass" getter="get_mass" default="0.75"> - The default amount of mass assigned to the Jiggle joints, if they are not overridden. Higher values lead to faster movements and more overshooting. - </member> - <member name="stiffness" type="float" setter="set_stiffness" getter="get_stiffness" default="3.0"> - The default amount of stiffness assigned to the Jiggle joints, if they are not overridden. Higher values act more like springs, quickly moving into the correct position. - </member> - <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath("")"> - The NodePath to the node that is the target for the Jiggle modification. This node is what the Jiggle chain will attempt to rotate the bone chain to. - </member> - <member name="use_gravity" type="bool" setter="set_use_gravity" getter="get_use_gravity" default="false"> - Whether the gravity vector, [member gravity], should be applied to the Jiggle joints, assuming they are not overriding the default settings. - </member> - </members> -</class> diff --git a/doc/classes/SkeletonModification3DLookAt.xml b/doc/classes/SkeletonModification3DLookAt.xml deleted file mode 100644 index aeed953ca9..0000000000 --- a/doc/classes/SkeletonModification3DLookAt.xml +++ /dev/null @@ -1,64 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="SkeletonModification3DLookAt" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> - <brief_description> - A modification that rotates a bone to look at a target. - </brief_description> - <description> - This [SkeletonModification3D] rotates a bone to look a target. This is extremely helpful for moving character's heads to look at the player, rotating a turret to look at a target, or any other case where you want to make a bone rotate towards something quickly and easily. - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_additional_rotation" qualifiers="const"> - <return type="Vector3" /> - <description> - Returns the amount of extra rotation that is applied to the bone after the LookAt modification executes. - </description> - </method> - <method name="get_lock_rotation_plane" qualifiers="const"> - <return type="int" /> - <description> - Returns the plane that the LookAt modification is limiting rotation to. - </description> - </method> - <method name="get_lock_rotation_to_plane" qualifiers="const"> - <return type="bool" /> - <description> - Returns whether the LookAt modification is limiting rotation to a single plane in 3D space. - </description> - </method> - <method name="set_additional_rotation"> - <return type="void" /> - <param index="0" name="additional_rotation" type="Vector3" /> - <description> - Sets the amount of extra rotation to be applied after the LookAt modification executes. This allows you to adjust the finished result. - </description> - </method> - <method name="set_lock_rotation_plane"> - <return type="void" /> - <param index="0" name="plane" type="int" /> - <description> - </description> - </method> - <method name="set_lock_rotation_to_plane"> - <return type="void" /> - <param index="0" name="lock_to_plane" type="bool" /> - <description> - When [code]true[/code], the LookAt modification will limit its rotation to a single plane in 3D space. The plane used can be configured using the [code]set_lock_rotation_plane[/code] function. - </description> - </method> - </methods> - <members> - <member name="bone_index" type="int" setter="set_bone_index" getter="get_bone_index" default="-2"> - The bone index of the bone that should be operated on by this modification. - When possible, this will also update the [member bone_name] based on data provided by the [Skeleton3D]. - </member> - <member name="bone_name" type="String" setter="set_bone_name" getter="get_bone_name" default=""""> - The name of the bone that should be operated on by this modification. - When possible, this will also update the [member bone_index] based on data provided by the [Skeleton3D]. - </member> - <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath("")"> - The NodePath to the node that is the target for the modification. - </member> - </members> -</class> diff --git a/doc/classes/SkeletonModification3DStackHolder.xml b/doc/classes/SkeletonModification3DStackHolder.xml deleted file mode 100644 index 9448e2c783..0000000000 --- a/doc/classes/SkeletonModification3DStackHolder.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="SkeletonModification3DStackHolder" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> - <brief_description> - A modification that holds and executes a [SkeletonModificationStack3D]. - </brief_description> - <description> - This [SkeletonModification3D] holds a reference to a [SkeletonModificationStack3D], allowing you to use multiple modification stacks on a single [Skeleton3D]. - [b]Note:[/b] The modifications in the held [SkeletonModificationStack3D] will only be executed if their execution mode matches the execution mode of the SkeletonModification3DStackHolder. - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_held_modification_stack" qualifiers="const"> - <return type="SkeletonModificationStack3D" /> - <description> - Returns the [SkeletonModificationStack3D] that this modification is holding. - </description> - </method> - <method name="set_held_modification_stack"> - <return type="void" /> - <param index="0" name="held_modification_stack" type="SkeletonModificationStack3D" /> - <description> - Sets the [SkeletonModificationStack3D] that this modification is holding. This modification stack will then be executed when this modification is executed. - </description> - </method> - </methods> -</class> diff --git a/doc/classes/SkeletonModification3DTwoBoneIK.xml b/doc/classes/SkeletonModification3DTwoBoneIK.xml deleted file mode 100644 index 0e7ffd5c80..0000000000 --- a/doc/classes/SkeletonModification3DTwoBoneIK.xml +++ /dev/null @@ -1,191 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="SkeletonModification3DTwoBoneIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> - <brief_description> - A modification that moves two bones to reach the target. - </brief_description> - <description> - This [SkeletonModification3D] uses an algorithm typically called TwoBoneIK. This algorithm works by leveraging the law of cosigns and the lengths of the bones to figure out what rotation the bones currently have, and what rotation they need to make a complete triangle, where the first bone, the second bone, and the target form the three vertices of the triangle. Because the algorithm works by making a triangle, it can only operate on two bones. - TwoBoneIK is great for arms, legs, and really any joints that can be represented by just two bones that bend to reach a target. This solver is more lightweight than [SkeletonModification3DFABRIK], but gives similar, natural looking results. - A [Node3D]-based node can be used to define the pole, or bend direction, allowing control over which direction the joint takes when bending to reach the target when the target is within reach. - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_auto_calculate_joint_length" qualifiers="const"> - <return type="bool" /> - <description> - Returns whether the TwoBoneIK modification will attempt to autocalculate the lengths of the two bones. - </description> - </method> - <method name="get_joint_one_bone_idx" qualifiers="const"> - <return type="int" /> - <description> - Returns the bone index of the first bone in the TwoBoneIK modification. - </description> - </method> - <method name="get_joint_one_bone_name" qualifiers="const"> - <return type="String" /> - <description> - Returns the name of the first bone in the TwoBoneIK modification. - </description> - </method> - <method name="get_joint_one_length" qualifiers="const"> - <return type="float" /> - <description> - Returns the length of the first bone in the TwoBoneIK modification. - </description> - </method> - <method name="get_joint_one_roll" qualifiers="const"> - <return type="float" /> - <description> - Returns the amount of roll/twist applied to the first bone in the TwoBoneIK modification. - </description> - </method> - <method name="get_joint_two_bone_idx" qualifiers="const"> - <return type="int" /> - <description> - Returns the bone index of the second bone in the TwoBoneIK modification. - </description> - </method> - <method name="get_joint_two_bone_name" qualifiers="const"> - <return type="String" /> - <description> - Returns the name of the second bone in the TwoBoneIK modification. - </description> - </method> - <method name="get_joint_two_length" qualifiers="const"> - <return type="float" /> - <description> - Returns the length of the second bone in the TwoBoneIK modification. - </description> - </method> - <method name="get_joint_two_roll" qualifiers="const"> - <return type="float" /> - <description> - Returns the amount of roll/twist applied to the second bone in the TwoBoneIK modification. - </description> - </method> - <method name="get_pole_node" qualifiers="const"> - <return type="NodePath" /> - <description> - Returns the node that is being used as the pole node for the TwoBoneIK modification, if a pole node has been set. - </description> - </method> - <method name="get_tip_node" qualifiers="const"> - <return type="NodePath" /> - <description> - Returns the node that is being used to calculate the tip position of the second bone in the TwoBoneIK modification, if a tip node has been set. - </description> - </method> - <method name="get_use_pole_node" qualifiers="const"> - <return type="bool" /> - <description> - Returns whether the TwoBoneIK modification will attempt to use the pole node to figure out which direction to bend, if a pole node has been set. - </description> - </method> - <method name="get_use_tip_node" qualifiers="const"> - <return type="bool" /> - <description> - Returns whether the TwoBoneIK modification will attempt to use the tip node to figure out the length and position of the tip of the second bone. - </description> - </method> - <method name="set_auto_calculate_joint_length"> - <return type="void" /> - <param index="0" name="auto_calculate_joint_length" type="bool" /> - <description> - If true, the TwoBoneIK modification will attempt to autocalculate the lengths of the bones being used. The first bone will be calculated by using the distance from the origin of the first bone to the origin of the second bone. - The second bone will be calculated either using the tip node if that setting is enabled, or by using the distances of the second bone's children. If the tip node is not enabled and the bone has no children, then the length cannot be autocalculated. In this case, the length will either have to be manually inputted or a tip node used to calculate the length. - </description> - </method> - <method name="set_joint_one_bone_idx"> - <return type="void" /> - <param index="0" name="bone_idx" type="int" /> - <description> - Sets the bone index, [param bone_idx], of the first bone. When possible, this will also update the [code]bone_name[/code] of the first bone based on data provided by the [Skeleton3D]. - </description> - </method> - <method name="set_joint_one_bone_name"> - <return type="void" /> - <param index="0" name="bone_name" type="String" /> - <description> - Sets the bone name, [param bone_name], of the first bone. When possible, this will also update the [code]bone_index[/code] of the first bone based on data provided by the [Skeleton3D]. - </description> - </method> - <method name="set_joint_one_length"> - <return type="void" /> - <param index="0" name="bone_length" type="float" /> - <description> - Sets the length of the first bone in the TwoBoneIK modification. - </description> - </method> - <method name="set_joint_one_roll"> - <return type="void" /> - <param index="0" name="roll" type="float" /> - <description> - Sets the amount of roll/twist applied to the first bone in the TwoBoneIK modification. - </description> - </method> - <method name="set_joint_two_bone_idx"> - <return type="void" /> - <param index="0" name="bone_idx" type="int" /> - <description> - Sets the bone index, [param bone_idx], of the second bone. When possible, this will also update the [code]bone_name[/code] of the second bone based on data provided by the [Skeleton3D]. - </description> - </method> - <method name="set_joint_two_bone_name"> - <return type="void" /> - <param index="0" name="bone_name" type="String" /> - <description> - Sets the bone name, [param bone_name], of the second bone. When possible, this will also update the [code]bone_index[/code] of the second bone based on data provided by the [Skeleton3D]. - </description> - </method> - <method name="set_joint_two_length"> - <return type="void" /> - <param index="0" name="bone_length" type="float" /> - <description> - Sets the length of the second bone in the TwoBoneIK modification. - </description> - </method> - <method name="set_joint_two_roll"> - <return type="void" /> - <param index="0" name="roll" type="float" /> - <description> - Sets the amount of roll/twist applied to the second bone in the TwoBoneIK modification. - </description> - </method> - <method name="set_pole_node"> - <return type="void" /> - <param index="0" name="pole_nodepath" type="NodePath" /> - <description> - Sets the node to be used as the for the pole of the TwoBoneIK. When a node is set and the modification is set to use the pole node, the TwoBoneIK modification will bend the nodes in the direction towards this node when the bones need to bend. - </description> - </method> - <method name="set_tip_node"> - <return type="void" /> - <param index="0" name="tip_nodepath" type="NodePath" /> - <description> - Sets the node to be used as the tip for the second bone. This is used to calculate the length and position of the end of the second bone in the TwoBoneIK modification. - [b]Note:[/b] The tip node should generally be a child node of a [BoneAttachment3D] node attached to the second bone, with the child node being offset so it is at the end of the bone. - </description> - </method> - <method name="set_use_pole_node"> - <return type="void" /> - <param index="0" name="use_pole_node" type="bool" /> - <description> - When [code]true[/code], the TwoBoneIK modification will bend the bones towards the pole node, if one has been set. This gives control over the direction the TwoBoneIK solver will bend, which is helpful for joints like elbows that only bend in certain directions. - </description> - </method> - <method name="set_use_tip_node"> - <return type="void" /> - <param index="0" name="use_tip_node" type="bool" /> - <description> - When [code]true[/code], the TwoBoneIK modification will use the tip node to calculate the distance and position of the end/tip of the second bone. This is the most stable solution for knowing the tip position and length of the second bone. - </description> - </method> - </methods> - <members> - <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath("")"> - The NodePath to the node that is the target for the TwoBoneIK modification. This node is what the modification will attempt to rotate the bones to reach. - </member> - </members> -</class> diff --git a/doc/classes/SkeletonModificationStack3D.xml b/doc/classes/SkeletonModificationStack3D.xml deleted file mode 100644 index 9eaeeefd8e..0000000000 --- a/doc/classes/SkeletonModificationStack3D.xml +++ /dev/null @@ -1,88 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="SkeletonModificationStack3D" inherits="Resource" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> - <brief_description> - A resource that holds a stack of [SkeletonModification3D]s. - </brief_description> - <description> - This resource is used by the Skeleton and holds a stack of [SkeletonModification3D]s. The SkeletonModificationStack3D controls the order of the modifications, which controls how they are applied. Modification order is especially important for full-body IK setups, as you need to execute the modifications in the correct order to get the desired results. For example, you want to execute a modification on the spine [i]before[/i] the arms on a humanoid skeleton. - Additionally, the SkeletonModificationStack3D also controls how strongly the modifications are applied to the [Skeleton3D] node. - </description> - <tutorials> - </tutorials> - <methods> - <method name="add_modification"> - <return type="void" /> - <param index="0" name="modification" type="SkeletonModification3D" /> - <description> - Adds the passed-in [SkeletonModification3D] to the stack. - </description> - </method> - <method name="delete_modification"> - <return type="void" /> - <param index="0" name="mod_idx" type="int" /> - <description> - Deletes the [SkeletonModification3D] at the index position [param mod_idx], if it exists. - </description> - </method> - <method name="enable_all_modifications"> - <return type="void" /> - <param index="0" name="enabled" type="bool" /> - <description> - Enables all [SkeletonModification3D]s in the stack. - </description> - </method> - <method name="execute"> - <return type="void" /> - <param index="0" name="delta" type="float" /> - <param index="1" name="execution_mode" type="int" /> - <description> - Executes all of the [SkeletonModification3D]s in the stack that use the same execution mode as the passed-in [param execution_mode], starting from index [code]0[/code] to [member modification_count]. - [b]Note:[/b] The order of the modifications can matter depending on the modifications. For example, modifications on a spine should operate before modifications on the arms in order to get proper results. - </description> - </method> - <method name="get_is_setup" qualifiers="const"> - <return type="bool" /> - <description> - Returns a boolean that indicates whether the modification stack is setup and can execute. - </description> - </method> - <method name="get_modification" qualifiers="const"> - <return type="SkeletonModification3D" /> - <param index="0" name="mod_idx" type="int" /> - <description> - Returns the [SkeletonModification3D] at the passed-in index, [param mod_idx]. - </description> - </method> - <method name="get_skeleton" qualifiers="const"> - <return type="Skeleton3D" /> - <description> - Returns the [Skeleton3D] node that the SkeletonModificationStack3D is bound to. - </description> - </method> - <method name="set_modification"> - <return type="void" /> - <param index="0" name="mod_idx" type="int" /> - <param index="1" name="modification" type="SkeletonModification3D" /> - <description> - Sets the modification at [param mod_idx] to the passed-in modification, [param modification]. - </description> - </method> - <method name="setup"> - <return type="void" /> - <description> - Sets up the modification stack so it can execute. This function should be called by [Skeleton3D] and shouldn't be called unless you know what you are doing. - </description> - </method> - </methods> - <members> - <member name="enabled" type="bool" setter="set_enabled" getter="get_enabled" default="false"> - When true, the modification's in the stack will be called. This is handled automatically through the [Skeleton3D] node. - </member> - <member name="modification_count" type="int" setter="set_modification_count" getter="get_modification_count" default="0"> - The number of modifications in the stack. - </member> - <member name="strength" type="float" setter="set_strength" getter="get_strength" default="1.0"> - The interpolation strength of the modifications in stack. A value of [code]0[/code] will make it where the modifications are not applied, a strength of [code]0.5[/code] will be half applied, and a strength of [code]1[/code] will allow the modifications to be fully applied and override the skeleton bone poses. - </member> - </members> -</class> diff --git a/doc/classes/SkeletonProfileHumanoid.xml b/doc/classes/SkeletonProfileHumanoid.xml index 0dbd66d8d6..7445272ccc 100644 --- a/doc/classes/SkeletonProfileHumanoid.xml +++ b/doc/classes/SkeletonProfileHumanoid.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="SkeletonProfileHumanoid" inherits="SkeletonProfile" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + A humanoid [SkeletonProfile] preset. </brief_description> <description> A [SkeletonProfile] as a preset that is optimized for the human form. This exists for standardization, so all parameters are read-only. diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml index b3145ea022..90c10e3664 100644 --- a/doc/classes/Transform3D.xml +++ b/doc/classes/Transform3D.xml @@ -41,6 +41,7 @@ <return type="Transform3D" /> <param index="0" name="from" type="Projection" /> <description> + Constructs a Transform3D from a [Projection] by trimming the last row of the projection matrix ([code]from.x.w[/code], [code]from.y.w[/code], [code]from.z.w[/code], and [code]from.w.w[/code] are not copied over). </description> </constructor> <constructor name="Transform3D"> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index bfabd2d97d..ff5a665bfd 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -45,11 +45,11 @@ <method name="create_item"> <return type="TreeItem" /> <param index="0" name="parent" type="TreeItem" default="null" /> - <param index="1" name="idx" type="int" default="-1" /> + <param index="1" name="index" type="int" default="-1" /> <description> Creates an item in the tree and adds it as a child of [param parent], which can be either a valid [TreeItem] or [code]null[/code]. If [param parent] is [code]null[/code], the root item will be the parent, or the new item will be the root itself if the tree is empty. - The new item will be the [param idx]th child of parent, or it will be the last child if there are not enough siblings. + The new item will be the [param index]-th child of parent, or it will be the last child if there are not enough siblings. </description> </method> <method name="deselect_all"> diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index ec6b166e57..91248092d9 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -18,7 +18,7 @@ <param index="3" name="disabled" type="bool" default="false" /> <param index="4" name="tooltip_text" type="String" default="""" /> <description> - Adds a button with [Texture2D] [param button] at column [param column]. The [param id] is used to identify the button. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip_text]. + Adds a button with [Texture2D] [param button] at column [param column]. The [param id] is used to identify the button in the according [signal Tree.button_clicked] signal and can be different from the buttons index. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip_text]. </description> </method> <method name="call_recursive" qualifiers="vararg"> @@ -44,10 +44,10 @@ </method> <method name="create_child"> <return type="TreeItem" /> - <param index="0" name="idx" type="int" default="-1" /> + <param index="0" name="index" type="int" default="-1" /> <description> Creates an item and adds it as a child. - The new item will be inserted as position [param idx] (the default value [code]-1[/code] means the last position), or it will be the last child if [param idx] is higher than the child count. + The new item will be inserted as position [param index] (the default value [code]-1[/code] means the last position), or it will be the last child if [param index] is higher than the child count. </description> </method> <method name="deselect"> @@ -60,17 +60,17 @@ <method name="erase_button"> <return type="void" /> <param index="0" name="column" type="int" /> - <param index="1" name="button_idx" type="int" /> + <param index="1" name="button_index" type="int" /> <description> - Removes the button at index [param button_idx] in column [param column]. + Removes the button at index [param button_index] in column [param column]. </description> </method> <method name="get_button" qualifiers="const"> <return type="Texture2D" /> <param index="0" name="column" type="int" /> - <param index="1" name="button_idx" type="int" /> + <param index="1" name="button_index" type="int" /> <description> - Returns the [Texture2D] of the button at index [param button_idx] in column [param column]. + Returns the [Texture2D] of the button at index [param button_index] in column [param column]. </description> </method> <method name="get_button_by_id" qualifiers="const"> @@ -91,17 +91,17 @@ <method name="get_button_id" qualifiers="const"> <return type="int" /> <param index="0" name="column" type="int" /> - <param index="1" name="button_idx" type="int" /> + <param index="1" name="button_index" type="int" /> <description> - Returns the ID for the button at index [param button_idx] in column [param column]. + Returns the ID for the button at index [param button_index] in column [param column]. </description> </method> <method name="get_button_tooltip_text" qualifiers="const"> <return type="String" /> <param index="0" name="column" type="int" /> - <param index="1" name="button_idx" type="int" /> + <param index="1" name="button_index" type="int" /> <description> - Returns the tooltip text for the button at index [param button_idx] in column [param column]. + Returns the tooltip text for the button at index [param button_index] in column [param column]. </description> </method> <method name="get_cell_mode" qualifiers="const"> @@ -113,9 +113,9 @@ </method> <method name="get_child"> <return type="TreeItem" /> - <param index="0" name="idx" type="int" /> + <param index="0" name="index" type="int" /> <description> - Returns a child item by its index (see [method get_child_count]). This method is often used for iterating all children of an item. + Returns a child item by its [param index] (see [method get_child_count]). This method is often used for iterating all children of an item. Negative indices access the children from the last one. </description> </method> @@ -332,9 +332,9 @@ <method name="is_button_disabled" qualifiers="const"> <return type="bool" /> <param index="0" name="column" type="int" /> - <param index="1" name="button_idx" type="int" /> + <param index="1" name="button_index" type="int" /> <description> - Returns [code]true[/code] if the button at index [param button_idx] for the given [param column] is disabled. + Returns [code]true[/code] if the button at index [param button_index] for the given [param column] is disabled. </description> </method> <method name="is_checked" qualifiers="const"> @@ -419,28 +419,28 @@ <method name="set_button"> <return type="void" /> <param index="0" name="column" type="int" /> - <param index="1" name="button_idx" type="int" /> + <param index="1" name="button_index" type="int" /> <param index="2" name="button" type="Texture2D" /> <description> - Sets the given column's button [Texture2D] at index [param button_idx] to [param button]. + Sets the given column's button [Texture2D] at index [param button_index] to [param button]. </description> </method> <method name="set_button_color"> <return type="void" /> <param index="0" name="column" type="int" /> - <param index="1" name="button_idx" type="int" /> + <param index="1" name="button_index" type="int" /> <param index="2" name="color" type="Color" /> <description> - Sets the given column's button color at index [param button_idx] to [param color]. + Sets the given column's button color at index [param button_index] to [param color]. </description> </method> <method name="set_button_disabled"> <return type="void" /> <param index="0" name="column" type="int" /> - <param index="1" name="button_idx" type="int" /> + <param index="1" name="button_index" type="int" /> <param index="2" name="disabled" type="bool" /> <description> - If [code]true[/code], disables the button at index [param button_idx] in the given [param column]. + If [code]true[/code], disables the button at index [param button_index] in the given [param column]. </description> </method> <method name="set_cell_mode"> diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml index eef35049e5..fc0dd9f05d 100644 --- a/doc/classes/Tween.xml +++ b/doc/classes/Tween.xml @@ -11,7 +11,7 @@ [codeblocks] [gdscript] var tween = get_tree().create_tween() - tween.tween_property($Sprite, "modulate", Color.red, 1) + tween.tween_property($Sprite, "modulate", Color.RED, 1) tween.tween_property($Sprite, "scale", Vector2(), 1) tween.tween_callback($Sprite.queue_free) [/gdscript] @@ -27,7 +27,7 @@ [codeblocks] [gdscript] var tween = get_tree().create_tween() - tween.tween_property($Sprite, "modulate", Color.red, 1).set_trans(Tween.TRANS_SINE) + tween.tween_property($Sprite, "modulate", Color.RED, 1).set_trans(Tween.TRANS_SINE) tween.tween_property($Sprite, "scale", Vector2(), 1).set_trans(Tween.TRANS_BOUNCE) tween.tween_callback($Sprite.queue_free) [/gdscript] @@ -42,7 +42,7 @@ [codeblocks] [gdscript] var tween = get_tree().create_tween().bind_node(self).set_trans(Tween.TRANS_ELASTIC) - tween.tween_property($Sprite, "modulate", Color.red, 1) + tween.tween_property($Sprite, "modulate", Color.RED, 1) tween.tween_property($Sprite, "scale", Vector2(), 1) tween.tween_callback($Sprite.queue_free) [/gdscript] @@ -288,8 +288,8 @@ [codeblocks] [gdscript] var tween = get_tree().create_tween() - tween.tween_callback($Sprite.set_modulate.bind(Color.red)).set_delay(2) - tween.tween_callback($Sprite.set_modulate.bind(Color.blue)).set_delay(2) + tween.tween_callback($Sprite.set_modulate.bind(Color.RED)).set_delay(2) + tween.tween_callback($Sprite.set_modulate.bind(Color.BLUE)).set_delay(2) [/gdscript] [csharp] Tween tween = GetTree().CreateTween(); diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml index 7258efbdda..42baf7728d 100644 --- a/doc/classes/UndoRedo.xml +++ b/doc/classes/UndoRedo.xml @@ -17,7 +17,7 @@ func undo_something(): pass # Put here the code that reverts what's done by "do_something()". - func _on_MyButton_pressed(): + func _on_my_button_pressed(): var node = get_node("MyNode2D") undo_redo.create_action("Move the node") undo_redo.add_do_method(self, "do_something") diff --git a/doc/classes/Variant.xml b/doc/classes/Variant.xml index 6b384d6a77..5416468ab6 100644 --- a/doc/classes/Variant.xml +++ b/doc/classes/Variant.xml @@ -38,7 +38,7 @@ # To get the name of the underlying Object type, you need the `get_class()` method. print("foo is a(n) %s" % foo.get_class()) # inject the class name into a formatted string. # Note also that there is not yet any way to get a script's `class_name` string easily. - # To fetch that value, you need to dig deeply into a hidden ProjectSettings setting: an Array of Dictionaries called "_global_script_classes". + # To fetch that value, you can parse the [code]res://.godot/global_script_class_cache.cfg[/code] file with the [ConfigFile] API. # Open your project.godot file to see it up close. [/gdscript] [csharp] @@ -70,6 +70,6 @@ Modifications to a container will modify all references to it. A [Mutex] should be created to lock it if multi-threaded access is desired. </description> <tutorials> - <link title="Variant class">$DOCS_URL/development/cpp/variant_class.html</link> + <link title="Variant class introduction">$DOCS_URL/contributing/development/core_and_modules/variant_class.html</link> </tutorials> </class> diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index 4cd6cf41da..dd145c016c 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -527,6 +527,39 @@ Set's the window's current mode. [b]Note:[/b] Fullscreen mode is not exclusive full screen on Windows and Linux. </member> + <member name="mouse_passthrough" type="bool" setter="set_flag" getter="get_flag" default="false"> + If [code]true[/code], all mouse event as passed to the underlying window of the same application. See also [member mouse_passthrough_polygon]. + [b]Note:[/b] This property is implemented on Linux (X11), macOS and Windows. + </member> + <member name="mouse_passthrough_polygon" type="PackedVector2Array" setter="set_mouse_passthrough_polygon" getter="get_mouse_passthrough_polygon" default="PackedVector2Array()"> + Sets a polygonal region of the window which accepts mouse events. Mouse events outside the region will be passed through. + Passing an empty array will disable passthrough support (all mouse events will be intercepted by the window, which is the default behavior). + [codeblocks] + [gdscript] + # Set region, using Path2D node. + $Window.mouse_passthrough_polygon = $Path2D.curve.get_baked_points() + + # Set region, using Polygon2D node. + $Window.mouse_passthrough_polygon = $Polygon2D.polygon + + # Reset region to default. + $Window.mouse_passthrough_polygon = [] + [/gdscript] + [csharp] + // Set region, using Path2D node. + GetNode<Window>("Window").MousePassthrough = GetNode<Path2D>("Path2D").Curve.GetBakedPoints(); + + // Set region, using Polygon2D node. + GetNode<Window>("Window").MousePassthrough = GetNode<Polygon2D>("Polygon2D").Polygon; + + // Reset region to default. + GetNode<Window>("Window").MousePassthrough = new Vector2[] {}; + [/csharp] + [/codeblocks] + [b]Note:[/b] This property is ignored if [member mouse_passthrough] is set to [code]true[/code]. + [b]Note:[/b] On Windows, the portion of a window that lies outside the region is not drawn, while on Linux (X11) and macOS it is. + [b]Note:[/b] This property is implemented on Linux (X11), macOS and Windows. + </member> <member name="popup_window" type="bool" setter="set_flag" getter="get_flag" default="false"> If [code]true[/code], the [Window] will be considered a popup. Popups are sub-windows that don't show as separate windows in system's window manager's window list and will send close request when anything is clicked outside of them (unless [member exclusive] is enabled). </member> @@ -695,7 +728,9 @@ Window content is expanded to the full size of the window. Unlike borderless window, the frame is left intact and can be used to resize the window, title bar is transparent, but have minimize/maximize/close buttons. Set with [member extend_to_title]. [b]Note:[/b] This flag is implemented on macOS. </constant> - <constant name="FLAG_MAX" value="7" enum="Flags"> + <constant name="FLAG_MOUSE_PASSTHROUGH" value="7" enum="Flags"> + </constant> + <constant name="FLAG_MAX" value="8" enum="Flags"> Max value of the [enum Flags]. </constant> <constant name="CONTENT_SCALE_MODE_DISABLED" value="0" enum="ContentScaleMode"> diff --git a/doc/classes/bool.xml b/doc/classes/bool.xml index d0ef664281..e1a98f0ea4 100644 --- a/doc/classes/bool.xml +++ b/doc/classes/bool.xml @@ -60,7 +60,7 @@ _can_shoot = false _cool_down.start() - func _on_CoolDownTimer_timeout(): + func _on_cool_down_timer_timeout(): _can_shoot = true [/gdscript] [csharp] diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index e54fad1551..2d81771898 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -2765,6 +2765,14 @@ void MaterialStorage::material_free(RID p_rid) { Material *material = material_owner.get_or_null(p_rid); ERR_FAIL_COND(!material); + // Need to clear texture arrays to prevent spin locking of their RID's. + // This happens when the app is being closed. + for (KeyValue<StringName, Variant> &E : material->params) { + if (E.value.get_type() == Variant::ARRAY) { + Array(E.value).clear(); + } + } + material_set_shader(p_rid, RID()); //clean up shader material->dependency.deleted_notify(p_rid); diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp index 65c4ca6131..19bf57df94 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp +++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp @@ -37,13 +37,14 @@ RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() { free_render_buffer_data(); } -void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { +void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); //internal_size.x = p_internal_size.x; // ignore for now //internal_size.y = p_internal_size.y; width = p_target_size.x; height = p_target_size.y; + //scaling_3d_mode = p_scaling_3d_mode //fsr_sharpness = p_fsr_sharpness; //texture_mipmap_bias = p_texture_mipmap_bias; render_target = p_render_target; diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h index 52a7737910..d07a0812f6 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.h +++ b/drivers/gles3/storage/render_scene_buffers_gles3.h @@ -81,7 +81,7 @@ public: private: public: virtual ~RenderSceneBuffersGLES3(); - virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override; + virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override; virtual void set_fsr_sharpness(float p_fsr_sharpness) override{}; virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override{}; diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index d4ab907e78..639f5e6de5 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -788,7 +788,7 @@ void AnimationBezierTrackEdit::_clear_selection() { } void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Update Selected Key Handles")); for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { const IntPair track_key_pair = E->get(); @@ -985,7 +985,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (I.value.has_point(mb->get_position())) { if (I.key == REMOVE_ICON) { if (!read_only) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action("Remove Bezier Track"); undo_redo->add_do_method(this, "_update_locked_tracks_after", track); @@ -1172,7 +1172,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { time += 0.0001; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Bezier Point")); undo_redo->add_do_method(animation.ptr(), "bezier_track_insert_key", selected_track, time, new_point); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time); @@ -1270,7 +1270,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (moving_selection) { //combit it - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Move Bezier Points")); List<AnimMoveRestore> to_restore; @@ -1471,7 +1471,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if ((moving_handle == -1 || moving_handle == 1) && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { if (!read_only) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Move Bezier Points")); if (moving_handle == -1) { real_t ratio = timeline->get_zoom_scale() * v_zoom; @@ -1543,7 +1543,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) { time += 0.001; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Bezier Point")); undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time); @@ -1591,7 +1591,7 @@ void AnimationBezierTrackEdit::duplicate_selection() { } } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Duplicate Keys")); List<Pair<int, real_t>> new_selection_values; @@ -1637,7 +1637,7 @@ void AnimationBezierTrackEdit::duplicate_selection() { void AnimationBezierTrackEdit::delete_selection() { if (selection.size()) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Delete Keys")); for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 89bb1f5ae6..857a9a664a 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -107,7 +107,7 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu float val = p_value; float prev_val = animation->track_get_key_transition(track, key); setting = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Change Transition"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val); undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val); @@ -119,7 +119,7 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu return true; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (animation->track_get_type(track)) { case Animation::TYPE_POSITION_3D: case Animation::TYPE_ROTATION_3D: @@ -704,7 +704,7 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p float val = p_value; float prev_val = animation->track_get_key_transition(track, key); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (!setting) { setting = true; undo_redo->create_action(TTR("Animation Multi Change Transition"), UndoRedo::MERGE_ENDS); @@ -714,7 +714,7 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p update_obj = true; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (animation->track_get_type(track)) { case Animation::TYPE_POSITION_3D: case Animation::TYPE_ROTATION_3D: @@ -925,7 +925,7 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p } } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (setting) { if (update_obj) { undo_redo->add_do_method(this, "_update_obj", animation); @@ -1252,7 +1252,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) { } editing = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Animation Length"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(animation.ptr(), "set_length", p_new_len); undo_redo->add_undo_method(animation.ptr(), "set_length", animation->get_length()); @@ -1265,7 +1265,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) { void AnimationTimelineEdit::_anim_loop_pressed() { if (!read_only) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Animation Loop")); switch (animation->get_loop_mode()) { case Animation::LOOP_NONE: { @@ -2392,7 +2392,7 @@ void AnimationTrackEdit::_zoom_changed() { } void AnimationTrackEdit::_path_submitted(const String &p_text) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Track Path")); undo_redo->add_do_method(animation.ptr(), "track_set_path", track, p_text); undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track)); @@ -2630,7 +2630,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (!read_only) { if (check_rect.has_point(pos)) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Toggle Track Enabled")); undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track)); undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track)); @@ -3020,7 +3020,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) { case MENU_CALL_MODE_DISCRETE: case MENU_CALL_MODE_CAPTURE: { Animation::UpdateMode update_mode = Animation::UpdateMode(p_index); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Animation Update Mode")); undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", track, update_mode); undo_redo->add_undo_method(animation.ptr(), "value_track_set_update_mode", track, animation->value_track_get_update_mode(track)); @@ -3034,7 +3034,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) { case MENU_INTERPOLATION_LINEAR_ANGLE: case MENU_INTERPOLATION_CUBIC_ANGLE: { Animation::InterpolationType interp_mode = Animation::InterpolationType(p_index - MENU_INTERPOLATION_NEAREST); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Animation Interpolation Mode")); undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track, interp_mode); undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", track, animation->track_get_interpolation_type(track)); @@ -3044,7 +3044,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) { case MENU_LOOP_WRAP: case MENU_LOOP_CLAMP: { bool loop_wrap = p_index == MENU_LOOP_WRAP; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Animation Loop Mode")); undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, loop_wrap); undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, animation->track_get_interpolation_loop_wrap(track)); @@ -3438,7 +3438,7 @@ void AnimationTrackEditor::_animation_track_remove_request(int p_track, Ref<Anim } int idx = p_track; if (idx >= 0 && idx < p_from_animation->get_track_count()) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Anim Track"), UndoRedo::MERGE_DISABLE, p_from_animation.ptr()); // Remove corresponding reset tracks if they are no longer needed. @@ -3639,7 +3639,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) { } void AnimationTrackEditor::_insert_track(bool p_reset_wanted, bool p_create_beziers) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Insert Key")); Ref<Animation> reset_anim; @@ -3968,7 +3968,7 @@ Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() { Ref<Animation> reset_anim; reset_anim.instantiate(); reset_anim->set_length(ANIM_MIN_LENGTH); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(al.ptr(), "add_animation", SceneStringNames::get_singleton()->RESET, reset_anim); undo_redo->add_do_method(AnimationPlayerEditor::get_singleton(), "_animation_player_changed", player); undo_redo->add_undo_method(al.ptr(), "remove_animation", SceneStringNames::get_singleton()->RESET); @@ -3978,7 +3978,7 @@ Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() { } void AnimationTrackEditor::_confirm_insert_list() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Insert Key")); bool create_reset = insert_confirm_reset->is_visible() && insert_confirm_reset->is_pressed(); @@ -4148,7 +4148,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD } } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (create_normal_track) { if (p_create_beziers) { bool valid; @@ -4600,7 +4600,7 @@ void AnimationTrackEditor::_update_scroll(double) { } void AnimationTrackEditor::_update_step(double p_new_step) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Animation Step")); float step_value = p_new_step; if (timeline->is_using_fps()) { @@ -4627,7 +4627,7 @@ void AnimationTrackEditor::_dropped_track(int p_from_track, int p_to_track) { } _clear_selection(true); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Rearrange Tracks")); undo_redo->add_do_method(animation.ptr(), "track_move_to", p_from_track, p_to_track); // Take into account that the position of the tracks that come after the one removed will change. @@ -4671,7 +4671,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { case Animation::TYPE_ROTATION_3D: case Animation::TYPE_SCALE_3D: case Animation::TYPE_METHOD: { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Track")); undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type); undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to); @@ -4700,7 +4700,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Track")); undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type); undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to); @@ -4719,7 +4719,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Track")); undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type); undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to); @@ -4744,7 +4744,7 @@ void AnimationTrackEditor::_add_track(int p_type) { void AnimationTrackEditor::_new_track_property_selected(String p_name) { String full_path = String(adding_track_path) + ":" + p_name; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (adding_track_type == Animation::TYPE_VALUE) { Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE; { @@ -4835,7 +4835,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { p_ofs += 0.0001; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (animation->track_get_type(p_track)) { case Animation::TYPE_POSITION_3D: { if (!root->has_node(animation->track_get_path(p_track))) { @@ -4991,7 +4991,7 @@ void AnimationTrackEditor::_add_method_key(const String &p_method) { } d["args"] = params; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Method Track Key")); undo_redo->add_do_method(animation.ptr(), "track_insert_key", insert_key_from_track_call_track, insert_key_from_track_call_ofs, d); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", insert_key_from_track_call_track, insert_key_from_track_call_ofs); @@ -5178,7 +5178,7 @@ void AnimationTrackEditor::_select_at_anim(const Ref<Animation> &p_anim, int p_t } void AnimationTrackEditor::_move_selection_commit() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Move Keys")); List<_AnimMoveRestore> to_restore; @@ -5430,7 +5430,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) { int start_track = transpose ? _get_track_selected() : top_track; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Duplicate Keys")); List<Pair<int, float>> new_selection_values; @@ -5660,7 +5660,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } int base_track = animation->get_track_count(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Paste Tracks")); for (int i = 0; i < track_clipboard.size(); i++) { undo_redo->add_do_method(animation.ptr(), "add_track", track_clipboard[i].track_type); @@ -5730,7 +5730,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { float s = scale->get_value(); ERR_FAIL_COND_MSG(s == 0, "Can't scale to 0."); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Scale Keys")); List<_AnimMoveRestore> to_restore; @@ -5810,7 +5810,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { ease_dialog->popup_centered(Size2(200, 100) * EDSCALE); } break; case EDIT_EASE_CONFIRM: { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Make Easing Keys")); Tween::TransitionType transition_type = static_cast<Tween::TransitionType>(transition_selection->get_selected_id()); @@ -5917,7 +5917,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { _anim_duplicate_keys(true); } break; case EDIT_ADD_RESET_KEY: { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Add RESET Keys")); Ref<Animation> reset = _create_and_get_reset_animation(); @@ -5978,7 +5978,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } if (selection.size()) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Delete Keys")); for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { @@ -6009,7 +6009,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { bake_dialog->popup_centered(Size2(200, 100) * EDSCALE); } break; case EDIT_BAKE_ANIMATION_CONFIRM: { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Bake Animation as Linear keys.")); int track_len = animation->get_track_count(); @@ -6130,7 +6130,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { animation->optimize(optimize_velocity_error->get_value(), optimize_angular_error->get_value(), optimize_precision_error->get_value()); _redraw_tracks(); _update_key_edit(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr())); undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this)); @@ -6200,7 +6200,7 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) { } } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr())); undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this)); _update_tracks(); @@ -6801,7 +6801,7 @@ void AnimationTrackKeyEditEditor::_time_edit_exited() { } int existing = animation->track_find_key(track, new_time, Animation::FIND_MODE_APPROX); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS); if (existing != -1) { diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index 0926a63f88..ba73a63245 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -31,7 +31,6 @@ #include "animation_track_editor_plugins.h" #include "editor/audio_stream_preview.h" -#include "editor/editor_node.h" #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" #include "editor/editor_undo_redo_manager.h" @@ -1018,7 +1017,7 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant ofs += 0.0001; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Audio Track Clip")); undo_redo->add_do_method(get_animation().ptr(), "audio_track_insert_key", get_track(), ofs, stream); undo_redo->add_undo_method(get_animation().ptr(), "track_remove_key_at_time", get_track(), ofs); @@ -1125,7 +1124,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (len_resizing && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { if (len_resizing_rel == 0 || len_resizing_index < 0) { len_resizing = false; diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp index b2e12e2409..dd27b61df9 100644 --- a/editor/array_property_edit.cpp +++ b/editor/array_property_edit.cpp @@ -31,7 +31,6 @@ #include "array_property_edit.h" #include "core/io/marshalls.h" -#include "editor/editor_node.h" #include "editor/editor_undo_redo_manager.h" #define ITEMS_PER_PAGE 100 @@ -88,7 +87,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { return true; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Resize Array")); ur->add_do_method(this, "_set_size", newsize); ur->add_undo_method(this, "_set_size", size); @@ -135,7 +134,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); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Change Array Value Type")); ur->add_do_method(this, "_set_value", idx, new_value); @@ -151,7 +150,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { Variant arr = get_array(); Variant value = arr.get(idx); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Change Array Value")); ur->add_do_method(this, "_set_value", idx, p_value); diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index ba7e7f2877..df8adf01e4 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -143,6 +143,7 @@ void FindReplaceBar::unhandled_input(const Ref<InputEvent> &p_event) { } bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col) { + text_editor->remove_secondary_carets(); String text = get_search_text(); Point2i pos = text_editor->search(text, p_flags, p_from_line, p_from_col); @@ -178,6 +179,7 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col) } void FindReplaceBar::_replace() { + text_editor->remove_secondary_carets(); bool selection_enabled = text_editor->has_selection(0); Point2i selection_begin, selection_end; if (selection_enabled) { @@ -225,6 +227,7 @@ void FindReplaceBar::_replace() { } void FindReplaceBar::_replace_all() { + text_editor->remove_secondary_carets(); text_editor->disconnect("text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed)); // Line as x so it gets priority in comparison, column as y. Point2i orig_cursor(text_editor->get_caret_line(0), text_editor->get_caret_column(0)); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 78987ee6ef..03d2a6565a 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -685,7 +685,7 @@ void ConnectionsDock::_connect(ConnectDialog::ConnectionData p_cd) { } Callable callable = p_cd.get_callable(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Connect '%s' to '%s'"), String(p_cd.signal), String(p_cd.method))); undo_redo->add_do_method(source, "connect", p_cd.signal, callable, p_cd.flags); undo_redo->add_undo_method(source, "disconnect", p_cd.signal, callable); @@ -706,7 +706,7 @@ void ConnectionsDock::_disconnect(TreeItem &p_item) { ERR_FAIL_COND(cd.source != selected_node); // Shouldn't happen but... Bugcheck. - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), cd.signal, cd.method)); Callable callable = cd.get_callable(); @@ -733,7 +733,7 @@ void ConnectionsDock::_disconnect_all() { TreeItem *child = item->get_first_child(); String signal_name = item->get_metadata(0).operator Dictionary()["name"]; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Disconnect all from signal: '%s'"), signal_name)); while (child) { diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp index d685db40d9..fc806ded5e 100644 --- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp +++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp @@ -213,7 +213,7 @@ Dictionary DebugAdapterParser::req_launch(const Dictionary &p_params) const { } EditorNode *editor = EditorNode::get_singleton(); - Error err = platform_string == "android" ? editor->run_play_native(device, idx) : editor->run_play_native(-1, idx); + Error err = platform_string == "android" ? editor->run_play_native(device * 10000 + idx) : editor->run_play_native(idx); if (err) { if (err == ERR_INVALID_PARAMETER && platform_string == "android") { return prepare_error_response(p_params, DAP::ErrorType::MISSING_DEVICE); diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index e4afbde89f..a368cacf56 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -275,7 +275,7 @@ void EditorDebuggerNode::stop(bool p_force) { }); _break_state_changed(); breakpoints.clear(); - EditorNode::get_undo_redo()->clear_history(false, EditorUndoRedoManager::REMOTE_HISTORY); + EditorUndoRedoManager::get_singleton()->clear_history(false, EditorUndoRedoManager::REMOTE_HISTORY); set_process(false); } diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp index 0d191cabe8..ad59a1c169 100644 --- a/editor/dictionary_property_edit.cpp +++ b/editor/dictionary_property_edit.cpp @@ -29,7 +29,6 @@ /**************************************************************************/ #include "dictionary_property_edit.h" -#include "editor/editor_node.h" #include "editor/editor_undo_redo_manager.h" void DictionaryPropertyEdit::_notif_change() { @@ -119,7 +118,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]; - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Change Dictionary Key")); ur->add_do_method(this, "_set_key", key, p_value); @@ -131,7 +130,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]; - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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 7ef99d56ab..5c97dc2d03 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -282,7 +282,7 @@ void EditorAudioBus::_name_changed(const String &p_new_name) { } updating_bus = true; - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); StringName current = AudioServer::get_singleton()->get_bus_name(get_index()); ur->create_action(TTR("Rename Audio Bus")); @@ -323,7 +323,7 @@ void EditorAudioBus::_volume_changed(float p_normalized) { slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db))); } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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())); @@ -417,7 +417,7 @@ void EditorAudioBus::_hide_value_preview() { void EditorAudioBus::_solo_toggled() { updating_bus = true; - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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())); @@ -431,7 +431,7 @@ void EditorAudioBus::_solo_toggled() { void EditorAudioBus::_mute_toggled() { updating_bus = true; - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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())); @@ -445,7 +445,7 @@ void EditorAudioBus::_mute_toggled() { void EditorAudioBus::_bypass_toggled() { updating_bus = true; - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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())); @@ -459,7 +459,7 @@ void EditorAudioBus::_bypass_toggled() { void EditorAudioBus::_send_selected(int p_which) { updating_bus = true; - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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())); @@ -509,7 +509,7 @@ void EditorAudioBus::_effect_edited() { int index = effect->get_metadata(0); updating_bus = true; - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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)); @@ -536,7 +536,7 @@ void EditorAudioBus::_effect_add(int p_which) { afxr->set_name(effect_options->get_item_text(p_which)); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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())); @@ -690,7 +690,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); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -732,7 +732,7 @@ void EditorAudioBus::_delete_effect_pressed(int p_option) { int index = item->get_metadata(0); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -1065,7 +1065,7 @@ void EditorAudioBuses::_notification(int p_what) { } void EditorAudioBuses::_add_bus() { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Add Audio Bus")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count() + 1); @@ -1097,7 +1097,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) { return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Delete Audio Bus")); ur->add_do_method(AudioServer::get_singleton(), "remove_bus", index); @@ -1119,7 +1119,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) { void EditorAudioBuses::_duplicate_bus(int p_which) { int add_at_pos = p_which + 1; - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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"); @@ -1142,7 +1142,7 @@ void EditorAudioBuses::_reset_bus_volume(Object *p_which) { EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which); int index = bus->get_index(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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)); @@ -1162,7 +1162,7 @@ void EditorAudioBuses::_request_drop_end() { } void EditorAudioBuses::_drop_at_index(int p_bus, int p_index) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Move Audio Bus")); ur->add_do_method(AudioServer::get_singleton(), "move_bus", p_bus, p_index); @@ -1221,7 +1221,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_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); + EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); call_deferred(SNAME("_select_layout")); } @@ -1237,7 +1237,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_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); + EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); call_deferred(SNAME("_select_layout")); } else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) { @@ -1257,7 +1257,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_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); + EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); call_deferred(SNAME("_select_layout")); } } @@ -1356,7 +1356,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_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); + EditorUndoRedoManager::get_singleton()->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 4001b849ff..65e3e5c0d8 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -194,7 +194,7 @@ void EditorAutoloadSettings::_autoload_edited() { TreeItem *ti = tree->get_edited(); int column = tree->get_edited_column(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (column == 0) { String name = ti->get_text(0); @@ -289,7 +289,7 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu String name = "autoload/" + ti->get_text(0); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (p_button) { case BUTTON_OPEN: { @@ -717,7 +717,7 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant & orders.sort(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Rearrange Autoloads")); @@ -760,7 +760,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_ name = "autoload/" + name; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Autoload")); // Singleton autoloads are represented with a leading "*" in their path. @@ -786,7 +786,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; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); int order = ProjectSettings::get_singleton()->get_order(name); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index c5fe89e35d..6e66962605 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -390,7 +390,7 @@ void EditorData::set_scene_as_saved(int p_idx) { } ERR_FAIL_INDEX(p_idx, edited_scene.size()); - get_undo_redo()->set_history_as_saved(edited_scene[p_idx].history_id); + undo_redo_manager->set_history_as_saved(edited_scene[p_idx].history_id); } bool EditorData::is_scene_changed(int p_idx) { @@ -399,7 +399,7 @@ bool EditorData::is_scene_changed(int p_idx) { } 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(); + uint64_t current_scene_version = undo_redo_manager->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; @@ -425,10 +425,6 @@ 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) { undo_redo_callbacks.push_back(p_callable); } @@ -998,6 +994,8 @@ void EditorData::script_class_set_name(const String &p_path, const StringName &p } void EditorData::script_class_save_icon_paths() { + Array script_classes = ProjectSettings::get_singleton()->get_global_class_list(); + Dictionary d; for (const KeyValue<StringName, String> &E : _script_class_icon_paths) { if (ScriptServer::is_global_class(E.key)) { @@ -1005,27 +1003,20 @@ void EditorData::script_class_save_icon_paths() { } } - Dictionary old; - if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) { - old = GLOBAL_GET("_global_script_class_icons"); - } - if ((!old.is_empty() || d.is_empty()) && d.hash() == old.hash()) { - return; - } - - if (d.is_empty()) { - if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) { - ProjectSettings::get_singleton()->clear("_global_script_class_icons"); + for (int i = 0; i < script_classes.size(); i++) { + Dictionary d2 = script_classes[i]; + if (!d2.has("class")) { + continue; } - } else { - ProjectSettings::get_singleton()->set("_global_script_class_icons", d); + d2["icon"] = d.get(d2["class"], ""); } - ProjectSettings::get_singleton()->save(); + ProjectSettings::get_singleton()->store_global_class_list(script_classes); } void EditorData::script_class_load_icon_paths() { script_class_clear_icon_paths(); +#ifndef DISABLE_DEPRECATED if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) { Dictionary d = GLOBAL_GET("_global_script_class_icons"); List<Variant> keys; @@ -1038,15 +1029,33 @@ void EditorData::script_class_load_icon_paths() { String path = ScriptServer::get_global_class_path(name); script_class_set_name(path, name); } + ProjectSettings::get_singleton()->clear("_global_script_class_icons"); + } +#endif + + Array script_classes = ProjectSettings::get_singleton()->get_global_class_list(); + for (int i = 0; i < script_classes.size(); i++) { + Dictionary d = script_classes[i]; + if (!d.has("class") || !d.has("path") || !d.has("icon")) { + continue; + } + + String name = d["class"]; + _script_class_icon_paths[name] = d["icon"]; + script_class_set_name(d["path"], name); } } EditorData::EditorData() { current_edited_scene = -1; - undo_redo_manager.instantiate(); + undo_redo_manager = memnew(EditorUndoRedoManager); script_class_load_icon_paths(); } +EditorData::~EditorData() { + memdelete(undo_redo_manager); +} + /////////////////////////////////////////////////////////////////////////////// void EditorSelection::_node_removed(Node *p_node) { diff --git a/editor/editor_data.h b/editor/editor_data.h index 385bcad1f9..bce9dd345d 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -133,7 +133,7 @@ private: HashMap<String, Vector<CustomType>> custom_types; List<PropertyData> clipboard; - Ref<EditorUndoRedoManager> undo_redo_manager; + EditorUndoRedoManager *undo_redo_manager; Vector<Callable> undo_redo_callbacks; HashMap<StringName, Callable> move_element_functions; @@ -168,7 +168,6 @@ public: int get_editor_plugin_count() const; EditorPlugin *get_editor_plugin(int p_idx); - 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(); @@ -245,6 +244,7 @@ public: void script_class_load_icon_paths(); EditorData(); + ~EditorData(); }; /** diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 4efc7c3055..9c056ffdd9 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1527,6 +1527,7 @@ void EditorFileSystem::update_script_classes() { ScriptServer::save_global_classes(); EditorNode::get_editor_data().script_class_save_icon_paths(); + emit_signal("script_classes_updated"); // Rescan custom loaders and savers. // Doing the following here because the `filesystem_changed` signal fires multiple times and isn't always followed by script classes update. @@ -2417,6 +2418,7 @@ void EditorFileSystem::_bind_methods() { ClassDB::bind_method(D_METHOD("reimport_files", "files"), &EditorFileSystem::reimport_files); ADD_SIGNAL(MethodInfo("filesystem_changed")); + ADD_SIGNAL(MethodInfo("script_classes_updated")); ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist"))); ADD_SIGNAL(MethodInfo("resources_reimported", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources"))); ADD_SIGNAL(MethodInfo("resources_reload", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources"))); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 5baa58873e..9b1a5e028b 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -41,7 +41,7 @@ #include "editor/plugins/script_editor_plugin.h" #include "scene/gui/line_edit.h" -#define CONTRIBUTE_URL vformat("%s/community/contributing/updating_the_class_reference.html", VERSION_DOCS_URL) +#define CONTRIBUTE_URL vformat("%s/contributing/documentation/updating_the_class_reference.html", VERSION_DOCS_URL) DocTools *EditorHelp::doc = nullptr; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 12aa44891d..5c977de8ff 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1361,38 +1361,22 @@ void EditorInspectorSection::_notification(int p_what) { } break; case NOTIFICATION_DRAG_BEGIN: { - Dictionary dd = get_viewport()->gui_get_drag_data(); - - // Only allow dropping if the section contains properties which can take the dragged data. - bool children_can_drop = false; - for (int child_idx = 0; child_idx < vbox->get_child_count(); child_idx++) { - Control *editor_property = Object::cast_to<Control>(vbox->get_child(child_idx)); - - // Test can_drop_data and can_drop_data_fw, since can_drop_data only works if set up with forwarding or if script attached. - if (editor_property && (editor_property->can_drop_data(Point2(), dd) || editor_property->call("_can_drop_data_fw", Point2(), dd, this))) { - children_can_drop = true; - break; - } - } - - dropping = children_can_drop; - queue_redraw(); + dropping_for_unfold = true; } break; case NOTIFICATION_DRAG_END: { - dropping = false; - queue_redraw(); + dropping_for_unfold = false; } break; case NOTIFICATION_MOUSE_ENTER: { - if (dropping) { + if (dropping || dropping_for_unfold) { dropping_unfold_timer->start(); } queue_redraw(); } break; case NOTIFICATION_MOUSE_EXIT: { - if (dropping) { + if (dropping || dropping_for_unfold) { dropping_unfold_timer->stop(); } queue_redraw(); @@ -1696,13 +1680,13 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) { } else { action_name = vformat("Move element %d to position %d in property array with prefix %s.", p_element_index, p_to_pos, array_element_prefix); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(action_name); if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) { // 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[] = { undo_redo.ptr(), object, array_element_prefix, p_element_index, p_to_pos }; + Variant args[] = { undo_redo, 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; @@ -1840,14 +1824,14 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) { } void EditorInspectorArray::_clear_array() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat("Clear property array with prefix %s.", array_element_prefix)); if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) { for (int i = count - 1; i >= 0; i--) { // 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[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 }; + Variant args[] = { undo_redo, 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; @@ -1893,7 +1877,7 @@ void EditorInspectorArray::_resize_array(int p_size) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat("Resize property array with prefix %s.", array_element_prefix)); if (p_size > count) { if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) { @@ -1901,7 +1885,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[] = { undo_redo.ptr(), object, array_element_prefix, -1, -1 }; + Variant args[] = { undo_redo, 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; @@ -1920,7 +1904,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[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 }; + Variant args[] = { undo_redo, 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; @@ -3568,8 +3552,8 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo } } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - if (!undo_redo.is_valid() || bool(object->call("_dont_undo_redo"))) { + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + if (bool(object->call("_dont_undo_redo"))) { object->set(p_name, p_value); if (p_refresh_all) { _edit_request_change(object, ""); @@ -3689,7 +3673,7 @@ void EditorInspector::_multiple_properties_changed(Vector<String> p_paths, Array } names += p_paths[i]; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set Multiple:") + " " + names, UndoRedo::MERGE_ENDS); for (int i = 0; i < p_paths.size(); i++) { _edit_set(p_paths[i], p_values[i], false, ""); @@ -3724,7 +3708,7 @@ void EditorInspector::_property_deleted(const String &p_path) { if (p_path.begins_with("metadata/")) { String name = p_path.replace_first("metadata/", ""); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Remove metadata %s"), name)); undo_redo->add_do_method(object, "remove_meta", name); undo_redo->add_undo_method(object, "set_meta", name, object->get_meta(name)); @@ -3790,26 +3774,17 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) { Node *node = Object::cast_to<Node>(object); ERR_FAIL_COND(!node); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_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); - if (editor_property_map.has(p_path)) { - for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) { - undo_redo->add_do_method(E->get(), "_update_editor_property_status"); - undo_redo->add_undo_method(E->get(), "_update_editor_property_status"); - } - } - undo_redo->commit_action(); - } else { - node->set_property_pinned(p_path, p_pinned); - if (editor_property_map.has(p_path)) { - for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) { - E->get()->update_editor_property_status(); - } + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + 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); + if (editor_property_map.has(p_path)) { + for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) { + undo_redo->add_do_method(E->get(), "_update_editor_property_status"); + undo_redo->add_undo_method(E->get(), "_update_editor_property_status"); } } + undo_redo->commit_action(); } void EditorInspector::_property_selected(const String &p_path, int p_focusable) { @@ -3988,7 +3963,7 @@ void EditorInspector::_add_meta_confirm() { Variant defval; Callable::CallError ce; Variant::construct(Variant::Type(add_meta_type->get_selected_id()), defval, nullptr, 0, ce); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Add metadata %s"), name)); undo_redo->add_do_method(object, "set_meta", name, defval); undo_redo->add_undo_method(object, "remove_meta", name); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index af8d1e6806..699a88e657 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -276,6 +276,7 @@ class EditorInspectorSection : public Container { Timer *dropping_unfold_timer = nullptr; bool dropping = false; + bool dropping_for_unfold = false; HashSet<StringName> revertable_properties; diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp index d57b3b66cc..5a372412fa 100644 --- a/editor/editor_locale_dialog.cpp +++ b/editor/editor_locale_dialog.cpp @@ -31,7 +31,6 @@ #include "editor_locale_dialog.h" #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" @@ -141,7 +140,7 @@ void EditorLocaleDialog::_filter_lang_option_changed() { f_lang_all.sort(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Changed Locale Language Filter")); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/language_filter", f_lang_all); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/language_filter", prev); @@ -175,7 +174,7 @@ void EditorLocaleDialog::_filter_script_option_changed() { f_script_all.sort(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Changed Locale Script Filter")); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/script_filter", f_script_all); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/script_filter", prev); @@ -209,7 +208,7 @@ void EditorLocaleDialog::_filter_cnt_option_changed() { f_cnt_all.sort(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Changed Locale Country Filter")); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/country_filter", f_cnt_all); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/country_filter", prev); @@ -224,7 +223,7 @@ void EditorLocaleDialog::_filter_mode_changed(int p_mode) { prev = GLOBAL_GET("internationalization/locale/locale_filter_mode"); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Changed Locale Filter Mode")); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter_mode", f_mode); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter_mode", prev); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index ae9261864f..62223b2445 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -288,7 +288,7 @@ void EditorNode::_update_scene_tabs() { icon = EditorNode::get_singleton()->get_object_icon(type_node, "Node"); } - bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i)); + bool unsaved = EditorUndoRedoManager::get_singleton()->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)) { @@ -533,8 +533,8 @@ void EditorNode::_notification(int p_what) { opening_prev = false; } - 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()); + bool global_unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY); + bool scene_or_global_unsaved = global_unsaved || EditorUndoRedoManager::get_singleton()->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(); @@ -584,10 +584,11 @@ void EditorNode::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { Engine::get_singleton()->set_editor_hint(true); - Window *window = static_cast<Window *>(get_tree()->get_root()); + Window *window = get_window(); if (window) { // Handle macOS fullscreen and extend-to-title changes. window->connect("titlebar_changed", callable_mp(this, &EditorNode::_titlebar_resized)); + window->set_theme(theme); } OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec"))); @@ -633,6 +634,10 @@ void EditorNode::_notification(int p_what) { set_addon_plugin_enabled(addons[i], true); } _initializing_plugins = false; + + if (!pending_addons.is_empty()) { + EditorFileSystem::get_singleton()->connect("script_classes_updated", callable_mp(this, &EditorNode::_enable_pending_addons)); + } } RenderingServer::get_singleton()->viewport_set_disable_2d(get_scene_root()->get_viewport_rid(), true); @@ -695,6 +700,7 @@ void EditorNode::_notification(int p_what) { theme_base->set_theme(theme); gui_base->set_theme(theme); + get_window()->set_theme(theme); gui_base->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Background"), SNAME("EditorStyles"))); scene_root_parent->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Content"), SNAME("EditorStyles"))); @@ -1128,7 +1134,7 @@ void EditorNode::_version_button_pressed() { } void EditorNode::_update_undo_redo_allowed() { - Ref<EditorUndoRedoManager> undo_redo = get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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()); } @@ -1680,7 +1686,7 @@ int EditorNode::_save_external_resources() { saved++; } - get_undo_redo()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY); + EditorUndoRedoManager::get_singleton()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY); return saved; } @@ -1857,7 +1863,7 @@ void EditorNode::_mark_unsaved_scenes() { String path = node->get_scene_file_path(); 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)); + EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(editor_data.get_scene_history_id(i)); } } @@ -2744,9 +2750,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 undo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR); } else { - String action = editor_data.get_undo_redo()->get_current_action_name(); - int id = editor_data.get_undo_redo()->get_current_action_history_id(); - if (!editor_data.get_undo_redo()->undo()) { + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + String action = undo_redo->get_current_action_name(); + int id = undo_redo->get_current_action_history_id(); + if (!undo_redo->undo()) { log->add_message(TTR("Nothing to undo."), EditorLog::MSG_TYPE_EDITOR); } else if (!action.is_empty()) { switch (id) { @@ -2763,18 +2770,19 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } } break; case EDIT_REDO: { + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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 (!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 = undo_redo->get_current_action_name(); if (action.is_empty()) { break; } - switch (editor_data.get_undo_redo()->get_current_action_history_id()) { + switch (undo_redo->get_current_action_history_id()) { case EditorUndoRedoManager::GLOBAL_HISTORY: log->add_message(vformat(TTR("Global Redo: %s"), action), EditorLog::MSG_TYPE_EDITOR); break; @@ -2817,7 +2825,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, editor_data.get_current_edited_scene_history_id()); + EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_current_edited_scene_history_id()); scene_tabs->set_current_tab(cur_idx); } break; @@ -2909,7 +2917,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case RELOAD_CURRENT_PROJECT: { if (!p_confirmed) { bool save_each = EDITOR_GET("interface/editor/save_each_scene_on_quit"); - if (_next_unsaved_scene(!save_each) == -1 && !get_undo_redo()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY)) { + if (_next_unsaved_scene(!save_each) == -1 && !EditorUndoRedoManager::get_singleton()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY)) { _discard_changes(); break; } else { @@ -3148,7 +3156,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) { if (!editor_data.get_edited_scene_root(i)) { continue; } - bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i)); + bool unsaved = EditorUndoRedoManager::get_singleton()->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) { @@ -3469,6 +3477,12 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled, // Errors in the script cause the base_type to be an empty StringName. if (scr->get_instance_base_type() == StringName()) { + if (_initializing_plugins) { + // However, if it happens during initialization, waiting for file scan might help. + pending_addons.push_back(p_addon); + return; + } + show_warning(vformat(TTR("Unable to load addon script from path: '%s'. This might be due to a code error in that script.\nDisabling the addon at '%s' to prevent further errors."), script_path, addon_path)); _remove_plugin_from_enabled(addon_path); return; @@ -3657,7 +3671,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)); } - get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(p_idx)); + EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_scene_history_id(p_idx)); } changing_scene = true; @@ -3724,7 +3738,7 @@ int EditorNode::new_scene() { // Remove placeholder empty scene. if (editor_data.get_edited_scene_count() > 1) { for (int i = 0; i < editor_data.get_edited_scene_count() - 1; i++) { - bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i)); + bool unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(i)); if (!unsaved && editor_data.get_scene_path(i).is_empty() && editor_data.get_edited_scene_root(i) == nullptr) { editor_data.remove_scene(i); idx--; @@ -3949,10 +3963,6 @@ 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); @@ -4378,6 +4388,13 @@ void EditorNode::_build_icon_type_cache() { } } +void EditorNode::_enable_pending_addons() { + for (uint32_t i = 0; i < pending_addons.size(); i++) { + set_addon_plugin_enabled(pending_addons[i], true); + } + pending_addons.clear(); +} + void EditorNode::_file_dialog_register(FileDialog *p_dialog) { singleton->file_dialogs.insert(p_dialog); } @@ -5065,8 +5082,8 @@ bool EditorNode::ensure_main_scene(bool p_from_native) { return true; } -Error EditorNode::run_play_native(int p_idx, int p_platform) { - return run_native->run_native(p_idx, p_platform); +Error EditorNode::run_play_native(int p_id) { + return run_native->run_native(p_id); } void EditorNode::run_play() { @@ -5222,7 +5239,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) { return; } - bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(p_tab)); + bool unsaved = EditorUndoRedoManager::get_singleton()->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")); @@ -5721,7 +5738,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(false, editor_data.get_current_edited_scene_history_id()); + EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_current_edited_scene_history_id()); } return; } @@ -5737,7 +5754,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(false, editor_data.get_scene_history_id(scene_idx)); + EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_scene_history_id(scene_idx)); // Recover the tab. scene_tabs->set_current_tab(current_tab); @@ -6055,8 +6072,8 @@ EditorNode::EditorNode() { singleton = this; - get_undo_redo()->connect("version_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed)); - get_undo_redo()->connect("history_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed)); + EditorUndoRedoManager::get_singleton()->connect("version_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed)); + EditorUndoRedoManager::get_singleton()->connect("history_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed)); TranslationServer::get_singleton()->set_enabled(false); // Load settings. diff --git a/editor/editor_node.h b/editor/editor_node.h index ae951808d5..fb2544c141 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -292,6 +292,7 @@ private: Vector<EditorPlugin *> editor_plugins; bool _initializing_plugins = false; HashMap<String, EditorPlugin *> addon_name_to_plugin; + LocalVector<String> pending_addons; PanelContainer *scene_root_parent = nullptr; Control *theme_base = nullptr; @@ -535,6 +536,7 @@ private: static void _resource_loaded(Ref<Resource> p_resource, const String &p_path); void _build_icon_type_cache(); + void _enable_pending_addons(); void _dialog_action(String p_file); @@ -729,7 +731,6 @@ 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 Ref<EditorUndoRedoManager> &get_undo_redo(); static HBoxContainer *get_menu_hb() { return singleton->menu_hb; } static VSplitContainer *get_top_split() { return singleton->top_split; } @@ -914,7 +915,7 @@ public: bool ensure_main_scene(bool p_from_native); - Error run_play_native(int p_idx, int p_platform); + Error run_play_native(int p_id); void run_play(); void run_play_current(); void run_play_custom(const String &p_custom); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index a5d1ddb2fa..ec866ad999 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -977,8 +977,8 @@ void EditorPlugin::_bind_methods() { BIND_ENUM_CONSTANT(AFTER_GUI_INPUT_CUSTOM); } -Ref<EditorUndoRedoManager> EditorPlugin::get_undo_redo() { - return EditorNode::get_undo_redo(); +EditorUndoRedoManager *EditorPlugin::get_undo_redo() { + return EditorUndoRedoManager::get_singleton(); } EditorPluginCreateFunc EditorPlugins::creation_funcs[MAX_CREATE_FUNCS]; diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 33081e867a..21eb4b89ef 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -148,7 +148,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - Ref<EditorUndoRedoManager> get_undo_redo(); + 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_properties.cpp b/editor/editor_properties.cpp index 8ef394a59f..f528053fee 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -3805,6 +3805,8 @@ static bool _find_recursive_resources(const Variant &v, HashSet<Resource *> &res return true; } } + + resources_found.erase(r.ptr()); } break; default: { } @@ -4584,6 +4586,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ return editor; } else { EditorPropertyDictionary *editor = memnew(EditorPropertyDictionary); + editor->setup(p_hint); return editor; } } break; diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index ed667aa7c8..069e80fc05 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -818,6 +818,10 @@ void EditorPropertyDictionary::_change_type_menu(int p_index) { update_property(); } +void EditorPropertyDictionary::setup(PropertyHint p_hint) { + property_hint = p_hint; +} + void EditorPropertyDictionary::update_property() { Variant updated_val = get_edited_object()->get(get_edited_property()); @@ -929,7 +933,13 @@ void EditorPropertyDictionary::update_property() { prop = editor; } break; case Variant::STRING: { - prop = memnew(EditorPropertyText); + if (i != amount && property_hint == PROPERTY_HINT_MULTILINE_TEXT) { + // If this is NOT the new key field and there's a multiline hint, + // show the field as multiline + prop = memnew(EditorPropertyMultilineText); + } else { + prop = memnew(EditorPropertyText); + } } break; diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index 96fc2dce24..73a16e3687 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -154,6 +154,7 @@ class EditorPropertyDictionary : public EditorProperty { EditorSpinSlider *size_sliderv = nullptr; Button *button_add_item = nullptr; EditorPaginator *paginator = nullptr; + PropertyHint property_hint; void _page_changed(int p_page); void _edit_pressed(); @@ -169,6 +170,7 @@ protected: void _notification(int p_what); public: + void setup(PropertyHint p_hint); virtual void update_property() override; EditorPropertyDictionary(); }; diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp index 195457c239..18ba19f5f6 100644 --- a/editor/editor_property_name_processor.cpp +++ b/editor/editor_property_name_processor.cpp @@ -211,6 +211,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["rmb"] = "RMB"; capitalize_string_remaps["rpc"] = "RPC"; capitalize_string_remaps["s3tc"] = "S3TC"; + capitalize_string_remaps["scp"] = "SCP"; capitalize_string_remaps["sdf"] = "SDF"; capitalize_string_remaps["sdfgi"] = "SDFGI"; capitalize_string_remaps["sdk"] = "SDK"; diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp index b0eb4c3d55..49723aa169 100644 --- a/editor/editor_run_native.cpp +++ b/editor/editor_run_native.cpp @@ -37,53 +37,27 @@ void EditorRunNative::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) { - Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(i); - if (eep.is_null()) { - continue; - } - Ref<ImageTexture> icon = eep->get_run_icon(); - if (!icon.is_null()) { - Ref<Image> im = icon->get_image(); - im = im->duplicate(); - im->clear_mipmaps(); - if (!im->is_empty()) { - im->resize(16 * EDSCALE, 16 * EDSCALE); - Ref<ImageTexture> small_icon = ImageTexture::create_from_image(im); - MenuButton *mb = memnew(MenuButton); - mb->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::run_native).bind(i)); - mb->connect("pressed", callable_mp(this, &EditorRunNative::run_native).bind(-1, i)); - mb->set_icon(small_icon); - add_child(mb); - menus[i] = mb; - } - } - } + case NOTIFICATION_THEME_CHANGED: { + remote_debug->set_icon(get_theme_icon(SNAME("PlayRemote"), SNAME("EditorIcons"))); } break; - case NOTIFICATION_PROCESS: { bool changed = EditorExport::get_singleton()->poll_export_platforms() || first; if (changed) { - for (KeyValue<int, MenuButton *> &E : menus) { - Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(E.key); - MenuButton *mb = E.value; - int dc = eep->get_options_count(); - - if (dc == 0) { - mb->hide(); - } else { - mb->get_popup()->clear(); - mb->show(); - if (dc == 1) { - mb->set_tooltip_text(eep->get_option_tooltip(0)); - } else { - mb->set_tooltip_text(eep->get_options_tooltip()); - for (int i = 0; i < dc; i++) { - mb->get_popup()->add_icon_item(eep->get_option_icon(i), eep->get_option_label(i)); - mb->get_popup()->set_item_tooltip(-1, eep->get_option_tooltip(i)); - } + remote_debug->get_popup()->clear(); + for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) { + Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(i); + if (eep.is_null()) { + continue; + } + int dc = MIN(eep->get_options_count(), 9000); + if (dc > 0) { + remote_debug->get_popup()->add_icon_item(eep->get_run_icon(), eep->get_name(), -1); + remote_debug->get_popup()->set_item_disabled(-1, true); + for (int j = 0; j < dc; j++) { + remote_debug->get_popup()->add_icon_item(eep->get_option_icon(j), eep->get_option_label(j), 10000 * i + j); + remote_debug->get_popup()->set_item_tooltip(-1, eep->get_option_tooltip(j)); + remote_debug->get_popup()->set_item_indent(-1, 2); } } } @@ -94,25 +68,22 @@ void EditorRunNative::_notification(int p_what) { } } -Error EditorRunNative::run_native(int p_idx, int p_platform) { - if (!EditorNode::get_singleton()->ensure_main_scene(true)) { - resume_idx = p_idx; - resume_platform = p_platform; +Error EditorRunNative::run_native(int p_id) { + if (p_id < 0) { return OK; } - Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(p_platform); - ERR_FAIL_COND_V(eep.is_null(), ERR_UNAVAILABLE); + int platform = p_id / 10000; + int idx = p_id % 10000; - if (p_idx == -1) { - if (eep->get_options_count() == 1) { - menus[p_platform]->get_popup()->hide(); - p_idx = 0; - } else { - return ERR_INVALID_PARAMETER; - } + if (!EditorNode::get_singleton()->ensure_main_scene(true)) { + resume_id = p_id; + return OK; } + Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(platform); + ERR_FAIL_COND_V(eep.is_null(), ERR_UNAVAILABLE); + Ref<EditorExportPreset> preset; for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { @@ -151,16 +122,18 @@ Error EditorRunNative::run_native(int p_idx, int p_platform) { } eep->clear_messages(); - Error err = eep->run(preset, p_idx, flags); + Error err = eep->run(preset, idx, flags); result_dialog_log->clear(); if (eep->fill_log_messages(result_dialog_log, err)) { - result_dialog->popup_centered_ratio(0.5); + if (eep->get_worst_message_type() >= EditorExportPlatform::EXPORT_MESSAGE_ERROR) { + result_dialog->popup_centered_ratio(0.5); + } } return err; } void EditorRunNative::resume_run_native() { - run_native(resume_idx, resume_platform); + run_native(resume_id); } void EditorRunNative::_bind_methods() { @@ -172,6 +145,13 @@ bool EditorRunNative::is_deploy_debug_remote_enabled() const { } EditorRunNative::EditorRunNative() { + remote_debug = memnew(MenuButton); + remote_debug->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::run_native)); + remote_debug->set_icon(get_theme_icon(SNAME("PlayRemote"), SNAME("EditorIcons"))); + remote_debug->set_tooltip_text(TTR("Remote Debug")); + + add_child(remote_debug); + result_dialog = memnew(AcceptDialog); result_dialog->set_title(TTR("Project Run")); result_dialog_log = memnew(RichTextLabel); @@ -182,6 +162,4 @@ EditorRunNative::EditorRunNative() { result_dialog->hide(); set_process(true); - resume_idx = 0; - resume_platform = 0; } diff --git a/editor/editor_run_native.h b/editor/editor_run_native.h index a87e27de97..2a5431e54b 100644 --- a/editor/editor_run_native.h +++ b/editor/editor_run_native.h @@ -42,18 +42,17 @@ class EditorRunNative : public HBoxContainer { RichTextLabel *result_dialog_log = nullptr; AcceptDialog *result_dialog = nullptr; - HashMap<int, MenuButton *> menus; + MenuButton *remote_debug = nullptr; bool first = true; - int resume_idx; - int resume_platform; + int resume_id = -1; protected: static void _bind_methods(); void _notification(int p_what); public: - Error run_native(int p_idx, int p_platform); + Error run_native(int p_id); bool is_deploy_debug_remote_enabled() const; void resume_run_native(); diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index 2881302775..f6054529f9 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -132,7 +132,7 @@ void EditorSettingsDialog::_notification(int p_what) { } break; case NOTIFICATION_READY: { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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); @@ -161,7 +161,7 @@ void EditorSettingsDialog::_notification(int p_what) { void EditorSettingsDialog::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); const Ref<InputEventKey> k = p_event; if (k.is_valid() && k->is_pressed()) { @@ -232,7 +232,7 @@ void EditorSettingsDialog::_event_config_confirmed() { void EditorSettingsDialog::_update_builtin_action(const String &p_name, const Array &p_events) { Array old_input_array = EditorSettings::get_singleton()->get_builtin_action_overrides(p_name); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Edit Built-in Action") + " '" + p_name + "'"); undo_redo->add_do_method(EditorSettings::get_singleton(), "mark_setting_changed", "builtin_action_overrides"); undo_redo->add_undo_method(EditorSettings::get_singleton(), "mark_setting_changed", "builtin_action_overrides"); @@ -248,7 +248,7 @@ void EditorSettingsDialog::_update_builtin_action(const String &p_name, const Ar void EditorSettingsDialog::_update_shortcut_events(const String &p_path, const Array &p_events) { Ref<Shortcut> current_sc = EditorSettings::get_singleton()->get_shortcut(p_path); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Edit Shortcut") + " '" + p_path + "'"); undo_redo->add_do_method(current_sc.ptr(), "set_events", p_events); undo_redo->add_undo_method(current_sc.ptr(), "set_events", current_sc->get_events()); diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp index 2ef52bd85a..f65f905b25 100644 --- a/editor/editor_undo_redo_manager.cpp +++ b/editor/editor_undo_redo_manager.cpp @@ -39,6 +39,8 @@ #include "editor/editor_node.h" #include "scene/main/node.h" +EditorUndoRedoManager *EditorUndoRedoManager::singleton = nullptr; + EditorUndoRedoManager::History &EditorUndoRedoManager::get_or_create_history(int p_idx) { if (!history_map.has(p_idx)) { History history; @@ -503,6 +505,16 @@ void EditorUndoRedoManager::_bind_methods() { BIND_ENUM_CONSTANT(INVALID_HISTORY); } +EditorUndoRedoManager *EditorUndoRedoManager::get_singleton() { + return singleton; +} + +EditorUndoRedoManager::EditorUndoRedoManager() { + if (!singleton) { + singleton = this; + } +} + 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 index 960d17d410..10daeae807 100644 --- a/editor/editor_undo_redo_manager.h +++ b/editor/editor_undo_redo_manager.h @@ -32,11 +32,13 @@ #define EDITOR_UNDO_REDO_MANAGER_H #include "core/object/class_db.h" -#include "core/object/ref_counted.h" +#include "core/object/object.h" #include "core/object/undo_redo.h" -class EditorUndoRedoManager : public RefCounted { - GDCLASS(EditorUndoRedoManager, RefCounted); +class EditorUndoRedoManager : public Object { + GDCLASS(EditorUndoRedoManager, Object); + + static EditorUndoRedoManager *singleton; public: enum SpecialHistory { @@ -132,6 +134,9 @@ public: int get_current_action_history_id(); void discard_history(int p_idx, bool p_erase_from_map = true); + + static EditorUndoRedoManager *get_singleton(); + EditorUndoRedoManager(); ~EditorUndoRedoManager(); }; diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index f48cabf207..cc96107f97 100644 --- a/editor/export/editor_export.cpp +++ b/editor/export/editor_export.cpp @@ -170,6 +170,12 @@ void EditorExport::_notification(int p_what) { case NOTIFICATION_PROCESS: { update_export_presets(); } break; + + case NOTIFICATION_EXIT_TREE: { + for (int i = 0; i < export_platforms.size(); i++) { + export_platforms.write[i]->cleanup(); + } + } break; } } diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index ef6c835b38..cacd181ad8 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -786,6 +786,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & HashSet<String> paths; Vector<String> path_remaps; + paths.insert(ProjectSettings::get_singleton()->get_project_data_path().path_join("global_script_class_cache.cfg")); if (p_preset->get_export_filter() == EditorExportPreset::EXPORT_ALL_RESOURCES) { //find stuff _export_find_resources(EditorFileSystem::get_singleton()->get_filesystem(), paths); @@ -1322,6 +1323,121 @@ Error EditorExportPlatform::_add_shared_object(void *p_userdata, const SharedObj return OK; } +void EditorExportPlatform::zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) { + String dir = p_folder.is_empty() ? p_root_path : p_root_path.path_join(p_folder); + + Ref<DirAccess> da = DirAccess::open(dir); + da->list_dir_begin(); + String f = da->get_next(); + while (!f.is_empty()) { + if (f == "." || f == "..") { + f = da->get_next(); + continue; + } + if (da->is_link(f)) { + OS::DateTime dt = OS::get_singleton()->get_datetime(); + + zip_fileinfo zipfi; + zipfi.tmz_date.tm_year = dt.year; + zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/ + zipfi.tmz_date.tm_mday = dt.day; + zipfi.tmz_date.tm_hour = dt.hour; + zipfi.tmz_date.tm_min = dt.minute; + zipfi.tmz_date.tm_sec = dt.second; + zipfi.dosDate = 0; + // 0120000: symbolic link type + // 0000755: permissions rwxr-xr-x + // 0000644: permissions rw-r--r-- + uint32_t _mode = 0120644; + zipfi.external_fa = (_mode << 16L) | !(_mode & 0200); + zipfi.internal_fa = 0; + + zipOpenNewFileInZip4(p_zip, + p_folder.path_join(f).utf8().get_data(), + &zipfi, + nullptr, + 0, + nullptr, + 0, + nullptr, + Z_DEFLATED, + Z_DEFAULT_COMPRESSION, + 0, + -MAX_WBITS, + DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, + nullptr, + 0, + 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions + 0); + + String target = da->read_link(f); + zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size()); + zipCloseFileInZip(p_zip); + } else if (da->current_is_dir()) { + zip_folder_recursive(p_zip, p_root_path, p_folder.path_join(f), p_pkg_name); + } else { + bool _is_executable = is_executable(dir.path_join(f)); + + OS::DateTime dt = OS::get_singleton()->get_datetime(); + + zip_fileinfo zipfi; + zipfi.tmz_date.tm_year = dt.year; + zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/ + zipfi.tmz_date.tm_mday = dt.day; + zipfi.tmz_date.tm_hour = dt.hour; + zipfi.tmz_date.tm_min = dt.minute; + zipfi.tmz_date.tm_sec = dt.second; + zipfi.dosDate = 0; + // 0100000: regular file type + // 0000755: permissions rwxr-xr-x + // 0000644: permissions rw-r--r-- + uint32_t _mode = (_is_executable ? 0100755 : 0100644); + zipfi.external_fa = (_mode << 16L) | !(_mode & 0200); + zipfi.internal_fa = 0; + + zipOpenNewFileInZip4(p_zip, + p_folder.path_join(f).utf8().get_data(), + &zipfi, + nullptr, + 0, + nullptr, + 0, + nullptr, + Z_DEFLATED, + Z_DEFAULT_COMPRESSION, + 0, + -MAX_WBITS, + DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, + nullptr, + 0, + 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions + 0); + + Ref<FileAccess> fa = FileAccess::open(dir.path_join(f), FileAccess::READ); + if (fa.is_null()) { + add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.path_join(f))); + return; + } + const int bufsize = 16384; + uint8_t buf[bufsize]; + + while (true) { + uint64_t got = fa->get_buffer(buf, bufsize); + if (got == 0) { + break; + } + zipWriteInFileInZip(p_zip, buf, got); + } + + zipCloseFileInZip(p_zip); + } + f = da->get_next(); + } + da->list_dir_end(); +} + Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files, bool p_embed, int64_t *r_embedded_start, int64_t *r_embedded_size) { EditorProgress ep("savepack", TTR("Packing"), 102, true); @@ -1642,5 +1758,123 @@ bool EditorExportPlatform::can_export(const Ref<EditorExportPreset> &p_preset, S return valid; } +Error EditorExportPlatform::ssh_run_on_remote(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, String *r_out, int p_port_fwd) const { + String ssh_path = EditorSettings::get_singleton()->get("export/ssh/ssh"); + if (ssh_path.is_empty()) { + ssh_path = "ssh"; + } + + List<String> args; + args.push_back("-p"); + args.push_back(p_port); + for (const String &E : p_ssh_args) { + args.push_back(E); + } + if (p_port_fwd > 0) { + args.push_back("-R"); + args.push_back(vformat("%d:localhost:%d", p_port_fwd, p_port_fwd)); + } + args.push_back(p_host); + args.push_back(p_cmd_args); + + String out; + int exit_code = -1; + + if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print("Executing: %s", ssh_path.utf8().get_data()); + for (const String &arg : args) { + OS::get_singleton()->print(" %s", arg.utf8().get_data()); + } + OS::get_singleton()->print("\n"); + } + + Error err = OS::get_singleton()->execute(ssh_path, args, &out, &exit_code, true); + if (out.is_empty()) { + print_verbose(vformat("Exit code: %d", exit_code)); + } else { + print_verbose(vformat("Exit code: %d, Output: %s", exit_code, out.replace("\r\n", "\n"))); + } + if (r_out) { + *r_out = out.replace("\r\n", "\n").get_slice("\n", 0); + } + if (err != OK) { + return err; + } else if (exit_code != 0) { + if (!out.is_empty()) { + print_line(out); + } + return FAILED; + } + return OK; +} + +Error EditorExportPlatform::ssh_run_on_remote_no_wait(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, OS::ProcessID *r_pid, int p_port_fwd) const { + String ssh_path = EditorSettings::get_singleton()->get("export/ssh/ssh"); + if (ssh_path.is_empty()) { + ssh_path = "ssh"; + } + + List<String> args; + args.push_back("-p"); + args.push_back(p_port); + for (const String &E : p_ssh_args) { + args.push_back(E); + } + if (p_port_fwd > 0) { + args.push_back("-R"); + args.push_back(vformat("%d:localhost:%d", p_port_fwd, p_port_fwd)); + } + args.push_back(p_host); + args.push_back(p_cmd_args); + + if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print("Executing: %s", ssh_path.utf8().get_data()); + for (const String &arg : args) { + OS::get_singleton()->print(" %s", arg.utf8().get_data()); + } + OS::get_singleton()->print("\n"); + } + + return OS::get_singleton()->create_process(ssh_path, args, r_pid); +} + +Error EditorExportPlatform::ssh_push_to_remote(const String &p_host, const String &p_port, const Vector<String> &p_scp_args, const String &p_src_file, const String &p_dst_file) const { + String scp_path = EditorSettings::get_singleton()->get("export/ssh/scp"); + if (scp_path.is_empty()) { + scp_path = "scp"; + } + + List<String> args; + args.push_back("-P"); + args.push_back(p_port); + for (const String &E : p_scp_args) { + args.push_back(E); + } + args.push_back(p_src_file); + args.push_back(vformat("%s:%s", p_host, p_dst_file)); + + String out; + int exit_code = -1; + + if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print("Executing: %s", scp_path.utf8().get_data()); + for (const String &arg : args) { + OS::get_singleton()->print(" %s", arg.utf8().get_data()); + } + OS::get_singleton()->print("\n"); + } + + Error err = OS::get_singleton()->execute(scp_path, args, &out, &exit_code, true); + if (err != OK) { + return err; + } else if (exit_code != 0) { + if (!out.is_empty()) { + print_line(out); + } + return FAILED; + } + return OK; +} + EditorExportPlatform::EditorExportPlatform() { } diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h index d3d8a8f186..1fb35759ac 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -35,6 +35,7 @@ class EditorFileSystemDirectory; struct EditorProgress; #include "core/io/dir_access.h" +#include "core/io/zip_io.h" #include "editor_export_preset.h" #include "editor_export_shared_object.h" #include "scene/gui/rich_text_label.h" @@ -92,7 +93,6 @@ private: void _export_find_resources(EditorFileSystemDirectory *p_dir, HashSet<String> &p_paths); void _export_find_dependencies(const String &p_path, HashSet<String> &p_paths); - void gen_debug_flags(Vector<String> &r_flags, int p_flags); static Error _save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key); static Error _save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key); @@ -126,6 +126,13 @@ protected: bool exists_export_template(String template_file_name, String *err) const; String find_export_template(String template_file_name, String *err = nullptr) const; void gen_export_flags(Vector<String> &r_flags, int p_flags); + void gen_debug_flags(Vector<String> &r_flags, int p_flags); + + virtual void zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name); + + Error ssh_run_on_remote(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, String *r_out = nullptr, int p_port_fwd = -1) const; + Error ssh_run_on_remote_no_wait(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, OS::ProcessID *r_pid = nullptr, int p_port_fwd = -1) const; + Error ssh_push_to_remote(const String &p_host, const String &p_port, const Vector<String> &p_scp_args, const String &p_src_file, const String &p_dst_file) const; public: virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const = 0; @@ -215,6 +222,7 @@ public: DEBUG_FLAG_VIEW_NAVIGATION = 16, }; + virtual void cleanup() {} virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) { return OK; } virtual Ref<Texture2D> get_run_icon() const { return get_logo(); } diff --git a/editor/export/editor_export_platform_pc.h b/editor/export/editor_export_platform_pc.h index c71a62ee5c..8c24f2fc68 100644 --- a/editor/export/editor_export_platform_pc.h +++ b/editor/export/editor_export_platform_pc.h @@ -62,7 +62,6 @@ public: virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { return OK; }; virtual Error export_project_data(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags); - void set_extension(const String &p_extension, const String &p_feature_key = "default"); void set_name(const String &p_name); void set_os_name(const String &p_name); diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp index f34ebfa541..784dbc116a 100644 --- a/editor/export/editor_export_plugin.cpp +++ b/editor/export/editor_export_plugin.cpp @@ -34,6 +34,7 @@ #include "core/io/dir_access.h" #include "core/io/file_access.h" #include "editor/editor_paths.h" +#include "editor/editor_settings.h" #include "editor/export/editor_export_platform.h" #include "scene/resources/resource_format_text.h" @@ -226,4 +227,8 @@ void EditorExportPlugin::_bind_methods() { } EditorExportPlugin::EditorExportPlugin() { + GLOBAL_DEF("editor/export/convert_text_resources_to_binary", false); + + EDITOR_DEF("export/ssh/ssh", ""); + EDITOR_DEF("export/ssh/scp", ""); } diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index df5d2dcd29..7136b4ceb6 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -480,7 +480,7 @@ void ProjectExportDialog::_enc_filters_changed(const String &p_filters) { } void ProjectExportDialog::_open_key_help_link() { - OS::get_singleton()->shell_open(vformat("%s/development/compiling/compiling_with_script_encryption_key.html", VERSION_DOCS_URL)); + OS::get_singleton()->shell_open(vformat("%s/contributing/development/compiling/compiling_with_script_encryption_key.html", VERSION_DOCS_URL)); } void ProjectExportDialog::_enc_pck_changed(bool p_pressed) { diff --git a/editor/fbx_importer_manager.cpp b/editor/fbx_importer_manager.cpp index dfea2e706a..2a005034a5 100644 --- a/editor/fbx_importer_manager.cpp +++ b/editor/fbx_importer_manager.cpp @@ -144,12 +144,8 @@ FBXImporterManager::FBXImporterManager() { browse_dialog = memnew(EditorFileDialog); browse_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); browse_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); -#if defined(X11_ENABLED) - browse_dialog->add_filter("FBX2glTF-linux-x86_64"); -#elif defined(OSX_ENABLED) - browse_dialog->add_filter("FBX2glTF-macos-x86_64"); -#elif defined(WINDOWS_ENABLED) - browse_dialog->add_filter("FBX2glTF-windows-x86_64"); +#ifdef WINDOWS_ENABLED + browse_dialog->add_filter("*.exe"); #endif browse_dialog->connect("file_selected", callable_mp(this, &FBXImporterManager::_select_file)); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 6eed3e3e61..17cdab60c8 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -2051,7 +2051,8 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected if (!fpath.ends_with("/")) { fpath = fpath.get_base_dir(); } - ScriptEditor::get_singleton()->open_text_file_create_dialog(fpath); + String dir = ProjectSettings::get_singleton()->globalize_path(fpath); + ScriptEditor::get_singleton()->open_text_file_create_dialog(dir); } break; } } diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 3ee7d5ddd8..7f0417ea29 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -130,7 +130,7 @@ void GroupDialog::_add_pressed() { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add to Group")); while (selected) { @@ -160,7 +160,7 @@ void GroupDialog::_removed_pressed() { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove from Group")); while (selected) { @@ -248,7 +248,7 @@ void GroupDialog::_group_renamed() { renamed_group->set_text(0, name); // Spaces trimmed. - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Rename Group")); List<Node *> nodes; @@ -325,7 +325,7 @@ void GroupDialog::_modify_group_pressed(Object *p_item, int p_column, int p_id, case DELETE_GROUP: { String name = ti->get_text(0); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete Group")); List<Node *> nodes; @@ -597,7 +597,7 @@ void GroupsEditor::_add_group(const String &p_group) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add to Group")); undo_redo->add_do_method(node, "add_to_group", name, true); @@ -652,7 +652,7 @@ void GroupsEditor::_group_renamed() { ti->set_text(0, name); // Spaces trimmed. - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Rename Group")); undo_redo->add_do_method(node, "remove_from_group", selected_group); @@ -688,7 +688,7 @@ void GroupsEditor::_modify_group(Object *p_item, int p_column, int p_id, MouseBu switch (p_id) { case DELETE_GROUP: { const String name = ti->get_text(0); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove from Group")); undo_redo->add_do_method(node, "remove_from_group", name); diff --git a/editor/history_dock.cpp b/editor/history_dock.cpp index f9fe1093b8..41ca519400 100644 --- a/editor/history_dock.cpp +++ b/editor/history_dock.cpp @@ -221,7 +221,7 @@ void HistoryDock::_notification(int p_notification) { HistoryDock::HistoryDock() { set_name("History"); - ur_manager = EditorNode::get_undo_redo(); + ur_manager = EditorUndoRedoManager::get_singleton(); ur_manager->connect("history_changed", callable_mp(this, &HistoryDock::on_history_changed)); ur_manager->connect("version_changed", callable_mp(this, &HistoryDock::on_version_changed)); diff --git a/editor/history_dock.h b/editor/history_dock.h index 81d1d02b79..d507f19b07 100644 --- a/editor/history_dock.h +++ b/editor/history_dock.h @@ -40,7 +40,7 @@ class EditorUndoRedoManager; class HistoryDock : public VBoxContainer { GDCLASS(HistoryDock, VBoxContainer); - Ref<EditorUndoRedoManager> ur_manager; + EditorUndoRedoManager *ur_manager; ItemList *action_list = nullptr; CheckBox *current_scene_checkbox = nullptr; diff --git a/editor/icons/PlayRemote.svg b/editor/icons/PlayRemote.svg new file mode 100644 index 0000000000..ea2195294f --- /dev/null +++ b/editor/icons/PlayRemote.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16"><path d="m12.998 2.548-9.996.005a2.006 2.006 0 0 0-2.006 2v4.61c0 1.107.898 2.003 2.006 2.003h3.996v.9h-1.68v.381H3.001v2h2.315v.38h5.366v-.38H13v-2.004h-2.315v-.378H9.004v-.9h3.994a2.006 2.006 0 0 0 2.006-2.003v-4.61c0-1.106-.9-2.003-2.006-2.003zm-7.496 1.31 5 3-5 3z" style="fill:#e0e0e0;fill-opacity:1"/></svg> diff --git a/editor/icons/README.md b/editor/icons/README.md index 3159565180..d191000985 100644 --- a/editor/icons/README.md +++ b/editor/icons/README.md @@ -3,5 +3,5 @@ This folder contains all the icons used by Godot editor (except for platform icons which are located in their respective platform folder). -See [Editor icons](https://docs.godotengine.org/en/latest/development/editor/creating_icons.html) +See [Editor icons](https://docs.godotengine.org/en/latest/contributing/development/editor/creating_icons.html) in the documentation for details on creating icons for the Godot editor. diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp index 7187e85df0..ba48fc9029 100644 --- a/editor/import/resource_importer_shader_file.cpp +++ b/editor/import/resource_importer_shader_file.cpp @@ -91,6 +91,7 @@ static String _include_function(const String &p_path, void *userpointer) { Error ResourceImporterShaderFile::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { /* STEP 1, Read shader code */ + ERR_FAIL_COND_V_EDMSG((OS::get_singleton()->get_current_rendering_method() == "gl_compatibility"), ERR_UNAVAILABLE, "Cannot import custom .glsl shaders when using the gl_compatibility rendering_method. Please switch to the forward_plus or mobile rendering methods to use custom shaders."); Error err; Ref<FileAccess> file = FileAccess::open(p_source_file, FileAccess::READ, &err); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 4cd8976e80..b28373e308 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -186,8 +186,8 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) { } } - int history_id = editor_data->get_undo_redo()->get_history_for_object(current).id; - editor_data->get_undo_redo()->clear_history(true, history_id); + int history_id = EditorUndoRedoManager::get_singleton()->get_history_for_object(current).id; + EditorUndoRedoManager::get_singleton()->clear_history(true, history_id); EditorNode::get_singleton()->get_editor_plugins_over()->edit(nullptr); EditorNode::get_singleton()->get_editor_plugins_over()->edit(current); diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp index 6fa980a8e5..5503645930 100644 --- a/editor/localization_editor.cpp +++ b/editor/localization_editor.cpp @@ -33,7 +33,6 @@ #include "core/config/project_settings.h" #include "core/string/translation.h" #include "editor/editor_file_dialog.h" -#include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_translation_parser.h" #include "editor/editor_undo_redo_manager.h" @@ -81,7 +80,7 @@ void LocalizationEditor::_translation_add(const PackedStringArray &p_paths) { } } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Add %d Translations"), p_paths.size())); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", translations); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", GLOBAL_GET("internationalization/locale/translations")); @@ -112,7 +111,7 @@ void LocalizationEditor::_translation_delete(Object *p_item, int p_column, int p translations.remove_at(idx); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Translation")); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", translations); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", GLOBAL_GET("internationalization/locale/translations")); @@ -143,7 +142,7 @@ void LocalizationEditor::_translation_res_add(const PackedStringArray &p_paths) } } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Translation Resource Remap: Add %d Path(s)"), p_paths.size())); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", prev); @@ -175,7 +174,7 @@ void LocalizationEditor::_translation_res_option_add(const PackedStringArray &p_ } remaps[key] = r; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Translation Resource Remap: Add %d Remap(s)"), p_paths.size())); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps")); @@ -239,7 +238,7 @@ void LocalizationEditor::_translation_res_option_changed() { updating_translations = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Resource Remap Language")); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps")); @@ -273,7 +272,7 @@ void LocalizationEditor::_translation_res_delete(Object *p_item, int p_column, i remaps.erase(key); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Resource Remap")); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps")); @@ -313,7 +312,7 @@ void LocalizationEditor::_translation_res_option_delete(Object *p_item, int p_co r.remove_at(idx); remaps[key] = r; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Resource Remap Option")); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps")); @@ -332,7 +331,7 @@ void LocalizationEditor::_pot_add(const PackedStringArray &p_paths) { } } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Add %d file(s) for POT generation"), p_paths.size())); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", pot_translations); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", GLOBAL_GET("internationalization/locale/translations_pot_files")); @@ -359,7 +358,7 @@ void LocalizationEditor::_pot_delete(Object *p_item, int p_column, int p_button, pot_translations.remove_at(idx); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove file from POT generation")); undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", pot_translations); undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", GLOBAL_GET("internationalization/locale/translations_pot_files")); diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp index dbbcd57742..2a55ac949f 100644 --- a/editor/multi_node_edit.cpp +++ b/editor/multi_node_edit.cpp @@ -55,7 +55,7 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value, node_path_target = es->get_node(p_value); } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(vformat(TTR("Set %s on %d nodes"), name, get_node_count()), UndoRedo::MERGE_ENDS); for (const NodePath &E : nodes) { diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index 8e94ae871b..7c23e19564 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -91,7 +91,7 @@ void AbstractPolygon2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) void AbstractPolygon2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { Node2D *node = _get_node(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(node, "set_polygon", p_polygon); undo_redo->add_undo_method(node, "set_polygon", p_previous); } @@ -101,7 +101,7 @@ Vector2 AbstractPolygon2DEditor::_get_offset(int p_idx) const { } void AbstractPolygon2DEditor::_commit_action() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(canvas_item_editor, "update_viewport"); undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); undo_redo->commit_action(); @@ -205,7 +205,7 @@ void AbstractPolygon2DEditor::_wip_close() { if (_is_line()) { _set_polygon(0, wip); } else if (wip.size() >= (_is_line() ? 2 : 3)) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Create Polygon")); _action_add_polygon(wip); if (_has_uv()) { @@ -257,7 +257,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) return false; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Ref<InputEventMouseButton> mb = p_event; if (!_has_resource()) { @@ -619,7 +619,7 @@ void AbstractPolygon2DEditor::_bind_methods() { } void AbstractPolygon2DEditor::remove_point(const Vertex &p_vertex) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Vector<Vector2> vertices = _get_polygon(p_vertex.polygon); if (vertices.size() > (_is_line() ? 2 : 3)) { diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index 85cca23e64..33aebe5883 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -157,7 +157,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Move Node Point")); undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point); undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); @@ -351,7 +351,7 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) { } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change BlendSpace1D Config")); undo_redo->add_do_method(blend_space.ptr(), "set_max_space", max_value->get_value()); undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space()); @@ -375,7 +375,7 @@ void AnimationNodeBlendSpace1DEditor::_labels_changed(String) { } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change BlendSpace1D Labels"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(blend_space.ptr(), "set_value_label", label_value->get_text()); undo_redo->add_undo_method(blend_space.ptr(), "set_value_label", blend_space->get_value_label()); @@ -431,7 +431,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) { } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Node Point")); undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos); undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); @@ -450,7 +450,7 @@ void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) { anim->set_animation(animations_to_add[p_index]); updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Animation Point")); undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos); undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); @@ -524,7 +524,7 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() { if (selected_point != -1) { updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove BlendSpace1D Point")); undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point); undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", blend_space->get_blend_point_node(selected_point), blend_space->get_blend_point_position(selected_point), selected_point); @@ -544,7 +544,7 @@ void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) { } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Move BlendSpace1D Node Point")); undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, edit_value->get_value()); undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index c22f0a9f15..7f8137f8d5 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -228,7 +228,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Triangle")); undo_redo->add_do_method(blend_space.ptr(), "add_triangle", making_triangle[0], making_triangle[1], making_triangle[2]); undo_redo->add_undo_method(blend_space.ptr(), "remove_triangle", blend_space->get_triangle_count()); @@ -254,7 +254,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven if (!read_only) { updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Move Node Point")); undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point); undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); @@ -362,7 +362,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Node Point")); undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos); undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); @@ -381,7 +381,7 @@ void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) { anim->set_animation(animations_to_add[p_index]); updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Animation Point")); undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos); undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); @@ -676,7 +676,7 @@ void AnimationNodeBlendSpace2DEditor::_config_changed(double) { } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change BlendSpace2D Config")); undo_redo->add_do_method(blend_space.ptr(), "set_max_space", Vector2(max_x_value->get_value(), max_y_value->get_value())); undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space()); @@ -702,7 +702,7 @@ void AnimationNodeBlendSpace2DEditor::_labels_changed(String) { } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change BlendSpace2D Labels"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(blend_space.ptr(), "set_x_label", label_x->get_text()); undo_redo->add_undo_method(blend_space.ptr(), "set_x_label", blend_space->get_x_label()); @@ -715,7 +715,7 @@ void AnimationNodeBlendSpace2DEditor::_labels_changed(String) { } void AnimationNodeBlendSpace2DEditor::_erase_selected() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (selected_point != -1) { updating = true; undo_redo->create_action(TTR("Remove BlendSpace2D Point")); @@ -778,7 +778,7 @@ void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) { return; } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Move Node Point")); undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, Vector2(edit_x->get_value(), edit_y->get_value())); undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); @@ -856,7 +856,7 @@ void AnimationNodeBlendSpace2DEditor::_open_editor() { } void AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Toggle Auto Triangles")); undo_redo->add_do_method(blend_space.ptr(), "set_auto_triangles", auto_triangles->is_pressed()); undo_redo->add_undo_method(blend_space.ptr(), "set_auto_triangles", blend_space->get_auto_triangles()); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index f680993026..14e3cb4b97 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -103,7 +103,7 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert return; } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS); undo_redo->add_do_property(tree, p_property, p_value); undo_redo->add_undo_property(tree, p_property, tree->get(p_property)); @@ -363,7 +363,7 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { name = base_name + " " + itos(base); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Node to BlendTree")); undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode, instance_pos / EDSCALE); undo_redo->add_undo_method(blend_tree.ptr(), "remove_node", name); @@ -432,7 +432,7 @@ void AnimationNodeBlendTreeEditor::_popup_hide() { void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which) { updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Node Moved")); undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE); undo_redo->add_undo_method(blend_tree.ptr(), "set_node_position", p_which, p_from / EDSCALE); @@ -454,7 +454,7 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Nodes Connected")); undo_redo->add_do_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from); undo_redo->add_undo_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index); @@ -471,7 +471,7 @@ void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from, graph->disconnect_node(p_from, p_from_index, p_to, p_to_index); updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Nodes Disconnected")); undo_redo->add_do_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index); undo_redo->add_undo_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from); @@ -487,7 +487,7 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options, Ref<AnimationNodeAnimation> anim = blend_tree->get_node(p_node); ERR_FAIL_COND(!anim.is_valid()); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set Animation")); undo_redo->add_do_method(anim.ptr(), "set_animation", option); undo_redo->add_undo_method(anim.ptr(), "set_animation", anim->get_animation()); @@ -501,7 +501,7 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete Node")); undo_redo->add_do_method(blend_tree.ptr(), "remove_node", p_which); undo_redo->add_undo_method(blend_tree.ptr(), "add_node", p_which, blend_tree->get_node(p_which), blend_tree.ptr()->get_node_position(p_which)); @@ -546,7 +546,7 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<String return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete Node(s)")); for (const StringName &F : to_erase) { @@ -580,7 +580,7 @@ void AnimationNodeBlendTreeEditor::_open_in_editor(const String &p_which) { void AnimationNodeBlendTreeEditor::_filter_toggled() { updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Toggle Filter On/Off")); undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_enabled", filter_enabled->is_pressed()); undo_redo->add_undo_method(_filter_edit.ptr(), "set_filter_enabled", _filter_edit->is_filter_enabled()); @@ -598,7 +598,7 @@ void AnimationNodeBlendTreeEditor::_filter_edited() { bool filtered = edited->is_checked(0); updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Filter")); undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_path", edited_path, filtered); undo_redo->add_undo_method(_filter_edit.ptr(), "set_filter_path", edited_path, _filter_edit->is_path_filtered(edited_path)); @@ -981,7 +981,7 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima String base_path = AnimationTreeEditor::get_singleton()->get_base_path(); updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Node Renamed")); undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name); undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name); diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index 9decbef51b..d66982f31b 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -94,7 +94,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(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library); ERR_FAIL_COND(!al.is_valid()); @@ -111,7 +111,7 @@ void AnimationLibraryEditor::_add_library_confirm() { } else { String lib_name = add_library_name->get_text(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Ref<AnimationLibrary> al; al.instantiate(); @@ -211,7 +211,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { ald->add_animation(animation_name, animation); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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); @@ -280,7 +280,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { Ref<Animation> animd = anim->duplicate(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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); @@ -328,7 +328,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { name = p_path.get_file().get_basename() + " " + itos(attempt); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), name)); undo_redo->add_do_method(player, "add_animation_library", name, al); @@ -366,7 +366,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { name = p_path.get_file().get_basename() + " " + itos(attempt); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Load Animation into Library: %s"), name)); undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); @@ -382,7 +382,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. - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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()); @@ -403,7 +403,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. - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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()); @@ -421,7 +421,7 @@ void AnimationLibraryEditor::_item_renamed() { String text = ti->get_text(0); String old_text = ti->get_metadata(0); bool restore_text = false; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (String(text).contains("/") || String(text).contains(":") || String(text).contains(",") || String(text).contains("[")) { restore_text = true; @@ -535,7 +535,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int name = base_name + " (" + itos(attempt) + ")"; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), name)); undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); @@ -561,7 +561,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int file_dialog_library = lib_name; } break; case LIB_BUTTON_DELETE: { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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); @@ -602,7 +602,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int } break; case ANIM_BUTTON_DELETE: { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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 10f2ce25d9..caee7514d0 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -94,6 +94,7 @@ void AnimationPlayerEditor::_notification(int p_what) { // Need the last frame after it stopped. frame->set_value(player->get_current_animation_position()); track_editor->set_anim_pos(player->get_current_animation_position()); + stop->set_icon(stop_icon); } last_active = player->is_playing(); @@ -119,8 +120,15 @@ void AnimationPlayerEditor::_notification(int p_what) { case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_THEME_CHANGED: { - autoplay->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons"))); + stop_icon = get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")); + pause_icon = get_theme_icon(SNAME("Pause"), SNAME("EditorIcons")); + if (player && player->is_playing()) { + stop->set_icon(pause_icon); + } else { + stop->set_icon(stop_icon); + } + autoplay->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons"))); play->set_icon(get_theme_icon(SNAME("PlayStart"), SNAME("EditorIcons"))); play_from->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons"))); play_bw->set_icon(get_theme_icon(SNAME("PlayStartBackwards"), SNAME("EditorIcons"))); @@ -137,7 +145,6 @@ void AnimationPlayerEditor::_notification(int p_what) { autoplay_reset_img->blit_rect(reset_img, Rect2i(Point2i(), icon_size), Point2i(icon_size.x, 0)); autoplay_reset_icon = ImageTexture::create_from_image(autoplay_reset_img); } - stop->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"))); onion_toggle->set_icon(get_theme_icon(SNAME("Onion"), SNAME("EditorIcons"))); onion_skinning->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); @@ -170,7 +177,7 @@ void AnimationPlayerEditor::_autoplay_pressed() { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); String current = animation->get_item_text(animation->get_selected()); if (player->get_autoplay() == current) { //unset @@ -204,7 +211,7 @@ void AnimationPlayerEditor::_play_pressed() { } //unstop - stop->set_pressed(false); + stop->set_icon(pause_icon); } void AnimationPlayerEditor::_play_from_pressed() { @@ -221,7 +228,7 @@ void AnimationPlayerEditor::_play_from_pressed() { } //unstop - stop->set_pressed(false); + stop->set_icon(pause_icon); } String AnimationPlayerEditor::_get_current() const { @@ -242,7 +249,7 @@ void AnimationPlayerEditor::_play_bw_pressed() { } //unstop - stop->set_pressed(false); + stop->set_icon(pause_icon); } void AnimationPlayerEditor::_play_bw_from_pressed() { @@ -259,7 +266,7 @@ void AnimationPlayerEditor::_play_bw_from_pressed() { } //unstop - stop->set_pressed(false); + stop->set_icon(pause_icon); } void AnimationPlayerEditor::_stop_pressed() { @@ -267,9 +274,16 @@ void AnimationPlayerEditor::_stop_pressed() { return; } - player->pause(); - play->set_pressed(false); - stop->set_pressed(true); + if (player->is_playing()) { + player->pause(); + } else { + String current = _get_current(); + player->stop(); + player->set_assigned_animation(current); + frame->set_value(0); + track_editor->set_anim_pos(0); + } + stop->set_icon(stop_icon); } void AnimationPlayerEditor::_animation_selected(int p_which) { @@ -388,7 +402,7 @@ void AnimationPlayerEditor::_animation_remove_confirmed() { if (current.contains("/")) { current = current.get_slice("/", 1); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Animation")); if (player->get_autoplay() == current) { undo_redo->add_do_method(player, "set_autoplay", ""); @@ -464,7 +478,7 @@ void AnimationPlayerEditor::_animation_name_edited() { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (name_dialog_op) { case TOOL_RENAME_ANIM: { String current = animation->get_item_text(animation->get_selected()); @@ -599,7 +613,7 @@ void AnimationPlayerEditor::_blend_editor_next_changed(const int p_idx) { String current = animation->get_item_text(animation->get_selected()); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Blend Next Changed")); undo_redo->add_do_method(player, "animation_set_next", current, blend_editor.next->get_item_text(p_idx)); undo_redo->add_undo_method(player, "animation_set_next", current, player->animation_get_next(current)); @@ -686,7 +700,7 @@ void AnimationPlayerEditor::_blend_edited() { float blend_time = selected->get_range(1); float prev_blend_time = player->get_blend_time(current, to); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Blend Time")); undo_redo->add_do_method(player, "set_blend_time", current, to, blend_time); undo_redo->add_undo_method(player, "set_blend_time", current, to, prev_blend_time); @@ -798,12 +812,9 @@ void AnimationPlayerEditor::_update_animation() { updating = true; if (player->is_playing()) { - play->set_pressed(true); - stop->set_pressed(false); - + stop->set_icon(pause_icon); } else { - play->set_pressed(false); - stop->set_pressed(true); + stop->set_icon(stop_icon); } scale->set_text(String::num(player->get_speed_scale(), 2)); @@ -1663,7 +1674,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug stop = memnew(Button); stop->set_flat(true); - stop->set_toggle_mode(true); hb->add_child(stop); stop->set_tooltip_text(TTR("Stop animation playback. (S)")); diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 6c690c812c..327200506f 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -101,6 +101,8 @@ class AnimationPlayerEditor : public VBoxContainer { OptionButton *library = nullptr; Label *name_title = nullptr; + Ref<Texture2D> stop_icon; + Ref<Texture2D> pause_icon; Ref<Texture2D> autoplay_icon; Ref<Texture2D> reset_icon; Ref<ImageTexture> autoplay_reset_icon; diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 0de5064a00..a675495429 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -246,7 +246,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv Ref<AnimationNode> an = state_machine->get_node(selected_node); updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Move Node")); for (int i = 0; i < node_rects.size(); i++) { @@ -543,7 +543,7 @@ void AnimationNodeStateMachineEditor::_group_selected_nodes() { } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action("Group"); // Move selected nodes to the new state machine @@ -658,7 +658,7 @@ void AnimationNodeStateMachineEditor::_ungroup_selected_nodes() { Vector<TransitionUR> transitions_ur; updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action("Ungroup"); // Move all child nodes to current state machine @@ -935,7 +935,7 @@ void AnimationNodeStateMachineEditor::_stop_connecting() { void AnimationNodeStateMachineEditor::_delete_selected() { TreeItem *item = delete_tree->get_next_selected(nullptr); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); while (item) { if (!updating) { updating = true; @@ -963,7 +963,7 @@ void AnimationNodeStateMachineEditor::_delete_all() { selected_multi_transition = TransitionLine(); updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action("Transition(s) Removed"); _erase_selected(true); for (int i = 0; i < multi_transitions.size(); i++) { @@ -1043,7 +1043,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Node and Transition")); undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node, add_node_pos); undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); @@ -1070,7 +1070,7 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) { } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Node and Transition")); undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim, add_node_pos); undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); @@ -1100,7 +1100,7 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action tr->set_advance_mode(auto_advance->is_pressed() ? AnimationNodeStateMachineTransition::AdvanceMode::ADVANCE_MODE_AUTO : AnimationNodeStateMachineTransition::AdvanceMode::ADVANCE_MODE_ENABLED); tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected())); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (!p_nested_action) { updating = true; undo_redo->create_action(TTR("Add Transition")); @@ -1778,7 +1778,7 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) { } updating = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Node Renamed")); undo_redo->add_do_method(state_machine.ptr(), "rename_node", prev_name, name); undo_redo->add_undo_method(state_machine.ptr(), "rename_node", name, prev_name); @@ -1813,7 +1813,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action if (!p_nested_action) { updating = true; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Node Removed")); for (int i = 0; i < node_rects.size(); i++) { @@ -1882,7 +1882,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action if (!p_nested_action) { updating = true; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Transition Removed")); undo_redo->add_do_method(state_machine.ptr(), "remove_transition", selected_transition_from, selected_transition_to); undo_redo->add_undo_method(state_machine.ptr(), "add_transition", selected_transition_from, selected_transition_to, tr); diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp index acd3271f97..bb3b8a124e 100644 --- a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp +++ b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp @@ -44,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) { - Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); - ERR_FAIL_COND(undo_redo_man.is_null()); + EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_NULL(undo_redo_man); 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 bd7b7ff1cb..4c14755b03 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -868,7 +868,7 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(action_name); for (CanvasItem *ci : modified_canvas_items) { CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci); @@ -933,7 +933,7 @@ void CanvasItemEditor::_add_node_pressed(int p_result) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Move Node(s) to Position")); for (Node *node : nodes_to_move) { CanvasItem *ci = Object::cast_to<CanvasItem>(node); @@ -1022,7 +1022,7 @@ void CanvasItemEditor::_on_grid_menu_id_pressed(int p_id) { } bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_event) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Ref<InputEventMouseButton> b = p_event; Ref<InputEventMouseMotion> m = p_event; @@ -1850,7 +1850,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { // Drag resize handles if (drag_type == DRAG_NONE) { - if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_ctrl_pressed()) || tool == TOOL_SCALE)) { + if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_command_or_control_pressed()) || tool == TOOL_SCALE)) { List<CanvasItem *> selection = _get_edited_canvas_items(); if (selection.size() == 1) { CanvasItem *ci = selection[0]; @@ -1897,7 +1897,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform; bool uniform = m->is_shift_pressed(); - bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL); + bool is_ctrl = m->is_ctrl_pressed(); Point2 drag_from_local = simple_xform.xform(drag_from); Point2 drag_to_local = simple_xform.xform(drag_to); @@ -1989,7 +1989,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { if (drag_type == DRAG_NONE) { //Start moving the nodes if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed()) { - if ((b->is_alt_pressed() && !b->is_ctrl_pressed()) || tool == TOOL_MOVE) { + if ((b->is_alt_pressed() && !b->is_command_or_control_pressed()) || tool == TOOL_MOVE) { List<CanvasItem *> selection = _get_edited_canvas_items(); drag_selection.clear(); @@ -3418,7 +3418,7 @@ void CanvasItemEditor::_draw_selection() { } // Draw the move handles - bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL); + bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL); bool is_alt = Input::get_singleton()->is_key_pressed(Key::ALT); if (tool == TOOL_MOVE && show_transformation_gizmos) { if (_is_node_movable(ci)) { @@ -4263,7 +4263,7 @@ void CanvasItemEditor::_update_override_camera_button(bool p_game_running) { } void CanvasItemEditor::_popup_callback(int p_op) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); last_option = MenuOption(p_op); switch (p_op) { case SHOW_ORIGIN: { @@ -5570,7 +5570,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & String name = path.get_file().get_basename(); child->set_name(Node::adjust_name_casing(name)); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Ref<Texture2D> texture = ResourceCache::get_ref(path); if (parent) { @@ -5649,7 +5649,7 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path)); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(parent, "add_child", instantiated_scene, true); undo_redo->add_do_method(instantiated_scene, "set_owner", edited_scene); undo_redo->add_do_reference(instantiated_scene); @@ -5690,7 +5690,7 @@ void CanvasItemEditorViewport::_perform_drop_data() { Vector<String> error_files; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Create Node")); for (int i = 0; i < selected_files.size(); i++) { diff --git a/editor/plugins/cast_2d_editor_plugin.cpp b/editor/plugins/cast_2d_editor_plugin.cpp index 078198e64b..723082c293 100644 --- a/editor/plugins/cast_2d_editor_plugin.cpp +++ b/editor/plugins/cast_2d_editor_plugin.cpp @@ -77,7 +77,7 @@ bool Cast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; } } else if (pressed) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set target_position")); undo_redo->add_do_property(node, "target_position", target_position); undo_redo->add_do_method(canvas_item_editor, "update_viewport"); diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index bed4658976..c2d5885e43 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -219,7 +219,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) { } void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set Handle")); switch (shape_type) { diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp index ad3e861b79..470b90aa7f 100644 --- a/editor/plugins/control_editor_plugin.cpp +++ b/editor/plugins/control_editor_plugin.cpp @@ -721,7 +721,7 @@ void ControlEditorToolbar::_anchors_preset_selected(int p_preset) { LayoutPreset preset = (LayoutPreset)p_preset; List<Node *> selection = editor_selection->get_selected_node_list(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Anchors, Offsets, Grow Direction")); for (Node *E : selection) { @@ -742,7 +742,7 @@ void ControlEditorToolbar::_anchors_preset_selected(int p_preset) { void ControlEditorToolbar::_anchors_to_current_ratio() { List<Node *> selection = editor_selection->get_selected_node_list(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Anchors, Offsets (Keep Ratio)")); for (Node *E : selection) { @@ -793,7 +793,7 @@ void ControlEditorToolbar::_anchor_mode_toggled(bool p_status) { void ControlEditorToolbar::_container_flags_selected(int p_flags, bool p_vertical) { List<Node *> selection = editor_selection->get_selected_node_list(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (p_vertical) { undo_redo->create_action(TTR("Change Vertical Size Flags")); } else { diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index b0bcda946e..20710bac19 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -140,7 +140,7 @@ 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) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent")); undo_redo->add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data()); undo_redo->add_undo_method(*_curve_ref, "_set_data", _undo_data); @@ -301,7 +301,7 @@ void CurveEditor::on_preset_item_selected(int preset_id) { break; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Load Curve Preset")); undo_redo->add_do_method(&curve, "_set_data", curve.get_data()); undo_redo->add_undo_method(&curve, "_set_data", previous_data); @@ -433,7 +433,7 @@ CurveEditor::TangentIndex CurveEditor::get_tangent_at(Vector2 pos) const { void CurveEditor::add_point(Vector2 pos) { ERR_FAIL_COND(_curve_ref.is_null()); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Curve Point")); Vector2 point_pos = get_world_pos(pos); @@ -455,7 +455,7 @@ void CurveEditor::add_point(Vector2 pos) { void CurveEditor::remove_point(int index) { ERR_FAIL_COND(_curve_ref.is_null()); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Curve Point")); Curve::Point p = _curve_ref->get_point(index); @@ -477,7 +477,7 @@ void CurveEditor::remove_point(int index) { void CurveEditor::toggle_linear(TangentIndex tangent) { ERR_FAIL_COND(_curve_ref.is_null()); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Toggle Curve Linear Tangent")); if (tangent == TANGENT_NONE) { @@ -621,8 +621,8 @@ struct CanvasItemPlotCurve { color2(p_color2) {} void operator()(Vector2 pos0, Vector2 pos1, bool in_definition) { - // FIXME: Using a line width greater than 1 breaks curve rendering - ci.draw_line(pos0, pos1, in_definition ? color1 : color2, 1); + // FIXME: Using a quad line breaks curve rendering. + ci.draw_line(pos0, pos1, in_definition ? color1 : color2, -1); } }; diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index 1a51224198..04b2a9337e 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -113,7 +113,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()); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -161,7 +161,7 @@ void GPUParticles2DEditorPlugin::_generate_visibility_rect() { particles->set_emitting(false); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Generate Visibility Rect")); undo_redo->add_do_method(particles, "set_visibility_rect", rect); undo_redo->add_undo_method(particles, "set_visibility_rect", particles->get_visibility_rect()); diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index 19ac553708..65f66c2661 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -274,7 +274,7 @@ void GPUParticles3DEditor::_menu_option(int p_option) { cpu_particles->set_visible(node->is_visible()); cpu_particles->set_process_mode(node->get_process_mode()); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -324,7 +324,7 @@ void GPUParticles3DEditor::_generate_aabb() { node->set_emitting(false); } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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.cpp b/editor/plugins/gradient_editor.cpp index 68aafd6fa8..3676c2c222 100644 --- a/editor/plugins/gradient_editor.cpp +++ b/editor/plugins/gradient_editor.cpp @@ -99,7 +99,7 @@ void GradientEditor::_gradient_changed() { void GradientEditor::_ramp_changed() { editing = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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 e03353a67b..7bd159a5b8 100644 --- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp +++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp @@ -55,7 +55,7 @@ void GradientTexture2DEditorRect::_update_fill_position() { String property_name = handle == HANDLE_FILL_FROM ? "fill_from" : "fill_to"; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Set %s"), property_name), UndoRedo::MERGE_ENDS); undo_redo->add_do_property(texture.ptr(), property_name, percent); undo_redo->add_undo_property(texture.ptr(), property_name, handle == HANDLE_FILL_FROM ? texture->get_fill_from() : texture->get_fill_to()); @@ -188,7 +188,7 @@ GradientTexture2DEditorRect::GradientTexture2DEditorRect() { /////////////////////// void GradientTexture2DEditor::_reverse_button_pressed() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Swap GradientTexture2D Fill Points")); undo_redo->add_do_property(texture.ptr(), "fill_from", texture->get_fill_to()); undo_redo->add_do_property(texture.ptr(), "fill_to", texture->get_fill_from()); diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp index bee1206b90..429add4540 100644 --- a/editor/plugins/light_occluder_2d_editor_plugin.cpp +++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp @@ -84,7 +84,7 @@ void LightOccluder2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) co void LightOccluder2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { Ref<OccluderPolygon2D> occluder = _ensure_occluder(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(occluder.ptr(), "set_polygon", p_polygon); undo_redo->add_undo_method(occluder.ptr(), "set_polygon", p_previous); } @@ -98,7 +98,7 @@ void LightOccluder2DEditor::_create_resource() { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Create Occluder Polygon")); undo_redo->add_do_method(node, "set_occluder_polygon", Ref<OccluderPolygon2D>(memnew(OccluderPolygon2D))); undo_redo->add_undo_method(node, "set_occluder_polygon", Variant(Ref<RefCounted>())); diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp index f2c487dd14..0185617c36 100644 --- a/editor/plugins/line_2d_editor_plugin.cpp +++ b/editor/plugins/line_2d_editor_plugin.cpp @@ -55,7 +55,7 @@ void Line2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) const { void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { Node2D *_node = _get_node(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(_node, "set_points", p_polygon); undo_redo->add_undo_method(_node, "set_points", p_previous); } diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index bb2bac7c04..36c143ca8d 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -291,8 +291,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) { - Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); - ERR_FAIL_COND(!undo_redo.is_valid()); + EditorUndoRedoManager *undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_NULL(undo_redo); // 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 6cc551d367..35b7367393 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -65,7 +65,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(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); List<Node *> selection = editor_selection->get_selected_node_list(); @@ -152,7 +152,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { Node *owner = get_tree()->get_edited_scene_root(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Create Trimesh Static Shape")); @@ -182,7 +182,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); if (simplify) { ur->create_action(TTR("Create Simplified Convex Shape")); @@ -222,7 +222,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Create Multiple Convex Shapes")); @@ -259,7 +259,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { Node *owner = get_tree()->get_edited_scene_root(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Create Navigation Mesh")); ur->add_do_method(node, "add_child", nmi, true); @@ -275,7 +275,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { outline_dialog->popup_centered(Vector2(200, 90)); } break; case MENU_OPTION_CREATE_DEBUG_TANGENTS: { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Create Debug Tangents")); MeshInstance3D *tangents = node->create_debug_tangents_node(); @@ -334,7 +334,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Unwrap UV2")); ur->add_do_method(node, "set_mesh", unwrapped_mesh); @@ -493,7 +493,7 @@ void MeshInstance3DEditor::_create_outline_mesh() { mi->set_mesh(mesho); Node *owner = get_tree()->get_edited_scene_root(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Create Outline")); diff --git a/editor/plugins/navigation_link_2d_editor_plugin.cpp b/editor/plugins/navigation_link_2d_editor_plugin.cpp index 53f9ff019f..21a1d839f0 100644 --- a/editor/plugins/navigation_link_2d_editor_plugin.cpp +++ b/editor/plugins/navigation_link_2d_editor_plugin.cpp @@ -85,7 +85,7 @@ bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e end_grabbed = false; } } else { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (start_grabbed) { undo_redo->create_action(TTR("Set start_location")); undo_redo->add_do_method(node, "set_start_location", node->get_start_location()); diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp index cbc225a7ff..957a520d8a 100644 --- a/editor/plugins/navigation_polygon_editor_plugin.cpp +++ b/editor/plugins/navigation_polygon_editor_plugin.cpp @@ -76,7 +76,7 @@ void NavigationPolygonEditor::_set_polygon(int p_idx, const Variant &p_polygon) void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) { Ref<NavigationPolygon> navpoly = _ensure_navpoly(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(navpoly.ptr(), "add_outline", p_polygon); undo_redo->add_undo_method(navpoly.ptr(), "remove_outline", navpoly->get_outline_count()); undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines"); @@ -85,7 +85,7 @@ void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) { void NavigationPolygonEditor::_action_remove_polygon(int p_idx) { Ref<NavigationPolygon> navpoly = _ensure_navpoly(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(navpoly.ptr(), "remove_outline", p_idx); undo_redo->add_undo_method(navpoly.ptr(), "add_outline_at_index", navpoly->get_outline(p_idx), p_idx); undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines"); @@ -94,7 +94,7 @@ void NavigationPolygonEditor::_action_remove_polygon(int p_idx) { void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { Ref<NavigationPolygon> navpoly = _ensure_navpoly(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(navpoly.ptr(), "set_outline", p_idx, p_polygon); undo_redo->add_undo_method(navpoly.ptr(), "set_outline", p_idx, p_previous); undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines"); @@ -110,7 +110,7 @@ void NavigationPolygonEditor::_create_resource() { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Create Navigation Polygon")); undo_redo->add_do_method(node, "set_navigation_polygon", Ref<NavigationPolygon>(memnew(NavigationPolygon))); undo_redo->add_undo_method(node, "set_navigation_polygon", Variant(Ref<RefCounted>())); diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 74db91a309..bb71c27bff 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -1337,13 +1337,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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -1562,7 +1562,7 @@ void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gi player->set_emission_angle(p_restore); } else { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -1823,7 +1823,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_ if (p_cancel) { camera->set("fov", p_restore); } else { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Change Camera FOV")); ur->add_do_property(camera, "fov", camera->get_fov()); ur->add_undo_property(camera, "fov", p_restore); @@ -1834,7 +1834,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_ if (p_cancel) { camera->set("size", p_restore); } else { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Change Camera Size")); ur->add_do_property(camera, "size", camera->get_size()); ur->add_undo_property(camera, "size", p_restore); @@ -2160,7 +2160,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -2174,7 +2174,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -2188,7 +2188,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -2902,7 +2902,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -3093,7 +3093,7 @@ void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -3259,7 +3259,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo * return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -3272,7 +3272,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo * return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -3531,7 +3531,7 @@ void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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()); @@ -3683,7 +3683,7 @@ void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -3823,7 +3823,7 @@ void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -4438,7 +4438,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -4452,7 +4452,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -4469,7 +4469,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); if (p_id == 0) { ur->create_action(TTR("Change Capsule Shape Radius")); ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); @@ -4494,7 +4494,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); if (p_id == 0) { ur->create_action(TTR("Change Cylinder Shape Radius")); ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); @@ -4519,7 +4519,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -5184,7 +5184,7 @@ void NavigationLink3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); if (p_id == 0) { ur->create_action(TTR("Change Start Location")); ur->add_do_method(link, "set_start_location", link->get_start_location()); @@ -5946,7 +5946,7 @@ void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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 4fe1a6c034..9198ebeca8 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -3104,7 +3104,7 @@ void Node3DEditorViewport::_draw() { } void Node3DEditorViewport::_menu_option(int p_option) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (p_option) { case VIEW_TOP: { cursor.y_rot = 0; @@ -4257,7 +4257,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path)); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(parent, "add_child", instantiated_scene, true); undo_redo->add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene()); undo_redo->add_do_reference(instantiated_scene); @@ -4286,7 +4286,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po } void Node3DEditorViewport::_perform_drop_data() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (spatial_editor->get_preview_material_target().is_valid()) { 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())); @@ -4496,7 +4496,7 @@ void Node3DEditorViewport::commit_transform() { TTRC("Translate"), TTRC("Scale"), }; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(_transform_name[_edit.mode]); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -6014,7 +6014,7 @@ void Node3DEditor::_xform_dialog_action() { t.basis.rotate(rotate); t.origin = translate; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("XForm Dialog")); const List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -6126,7 +6126,7 @@ void Node3DEditor::_update_camera_override_viewport(Object *p_viewport) { } void Node3DEditor::_menu_item_pressed(int p_option) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (p_option) { case MENU_TOOL_SELECT: case MENU_TOOL_MOVE: @@ -7312,7 +7312,7 @@ void Node3DEditor::_snap_selected_nodes_to_floor() { } if (snapped_to_floor) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Snap Nodes to Floor")); // Perform snapping if at least one node can be snapped @@ -7382,7 +7382,7 @@ void Node3DEditor::_add_sun_to_scene(bool p_already_added_environment) { ERR_FAIL_COND(!base); Node *new_sun = preview_sun->duplicate(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Preview Sun to Scene")); undo_redo->add_do_method(base, "add_child", new_sun, true); // Move to the beginning of the scene tree since more "global" nodes @@ -7416,7 +7416,7 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) { new_env->set_camera_attributes(preview_environment->get_camera_attributes()->duplicate(true)); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Preview Environment to Scene")); undo_redo->add_do_method(base, "add_child", new_env, true); // Move to the beginning of the scene tree since more "global" nodes diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index b78ffb7612..63f6643ba3 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -120,7 +120,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } // Check for point deletion. - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if ((mb->get_button_index() == MouseButton::RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == MouseButton::LEFT && mode == MODE_DELETE)) { if (dist_to_p < grab_threshold) { undo_redo->create_action(TTR("Remove Point from Curve")); @@ -155,7 +155,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && ((mb->is_command_or_control_pressed() && mode == MODE_EDIT) || mode == MODE_CREATE)) { Ref<Curve2D> curve = node->get_curve(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Point to Curve")); undo_redo->add_do_method(curve.ptr(), "add_point", cpoint); undo_redo->add_undo_method(curve.ptr(), "remove_point", curve->get_point_count()); @@ -191,7 +191,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { insertion_point = curve->get_point_count() - 2; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Split Curve")); undo_redo->add_do_method(curve.ptr(), "add_point", xform.affine_inverse().xform(gpoint2), Vector2(0, 0), Vector2(0, 0), insertion_point + 1); undo_redo->add_undo_method(curve.ptr(), "remove_point", insertion_point + 1); @@ -215,7 +215,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (!mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && action != ACTION_NONE) { Ref<Curve2D> curve = node->get_curve(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from); switch (action) { case ACTION_NONE: @@ -491,7 +491,7 @@ void Path2DEditor::_mode_selected(int p_mode) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Point from Curve")); undo_redo->add_do_method(node->get_curve().ptr(), "add_point", begin); undo_redo->add_undo_method(node->get_curve().ptr(), "remove_point", node->get_curve()->get_point_count()); diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index 917b8245a3..75cd04bee8 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -174,7 +174,7 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); if (!p_secondary) { if (p_cancel) { @@ -409,7 +409,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p } } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); if (closest_seg != -1) { //subdivide @@ -451,21 +451,21 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p // Find the offset and point index of the place to break up. // Also check for the control points. if (dist_to_p < click_dist) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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)); @@ -544,7 +544,7 @@ void Path3DEditorPlugin::_close_curve() { if (c->get_point_position(0) == c->get_point_position(c->get_point_count() - 1)) { return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 9d8f1a1578..05fc464226 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -156,7 +156,7 @@ void Polygon2DEditor::_sync_bones() { Array new_bones = node->call("_get_bones"); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Sync Bones")); undo_redo->add_do_method(node, "_set_bones", new_bones); undo_redo->add_undo_method(node, "_set_bones", prev_bones); @@ -286,7 +286,7 @@ void Polygon2DEditor::_uv_edit_popup_hide() { } void Polygon2DEditor::_menu_option(int p_option) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (p_option) { case MODE_EDIT_UV: { if (node->get_texture().is_null()) { @@ -399,7 +399,7 @@ void Polygon2DEditor::_update_polygon_editing_state() { void Polygon2DEditor::_commit_action() { // Makes that undo/redoing actions made outside of the UV editor still affect its polygon. - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->add_do_method(CanvasItemEditor::get_singleton(), "update_viewport"); @@ -467,7 +467,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { mtx.columns[2] = -uv_draw_ofs; mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom)); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Ref<InputEventMouseButton> mb = p_input; if (mb.is_valid()) { diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp index 8dc0ca9431..9defb4de9b 100644 --- a/editor/plugins/polygon_3d_editor_plugin.cpp +++ b/editor/plugins/polygon_3d_editor_plugin.cpp @@ -96,7 +96,7 @@ void Polygon3DEditor::_menu_option(int p_option) { void Polygon3DEditor::_wip_close() { Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node; ERR_FAIL_COND_MSG(!obj, "Edited object is not valid."); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Create Polygon3D")); undo_redo->add_undo_method(obj, "set_polygon", obj->call("get_polygon")); undo_redo->add_do_method(obj, "set_polygon", wip); @@ -186,7 +186,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca if (mb->is_pressed()) { if (mb->is_ctrl_pressed()) { if (poly.size() < 3) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Edit Poly")); undo_redo->add_undo_method(obj, "set_polygon", poly); poly.push_back(cpoint); @@ -265,7 +265,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca ERR_FAIL_INDEX_V(edited_point, poly.size(), EditorPlugin::AFTER_GUI_INPUT_PASS); poly.write[edited_point] = edited_point_pos; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Edit Poly")); undo_redo->add_do_method(obj, "set_polygon", poly); undo_redo->add_undo_method(obj, "set_polygon", pre_move_edit); @@ -294,7 +294,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca } if (closest_idx >= 0) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Edit Poly (Remove Point)")); undo_redo->add_undo_method(obj, "set_polygon", poly); poly.remove_at(closest_idx); diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index 2a5529e229..250f1403af 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -71,7 +71,7 @@ void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths) name = basename + " " + itos(counter); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Resource")); undo_redo->add_do_method(preloader, "add_resource", name, resource); undo_redo->add_undo_method(preloader, "remove_resource", name); @@ -116,7 +116,7 @@ void ResourcePreloaderEditor::_item_edited() { } Ref<Resource> samp = preloader->get_resource(old_name); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Rename Resource")); undo_redo->add_do_method(preloader, "remove_resource", old_name); undo_redo->add_do_method(preloader, "add_resource", new_name, samp); @@ -129,7 +129,7 @@ void ResourcePreloaderEditor::_item_edited() { } void ResourcePreloaderEditor::_remove_resource(const String &p_to_remove) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete Resource")); undo_redo->add_do_method(preloader, "remove_resource", p_to_remove); undo_redo->add_undo_method(preloader, "add_resource", p_to_remove, preloader->get_resource(p_to_remove)); @@ -163,7 +163,7 @@ void ResourcePreloaderEditor::_paste_pressed() { name = basename + " " + itos(counter); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Paste Resource")); undo_redo->add_do_method(preloader, "add_resource", name, r); undo_redo->add_undo_method(preloader, "remove_resource", name); @@ -322,7 +322,7 @@ void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant name = basename + "_" + itos(counter); } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Resource")); undo_redo->add_do_method(preloader, "add_resource", name, r); undo_redo->add_undo_method(preloader, "remove_resource", name); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index caa42b677c..4268abe4a2 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -439,6 +439,8 @@ void ScriptEditor::_goto_script_line(Ref<RefCounted> p_script, int p_line) { } else if (current) { current->goto_line(p_line, true); } + + _save_history(); } } } @@ -2553,9 +2555,9 @@ void ScriptEditor::open_script_create_dialog(const String &p_base_name, const St } void ScriptEditor::open_text_file_create_dialog(const String &p_base_path, const String &p_base_name) { - file_dialog->set_current_file(p_base_name); - file_dialog->set_current_dir(p_base_path); _menu_option(FILE_NEW_TEXTFILE); + file_dialog->set_current_dir(p_base_path); + file_dialog->set_current_file(p_base_name); open_textfile_after_create = false; } diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index a822584619..709ca30858 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -229,7 +229,7 @@ void ShaderEditorPlugin::_close_shader(int p_index) { memdelete(c); edited_shaders.remove_at(p_index); _update_shader_list(); - EditorNode::get_undo_redo()->clear_history(); // To prevent undo on deleted graphs. + EditorUndoRedoManager::get_singleton()->clear_history(); // To prevent undo on deleted graphs. } void ShaderEditorPlugin::_resource_saved(Object *obj) { diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index d90d6b6756..06db696330 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -61,7 +61,7 @@ void Skeleton2DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -77,7 +77,7 @@ void Skeleton2DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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 956150ec69..53486d9509 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -116,7 +116,7 @@ void BoneTransformEditor::_value_changed(const String &p_property, Variant p_val return; } if (skeleton) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS); undo_redo->add_undo_property(skeleton, p_property, skeleton->get(p_property)); undo_redo->add_do_property(skeleton, p_property, p_value); @@ -271,7 +271,7 @@ void Skeleton3DEditor::reset_pose(const bool p_all_bones) { return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS); if (p_all_bones) { for (int i = 0; i < bone_len; i++) { @@ -338,7 +338,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) { return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Set Bone Rest"), UndoRedo::MERGE_ENDS); if (p_all_bones) { for (int i = 0; i < bone_len; i++) { @@ -358,7 +358,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) { } void Skeleton3DEditor::create_physical_skeleton() { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ERR_FAIL_COND(!get_tree()); Node *owner = get_tree()->get_edited_scene_root(); @@ -593,7 +593,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_node = Object::cast_to<Skeleton3D>(node); ERR_FAIL_NULL(skeleton_node); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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_node->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) { @@ -1323,7 +1323,7 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c Skeleton3DEditor *se = Skeleton3DEditor::get_singleton(); Node3DEditor *ne = Node3DEditor::get_singleton(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index 2a8994d239..0d00bfa8fd 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -344,7 +344,7 @@ void Sprite2DEditor::_convert_to_mesh_2d_node() { MeshInstance2D *mesh_instance = memnew(MeshInstance2D); mesh_instance->set_mesh(mesh); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -402,7 +402,7 @@ void Sprite2DEditor::_convert_to_polygon_2d_node() { polygon_2d_instance->set_polygon(polygon); polygon_2d_instance->set_polygons(polys); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -424,7 +424,7 @@ void Sprite2DEditor::_create_collision_polygon_2d_node() { CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D); collision_polygon_2d_instance->set_polygon(outline); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -457,7 +457,7 @@ void Sprite2DEditor::_create_light_occluder_2d_node() { LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D); light_occluder_2d_instance->set_occluder_polygon(polygon); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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 f4ec026504..d5365068c3 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -251,7 +251,7 @@ void SpriteFramesEditor::_sheet_add_frames() { const Size2i offset = _get_offset(); const Size2i separation = _get_separation(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Frame")); int fc = frames->get_frame_count(edited_anim); @@ -470,7 +470,7 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_ return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Frame")); int fc = frames->get_frame_count(edited_anim); @@ -541,7 +541,7 @@ void SpriteFramesEditor::_paste_pressed() { return; ///beh should show an error i guess } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Paste Frame")); undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, duration); undo_redo->add_undo_method(frames, "remove_frame", edited_anim, frames->get_frame_count(edited_anim)); @@ -584,7 +584,7 @@ void SpriteFramesEditor::_empty_pressed() { Ref<Texture2D> texture; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Empty")); undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, from); undo_redo->add_undo_method(frames, "remove_frame", edited_anim, from); @@ -608,7 +608,7 @@ void SpriteFramesEditor::_empty2_pressed() { Ref<Texture2D> texture; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Empty")); undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, from + 1); undo_redo->add_undo_method(frames, "remove_frame", edited_anim, from + 1); @@ -632,7 +632,7 @@ void SpriteFramesEditor::_up_pressed() { sel = to_move; sel -= 1; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Move Frame")); undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move - 1), frames->get_frame_duration(edited_anim, to_move - 1)); undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move - 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move)); @@ -658,7 +658,7 @@ void SpriteFramesEditor::_down_pressed() { sel = to_move; sel += 1; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Move Frame")); undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move + 1), frames->get_frame_duration(edited_anim, to_move + 1)); undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move + 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move)); @@ -681,7 +681,7 @@ void SpriteFramesEditor::_delete_pressed() { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete Resource")); undo_redo->add_do_method(frames, "remove_frame", edited_anim, to_delete); undo_redo->add_undo_method(frames, "add_frame", edited_anim, frames->get_frame_texture(edited_anim, to_delete), frames->get_frame_duration(edited_anim, to_delete), to_delete); @@ -768,7 +768,7 @@ void SpriteFramesEditor::_animation_name_edited() { List<Node *> nodes; _find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames)); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Rename Animation")); undo_redo->add_do_method(frames, "rename_animation", edited_anim, name); undo_redo->add_undo_method(frames, "rename_animation", name, edited_anim); @@ -798,7 +798,7 @@ void SpriteFramesEditor::_animation_add() { List<Node *> nodes; _find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames)); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Animation")); undo_redo->add_do_method(frames, "add_animation", name); undo_redo->add_undo_method(frames, "remove_animation", name); @@ -831,7 +831,7 @@ void SpriteFramesEditor::_animation_remove() { } void SpriteFramesEditor::_animation_remove_confirmed() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Animation")); undo_redo->add_do_method(frames, "remove_animation", edited_anim); undo_redo->add_undo_method(frames, "add_animation", edited_anim); @@ -860,7 +860,7 @@ void SpriteFramesEditor::_animation_loop_changed() { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Animation Loop")); undo_redo->add_do_method(frames, "set_animation_loop", edited_anim, anim_loop->is_pressed()); undo_redo->add_undo_method(frames, "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim)); @@ -874,7 +874,7 @@ void SpriteFramesEditor::_animation_speed_changed(double p_value) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Animation FPS"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(frames, "set_animation_speed", edited_anim, p_value); undo_redo->add_undo_method(frames, "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim)); @@ -926,7 +926,7 @@ void SpriteFramesEditor::_frame_duration_changed(double p_value) { Ref<Texture2D> texture = frames->get_frame_texture(edited_anim, index); float old_duration = frames->get_frame_duration(edited_anim, index); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set Frame Duration")); undo_redo->add_do_method(frames, "set_frame", edited_anim, index, texture, p_value); undo_redo->add_undo_method(frames, "set_frame", edited_anim, index, texture, old_duration); @@ -1206,7 +1206,7 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da reorder = true; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (reorder) { //drop is from reordering frames int from_frame = -1; float duration = 1.0; diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 05d32e1d08..9bad2f2fbf 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -300,7 +300,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { mtx.xform(rect.position + Vector2(0, rect.size.y / 2)) + Vector2(-handle_offset, 0) }; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Ref<InputEventMouseButton> mb = p_input; if (mb.is_valid()) { if (mb->get_button_index() == MouseButton::LEFT) { @@ -349,7 +349,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { for (const Rect2 &E : autoslice_cache) { if (E.has_point(point)) { rect = E; - if (Input::get_singleton()->is_key_pressed(Key::CTRL) && !(Input::get_singleton()->is_key_pressed(Key(Key::SHIFT | Key::ALT)))) { + if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !(Input::get_singleton()->is_key_pressed(Key(Key::SHIFT | Key::ALT)))) { Rect2 r; if (atlas_tex.is_valid()) { r = atlas_tex->get_region(); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 68c1041a0b..40aac77a99 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -800,7 +800,7 @@ void ThemeItemImportTree::_import_selected() { ProgressDialog::get_singleton()->end_task("import_theme_items"); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Import Theme Items")); ur->add_do_method(*edited_theme, "clear"); @@ -1498,7 +1498,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); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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)); @@ -1517,7 +1517,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(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Add Theme Type")); ur->add_do_method(*edited_theme, "add_type", new_type); @@ -1529,7 +1529,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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Create Theme Item")); switch (p_data_type) { @@ -1574,7 +1574,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(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Remove Theme Type")); new_snapshot->remove_type(p_theme_type); @@ -1597,7 +1597,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(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Remove Data Type Items From Theme")); new_snapshot->get_theme_item_list(p_data_type, p_item_type, &names); @@ -1626,7 +1626,7 @@ void ThemeItemEditorDialog::_remove_class_items() { Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Remove Class Items From Theme")); for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { @@ -1662,7 +1662,7 @@ void ThemeItemEditorDialog::_remove_custom_items() { Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Remove Custom Items From Theme")); for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { @@ -1698,7 +1698,7 @@ void ThemeItemEditorDialog::_remove_all_items() { Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Remove All Items From Theme")); for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { @@ -1802,7 +1802,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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -2828,7 +2828,7 @@ void ThemeTypeEditor::_add_default_type_items() { updating = false; - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Override All Default Theme Items")); ur->add_do_method(*edited_theme, "merge_with", new_snapshot); @@ -2848,7 +2848,7 @@ void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) { } String item_name = le->get_text().strip_edges(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Add Theme Item")); switch (p_data_type) { @@ -2893,7 +2893,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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Override Theme Item")); switch (p_data_type) { @@ -2932,7 +2932,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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Remove Theme Item")); switch (p_data_type) { @@ -3006,7 +3006,7 @@ void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Rename Theme Item")); switch (p_data_type) { @@ -3062,7 +3062,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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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)); @@ -3070,7 +3070,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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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)); @@ -3078,7 +3078,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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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)); @@ -3090,7 +3090,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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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>()); @@ -3107,7 +3107,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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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>()); @@ -3124,7 +3124,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) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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>()); @@ -3167,7 +3167,7 @@ void ThemeTypeEditor::_on_pin_leader_button_pressed(Control *p_editor, String p_ stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource(); } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Pin Stylebox")); ur->add_do_method(this, "_pin_leading_stylebox", p_item_name, stylebox); @@ -3200,7 +3200,7 @@ void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_ } void ThemeTypeEditor::_on_unpin_leader_button_pressed() { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -3269,7 +3269,7 @@ void ThemeTypeEditor::_update_stylebox_from_leading() { } void ThemeTypeEditor::_type_variation_changed(const String p_value) { - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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 deb1df42d3..eaf72d36ba 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.cpp +++ b/editor/plugins/tiles/atlas_merging_dialog.cpp @@ -31,7 +31,6 @@ #include "atlas_merging_dialog.h" #include "editor/editor_file_dialog.h" -#include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_undo_redo_manager.h" @@ -56,7 +55,7 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla new_texture_region_size = new_texture_region_size.max(atlas_source->get_texture_region_size()); } - // Generate the merged TileSetAtlasSource. + // Generate the new texture. Vector2i atlas_offset; int line_height = 0; for (int source_index = 0; source_index < p_atlas_sources.size(); source_index++) { @@ -72,28 +71,6 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla Rect2i new_tile_rect_in_altas = Rect2i(atlas_offset + tile_id, atlas_source->get_tile_size_in_atlas(tile_id)); - // Create tiles and alternatives, then copy their properties. - for (int alternative_index = 0; alternative_index < atlas_source->get_alternative_tiles_count(tile_id); alternative_index++) { - int alternative_id = atlas_source->get_alternative_tile_id(tile_id, alternative_index); - if (alternative_id == 0) { - merged->create_tile(new_tile_rect_in_altas.position, new_tile_rect_in_altas.size); - } else { - merged->create_alternative_tile(new_tile_rect_in_altas.position, alternative_index); - } - - // Copy the properties. - TileData *original_tile_data = atlas_source->get_tile_data(tile_id, alternative_id); - List<PropertyInfo> properties; - original_tile_data->get_property_list(&properties); - for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - const StringName &property_name = E->get().name; - merged->set(property_name, original_tile_data->get(property_name)); - } - - // Add to the mapping. - merged_mapping[source_index][tile_id] = new_tile_rect_in_altas.position; - } - // Copy the texture. for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(tile_id); frame++) { Rect2i src_rect = atlas_source->get_tile_texture_region(tile_id, frame); @@ -103,6 +80,9 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla } output_image->blit_rect(atlas_source->get_texture()->get_image(), src_rect, dst_rect_wide.get_center() - src_rect.size / 2); } + + // Add to the mapping. + merged_mapping[source_index][tile_id] = new_tile_rect_in_altas.position; } // Compute the atlas offset. @@ -115,8 +95,43 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla } } - merged->set_name(p_atlas_sources[0]->get_name()); merged->set_texture(ImageTexture::create_from_image(output_image)); + + // Copy the tiles to the merged TileSetAtlasSource. + for (int source_index = 0; source_index < p_atlas_sources.size(); source_index++) { + Ref<TileSetAtlasSource> atlas_source = p_atlas_sources[source_index]; + for (KeyValue<Vector2i, Vector2i> tile_mapping : merged_mapping[source_index]) { + // Create tiles and alternatives, then copy their properties. + for (int alternative_index = 0; alternative_index < atlas_source->get_alternative_tiles_count(tile_mapping.key); alternative_index++) { + int alternative_id = atlas_source->get_alternative_tile_id(tile_mapping.key, alternative_index); + if (alternative_id == 0) { + merged->create_tile(tile_mapping.value, atlas_source->get_tile_size_in_atlas(tile_mapping.key)); + } else { + merged->create_alternative_tile(tile_mapping.value, alternative_index); + } + + // Copy the properties. + TileData *src_tile_data = atlas_source->get_tile_data(tile_mapping.key, alternative_id); + List<PropertyInfo> properties; + src_tile_data->get_property_list(&properties); + + TileData *dst_tile_data = merged->get_tile_data(tile_mapping.value, alternative_id); + for (PropertyInfo property : properties) { + if (!(property.usage & PROPERTY_USAGE_STORAGE)) { + continue; + } + Variant value = src_tile_data->get(property.name); + Variant default_value = ClassDB::class_get_default_property_value("TileData", property.name); + if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) { + continue; + } + dst_tile_data->set(property.name, value); + } + } + } + } + + merged->set_name(p_atlas_sources[0]->get_name()); merged->set_texture_region_size(new_texture_region_size); } } @@ -151,10 +166,12 @@ void AtlasMergingDialog::_merge_confirmed(String p_path) { Ref<ImageTexture> output_image_texture = merged->get_texture(); output_image_texture->get_image()->save_png(p_path); + ResourceLoader::import(p_path); + Ref<Texture2D> new_texture_resource = ResourceLoader::load(p_path, "Texture2D"); merged->set_texture(new_texture_resource); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Merge TileSetAtlasSource")); int next_id = tile_set->get_next_source_id(); undo_redo->add_do_method(*tile_set, "add_source", merged, next_id); @@ -194,7 +211,7 @@ void AtlasMergingDialog::ok_pressed() { } void AtlasMergingDialog::cancel_pressed() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (int i = 0; i < commited_actions_count; i++) { undo_redo->undo(); } @@ -225,6 +242,14 @@ bool AtlasMergingDialog::_get(const StringName &p_name, Variant &r_ret) const { return false; } +void AtlasMergingDialog::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_VISIBILITY_CHANGED: { + _update_texture(); + } break; + } +} + void AtlasMergingDialog::update_tile_set(Ref<TileSet> p_tile_set) { ERR_FAIL_COND(!p_tile_set.is_valid()); tile_set = p_tile_set; diff --git a/editor/plugins/tiles/atlas_merging_dialog.h b/editor/plugins/tiles/atlas_merging_dialog.h index 032541c90e..bf1b56894f 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.h +++ b/editor/plugins/tiles/atlas_merging_dialog.h @@ -75,6 +75,8 @@ protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; + void _notification(int p_what); + public: void update_tile_set(Ref<TileSet> p_tile_set); diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index fb4787f13c..966d394ca1 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -265,12 +265,12 @@ void GenericTilePolygonEditor::_zoom_changed() { } void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { - Ref<EditorUndoRedoManager> undo_redo; + EditorUndoRedoManager *undo_redo; if (use_undo_redo) { - undo_redo = EditorNode::get_undo_redo(); + undo_redo = EditorUndoRedoManager::get_singleton(); } else { // This nice hack allows for discarding undo actions without making code too complex. - undo_redo.instantiate(); + undo_redo = memnew(EditorUndoRedoManager); } switch (p_item_pressed) { @@ -361,6 +361,10 @@ 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) { @@ -445,12 +449,12 @@ void GenericTilePolygonEditor::_snap_to_half_pixel(Point2 &r_point) { } void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) { - Ref<EditorUndoRedoManager> undo_redo; + EditorUndoRedoManager *undo_redo; if (use_undo_redo) { - undo_redo = EditorNode::get_undo_redo(); + undo_redo = EditorUndoRedoManager::get_singleton(); } else { // This nice hack allows for discarding undo actions without making code too complex. - undo_redo.instantiate(); + undo_redo = memnew(EditorUndoRedoManager); } real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius"); @@ -643,6 +647,10 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) } base_control->queue_redraw(); + + if (!use_undo_redo) { + memdelete(undo_redo); + } } void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) { @@ -902,7 +910,7 @@ Variant TileDataDefaultEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_s } void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) { Vector2i coords = E.key.get_atlas_coords(); undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/%s", coords.x, coords.y, E.key.alternative_tile, property), E.value); @@ -971,7 +979,7 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti } } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { if (mb->get_button_index() == MouseButton::LEFT) { @@ -1095,7 +1103,7 @@ void TileDataDefaultEditor::forward_painting_alternatives_gui_input(TileAtlasVie drag_last_pos = mb->get_position(); } } else { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Painting Tiles Property")); _setup_undo_redo_action(p_tile_set_atlas_source, drag_modified, drag_painted_value); undo_redo->commit_action(false); @@ -1345,7 +1353,7 @@ Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_ } void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) { Vector2i coords = E.key.get_atlas_coords(); undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/occlusion_layer_%d/polygon", coords.x, coords.y, E.key.alternative_tile, occlusion_layer), E.value); @@ -1525,7 +1533,7 @@ Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) { Array new_array = p_new_value; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (KeyValue<TileMapCell, Variant> &E : p_previous_values) { Array old_array = E.value; @@ -2227,7 +2235,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t } } } else { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET_RECT) { Rect2i rect; rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); @@ -2600,7 +2608,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi } } } else { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) { undo_redo->create_action(TTR("Painting Tiles Property")); for (KeyValue<TileMapCell, Variant> &E : drag_modified) { @@ -2747,7 +2755,7 @@ Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atla } void TileDataNavigationEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) { Vector2i coords = E.key.get_atlas_coords(); undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/navigation_layer_%d/polygon", coords.x, coords.y, E.key.alternative_tile, navigation_layer), E.value); diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index dd4daa45b7..81dd8bc8a6 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -273,7 +273,7 @@ void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEven if (ED_IS_SHORTCUT("tiles_editor/paste", p_event) && p_event->is_pressed() && !p_event->is_echo()) { select_last_pattern = true; int new_pattern_index = tile_set->get_patterns_count(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add TileSet pattern")); undo_redo->add_do_method(*tile_set, "add_pattern", tile_map_clipboard, new_pattern_index); undo_redo->add_undo_method(*tile_set, "remove_pattern", new_pattern_index); @@ -283,7 +283,7 @@ void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEven if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) { Vector<int> selected = patterns_item_list->get_selected_items(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove TileSet patterns")); for (int i = 0; i < selected.size(); i++) { int pattern_index = selected[i]; @@ -515,7 +515,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p if (ED_IS_SHORTCUT("tiles_editor/cut", p_event)) { // Delete selected tiles. if (!tile_map_selection.is_empty()) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete tiles")); for (const Vector2i &E : tile_map_selection) { undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); @@ -547,7 +547,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p if (ED_IS_SHORTCUT("tiles_editor/delete", p_event)) { // Delete selected tiles. if (!tile_map_selection.is_empty()) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete tiles")); for (const Vector2i &E : tile_map_selection) { undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); @@ -646,12 +646,12 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p } } else { // Check if we are picking a tile. - if (picker_button->is_pressed() || (Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) { + if (picker_button->is_pressed() || (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) { drag_type = DRAG_TYPE_PICK; drag_start_mouse_pos = mpos; } else { // Paint otherwise. - if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) { + if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) { drag_type = DRAG_TYPE_PAINT; drag_start_mouse_pos = mpos; drag_modified.clear(); @@ -667,11 +667,11 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } _fix_invalid_tiles_in_tile_map_selection(); - } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL))) { + } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) { drag_type = DRAG_TYPE_LINE; drag_start_mouse_pos = mpos; drag_modified.clear(); - } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CTRL))) { + } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) { drag_type = DRAG_TYPE_RECT; drag_start_mouse_pos = mpos; drag_modified.clear(); @@ -742,7 +742,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over // Draw the selection. if ((tiles_bottom_panel->is_visible_in_tree() || patterns_bottom_panel->is_visible_in_tree()) && tool_buttons_group->get_pressed_button() == select_tool_button) { // In select mode, we only draw the current selection if we are modifying it (pressing control or shift). - if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) { + if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) { // Do nothing } else { Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color"); @@ -812,7 +812,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over Vector2i coords = tile_map->map_pattern(tile_map->local_to_map(drag_last_mouse_pos - mouse_offset), clipboard_used_cells[i], tile_map_clipboard); preview[coords] = TileMapCell(tile_map_clipboard->get_cell_source_id(clipboard_used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(clipboard_used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(clipboard_used_cells[i])); } - } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) { + } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) { bool expand_grid = false; if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) { // Preview for a single pattern. @@ -1240,20 +1240,20 @@ void TileMapEditorTilesPlugin::_stop_dragging() { Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform(); Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position()); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (drag_type) { case DRAG_TYPE_SELECT: { undo_redo->create_action(TTR("Change selection")); undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection()); - if (!Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL)) { + if (!Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) { tile_map_selection.clear(); } Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos) - tile_map->local_to_map(drag_start_mouse_pos)).abs(); for (int x = rect.position.x; x <= rect.get_end().x; x++) { for (int y = rect.position.y; y <= rect.get_end().y; y++) { Vector2i coords = Vector2i(x, y); - if (Input::get_singleton()->is_key_pressed(Key::CTRL)) { + if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) { if (tile_map_selection.has(coords)) { tile_map_selection.erase(coords); } @@ -2641,7 +2641,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() { Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform(); Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position()); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (drag_type) { case DRAG_TYPE_PICK: { Vector2i coords = tile_map->local_to_map(mpos); @@ -2875,7 +2875,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> drag_type = DRAG_TYPE_PICK; } else { // Paint otherwise. - if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) { + if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) { if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) { return true; } @@ -2890,14 +2890,14 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key); tile_map->set_cell(tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } - } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL))) { + } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) { if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) { return true; } drag_type = DRAG_TYPE_LINE; drag_start_mouse_pos = mpos; drag_modified.clear(); - } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CTRL))) { + } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) { if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) { return true; } @@ -2982,7 +2982,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o tile_xform.set_scale(tile_shape_size); tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false); } - } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) { + } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) { bool expand_grid = false; if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) { // Preview for a single tile. @@ -3303,12 +3303,16 @@ void TileMapEditorTerrainsPlugin::_update_theme() { void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) { _stop_dragging(); // Avoids staying in a wrong drag state. - tile_map_id = p_tile_map_id; - tile_map_layer = p_tile_map_layer; + if (tile_map_id != p_tile_map_id) { + tile_map_id = p_tile_map_id; - _update_terrains_cache(); - _update_terrains_tree(); - _update_tiles_list(); + // Clear the selection. + _update_terrains_cache(); + _update_terrains_tree(); + _update_tiles_list(); + } + + tile_map_layer = p_tile_map_layer; } TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() { @@ -3485,7 +3489,7 @@ void TileMapEditor::_advanced_menu_button_id_pressed(int p_id) { } if (p_id == 0) { // Replace Tile Proxies - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Replace Tiles with Proxies")); for (int layer_index = 0; layer_index < tile_map->get_layers_count(); layer_index++) { TypedArray<Vector2i> used_cells = tile_map->get_used_cells(layer_index); @@ -3702,8 +3706,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) { - Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); - ERR_FAIL_COND(undo_redo_man.is_null()); + EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_NULL(undo_redo_man); TileMap *tile_map = Object::cast_to<TileMap>(p_edited); if (!tile_map) { diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp index ef82e748a8..f6aeffa13f 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp @@ -30,10 +30,11 @@ #include "tile_proxies_manager_dialog.h" -#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/dialogs.h" +#include "scene/gui/popup_menu.h" #include "scene/gui/separator.h" void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index, Object *p_item_list) { @@ -55,7 +56,7 @@ void TileProxiesManagerDialog::_menu_id_pressed(int p_id) { } void TileProxiesManagerDialog::_delete_selected_bindings() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Tile Proxies")); Vector<int> source_level_selected = source_level_list->get_selected_items(); @@ -155,7 +156,7 @@ void TileProxiesManagerDialog::_property_changed(const String &p_path, const Var } void TileProxiesManagerDialog::_add_button_pressed() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (from.source_id != TileSet::INVALID_SOURCE && to.source_id != TileSet::INVALID_SOURCE) { Vector2i from_coords = from.get_atlas_coords(); Vector2i to_coords = to.get_atlas_coords(); @@ -196,7 +197,7 @@ void TileProxiesManagerDialog::_add_button_pressed() { } void TileProxiesManagerDialog::_clear_invalid_button_pressed() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete All Invalid Tile Proxies")); undo_redo->add_do_method(*tile_set, "cleanup_invalid_tile_proxies"); @@ -224,7 +225,7 @@ void TileProxiesManagerDialog::_clear_invalid_button_pressed() { } void TileProxiesManagerDialog::_clear_all_button_pressed() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete All Tile Proxies")); undo_redo->add_do_method(*tile_set, "clear_tile_proxies"); @@ -305,7 +306,7 @@ void TileProxiesManagerDialog::_unhandled_key_input(Ref<InputEvent> p_event) { } void TileProxiesManagerDialog::cancel_pressed() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (int i = 0; i < commited_actions_count; i++) { undo_redo->undo(); } diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 146a53f3dd..43eaafc02c 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -1021,38 +1021,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size(); - if (drag_type == DRAG_TYPE_NONE) { - if (selection.size() == 1) { - // Change the cursor depending on the hovered thing. - TileSelection selected = selection.front()->get(); - if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) { - Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position(); - Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile); - Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile); - Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom(); - Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0); - const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) }; - const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) }; - CursorShape cursor_shape = CURSOR_ARROW; - bool can_grow[4]; - for (int i = 0; i < 4; i++) { - can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile); - can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1; - } - for (int i = 0; i < 4; i++) { - Vector2 pos = rect.position + rect.size * coords[i]; - if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) { - cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE; - } - Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4]; - if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) { - cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE; - } - } - tile_atlas_control->set_default_cursor_shape(cursor_shape); - } - } - } else if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) { + if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) { // Create big tile. new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); @@ -1243,7 +1212,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0); const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) }; const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) }; - CursorShape cursor_shape = CURSOR_ARROW; bool can_grow[4]; for (int i = 0; i < 4; i++) { can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile); @@ -1257,7 +1225,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven drag_last_mouse_pos = drag_start_mouse_pos; drag_current_tile = selected.tile; drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile)); - cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE; } Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4]; if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) { @@ -1266,10 +1233,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven drag_last_mouse_pos = drag_start_mouse_pos; drag_current_tile = selected.tile; drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile)); - cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE; } } - tile_atlas_control->set_default_cursor_shape(cursor_shape); } } @@ -1292,7 +1257,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven drag_last_mouse_pos = drag_start_mouse_pos; drag_current_tile = selected.tile; drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile)); - tile_atlas_control->set_default_cursor_shape(CURSOR_MOVE); } else { // Start selection dragging. drag_type = DRAG_TYPE_RECT_SELECT; @@ -1332,7 +1296,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven } void TileSetAtlasSourceEditor::_end_dragging() { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (drag_type) { case DRAG_TYPE_CREATE_TILES: undo_redo->create_action(TTR("Create tiles")); @@ -1543,7 +1507,67 @@ void TileSetAtlasSourceEditor::_end_dragging() { drag_modified_tiles.clear(); drag_type = DRAG_TYPE_NONE; - tile_atlas_control->set_default_cursor_shape(CURSOR_ARROW); + // Change mouse accordingly. +} + +Control::CursorShape TileSetAtlasSourceEditor::get_cursor_shape(const Point2 &p_pos) const { + Control::CursorShape cursor_shape = get_default_cursor_shape(); + if (drag_type == DRAG_TYPE_NONE) { + if (selection.size() == 1) { + // Change the cursor depending on the hovered thing. + TileSelection selected = selection.front()->get(); + if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) { + Transform2D xform = tile_atlas_control->get_global_transform().affine_inverse() * get_global_transform(); + Vector2 mouse_local_pos = xform.xform(p_pos); + Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile); + Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile); + Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom(); + Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0); + const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) }; + const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) }; + bool can_grow[4]; + for (int i = 0; i < 4; i++) { + can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile); + can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1; + } + for (int i = 0; i < 4; i++) { + Vector2 pos = rect.position + rect.size * coords[i]; + if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) { + cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE; + } + Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4]; + if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) { + cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE; + } + } + } + } + } else { + switch (drag_type) { + case DRAG_TYPE_RESIZE_TOP_LEFT: + case DRAG_TYPE_RESIZE_BOTTOM_RIGHT: + cursor_shape = CURSOR_FDIAGSIZE; + break; + case DRAG_TYPE_RESIZE_TOP: + case DRAG_TYPE_RESIZE_BOTTOM: + cursor_shape = CURSOR_VSIZE; + break; + case DRAG_TYPE_RESIZE_TOP_RIGHT: + case DRAG_TYPE_RESIZE_BOTTOM_LEFT: + cursor_shape = CURSOR_BDIAGSIZE; + break; + case DRAG_TYPE_RESIZE_LEFT: + case DRAG_TYPE_RESIZE_RIGHT: + cursor_shape = CURSOR_HSIZE; + break; + case DRAG_TYPE_MOVE_TILE: + cursor_shape = CURSOR_MOVE; + break; + default: + break; + } + } + return cursor_shape; } HashMap<Vector2i, List<const PropertyInfo *>> TileSetAtlasSourceEditor::_group_properties_per_tiles(const List<PropertyInfo> &r_list, const TileSetAtlasSource *p_atlas) { @@ -1563,7 +1587,7 @@ HashMap<Vector2i, List<const PropertyInfo *>> TileSetAtlasSourceEditor::_group_p } void TileSetAtlasSourceEditor::_menu_option(int p_option) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); switch (p_option) { case TILE_DELETE: { @@ -2079,8 +2103,8 @@ 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) { - Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); - ERR_FAIL_COND(!undo_redo_man.is_valid()); + EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_NULL(undo_redo_man); #define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property)); @@ -2210,7 +2234,7 @@ void TileSetAtlasSourceEditor::_auto_create_tiles() { Vector2i separation = tile_set_atlas_source->get_separation(); Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size(); Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Create tiles in non-transparent texture regions")); for (int y = 0; y < grid_size.y; y++) { for (int x = 0; x < grid_size.x; x++) { @@ -2256,7 +2280,7 @@ void TileSetAtlasSourceEditor::_auto_remove_tiles() { Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size(); Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove tiles in fully transparent texture regions")); List<PropertyInfo> list; diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h index 85f780ea26..bcab1296ad 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.h +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h @@ -277,6 +277,8 @@ public: void edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_source, int p_source_id); void init_source(); + virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override; + TileSetAtlasSourceEditor(); ~TileSetAtlasSourceEditor(); }; diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index b44cb18dc7..4f6522f130 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -67,7 +67,7 @@ void TileSetEditor::_drop_data_fw(const Point2 &p_point, const Variant &p_data, // Actually create the new source. Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource); atlas_source->set_texture(resource); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add a new atlas source")); undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id); undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size()); @@ -260,7 +260,7 @@ void TileSetEditor::_source_delete_pressed() { Ref<TileSetSource> source = tile_set->get_source(to_delete); // Remove the source. - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove source")); undo_redo->add_do_method(*tile_set, "remove_source", to_delete); undo_redo->add_undo_method(*tile_set, "add_source", source, to_delete); @@ -279,7 +279,7 @@ void TileSetEditor::_source_add_id_pressed(int p_id_pressed) { Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource); // Add a new source. - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add atlas source")); undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id); undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size()); @@ -294,7 +294,7 @@ void TileSetEditor::_source_add_id_pressed(int p_id_pressed) { Ref<TileSetScenesCollectionSource> scene_collection_source = memnew(TileSetScenesCollectionSource); // Add a new source. - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add atlas source")); undo_redo->add_do_method(*tile_set, "add_source", scene_collection_source, source_id); undo_redo->add_undo_method(*tile_set, "remove_source", source_id); @@ -369,7 +369,7 @@ void TileSetEditor::_patterns_item_list_gui_input(const Ref<InputEvent> &p_event if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) { Vector<int> selected = patterns_item_list->get_selected_items(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove TileSet patterns")); for (int i = 0; i < selected.size(); i++) { int pattern_index = selected[i]; @@ -416,8 +416,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) { - Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); - ERR_FAIL_COND(undo_redo_man.is_null()); + EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_NULL(undo_redo_man); TileSet *ed_tile_set = Object::cast_to<TileSet>(p_edited); if (!ed_tile_set) { @@ -597,8 +597,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) { - Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); - ERR_FAIL_COND(undo_redo_man.is_null()); + EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_NULL(undo_redo_man); #define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property)); TileSet *ed_tile_set = Object::cast_to<TileSet>(p_edited); diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp index 0ff8788626..8d48302f1a 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp @@ -237,7 +237,7 @@ void TileSetScenesCollectionSourceEditor::_scenes_list_item_activated(int p_inde void TileSetScenesCollectionSourceEditor::_source_add_pressed() { int scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add a Scene Tile")); undo_redo->add_do_method(tile_set_scenes_collection_source, "create_scene_tile", Ref<PackedScene>(), scene_id); undo_redo->add_undo_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id); @@ -252,7 +252,7 @@ void TileSetScenesCollectionSourceEditor::_source_delete_pressed() { ERR_FAIL_COND(selected_indices.size() <= 0); int scene_id = scene_tiles_list->get_item_metadata(selected_indices[0]); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove a Scene Tile")); undo_redo->add_do_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id); undo_redo->add_undo_method(tile_set_scenes_collection_source, "create_scene_tile", tile_set_scenes_collection_source->get_scene_tile_scene(scene_id), scene_id); @@ -404,7 +404,7 @@ void TileSetScenesCollectionSourceEditor::_drop_data_fw(const Point2 &p_point, c Ref<PackedScene> resource = ResourceLoader::load(files[i]); if (resource.is_valid()) { int scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add a Scene Tile")); undo_redo->add_do_method(tile_set_scenes_collection_source, "create_scene_tile", resource, scene_id); undo_redo->add_undo_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id); diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index b40e588e07..19ee0ae98d 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -185,26 +185,34 @@ void TilesEditorPlugin::_notification(int p_what) { } void TilesEditorPlugin::make_visible(bool p_visible) { - is_visible = p_visible; - - if (is_visible) { + if (p_visible || is_tile_map_selected()) { // Disable and hide invalid editors. TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); tileset_editor_button->set_visible(tile_set.is_valid()); tilemap_editor_button->set_visible(tile_map); - if (tile_map && !is_editing_tile_set) { + if (tile_map && (!is_editing_tile_set || !p_visible)) { EditorNode::get_singleton()->make_bottom_panel_item_visible(tilemap_editor); } else { EditorNode::get_singleton()->make_bottom_panel_item_visible(tileset_editor); } - + is_visible = true; } else { tileset_editor_button->hide(); tilemap_editor_button->hide(); EditorNode::get_singleton()->hide_bottom_panel(); + is_visible = false; } } +bool TilesEditorPlugin::is_tile_map_selected() { + TypedArray<Node> selection = get_editor_interface()->get_selection()->get_selected_nodes(); + if (selection.size() == 1 && Object::cast_to<TileMap>(selection[0])) { + return true; + } + + return false; +} + void TilesEditorPlugin::queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileMapPattern> p_pattern, Callable p_callback) { ERR_FAIL_COND(!p_tile_set.is_valid()); ERR_FAIL_COND(!p_pattern.is_valid()); @@ -362,19 +370,24 @@ void TilesEditorPlugin::edit(Object *p_object) { } else if (p_object->is_class("TileSet")) { tile_set = Ref<TileSet>(p_object); if (tile_map) { - if (tile_map->get_tileset() != tile_set || !tile_map->is_inside_tree()) { + if (tile_map->get_tileset() != tile_set || !tile_map->is_inside_tree() || !is_tile_map_selected()) { tile_map = nullptr; tile_map_id = ObjectID(); } } is_editing_tile_set = true; - EditorNode::get_singleton()->make_bottom_panel_item_visible(tileset_editor); } } // Update the editors. _update_editors(); + // If the tileset is being edited, the visibility function must be called + // here after _update_editors has been called. + if (is_editing_tile_set) { + EditorNode::get_singleton()->make_bottom_panel_item_visible(tileset_editor); + } + // Add change listener. if (tile_map) { tile_map->connect("changed", callable_mp(this, &TilesEditorPlugin::_tile_map_changed)); diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h index 5b91584aa3..50073e59c6 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.h +++ b/editor/plugins/tiles/tiles_editor_plugin.h @@ -110,6 +110,8 @@ public: virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return tilemap_editor->forward_canvas_gui_input(p_event); } virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { tilemap_editor->forward_canvas_draw_over_viewport(p_overlay); } + bool is_tile_map_selected(); + // Pattern preview API. void queue_pattern_preview(Ref<TileSet> p_tile_set, Ref<TileMapPattern> p_pattern, Callable p_callback); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 56dbdb49eb..2c93d46e38 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -129,30 +129,32 @@ void VisualShaderGraphPlugin::set_connections(const List<VisualShader::Connectio void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id) { if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].output_ports.has(p_port_id)) { - for (const KeyValue<int, Port> &E : links[p_node_id].output_ports) { + Link &link = links[p_node_id]; + + for (const KeyValue<int, Port> &E : link.output_ports) { if (E.value.preview_button != nullptr) { E.value.preview_button->set_pressed(false); } } + bool is_dirty = link.preview_pos < 0; - if (links[p_node_id].preview_visible && !is_dirty() && links[p_node_id].preview_box != nullptr) { - links[p_node_id].graph_node->remove_child(links[p_node_id].preview_box); - memdelete(links[p_node_id].preview_box); - links[p_node_id].graph_node->reset_size(); - links[p_node_id].preview_visible = false; + if (!is_dirty && link.preview_visible && link.preview_box != nullptr) { + link.graph_node->remove_child(link.preview_box); + memdelete(link.preview_box); + link.preview_box = nullptr; + link.graph_node->reset_size(); + link.preview_visible = false; } - if (p_port_id != -1 && links[p_node_id].output_ports[p_port_id].preview_button != nullptr) { - if (is_dirty()) { - links[p_node_id].preview_pos = links[p_node_id].graph_node->get_child_count(); + if (p_port_id != -1 && link.output_ports[p_port_id].preview_button != nullptr) { + if (is_dirty) { + link.preview_pos = link.graph_node->get_child_count(); } VBoxContainer *vbox = memnew(VBoxContainer); - links[p_node_id].graph_node->add_child(vbox); - if (links[p_node_id].preview_pos != -1) { - links[p_node_id].graph_node->move_child(vbox, links[p_node_id].preview_pos); - } - links[p_node_id].graph_node->set_slot_draw_stylebox(vbox->get_index(), false); + link.graph_node->add_child(vbox); + link.graph_node->move_child(vbox, link.preview_pos); + link.graph_node->set_slot_draw_stylebox(vbox->get_index(), false); Control *offset = memnew(Control); offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE)); @@ -162,9 +164,9 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p port_preview->setup(visual_shader, visual_shader->get_shader_type(), p_node_id, p_port_id); port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER); vbox->add_child(port_preview); - links[p_node_id].preview_visible = true; - links[p_node_id].preview_box = vbox; - links[p_node_id].output_ports[p_port_id].preview_button->set_pressed(true); + link.preview_visible = true; + link.preview_box = vbox; + link.output_ports[p_port_id].preview_button->set_pressed(true); } } } @@ -329,14 +331,6 @@ void VisualShaderGraphPlugin::clear_links() { links.clear(); } -bool VisualShaderGraphPlugin::is_dirty() const { - return dirty; -} - -void VisualShaderGraphPlugin::make_dirty(bool p_enabled) { - dirty = p_enabled; -} - void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node) { links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, HashMap<int, InputPort>(), HashMap<int, Port>(), nullptr, nullptr, nullptr, { nullptr, nullptr, nullptr } }); } @@ -426,7 +420,13 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool editor->_update_created_node(node); if (p_just_update) { - links[p_id].graph_node = node; + Link &link = links[p_id]; + + link.graph_node = node; + link.preview_box = nullptr; + link.preview_pos = -1; + link.output_ports.clear(); + link.input_ports.clear(); } else { register_link(p_type, p_id, vsnode.ptr(), node); } @@ -1861,7 +1861,7 @@ void VisualShaderEditor::_update_parameters(bool p_update_refs) { } void VisualShaderEditor::_update_parameter_refs(HashSet<String> &p_deleted_names) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (int i = 0; i < VisualShader::TYPE_MAX; i++) { VisualShader::Type type = VisualShader::Type(i); @@ -1916,15 +1916,12 @@ void VisualShaderEditor::_update_graph() { _update_varyings(); graph_plugin->clear_links(); - graph_plugin->make_dirty(true); graph_plugin->update_theme(); for (int n_i = 0; n_i < nodes.size(); n_i++) { graph_plugin->add_node(type, nodes[n_i], false); } - graph_plugin->make_dirty(false); - for (const VisualShader::Connection &E : node_connections) { int from = E.from_node; int from_idx = E.from_port; @@ -1961,7 +1958,7 @@ void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Input Port")); undo_redo->add_do_method(node.ptr(), "add_input_port", p_port, p_port_type, p_name); undo_redo->add_undo_method(node.ptr(), "remove_input_port", p_port); @@ -1977,7 +1974,7 @@ void VisualShaderEditor::_add_output_port(int p_node, int p_port, int p_port_typ return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Output Port")); undo_redo->add_do_method(node.ptr(), "add_output_port", p_port, p_port_type, p_name); undo_redo->add_undo_method(node.ptr(), "remove_output_port", p_port); @@ -1993,7 +1990,7 @@ void VisualShaderEditor::_change_input_port_type(int p_type, int p_node, int p_p return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Input Port Type")); undo_redo->add_do_method(node.ptr(), "set_input_port_type", p_port, p_type); undo_redo->add_undo_method(node.ptr(), "set_input_port_type", p_port, node->get_input_port_type(p_port)); @@ -2009,7 +2006,7 @@ void VisualShaderEditor::_change_output_port_type(int p_type, int p_node, int p_ return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Output Port Type")); undo_redo->add_do_method(node.ptr(), "set_output_port_type", p_port, p_type); undo_redo->add_undo_method(node.ptr(), "set_output_port_type", p_port, node->get_output_port_type(p_port)); @@ -2038,7 +2035,7 @@ void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *p return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Input Port Name")); undo_redo->add_do_method(node.ptr(), "set_input_port_name", p_port_id, validated_name); undo_redo->add_undo_method(node.ptr(), "set_input_port_name", p_port_id, node->get_input_port_name(p_port_id)); @@ -2065,7 +2062,7 @@ void VisualShaderEditor::_change_output_port_name(const String &p_text, Object * return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Change Output Port Name")); undo_redo->add_do_method(node.ptr(), "set_output_port_name", p_port_id, validated_name); undo_redo->add_undo_method(node.ptr(), "set_output_port_name", p_port_id, prev_name); @@ -2078,7 +2075,7 @@ void VisualShaderEditor::_expand_output_port(int p_node, int p_port, bool p_expa Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node); ERR_FAIL_COND(!node.is_valid()); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (p_expand) { undo_redo->create_action(TTR("Expand Output Port")); } else { @@ -2176,7 +2173,7 @@ void VisualShaderEditor::_remove_input_port(int p_node, int p_port) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Input Port")); List<VisualShader::Connection> conns; @@ -2226,7 +2223,7 @@ void VisualShaderEditor::_remove_output_port(int p_node, int p_port) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Remove Output Port")); List<VisualShader::Connection> conns; @@ -2293,7 +2290,7 @@ void VisualShaderEditor::_expression_focus_out(Object *code_edit, int p_node) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set VisualShader Expression")); undo_redo->add_do_method(node.ptr(), "set_expression", expression_box->get_text()); undo_redo->add_undo_method(node.ptr(), "set_expression", node->get_expression()); @@ -2357,7 +2354,7 @@ void VisualShaderEditor::_node_resized(const Vector2 &p_new_size, int p_type, in return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Resize VisualShader Node"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(this, "_set_node_size", p_type, p_node, p_new_size); undo_redo->add_undo_method(this, "_set_node_size", p_type, p_node, node->get_size()); @@ -2374,7 +2371,7 @@ void VisualShaderEditor::_preview_select_port(int p_node, int p_port) { if (node->get_output_port_for_preview() == p_port) { p_port = -1; //toggle it } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(p_port == -1 ? TTR("Hide Port Preview") : TTR("Show Port Preview")); undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", p_port); undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", prev_port); @@ -2420,7 +2417,7 @@ void VisualShaderEditor::_comment_title_popup_hide() { if (node->get_title() == comment_title_change_edit->get_text()) { return; // nothing changed - ignored } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set Comment Node Title")); undo_redo->add_do_method(node.ptr(), "set_title", comment_title_change_edit->get_text()); undo_redo->add_undo_method(node.ptr(), "set_title", node->get_title()); @@ -2463,7 +2460,7 @@ void VisualShaderEditor::_comment_desc_popup_hide() { if (node->get_description() == comment_desc_change_edit->get_text()) { return; // nothing changed - ignored } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set Comment Node Description")); undo_redo->add_do_method(node.ptr(), "set_description", comment_desc_change_edit->get_text()); undo_redo->add_undo_method(node.ptr(), "set_description", node->get_title()); @@ -2484,7 +2481,7 @@ void VisualShaderEditor::_parameter_line_edit_changed(const String &p_text, int return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set Parameter Name")); undo_redo->add_do_method(node.ptr(), "set_parameter_name", validated_name); undo_redo->add_undo_method(node.ptr(), "set_parameter_name", node->get_parameter_name()); @@ -2520,7 +2517,7 @@ void VisualShaderEditor::_port_edited(const StringName &p_property, const Varian Ref<VisualShaderNode> vsn = visual_shader->get_node(type, editing_node); ERR_FAIL_COND(!vsn.is_valid()); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set Input Default Port")); Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(vsn.ptr()); @@ -2966,7 +2963,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri int id_to_use = visual_shader->get_valid_node_id(type); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (p_resource_path.is_empty()) { undo_redo->create_action(TTR("Add Node to Visual Shader")); } else { @@ -3133,7 +3130,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri } void VisualShaderEditor::_add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Add Varying to Visual Shader: %s"), p_name)); undo_redo->add_do_method(visual_shader.ptr(), "add_varying", p_name, p_mode, p_type); @@ -3168,7 +3165,7 @@ void VisualShaderEditor::_add_varying(const String &p_name, VisualShader::Varyin } void VisualShaderEditor::_remove_varying(const String &p_name) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Remove Varying from Visual Shader: %s"), p_name)); VisualShader::VaryingMode var_mode = visual_shader->get_varying_mode(p_name); @@ -3256,7 +3253,7 @@ void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_t void VisualShaderEditor::_nodes_dragged() { drag_dirty = false; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Node(s) Moved")); for (const DragOp &E : drag_buffer) { @@ -3280,7 +3277,7 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Nodes Connected")); List<VisualShader::Connection> conns; @@ -3312,7 +3309,7 @@ void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from int from = p_from.to_int(); int to = p_to.to_int(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Nodes Disconnected")); undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index); undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index); @@ -3352,7 +3349,7 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) { List<VisualShader::Connection> conns; visual_shader->get_node_connections(type, &conns); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (const int &F : p_nodes) { for (const VisualShader::Connection &E : conns) { if (E.from_node == F || E.to_node == F) { @@ -3411,7 +3408,7 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) { } void VisualShaderEditor::_replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_to); undo_redo->add_undo_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_from); } @@ -3446,7 +3443,7 @@ void VisualShaderEditor::_update_parameter(VisualShader::Type p_type_id, int p_n void VisualShaderEditor::_convert_constants_to_parameters(bool p_vice_versa) { VisualShader::Type type_id = get_current_shader_type(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (!p_vice_versa) { undo_redo->create_action(TTR("Convert Constant Node(s) To Parameter(s)")); } else { @@ -3645,7 +3642,7 @@ void VisualShaderEditor::_delete_node_request(int p_type, int p_node) { List<int> to_erase; to_erase.push_back(p_node); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete VisualShader Node")); _delete_nodes(p_type, to_erase); undo_redo->commit_action(); @@ -3674,7 +3671,7 @@ void VisualShaderEditor::_delete_nodes_request(const TypedArray<StringName> &p_n return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete VisualShader Node(s)")); _delete_nodes(get_current_shader_type(), to_erase); undo_redo->commit_action(); @@ -4087,7 +4084,7 @@ void VisualShaderEditor::_dup_copy_nodes(int p_type, List<CopyItem> &r_items, Li } void VisualShaderEditor::_dup_paste_nodes(int p_type, List<CopyItem> &r_items, const List<VisualShader::Connection> &p_connections, const Vector2 &p_offset, bool p_duplicate) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (p_duplicate) { undo_redo->create_action(TTR("Duplicate VisualShader Node(s)")); } else { @@ -4206,7 +4203,7 @@ void VisualShaderEditor::_copy_nodes(bool p_cut) { _dup_copy_nodes(get_current_shader_type(), copy_items_buffer, copy_connections_buffer); if (p_cut) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Cut VisualShader Node(s)")); List<int> ids; @@ -4293,7 +4290,7 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, bool type_changed = next_input_type != prev_input_type; - Ref<EditorUndoRedoManager> &undo_redo_man = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton(); undo_redo_man->create_action(TTR("Visual Shader Input Type Changed")); undo_redo_man->add_do_method(p_input.ptr(), "set_input_name", p_name); @@ -4362,7 +4359,7 @@ void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParamete bool type_changed = p_parameter_ref->get_parameter_type_by_name(p_name) != p_parameter_ref->get_parameter_type_by_name(prev_name); - Ref<EditorUndoRedoManager> &undo_redo_man = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton(); undo_redo_man->create_action(TTR("ParameterRef Name Changed")); undo_redo_man->add_do_method(p_parameter_ref.ptr(), "set_parameter_name", p_name); @@ -4406,7 +4403,7 @@ void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_var bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid(); - Ref<EditorUndoRedoManager> &undo_redo_man = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton(); undo_redo_man->create_action(TTR("Varying Name Changed")); undo_redo_man->add_do_method(p_varying.ptr(), "set_varying_name", p_name); @@ -4477,7 +4474,7 @@ void VisualShaderEditor::_float_constant_selected(int p_which) { return; // same } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Set Constant: %s"), float_constant_defs[p_which].name)); undo_redo->add_do_method(node.ptr(), "set_constant", float_constant_defs[p_which].value); undo_redo->add_undo_method(node.ptr(), "set_constant", node->get_constant()); @@ -4741,7 +4738,7 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da saved_node_pos_dirty = true; _add_node(idx, add_options[idx].ops); } else if (d.has("files")) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Node(s) to Visual Shader")); if (d["files"].get_type() == Variant::PACKED_STRING_ARRAY) { @@ -6172,7 +6169,7 @@ public: return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); updating = true; undo_redo->create_action(TTR("Edit Visual Property:") + " " + p_property, UndoRedo::MERGE_ENDS); @@ -6374,7 +6371,7 @@ void EditorPropertyVisualShaderMode::_option_selected(int p_which) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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 88f5e3359c..c4f6b4952c 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -95,7 +95,6 @@ private: Ref<VisualShader> visual_shader; HashMap<int, Link> links; List<VisualShader::Connection> connections; - bool dirty = false; Color vector_expanded_color[4]; @@ -115,8 +114,6 @@ public: void clear_links(); void set_shader_type(VisualShader::Type p_type); bool is_preview_visible(int p_id) const; - bool is_dirty() const; - void make_dirty(bool p_enabled); void update_node(VisualShader::Type p_type, int p_id); void update_node_deferred(VisualShader::Type p_type, int p_node_id); void add_node(VisualShader::Type p_type, int p_id, bool p_just_update); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 69c21177f9..560549d249 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -114,7 +114,7 @@ void ProjectSettingsEditor::_add_setting() { Variant value; Variant::construct(Variant::Type(type_box->get_selected_id()), value, nullptr, 0, ce); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Project Setting")); undo_redo->add_do_property(ps, setting, value); undo_redo->add_undo_property(ps, setting, ps->has_setting(setting) ? ps->get(setting) : Variant()); @@ -134,7 +134,7 @@ void ProjectSettingsEditor::_delete_setting() { Variant value = ps->get(setting); int order = ps->get_order(setting); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Delete Item")); undo_redo->add_do_method(ps, "clear", setting); @@ -223,7 +223,7 @@ void ProjectSettingsEditor::_select_type(Variant::Type p_type) { void ProjectSettingsEditor::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); const Ref<InputEventKey> k = p_event; if (k.is_valid() && k->is_pressed()) { @@ -345,7 +345,7 @@ void ProjectSettingsEditor::_action_added(const String &p_name) { action["events"] = Array(); action["deadzone"] = 0.5f; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Input Action")); undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, action); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", name); @@ -361,7 +361,7 @@ void ProjectSettingsEditor::_action_edited(const String &p_name, const Dictionar const String property_name = "input/" + p_name; Dictionary old_val = GLOBAL_GET(property_name); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (old_val["deadzone"] != p_action["deadzone"]) { // Deadzone Changed undo_redo->create_action(TTR("Change Action deadzone")); @@ -398,7 +398,7 @@ void ProjectSettingsEditor::_action_removed(const String &p_name) { Dictionary old_val = GLOBAL_GET(property_name); int order = ProjectSettings::get_singleton()->get_order(property_name); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Erase Input Action")); undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", property_name); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", property_name, old_val); @@ -421,7 +421,7 @@ void ProjectSettingsEditor::_action_renamed(const String &p_old_name, const Stri int order = ProjectSettings::get_singleton()->get_order(old_property_name); Dictionary action = GLOBAL_GET(old_property_name); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Rename Input Action Event")); // Do: clear old, set new undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", old_property_name); @@ -451,7 +451,7 @@ void ProjectSettingsEditor::_action_reordered(const String &p_action_name, const HashMap<String, Variant> action_values; ProjectSettings::get_singleton()->get_property_list(&props); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Update Input Action Order")); for (const PropertyInfo &prop : props) { diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index b7b316df64..c3a99e96ef 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -583,7 +583,7 @@ void RenameDialog::rename() { _iterate_scene(root_node, selected_node_list, &global_count); if (!to_rename.is_empty()) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Batch Rename")); // Make sure to iterate reversed so that child nodes will find parents. diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index ac6bceaa55..733f140a56 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -231,7 +231,7 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Instantiate Scene(s)")); for (int i = 0; i < instances.size(); i++) { @@ -275,7 +275,7 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Replace with Branch Scene")); Node *parent = base->get_parent(); @@ -540,7 +540,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Detach Script"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); undo_redo->add_do_method(EditorNode::get_singleton(), "push_item", (Script *)nullptr); @@ -611,7 +611,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; // one or more nodes can not be moved } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (selection.size() == 1) { undo_redo->create_action(TTR("Move Node In Parent")); } @@ -661,7 +661,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Duplicate Node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get()); undo_redo->add_do_method(editor_selection, "clear"); @@ -778,7 +778,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Make node as Root")); undo_redo->add_do_method(node->get_parent(), "remove_child", node); undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", node); @@ -1023,7 +1023,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(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (!root) { break; } @@ -1099,7 +1099,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { bool enabling = !first_selected->get()->is_unique_name_in_owner(); List<Node *> full_selection = editor_selection->get_full_selected_node_list(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (enabling) { Vector<Node *> new_unique_nodes; @@ -1226,7 +1226,7 @@ void SceneTreeDock::_property_selected(int p_idx) { } void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, Ref<Resource> p_res) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Set %s"), p_property)); undo_redo->add_do_property(p_node, p_property, p_res); undo_redo->add_undo_property(p_node, p_property, p_node->get(p_property)); @@ -1234,7 +1234,7 @@ void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, Ref< } void SceneTreeDock::add_root_node(Node *p_node) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action_for_history(TTR("New Scene Root"), editor_data->get_current_edited_scene_history_id()); undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node); undo_redo->add_do_method(scene_tree, "update_tree"); @@ -1385,7 +1385,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) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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; @@ -1619,7 +1619,7 @@ 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)) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_property(p_base, propertyname, updated_variant); undo_redo->add_undo_property(p_base, propertyname, old_variant); p_base->set(propertyname, updated_variant); @@ -1666,7 +1666,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath> } HashMap<Node *, NodePath>::Iterator found_path = p_renames->find(n); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (found_path) { if (found_path->value == NodePath()) { //will be erased @@ -1833,7 +1833,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>(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Reparent Node"), UndoRedo::MERGE_DISABLE, p_nodes[0]); HashMap<Node *, NodePath> path_renames; @@ -1968,7 +1968,7 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, selected.front()->get()); for (Node *E : selected) { Ref<Script> existing = E->get_script(); @@ -1994,7 +1994,7 @@ void SceneTreeDock::_shader_created(Ref<Shader> p_shader) { Ref<Shader> existing = selected_shader_material->get_shader(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set Shader")); undo_redo->add_do_method(selected_shader_material.ptr(), "set_shader", p_shader); undo_redo->add_undo_method(selected_shader_material.ptr(), "set_shader", existing); @@ -2063,7 +2063,7 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { EditorNode::get_singleton()->get_editor_plugins_over()->make_visible(false); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(p_cut ? TTR("Cut Node(s)") : TTR("Remove Node(s)"), UndoRedo::MERGE_DISABLE, remove_list.front()->get()); bool entire_scene = false; @@ -2193,7 +2193,7 @@ void SceneTreeDock::_do_create(Node *p_parent) { } child->set_name(new_name); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action_for_history(TTR("Create Node"), editor_data->get_current_edited_scene_history_id()); if (edited_scene) { @@ -2262,7 +2262,7 @@ void SceneTreeDock::_create() { List<Node *> selection = editor_selection->get_selected_node_list(); ERR_FAIL_COND(selection.size() <= 0); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Change type of node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get()); for (Node *n : selection) { @@ -2396,7 +2396,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) { - EditorNode::get_undo_redo()->clear_history(); + EditorUndoRedoManager::get_singleton()->clear_history(); } newnode->set_name(newname); @@ -2618,7 +2618,7 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (Input::get_singleton()->is_key_pressed(Key::CTRL)) { Object *obj = ClassDB::instantiate(scr->get_instance_base_type()); ERR_FAIL_NULL(obj); @@ -3190,7 +3190,7 @@ List<Node *> SceneTreeDock::paste_nodes() { owner = paste_parent; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Paste Node(s)"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); ur->add_do_method(editor_selection, "clear"); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index b4f1ca5d0b..148dcd862a 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -68,7 +68,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i Node *n = get_node(np); ERR_FAIL_COND(!n); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (p_id == BUTTON_SUBSCENE) { if (n == get_scene_node()) { if (n && n->get_scene_inherited_state().is_valid()) { @@ -176,7 +176,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i void SceneTreeEditor::_toggle_visible(Node *p_node) { if (p_node->has_method("is_visible") && p_node->has_method("set_visible")) { bool v = bool(p_node->call("is_visible")); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(p_node, "set_visible", !v); undo_redo->add_undo_method(p_node, "set_visible", v); } @@ -1015,7 +1015,7 @@ void SceneTreeEditor::_renamed() { which->set_metadata(0, n->get_path()); emit_signal(SNAME("node_renamed")); } else { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Rename Node")); emit_signal(SNAME("node_prerename"), n, new_name); undo_redo->add_do_method(this, "_rename_node", n->get_instance_id(), new_name); diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp index 4ac0a5b672..800de431eb 100644 --- a/editor/shader_globals_editor.cpp +++ b/editor/shader_globals_editor.cpp @@ -70,7 +70,7 @@ class ShaderGlobalsEditorInterface : public Object { GDCLASS(ShaderGlobalsEditorInterface, Object) void _set_var(const StringName &p_name, const Variant &p_value, const Variant &p_prev_value) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Set Shader Global Variable")); undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_value); @@ -399,7 +399,7 @@ void ShaderGlobalsEditor::_variable_added() { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Variant value = create_var(RS::GlobalShaderParameterType(variable_type->get_selected())); @@ -418,7 +418,7 @@ void ShaderGlobalsEditor::_variable_added() { } void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Shader Global Parameter")); undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_remove", p_variable); diff --git a/main/main.cpp b/main/main.cpp index e38669f161..7ba5ffab2a 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1385,7 +1385,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph #ifdef TOOLS_ENABLED if (editor) { packed_data->set_disabled(true); - globals->set_disable_feature_overrides(true); Engine::get_singleton()->set_editor_hint(true); main_args.push_back("--editor"); if (!init_windowed) { diff --git a/main/performance.cpp b/main/performance.cpp index 869a947b2a..e24a3673b9 100644 --- a/main/performance.cpp +++ b/main/performance.cpp @@ -316,6 +316,7 @@ uint64_t Performance::get_monitor_modification_time() { Performance::Performance() { _process_time = 0; _physics_process_time = 0; + _navigation_process_time = 0; _monitor_modification_time = 0; singleton = this; } diff --git a/methods.py b/methods.py index ee88401671..7ede2592ff 100644 --- a/methods.py +++ b/methods.py @@ -488,29 +488,29 @@ def use_windows_spawn_fix(self, platform=None): def save_active_platforms(apnames, ap): for x in ap: - names = ["logo"] - if os.path.isfile(x + "/run_icon.png"): - names.append("run_icon") - - for name in names: - pngf = open(x + "/" + name + ".png", "rb") - b = pngf.read(1) - str = " /* AUTOGENERATED FILE, DO NOT EDIT */ \n" - str += " static const unsigned char _" + x[9:] + "_" + name + "[]={" + svg_names = [] + if os.path.isfile(x + "/logo.svg"): + svg_names.append("logo") + if os.path.isfile(x + "/run_icon.svg"): + svg_names.append("run_icon") + + for name in svg_names: + svgf = open(x + "/" + name + ".svg", "rb") + b = svgf.read(1) + svg_str = " /* AUTOGENERATED FILE, DO NOT EDIT */ \n" + svg_str += " static const char *_" + x[9:] + "_" + name + '_svg = "' while len(b) == 1: - str += hex(ord(b)) - b = pngf.read(1) - if len(b) == 1: - str += "," + svg_str += "\\" + hex(ord(b))[1:] + b = svgf.read(1) - str += "};\n" + svg_str += '";\n' - pngf.close() + svgf.close() # NOTE: It is safe to generate this file here, since this is still executed serially - wf = x + "/" + name + ".gen.h" - with open(wf, "w") as pngw: - pngw.write(str) + wf = x + "/" + name + "_svg.gen.h" + with open(wf, "w") as svgw: + svgw.write(svg_str) def no_verbose(sys, env): diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp index 61787691a3..2c533cb36d 100644 --- a/modules/csg/editor/csg_gizmos.cpp +++ b/modules/csg/editor/csg_gizmos.cpp @@ -217,7 +217,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -231,7 +231,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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); @@ -249,7 +249,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); if (p_id == 0) { ur->create_action(TTR("Change Cylinder Radius")); ur->add_do_method(s, "set_radius", s->get_radius()); @@ -274,7 +274,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); 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/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 0c858a36e7..1b488d560c 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -889,11 +889,11 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, resolve_function_signature(member.function, p_source); break; case GDScriptParser::ClassNode::Member::ENUM_VALUE: { + member.enum_value.identifier->set_datatype(resolving_datatype); + if (member.enum_value.custom_value) { check_class_member_name_conflict(p_class, member.enum_value.identifier->name, member.enum_value.custom_value); - member.enum_value.identifier->set_datatype(resolving_datatype); - const GDScriptParser::EnumNode *prev_enum = current_enum; current_enum = member.enum_value.parent_enum; reduce_expression(member.enum_value.custom_value); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 0a1ae46927..397c43b14b 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -80,7 +80,7 @@ Ref<Script> GDScriptLanguage::make_template(const String &p_template, const Stri } processed_template = processed_template.replace("_BASE_", p_base_class_name) - .replace("_CLASS_", p_class_name) + .replace("_CLASS_", p_class_name.to_pascal_case()) .replace("_TS_", _get_indentation()); scr->set_source_code(processed_template); return scr; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index bbea6fe857..97d5c1d8b2 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3794,6 +3794,26 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.type = Variant::INT; } } + if (p_annotation->name == SNAME("@export_multiline")) { + if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type()) { + DataType inner_type = export_type.get_container_element_type(); + if (inner_type.builtin_type != Variant::STRING) { + push_error(vformat(R"("%s" annotation on arrays requires a string type but type "%s" was given instead.)", p_annotation->name.operator String(), inner_type.to_string()), variable); + return false; + } + + String hint_prefix = itos(inner_type.builtin_type) + "/" + itos(variable->export_info.hint); + variable->export_info.hint = PROPERTY_HINT_TYPE_STRING; + variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string; + variable->export_info.type = Variant::ARRAY; + + return true; + } else if (export_type.builtin_type == Variant::DICTIONARY) { + variable->export_info.type = Variant::DICTIONARY; + + return true; + } + } if (p_annotation->name == SNAME("@export")) { if (variable->datatype_specifier == nullptr && variable->initializer == nullptr) { diff --git a/modules/gdscript/tests/README.md b/modules/gdscript/tests/README.md index 6e54085962..361d586d32 100644 --- a/modules/gdscript/tests/README.md +++ b/modules/gdscript/tests/README.md @@ -4,5 +4,5 @@ The `scripts/` folder contains integration tests in the form of GDScript files and output files. See the -[Integration tests for GDScript documentation](https://docs.godotengine.org/en/latest/development/cpp/unit_testing.html#integration-tests-for-gdscript) +[Integration tests for GDScript documentation](https://docs.godotengine.org/en/latest/contributing/development/core_and_modules/unit_testing.html#integration-tests-for-gdscript) for information about creating and running GDScript integration tests. diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml index f313f4b28f..d7e8141eb1 100644 --- a/modules/gltf/doc_classes/GLTFDocument.xml +++ b/modules/gltf/doc_classes/GLTFDocument.xml @@ -15,7 +15,7 @@ <param index="2" name="state" type="GLTFState" /> <param index="3" name="flags" type="int" default="0" /> <description> - Takes a [PackedByteArray] defining a gLTF and returns a [GLTFState] object through the [param state] parameter. + Takes a [PackedByteArray] defining a GLTF and imports the data to the given [GLTFState] object through the [param state] parameter. [b]Note:[/b] The [param base_path] tells [method append_from_buffer] where to find dependencies and can be empty. </description> </method> @@ -26,7 +26,7 @@ <param index="2" name="flags" type="int" default="0" /> <param index="3" name="base_path" type="String" default="""" /> <description> - Takes a path to a gLTF file and returns a [GLTFState] object through the [param state] parameter. + Takes a path to a GLTF file and imports the data at that file path to the given [GLTFState] object through the [param state] parameter. [b]Note:[/b] The [param base_path] tells [method append_from_file] where to find dependencies and can be empty. </description> </method> @@ -36,14 +36,14 @@ <param index="1" name="state" type="GLTFState" /> <param index="2" name="flags" type="int" default="0" /> <description> - Takes a Godot Engine scene node and returns a [GLTFState] object through the [param state] parameter. + Takes a Godot Engine scene node and exports it and its descendants to the given [GLTFState] object through the [param state] parameter. </description> </method> <method name="generate_buffer"> <return type="PackedByteArray" /> <param index="0" name="state" type="GLTFState" /> <description> - Takes a [GLTFState] object through the [param state] parameter and returns a gLTF [PackedByteArray]. + Takes a [GLTFState] object through the [param state] parameter and returns a GLTF [PackedByteArray]. </description> </method> <method name="generate_scene"> diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index 67bb99de16..183190460e 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -461,7 +461,7 @@ void GridMapEditor::_delete_selection() { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("GridMap Delete Selection")); for (int i = selection.begin.x; i <= selection.end.x; i++) { for (int j = selection.begin.y; j <= selection.end.y; j++) { @@ -482,7 +482,7 @@ void GridMapEditor::_fill_selection() { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("GridMap Fill Selection")); for (int i = selection.begin.x; i <= selection.end.x; i++) { for (int j = selection.begin.y; j <= selection.end.y; j++) { @@ -576,7 +576,7 @@ void GridMapEditor::_do_paste() { rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation); Vector3 ofs = paste_indicator.current - paste_indicator.click; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("GridMap Paste Selection")); for (const ClipboardItem &item : clipboard_items) { @@ -664,7 +664,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D } else { if ((mb->get_button_index() == MouseButton::RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_PAINT)) { if (set_items.size()) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("GridMap Paint")); for (const SetItem &si : set_items) { undo_redo->add_do_method(node, "set_cell_item", si.position, si.new_value, si.new_orientation); @@ -686,7 +686,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D } if (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_SELECT) { - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("GridMap Selection")); undo_redo->add_do_method(this, "_set_selection", selection.active, selection.begin, selection.end); undo_redo->add_undo_method(this, "_set_selection", last_selection.active, last_selection.begin, last_selection.end); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index c45fdda75c..e39127e0a1 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -688,7 +688,7 @@ bool CSharpLanguage::is_assembly_reloading_needed() { return false; // Already up to date } } else { - String assembly_name = ProjectSettings::get_singleton()->get_setting("dotnet/project/assembly_name"); + String assembly_name = GLOBAL_GET("dotnet/project/assembly_name"); if (assembly_name.is_empty()) { assembly_name = ProjectSettings::get_singleton()->get_safe_project_name(); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs index a2916d4ae8..0e46b63b59 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs @@ -437,48 +437,25 @@ namespace Godot /// <summary> /// Returns <see langword="true"/> if the <see cref="AABB"/> overlaps with <paramref name="with"/> /// (i.e. they have at least one point in common). - /// - /// If <paramref name="includeBorders"/> is <see langword="true"/>, - /// they will also be considered overlapping if their borders touch, - /// even without intersection. /// </summary> /// <param name="with">The other <see cref="AABB"/> to check for intersections with.</param> - /// <param name="includeBorders">Whether or not to consider borders.</param> /// <returns> /// A <see langword="bool"/> for whether or not they are intersecting. /// </returns> - public readonly bool Intersects(AABB with, bool includeBorders = false) + public readonly bool Intersects(AABB with) { - if (includeBorders) - { - if (_position.x > with._position.x + with._size.x) - return false; - if (_position.x + _size.x < with._position.x) - return false; - if (_position.y > with._position.y + with._size.y) - return false; - if (_position.y + _size.y < with._position.y) - return false; - if (_position.z > with._position.z + with._size.z) - return false; - if (_position.z + _size.z < with._position.z) - return false; - } - else - { - if (_position.x >= with._position.x + with._size.x) - return false; - if (_position.x + _size.x <= with._position.x) - return false; - if (_position.y >= with._position.y + with._size.y) - return false; - if (_position.y + _size.y <= with._position.y) - return false; - if (_position.z >= with._position.z + with._size.z) - return false; - if (_position.z + _size.z <= with._position.z) - return false; - } + if (_position.x >= with._position.x + with._size.x) + return false; + if (_position.x + _size.x <= with._position.x) + return false; + if (_position.y >= with._position.y + with._size.y) + return false; + if (_position.y + _size.y <= with._position.y) + return false; + if (_position.z >= with._position.z + with._size.z) + return false; + if (_position.z + _size.z <= with._position.z) + return false; return true; } @@ -586,6 +563,16 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this <see cref="AABB"/> is finite, by calling + /// <see cref="Mathf.IsFinite"/> on each component. + /// </summary> + /// <returns>Whether this vector is finite or not.</returns> + public readonly bool IsFinite() + { + return _position.IsFinite() && _size.IsFinite(); + } + + /// <summary> /// Returns a larger <see cref="AABB"/> that contains this <see cref="AABB"/> and <paramref name="with"/>. /// </summary> /// <param name="with">The other <see cref="AABB"/>.</param> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 5d390a298d..19f7c54847 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -120,31 +120,6 @@ namespace Godot } /// <summary> - /// The scale of this basis. - /// </summary> - /// <value>Equivalent to the lengths of each column vector, but negative if the determinant is negative.</value> - public Vector3 Scale - { - readonly get - { - real_t detSign = Mathf.Sign(Determinant()); - return detSign * new Vector3 - ( - Column0.Length(), - Column1.Length(), - Column2.Length() - ); - } - set - { - value /= Scale; // Value becomes what's called "delta_scale" in core. - Column0 *= value.x; - Column1 *= value.y; - Column2 *= value.z; - } - } - - /// <summary> /// Access whole columns in the form of <see cref="Vector3"/>. /// </summary> /// <param name="column">Which column vector.</param> @@ -493,12 +468,6 @@ namespace Godot } } - /// <summary> - /// Returns the basis's rotation in the form of a quaternion. - /// See <see cref="GetEuler"/> if you need Euler angles, but keep in - /// mind that quaternions should generally be preferred to Euler angles. - /// </summary> - /// <returns>A <see cref="Quaternion"/> representing the basis's rotation.</returns> internal readonly Quaternion GetQuaternion() { real_t trace = Row0[0] + Row1[1] + Row2[2]; @@ -573,106 +542,18 @@ namespace Godot } /// <summary> - /// Get rows by index. Rows are not very useful for user code, - /// but are more efficient for some internal calculations. - /// </summary> - /// <param name="index">Which row.</param> - /// <exception cref="ArgumentOutOfRangeException"> - /// <paramref name="index"/> is not 0, 1 or 2. - /// </exception> - /// <returns>One of <c>Row0</c>, <c>Row1</c>, or <c>Row2</c>.</returns> - public readonly Vector3 GetRow(int index) - { - switch (index) - { - case 0: - return Row0; - case 1: - return Row1; - case 2: - return Row2; - default: - throw new ArgumentOutOfRangeException(nameof(index)); - } - } - - /// <summary> - /// Sets rows by index. Rows are not very useful for user code, - /// but are more efficient for some internal calculations. - /// </summary> - /// <param name="index">Which row.</param> - /// <param name="value">The vector to set the row to.</param> - /// <exception cref="ArgumentOutOfRangeException"> - /// <paramref name="index"/> is not 0, 1 or 2. - /// </exception> - public void SetRow(int index, Vector3 value) - { - switch (index) - { - case 0: - Row0 = value; - return; - case 1: - Row1 = value; - return; - case 2: - Row2 = value; - return; - default: - throw new ArgumentOutOfRangeException(nameof(index)); - } - } - - /// <summary> - /// 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 <see cref="GridMap"/> editor. - /// - /// For further details, refer to the Godot source code. + /// Assuming that the matrix is the combination of a rotation and scaling, + /// return the absolute value of scaling factors along each axis. /// </summary> - /// <returns>The orthogonal index.</returns> - public readonly int GetOrthogonalIndex() + public readonly Vector3 GetScale() { - var orth = this; - - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - var row = orth.GetRow(i); - - real_t v = row[j]; - - if (v > 0.5f) - { - v = 1.0f; - } - else if (v < -0.5f) - { - v = -1.0f; - } - else - { - v = 0f; - } - - row[j] = v; - - orth.SetRow(i, row); - } - } - - for (int i = 0; i < 24; i++) - { - if (orth == _orthoBases[i]) - { - return i; - } - } - - return 0; + real_t detSign = Mathf.Sign(Determinant()); + return detSign * new Vector3 + ( + Column0.Length(), + Column1.Length(), + Column2.Length() + ); } /// <summary> @@ -709,6 +590,16 @@ namespace Godot ); } + /// <summary> + /// Returns <see langword="true"/> if this basis is finite, by calling + /// <see cref="Mathf.IsFinite"/> on each component. + /// </summary> + /// <returns>Whether this vector is finite or not.</returns> + public readonly bool IsFinite() + { + return Row0.IsFinite() && Row1.IsFinite() && Row2.IsFinite(); + } + internal readonly Basis Lerp(Basis to, real_t weight) { Basis b = this; @@ -896,7 +787,7 @@ namespace Godot /// <param name="quaternion">The quaternion to create the basis from.</param> public Basis(Quaternion quaternion) { - real_t s = 2.0f / quaternion.LengthSquared; + real_t s = 2.0f / quaternion.LengthSquared(); real_t xs = quaternion.x * s; real_t ys = quaternion.y * s; @@ -967,8 +858,20 @@ namespace Godot // We need to assign the struct fields here first so we can't do it that way... } - // Arguments are named such that xy is equal to calling x.y - internal Basis(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz) + /// <summary> + /// Constructs a transformation matrix from the given components. + /// Arguments are named such that xy is equal to calling <c>x.y</c>. + /// </summary> + /// <param name="xx">The X component of the X column vector, accessed via <c>b.x.x</c> or <c>[0][0]</c>.</param> + /// <param name="yx">The X component of the Y column vector, accessed via <c>b.y.x</c> or <c>[1][0]</c>.</param> + /// <param name="zx">The X component of the Z column vector, accessed via <c>b.z.x</c> or <c>[2][0]</c>.</param> + /// <param name="xy">The Y component of the X column vector, accessed via <c>b.x.y</c> or <c>[0][1]</c>.</param> + /// <param name="yy">The Y component of the Y column vector, accessed via <c>b.y.y</c> or <c>[1][1]</c>.</param> + /// <param name="zy">The Y component of the Z column vector, accessed via <c>b.y.y</c> or <c>[2][1]</c>.</param> + /// <param name="xz">The Z component of the X column vector, accessed via <c>b.x.y</c> or <c>[0][2]</c>.</param> + /// <param name="yz">The Z component of the Y column vector, accessed via <c>b.y.y</c> or <c>[1][2]</c>.</param> + /// <param name="zz">The Z component of the Z column vector, accessed via <c>b.y.y</c> or <c>[2][2]</c>.</param> + public Basis(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz) { Row0 = new Vector3(xx, yx, zx); Row1 = new Vector3(xy, yy, zy); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs index 3f9e986f62..b2cb0f5e6b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs @@ -440,6 +440,17 @@ namespace Godot } /// <summary> + /// Returns whether <paramref name="s"/> is a finite value, i.e. it is not + /// <see cref="NaN"/>, positive infinite, or negative infinity. + /// </summary> + /// <param name="s">The value to check.</param> + /// <returns>A <see langword="bool"/> for whether or not the value is a finite value.</returns> + public static bool IsFinite(real_t s) + { + return real_t.IsFinite(s); + } + + /// <summary> /// Returns whether <paramref name="s"/> is an infinity value (either positive infinity or negative infinity). /// </summary> /// <param name="s">The value to check.</param> @@ -460,10 +471,11 @@ namespace Godot } /// <summary> - /// Returns <see langword="true"/> if <paramref name="s"/> is approximately zero. + /// Returns <see langword="true"/> if <paramref name="s"/> is zero or almost zero. /// The comparison is done using a tolerance calculation with <see cref="Epsilon"/>. /// - /// This method is faster than using <see cref="IsEqualApprox(real_t, real_t)"/> with one value as zero. + /// This method is faster than using <see cref="IsEqualApprox(real_t, real_t)"/> with + /// one value as zero. /// </summary> /// <param name="s">The value to check.</param> /// <returns>A <see langword="bool"/> for whether or not the value is nearly zero.</returns> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs index 42c6b0a37e..8a125e3c73 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs @@ -15,7 +15,7 @@ namespace Godot private Vector3 _normal; /// <summary> - /// The normal of the plane, which must be normalized. + /// The normal of the plane, which must be a unit vector. /// In the scalar equation of the plane <c>ax + by + cz = d</c>, this is /// the vector <c>(a, b, c)</c>, where <c>d</c> is the <see cref="D"/> property. /// </summary> @@ -85,23 +85,6 @@ namespace Godot public real_t D { get; set; } /// <summary> - /// The center of the plane, the point where the normal line intersects the plane. - /// </summary> - /// <value>Equivalent to <see cref="Normal"/> multiplied by <see cref="D"/>.</value> - public Vector3 Center - { - readonly get - { - return _normal * D; - } - set - { - _normal = value.Normalized(); - D = value.Length(); - } - } - - /// <summary> /// Returns the shortest distance from this plane to the position <paramref name="point"/>. /// </summary> /// <param name="point">The position to use for the calculation.</param> @@ -112,6 +95,16 @@ namespace Godot } /// <summary> + /// Returns the center of the plane, the point on the plane closest to the origin. + /// The point where the normal line going through the origin intersects the plane. + /// </summary> + /// <value>Equivalent to <see cref="Normal"/> multiplied by <see cref="D"/>.</value> + public readonly Vector3 GetCenter() + { + return _normal * D; + } + + /// <summary> /// Returns <see langword="true"/> if point is inside the plane. /// Comparison uses a custom minimum tolerance threshold. /// </summary> @@ -155,7 +148,7 @@ namespace Godot /// <param name="from">The start of the ray.</param> /// <param name="dir">The direction of the ray, normalized.</param> /// <returns>The intersection, or <see langword="null"/> if none is found.</returns> - public readonly Vector3? IntersectRay(Vector3 from, Vector3 dir) + public readonly Vector3? IntersectsRay(Vector3 from, Vector3 dir) { real_t den = _normal.Dot(dir); @@ -183,7 +176,7 @@ namespace Godot /// <param name="begin">The start of the line segment.</param> /// <param name="end">The end of the line segment.</param> /// <returns>The intersection, or <see langword="null"/> if none is found.</returns> - public readonly Vector3? IntersectSegment(Vector3 begin, Vector3 end) + public readonly Vector3? IntersectsSegment(Vector3 begin, Vector3 end) { Vector3 segment = begin - end; real_t den = _normal.Dot(segment); @@ -205,6 +198,16 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this plane is finite, by calling + /// <see cref="Mathf.IsFinite"/> on each component. + /// </summary> + /// <returns>Whether this vector is finite or not.</returns> + public readonly bool IsFinite() + { + return _normal.IsFinite() && Mathf.IsFinite(D); + } + + /// <summary> /// Returns <see langword="true"/> if <paramref name="point"/> is located above the plane. /// </summary> /// <param name="point">The point to check.</param> @@ -280,10 +283,21 @@ namespace Godot } /// <summary> + /// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector. + /// The plane will intersect the origin. + /// </summary> + /// <param name="normal">The normal of the plane, must be a unit vector.</param> + public Plane(Vector3 normal) + { + _normal = normal; + D = 0; + } + + /// <summary> /// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector and /// the plane's distance to the origin <paramref name="d"/>. /// </summary> - /// <param name="normal">The normal of the plane, must be normalized.</param> + /// <param name="normal">The normal of the plane, must be a unit vector.</param> /// <param name="d">The plane's distance from the origin. This value is typically non-negative.</param> public Plane(Vector3 normal, real_t d) { @@ -295,7 +309,7 @@ namespace Godot /// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector and /// a <paramref name="point"/> on the plane. /// </summary> - /// <param name="normal">The normal of the plane, must be normalized.</param> + /// <param name="normal">The normal of the plane, must be a unit vector.</param> /// <param name="point">The point on the plane.</param> public Plane(Vector3 normal, Vector3 point) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index bd0dea0c1c..47106bb402 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -97,27 +97,6 @@ namespace Godot } /// <summary> - /// Returns the length (magnitude) of the quaternion. - /// </summary> - /// <seealso cref="LengthSquared"/> - /// <value>Equivalent to <c>Mathf.Sqrt(LengthSquared)</c>.</value> - public readonly real_t Length - { - get { return Mathf.Sqrt(LengthSquared); } - } - - /// <summary> - /// Returns the squared length (squared magnitude) of the quaternion. - /// This method runs faster than <see cref="Length"/>, so prefer it if - /// you need to compare quaternions or need the squared length for some formula. - /// </summary> - /// <value>Equivalent to <c>Dot(this)</c>.</value> - public readonly real_t LengthSquared - { - get { return Dot(this); } - } - - /// <summary> /// Returns the angle between this quaternion and <paramref name="to"/>. /// This is the magnitude of the angle you would need to rotate /// by to get from one to the other. @@ -340,12 +319,22 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this quaternion is finite, by calling + /// <see cref="Mathf.IsFinite"/> on each component. + /// </summary> + /// <returns>Whether this vector is finite or not.</returns> + public readonly bool IsFinite() + { + return Mathf.IsFinite(x) && Mathf.IsFinite(y) && Mathf.IsFinite(z) && Mathf.IsFinite(w); + } + + /// <summary> /// Returns whether the quaternion is normalized or not. /// </summary> /// <returns>A <see langword="bool"/> for whether the quaternion is normalized or not.</returns> public readonly bool IsNormalized() { - return Mathf.Abs(LengthSquared - 1) <= Mathf.Epsilon; + return Mathf.Abs(LengthSquared() - 1) <= Mathf.Epsilon; } public readonly Quaternion Log() @@ -355,12 +344,33 @@ namespace Godot } /// <summary> + /// Returns the length (magnitude) of the quaternion. + /// </summary> + /// <seealso cref="LengthSquared"/> + /// <value>Equivalent to <c>Mathf.Sqrt(LengthSquared)</c>.</value> + public readonly real_t Length() + { + return Mathf.Sqrt(LengthSquared()); + } + + /// <summary> + /// Returns the squared length (squared magnitude) of the quaternion. + /// This method runs faster than <see cref="Length"/>, so prefer it if + /// you need to compare quaternions or need the squared length for some formula. + /// </summary> + /// <value>Equivalent to <c>Dot(this)</c>.</value> + public readonly real_t LengthSquared() + { + return Dot(this); + } + + /// <summary> /// Returns a copy of the quaternion, normalized to unit length. /// </summary> /// <returns>The normalized quaternion.</returns> public readonly Quaternion Normalized() { - return this / Length; + return this / Length(); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index b0e0e75a34..1a8696d3bc 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs @@ -101,6 +101,16 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this <see cref="Rect2"/> is finite, by calling + /// <see cref="Mathf.IsFinite"/> on each component. + /// </summary> + /// <returns>Whether this vector is finite or not.</returns> + public bool IsFinite() + { + return _position.IsFinite() && _size.IsFinite(); + } + + /// <summary> /// Returns <see langword="true"/> if this <see cref="Rect2"/> completely encloses another one. /// </summary> /// <param name="b">The other <see cref="Rect2"/> that may be enclosed.</param> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs index faee81a98a..cf8939a859 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs @@ -275,38 +275,19 @@ namespace Godot /// <summary> /// Returns <see langword="true"/> if the <see cref="Rect2i"/> overlaps with <paramref name="b"/> /// (i.e. they have at least one point in common). - /// - /// If <paramref name="includeBorders"/> is <see langword="true"/>, - /// they will also be considered overlapping if their borders touch, - /// even without intersection. /// </summary> /// <param name="b">The other <see cref="Rect2i"/> to check for intersections with.</param> - /// <param name="includeBorders">Whether or not to consider borders.</param> /// <returns>A <see langword="bool"/> for whether or not they are intersecting.</returns> - public readonly bool Intersects(Rect2i b, bool includeBorders = false) + public readonly bool Intersects(Rect2i b) { - if (includeBorders) - { - if (_position.x > b._position.x + b._size.x) - return false; - if (_position.x + _size.x < b._position.x) - return false; - if (_position.y > b._position.y + b._size.y) - return false; - if (_position.y + _size.y < b._position.y) - return false; - } - else - { - if (_position.x >= b._position.x + b._size.x) - return false; - if (_position.x + _size.x <= b._position.x) - return false; - if (_position.y >= b._position.y + b._size.y) - return false; - if (_position.y + _size.y <= b._position.y) - return false; - } + if (_position.x >= b._position.x + b._size.x) + return false; + if (_position.x + _size.x <= b._position.x) + return false; + if (_position.y >= b._position.y + b._size.y) + return false; + if (_position.y + _size.y <= b._position.y) + return false; return true; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 756f71e5b2..6dda150c2b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -32,45 +32,6 @@ namespace Godot public Vector2 origin; /// <summary> - /// The rotation of this transformation matrix. - /// </summary> - /// <value>Getting is equivalent to calling <see cref="Mathf.Atan2(real_t, real_t)"/> with the values of <see cref="x"/>.</value> - public real_t Rotation - { - readonly get - { - return Mathf.Atan2(x.y, x.x); - } - set - { - Vector2 scale = Scale; - x.x = y.y = Mathf.Cos(value); - x.y = y.x = Mathf.Sin(value); - y.x *= -1; - Scale = scale; - } - } - - /// <summary> - /// The scale of this transformation matrix. - /// </summary> - /// <value>Equivalent to the lengths of each column vector, but Y is negative if the determinant is negative.</value> - public Vector2 Scale - { - readonly get - { - real_t detSign = Mathf.Sign(BasisDeterminant()); - return new Vector2(x.Length(), detSign * y.Length()); - } - set - { - value /= Scale; // Value becomes what's called "delta_scale" in core. - x *= value.x; - y *= value.y; - } - } - - /// <summary> /// Access whole columns in the form of <see cref="Vector2"/>. /// The third column is the <see cref="origin"/> vector. /// </summary> @@ -203,6 +164,23 @@ namespace Godot } /// <summary> + /// Returns the transform's rotation (in radians). + /// </summary> + public readonly real_t GetRotation() + { + return Mathf.Atan2(x.y, x.x); + } + + /// <summary> + /// Returns the scale. + /// </summary> + public readonly Vector2 GetScale() + { + real_t detSign = Mathf.Sign(BasisDeterminant()); + return new Vector2(x.Length(), detSign * y.Length()); + } + + /// <summary> /// Interpolates this transform to the other <paramref name="transform"/> by <paramref name="weight"/>. /// </summary> /// <param name="transform">The other transform.</param> @@ -210,11 +188,11 @@ namespace Godot /// <returns>The interpolated transform.</returns> public readonly Transform2D InterpolateWith(Transform2D transform, real_t weight) { - real_t r1 = Rotation; - real_t r2 = transform.Rotation; + real_t r1 = GetRotation(); + real_t r2 = transform.GetRotation(); - Vector2 s1 = Scale; - Vector2 s2 = transform.Scale; + Vector2 s1 = GetScale(); + Vector2 s2 = transform.GetScale(); // Slerp rotation var v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1)); @@ -271,6 +249,16 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this transform is finite, by calling + /// <see cref="Mathf.IsFinite"/> on each component. + /// </summary> + /// <returns>Whether this vector is finite or not.</returns> + public readonly bool IsFinite() + { + return x.IsFinite() && y.IsFinite() && origin.IsFinite(); + } + + /// <summary> /// Returns the transform with the basis orthogonal (90 degrees), /// and normalized axis vectors (scale of 1 or -1). /// </summary> @@ -423,7 +411,7 @@ namespace Godot /// <summary> /// Constructs a transformation matrix from the given components. - /// Arguments are named such that xy is equal to calling x.y + /// Arguments are named such that xy is equal to calling <c>x.y</c>. /// </summary> /// <param name="xx">The X component of the X column vector, accessed via <c>t.x.x</c> or <c>[0][0]</c>.</param> /// <param name="xy">The Y component of the X column vector, accessed via <c>t.x.y</c> or <c>[0][1]</c>.</param> @@ -453,6 +441,24 @@ namespace Godot } /// <summary> + /// Constructs a transformation matrix from a <paramref name="rotation"/> value, + /// <paramref name="scale"/> vector, <paramref name="skew"/> value, and + /// <paramref name="origin"/> vector. + /// </summary> + /// <param name="rotation">The rotation of the new transform, in radians.</param> + /// <param name="scale">The scale of the new transform.</param> + /// <param name="skew">The skew of the new transform, in radians.</param> + /// <param name="origin">The origin vector, or column index 2.</param> + public Transform2D(real_t rotation, Vector2 scale, real_t skew, Vector2 origin) + { + x.x = Mathf.Cos(rotation) * scale.x; + y.y = Mathf.Cos(rotation + skew) * scale.y; + y.x = -Mathf.Sin(rotation + skew) * scale.y; + x.y = Mathf.Sin(rotation) * scale.x; + this.origin = origin; + } + + /// <summary> /// Composes these two transformation matrices by multiplying them /// together. This has the effect of transforming the second transform /// (the child) by the first transform (the parent). diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 39167bd116..6b2475fc59 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -115,16 +115,30 @@ namespace Godot } /// <summary> - /// Interpolates this transform to the other <paramref name="transform"/> by <paramref name="weight"/>. + /// Returns a transform interpolated between this transform and another + /// <paramref name="transform"/> by a given <paramref name="weight"/> + /// (on the range of 0.0 to 1.0). /// </summary> /// <param name="transform">The other transform.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated transform.</returns> public readonly Transform3D InterpolateWith(Transform3D transform, real_t weight) { - Basis retBasis = basis.Lerp(transform.basis, weight); - Vector3 retOrigin = origin.Lerp(transform.origin, weight); - return new Transform3D(retBasis, retOrigin); + Vector3 sourceScale = basis.GetScale(); + Quaternion sourceRotation = basis.GetRotationQuaternion(); + Vector3 sourceLocation = origin; + + Vector3 destinationScale = transform.basis.GetScale(); + Quaternion destinationRotation = transform.basis.GetRotationQuaternion(); + Vector3 destinationLocation = transform.origin; + + var interpolated = new Transform3D(); + Quaternion quaternion = sourceRotation.Slerp(destinationRotation, weight).Normalized(); + Vector3 scale = sourceScale.Lerp(destinationScale, weight); + interpolated.basis.SetQuaternionScale(quaternion, scale); + interpolated.origin = sourceLocation.Lerp(destinationLocation, weight); + + return interpolated; } /// <summary> @@ -140,6 +154,16 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this transform is finite, by calling + /// <see cref="Mathf.IsFinite"/> on each component. + /// </summary> + /// <returns>Whether this vector is finite or not.</returns> + public readonly bool IsFinite() + { + return basis.IsFinite() && origin.IsFinite(); + } + + /// <summary> /// Returns a copy of the transform rotated such that its /// -Z axis (forward) points towards the <paramref name="target"/> position. /// @@ -223,34 +247,6 @@ namespace Godot return new Transform3D(basis * tmpBasis, origin); } - /// <summary> - /// Returns a transform spherically interpolated between this transform and - /// another <paramref name="transform"/> by <paramref name="weight"/>. - /// </summary> - /// <param name="transform">The other transform.</param> - /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> - /// <returns>The interpolated transform.</returns> - public readonly Transform3D SphericalInterpolateWith(Transform3D transform, real_t weight) - { - /* not sure if very "efficient" but good enough? */ - - Vector3 sourceScale = basis.Scale; - Quaternion sourceRotation = basis.GetRotationQuaternion(); - Vector3 sourceLocation = origin; - - Vector3 destinationScale = transform.basis.Scale; - Quaternion destinationRotation = transform.basis.GetRotationQuaternion(); - Vector3 destinationLocation = transform.origin; - - var interpolated = new Transform3D(); - Quaternion quaternion = sourceRotation.Slerp(destinationRotation, weight).Normalized(); - Vector3 scale = sourceScale.Lerp(destinationScale, weight); - interpolated.basis.SetQuaternionScale(quaternion, scale); - interpolated.origin = sourceLocation.Lerp(destinationLocation, weight); - - return interpolated; - } - private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up) { // Make rotation matrix @@ -346,15 +342,25 @@ namespace Godot } /// <summary> - /// Constructs a transformation matrix from the given <paramref name="quaternion"/> - /// and <paramref name="origin"/> vector. + /// Constructs a transformation matrix from the given components. + /// Arguments are named such that xy is equal to calling <c>basis.x.y</c>. /// </summary> - /// <param name="quaternion">The <see cref="Quaternion"/> to create the basis from.</param> - /// <param name="origin">The origin vector, or column index 3.</param> - public Transform3D(Quaternion quaternion, Vector3 origin) + /// <param name="xx">The X component of the X column vector, accessed via <c>t.basis.x.x</c> or <c>[0][0]</c>.</param> + /// <param name="yx">The X component of the Y column vector, accessed via <c>t.basis.y.x</c> or <c>[1][0]</c>.</param> + /// <param name="zx">The X component of the Z column vector, accessed via <c>t.basis.z.x</c> or <c>[2][0]</c>.</param> + /// <param name="xy">The Y component of the X column vector, accessed via <c>t.basis.x.y</c> or <c>[0][1]</c>.</param> + /// <param name="yy">The Y component of the Y column vector, accessed via <c>t.basis.y.y</c> or <c>[1][1]</c>.</param> + /// <param name="zy">The Y component of the Z column vector, accessed via <c>t.basis.y.y</c> or <c>[2][1]</c>.</param> + /// <param name="xz">The Z component of the X column vector, accessed via <c>t.basis.x.y</c> or <c>[0][2]</c>.</param> + /// <param name="yz">The Z component of the Y column vector, accessed via <c>t.basis.y.y</c> or <c>[1][2]</c>.</param> + /// <param name="zz">The Z component of the Z column vector, accessed via <c>t.basis.y.y</c> or <c>[2][2]</c>.</param> + /// <param name="ox">The X component of the origin vector, accessed via <c>t.origin.x</c> or <c>[2][0]</c>.</param> + /// <param name="oy">The Y component of the origin vector, accessed via <c>t.origin.y</c> or <c>[2][1]</c>.</param> + /// <param name="oz">The Z component of the origin vector, accessed via <c>t.origin.z</c> or <c>[2][2]</c>.</param> + public Transform3D(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz, real_t ox, real_t oy, real_t oz) { - basis = new Basis(quaternion); - this.origin = origin; + basis = new Basis(xx, yx, zx, xy, yy, zy, xz, yz, zz); + origin = new Vector3(ox, oy, oz); } /// <summary> @@ -370,6 +376,29 @@ namespace Godot } /// <summary> + /// Constructs a transformation matrix from the given <paramref name="projection"/> + /// by trimming the last row of the projection matrix (<c>projection.x.w</c>, + /// <c>projection.y.w</c>, <c>projection.z.w</c>, and <c>projection.w.w</c> + /// are not copied over). + /// </summary> + /// <param name="projection">The <see cref="Projection"/> to create the transform from.</param> + public Transform3D(Projection projection) + { + basis = new Basis + ( + projection.x.x, projection.y.x, projection.z.x, + projection.x.y, projection.y.y, projection.z.y, + projection.x.z, projection.y.z, projection.z.z + ); + origin = new Vector3 + ( + projection.w.x, + projection.w.y, + projection.w.z + ); + } + + /// <summary> /// Composes these two transformation matrices by multiplying them /// together. This has the effect of transforming the second transform /// (the child) by the first transform (the parent). diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 4c60080ee9..57cbef1c5c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -334,6 +334,16 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this vector is finite, by calling + /// <see cref="Mathf.IsFinite"/> on each component. + /// </summary> + /// <returns>Whether this vector is finite or not.</returns> + public readonly bool IsFinite() + { + return Mathf.IsFinite(x) && Mathf.IsFinite(y); + } + + /// <summary> /// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise. /// </summary> /// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns> @@ -989,6 +999,18 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this vector's values are approximately zero, + /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component. + /// This method is faster than using <see cref="IsEqualApprox"/> with one value + /// as a zero vector. + /// </summary> + /// <returns>Whether or not the vector is approximately zero.</returns> + public readonly bool IsZeroApprox() + { + return Mathf.IsZeroApprox(x) && Mathf.IsZeroApprox(y); + } + + /// <summary> /// Serves as the hash function for <see cref="Vector2"/>. /// </summary> /// <returns>A hash code for this vector.</returns> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index fefdee33a5..031464dcc6 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -331,6 +331,16 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this vector is finite, by calling + /// <see cref="Mathf.IsFinite"/> on each component. + /// </summary> + /// <returns>Whether this vector is finite or not.</returns> + public readonly bool IsFinite() + { + return Mathf.IsFinite(x) && Mathf.IsFinite(y) && Mathf.IsFinite(z); + } + + /// <summary> /// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise. /// </summary> /// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns> @@ -1060,6 +1070,18 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this vector's values are approximately zero, + /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component. + /// This method is faster than using <see cref="IsEqualApprox"/> with one value + /// as a zero vector. + /// </summary> + /// <returns>Whether or not the vector is approximately zero.</returns> + public readonly bool IsZeroApprox() + { + return Mathf.IsZeroApprox(x) && Mathf.IsZeroApprox(y) && Mathf.IsZeroApprox(z); + } + + /// <summary> /// Serves as the hash function for <see cref="Vector3"/>. /// </summary> /// <returns>A hash code for this vector.</returns> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs index 3191e8adc0..0f4528bb40 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs @@ -280,6 +280,16 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this vector is finite, by calling + /// <see cref="Mathf.IsFinite"/> on each component. + /// </summary> + /// <returns>Whether this vector is finite or not.</returns> + public readonly bool IsFinite() + { + return Mathf.IsFinite(x) && Mathf.IsFinite(y) && Mathf.IsFinite(z) && Mathf.IsFinite(w); + } + + /// <summary> /// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise. /// </summary> /// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns> @@ -857,6 +867,18 @@ namespace Godot } /// <summary> + /// Returns <see langword="true"/> if this vector's values are approximately zero, + /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component. + /// This method is faster than using <see cref="IsEqualApprox"/> with one value + /// as a zero vector. + /// </summary> + /// <returns>Whether or not the vector is approximately zero.</returns> + public readonly bool IsZeroApprox() + { + return Mathf.IsZeroApprox(x) && Mathf.IsZeroApprox(y) && Mathf.IsZeroApprox(z) && Mathf.IsZeroApprox(w); + } + + /// <summary> /// Serves as the hash function for <see cref="Vector4"/>. /// </summary> /// <returns>A hash code for this vector.</returns> diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 6664dfb2dd..86b0e04206 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -289,7 +289,7 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime } #else static String get_assembly_name() { - String assembly_name = ProjectSettings::get_singleton()->get_setting("dotnet/project/assembly_name"); + String assembly_name = GLOBAL_GET("dotnet/project/assembly_name"); if (assembly_name.is_empty()) { assembly_name = ProjectSettings::get_singleton()->get_safe_project_name(); @@ -466,7 +466,7 @@ void GDMono::_init_godot_api_hashes() { #ifdef TOOLS_ENABLED bool GDMono::_load_project_assembly() { - String assembly_name = ProjectSettings::get_singleton()->get_setting("dotnet/project/assembly_name"); + String assembly_name = GLOBAL_GET("dotnet/project/assembly_name"); if (assembly_name.is_empty()) { assembly_name = ProjectSettings::get_singleton()->get_safe_project_name(); diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp index 4ab41cfcb0..9b071ecc02 100644 --- a/modules/multiplayer/editor/replication_editor.cpp +++ b/modules/multiplayer/editor/replication_editor.cpp @@ -142,7 +142,7 @@ void ReplicationEditor::_add_sync_property(String p_path) { return; } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add property to synchronizer")); if (config.is_null()) { @@ -357,7 +357,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); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); bool value = ti->is_checked(column); String method; if (column == 1) { @@ -397,7 +397,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); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); 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/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp index e3fe06c6f7..586b0b0697 100644 --- a/modules/openxr/editor/openxr_action_editor.cpp +++ b/modules/openxr/editor/openxr_action_editor.cpp @@ -29,7 +29,6 @@ /**************************************************************************/ #include "openxr_action_editor.h" -#include "editor/editor_node.h" void OpenXRActionEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_do_set_name", "name"), &OpenXRActionEditor::_do_set_name); @@ -125,7 +124,7 @@ void OpenXRActionEditor::_on_remove_action() { } OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) { - undo_redo = EditorNode::get_undo_redo(); + undo_redo = EditorUndoRedoManager::get_singleton(); action = p_action; set_h_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/modules/openxr/editor/openxr_action_editor.h b/modules/openxr/editor/openxr_action_editor.h index 8af5448aed..765b3ef378 100644 --- a/modules/openxr/editor/openxr_action_editor.h +++ b/modules/openxr/editor/openxr_action_editor.h @@ -43,7 +43,7 @@ class OpenXRActionEditor : public HBoxContainer { GDCLASS(OpenXRActionEditor, HBoxContainer); private: - Ref<EditorUndoRedoManager> undo_redo; + EditorUndoRedoManager *undo_redo; Ref<OpenXRAction> action; LineEdit *action_name = nullptr; diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp index 12c95f8978..ad5a515a01 100644 --- a/modules/openxr/editor/openxr_action_map_editor.cpp +++ b/modules/openxr/editor/openxr_action_map_editor.cpp @@ -387,7 +387,7 @@ void OpenXRActionMapEditor::_clear_action_map() { } OpenXRActionMapEditor::OpenXRActionMapEditor() { - undo_redo = EditorNode::get_undo_redo(); + undo_redo = EditorUndoRedoManager::get_singleton(); set_custom_minimum_size(Size2(0.0, 300.0)); top_hb = memnew(HBoxContainer); diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h index 47bfda3425..a04bae4a6e 100644 --- a/modules/openxr/editor/openxr_action_map_editor.h +++ b/modules/openxr/editor/openxr_action_map_editor.h @@ -48,7 +48,7 @@ class OpenXRActionMapEditor : public VBoxContainer { GDCLASS(OpenXRActionMapEditor, VBoxContainer); private: - Ref<EditorUndoRedoManager> undo_redo; + EditorUndoRedoManager *undo_redo; String edited_path; Ref<OpenXRActionMap> action_map; diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp index 078d83f5f2..bcb0f5f8b1 100644 --- a/modules/openxr/editor/openxr_action_set_editor.cpp +++ b/modules/openxr/editor/openxr_action_set_editor.cpp @@ -29,7 +29,6 @@ /**************************************************************************/ #include "openxr_action_set_editor.h" -#include "editor/editor_node.h" #include "openxr_action_editor.h" void OpenXRActionSetEditor::_bind_methods() { @@ -212,7 +211,7 @@ void OpenXRActionSetEditor::set_focus_on_entry() { } OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set) { - undo_redo = EditorNode::get_undo_redo(); + undo_redo = EditorUndoRedoManager::get_singleton(); action_map = p_action_map; action_set = p_action_set; diff --git a/modules/openxr/editor/openxr_action_set_editor.h b/modules/openxr/editor/openxr_action_set_editor.h index 6040f7fb4e..129f800abe 100644 --- a/modules/openxr/editor/openxr_action_set_editor.h +++ b/modules/openxr/editor/openxr_action_set_editor.h @@ -44,7 +44,7 @@ class OpenXRActionSetEditor : public HBoxContainer { GDCLASS(OpenXRActionSetEditor, HBoxContainer); private: - Ref<EditorUndoRedoManager> undo_redo; + EditorUndoRedoManager *undo_redo; Ref<OpenXRActionMap> action_map; Ref<OpenXRActionSet> action_set; diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp index 76b0ae5a3c..6a848dd430 100644 --- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp +++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp @@ -29,7 +29,6 @@ /**************************************************************************/ #include "openxr_interaction_profile_editor.h" -#include "editor/editor_node.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" #include "scene/gui/label.h" @@ -141,7 +140,7 @@ void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Ref<Open } OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) { - undo_redo = EditorNode::get_undo_redo(); + undo_redo = EditorUndoRedoManager::get_singleton(); action_map = p_action_map; interaction_profile = p_interaction_profile; diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.h b/modules/openxr/editor/openxr_interaction_profile_editor.h index 73dba71cbd..fa25a000a9 100644 --- a/modules/openxr/editor/openxr_interaction_profile_editor.h +++ b/modules/openxr/editor/openxr_interaction_profile_editor.h @@ -43,7 +43,7 @@ class OpenXRInteractionProfileEditorBase : public ScrollContainer { GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer); protected: - Ref<EditorUndoRedoManager> undo_redo; + EditorUndoRedoManager *undo_redo; Ref<OpenXRInteractionProfile> interaction_profile; Ref<OpenXRActionMap> action_map; diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub index 37c8a95905..209ebab388 100644 --- a/modules/raycast/SCsub +++ b/modules/raycast/SCsub @@ -96,7 +96,7 @@ if env["builtin_embree"]: if not env.msvc: # Flags synced with upstream gnu.cmake. - if env["arch"] == "arm64" and env["platform"] == "linuxbsd": + if env["arch"] == "arm64" and env["platform"] == "linuxbsd" and not env["use_llvm"]: env_thirdparty.Append(CXXFLAGS=["-flax-vector-conversions"]) env_thirdparty.Append( diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 44a2c76727..e52b87741e 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -42,7 +42,7 @@ using namespace godot; -#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var) +#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var) #else // Headers for building as built-in module. diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 809bfbe41a..034f88e387 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -42,7 +42,7 @@ using namespace godot; -#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var) +#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var) #else // Headers for building as built-in module. diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml index f5964eb4d1..ba1750386f 100644 --- a/modules/webxr/doc_classes/WebXRInterface.xml +++ b/modules/webxr/doc_classes/WebXRInterface.xml @@ -18,7 +18,7 @@ func _ready(): # We assume this node has a button as a child. # This button is for the user to consent to entering immersive VR mode. - $Button.pressed.connect(self._on_Button_pressed) + $Button.pressed.connect(self._on_button_pressed) webxr_interface = XRServer.find_interface("WebXR") if webxr_interface: @@ -38,7 +38,7 @@ if session_mode == 'immersive-vr': vr_supported = supported - func _on_Button_pressed(): + func _on_button_pressed(): if not vr_supported: OS.alert("Your browser doesn't support VR") return diff --git a/platform/android/README.md b/platform/android/README.md index f6aabab708..01eb9c03a6 100644 --- a/platform/android/README.md +++ b/platform/android/README.md @@ -5,7 +5,7 @@ using [Gradle](https://gradle.org/) as a build system. ## Documentation -- [Compiling for Android](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_android.html) +- [Compiling for Android](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_android.html) - Instructions on building this platform port from source. - [Exporting for Android](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_android.html) - Instructions on using the compiled export templates to export a project. diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index a602cc7926..bb1ad3d83b 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -43,10 +43,16 @@ #include "editor/editor_log.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" +#include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "main/splash.gen.h" -#include "platform/android/logo.gen.h" -#include "platform/android/run_icon.gen.h" +#include "platform/android/logo_svg.gen.h" +#include "platform/android/run_icon_svg.gen.h" + +#include "modules/modules_enabled.gen.h" // For svg. +#ifdef MODULE_SVG_ENABLED +#include "modules/svg/image_loader_svg.h" +#endif #include <string.h> @@ -3238,8 +3244,17 @@ void EditorExportPlatformAndroid::resolve_platform_feature_priorities(const Ref< } EditorExportPlatformAndroid::EditorExportPlatformAndroid() { - logo = ImageTexture::create_from_image(memnew(Image(_android_logo))); - run_icon = ImageTexture::create_from_image(memnew(Image(_android_run_icon))); +#ifdef MODULE_SVG_ENABLED + Ref<Image> img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _android_logo_svg, EDSCALE, upsample, false); + logo = ImageTexture::create_from_image(img); + + img_loader.create_image_from_string(img, _android_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); +#endif devices_changed.set(); plugins_changed.set(); diff --git a/platform/android/logo.png b/platform/android/logo.png Binary files differdeleted file mode 100644 index 9c8be93646..0000000000 --- a/platform/android/logo.png +++ /dev/null diff --git a/platform/android/logo.svg b/platform/android/logo.svg new file mode 100644 index 0000000000..f154e55d11 --- /dev/null +++ b/platform/android/logo.svg @@ -0,0 +1 @@ +<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M22.904 20.192a1.25 1.25 0 1 1 1.25-1.25 1.25 1.25 0 0 1-1.25 1.25m-13.808 0a1.25 1.25 0 1 1 1.25-1.25 1.25 1.25 0 0 1-1.25 1.25m14.256-7.525 2.496-4.323a.52.52 0 1 0-.899-.52l-2.528 4.378a15.69 15.69 0 0 0-12.842 0L7.051 7.823a.52.52 0 1 0-.9.521l2.497 4.323C4.361 15 1.43 19.34 1 24.467h30c-.43-5.128-3.361-9.468-7.648-11.8" fill="#56d881"/></svg> diff --git a/platform/android/run_icon.png b/platform/android/run_icon.png Binary files differdeleted file mode 100644 index b687c9ac31..0000000000 --- a/platform/android/run_icon.png +++ /dev/null diff --git a/platform/android/run_icon.svg b/platform/android/run_icon.svg new file mode 100644 index 0000000000..24d930fece --- /dev/null +++ b/platform/android/run_icon.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M11.187 9.936a.577.577 0 1 1 .578-.578.577.577 0 0 1-.578.578m-6.374 0a.577.577 0 1 1 .577-.578.577.577 0 0 1-.577.578m6.581-3.475 1.153-1.996a.24.24 0 1 0-.415-.24l-1.167 2.021a7.244 7.244 0 0 0-5.93 0L3.868 4.225a.24.24 0 1 0-.415.24l1.153 1.996a6.806 6.806 0 0 0-3.532 5.448h13.852a6.807 6.807 0 0 0-3.532-5.448" fill="#56d881" style="fill:#e0e0e0;fill-opacity:1"/></svg> diff --git a/platform/ios/README.md b/platform/ios/README.md index 82c275ad31..0e1d6802cb 100644 --- a/platform/ios/README.md +++ b/platform/ios/README.md @@ -8,7 +8,7 @@ project template used for packaging the iOS export templates. ## Documentation -- [Compiling for iOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_ios.html) +- [Compiling for iOS](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_ios.html) - Instructions on building this platform port from source. - [Exporting for iOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_ios.html) - Instructions on using the compiled export templates to export a project. diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 43eb0f4b1f..ccd3480d11 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -32,6 +32,13 @@ #include "core/string/translation.h" #include "editor/editor_node.h" +#include "editor/editor_scale.h" +#include "platform/ios/logo_svg.gen.h" + +#include "modules/modules_enabled.gen.h" // For svg. +#ifdef MODULE_SVG_ENABLED +#include "modules/svg/image_loader_svg.h" +#endif void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { // Vulkan and OpenGL ES 3.0 both mandate ETC2 support. @@ -1926,7 +1933,15 @@ bool EditorExportPlatformIOS::has_valid_project_configuration(const Ref<EditorEx } EditorExportPlatformIOS::EditorExportPlatformIOS() { - logo = ImageTexture::create_from_image(memnew(Image(_ios_logo))); +#ifdef MODULE_SVG_ENABLED + Ref<Image> img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _ios_logo_svg, EDSCALE, upsample, false); + logo = ImageTexture::create_from_image(img); +#endif + plugins_changed.set(); #ifndef ANDROID_ENABLED check_for_changes_thread.start(_check_for_changes_poll_thread, this); diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h index deadec4b43..628dae2e6f 100644 --- a/platform/ios/export/export_plugin.h +++ b/platform/ios/export/export_plugin.h @@ -43,7 +43,6 @@ #include "editor/editor_settings.h" #include "editor/export/editor_export_platform.h" #include "main/splash.gen.h" -#include "platform/ios/logo.gen.h" #include "string.h" #include "godot_plugin_config.h" diff --git a/platform/ios/logo.png b/platform/ios/logo.png Binary files differdeleted file mode 100644 index 966d8aa70a..0000000000 --- a/platform/ios/logo.png +++ /dev/null diff --git a/platform/ios/logo.svg b/platform/ios/logo.svg new file mode 100644 index 0000000000..47a72bcf49 --- /dev/null +++ b/platform/ios/logo.svg @@ -0,0 +1 @@ +<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M1 23.27h2.504V12.61H1zm1.247-12.057c.784 0 1.398-.603 1.398-1.358 0-.764-.614-1.367-1.398-1.367-.774 0-1.388.603-1.388 1.367 0 .755.614 1.358 1.388 1.358zm9.594-2.695c-4.233 0-6.888 2.886-6.888 7.502s2.654 7.492 6.888 7.492c4.224 0 6.88-2.876 6.88-7.492s-2.656-7.502-6.88-7.502zm0 2.212c2.585 0 4.234 2.052 4.234 5.29 0 3.228-1.649 5.28-4.234 5.28-2.594 0-4.233-2.052-4.233-5.28 0-3.238 1.639-5.29 4.233-5.29zm7.936 8.458c.11 2.675 2.303 4.324 5.641 4.324 3.51 0 5.723-1.73 5.723-4.485 0-2.162-1.247-3.379-4.194-4.053l-1.67-.382c-1.78-.422-2.513-.985-2.513-1.95 0-1.208 1.106-2.012 2.745-2.012 1.66 0 2.796.814 2.916 2.172H30.9c-.06-2.554-2.172-4.284-5.37-4.284-3.158 0-5.4 1.74-5.4 4.314 0 2.072 1.267 3.36 3.942 3.973l1.88.442c1.83.433 2.575 1.036 2.575 2.082 0 1.207-1.217 2.072-2.967 2.072-1.77 0-3.107-.875-3.268-2.213h-2.514z" fill="#bfbfbf"/></svg> diff --git a/platform/linuxbsd/README.md b/platform/linuxbsd/README.md index efa8682062..c4f287cc6c 100644 --- a/platform/linuxbsd/README.md +++ b/platform/linuxbsd/README.md @@ -7,7 +7,7 @@ used by this platform. ## Documentation -- [Compiling for Linux/*BSD](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_linuxbsd.html) +- [Compiling for Linux/*BSD](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_linuxbsd.html) - Instructions on building this platform port from source. - [Exporting for Linux/*BSD](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_linux.html) - Instructions on using the compiled export templates to export a project. diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp index add69c436f..8d03e3d31c 100644 --- a/platform/linuxbsd/crash_handler_linuxbsd.cpp +++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp @@ -44,6 +44,7 @@ #include <cxxabi.h> #include <dlfcn.h> #include <execinfo.h> +#include <link.h> #include <signal.h> #include <stdlib.h> @@ -79,7 +80,27 @@ static void handle_crash(int sig) { } print_error(vformat("Dumping the backtrace. %s", msg)); char **strings = backtrace_symbols(bt_buffer, size); + // PIE executable relocation, zero for non-PIE executables + uintptr_t relocation = _r_debug.r_map->l_addr; if (strings) { + List<String> args; + for (size_t i = 0; i < size; i++) { + char str[1024]; + snprintf(str, 1024, "%p", (void *)((uintptr_t)bt_buffer[i] - relocation)); + args.push_back(str); + } + args.push_back("-e"); + args.push_back(_execpath); + + // Try to get the file/line number using addr2line + int ret; + String output = ""; + Error err = OS::get_singleton()->execute(String("addr2line"), args, &output, &ret); + Vector<String> addr2line_results; + if (err == OK) { + addr2line_results = output.substr(0, output.length() - 1).split("\n", false); + } + for (size_t i = 1; i < size; i++) { char fname[1024]; Dl_info info; @@ -102,24 +123,7 @@ static void handle_crash(int sig) { } } - List<String> args; - - char str[1024]; - snprintf(str, 1024, "%p", bt_buffer[i]); - args.push_back(str); - args.push_back("-e"); - args.push_back(_execpath); - - String output = ""; - - // Try to get the file/line number using addr2line - int ret; - Error err = OS::get_singleton()->execute(String("addr2line"), args, &output, &ret); - if (err == OK) { - output = output.substr(0, output.length() - 1); - } - - print_error(vformat("[%d] %s (%s)", (int64_t)i, fname, output)); + print_error(vformat("[%d] %s (%s)", (int64_t)i, fname, err == OK ? addr2line_results[i] : "")); } free(strings); diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index e6925a2011..2c5a945b6c 100644 --- a/platform/linuxbsd/export/export.cpp +++ b/platform/linuxbsd/export/export.cpp @@ -36,7 +36,6 @@ void register_linuxbsd_exporter() { Ref<EditorExportPlatformLinuxBSD> platform; platform.instantiate(); - platform->set_logo(ImageTexture::create_from_image(memnew(Image(_linuxbsd_logo)))); platform->set_name("Linux/X11"); platform->set_os_name("Linux"); platform->set_chmod_flags(0755); diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp index f6e59bf465..c900cad007 100644 --- a/platform/linuxbsd/export/export_plugin.cpp +++ b/platform/linuxbsd/export/export_plugin.cpp @@ -32,6 +32,15 @@ #include "core/config/project_settings.h" #include "editor/editor_node.h" +#include "editor/editor_paths.h" +#include "editor/editor_scale.h" +#include "platform/linuxbsd/logo_svg.gen.h" +#include "platform/linuxbsd/run_icon_svg.gen.h" + +#include "modules/modules_enabled.gen.h" // For svg. +#ifdef MODULE_SVG_ENABLED +#include "modules/svg/image_loader_svg.h" +#endif Error EditorExportPlatformLinuxBSD::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) { Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); @@ -49,26 +58,47 @@ Error EditorExportPlatformLinuxBSD::_export_debug_script(const Ref<EditorExportP } Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { - Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, p_path, p_flags); - - if (err != OK) { - return err; - } + bool export_as_zip = p_path.ends_with("zip"); - String app_name; + String pkg_name; if (String(GLOBAL_GET("application/config/name")) != "") { - app_name = String(GLOBAL_GET("application/config/name")); + pkg_name = String(GLOBAL_GET("application/config/name")); } else { - app_name = "Unnamed"; + pkg_name = "Unnamed"; + } + + pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name); + + // Setup temp folder. + String path = p_path; + String tmp_dir_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name); + + Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path); + if (export_as_zip) { + if (tmp_app_dir.is_null()) { + return ERR_CANT_CREATE; + } + if (DirAccess::exists(tmp_dir_path)) { + if (tmp_app_dir->change_dir(tmp_dir_path) == OK) { + tmp_app_dir->erase_contents_recursive(); + } + } + tmp_app_dir->make_dir_recursive(tmp_dir_path); + path = tmp_dir_path.path_join(p_path.get_file().get_basename()); + } + + // Export project. + Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, path, p_flags); + if (err != OK) { + return err; } - app_name = OS::get_singleton()->get_safe_dir_name(app_name); // Save console script. if (err == OK) { int con_scr = p_preset->get("debug/export_console_script"); if ((con_scr == 1 && p_debug) || (con_scr == 2)) { - String scr_path = p_path.get_basename() + ".sh"; - err = _export_debug_script(p_preset, app_name, p_path.get_file(), scr_path); + String scr_path = path.get_basename() + ".sh"; + err = _export_debug_script(p_preset, pkg_name, path.get_file(), scr_path); FileAccess::set_unix_permissions(scr_path, 0755); if (err != OK) { add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), TTR("Could not create console script.")); @@ -76,6 +106,27 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset> } } + // ZIP project. + if (export_as_zip) { + if (FileAccess::exists(p_path)) { + OS::get_singleton()->move_to_trash(p_path); + } + + Ref<FileAccess> io_fa_dst; + zlib_filefunc_def io_dst = zipio_create_io(&io_fa_dst); + zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst); + + zip_folder_recursive(zip, tmp_dir_path, "", pkg_name); + + zipClose(zip, nullptr); + + if (tmp_app_dir->change_dir(tmp_dir_path) == OK) { + tmp_app_dir->erase_contents_recursive(); + tmp_app_dir->change_dir(".."); + tmp_app_dir->remove(pkg_name); + } + } + return err; } @@ -86,12 +137,51 @@ String EditorExportPlatformLinuxBSD::get_template_file_name(const String &p_targ List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const { List<String> list; list.push_back(p_preset->get("binary_format/architecture")); + list.push_back("zip"); + return list; } void EditorExportPlatformLinuxBSD::get_export_options(List<ExportOption> *r_options) { EditorExportPlatformPC::get_export_options(r_options); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64,arm32,rv64,ppc64,ppc32"), "x86_64")); + + String run_script = "#!/usr/bin/env bash\n" + "export DISPLAY=:0\n" + "unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"\n" + "\"{temp_dir}/{exe_name}\" {cmd_args}"; + + String cleanup_script = "#!/usr/bin/env bash\n" + "kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")\n" + "rm -rf \"{temp_dir}\""; + + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22")); + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script)); +} + +bool EditorExportPlatformLinuxBSD::is_elf(const String &p_path) const { + Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("Can't open file: \"%s\".", p_path)); + uint32_t magic = fb->get_32(); + return (magic == 0x464c457f); +} + +bool EditorExportPlatformLinuxBSD::is_shebang(const String &p_path) const { + Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("Can't open file: \"%s\".", p_path)); + uint16_t magic = fb->get_16(); + return (magic == 0x2123); +} + +bool EditorExportPlatformLinuxBSD::is_executable(const String &p_path) const { + return is_elf(p_path) || is_shebang(p_path); } Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) { @@ -200,3 +290,235 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int } return OK; } + +Ref<Texture2D> EditorExportPlatformLinuxBSD::get_run_icon() const { + return run_icon; +} + +bool EditorExportPlatformLinuxBSD::poll_export() { + Ref<EditorExportPreset> preset; + + for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { + Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i); + if (ep->is_runnable() && ep->get_platform() == this) { + preset = ep; + break; + } + } + + int prev = menu_options; + menu_options = (preset.is_valid() && preset->get("ssh_remote_deploy/enabled").operator bool()); + if (ssh_pid != 0 || !cleanup_commands.is_empty()) { + if (menu_options == 0) { + cleanup(); + } else { + menu_options += 1; + } + } + return menu_options != prev; +} + +Ref<ImageTexture> EditorExportPlatformLinuxBSD::get_option_icon(int p_index) const { + return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index); +} + +int EditorExportPlatformLinuxBSD::get_options_count() const { + return menu_options; +} + +String EditorExportPlatformLinuxBSD::get_option_label(int p_index) const { + return (p_index) ? TTR("Stop and uninstall") : TTR("Run on remote Linux/BSD system"); +} + +String EditorExportPlatformLinuxBSD::get_option_tooltip(int p_index) const { + return (p_index) ? TTR("Stop and uninstall running project from the remote system") : TTR("Run exported project on remote Linux/BSD system"); +} + +void EditorExportPlatformLinuxBSD::cleanup() { + if (ssh_pid != 0 && OS::get_singleton()->is_process_running(ssh_pid)) { + print_line("Terminating connection..."); + OS::get_singleton()->kill(ssh_pid); + OS::get_singleton()->delay_usec(1000); + } + + if (!cleanup_commands.is_empty()) { + print_line("Stopping and deleting previous version..."); + for (const SSHCleanupCommand &cmd : cleanup_commands) { + if (cmd.wait) { + ssh_run_on_remote(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args); + } else { + ssh_run_on_remote_no_wait(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args); + } + } + } + ssh_pid = 0; + cleanup_commands.clear(); +} + +Error EditorExportPlatformLinuxBSD::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) { + cleanup(); + if (p_device) { // Stop command, cleanup only. + return OK; + } + + EditorProgress ep("run", TTR("Running..."), 5); + + const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("linuxbsd"); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (!da->dir_exists(dest)) { + Error err = da->make_dir_recursive(dest); + if (err != OK) { + EditorNode::get_singleton()->show_warning(TTR("Could not create temp directory:") + "\n" + dest); + return err; + } + } + + String host = p_preset->get("ssh_remote_deploy/host").operator String(); + String port = p_preset->get("ssh_remote_deploy/port").operator String(); + if (port.is_empty()) { + port = "22"; + } + Vector<String> extra_args_ssh = p_preset->get("ssh_remote_deploy/extra_args_ssh").operator String().split(" "); + Vector<String> extra_args_scp = p_preset->get("ssh_remote_deploy/extra_args_scp").operator String().split(" "); + + const String basepath = dest.path_join("tmp_linuxbsd_export"); + +#define CLEANUP_AND_RETURN(m_err) \ + { \ + if (da->file_exists(basepath + ".zip")) { \ + da->remove(basepath + ".zip"); \ + } \ + if (da->file_exists(basepath + "_start.sh")) { \ + da->remove(basepath + "_start.sh"); \ + } \ + if (da->file_exists(basepath + "_clean.sh")) { \ + da->remove(basepath + "_clean.sh"); \ + } \ + return m_err; \ + } \ + ((void)0) + + if (ep.step(TTR("Exporting project..."), 1)) { + return ERR_SKIP; + } + Error err = export_project(p_preset, true, basepath + ".zip", p_debug_flags); + if (err != OK) { + DirAccess::remove_file_or_error(basepath + ".zip"); + return err; + } + + String cmd_args; + { + Vector<String> cmd_args_list; + gen_debug_flags(cmd_args_list, p_debug_flags); + for (int i = 0; i < cmd_args_list.size(); i++) { + if (i != 0) { + cmd_args += " "; + } + cmd_args += cmd_args_list[i]; + } + } + + const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT); + int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port"); + + print_line("Creating temporary directory..."); + ep.step(TTR("Creating temporary directory..."), 2); + String temp_dir; + err = ssh_run_on_remote(host, port, extra_args_ssh, "mktemp -d", &temp_dir); + if (err != OK || temp_dir.is_empty()) { + CLEANUP_AND_RETURN(err); + } + + print_line("Uploading archive..."); + ep.step(TTR("Uploading archive..."), 3); + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + ".zip", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + + { + String run_script = p_preset->get("ssh_remote_deploy/run_script"); + run_script = run_script.replace("{temp_dir}", temp_dir); + run_script = run_script.replace("{archive_name}", basepath.get_file() + ".zip"); + run_script = run_script.replace("{exe_name}", basepath.get_file()); + run_script = run_script.replace("{cmd_args}", cmd_args); + + Ref<FileAccess> f = FileAccess::open(basepath + "_start.sh", FileAccess::WRITE); + if (f.is_null()) { + CLEANUP_AND_RETURN(err); + } + + f->store_string(run_script); + } + + { + String clean_script = p_preset->get("ssh_remote_deploy/cleanup_script"); + clean_script = clean_script.replace("{temp_dir}", temp_dir); + clean_script = clean_script.replace("{archive_name}", basepath.get_file() + ".zip"); + clean_script = clean_script.replace("{exe_name}", basepath.get_file()); + clean_script = clean_script.replace("{cmd_args}", cmd_args); + + Ref<FileAccess> f = FileAccess::open(basepath + "_clean.sh", FileAccess::WRITE); + if (f.is_null()) { + CLEANUP_AND_RETURN(err); + } + + f->store_string(clean_script); + } + + print_line("Uploading scripts..."); + ep.step(TTR("Uploading scripts..."), 4); + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_start.sh", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + err = ssh_run_on_remote(host, port, extra_args_ssh, vformat("chmod +x \"%s/%s\"", temp_dir, basepath.get_file() + "_start.sh")); + if (err != OK || temp_dir.is_empty()) { + CLEANUP_AND_RETURN(err); + } + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_clean.sh", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + err = ssh_run_on_remote(host, port, extra_args_ssh, vformat("chmod +x \"%s/%s\"", temp_dir, basepath.get_file() + "_clean.sh")); + if (err != OK || temp_dir.is_empty()) { + CLEANUP_AND_RETURN(err); + } + + print_line("Starting project..."); + ep.step(TTR("Starting project..."), 5); + err = ssh_run_on_remote_no_wait(host, port, extra_args_ssh, vformat("\"%s/%s\"", temp_dir, basepath.get_file() + "_start.sh"), &ssh_pid, (use_remote) ? dbg_port : -1); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + + cleanup_commands.clear(); + cleanup_commands.push_back(SSHCleanupCommand(host, port, extra_args_ssh, vformat("\"%s/%s\"", temp_dir, basepath.get_file() + "_clean.sh"))); + + print_line("Project started."); + + CLEANUP_AND_RETURN(OK); +#undef CLEANUP_AND_RETURN +} + +EditorExportPlatformLinuxBSD::EditorExportPlatformLinuxBSD() { +#ifdef MODULE_SVG_ENABLED + Ref<Image> img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false); + set_logo(ImageTexture::create_from_image(img)); + + img_loader.create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); +#endif + + Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); + if (theme.is_valid()) { + stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); + } else { + stop_icon.instantiate(); + } +} diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h index 71cf18ff3e..4f860c3fd0 100644 --- a/platform/linuxbsd/export/export_plugin.h +++ b/platform/linuxbsd/export/export_plugin.h @@ -34,19 +34,58 @@ #include "core/io/file_access.h" #include "editor/editor_settings.h" #include "editor/export/editor_export_platform_pc.h" -#include "platform/linuxbsd/logo.gen.h" #include "scene/resources/texture.h" class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC { + HashMap<String, String> extensions; + + struct SSHCleanupCommand { + String host; + String port; + Vector<String> ssh_args; + String cmd_args; + bool wait = false; + + SSHCleanupCommand(){}; + SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) { + host = p_host; + port = p_port; + ssh_args = p_ssh_arg; + cmd_args = p_cmd_args; + wait = p_wait; + }; + }; + + Ref<ImageTexture> run_icon; + Ref<ImageTexture> stop_icon; + + Vector<SSHCleanupCommand> cleanup_commands; + OS::ProcessID ssh_pid = 0; + int menu_options = 0; + + bool is_elf(const String &p_path) const; + bool is_shebang(const String &p_path) const; + Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); public: - void set_extension(const String &p_extension, const String &p_feature_key = "default"); - virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; virtual void get_export_options(List<ExportOption> *r_options) override; + virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; virtual String get_template_file_name(const String &p_target, const String &p_arch) const override; virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override; + virtual bool is_executable(const String &p_path) const override; + + virtual Ref<Texture2D> get_run_icon() const override; + virtual bool poll_export() override; + virtual Ref<ImageTexture> get_option_icon(int p_index) const override; + virtual int get_options_count() const override; + virtual String get_option_label(int p_index) const override; + virtual String get_option_tooltip(int p_index) const override; + virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override; + virtual void cleanup() override; + + EditorExportPlatformLinuxBSD(); }; #endif // LINUXBSD_EXPORT_PLUGIN_H diff --git a/platform/linuxbsd/logo.png b/platform/linuxbsd/logo.png Binary files differdeleted file mode 100644 index 078654b757..0000000000 --- a/platform/linuxbsd/logo.png +++ /dev/null diff --git a/platform/linuxbsd/logo.svg b/platform/linuxbsd/logo.svg new file mode 100644 index 0000000000..e5f9f03e0c --- /dev/null +++ b/platform/linuxbsd/logo.svg @@ -0,0 +1 @@ +<svg height="32" width="32"><path d="M13 31h6s3 0 6-6c2.864-5.727-6-17-6-17h-6S3.775 18.55 7 25c3 6 6 6 6 6z" fill="#fff"/><path d="M15.876 28.636c-.05.322-.116.637-.204.941-.142.496-.35.993-.659 1.416.32.02.649.023.985.007a9.1 9.1 0 0 0 .985-.007c-.309-.423-.516-.92-.659-1.416a7.666 7.666 0 0 1-.203-.94l-.123.003c-.04 0-.081-.003-.122-.004z" fill="#333"/><path d="M21.693 21.916c-.629.01-.934.633-1.497.7-.694.08-1.128-.722-2.11-.123-.98.6-1.826 7.473.45 8.409 2.274.935 6.506-4.545 6.23-5.662-.275-1.116-1.146-.853-1.582-1.399-.436-.545.003-1.41-.995-1.82a1.246 1.246 0 0 0-.496-.105zm-11.461 0a1.315 1.315 0 0 0-.421.105c-.998.41-.56 1.275-.995 1.82-.436.546-1.31.283-1.586 1.4-.275 1.116 3.956 6.596 6.232 5.66 2.275-.935 1.429-7.808.448-8.408-.981-.6-1.415.204-2.11.122-.584-.068-.888-.739-1.568-.7z" fill="#f4bb37"/><path d="M15.998.99c-2.934 0-4.657 1.79-4.982 4.204-.324 2.414.198 2.856-.614 5.328-.813 2.472-4.456 6.71-4.37 10.62.026 1.217.166 2.27.41 3.192.3-.496.743-.846 1.066-.995.253-.117.375-.173.432-.194.008-.062.04-.205.098-.485.08-.386.387-.99.91-1.386-.005-.12-.01-.239-.013-.363-.06-3.033 3.073-6.318 3.65-8.236.577-1.917.326-2.114.421-2.59.096-.477.463-1.032.992-1.475a.23.23 0 0 1 .15-.06c.482-.005.965 1.75 1.898 1.752.933 0 1.419-2.141 1.956-1.692.529.443.896.998.992 1.474.095.477-.156.674.42 2.591.578 1.918 3.708 5.203 3.648 8.236-.003.123-.008.24-.014.36.526.396.834 1.002.914 1.389.058.28.09.423.098.485.057.021.18.08.432.197.323.15.764.499 1.063.995.244-.922.387-1.976.414-3.195.085-3.91-3.562-8.148-4.374-10.62-.813-2.472-.287-2.914-.611-5.328C20.659 2.78 18.933.99 15.998.99z" fill="#333"/></svg> diff --git a/platform/linuxbsd/run_icon.svg b/platform/linuxbsd/run_icon.svg new file mode 100644 index 0000000000..56465a0df3 --- /dev/null +++ b/platform/linuxbsd/run_icon.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M7.941 13.966a3.62 3.62 0 0 1-.096.444 2.129 2.129 0 0 1-.31.668c.15.01.305.01.464.003.16.008.314.007.465-.003a2.129 2.129 0 0 1-.31-.668 3.62 3.62 0 0 1-.097-.444l-.058.001-.058-.001z" fill="#333" style="stroke-width:.472092;fill:#e0e0e0;fill-opacity:1"/><path d="M10.688 10.793c-.297.005-.441.299-.707.33-.328.038-.533-.34-.996-.058-.463.283-.862 3.528.212 3.97 1.074.442 3.072-2.146 2.942-2.673-.13-.527-.542-.403-.747-.66-.206-.258 0-.666-.47-.86a.588.588 0 0 0-.234-.05zm-5.411 0a.62.62 0 0 0-.199.05c-.47.193-.264.601-.47.859-.205.257-.618.133-.748.66s1.867 3.115 2.942 2.673c1.074-.442.674-3.687.211-3.97-.463-.283-.668.096-.995.058-.277-.032-.42-.349-.741-.33z" fill="#f4bb37" style="stroke-width:.472092;fill:#e0e0e0;fill-opacity:1"/><path d="M8 .914c-1.386 0-2.2.845-2.353 1.985-.153 1.14.094 1.348-.29 2.515s-2.103 3.168-2.063 5.013c.012.575.078 1.072.194 1.507a1.25 1.25 0 0 1 .503-.47 4.37 4.37 0 0 1 .204-.09c.004-.03.019-.098.046-.23.038-.182.183-.467.43-.654a4.773 4.773 0 0 1-.006-.172c-.029-1.431 1.45-2.982 1.723-3.888.272-.905.154-.998.199-1.223.045-.225.218-.487.468-.696a.11.11 0 0 1 .07-.028c.228-.003.456.826.897.827.44 0 .67-1.01.923-.799.25.21.423.471.468.696.045.225-.073.318.199 1.223.272.906 1.75 2.457 1.722 3.888-.001.058-.004.114-.007.17a1.2 1.2 0 0 1 .432.656c.027.132.042.2.046.23.027.01.085.037.204.092.153.07.36.236.502.47.115-.435.183-.933.195-1.509.04-1.845-1.681-3.846-2.065-5.013-.383-1.167-.135-1.376-.288-2.515C10.2 1.759 9.385.914 7.999.914Z" fill="#333" style="stroke-width:.472092;fill:#e0e0e0;fill-opacity:1"/></svg> diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 10fd9972e3..a2c34bb874 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -1420,13 +1420,22 @@ void DisplayServerX11::window_set_mouse_passthrough(const Vector<Vector2> &p_reg _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); - const WindowData &wd = windows[p_window]; + windows[p_window].mpath = p_region; + _update_window_mouse_passthrough(p_window); +} + +void DisplayServerX11::_update_window_mouse_passthrough(WindowID p_window) { + ERR_FAIL_COND(!windows.has(p_window)); + + const Vector<Vector2> region_path = windows[p_window].mpath; int event_base, error_base; const Bool ext_okay = XShapeQueryExtension(x11_display, &event_base, &error_base); if (ext_okay) { Region region; - if (p_region.size() == 0) { + if (windows[p_window].mpass) { + region = XCreateRegion(); + } else if (region_path.size() == 0) { region = XCreateRegion(); XRectangle rect; rect.x = 0; @@ -1435,15 +1444,15 @@ void DisplayServerX11::window_set_mouse_passthrough(const Vector<Vector2> &p_reg rect.height = window_get_size_with_decorations(p_window).y; XUnionRectWithRegion(&rect, region, region); } else { - XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * p_region.size()); - for (int i = 0; i < p_region.size(); i++) { - points[i].x = p_region[i].x; - points[i].y = p_region[i].y; + XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * region_path.size()); + for (int i = 0; i < region_path.size(); i++) { + points[i].x = region_path[i].x; + points[i].y = region_path[i].y; } - region = XPolygonRegion(points, p_region.size(), EvenOddRule); + region = XPolygonRegion(points, region_path.size(), EvenOddRule); memfree(points); } - XShapeCombineRegion(x11_display, wd.x11_window, ShapeInput, 0, 0, region, ShapeSet); + XShapeCombineRegion(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, region, ShapeSet); XDestroyRegion(region); } } @@ -2312,6 +2321,7 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo window_set_size(window_get_size(p_window), p_window); wd.borderless = p_enabled; + _update_window_mouse_passthrough(p_window); } break; case WINDOW_FLAG_ALWAYS_ON_TOP: { ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID, "Can't make a window transient if the 'on top' flag is active."); @@ -2345,6 +2355,10 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo case WINDOW_FLAG_NO_FOCUS: { wd.no_focus = p_enabled; } break; + case WINDOW_FLAG_MOUSE_PASSTHROUGH: { + wd.mpass = p_enabled; + _update_window_mouse_passthrough(p_window); + } break; case WINDOW_FLAG_POPUP: { XWindowAttributes xwa; XSync(x11_display, False); @@ -2398,6 +2412,9 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co case WINDOW_FLAG_NO_FOCUS: { return wd.no_focus; } break; + case WINDOW_FLAG_MOUSE_PASSTHROUGH: { + return wd.mpass; + } break; case WINDOW_FLAG_POPUP: { return wd.is_popup; } break; diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index 43a66f95b2..437766d953 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -149,6 +149,8 @@ class DisplayServerX11 : public DisplayServer { Callable input_text_callback; Callable drop_files_callback; + Vector<Vector2> mpath; + WindowID transient_parent = INVALID_WINDOW_ID; HashSet<WindowID> transient_children; @@ -169,6 +171,7 @@ class DisplayServerX11 : public DisplayServer { bool maximized = false; bool is_popup = false; bool layered_window = false; + bool mpass = false; Rect2i parent_safe_rect; @@ -245,6 +248,7 @@ class DisplayServerX11 : public DisplayServer { Atom _process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property, Atom p_selection) const; void _handle_selection_request_event(XSelectionRequestEvent *p_event) const; + void _update_window_mouse_passthrough(WindowID p_window); String _clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const; String _clipboard_get(Atom p_source, Window x11_window) const; diff --git a/platform/macos/README.md b/platform/macos/README.md index feead80736..205c59e05d 100644 --- a/platform/macos/README.md +++ b/platform/macos/README.md @@ -11,7 +11,7 @@ packaging macOS export templates. ## Documentation -- [Compiling for macOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_macos.html) +- [Compiling for macOS](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_macos.html) - Instructions on building this platform port from source. - [Exporting for macOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_macos.html) - Instructions on using the compiled export templates to export a project. diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index 7f57644a4c..4873db4b64 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -114,6 +114,7 @@ public: bool resize_disabled = false; bool no_focus = false; bool is_popup = false; + bool mpass = false; Rect2i parent_safe_rect; }; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 865b8d9711..63280c7887 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -2974,6 +2974,9 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win case WINDOW_FLAG_NO_FOCUS: { wd.no_focus = p_enabled; } break; + case WINDOW_FLAG_MOUSE_PASSTHROUGH: { + wd.mpass = p_enabled; + } break; case WINDOW_FLAG_POPUP: { ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup."); ERR_FAIL_COND_MSG([wd.window_object isVisible] && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened."); @@ -3013,6 +3016,9 @@ bool DisplayServerMacOS::window_get_flag(WindowFlags p_flag, WindowID p_window) case WINDOW_FLAG_NO_FOCUS: { return wd.no_focus; } break; + case WINDOW_FLAG_MOUSE_PASSTHROUGH: { + return wd.mpass; + } break; case WINDOW_FLAG_POPUP: { return wd.is_popup; } break; @@ -3487,7 +3493,11 @@ void DisplayServerMacOS::process_events() { for (KeyValue<WindowID, WindowData> &E : windows) { WindowData &wd = E.value; - if (wd.mpath.size() > 0) { + if (wd.mpass) { + if (![wd.window_object ignoresMouseEvents]) { + [wd.window_object setIgnoresMouseEvents:YES]; + } + } else if (wd.mpath.size() > 0) { update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); if (Geometry2D::is_point_in_polygon(wd.mouse_pos, wd.mpath)) { if ([wd.window_object ignoresMouseEvents]) { diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index 311619f657..73fbd45400 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -38,8 +38,14 @@ #include "core/string/translation.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" +#include "editor/editor_scale.h" +#include "platform/macos/logo_svg.gen.h" +#include "platform/macos/run_icon_svg.gen.h" -#include "modules/modules_enabled.gen.h" // For regex. +#include "modules/modules_enabled.gen.h" // For svg and regex. +#ifdef MODULE_SVG_ENABLED +#include "modules/svg/image_loader_svg.h" +#endif void EditorExportPlatformMacOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { if (p_preset->get("texture_format/s3tc")) { @@ -207,6 +213,23 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false)); + + String run_script = "#!/usr/bin/env bash\n" + "unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"\n" + "open \"{temp_dir}/{exe_name}.app\" --args {cmd_args}"; + + String cleanup_script = "#!/usr/bin/env bash\n" + "kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\")\n" + "rm -rf \"{temp_dir}\""; + + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22")); + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script)); } void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, Vector<uint8_t> &p_dest) { @@ -993,7 +1016,7 @@ Error EditorExportPlatformMacOS::_create_dmg(const String &p_dmg_path, const Str return OK; } -bool EditorExportPlatformMacOS::is_shbang(const String &p_path) const { +bool EditorExportPlatformMacOS::is_shebang(const String &p_path) const { Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ); ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("Can't open file: \"%s\".", p_path)); uint16_t magic = fb->get_16(); @@ -1001,7 +1024,7 @@ bool EditorExportPlatformMacOS::is_shbang(const String &p_path) const { } bool EditorExportPlatformMacOS::is_executable(const String &p_path) const { - return MachO::is_macho(p_path) || LipO::is_lipo(p_path) || is_shbang(p_path); + return MachO::is_macho(p_path) || LipO::is_lipo(p_path) || is_shebang(p_path); } Error EditorExportPlatformMacOS::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) { @@ -1082,7 +1105,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p } else { pkg_name = "Unnamed"; } - pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name); String export_format; @@ -1684,7 +1706,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p zlib_filefunc_def io_dst = zipio_create_io(&io_fa_dst); zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst); - _zip_folder_recursive(zip, tmp_base_path_name, "", pkg_name); + zip_folder_recursive(zip, tmp_base_path_name, "", pkg_name); zipClose(zip, nullptr); } @@ -1723,119 +1745,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p return err; } -void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) { - String dir = p_folder.is_empty() ? p_root_path : p_root_path.path_join(p_folder); - - Ref<DirAccess> da = DirAccess::open(dir); - da->list_dir_begin(); - String f = da->get_next(); - while (!f.is_empty()) { - if (f == "." || f == "..") { - f = da->get_next(); - continue; - } - if (da->is_link(f)) { - OS::DateTime dt = OS::get_singleton()->get_datetime(); - - zip_fileinfo zipfi; - zipfi.tmz_date.tm_year = dt.year; - zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/ - zipfi.tmz_date.tm_mday = dt.day; - zipfi.tmz_date.tm_hour = dt.hour; - zipfi.tmz_date.tm_min = dt.minute; - zipfi.tmz_date.tm_sec = dt.second; - zipfi.dosDate = 0; - // 0120000: symbolic link type - // 0000755: permissions rwxr-xr-x - // 0000644: permissions rw-r--r-- - uint32_t _mode = 0120644; - zipfi.external_fa = (_mode << 16L) | !(_mode & 0200); - zipfi.internal_fa = 0; - - zipOpenNewFileInZip4(p_zip, - p_folder.path_join(f).utf8().get_data(), - &zipfi, - nullptr, - 0, - nullptr, - 0, - nullptr, - Z_DEFLATED, - Z_DEFAULT_COMPRESSION, - 0, - -MAX_WBITS, - DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, - nullptr, - 0, - 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions - 0); - - String target = da->read_link(f); - zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size()); - zipCloseFileInZip(p_zip); - } else if (da->current_is_dir()) { - _zip_folder_recursive(p_zip, p_root_path, p_folder.path_join(f), p_pkg_name); - } else { - OS::DateTime dt = OS::get_singleton()->get_datetime(); - - zip_fileinfo zipfi; - zipfi.tmz_date.tm_year = dt.year; - zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/ - zipfi.tmz_date.tm_mday = dt.day; - zipfi.tmz_date.tm_hour = dt.hour; - zipfi.tmz_date.tm_min = dt.minute; - zipfi.tmz_date.tm_sec = dt.second; - zipfi.dosDate = 0; - // 0100000: regular file type - // 0000755: permissions rwxr-xr-x - // 0000644: permissions rw-r--r-- - uint32_t _mode = (is_executable(dir.path_join(f)) ? 0100755 : 0100644); - zipfi.external_fa = (_mode << 16L) | !(_mode & 0200); - zipfi.internal_fa = 0; - - zipOpenNewFileInZip4(p_zip, - p_folder.path_join(f).utf8().get_data(), - &zipfi, - nullptr, - 0, - nullptr, - 0, - nullptr, - Z_DEFLATED, - Z_DEFAULT_COMPRESSION, - 0, - -MAX_WBITS, - DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, - nullptr, - 0, - 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions - 0); - - Ref<FileAccess> fa = FileAccess::open(dir.path_join(f), FileAccess::READ); - if (fa.is_null()) { - add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.path_join(f))); - return; - } - const int bufsize = 16384; - uint8_t buf[bufsize]; - - while (true) { - uint64_t got = fa->get_buffer(buf, bufsize); - if (got == 0) { - break; - } - zipWriteInFileInZip(p_zip, buf, got); - } - - zipCloseFileInZip(p_zip); - } - f = da->get_next(); - } - da->list_dir_end(); -} - bool EditorExportPlatformMacOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err; bool valid = false; @@ -2012,9 +1921,242 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor return valid; } -EditorExportPlatformMacOS::EditorExportPlatformMacOS() { - logo = ImageTexture::create_from_image(memnew(Image(_macos_logo))); +Ref<Texture2D> EditorExportPlatformMacOS::get_run_icon() const { + return run_icon; +} + +bool EditorExportPlatformMacOS::poll_export() { + Ref<EditorExportPreset> preset; + + for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { + Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i); + if (ep->is_runnable() && ep->get_platform() == this) { + preset = ep; + break; + } + } + + int prev = menu_options; + menu_options = (preset.is_valid() && preset->get("ssh_remote_deploy/enabled").operator bool()); + if (ssh_pid != 0 || !cleanup_commands.is_empty()) { + if (menu_options == 0) { + cleanup(); + } else { + menu_options += 1; + } + } + return menu_options != prev; +} + +Ref<ImageTexture> EditorExportPlatformMacOS::get_option_icon(int p_index) const { + return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index); +} + +int EditorExportPlatformMacOS::get_options_count() const { + return menu_options; +} + +String EditorExportPlatformMacOS::get_option_label(int p_index) const { + return (p_index) ? TTR("Stop and uninstall") : TTR("Run on remote macOS system"); +} + +String EditorExportPlatformMacOS::get_option_tooltip(int p_index) const { + return (p_index) ? TTR("Stop and uninstall running project from the remote system") : TTR("Run exported project on remote macOS system"); +} + +void EditorExportPlatformMacOS::cleanup() { + if (ssh_pid != 0 && OS::get_singleton()->is_process_running(ssh_pid)) { + print_line("Terminating connection..."); + OS::get_singleton()->kill(ssh_pid); + OS::get_singleton()->delay_usec(1000); + } + + if (!cleanup_commands.is_empty()) { + print_line("Stopping and deleting previous version..."); + for (const SSHCleanupCommand &cmd : cleanup_commands) { + if (cmd.wait) { + ssh_run_on_remote(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args); + } else { + ssh_run_on_remote_no_wait(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args); + } + } + } + ssh_pid = 0; + cleanup_commands.clear(); +} + +Error EditorExportPlatformMacOS::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) { + cleanup(); + if (p_device) { // Stop command, cleanup only. + return OK; + } + + EditorProgress ep("run", TTR("Running..."), 5); + + const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("macos"); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (!da->dir_exists(dest)) { + Error err = da->make_dir_recursive(dest); + if (err != OK) { + EditorNode::get_singleton()->show_warning(TTR("Could not create temp directory:") + "\n" + dest); + return err; + } + } + + String pkg_name; + if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") { + pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name")); + } else { + pkg_name = "Unnamed"; + } + pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name); + + String host = p_preset->get("ssh_remote_deploy/host").operator String(); + String port = p_preset->get("ssh_remote_deploy/port").operator String(); + if (port.is_empty()) { + port = "22"; + } + Vector<String> extra_args_ssh = p_preset->get("ssh_remote_deploy/extra_args_ssh").operator String().split(" "); + Vector<String> extra_args_scp = p_preset->get("ssh_remote_deploy/extra_args_scp").operator String().split(" "); + + const String basepath = dest.path_join("tmp_macos_export"); + +#define CLEANUP_AND_RETURN(m_err) \ + { \ + if (da->file_exists(basepath + ".zip")) { \ + da->remove(basepath + ".zip"); \ + } \ + if (da->file_exists(basepath + "_start.sh")) { \ + da->remove(basepath + "_start.sh"); \ + } \ + if (da->file_exists(basepath + "_clean.sh")) { \ + da->remove(basepath + "_clean.sh"); \ + } \ + return m_err; \ + } \ + ((void)0) + + if (ep.step(TTR("Exporting project..."), 1)) { + return ERR_SKIP; + } + Error err = export_project(p_preset, true, basepath + ".zip", p_debug_flags); + if (err != OK) { + DirAccess::remove_file_or_error(basepath + ".zip"); + return err; + } + + String cmd_args; + { + Vector<String> cmd_args_list; + gen_debug_flags(cmd_args_list, p_debug_flags); + for (int i = 0; i < cmd_args_list.size(); i++) { + if (i != 0) { + cmd_args += " "; + } + cmd_args += cmd_args_list[i]; + } + } + + const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT); + int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port"); + + print_line("Creating temporary directory..."); + ep.step(TTR("Creating temporary directory..."), 2); + String temp_dir; + err = ssh_run_on_remote(host, port, extra_args_ssh, "mktemp -d", &temp_dir); + if (err != OK || temp_dir.is_empty()) { + CLEANUP_AND_RETURN(err); + } + + print_line("Uploading archive..."); + ep.step(TTR("Uploading archive..."), 3); + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + ".zip", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + + { + String run_script = p_preset->get("ssh_remote_deploy/run_script"); + run_script = run_script.replace("{temp_dir}", temp_dir); + run_script = run_script.replace("{archive_name}", basepath.get_file() + ".zip"); + run_script = run_script.replace("{exe_name}", pkg_name); + run_script = run_script.replace("{cmd_args}", cmd_args); + + Ref<FileAccess> f = FileAccess::open(basepath + "_start.sh", FileAccess::WRITE); + if (f.is_null()) { + CLEANUP_AND_RETURN(err); + } + + f->store_string(run_script); + } + + { + String clean_script = p_preset->get("ssh_remote_deploy/cleanup_script"); + clean_script = clean_script.replace("{temp_dir}", temp_dir); + clean_script = clean_script.replace("{archive_name}", basepath.get_file() + ".zip"); + clean_script = clean_script.replace("{exe_name}", pkg_name); + clean_script = clean_script.replace("{cmd_args}", cmd_args); + + Ref<FileAccess> f = FileAccess::open(basepath + "_clean.sh", FileAccess::WRITE); + if (f.is_null()) { + CLEANUP_AND_RETURN(err); + } + + f->store_string(clean_script); + } + + print_line("Uploading scripts..."); + ep.step(TTR("Uploading scripts..."), 4); + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_start.sh", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + err = ssh_run_on_remote(host, port, extra_args_ssh, vformat("chmod +x \"%s/%s\"", temp_dir, basepath.get_file() + "_start.sh")); + if (err != OK || temp_dir.is_empty()) { + CLEANUP_AND_RETURN(err); + } + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_clean.sh", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + err = ssh_run_on_remote(host, port, extra_args_ssh, vformat("chmod +x \"%s/%s\"", temp_dir, basepath.get_file() + "_clean.sh")); + if (err != OK || temp_dir.is_empty()) { + CLEANUP_AND_RETURN(err); + } + + print_line("Starting project..."); + ep.step(TTR("Starting project..."), 5); + err = ssh_run_on_remote_no_wait(host, port, extra_args_ssh, vformat("\"%s/%s\"", temp_dir, basepath.get_file() + "_start.sh"), &ssh_pid, (use_remote) ? dbg_port : -1); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + + cleanup_commands.clear(); + cleanup_commands.push_back(SSHCleanupCommand(host, port, extra_args_ssh, vformat("\"%s/%s\"", temp_dir, basepath.get_file() + "_clean.sh"))); + + print_line("Project started."); + + CLEANUP_AND_RETURN(OK); +#undef CLEANUP_AND_RETURN } -EditorExportPlatformMacOS::~EditorExportPlatformMacOS() { +EditorExportPlatformMacOS::EditorExportPlatformMacOS() { +#ifdef MODULE_SVG_ENABLED + Ref<Image> img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _macos_logo_svg, EDSCALE, upsample, false); + logo = ImageTexture::create_from_image(img); + + img_loader.create_image_from_string(img, _macos_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); +#endif + + Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); + if (theme.is_valid()) { + stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); + } else { + stop_icon.instantiate(); + } } diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h index 7de6ddf304..c10192949c 100644 --- a/platform/macos/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -36,12 +36,10 @@ #include "core/io/file_access.h" #include "core/io/marshalls.h" #include "core/io/resource_saver.h" -#include "core/io/zip_io.h" #include "core/os/os.h" #include "core/version.h" #include "editor/editor_settings.h" #include "editor/export/editor_export.h" -#include "platform/macos/logo.gen.h" #include <sys/stat.h> @@ -52,6 +50,30 @@ class EditorExportPlatformMacOS : public EditorExportPlatform { Ref<ImageTexture> logo; + struct SSHCleanupCommand { + String host; + String port; + Vector<String> ssh_args; + String cmd_args; + bool wait = false; + + SSHCleanupCommand(){}; + SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) { + host = p_host; + port = p_port; + ssh_args = p_ssh_arg; + cmd_args = p_cmd_args; + wait = p_wait; + }; + }; + + Ref<ImageTexture> run_icon; + Ref<ImageTexture> stop_icon; + + Vector<SSHCleanupCommand> cleanup_commands; + OS::ProcessID ssh_pid = 0; + int menu_options = 0; + void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary); void _make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data); @@ -65,14 +87,17 @@ class EditorExportPlatformMacOS : public EditorExportPlatform { Ref<DirAccess> &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path); Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name); - void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name); Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); bool use_codesign() const { return true; } #ifdef MACOS_ENABLED - bool use_dmg() const { return true; } + bool use_dmg() const { + return true; + } #else - bool use_dmg() const { return false; } + bool use_dmg() const { + return false; + } #endif bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const { @@ -97,7 +122,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform { return true; } - bool is_shbang(const String &p_path) const; + bool is_shebang(const String &p_path) const; protected: virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; @@ -105,9 +130,15 @@ protected: virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; public: - virtual String get_name() const override { return "macOS"; } - virtual String get_os_name() const override { return "macOS"; } - virtual Ref<Texture2D> get_logo() const override { return logo; } + virtual String get_name() const override { + return "macOS"; + } + virtual String get_os_name() const override { + return "macOS"; + } + virtual Ref<Texture2D> get_logo() const override { + return logo; + } virtual bool is_executable(const String &p_path) const override; virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override { @@ -133,8 +164,16 @@ public: virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override { } + virtual Ref<Texture2D> get_run_icon() const override; + virtual bool poll_export() override; + virtual Ref<ImageTexture> get_option_icon(int p_index) const override; + virtual int get_options_count() const override; + virtual String get_option_label(int p_index) const override; + virtual String get_option_tooltip(int p_index) const override; + virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override; + virtual void cleanup() override; + EditorExportPlatformMacOS(); - ~EditorExportPlatformMacOS(); }; #endif // MACOS_EXPORT_PLUGIN_H diff --git a/platform/macos/logo.png b/platform/macos/logo.png Binary files differdeleted file mode 100644 index b5a660b165..0000000000 --- a/platform/macos/logo.png +++ /dev/null diff --git a/platform/macos/logo.svg b/platform/macos/logo.svg new file mode 100644 index 0000000000..759583d76b --- /dev/null +++ b/platform/macos/logo.svg @@ -0,0 +1 @@ +<svg height="32" viewBox="0 0 25.6 25.6" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M.948 19.474V6.126c0-2.767 2.42-5.178 5.178-5.178h6.904s-2.992 7.506-2.992 13.233c0 .346.337.69.69.69h2.877c0 6.648.906 8.436 1.266 9.781H6.126c-2.75 0-5.178-2.407-5.178-5.178z" fill="#1c9ef8"/><path d="M7.162 8.312v1.496" fill="none" stroke="#323232" stroke-linecap="round" stroke-width="1.036"/><path d="M10.729 14.871c-.352 0-.69-.344-.69-.69C10.038 8.414 13.03.948 13.03.948h6.444c2.77 0 5.178 2.416 5.178 5.178v13.348c0 2.754-2.407 5.178-5.178 5.178h-4.603c-.357-1.333-1.266-2.887-1.266-9.78z" fill="#e1e6ed"/><g fill="none" stroke="#323232" stroke-linecap="round"><path d="M17.575 8.255V9.75" stroke-width="1.036"/><path d="M5.55 16.943c1.037 1.794 3.907 2.876 6.79 2.876 2.877 0 5.745-1.068 6.789-2.876" stroke-width=".69"/></g></svg> diff --git a/platform/macos/run_icon.svg b/platform/macos/run_icon.svg new file mode 100644 index 0000000000..c7067bb4b6 --- /dev/null +++ b/platform/macos/run_icon.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke-width:.93168;-inkscape-stroke:none" d="M4.418 1.055c-1.82 0-3.365 1.537-3.365 3.363v7.164c0 1.829 1.548 3.363 3.365 3.363h7.164c1.828 0 3.363-1.544 3.363-3.363V4.418c0-1.822-1.537-3.363-3.363-3.363H7.729Zm3.875 1.164h3.291c1.149 0 2.2 1.053 2.2 2.199v7.164c0 1.14-1.052 2.2-2.2 2.2h-2.15a8.884 8.884 0 0 1-.358-1.598c-.135.02-.487.082-.693.117a3.947 3.947 0 0 1-.049.004l-.008-.002a7.345 7.345 0 0 1-1.205-.004 7.114 7.114 0 0 1-.926-.139 6.057 6.057 0 0 1-.867-.271 3.843 3.843 0 0 1-.988-.566 3.214 3.214 0 0 1-.397-.378 2.8 2.8 0 0 1-.318-.441.558.558 0 0 1-.059-.424.564.564 0 0 1 .881-.299.56.56 0 0 1 .145.164c.083.138.188.26.312.362.096.082.2.158.307.224.12.075.243.142.371.201.285.139.583.247.89.319a5.35 5.35 0 0 0 1.282.158c.065 0 .129-.005.184-.006.056 0 .102-.005.148-.008l.096-.006c.114-.009.228-.02.31-.032.083-.013.11-.021.143-.028.099-.022.204-.058.327-.089a28.438 28.438 0 0 1-.06-1.929V8.53H6.887c.048-1.963.746-4.357 1.181-5.677.1-.293.184-.527.225-.633ZM4.973 5.03h.002a.562.562 0 0 1 .558.559v.805a.556.556 0 0 1-.558.558.56.56 0 0 1-.397-.162.565.565 0 0 1-.164-.396V5.59a.561.561 0 0 1 .559-.559Z"/><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke-linecap:round;-inkscape-stroke:none" d="M26.117 11.467c.008.11.014.225.022.328.022.283.052.565.088.846l.012.053c1.238-.252 2.448-.829 3.011-1.803a.6.6 0 1 0-1.039-.6c-.28.486-1.161.936-2.094 1.176z" transform="translate(-15.37 .357) scale(.93168)"/><g style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-opacity:1"><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-opacity:1;-inkscape-stroke:none" d="M27.836 5.585v.862" transform="translate(-15.37 .357) scale(.93168)"/><path style="color:#000;fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-linecap:round;stroke-opacity:1;-inkscape-stroke:none" d="M27.836 4.984a.6.6 0 0 0-.6.6v.863a.6.6 0 0 0 .6.6.6.6 0 0 0 .6-.6v-.863a.6.6 0 0 0-.6-.6Z" transform="translate(-15.37 .357) scale(.93168)"/></g></svg> diff --git a/platform/uwp/README.md b/platform/uwp/README.md index 575f90e3c7..d69a8a8850 100644 --- a/platform/uwp/README.md +++ b/platform/uwp/README.md @@ -14,7 +14,7 @@ project template used for packaging the UWP export templates. ## Documentation -- [Compiling for Universal Windows Platform](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_uwp.html) +- [Compiling for Universal Windows Platform](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_uwp.html) - Instructions on building this platform port from source. - [Exporting for Universal Windows Platform](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_uwp.html) - Instructions on using the compiled export templates to export a project. diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp index 6eb74fd90a..f810cb0ca9 100644 --- a/platform/uwp/export/export_plugin.cpp +++ b/platform/uwp/export/export_plugin.cpp @@ -30,8 +30,14 @@ #include "export_plugin.h" +#include "editor/editor_scale.h" #include "editor/editor_settings.h" -#include "platform/uwp/logo.gen.h" +#include "platform/uwp/logo_svg.gen.h" + +#include "modules/modules_enabled.gen.h" // For svg and regex. +#ifdef MODULE_SVG_ENABLED +#include "modules/svg/image_loader_svg.h" +#endif String EditorExportPlatformUWP::get_name() const { return "UWP"; @@ -504,5 +510,13 @@ void EditorExportPlatformUWP::resolve_platform_feature_priorities(const Ref<Edit } EditorExportPlatformUWP::EditorExportPlatformUWP() { - logo = ImageTexture::create_from_image(memnew(Image(_uwp_logo))); +#ifdef MODULE_SVG_ENABLED + Ref<Image> img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _uwp_logo_svg, EDSCALE, upsample, false); + + logo = ImageTexture::create_from_image(img); +#endif } diff --git a/platform/uwp/logo.png b/platform/uwp/logo.png Binary files differdeleted file mode 100644 index 9017a30636..0000000000 --- a/platform/uwp/logo.png +++ /dev/null diff --git a/platform/uwp/logo.svg b/platform/uwp/logo.svg new file mode 100644 index 0000000000..5bcbdcfcd4 --- /dev/null +++ b/platform/uwp/logo.svg @@ -0,0 +1 @@ +<svg height="32" width="32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g transform="translate(8.981 1.816)"><circle style="fill:#2f75bb;fill-opacity:1;stroke:none;stroke-width:.815427" cx="7.019" cy="14.184" r="13.825"/><path d="m-1.192 8.234 6.73-.927v6.503h-6.73Zm0 11.899 6.73.927v-6.422h-6.73Zm7.47 1.026 8.952 1.236v-7.757H6.278Zm0-13.951v6.602h8.952V5.973Z" fill="#00abed" style="fill:#fff;fill-opacity:1"/></g></svg> diff --git a/platform/web/README.md b/platform/web/README.md index 1265ca09df..906eb508fe 100644 --- a/platform/web/README.md +++ b/platform/web/README.md @@ -10,7 +10,7 @@ this platform such as the html shell (web page). ## Documentation -- [Compiling for the Web](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_web.html) +- [Compiling for the Web](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_web.html) - Instructions on building this platform port from source. - [Exporting for the Web](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html) - Instructions on using the compiled export templates to export a project. diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp index 3e11db6887..d8e04904c7 100644 --- a/platform/web/export/export_plugin.cpp +++ b/platform/web/export/export_plugin.cpp @@ -31,7 +31,15 @@ #include "export_plugin.h" #include "core/config/project_settings.h" +#include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "platform/web/logo_svg.gen.h" +#include "platform/web/run_icon_svg.gen.h" + +#include "modules/modules_enabled.gen.h" // For svg. +#ifdef MODULE_SVG_ENABLED +#include "modules/svg/image_loader_svg.h" +#endif Error EditorExportPlatformWeb::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) { Ref<FileAccess> io_fa; @@ -153,7 +161,7 @@ void EditorExportPlatformWeb::_fix_html(Vector<uint8_t> &p_html, const Ref<Edito const String custom_head_include = p_preset->get("html/head_include"); HashMap<String, String> replaces; replaces["$GODOT_URL"] = p_name + ".js"; - replaces["$GODOT_PROJECT_NAME"] = ProjectSettings::get_singleton()->get_setting("application/config/name"); + replaces["$GODOT_PROJECT_NAME"] = GLOBAL_GET("application/config/name"); replaces["$GODOT_HEAD_INCLUDE"] = head_include + custom_head_include; replaces["$GODOT_CONFIG"] = str_config; _replace_strings(replaces, p_html); @@ -193,7 +201,7 @@ Error EditorExportPlatformWeb::_add_manifest_icon(const String &p_path, const St } Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) { - String proj_name = ProjectSettings::get_singleton()->get_setting("application/config/name"); + String proj_name = GLOBAL_GET("application/config/name"); if (proj_name.is_empty()) { proj_name = "Godot Game"; } @@ -651,8 +659,17 @@ EditorExportPlatformWeb::EditorExportPlatformWeb() { server.instantiate(); server_thread.start(_server_thread_poll, this); - logo = ImageTexture::create_from_image(memnew(Image(_web_logo))); - run_icon = ImageTexture::create_from_image(memnew(Image(_web_run_icon))); +#ifdef MODULE_SVG_ENABLED + Ref<Image> img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _web_logo_svg, EDSCALE, upsample, false); + logo = ImageTexture::create_from_image(img); + + img_loader.create_image_from_string(img, _web_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); +#endif Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); if (theme.is_valid()) { diff --git a/platform/web/export/export_plugin.h b/platform/web/export/export_plugin.h index b85492b66f..e74c945837 100644 --- a/platform/web/export/export_plugin.h +++ b/platform/web/export/export_plugin.h @@ -38,11 +38,8 @@ #include "core/io/zip_io.h" #include "editor/editor_node.h" #include "editor/export/editor_export_platform.h" -#include "main/splash.gen.h" -#include "platform/web/logo.gen.h" -#include "platform/web/run_icon.gen.h" - #include "editor_http_server.h" +#include "main/splash.gen.h" class EditorExportPlatformWeb : public EditorExportPlatform { GDCLASS(EditorExportPlatformWeb, EditorExportPlatform); diff --git a/platform/web/logo.png b/platform/web/logo.png Binary files differdeleted file mode 100644 index c046d87dc4..0000000000 --- a/platform/web/logo.png +++ /dev/null diff --git a/platform/web/logo.svg b/platform/web/logo.svg new file mode 100644 index 0000000000..567b6f3c77 --- /dev/null +++ b/platform/web/logo.svg @@ -0,0 +1 @@ +<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M7 5h18v21H7z" fill="#fff"/><path d="M3.143 1 5.48 27.504 15.967 31l10.553-3.496L28.857 1zM23.78 9.565H11.473l.275 3.308h11.759l-.911 9.937-6.556 1.808v.02h-.073l-6.61-1.828-.402-5.076h3.195l.234 2.552 3.583.97 3.595-.97.402-4.165H8.788L7.93 6.37h16.145z" fill="#eb6428"/></svg> diff --git a/platform/web/run_icon.png b/platform/web/run_icon.png Binary files differdeleted file mode 100644 index 574abb0150..0000000000 --- a/platform/web/run_icon.png +++ /dev/null diff --git a/platform/web/run_icon.svg b/platform/web/run_icon.svg new file mode 100644 index 0000000000..494f53cb90 --- /dev/null +++ b/platform/web/run_icon.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M3.143 1 5.48 27.504 15.967 31l10.553-3.496L28.857 1ZM23.78 9.565H11.473l.275 3.308h11.759l-.911 9.937-6.556 1.808v.02h-.073l-6.61-1.828-.402-5.076h3.195l.234 2.552 3.583.97 3.595-.97.402-4.165H8.788L7.93 6.37h16.145Z" fill="#eb6428" style="fill:#e0e0e0;fill-opacity:1" transform="translate(.586 .586) scale(.46337)"/></svg> diff --git a/platform/windows/README.md b/platform/windows/README.md index c04032ae1d..4c775576fe 100644 --- a/platform/windows/README.md +++ b/platform/windows/README.md @@ -7,7 +7,7 @@ used by this platform. ## Documentation -- [Compiling for Windows](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_windows.html) +- [Compiling for Windows](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html) - Instructions on building this platform port from source. - [Exporting for Windows](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_windows.html) - Instructions on using the compiled export templates to export a project. diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 2d787c84e2..914cd07b50 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -735,6 +735,9 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) { wd.no_focus = true; } + if (p_flags & WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT) { + wd.mpass = true; + } if (p_flags & WINDOW_FLAG_POPUP_BIT) { wd.is_popup = true; } @@ -918,7 +921,7 @@ void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); - if (windows[p_window].mpath.size() == 0) { + if (windows[p_window].mpass || windows[p_window].mpath.size() == 0) { SetWindowRgn(windows[p_window].hWnd, nullptr, TRUE); } else { POINT *points = (POINT *)memalloc(sizeof(POINT) * windows[p_window].mpath.size()); @@ -1499,6 +1502,10 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W wd.no_focus = p_enabled; _update_window_style(p_window); } break; + case WINDOW_FLAG_MOUSE_PASSTHROUGH: { + wd.mpass = p_enabled; + _update_window_mouse_passthrough(p_window); + } break; case WINDOW_FLAG_POPUP: { ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup."); ERR_FAIL_COND_MSG(IsWindowVisible(wd.hWnd) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened."); @@ -1530,6 +1537,9 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window case WINDOW_FLAG_NO_FOCUS: { return wd.no_focus; } break; + case WINDOW_FLAG_MOUSE_PASSTHROUGH: { + return wd.mpass; + } break; case WINDOW_FLAG_POPUP: { return wd.is_popup; } break; @@ -2464,6 +2474,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA // Process window messages. switch (uMsg) { + case WM_NCHITTEST: { + if (windows[window_id].mpass) { + return HTTRANSPARENT; + } + } break; case WM_MOUSEACTIVATE: { if (windows[window_id].no_focus) { return MA_NOACTIVATEANDEAT; // Do not activate, and discard mouse messages. @@ -3656,7 +3671,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, DWORD dwExStyle; DWORD dwStyle; - _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle); + _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle); RECT WindowRect; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 84f2dee35e..ce4b94af59 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -370,6 +370,7 @@ class DisplayServerWindows : public DisplayServer { bool window_has_focus = false; bool exclusive = false; bool context_created = false; + bool mpass = false; // Used to transfer data between events using timer. WPARAM saved_wparam; diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index b0e2f5a05b..4112bb84b5 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -51,7 +51,6 @@ void register_windows_exporter() { Ref<EditorExportPlatformWindows> platform; platform.instantiate(); - platform->set_logo(ImageTexture::create_from_image(memnew(Image(_windows_logo)))); platform->set_name("Windows Desktop"); platform->set_os_name("Windows"); diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 7c61a79fc8..bf32b16018 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -34,6 +34,14 @@ #include "core/io/image_loader.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" +#include "editor/editor_scale.h" +#include "platform/windows/logo_svg.gen.h" +#include "platform/windows/run_icon_svg.gen.h" + +#include "modules/modules_enabled.gen.h" // For svg. +#ifdef MODULE_SVG_ENABLED +#include "modules/svg/image_loader_svg.h" +#endif Error EditorExportPlatformWindows::_process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path) { static const uint8_t icon_size[] = { 16, 32, 48, 64, 128, 0 /*256*/ }; @@ -168,9 +176,39 @@ Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> } Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { - String pck_path = p_path; - if (p_preset->get("binary_format/embed_pck")) { - pck_path = p_path.get_basename() + ".tmp"; + bool export_as_zip = p_path.ends_with("zip"); + bool embedded = p_preset->get("binary_format/embed_pck"); + + String pkg_name; + if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") { + pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name")); + } else { + pkg_name = "Unnamed"; + } + + pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name); + + // Setup temp folder. + String path = p_path; + String tmp_dir_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name); + Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path); + if (export_as_zip) { + if (tmp_app_dir.is_null()) { + return ERR_CANT_CREATE; + } + if (DirAccess::exists(tmp_dir_path)) { + if (tmp_app_dir->change_dir(tmp_dir_path) == OK) { + tmp_app_dir->erase_contents_recursive(); + } + } + tmp_app_dir->make_dir_recursive(tmp_dir_path); + path = tmp_dir_path.path_join(p_path.get_file().get_basename() + ".exe"); + } + + // Export project. + String pck_path = path; + if (embedded) { + pck_path = pck_path.get_basename() + ".tmp"; } Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags); if (p_preset->get("codesign/enable") && err == OK) { @@ -181,7 +219,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> } } - if (p_preset->get("binary_format/embed_pck") && err == OK) { + if (embedded && err == OK) { Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir()); err = tmp_dir->rename(pck_path, p_path); if (err != OK) { @@ -189,6 +227,27 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> } } + // ZIP project. + if (export_as_zip) { + if (FileAccess::exists(p_path)) { + OS::get_singleton()->move_to_trash(p_path); + } + + Ref<FileAccess> io_fa_dst; + zlib_filefunc_def io_dst = zipio_create_io(&io_fa_dst); + zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst); + + zip_folder_recursive(zip, tmp_dir_path, "", pkg_name); + + zipClose(zip, nullptr); + + if (tmp_app_dir->change_dir(tmp_dir_path) == OK) { + tmp_app_dir->erase_contents_recursive(); + tmp_app_dir->change_dir(".."); + tmp_app_dir->remove(pkg_name); + } + } + return err; } @@ -199,6 +258,7 @@ String EditorExportPlatformWindows::get_template_file_name(const String &p_targe List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const { List<String> list; list.push_back("exe"); + list.push_back("zip"); return list; } @@ -212,6 +272,7 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExpor void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) { EditorExportPlatformPC::get_export_options(r_options); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false)); @@ -235,6 +296,29 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), "")); + + String run_script = "Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'\n" + "$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'\n" + "$trigger = New-ScheduledTaskTrigger -Once -At 00:00\n" + "$settings = New-ScheduledTaskSettingsSet\n" + "$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings\n" + "Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true\n" + "Start-ScheduledTask -TaskName godot_remote_debug\n" + "while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }\n" + "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"; + + String cleanup_script = "Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue\n" + "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue\n" + "Remove-Item -Recurse -Force '{temp_dir}'"; + + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22")); + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script)); } Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon) { @@ -659,3 +743,227 @@ Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int6 } return OK; } + +Ref<Texture2D> EditorExportPlatformWindows::get_run_icon() const { + return run_icon; +} + +bool EditorExportPlatformWindows::poll_export() { + Ref<EditorExportPreset> preset; + + for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { + Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i); + if (ep->is_runnable() && ep->get_platform() == this) { + preset = ep; + break; + } + } + + int prev = menu_options; + menu_options = (preset.is_valid() && preset->get("ssh_remote_deploy/enabled").operator bool()); + if (ssh_pid != 0 || !cleanup_commands.is_empty()) { + if (menu_options == 0) { + cleanup(); + } else { + menu_options += 1; + } + } + return menu_options != prev; +} + +Ref<ImageTexture> EditorExportPlatformWindows::get_option_icon(int p_index) const { + return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index); +} + +int EditorExportPlatformWindows::get_options_count() const { + return menu_options; +} + +String EditorExportPlatformWindows::get_option_label(int p_index) const { + return (p_index) ? TTR("Stop and uninstall") : TTR("Run on remote Windows system"); +} + +String EditorExportPlatformWindows::get_option_tooltip(int p_index) const { + return (p_index) ? TTR("Stop and uninstall running project from the remote system") : TTR("Run exported project on remote Windows system"); +} + +void EditorExportPlatformWindows::cleanup() { + if (ssh_pid != 0 && OS::get_singleton()->is_process_running(ssh_pid)) { + print_line("Terminating connection..."); + OS::get_singleton()->kill(ssh_pid); + OS::get_singleton()->delay_usec(1000); + } + + if (!cleanup_commands.is_empty()) { + print_line("Stopping and deleting previous version..."); + for (const SSHCleanupCommand &cmd : cleanup_commands) { + if (cmd.wait) { + ssh_run_on_remote(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args); + } else { + ssh_run_on_remote_no_wait(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args); + } + } + } + ssh_pid = 0; + cleanup_commands.clear(); +} + +Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) { + cleanup(); + if (p_device) { // Stop command, cleanup only. + return OK; + } + + EditorProgress ep("run", TTR("Running..."), 5); + + const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("windows"); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (!da->dir_exists(dest)) { + Error err = da->make_dir_recursive(dest); + if (err != OK) { + EditorNode::get_singleton()->show_warning(TTR("Could not create temp directory:") + "\n" + dest); + return err; + } + } + + String host = p_preset->get("ssh_remote_deploy/host").operator String(); + String port = p_preset->get("ssh_remote_deploy/port").operator String(); + if (port.is_empty()) { + port = "22"; + } + Vector<String> extra_args_ssh = p_preset->get("ssh_remote_deploy/extra_args_ssh").operator String().split(" "); + Vector<String> extra_args_scp = p_preset->get("ssh_remote_deploy/extra_args_scp").operator String().split(" "); + + const String basepath = dest.path_join("tmp_windows_export"); + +#define CLEANUP_AND_RETURN(m_err) \ + { \ + if (da->file_exists(basepath + ".zip")) { \ + da->remove(basepath + ".zip"); \ + } \ + if (da->file_exists(basepath + "_start.ps1")) { \ + da->remove(basepath + "_start.ps1"); \ + } \ + if (da->file_exists(basepath + "_clean.ps1")) { \ + da->remove(basepath + "_clean.ps1"); \ + } \ + return m_err; \ + } \ + ((void)0) + + if (ep.step(TTR("Exporting project..."), 1)) { + return ERR_SKIP; + } + Error err = export_project(p_preset, true, basepath + ".zip", p_debug_flags); + if (err != OK) { + DirAccess::remove_file_or_error(basepath + ".zip"); + return err; + } + + String cmd_args; + { + Vector<String> cmd_args_list; + gen_debug_flags(cmd_args_list, p_debug_flags); + for (int i = 0; i < cmd_args_list.size(); i++) { + if (i != 0) { + cmd_args += " "; + } + cmd_args += cmd_args_list[i]; + } + } + + const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT); + int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port"); + + print_line("Creating temporary directory..."); + ep.step(TTR("Creating temporary directory..."), 2); + String temp_dir; + err = ssh_run_on_remote(host, port, extra_args_ssh, "powershell -command \\\"\\$tmp = Join-Path \\$Env:Temp \\$(New-Guid); New-Item -Type Directory -Path \\$tmp | Out-Null; Write-Output \\$tmp\\\"", &temp_dir); + if (err != OK || temp_dir.is_empty()) { + CLEANUP_AND_RETURN(err); + } + + print_line("Uploading archive..."); + ep.step(TTR("Uploading archive..."), 3); + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + ".zip", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + + { + String run_script = p_preset->get("ssh_remote_deploy/run_script"); + run_script = run_script.replace("{temp_dir}", temp_dir); + run_script = run_script.replace("{archive_name}", basepath.get_file() + ".zip"); + run_script = run_script.replace("{exe_name}", basepath.get_file() + ".exe"); + run_script = run_script.replace("{cmd_args}", cmd_args); + + Ref<FileAccess> f = FileAccess::open(basepath + "_start.ps1", FileAccess::WRITE); + if (f.is_null()) { + CLEANUP_AND_RETURN(err); + } + + f->store_string(run_script); + } + + { + String clean_script = p_preset->get("ssh_remote_deploy/cleanup_script"); + clean_script = clean_script.replace("{temp_dir}", temp_dir); + clean_script = clean_script.replace("{archive_name}", basepath.get_file() + ".zip"); + clean_script = clean_script.replace("{exe_name}", basepath.get_file() + ".exe"); + clean_script = clean_script.replace("{cmd_args}", cmd_args); + + Ref<FileAccess> f = FileAccess::open(basepath + "_clean.ps1", FileAccess::WRITE); + if (f.is_null()) { + CLEANUP_AND_RETURN(err); + } + + f->store_string(clean_script); + } + + print_line("Uploading scripts..."); + ep.step(TTR("Uploading scripts..."), 4); + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_start.ps1", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_clean.ps1", temp_dir); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + + print_line("Starting project..."); + ep.step(TTR("Starting project..."), 5); + err = ssh_run_on_remote_no_wait(host, port, extra_args_ssh, vformat("powershell -file \"%s\\%s\"", temp_dir, basepath.get_file() + "_start.ps1"), &ssh_pid, (use_remote) ? dbg_port : -1); + if (err != OK) { + CLEANUP_AND_RETURN(err); + } + + cleanup_commands.clear(); + cleanup_commands.push_back(SSHCleanupCommand(host, port, extra_args_ssh, vformat("powershell -file \"%s\\%s\"", temp_dir, basepath.get_file() + "_clean.ps1"))); + + print_line("Project started."); + + CLEANUP_AND_RETURN(OK); +#undef CLEANUP_AND_RETURN +} + +EditorExportPlatformWindows::EditorExportPlatformWindows() { +#ifdef MODULE_SVG_ENABLED + Ref<Image> img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false); + set_logo(ImageTexture::create_from_image(img)); + + img_loader.create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); +#endif + + Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); + if (theme.is_valid()) { + stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); + } else { + stop_icon.instantiate(); + } +} diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index 96608728d3..fa75a17a1f 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -35,9 +35,32 @@ #include "core/os/os.h" #include "editor/editor_settings.h" #include "editor/export/editor_export_platform_pc.h" -#include "platform/windows/logo.gen.h" class EditorExportPlatformWindows : public EditorExportPlatformPC { + struct SSHCleanupCommand { + String host; + String port; + Vector<String> ssh_args; + String cmd_args; + bool wait = false; + + SSHCleanupCommand(){}; + SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) { + host = p_host; + port = p_port; + ssh_args = p_ssh_arg; + cmd_args = p_cmd_args; + wait = p_wait; + }; + }; + + Ref<ImageTexture> run_icon; + Ref<ImageTexture> stop_icon; + + Vector<SSHCleanupCommand> cleanup_commands; + OS::ProcessID ssh_pid = 0; + int menu_options = 0; + Error _process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path); Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon); Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path); @@ -53,6 +76,17 @@ public: virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; virtual String get_template_file_name(const String &p_target, const String &p_arch) const override; virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override; + + virtual Ref<Texture2D> get_run_icon() const override; + virtual bool poll_export() override; + virtual Ref<ImageTexture> get_option_icon(int p_index) const override; + virtual int get_options_count() const override; + virtual String get_option_label(int p_index) const override; + virtual String get_option_tooltip(int p_index) const override; + virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override; + virtual void cleanup() override; + + EditorExportPlatformWindows(); }; #endif // WINDOWS_EXPORT_PLUGIN_H diff --git a/platform/windows/logo.png b/platform/windows/logo.png Binary files differdeleted file mode 100644 index f06b463850..0000000000 --- a/platform/windows/logo.png +++ /dev/null diff --git a/platform/windows/logo.svg b/platform/windows/logo.svg new file mode 100644 index 0000000000..77a0b20766 --- /dev/null +++ b/platform/windows/logo.svg @@ -0,0 +1 @@ +<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="m1 5.132 12.295-1.694v11.879H1zm0 21.736 12.295 1.695V16.83H1zm13.647 1.875L31 31V16.83H14.647zm0-25.486v12.06H31V1z" fill="#00abed"/></svg> diff --git a/platform/windows/run_icon.svg b/platform/windows/run_icon.svg new file mode 100644 index 0000000000..0897276ef7 --- /dev/null +++ b/platform/windows/run_icon.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m1.095 2.997 5.66-.78v5.469h-5.66zm0 10.006 5.66.78v-5.4h-5.66zm6.282.863 7.528 1.04V8.381H7.377Zm0-11.732v5.552h7.528V1.095Z" fill="#00abed" style="stroke-width:.460341;fill:#e0e0e0;fill-opacity:1"/></svg> diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 09f4406ffe..5036dd30b1 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -31,6 +31,7 @@ #include "path_2d.h" #include "core/math/geometry_2d.h" +#include "scene/main/timer.h" #ifdef TOOLS_ENABLED #include "editor/editor_scale.h" @@ -171,6 +172,12 @@ void Path2D::_curve_changed() { } queue_redraw(); + for (int i = 0; i < get_child_count(); i++) { + PathFollow2D *follow = Object::cast_to<PathFollow2D>(get_child(i)); + if (follow) { + follow->path_changed(); + } + } } void Path2D::set_curve(const Ref<Curve2D> &p_curve) { @@ -200,6 +207,14 @@ void Path2D::_bind_methods() { ///////////////////////////////////////////////////////////////////////////////// +void PathFollow2D::path_changed() { + if (update_timer && !update_timer->is_stopped()) { + update_timer->start(); + } else { + _update_transform(); + } +} + void PathFollow2D::_update_transform() { if (!path) { return; @@ -230,6 +245,16 @@ void PathFollow2D::_update_transform() { void PathFollow2D::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_READY: { + if (Engine::get_singleton()->is_editor_hint()) { + update_timer = memnew(Timer); + update_timer->set_wait_time(0.2); + update_timer->set_one_shot(true); + update_timer->connect("timeout", callable_mp(this, &PathFollow2D::_update_transform)); + add_child(update_timer, false, Node::INTERNAL_MODE_BACK); + } + } break; + case NOTIFICATION_ENTER_TREE: { path = Object::cast_to<Path2D>(get_parent()); if (path) { diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index 884743dd2a..89c77c49eb 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -34,6 +34,8 @@ #include "scene/2d/node_2d.h" #include "scene/resources/curve.h" +class Timer; + class Path2D : public Node2D { GDCLASS(Path2D, Node2D); @@ -65,6 +67,7 @@ public: private: Path2D *path = nullptr; real_t progress = 0.0; + Timer *update_timer = nullptr; real_t h_offset = 0.0; real_t v_offset = 0.0; real_t lookahead = 4.0; @@ -81,6 +84,8 @@ protected: static void _bind_methods(); public: + void path_changed(); + void set_progress(real_t p_progress); real_t get_progress() const; diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index a44e66ce2a..fe7f6837f0 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -61,11 +61,7 @@ void BoneAttachment3D::_validate_property(PropertyInfo &p_property) const { } bool BoneAttachment3D::_set(const StringName &p_path, const Variant &p_value) { - if (p_path == SNAME("override_pose")) { - set_override_pose(p_value); - } else if (p_path == SNAME("override_mode")) { - set_override_mode(p_value); - } else if (p_path == SNAME("use_external_skeleton")) { + if (p_path == SNAME("use_external_skeleton")) { set_use_external_skeleton(p_value); } else if (p_path == SNAME("external_skeleton")) { set_external_skeleton(p_value); @@ -75,11 +71,7 @@ bool BoneAttachment3D::_set(const StringName &p_path, const Variant &p_value) { } bool BoneAttachment3D::_get(const StringName &p_path, Variant &r_ret) const { - if (p_path == SNAME("override_pose")) { - r_ret = get_override_pose(); - } else if (p_path == SNAME("override_mode")) { - r_ret = get_override_mode(); - } else if (p_path == SNAME("use_external_skeleton")) { + if (p_path == SNAME("use_external_skeleton")) { r_ret = get_use_external_skeleton(); } else if (p_path == SNAME("external_skeleton")) { r_ret = get_external_skeleton(); @@ -208,14 +200,10 @@ void BoneAttachment3D::_transform_changed() { Transform3D our_trans = get_transform(); if (use_external_skeleton) { - our_trans = sk->world_transform_to_global_pose(get_global_transform()); + our_trans = sk->get_global_transform().affine_inverse() * get_global_transform(); } - if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) { - sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true); - } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) { - sk->set_bone_local_pose_override(bone_idx, sk->global_pose_to_local_pose(bone_idx, our_trans), 1.0, true); - } + sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true); } } @@ -267,11 +255,7 @@ void BoneAttachment3D::set_override_pose(bool p_override) { if (!override_pose) { Skeleton3D *sk = _get_skeleton3d(); if (sk) { - if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) { - sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false); - } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) { - sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false); - } + sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false); } _transform_changed(); } @@ -282,27 +266,6 @@ bool BoneAttachment3D::get_override_pose() const { return override_pose; } -void BoneAttachment3D::set_override_mode(int p_mode) { - if (override_pose) { - Skeleton3D *sk = _get_skeleton3d(); - if (sk) { - if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) { - sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false); - } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) { - sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false); - } - } - override_mode = p_mode; - _transform_changed(); - return; - } - override_mode = p_mode; -} - -int BoneAttachment3D::get_override_mode() const { - return override_mode; -} - void BoneAttachment3D::set_use_external_skeleton(bool p_use_external) { use_external_skeleton = p_use_external; @@ -361,7 +324,7 @@ void BoneAttachment3D::on_bone_pose_update(int p_bone_index) { if (sk) { if (!override_pose) { if (use_external_skeleton) { - set_global_transform(sk->global_pose_to_world_transform(sk->get_bone_global_pose(bone_idx))); + set_global_transform(sk->get_global_transform() * sk->get_bone_global_pose(bone_idx)); } else { set_transform(sk->get_bone_global_pose(bone_idx)); } @@ -407,8 +370,6 @@ void BoneAttachment3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_override_pose", "override_pose"), &BoneAttachment3D::set_override_pose); ClassDB::bind_method(D_METHOD("get_override_pose"), &BoneAttachment3D::get_override_pose); - ClassDB::bind_method(D_METHOD("set_override_mode", "override_mode"), &BoneAttachment3D::set_override_mode); - ClassDB::bind_method(D_METHOD("get_override_mode"), &BoneAttachment3D::get_override_mode); ClassDB::bind_method(D_METHOD("set_use_external_skeleton", "use_external_skeleton"), &BoneAttachment3D::set_use_external_skeleton); ClassDB::bind_method(D_METHOD("get_use_external_skeleton"), &BoneAttachment3D::get_use_external_skeleton); @@ -420,4 +381,5 @@ void BoneAttachment3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_idx"), "set_bone_idx", "get_bone_idx"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_pose"), "set_override_pose", "get_override_pose"); } diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h index 2065271bbe..327cbaa0ab 100644 --- a/scene/3d/bone_attachment_3d.h +++ b/scene/3d/bone_attachment_3d.h @@ -44,14 +44,8 @@ class BoneAttachment3D : public Node3D { int bone_idx = -1; bool override_pose = false; - int override_mode = 0; bool _override_dirty = false; - enum OVERRIDE_MODES { - MODE_GLOBAL_POSE, - MODE_LOCAL_POSE, - }; - bool use_external_skeleton = false; NodePath external_skeleton_node; ObjectID external_skeleton_node_cache; @@ -86,8 +80,6 @@ public: void set_override_pose(bool p_override); bool get_override_pose() const; - void set_override_mode(int p_mode); - int get_override_mode() const; void set_use_external_skeleton(bool p_external_skeleton); bool get_use_external_skeleton() const; diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 4eadaa603f..1b46879079 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -33,7 +33,6 @@ #include "core/object/message_queue.h" #include "core/variant/type_info.h" #include "scene/3d/physics_body_3d.h" -#include "scene/resources/skeleton_modification_3d.h" #include "scene/resources/surface_tool.h" #include "scene/scene_string_names.h" @@ -70,13 +69,6 @@ SkinReference::~SkinReference() { bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) { String path = p_path; -#ifndef _3D_DISABLED - if (path.begins_with("modification_stack")) { - set_modification_stack(p_value); - return true; - } -#endif //_3D_DISABLED - if (!path.begins_with("bones/")) { return false; } @@ -113,13 +105,6 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) { bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const { String path = p_path; -#ifndef _3D_DISABLED - if (path.begins_with("modification_stack")) { - r_ret = modification_stack; - return true; - } -#endif //_3D_DISABLED - if (!path.begins_with("bones/")) { return false; } @@ -162,14 +147,6 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + PNAME("scale"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR)); } -#ifndef _3D_DISABLED - p_list->push_back( - PropertyInfo(Variant::OBJECT, "modification_stack", - PROPERTY_HINT_RESOURCE_TYPE, - "SkeletonModificationStack3D", - PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); -#endif //_3D_DISABLED - for (PropertyInfo &E : *p_list) { _validate_property(E); } @@ -330,24 +307,10 @@ void Skeleton3D::_notification(int p_what) { } } } - - if (modification_stack.is_valid()) { - execute_modifications(get_physics_process_delta_time(), SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_physics_process); - } - } break; - - case NOTIFICATION_INTERNAL_PROCESS: { - if (modification_stack.is_valid()) { - execute_modifications(get_process_delta_time(), SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_process); - } } break; - case NOTIFICATION_READY: { - set_physics_process_internal(true); - set_process_internal(true); - - if (modification_stack.is_valid()) { - set_modification_stack(modification_stack); + if (Engine::get_singleton()->is_editor_hint()) { + set_physics_process_internal(true); } } break; #endif // _3D_DISABLED @@ -395,99 +358,6 @@ Transform3D Skeleton3D::get_bone_global_pose_no_override(int p_bone) const { return bones[p_bone].pose_global_no_override; } -void Skeleton3D::clear_bones_local_pose_override() { - for (int i = 0; i < bones.size(); i += 1) { - bones.write[i].local_pose_override_amount = 0; - } - _make_dirty(); -} - -void Skeleton3D::set_bone_local_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - bones.write[p_bone].local_pose_override_amount = p_amount; - bones.write[p_bone].local_pose_override = p_pose; - bones.write[p_bone].local_pose_override_reset = !p_persistent; - _make_dirty(); -} - -Transform3D Skeleton3D::get_bone_local_pose_override(int p_bone) const { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - return bones[p_bone].local_pose_override; -} - -void Skeleton3D::update_bone_rest_forward_vector(int p_bone, bool p_force_update) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - - if (bones[p_bone].rest_bone_forward_vector.length_squared() > 0 && p_force_update == false) { - update_bone_rest_forward_axis(p_bone, p_force_update); - } - - // If it is a child/leaf bone... - if (get_bone_parent(p_bone) > 0) { - bones.write[p_bone].rest_bone_forward_vector = bones[p_bone].rest.origin.normalized(); - } else { - // If it has children... - Vector<int> child_bones = get_bone_children(p_bone); - if (child_bones.size() > 0) { - Vector3 combined_child_dir = Vector3(0, 0, 0); - for (int i = 0; i < child_bones.size(); i++) { - combined_child_dir += bones[child_bones[i]].rest.origin.normalized(); - } - combined_child_dir = combined_child_dir / child_bones.size(); - bones.write[p_bone].rest_bone_forward_vector = combined_child_dir.normalized(); - } else { - WARN_PRINT_ONCE("Cannot calculate forward direction for bone " + itos(p_bone)); - WARN_PRINT_ONCE("Assuming direction of (0, 1, 0) for bone"); - bones.write[p_bone].rest_bone_forward_vector = Vector3(0, 1, 0); - } - } - update_bone_rest_forward_axis(p_bone, p_force_update); -} - -void Skeleton3D::update_bone_rest_forward_axis(int p_bone, bool p_force_update) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - if (bones[p_bone].rest_bone_forward_axis > -1 && p_force_update == false) { - return; - } - - Vector3 forward_axis_absolute = bones[p_bone].rest_bone_forward_vector.abs(); - if (forward_axis_absolute.x > forward_axis_absolute.y && forward_axis_absolute.x > forward_axis_absolute.z) { - if (bones[p_bone].rest_bone_forward_vector.x > 0) { - bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_X_FORWARD; - } else { - bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_X_FORWARD; - } - } else if (forward_axis_absolute.y > forward_axis_absolute.x && forward_axis_absolute.y > forward_axis_absolute.z) { - if (bones[p_bone].rest_bone_forward_vector.y > 0) { - bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_Y_FORWARD; - } else { - bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_Y_FORWARD; - } - } else { - if (bones[p_bone].rest_bone_forward_vector.z > 0) { - bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_Z_FORWARD; - } else { - bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_Z_FORWARD; - } - } -} - -Vector3 Skeleton3D::get_bone_axis_forward_vector(int p_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, Vector3(0, 0, 0)); - return bones[p_bone].rest_bone_forward_vector; -} - -int Skeleton3D::get_bone_axis_forward_enum(int p_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, -1); - return bones[p_bone].rest_bone_forward_axis; -} - void Skeleton3D::set_motion_scale(float p_motion_scale) { if (p_motion_scale <= 0) { motion_scale = 1; @@ -503,6 +373,10 @@ float Skeleton3D::get_motion_scale() const { // Skeleton creation api +uint64_t Skeleton3D::get_version() const { + return version; +} + void Skeleton3D::add_bone(const String &p_name) { ERR_FAIL_COND(p_name.is_empty() || p_name.contains(":") || p_name.contains("/")); @@ -546,6 +420,7 @@ void Skeleton3D::set_bone_name(int p_bone, const String &p_name) { } bones.write[p_bone].name = p_name; + version++; } bool Skeleton3D::is_bone_parent_of(int p_bone, int p_parent_bone_id) const { @@ -1068,23 +943,10 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) { b.global_rest = b.parent >= 0 ? bonesptr[b.parent].global_rest * b.rest : b.rest; } - if (b.local_pose_override_amount >= CMP_EPSILON) { - Transform3D override_local_pose; - if (b.parent >= 0) { - override_local_pose = bonesptr[b.parent].pose_global * b.local_pose_override; - } else { - override_local_pose = b.local_pose_override; - } - b.pose_global = b.pose_global.interpolate_with(override_local_pose, b.local_pose_override_amount); - } - if (b.global_pose_override_amount >= CMP_EPSILON) { b.pose_global = b.pose_global.interpolate_with(b.global_pose_override, b.global_pose_override_amount); } - if (b.local_pose_override_reset) { - b.local_pose_override_amount = 0.0; - } if (b.global_pose_override_reset) { b.global_pose_override_amount = 0.0; } @@ -1100,100 +962,6 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) { rest_dirty = false; } -// Helper functions - -Transform3D Skeleton3D::global_pose_to_world_transform(Transform3D p_global_pose) { - return get_global_transform() * p_global_pose; -} - -Transform3D Skeleton3D::world_transform_to_global_pose(Transform3D p_world_transform) { - return get_global_transform().affine_inverse() * p_world_transform; -} - -Transform3D Skeleton3D::global_pose_to_local_pose(int p_bone_idx, Transform3D p_global_pose) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D()); - if (bones[p_bone_idx].parent >= 0) { - int parent_bone_idx = bones[p_bone_idx].parent; - Transform3D conversion_transform = get_bone_global_pose(parent_bone_idx).affine_inverse(); - return conversion_transform * p_global_pose; - } else { - return p_global_pose; - } -} - -Transform3D Skeleton3D::local_pose_to_global_pose(int p_bone_idx, Transform3D p_local_pose) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D()); - if (bones[p_bone_idx].parent >= 0) { - int parent_bone_idx = bones[p_bone_idx].parent; - return bones[parent_bone_idx].pose_global * p_local_pose; - } else { - return p_local_pose; - } -} - -Basis Skeleton3D::global_pose_z_forward_to_bone_forward(int p_bone_idx, Basis p_basis) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Basis()); - Basis return_basis = p_basis; - - if (bones[p_bone_idx].rest_bone_forward_axis < 0) { - update_bone_rest_forward_vector(p_bone_idx, true); - } - - if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_X_FORWARD) { - return_basis.rotate_local(Vector3(0, 1, 0), (Math_PI / 2.0)); - } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_X_FORWARD) { - return_basis.rotate_local(Vector3(0, 1, 0), -(Math_PI / 2.0)); - } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_Y_FORWARD) { - return_basis.rotate_local(Vector3(1, 0, 0), -(Math_PI / 2.0)); - } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_Y_FORWARD) { - return_basis.rotate_local(Vector3(1, 0, 0), (Math_PI / 2.0)); - } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_Z_FORWARD) { - // Do nothing! - } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_Z_FORWARD) { - return_basis.rotate_local(Vector3(0, 0, 1), Math_PI); - } - - return return_basis; -} - -// Modifications - -#ifndef _3D_DISABLED - -void Skeleton3D::set_modification_stack(Ref<SkeletonModificationStack3D> p_stack) { - if (modification_stack.is_valid()) { - modification_stack->is_setup = false; - modification_stack->set_skeleton(nullptr); - } - - modification_stack = p_stack; - if (modification_stack.is_valid()) { - modification_stack->set_skeleton(this); - modification_stack->setup(); - } -} -Ref<SkeletonModificationStack3D> Skeleton3D::get_modification_stack() { - return modification_stack; -} - -void Skeleton3D::execute_modifications(real_t p_delta, int p_execution_mode) { - if (!modification_stack.is_valid()) { - return; - } - - // Needed to avoid the issue where the stack looses reference to the skeleton when the scene is saved. - if (modification_stack->skeleton != this) { - modification_stack->set_skeleton(this); - } - - modification_stack->execute(p_delta, p_execution_mode); -} - -#endif // _3D_DISABLED - void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton3D::add_bone); ClassDB::bind_method(D_METHOD("find_bone", "name"), &Skeleton3D::find_bone); @@ -1204,6 +972,7 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bone_parent", "bone_idx", "parent_idx"), &Skeleton3D::set_bone_parent); ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton3D::get_bone_count); + ClassDB::bind_method(D_METHOD("get_version"), &Skeleton3D::get_version); ClassDB::bind_method(D_METHOD("unparent_bone_and_rest", "bone_idx"), &Skeleton3D::unparent_bone_and_rest); @@ -1243,23 +1012,12 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton3D::get_bone_global_pose); ClassDB::bind_method(D_METHOD("get_bone_global_pose_no_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_no_override); - ClassDB::bind_method(D_METHOD("clear_bones_local_pose_override"), &Skeleton3D::clear_bones_local_pose_override); - ClassDB::bind_method(D_METHOD("set_bone_local_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_local_pose_override, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_bone_local_pose_override", "bone_idx"), &Skeleton3D::get_bone_local_pose_override); - ClassDB::bind_method(D_METHOD("force_update_all_bone_transforms"), &Skeleton3D::force_update_all_bone_transforms); ClassDB::bind_method(D_METHOD("force_update_bone_child_transform", "bone_idx"), &Skeleton3D::force_update_bone_children_transforms); ClassDB::bind_method(D_METHOD("set_motion_scale", "motion_scale"), &Skeleton3D::set_motion_scale); ClassDB::bind_method(D_METHOD("get_motion_scale"), &Skeleton3D::get_motion_scale); - // Helper functions - ClassDB::bind_method(D_METHOD("global_pose_to_world_transform", "global_pose"), &Skeleton3D::global_pose_to_world_transform); - ClassDB::bind_method(D_METHOD("world_transform_to_global_pose", "world_transform"), &Skeleton3D::world_transform_to_global_pose); - ClassDB::bind_method(D_METHOD("global_pose_to_local_pose", "bone_idx", "global_pose"), &Skeleton3D::global_pose_to_local_pose); - ClassDB::bind_method(D_METHOD("local_pose_to_global_pose", "bone_idx", "local_pose"), &Skeleton3D::local_pose_to_global_pose); - ClassDB::bind_method(D_METHOD("global_pose_z_forward_to_bone_forward", "bone_idx", "basis"), &Skeleton3D::global_pose_z_forward_to_bone_forward); - ClassDB::bind_method(D_METHOD("set_show_rest_only", "enabled"), &Skeleton3D::set_show_rest_only); ClassDB::bind_method(D_METHOD("is_show_rest_only"), &Skeleton3D::is_show_rest_only); @@ -1271,11 +1029,6 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton3D::physical_bones_add_collision_exception); ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception); - // Modifications - ClassDB::bind_method(D_METHOD("set_modification_stack", "modification_stack"), &Skeleton3D::set_modification_stack); - ClassDB::bind_method(D_METHOD("get_modification_stack"), &Skeleton3D::get_modification_stack); - ClassDB::bind_method(D_METHOD("execute_modifications", "delta", "execution_mode"), &Skeleton3D::execute_modifications); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "motion_scale", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater"), "set_motion_scale", "get_motion_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_rest_only"), "set_show_rest_only", "is_show_rest_only"); #ifndef _3D_DISABLED diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index f66cc2f9ed..3df909d936 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -32,7 +32,6 @@ #define SKELETON_3D_H #include "scene/3d/node_3d.h" -#include "scene/resources/skeleton_modification_3d.h" #include "scene/resources/skin.h" typedef int BoneId; @@ -64,8 +63,6 @@ public: ~SkinReference(); }; -class SkeletonModificationStack3D; - class Skeleton3D : public Node3D { GDCLASS(Skeleton3D, Node3D); @@ -104,17 +101,8 @@ private: PhysicalBone3D *physical_bone = nullptr; PhysicalBone3D *cache_parent_physical_bone = nullptr; - real_t local_pose_override_amount; - bool local_pose_override_reset; - Transform3D local_pose_override; - Vector<int> child_bones; - // The forward direction vector and rest bone forward axis are cached because they do not change - // 99% of the time, but recalculating them can be expensive on models with many bones. - Vector3 rest_bone_forward_vector; - int rest_bone_forward_axis = -1; - Bone() { parent = -1; enabled = true; @@ -124,12 +112,7 @@ private: physical_bone = nullptr; cache_parent_physical_bone = nullptr; #endif // _3D_DISABLED - local_pose_override_amount = 0; - local_pose_override_reset = false; child_bones = Vector<int>(); - - rest_bone_forward_vector = Vector3(0, 0, 0); - rest_bone_forward_axis = -1; } }; @@ -162,25 +145,13 @@ protected: void _notification(int p_what); static void _bind_methods(); -#ifndef _3D_DISABLED - Ref<SkeletonModificationStack3D> modification_stack; -#endif // _3D_DISABLED - public: - enum Bone_Forward_Axis { - BONE_AXIS_X_FORWARD = 0, - BONE_AXIS_Y_FORWARD = 1, - BONE_AXIS_Z_FORWARD = 2, - BONE_AXIS_NEGATIVE_X_FORWARD = 3, - BONE_AXIS_NEGATIVE_Y_FORWARD = 4, - BONE_AXIS_NEGATIVE_Z_FORWARD = 5, - }; - enum { NOTIFICATION_UPDATE_SKELETON = 50 }; // skeleton creation api + uint64_t get_version() const; void add_bone(const String &p_name); int find_bone(const String &p_name) const; String get_bone_name(int p_bone) const; @@ -233,10 +204,6 @@ public: 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); - void clear_bones_local_pose_override(); - Transform3D get_bone_local_pose_override(int p_bone) const; - void set_bone_local_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false); - void localize_rests(); // used for loaders and tools Ref<Skin> create_skin_from_rest_transforms(); @@ -247,26 +214,6 @@ public: void force_update_all_bone_transforms(); void force_update_bone_children_transforms(int bone_idx); - void update_bone_rest_forward_vector(int p_bone, bool p_force_update = false); - void update_bone_rest_forward_axis(int p_bone, bool p_force_update = false); - Vector3 get_bone_axis_forward_vector(int p_bone); - int get_bone_axis_forward_enum(int p_bone); - - // Helper functions - Transform3D global_pose_to_world_transform(Transform3D p_global_pose); - Transform3D world_transform_to_global_pose(Transform3D p_transform); - Transform3D global_pose_to_local_pose(int p_bone_idx, Transform3D p_global_pose); - Transform3D local_pose_to_global_pose(int p_bone_idx, Transform3D p_local_pose); - - Basis global_pose_z_forward_to_bone_forward(int p_bone_idx, Basis p_basis); - - // Modifications -#ifndef _3D_DISABLED - Ref<SkeletonModificationStack3D> get_modification_stack(); - void set_modification_stack(Ref<SkeletonModificationStack3D> p_stack); - void execute_modifications(real_t p_delta, int p_execution_mode); -#endif // _3D_DISABLED - // Physical bone API void set_animate_physical_bones(bool p_enabled); diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp index f35cd3fbc5..75f54a925b 100644 --- a/scene/3d/skeleton_ik_3d.cpp +++ b/scene/3d/skeleton_ik_3d.cpp @@ -249,6 +249,26 @@ void FabrikInverseKinematic::make_goal(Task *p_task, const Transform3D &p_invers } } +static Vector3 get_bone_axis_forward_vector(Skeleton3D *skeleton, int p_bone) { + // If it is a child/leaf bone... + if (skeleton->get_bone_parent(p_bone) > 0) { + return skeleton->get_bone_rest(p_bone).origin.normalized(); + } + // If it has children... + Vector<int> child_bones = skeleton->get_bone_children(p_bone); + if (child_bones.size() == 0) { + WARN_PRINT_ONCE("Cannot calculate forward direction for bone " + itos(p_bone)); + WARN_PRINT_ONCE("Assuming direction of (0, 1, 0) for bone"); + return Vector3(0, 1, 0); + } + Vector3 combined_child_dir = Vector3(0, 0, 0); + for (int i = 0; i < child_bones.size(); i++) { + combined_child_dir += skeleton->get_bone_rest(child_bones[i]).origin.normalized(); + } + combined_child_dir = combined_child_dir / child_bones.size(); + return combined_child_dir.normalized(); +} + void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position) { if (blending_delta <= 0.01f) { // Before skipping, make sure we undo the global pose overrides @@ -287,8 +307,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove new_bone_pose.origin = ci->current_pos; if (!ci->children.is_empty()) { - p_task->skeleton->update_bone_rest_forward_vector(ci->bone); - Vector3 forward_vector = p_task->skeleton->get_bone_axis_forward_vector(ci->bone); + Vector3 forward_vector = get_bone_axis_forward_vector(p_task->skeleton, ci->bone); // Rotate the bone towards the next bone in the chain: new_bone_pose.basis.rotate_to_align(forward_vector, new_bone_pose.origin.direction_to(ci->children[0].current_pos)); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 4714282347..0771c7ef06 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -745,7 +745,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } break; case Animation::TYPE_METHOD: { - if (!nc->node) { + if (!nc->node || is_stopping) { continue; } if (!p_is_current) { @@ -808,7 +808,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } break; case Animation::TYPE_AUDIO: { - if (!nc->node) { + if (!nc->node || is_stopping) { continue; } @@ -915,6 +915,10 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } break; case Animation::TYPE_ANIMATION: { + if (is_stopping) { + continue; + } + AnimationPlayer *player = Object::cast_to<AnimationPlayer>(nc->node); if (!player) { continue; @@ -1658,7 +1662,7 @@ void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, floa } if (get_current_animation() != p_name) { - _stop_playing_caches(); + _stop_playing_caches(false); } c.current.from = &animation_set[name]; @@ -1808,7 +1812,7 @@ void AnimationPlayer::_animation_changed(const StringName &p_name) { } } -void AnimationPlayer::_stop_playing_caches() { +void AnimationPlayer::_stop_playing_caches(bool p_reset) { for (TrackNodeCache *E : playing_caches) { if (E->node && E->audio_playing) { E->node->call(SNAME("stop")); @@ -1818,7 +1822,12 @@ void AnimationPlayer::_stop_playing_caches() { if (!player) { continue; } - player->stop(); + + if (p_reset) { + player->stop(); + } else { + player->pause(); + } } } @@ -1830,7 +1839,7 @@ void AnimationPlayer::_node_removed(Node *p_node) { } void AnimationPlayer::clear_caches() { - _stop_playing_caches(); + _stop_playing_caches(true); node_cache_map.clear(); @@ -1952,13 +1961,15 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) { } void AnimationPlayer::_stop_internal(bool p_reset) { - _stop_playing_caches(); + _stop_playing_caches(p_reset); Playback &c = playback; c.blend.clear(); if (p_reset) { + is_stopping = true; + seek(0, true); + is_stopping = false; c.current.from = nullptr; c.current.speed_scale = 1; - c.current.pos = 0; } _set_process(false); queued.clear(); @@ -2089,7 +2100,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) { Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values(); old_values->restore(); - Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Animation 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 80ceb70d10..8dfa7aed27 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -192,6 +192,7 @@ private: uint64_t accum_pass = 1; float speed_scale = 1.0; double default_blend_time = 0.0; + bool is_stopping = false; struct AnimationData { String name; @@ -277,7 +278,7 @@ private: void _animation_process(double p_delta); void _node_removed(Node *p_node); - void _stop_playing_caches(); + void _stop_playing_caches(bool p_reset); // bind helpers Vector<String> _get_animation_list() const { diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index be8c23844f..39d1793368 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -280,7 +280,16 @@ bool Tween::step(double p_delta) { } if (!started) { - ERR_FAIL_COND_V_MSG(tweeners.is_empty(), false, "Tween started, but has no Tweeners."); + if (tweeners.is_empty()) { + String tween_id; + Node *node = get_bound_node(); + if (node) { + tween_id = vformat("Tween (bound to %s)", node->is_inside_tree() ? (String)node->get_path() : (String)node->get_name()); + } else { + tween_id = to_string(); + } + ERR_FAIL_V_MSG(false, tween_id + ": started with no Tweeners."); + } current_step = 0; loops_done = 0; total_time = 0; @@ -393,6 +402,15 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, d return ret; } +String Tween::to_string() { + String ret = Object::to_string(); + Node *node = get_bound_node(); + if (node) { + ret += vformat(" (bound to %s)", node->get_name()); + } + return ret; +} + void Tween::_bind_methods() { ClassDB::bind_method(D_METHOD("tween_property", "object", "property", "final_val", "duration"), &Tween::tween_property); ClassDB::bind_method(D_METHOD("tween_interval", "time"), &Tween::tween_interval); diff --git a/scene/animation/tween.h b/scene/animation/tween.h index 08911d6623..58217db535 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -130,6 +130,8 @@ protected: static void _bind_methods(); public: + virtual String to_string() override; + Ref<PropertyTweener> tween_property(Object *p_target, NodePath p_property, Variant p_to, double p_duration); Ref<IntervalTweener> tween_interval(double p_time); Ref<CallbackTweener> tween_callback(Callable p_callback); diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 9cc25bf743..d0326290ac 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -30,6 +30,7 @@ #include "base_button.h" +#include "core/config/project_settings.h" #include "core/os/keyboard.h" #include "scene/main/window.h" #include "scene/scene_string_names.h" @@ -127,7 +128,6 @@ void BaseButton::_notification(int p_what) { status.hovering = false; status.press_attempt = false; status.pressing_inside = false; - status.shortcut_press = false; } break; } } @@ -154,14 +154,10 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) { if (status.press_attempt && status.pressing_inside) { if (toggle_mode) { bool is_pressed = p_event->is_pressed(); - if (Object::cast_to<InputEventShortcut>(*p_event)) { - is_pressed = false; - } if ((is_pressed && action_mode == ACTION_MODE_BUTTON_PRESS) || (!is_pressed && action_mode == ACTION_MODE_BUTTON_RELEASE)) { if (action_mode == ACTION_MODE_BUTTON_PRESS) { status.press_attempt = false; status.pressing_inside = false; - status.shortcut_press = false; } status.pressed = !status.pressed; _unpress_group(); @@ -187,7 +183,6 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) { } status.press_attempt = false; status.pressing_inside = false; - status.shortcut_press = false; emit_signal(SNAME("button_up")); } @@ -212,7 +207,6 @@ void BaseButton::set_disabled(bool p_disabled) { } status.press_attempt = false; status.pressing_inside = false; - status.shortcut_press = false; } queue_redraw(); } @@ -267,6 +261,10 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const { return DRAW_DISABLED; } + if (in_shortcut_feedback) { + return DRAW_HOVER_PRESSED; + } + if (!status.press_attempt && status.hovering) { if (status.pressed) { return DRAW_HOVER_PRESSED; @@ -285,7 +283,7 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const { pressing = status.pressed; } - if ((shortcut_feedback || !status.shortcut_press) && pressing) { + if (pressing) { return DRAW_PRESSED; } else { return DRAW_NORMAL; @@ -339,6 +337,14 @@ bool BaseButton::is_keep_pressed_outside() const { return keep_pressed_outside; } +void BaseButton::set_shortcut_feedback(bool p_enable) { + shortcut_feedback = p_enable; +} + +bool BaseButton::is_shortcut_feedback() const { + return shortcut_feedback; +} + void BaseButton::set_shortcut(const Ref<Shortcut> &p_shortcut) { shortcut = p_shortcut; set_process_shortcut_input(shortcut.is_valid()); @@ -348,13 +354,45 @@ Ref<Shortcut> BaseButton::get_shortcut() const { return shortcut; } +void BaseButton::_shortcut_feedback_timeout() { + in_shortcut_feedback = false; + queue_redraw(); +} + void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->matches_event(p_event)) { - status.shortcut_press = true; - on_action_event(p_event); + if (!is_disabled() && p_event->is_pressed() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->matches_event(p_event)) { + if (toggle_mode) { + status.pressed = !status.pressed; + + if (status.pressed) { + _unpress_group(); + if (button_group.is_valid()) { + button_group->emit_signal(SNAME("pressed"), this); + } + } + + _toggled(status.pressed); + _pressed(); + + } else { + _pressed(); + } + queue_redraw(); accept_event(); + + if (shortcut_feedback) { + if (shortcut_feedback_timer == nullptr) { + shortcut_feedback_timer = memnew(Timer); + add_child(shortcut_feedback_timer); + shortcut_feedback_timer->set_wait_time(GLOBAL_GET("gui/timers/button_shortcut_feedback_highlight_time")); + shortcut_feedback_timer->connect("timeout", callable_mp(this, &BaseButton::_shortcut_feedback_timeout)); + } + + in_shortcut_feedback = true; + shortcut_feedback_timer->start(); + } } } @@ -393,14 +431,6 @@ bool BaseButton::_was_pressed_by_mouse() const { return was_mouse_pressed; } -void BaseButton::set_shortcut_feedback(bool p_feedback) { - shortcut_feedback = p_feedback; -} - -bool BaseButton::is_shortcut_feedback() const { - return shortcut_feedback; -} - PackedStringArray BaseButton::get_configuration_warnings() const { PackedStringArray warnings = Control::get_configuration_warnings(); @@ -429,6 +459,8 @@ void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_draw_mode"), &BaseButton::get_draw_mode); ClassDB::bind_method(D_METHOD("set_keep_pressed_outside", "enabled"), &BaseButton::set_keep_pressed_outside); ClassDB::bind_method(D_METHOD("is_keep_pressed_outside"), &BaseButton::is_keep_pressed_outside); + ClassDB::bind_method(D_METHOD("set_shortcut_feedback", "enabled"), &BaseButton::set_shortcut_feedback); + ClassDB::bind_method(D_METHOD("is_shortcut_feedback"), &BaseButton::is_shortcut_feedback); ClassDB::bind_method(D_METHOD("set_shortcut", "shortcut"), &BaseButton::set_shortcut); ClassDB::bind_method(D_METHOD("get_shortcut"), &BaseButton::get_shortcut); @@ -436,9 +468,6 @@ void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_button_group", "button_group"), &BaseButton::set_button_group); ClassDB::bind_method(D_METHOD("get_button_group"), &BaseButton::get_button_group); - ClassDB::bind_method(D_METHOD("set_shortcut_feedback", "enabled"), &BaseButton::set_shortcut_feedback); - ClassDB::bind_method(D_METHOD("is_shortcut_feedback"), &BaseButton::is_shortcut_feedback); - GDVIRTUAL_BIND(_pressed); GDVIRTUAL_BIND(_toggled, "button_pressed"); @@ -466,6 +495,8 @@ void BaseButton::_bind_methods() { BIND_ENUM_CONSTANT(ACTION_MODE_BUTTON_PRESS); BIND_ENUM_CONSTANT(ACTION_MODE_BUTTON_RELEASE); + + GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "gui/timers/button_shortcut_feedback_highlight_time", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), 0.2); } BaseButton::BaseButton() { diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index f7c864c5fb..962a16c453 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -51,9 +51,9 @@ private: bool shortcut_in_tooltip = true; bool was_mouse_pressed = false; bool keep_pressed_outside = false; + bool shortcut_feedback = true; Ref<Shortcut> shortcut; ObjectID shortcut_context; - bool shortcut_feedback = true; ActionMode action_mode = ACTION_MODE_BUTTON_RELEASE; struct Status { @@ -61,7 +61,6 @@ private: bool hovering = false; bool press_attempt = false; bool pressing_inside = false; - bool shortcut_press = false; bool disabled = false; @@ -75,6 +74,10 @@ private: void on_action_event(Ref<InputEvent> p_event); + Timer *shortcut_feedback_timer = nullptr; + bool in_shortcut_feedback = false; + void _shortcut_feedback_timeout(); + protected: virtual void pressed(); virtual void toggled(bool p_pressed); @@ -122,6 +125,9 @@ public: void set_keep_pressed_outside(bool p_on); bool is_keep_pressed_outside() const; + void set_shortcut_feedback(bool p_enable); + bool is_shortcut_feedback() const; + void set_button_mask(BitField<MouseButtonMask> p_mask); BitField<MouseButtonMask> get_button_mask() const; @@ -133,9 +139,6 @@ public: void set_button_group(const Ref<ButtonGroup> &p_group); Ref<ButtonGroup> get_button_group() const; - void set_shortcut_feedback(bool p_feedback); - bool is_shortcut_feedback() const; - PackedStringArray get_configuration_warnings() const override; BaseButton(); diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 7539810feb..4356e91e41 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -2086,9 +2086,11 @@ void CodeEdit::confirm_code_completion(bool p_replace) { int post_brace_pair = get_caret_column(i) < get_line(caret_line).length() ? _get_auto_brace_pair_close_at_pos(caret_line, get_caret_column(i)) : -1; // Strings do not nest like brackets, so ensure we don't add an additional closing pair. - if (has_string_delimiter(String::chr(last_completion_char)) && post_brace_pair != -1 && last_char_matches) { - remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1); - adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1); + if (has_string_delimiter(String::chr(last_completion_char))) { + if (post_brace_pair != -1 && last_char_matches) { + remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1); + adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1); + } } else { if (pre_brace_pair != -1 && pre_brace_pair != post_brace_pair && last_char_matches) { remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 4188946494..10dbad232a 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -758,6 +758,7 @@ void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos, } void Control::set_begin(const Size2 &p_point) { + ERR_FAIL_COND(!isfinite(p_point.x) || !isfinite(p_point.y)); if (data.offset[0] == p_point.x && data.offset[1] == p_point.y) { return; } @@ -1405,6 +1406,7 @@ void Control::_set_size(const Size2 &p_size) { } void Control::set_size(const Size2 &p_size, bool p_keep_offsets) { + ERR_FAIL_COND(!isfinite(p_size.x) || !isfinite(p_size.y)); Size2 new_size = p_size; Size2 min = get_combined_minimum_size(); if (new_size.x < min.x) { @@ -1595,7 +1597,7 @@ void Control::set_custom_minimum_size(const Size2 &p_custom) { return; } - if (isnan(p_custom.x) || isnan(p_custom.y)) { + if (!isfinite(p_custom.x) || !isfinite(p_custom.y)) { // Prevent infinite loop. return; } diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 2fd6d666e5..6c495ab2c9 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -1496,6 +1496,7 @@ float GraphEdit::get_zoom() const { void GraphEdit::set_zoom_step(float p_zoom_step) { p_zoom_step = abs(p_zoom_step); + ERR_FAIL_COND(!isfinite(p_zoom_step)); if (zoom_step == p_zoom_step) { return; } diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp index 5a3f4af106..20472ab46e 100644 --- a/scene/gui/texture_rect.cpp +++ b/scene/gui/texture_rect.cpp @@ -178,6 +178,16 @@ void TextureRect::_bind_methods() { BIND_ENUM_CONSTANT(STRETCH_KEEP_ASPECT_COVERED); } +#ifndef DISABLE_DEPRECATED +bool TextureRect::_set(const StringName &p_name, const Variant &p_value) { + if ((p_name == SNAME("expand") || p_name == SNAME("ignore_texture_size")) && p_value.operator bool()) { + expand_mode = EXPAND_IGNORE_SIZE; + return true; + } + return false; +} +#endif + void TextureRect::_texture_changed() { if (texture.is_valid()) { queue_redraw(); diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h index 6f17ebd87f..2425c6094b 100644 --- a/scene/gui/texture_rect.h +++ b/scene/gui/texture_rect.h @@ -69,6 +69,9 @@ protected: void _notification(int p_what); virtual Size2 get_minimum_size() const override; static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + bool _set(const StringName &p_name, const Variant &p_value); +#endif public: void set_texture(const Ref<Texture2D> &p_tex); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 3458b87b8d..2138f10ad0 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -657,7 +657,7 @@ int TreeItem::get_custom_minimum_height() const { /* Item manipulation */ -TreeItem *TreeItem::create_child(int p_idx) { +TreeItem *TreeItem::create_child(int p_index) { TreeItem *ti = memnew(TreeItem(tree)); if (tree) { ti->cells.resize(tree->columns.size()); @@ -669,7 +669,7 @@ TreeItem *TreeItem::create_child(int p_idx) { int idx = 0; while (c) { - if (idx++ == p_idx) { + if (idx++ == p_index) { c->prev = ti; ti->next = c; break; @@ -683,7 +683,7 @@ TreeItem *TreeItem::create_child(int p_idx) { ti->prev = l_prev; if (!children_cache.is_empty()) { if (ti->next) { - children_cache.insert(p_idx, ti); + children_cache.insert(p_index, ti); } else { children_cache.append(ti); } @@ -826,15 +826,15 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) { return next_item; } -TreeItem *TreeItem::get_child(int p_idx) { +TreeItem *TreeItem::get_child(int p_index) { _create_children_cache(); - if (p_idx < 0) { - p_idx += children_cache.size(); + if (p_index < 0) { + p_index += children_cache.size(); } - ERR_FAIL_INDEX_V(p_idx, children_cache.size(), nullptr); + ERR_FAIL_INDEX_V(p_index, children_cache.size(), nullptr); - return children_cache.get(p_idx); + return children_cache.get(p_index); } int TreeItem::get_visible_child_count() { @@ -1058,28 +1058,28 @@ int TreeItem::get_button_count(int p_column) const { return cells[p_column].buttons.size(); } -Ref<Texture2D> TreeItem::get_button(int p_column, int p_idx) const { +Ref<Texture2D> TreeItem::get_button(int p_column, int p_index) const { ERR_FAIL_INDEX_V(p_column, cells.size(), Ref<Texture2D>()); - ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), Ref<Texture2D>()); - return cells[p_column].buttons[p_idx].texture; + ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), Ref<Texture2D>()); + return cells[p_column].buttons[p_index].texture; } -String TreeItem::get_button_tooltip_text(int p_column, int p_idx) const { +String TreeItem::get_button_tooltip_text(int p_column, int p_index) const { ERR_FAIL_INDEX_V(p_column, cells.size(), String()); - ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), String()); - return cells[p_column].buttons[p_idx].tooltip; + ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), String()); + return cells[p_column].buttons[p_index].tooltip; } -int TreeItem::get_button_id(int p_column, int p_idx) const { +int TreeItem::get_button_id(int p_column, int p_index) const { ERR_FAIL_INDEX_V(p_column, cells.size(), -1); - ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), -1); - return cells[p_column].buttons[p_idx].id; + ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), -1); + return cells[p_column].buttons[p_index].id; } -void TreeItem::erase_button(int p_column, int p_idx) { +void TreeItem::erase_button(int p_column, int p_index) { ERR_FAIL_INDEX(p_column, cells.size()); - ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); - cells.write[p_column].buttons.remove_at(p_idx); + ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size()); + cells.write[p_column].buttons.remove_at(p_index); _changed_notify(p_column); } @@ -1094,52 +1094,52 @@ int TreeItem::get_button_by_id(int p_column, int p_id) const { return -1; } -void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture2D> &p_button) { +void TreeItem::set_button(int p_column, int p_index, const Ref<Texture2D> &p_button) { ERR_FAIL_COND(p_button.is_null()); ERR_FAIL_INDEX(p_column, cells.size()); - ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); + ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size()); - if (cells[p_column].buttons[p_idx].texture == p_button) { + if (cells[p_column].buttons[p_index].texture == p_button) { return; } - cells.write[p_column].buttons.write[p_idx].texture = p_button; + cells.write[p_column].buttons.write[p_index].texture = p_button; cells.write[p_column].cached_minimum_size_dirty = true; _changed_notify(p_column); } -void TreeItem::set_button_color(int p_column, int p_idx, const Color &p_color) { +void TreeItem::set_button_color(int p_column, int p_index, const Color &p_color) { ERR_FAIL_INDEX(p_column, cells.size()); - ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); + ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size()); - if (cells[p_column].buttons[p_idx].color == p_color) { + if (cells[p_column].buttons[p_index].color == p_color) { return; } - cells.write[p_column].buttons.write[p_idx].color = p_color; + cells.write[p_column].buttons.write[p_index].color = p_color; _changed_notify(p_column); } -void TreeItem::set_button_disabled(int p_column, int p_idx, bool p_disabled) { +void TreeItem::set_button_disabled(int p_column, int p_index, bool p_disabled) { ERR_FAIL_INDEX(p_column, cells.size()); - ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); + ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size()); - if (cells[p_column].buttons[p_idx].disabled == p_disabled) { + if (cells[p_column].buttons[p_index].disabled == p_disabled) { return; } - cells.write[p_column].buttons.write[p_idx].disabled = p_disabled; + cells.write[p_column].buttons.write[p_index].disabled = p_disabled; cells.write[p_column].cached_minimum_size_dirty = true; _changed_notify(p_column); } -bool TreeItem::is_button_disabled(int p_column, int p_idx) const { +bool TreeItem::is_button_disabled(int p_column, int p_index) const { ERR_FAIL_INDEX_V(p_column, cells.size(), false); - ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), false); + ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), false); - return cells[p_column].buttons[p_idx].disabled; + return cells[p_column].buttons[p_index].disabled; } void TreeItem::set_editable(int p_column, bool p_editable) { @@ -1497,15 +1497,15 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("add_button", "column", "button", "id", "disabled", "tooltip_text"), &TreeItem::add_button, DEFVAL(-1), DEFVAL(false), DEFVAL("")); ClassDB::bind_method(D_METHOD("get_button_count", "column"), &TreeItem::get_button_count); - ClassDB::bind_method(D_METHOD("get_button_tooltip_text", "column", "button_idx"), &TreeItem::get_button_tooltip_text); - ClassDB::bind_method(D_METHOD("get_button_id", "column", "button_idx"), &TreeItem::get_button_id); + ClassDB::bind_method(D_METHOD("get_button_tooltip_text", "column", "button_index"), &TreeItem::get_button_tooltip_text); + ClassDB::bind_method(D_METHOD("get_button_id", "column", "button_index"), &TreeItem::get_button_id); ClassDB::bind_method(D_METHOD("get_button_by_id", "column", "id"), &TreeItem::get_button_by_id); - ClassDB::bind_method(D_METHOD("get_button", "column", "button_idx"), &TreeItem::get_button); - ClassDB::bind_method(D_METHOD("set_button", "column", "button_idx", "button"), &TreeItem::set_button); - ClassDB::bind_method(D_METHOD("erase_button", "column", "button_idx"), &TreeItem::erase_button); - ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_idx", "disabled"), &TreeItem::set_button_disabled); - ClassDB::bind_method(D_METHOD("set_button_color", "column", "button_idx", "color"), &TreeItem::set_button_color); - ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled); + ClassDB::bind_method(D_METHOD("get_button", "column", "button_index"), &TreeItem::get_button); + ClassDB::bind_method(D_METHOD("set_button", "column", "button_index", "button"), &TreeItem::set_button); + ClassDB::bind_method(D_METHOD("erase_button", "column", "button_index"), &TreeItem::erase_button); + ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_index", "disabled"), &TreeItem::set_button_disabled); + ClassDB::bind_method(D_METHOD("set_button_color", "column", "button_index", "color"), &TreeItem::set_button_color); + ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_index"), &TreeItem::is_button_disabled); ClassDB::bind_method(D_METHOD("set_tooltip_text", "column", "tooltip"), &TreeItem::set_tooltip_text); ClassDB::bind_method(D_METHOD("get_tooltip_text", "column"), &TreeItem::get_tooltip_text); @@ -1518,7 +1518,7 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding); ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled); - ClassDB::bind_method(D_METHOD("create_child", "idx"), &TreeItem::create_child, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("create_child", "index"), &TreeItem::create_child, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_tree"), &TreeItem::get_tree); ClassDB::bind_method(D_METHOD("get_next"), &TreeItem::get_next); @@ -1529,7 +1529,7 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_next_visible", "wrap"), &TreeItem::get_next_visible, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_prev_visible", "wrap"), &TreeItem::get_prev_visible, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_child", "idx"), &TreeItem::get_child); + ClassDB::bind_method(D_METHOD("get_child", "index"), &TreeItem::get_child); ClassDB::bind_method(D_METHOD("get_child_count"), &TreeItem::get_child_count); ClassDB::bind_method(D_METHOD("get_children"), &TreeItem::get_children); ClassDB::bind_method(D_METHOD("get_index"), &TreeItem::get_index); @@ -4108,14 +4108,14 @@ Size2 Tree::get_minimum_size() const { } } -TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) { +TreeItem *Tree::create_item(TreeItem *p_parent, int p_index) { ERR_FAIL_COND_V(blocked > 0, nullptr); TreeItem *ti = nullptr; if (p_parent) { ERR_FAIL_COND_V_MSG(p_parent->tree != this, nullptr, "A different tree owns the given parent"); - ti = p_parent->create_child(p_idx); + ti = p_parent->create_child(p_index); } else { if (!root) { // No root exists, make the given item the new root. @@ -4126,7 +4126,7 @@ TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) { root = ti; } else { // Root exists, append or insert to root. - ti = create_item(root, p_idx); + ti = create_item(root, p_index); } } @@ -5162,7 +5162,7 @@ bool Tree::get_allow_reselect() const { void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("clear"), &Tree::clear); - ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::create_item, DEFVAL(Variant()), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("create_item", "parent", "index"), &Tree::create_item, DEFVAL(Variant()), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_root"), &Tree::get_root); ClassDB::bind_method(D_METHOD("set_column_custom_minimum_width", "column", "min_width"), &Tree::set_column_custom_minimum_width); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index e0ed5fdfb5..ec639ce439 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -247,15 +247,15 @@ public: void add_button(int p_column, const Ref<Texture2D> &p_button, int p_id = -1, bool p_disabled = false, const String &p_tooltip = ""); int get_button_count(int p_column) const; - String get_button_tooltip_text(int p_column, int p_idx) const; - Ref<Texture2D> get_button(int p_column, int p_idx) const; - int get_button_id(int p_column, int p_idx) const; - void erase_button(int p_column, int p_idx); + String get_button_tooltip_text(int p_column, int p_index) const; + Ref<Texture2D> get_button(int p_column, int p_index) const; + int get_button_id(int p_column, int p_index) const; + void erase_button(int p_column, int p_index); int get_button_by_id(int p_column, int p_id) const; - void set_button(int p_column, int p_idx, const Ref<Texture2D> &p_button); - void set_button_color(int p_column, int p_idx, const Color &p_color); - void set_button_disabled(int p_column, int p_idx, bool p_disabled); - bool is_button_disabled(int p_column, int p_idx) const; + void set_button(int p_column, int p_index, const Ref<Texture2D> &p_button); + void set_button_color(int p_column, int p_index, const Color &p_color); + void set_button_disabled(int p_column, int p_index, bool p_disabled); + bool is_button_disabled(int p_column, int p_index) const; /* range works for mode number or mode combo */ @@ -329,7 +329,7 @@ public: /* Item manipulation */ - TreeItem *create_child(int p_idx = -1); + TreeItem *create_child(int p_index = -1); Tree *get_tree() const; @@ -341,7 +341,7 @@ public: TreeItem *get_prev_visible(bool p_wrap = false); TreeItem *get_next_visible(bool p_wrap = false); - TreeItem *get_child(int p_idx); + TreeItem *get_child(int p_index); int get_visible_child_count(); int get_child_count(); TypedArray<TreeItem> get_children(); @@ -647,7 +647,7 @@ public: void clear(); - TreeItem *create_item(TreeItem *p_parent = nullptr, int p_idx = -1); + TreeItem *create_item(TreeItem *p_parent = nullptr, int p_index = -1); TreeItem *get_root() const; TreeItem *get_last_item() const; diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 05caad78a0..9be1a6431b 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -558,7 +558,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); if (p_filled) { - if (p_width != 1.0) { + if (p_width != -1.0) { WARN_PRINT("The draw_rect() \"width\" argument has no effect when \"filled\" is \"true\"."); } @@ -567,7 +567,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil // Thick lines are offset depending on their width to avoid partial overlapping. // Thin lines don't require an offset, so don't apply one in this case real_t offset; - if (p_width >= 2) { + if (p_width >= 0) { offset = p_width / 2.0; } else { offset = 0.0; @@ -647,11 +647,11 @@ void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p p_style_box->draw(canvas_item, p_rect); } -void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, real_t p_width) { +void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); - RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width); + RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid); } void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const Size2 &p_scale) { @@ -968,14 +968,14 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent); ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled); - ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("draw_dashed_line", "from", "to", "color", "width", "dash", "aligned"), &CanvasItem::draw_dashed_line, DEFVAL(1.0), DEFVAL(2.0), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(-1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("draw_dashed_line", "from", "to", "color", "width", "dash", "aligned"), &CanvasItem::draw_dashed_line, DEFVAL(-1.0), DEFVAL(2.0), DEFVAL(true)); ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &CanvasItem::draw_arc, DEFVAL(1.0), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(1.0)); - ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0)); - ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0)); + ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(-1.0)); + ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(-1.0)); + ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(-1.0)); ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle); ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false)); @@ -983,7 +983,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range", "scale"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0), DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("draw_lcd_texture_rect_region", "texture", "rect", "src_rect", "modulate"), &CanvasItem::draw_lcd_texture_rect_region, DEFVAL(Color(1, 1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box); - ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0)); + ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>())); ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>())); ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>())); ClassDB::bind_method(D_METHOD("draw_string", "font", "pos", "text", "alignment", "width", "font_size", "modulate", "jst_flags", "direction", "orientation"), &CanvasItem::draw_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(Font::DEFAULT_FONT_SIZE), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL)); diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 62357a1834..b2c12b2ea2 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -247,14 +247,14 @@ public: /* DRAWING API */ - void draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0, real_t p_dash = 2.0, bool p_aligned = true); - void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false); + void draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = -1.0, real_t p_dash = 2.0, bool p_aligned = true); + void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = -1.0, bool p_antialiased = false); void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false); void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0, bool p_antialiased = false); void draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false); - void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0); - void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0); - void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, real_t p_width = 1.0); + void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = -1.0); + void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = -1.0); + void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, real_t p_width = -1.0); void draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color); void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1)); void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false); @@ -262,7 +262,7 @@ public: void draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), double p_outline = 0.0, double p_pixel_range = 4.0, double p_scale = 1.0); void draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)); void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect); - void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), real_t p_width = 1); + void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>()); void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>()); void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>()); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index b5c587c0aa..fbe11c94d1 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1134,7 +1134,6 @@ Error SceneTree::change_scene_to_packed(const Ref<PackedScene> &p_scene) { ERR_FAIL_COND_V_MSG(p_scene.is_null(), ERR_INVALID_PARAMETER, "Can't change to a null scene. Use unload_current_scene() if you wish to unload it."); Node *new_scene = p_scene->instantiate(); - new_scene = p_scene->instantiate(); ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE); call_deferred(SNAME("_change_scene"), new_scene); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 7ca1f9d3ec..9c7e04c433 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1256,6 +1256,7 @@ void Viewport::_gui_show_tooltip() { panel->set_transient(true); panel->set_flag(Window::FLAG_NO_FOCUS, true); panel->set_flag(Window::FLAG_POPUP, false); + panel->set_flag(Window::FLAG_MOUSE_PASSTHROUGH, true); panel->set_wrap_controls(true); panel->add_child(base_tooltip); panel->gui_parent = this; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index c5dbfffd7b..4baedc8c14 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -489,6 +489,7 @@ void Window::_make_window() { ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); DisplayServer::get_singleton()->window_set_max_size(Size2i(), window_id); DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id); + DisplayServer::get_singleton()->window_set_mouse_passthrough(mpath, window_id); String tr_title = atr(title); #ifdef DEBUG_ENABLED if (window_id == DisplayServer::MAIN_WINDOW_ID) { @@ -1235,6 +1236,18 @@ DisplayServer::WindowID Window::get_window_id() const { return window_id; } +void Window::set_mouse_passthrough_polygon(const Vector<Vector2> &p_region) { + mpath = p_region; + if (window_id == DisplayServer::INVALID_WINDOW_ID) { + return; + } + DisplayServer::get_singleton()->window_set_mouse_passthrough(mpath, window_id); +} + +Vector<Vector2> Window::get_mouse_passthrough_polygon() const { + return mpath; +} + void Window::set_wrap_controls(bool p_enable) { wrap_controls = p_enable; if (wrap_controls) { @@ -2163,6 +2176,9 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &Window::set_use_font_oversampling); ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &Window::is_using_font_oversampling); + ClassDB::bind_method(D_METHOD("set_mouse_passthrough_polygon", "polygon"), &Window::set_mouse_passthrough_polygon); + ClassDB::bind_method(D_METHOD("get_mouse_passthrough_polygon"), &Window::get_mouse_passthrough_polygon); + ClassDB::bind_method(D_METHOD("set_wrap_controls", "enable"), &Window::set_wrap_controls); ClassDB::bind_method(D_METHOD("is_wrapping_controls"), &Window::is_wrapping_controls); ClassDB::bind_method(D_METHOD("child_controls_changed"), &Window::child_controls_changed); @@ -2243,6 +2259,8 @@ void Window::_bind_methods() { } ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen", PROPERTY_HINT_ENUM, screen_hints), "set_current_screen", "get_current_screen"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "mouse_passthrough_polygon"), "set_mouse_passthrough_polygon", "get_mouse_passthrough_polygon"); + ADD_GROUP("Flags", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_controls"), "set_wrap_controls", "is_wrapping_controls"); @@ -2255,6 +2273,7 @@ void Window::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable"), "set_flag", "get_flag", FLAG_NO_FOCUS); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_window"), "set_flag", "get_flag", FLAG_POPUP); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "extend_to_title"), "set_flag", "get_flag", FLAG_EXTEND_TO_TITLE); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "mouse_passthrough"), "set_flag", "get_flag", FLAG_MOUSE_PASSTHROUGH); ADD_GROUP("Limits", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size", PROPERTY_HINT_NONE, "suffix:px"), "set_min_size", "get_min_size"); @@ -2302,6 +2321,7 @@ void Window::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_NO_FOCUS); BIND_ENUM_CONSTANT(FLAG_POPUP); BIND_ENUM_CONSTANT(FLAG_EXTEND_TO_TITLE); + BIND_ENUM_CONSTANT(FLAG_MOUSE_PASSTHROUGH); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED); diff --git a/scene/main/window.h b/scene/main/window.h index b4887437a1..d819ca7c60 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -59,6 +59,7 @@ public: FLAG_NO_FOCUS = DisplayServer::WINDOW_FLAG_NO_FOCUS, FLAG_POPUP = DisplayServer::WINDOW_FLAG_POPUP, FLAG_EXTEND_TO_TITLE = DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE, + FLAG_MOUSE_PASSTHROUGH = DisplayServer::WINDOW_FLAG_MOUSE_PASSTHROUGH, FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX, }; @@ -101,6 +102,7 @@ private: mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE); mutable Size2i min_size; mutable Size2i max_size; + mutable Vector<Vector2> mpath; mutable Mode mode = MODE_WINDOWED; mutable bool flags[FLAG_MAX] = {}; bool visible = true; @@ -281,6 +283,9 @@ public: void set_use_font_oversampling(bool p_oversampling); bool is_using_font_oversampling() const; + void set_mouse_passthrough_polygon(const Vector<Vector2> &p_region); + Vector<Vector2> get_mouse_passthrough_polygon() const; + void set_wrap_controls(bool p_enable); bool is_wrapping_controls() const; void child_controls_changed(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 00c538976f..d56b94b6fe 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -184,15 +184,7 @@ #include "scene/resources/skeleton_modification_2d_physicalbones.h" #include "scene/resources/skeleton_modification_2d_stackholder.h" #include "scene/resources/skeleton_modification_2d_twoboneik.h" -#include "scene/resources/skeleton_modification_3d.h" -#include "scene/resources/skeleton_modification_3d_ccdik.h" -#include "scene/resources/skeleton_modification_3d_fabrik.h" -#include "scene/resources/skeleton_modification_3d_jiggle.h" -#include "scene/resources/skeleton_modification_3d_lookat.h" -#include "scene/resources/skeleton_modification_3d_stackholder.h" -#include "scene/resources/skeleton_modification_3d_twoboneik.h" #include "scene/resources/skeleton_modification_stack_2d.h" -#include "scene/resources/skeleton_modification_stack_3d.h" #include "scene/resources/skeleton_profile.h" #include "scene/resources/sky.h" #include "scene/resources/sky_material.h" @@ -833,15 +825,6 @@ void register_scene_types() { GDREGISTER_CLASS(ConvexPolygonShape3D); GDREGISTER_CLASS(ConcavePolygonShape3D); - GDREGISTER_CLASS(SkeletonModificationStack3D); - GDREGISTER_CLASS(SkeletonModification3D); - GDREGISTER_CLASS(SkeletonModification3DLookAt); - GDREGISTER_CLASS(SkeletonModification3DCCDIK); - GDREGISTER_CLASS(SkeletonModification3DFABRIK); - GDREGISTER_CLASS(SkeletonModification3DJiggle); - GDREGISTER_CLASS(SkeletonModification3DTwoBoneIK); - GDREGISTER_CLASS(SkeletonModification3DStackHolder); - OS::get_singleton()->yield(); // may take time to init #endif // _3D_DISABLED diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp index d92d4fa4a4..e51b48a4b1 100644 --- a/scene/resources/convex_polygon_shape_2d.cpp +++ b/scene/resources/convex_polygon_shape_2d.cpp @@ -82,7 +82,7 @@ void ConvexPolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) { if (is_collision_outline_enabled()) { RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`. - RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color, 1.0, true); + RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color, 1.0); } } diff --git a/scene/resources/skeleton_modification_3d.cpp b/scene/resources/skeleton_modification_3d.cpp deleted file mode 100644 index 92fb4bfd78..0000000000 --- a/scene/resources/skeleton_modification_3d.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 "skeleton_modification_3d.h" -#include "scene/3d/skeleton_3d.h" - -void SkeletonModification3D::_execute(real_t p_delta) { - GDVIRTUAL_CALL(_execute, p_delta); - - if (!enabled) { - return; - } -} - -void SkeletonModification3D::_setup_modification(SkeletonModificationStack3D *p_stack) { - stack = p_stack; - if (stack) { - is_setup = true; - } else { - WARN_PRINT("Could not setup modification with name " + this->get_name()); - } - - GDVIRTUAL_CALL(_setup_modification, Ref<SkeletonModificationStack3D>(p_stack)); -} - -void SkeletonModification3D::set_enabled(bool p_enabled) { - enabled = p_enabled; -} - -bool SkeletonModification3D::get_enabled() { - return enabled; -} - -// Helper function. Needed for CCDIK. -real_t SkeletonModification3D::clamp_angle(real_t p_angle, real_t p_min_bound, real_t p_max_bound, bool p_invert) { - // Map to the 0 to 360 range (in radians though) instead of the -180 to 180 range. - if (p_angle < 0) { - p_angle = Math_TAU + p_angle; - } - - // Make min and max in the range of 0 to 360 (in radians), and make sure they are in the right order - if (p_min_bound < 0) { - p_min_bound = Math_TAU + p_min_bound; - } - if (p_max_bound < 0) { - p_max_bound = Math_TAU + p_max_bound; - } - if (p_min_bound > p_max_bound) { - SWAP(p_min_bound, p_max_bound); - } - - bool is_beyond_bounds = (p_angle < p_min_bound || p_angle > p_max_bound); - bool is_within_bounds = (p_angle > p_min_bound && p_angle < p_max_bound); - - // Note: May not be the most optimal way to clamp, but it always constraints to the nearest angle. - if ((!p_invert && is_beyond_bounds) || (p_invert && is_within_bounds)) { - Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound)); - Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound)); - Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle)); - - if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) { - p_angle = p_min_bound; - } else { - p_angle = p_max_bound; - } - } - - return p_angle; -} - -bool SkeletonModification3D::_print_execution_error(bool p_condition, String p_message) { - // If the modification is not setup, don't bother printing the error - if (!is_setup) { - return p_condition; - } - - if (p_condition && !execution_error_found) { - ERR_PRINT(p_message); - execution_error_found = true; - } - return p_condition; -} - -Ref<SkeletonModificationStack3D> SkeletonModification3D::get_modification_stack() { - return stack; -} - -void SkeletonModification3D::set_is_setup(bool p_is_setup) { - is_setup = p_is_setup; -} - -bool SkeletonModification3D::get_is_setup() const { - return is_setup; -} - -void SkeletonModification3D::set_execution_mode(int p_mode) { - execution_mode = p_mode; -} - -int SkeletonModification3D::get_execution_mode() const { - return execution_mode; -} - -void SkeletonModification3D::_bind_methods() { - GDVIRTUAL_BIND(_execute, "delta"); - GDVIRTUAL_BIND(_setup_modification, "modification_stack") - - ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModification3D::set_enabled); - ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModification3D::get_enabled); - ClassDB::bind_method(D_METHOD("get_modification_stack"), &SkeletonModification3D::get_modification_stack); - ClassDB::bind_method(D_METHOD("set_is_setup", "is_setup"), &SkeletonModification3D::set_is_setup); - ClassDB::bind_method(D_METHOD("get_is_setup"), &SkeletonModification3D::get_is_setup); - ClassDB::bind_method(D_METHOD("set_execution_mode", "execution_mode"), &SkeletonModification3D::set_execution_mode); - ClassDB::bind_method(D_METHOD("get_execution_mode"), &SkeletonModification3D::get_execution_mode); - ClassDB::bind_method(D_METHOD("clamp_angle", "angle", "min", "max", "invert"), &SkeletonModification3D::clamp_angle); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process,physics_process"), "set_execution_mode", "get_execution_mode"); -} - -SkeletonModification3D::SkeletonModification3D() { - stack = nullptr; - is_setup = false; -} diff --git a/scene/resources/skeleton_modification_3d.h b/scene/resources/skeleton_modification_3d.h deleted file mode 100644 index 367adbd977..0000000000 --- a/scene/resources/skeleton_modification_3d.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 SKELETON_MODIFICATION_3D_H -#define SKELETON_MODIFICATION_3D_H - -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_stack_3d.h" - -class SkeletonModificationStack3D; - -class SkeletonModification3D : public Resource { - GDCLASS(SkeletonModification3D, Resource); - friend class Skeleton3D; - friend class SkeletonModificationStack3D; - -protected: - static void _bind_methods(); - - SkeletonModificationStack3D *stack = nullptr; - int execution_mode = 0; // 0 = process - - bool enabled = true; - bool is_setup = false; - bool execution_error_found = false; - - bool _print_execution_error(bool p_condition, String p_message); - - GDVIRTUAL1(_execute, double) - GDVIRTUAL1(_setup_modification, Ref<SkeletonModificationStack3D>) - -public: - virtual void _execute(real_t p_delta); - virtual void _setup_modification(SkeletonModificationStack3D *p_stack); - - real_t clamp_angle(real_t p_angle, real_t p_min_bound, real_t p_max_bound, bool p_invert); - - void set_enabled(bool p_enabled); - bool get_enabled(); - - void set_execution_mode(int p_mode); - int get_execution_mode() const; - - Ref<SkeletonModificationStack3D> get_modification_stack(); - - void set_is_setup(bool p_setup); - bool get_is_setup() const; - - SkeletonModification3D(); -}; - -#endif // SKELETON_MODIFICATION_3D_H diff --git a/scene/resources/skeleton_modification_3d_ccdik.cpp b/scene/resources/skeleton_modification_3d_ccdik.cpp deleted file mode 100644 index b5c930f970..0000000000 --- a/scene/resources/skeleton_modification_3d_ccdik.cpp +++ /dev/null @@ -1,474 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_ccdik.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 "scene/resources/skeleton_modification_3d_ccdik.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -bool SkeletonModification3DCCDIK::_set(const StringName &p_path, const Variant &p_value) { - String path = p_path; - - if (path.begins_with("joint_data/")) { - int ccdik_data_size = ccdik_data_chain.size(); - int which = path.get_slicec('/', 1).to_int(); - String what = path.get_slicec('/', 2); - ERR_FAIL_INDEX_V(which, ccdik_data_size, false); - - if (what == "bone_name") { - set_ccdik_joint_bone_name(which, p_value); - } else if (what == "bone_index") { - set_ccdik_joint_bone_index(which, p_value); - } else if (what == "ccdik_axis") { - set_ccdik_joint_ccdik_axis(which, p_value); - } else if (what == "enable_joint_constraint") { - set_ccdik_joint_enable_constraint(which, p_value); - } else if (what == "joint_constraint_angle_min") { - set_ccdik_joint_constraint_angle_min(which, Math::deg_to_rad(real_t(p_value))); - } else if (what == "joint_constraint_angle_max") { - set_ccdik_joint_constraint_angle_max(which, Math::deg_to_rad(real_t(p_value))); - } else if (what == "joint_constraint_angles_invert") { - set_ccdik_joint_constraint_invert(which, p_value); - } - return true; - } - return true; -} - -bool SkeletonModification3DCCDIK::_get(const StringName &p_path, Variant &r_ret) const { - String path = p_path; - - if (path.begins_with("joint_data/")) { - const int ccdik_data_size = ccdik_data_chain.size(); - int which = path.get_slicec('/', 1).to_int(); - String what = path.get_slicec('/', 2); - ERR_FAIL_INDEX_V(which, ccdik_data_size, false); - - if (what == "bone_name") { - r_ret = get_ccdik_joint_bone_name(which); - } else if (what == "bone_index") { - r_ret = get_ccdik_joint_bone_index(which); - } else if (what == "ccdik_axis") { - r_ret = get_ccdik_joint_ccdik_axis(which); - } else if (what == "enable_joint_constraint") { - r_ret = get_ccdik_joint_enable_constraint(which); - } else if (what == "joint_constraint_angle_min") { - r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_min(which)); - } else if (what == "joint_constraint_angle_max") { - r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_max(which)); - } else if (what == "joint_constraint_angles_invert") { - r_ret = get_ccdik_joint_constraint_invert(which); - } - return true; - } - return true; -} - -void SkeletonModification3DCCDIK::_get_property_list(List<PropertyInfo> *p_list) const { - for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) { - String base_string = "joint_data/" + itos(i) + "/"; - - p_list->push_back(PropertyInfo(Variant::STRING_NAME, base_string + "bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - - p_list->push_back(PropertyInfo(Variant::INT, base_string + "ccdik_axis", - PROPERTY_HINT_ENUM, "X Axis,Y Axis,Z Axis", PROPERTY_USAGE_DEFAULT)); - - p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "enable_joint_constraint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - if (ccdik_data_chain[i].enable_constraint) { - p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "joint_constraint_angle_min", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "joint_constraint_angle_max", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "joint_constraint_angles_invert", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - } - } -} - -void SkeletonModification3DCCDIK::_execute(real_t p_delta) { - ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, - "Modification is not setup and therefore cannot execute!"); - if (!enabled) { - return; - } - - if (target_node_cache.is_null()) { - _print_execution_error(true, "Target cache is out of date. Attempting to update"); - update_target_cache(); - return; - } - if (tip_node_cache.is_null()) { - _print_execution_error(true, "Tip cache is out of date. Attempting to update"); - update_tip_cache(); - return; - } - - // Reset the local bone overrides for CCDIK affected nodes - for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) { - stack->skeleton->set_bone_local_pose_override(ccdik_data_chain[i].bone_idx, - stack->skeleton->get_bone_local_pose_override(ccdik_data_chain[i].bone_idx), - 0.0, false); - } - - Node3D *node_target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache)); - Node3D *node_tip = Object::cast_to<Node3D>(ObjectDB::get_instance(tip_node_cache)); - - if (_print_execution_error(!node_target || !node_target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) { - return; - } - if (_print_execution_error(!node_tip || !node_tip->is_inside_tree(), "Tip node is not in the scene tree. Cannot execute modification!")) { - return; - } - - if (use_high_quality_solve) { - for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) { - for (uint32_t j = i; j < ccdik_data_chain.size(); j++) { - _execute_ccdik_joint(j, node_target, node_tip); - } - } - } else { - for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) { - _execute_ccdik_joint(i, node_target, node_tip); - } - } - - execution_error_found = false; -} - -void SkeletonModification3DCCDIK::_execute_ccdik_joint(int p_joint_idx, Node3D *p_target, Node3D *p_tip) { - CCDIK_Joint_Data ccdik_data = ccdik_data_chain[p_joint_idx]; - - if (_print_execution_error(ccdik_data.bone_idx < 0 || ccdik_data.bone_idx > stack->skeleton->get_bone_count(), - "CCDIK joint: bone index for joint" + itos(p_joint_idx) + " not found. Cannot execute modification!")) { - return; - } - - Transform3D bone_trans = stack->skeleton->global_pose_to_local_pose(ccdik_data.bone_idx, stack->skeleton->get_bone_global_pose(ccdik_data.bone_idx)); - Transform3D tip_trans = stack->skeleton->global_pose_to_local_pose(ccdik_data.bone_idx, stack->skeleton->world_transform_to_global_pose(p_tip->get_global_transform())); - Transform3D target_trans = stack->skeleton->global_pose_to_local_pose(ccdik_data.bone_idx, stack->skeleton->world_transform_to_global_pose(p_target->get_global_transform())); - - if (tip_trans.origin.distance_to(target_trans.origin) <= 0.01) { - return; - } - - // Inspired (and very loosely based on) by the CCDIK algorithm made by Zalo on GitHub (https://github.com/zalo/MathUtilities) - // Convert the 3D position to a 2D position so we can use Atan2 (via the angle function) - // to know how much rotation we need on the given axis to place the tip at the target. - Vector2 tip_pos_2d; - Vector2 target_pos_2d; - if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_X) { - tip_pos_2d = Vector2(tip_trans.origin.y, tip_trans.origin.z); - target_pos_2d = Vector2(target_trans.origin.y, target_trans.origin.z); - bone_trans.basis.rotate_local(Vector3(1, 0, 0), target_pos_2d.angle() - tip_pos_2d.angle()); - } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Y) { - tip_pos_2d = Vector2(tip_trans.origin.z, tip_trans.origin.x); - target_pos_2d = Vector2(target_trans.origin.z, target_trans.origin.x); - bone_trans.basis.rotate_local(Vector3(0, 1, 0), target_pos_2d.angle() - tip_pos_2d.angle()); - } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Z) { - tip_pos_2d = Vector2(tip_trans.origin.x, tip_trans.origin.y); - target_pos_2d = Vector2(target_trans.origin.x, target_trans.origin.y); - bone_trans.basis.rotate_local(Vector3(0, 0, 1), target_pos_2d.angle() - tip_pos_2d.angle()); - } else { - // Should never happen, but... - ERR_FAIL_MSG("CCDIK joint: Unknown axis vector passed for joint" + itos(p_joint_idx) + ". Cannot execute modification!"); - } - - if (ccdik_data.enable_constraint) { - Vector3 rotation_axis; - real_t rotation_angle; - bone_trans.basis.get_axis_angle(rotation_axis, rotation_angle); - - // Note: When the axis has a negative direction, the angle is OVER 180 degrees and therefore we need to account for this - // when constraining. - if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_X) { - if (rotation_axis.x < 0) { - rotation_angle += Math_PI; - rotation_axis = Vector3(1, 0, 0); - } - } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Y) { - if (rotation_axis.y < 0) { - rotation_angle += Math_PI; - rotation_axis = Vector3(0, 1, 0); - } - } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Z) { - if (rotation_axis.z < 0) { - rotation_angle += Math_PI; - rotation_axis = Vector3(0, 0, 1); - } - } else { - // Should never happen, but... - ERR_FAIL_MSG("CCDIK joint: Unknown axis vector passed for joint" + itos(p_joint_idx) + ". Cannot execute modification!"); - } - rotation_angle = clamp_angle(rotation_angle, ccdik_data.constraint_angle_min, ccdik_data.constraint_angle_max, ccdik_data.constraint_angles_invert); - - bone_trans.basis.set_axis_angle(rotation_axis, rotation_angle); - } - - stack->skeleton->set_bone_local_pose_override(ccdik_data.bone_idx, bone_trans, stack->strength, true); - stack->skeleton->force_update_bone_children_transforms(ccdik_data.bone_idx); -} - -void SkeletonModification3DCCDIK::_setup_modification(SkeletonModificationStack3D *p_stack) { - stack = p_stack; - if (stack != nullptr) { - is_setup = true; - execution_error_found = false; - update_target_cache(); - update_tip_cache(); - } -} - -void SkeletonModification3DCCDIK::update_target_cache() { - if (!is_setup || !stack) { - _print_execution_error(true, "Cannot update target cache: modification is not properly setup!"); - return; - } - - target_node_cache = ObjectID(); - if (stack->skeleton) { - if (stack->skeleton->is_inside_tree()) { - if (stack->skeleton->has_node(target_node)) { - Node *node = stack->skeleton->get_node(target_node); - ERR_FAIL_COND_MSG(!node || stack->skeleton == node, - "Cannot update target cache: node is this modification's skeleton or cannot be found!"); - ERR_FAIL_COND_MSG(!node->is_inside_tree(), - "Cannot update target cache: node is not in scene tree!"); - target_node_cache = node->get_instance_id(); - - execution_error_found = false; - } - } - } -} - -void SkeletonModification3DCCDIK::update_tip_cache() { - if (!is_setup || !stack) { - _print_execution_error(true, "Cannot update tip cache: modification is not properly setup!"); - return; - } - - tip_node_cache = ObjectID(); - if (stack->skeleton) { - if (stack->skeleton->is_inside_tree()) { - if (stack->skeleton->has_node(tip_node)) { - Node *node = stack->skeleton->get_node(tip_node); - ERR_FAIL_COND_MSG(!node || stack->skeleton == node, - "Cannot update tip cache: node is this modification's skeleton or cannot be found!"); - ERR_FAIL_COND_MSG(!node->is_inside_tree(), - "Cannot update tip cache: node is not in scene tree!"); - tip_node_cache = node->get_instance_id(); - - execution_error_found = false; - } - } - } -} - -void SkeletonModification3DCCDIK::set_target_node(const NodePath &p_target_node) { - target_node = p_target_node; - update_target_cache(); -} - -NodePath SkeletonModification3DCCDIK::get_target_node() const { - return target_node; -} - -void SkeletonModification3DCCDIK::set_tip_node(const NodePath &p_tip_node) { - tip_node = p_tip_node; - update_tip_cache(); -} - -NodePath SkeletonModification3DCCDIK::get_tip_node() const { - return tip_node; -} - -void SkeletonModification3DCCDIK::set_use_high_quality_solve(bool p_high_quality) { - use_high_quality_solve = p_high_quality; -} - -bool SkeletonModification3DCCDIK::get_use_high_quality_solve() const { - return use_high_quality_solve; -} - -// CCDIK joint data functions -String SkeletonModification3DCCDIK::get_ccdik_joint_bone_name(int p_joint_idx) const { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, String()); - return ccdik_data_chain[p_joint_idx].bone_name; -} - -void SkeletonModification3DCCDIK::set_ccdik_joint_bone_name(int p_joint_idx, String p_bone_name) { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - ccdik_data_chain[p_joint_idx].bone_name = p_bone_name; - - if (stack) { - if (stack->skeleton) { - ccdik_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(p_bone_name); - } - } - execution_error_found = false; - notify_property_list_changed(); -} - -int SkeletonModification3DCCDIK::get_ccdik_joint_bone_index(int p_joint_idx) const { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1); - return ccdik_data_chain[p_joint_idx].bone_idx; -} - -void SkeletonModification3DCCDIK::set_ccdik_joint_bone_index(int p_joint_idx, int p_bone_idx) { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!"); - ccdik_data_chain[p_joint_idx].bone_idx = p_bone_idx; - - if (stack) { - if (stack->skeleton) { - ccdik_data_chain[p_joint_idx].bone_name = stack->skeleton->get_bone_name(p_bone_idx); - } - } - execution_error_found = false; - notify_property_list_changed(); -} - -int SkeletonModification3DCCDIK::get_ccdik_joint_ccdik_axis(int p_joint_idx) const { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1); - return ccdik_data_chain[p_joint_idx].ccdik_axis; -} - -void SkeletonModification3DCCDIK::set_ccdik_joint_ccdik_axis(int p_joint_idx, int p_axis) { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - ERR_FAIL_COND_MSG(p_axis < 0, "CCDIK axis is out of range: The axis mode is too low!"); - ccdik_data_chain[p_joint_idx].ccdik_axis = p_axis; - notify_property_list_changed(); -} - -bool SkeletonModification3DCCDIK::get_ccdik_joint_enable_constraint(int p_joint_idx) const { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false); - return ccdik_data_chain[p_joint_idx].enable_constraint; -} - -void SkeletonModification3DCCDIK::set_ccdik_joint_enable_constraint(int p_joint_idx, bool p_enable) { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - ccdik_data_chain[p_joint_idx].enable_constraint = p_enable; - notify_property_list_changed(); -} - -real_t SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_min(int p_joint_idx) const { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false); - return ccdik_data_chain[p_joint_idx].constraint_angle_min; -} - -void SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_min(int p_joint_idx, real_t p_angle_min) { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - ccdik_data_chain[p_joint_idx].constraint_angle_min = p_angle_min; -} - -real_t SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_max(int p_joint_idx) const { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false); - return ccdik_data_chain[p_joint_idx].constraint_angle_max; -} - -void SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_max(int p_joint_idx, real_t p_angle_max) { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - ccdik_data_chain[p_joint_idx].constraint_angle_max = p_angle_max; -} - -bool SkeletonModification3DCCDIK::get_ccdik_joint_constraint_invert(int p_joint_idx) const { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false); - return ccdik_data_chain[p_joint_idx].constraint_angles_invert; -} - -void SkeletonModification3DCCDIK::set_ccdik_joint_constraint_invert(int p_joint_idx, bool p_invert) { - const int bone_chain_size = ccdik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - ccdik_data_chain[p_joint_idx].constraint_angles_invert = p_invert; -} - -int SkeletonModification3DCCDIK::get_ccdik_data_chain_length() { - return ccdik_data_chain.size(); -} -void SkeletonModification3DCCDIK::set_ccdik_data_chain_length(int p_length) { - ERR_FAIL_COND(p_length < 0); - ccdik_data_chain.resize(p_length); - execution_error_found = false; - notify_property_list_changed(); -} - -void SkeletonModification3DCCDIK::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DCCDIK::set_target_node); - ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DCCDIK::get_target_node); - - ClassDB::bind_method(D_METHOD("set_tip_node", "tip_nodepath"), &SkeletonModification3DCCDIK::set_tip_node); - ClassDB::bind_method(D_METHOD("get_tip_node"), &SkeletonModification3DCCDIK::get_tip_node); - - ClassDB::bind_method(D_METHOD("set_use_high_quality_solve", "high_quality_solve"), &SkeletonModification3DCCDIK::set_use_high_quality_solve); - ClassDB::bind_method(D_METHOD("get_use_high_quality_solve"), &SkeletonModification3DCCDIK::get_use_high_quality_solve); - - // CCDIK joint data functions - ClassDB::bind_method(D_METHOD("get_ccdik_joint_bone_name", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_bone_name); - ClassDB::bind_method(D_METHOD("set_ccdik_joint_bone_name", "joint_idx", "bone_name"), &SkeletonModification3DCCDIK::set_ccdik_joint_bone_name); - ClassDB::bind_method(D_METHOD("get_ccdik_joint_bone_index", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_bone_index); - ClassDB::bind_method(D_METHOD("set_ccdik_joint_bone_index", "joint_idx", "bone_index"), &SkeletonModification3DCCDIK::set_ccdik_joint_bone_index); - ClassDB::bind_method(D_METHOD("get_ccdik_joint_ccdik_axis", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_ccdik_axis); - ClassDB::bind_method(D_METHOD("set_ccdik_joint_ccdik_axis", "joint_idx", "axis"), &SkeletonModification3DCCDIK::set_ccdik_joint_ccdik_axis); - ClassDB::bind_method(D_METHOD("get_ccdik_joint_enable_joint_constraint", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_enable_constraint); - ClassDB::bind_method(D_METHOD("set_ccdik_joint_enable_joint_constraint", "joint_idx", "enable"), &SkeletonModification3DCCDIK::set_ccdik_joint_enable_constraint); - ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_min", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_min); - ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_min", "joint_idx", "min_angle"), &SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_min); - ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_max", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_max); - ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_max", "joint_idx", "max_angle"), &SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_max); - ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_invert", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_constraint_invert); - ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_invert", "joint_idx", "invert"), &SkeletonModification3DCCDIK::set_ccdik_joint_constraint_invert); - - ClassDB::bind_method(D_METHOD("set_ccdik_data_chain_length", "length"), &SkeletonModification3DCCDIK::set_ccdik_data_chain_length); - ClassDB::bind_method(D_METHOD("get_ccdik_data_chain_length"), &SkeletonModification3DCCDIK::get_ccdik_data_chain_length); - - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "tip_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_tip_node", "get_tip_node"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "high_quality_solve", PROPERTY_HINT_NONE, ""), "set_use_high_quality_solve", "get_use_high_quality_solve"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "ccdik_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_ccdik_data_chain_length", "get_ccdik_data_chain_length"); -} - -SkeletonModification3DCCDIK::SkeletonModification3DCCDIK() { - stack = nullptr; - is_setup = false; - enabled = true; -} - -SkeletonModification3DCCDIK::~SkeletonModification3DCCDIK() { -} diff --git a/scene/resources/skeleton_modification_3d_ccdik.h b/scene/resources/skeleton_modification_3d_ccdik.h deleted file mode 100644 index 30c29bb3aa..0000000000 --- a/scene/resources/skeleton_modification_3d_ccdik.h +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_ccdik.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 SKELETON_MODIFICATION_3D_CCDIK_H -#define SKELETON_MODIFICATION_3D_CCDIK_H - -#include "core/templates/local_vector.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -class SkeletonModification3DCCDIK : public SkeletonModification3D { - GDCLASS(SkeletonModification3DCCDIK, SkeletonModification3D); - -private: - enum CCDIK_Axes { - AXIS_X, - AXIS_Y, - AXIS_Z - }; - - struct CCDIK_Joint_Data { - String bone_name = ""; - int bone_idx = -1; - int ccdik_axis = 0; - - bool enable_constraint = false; - real_t constraint_angle_min = 0; - real_t constraint_angle_max = (2.0 * Math_PI); - bool constraint_angles_invert = false; - }; - - LocalVector<CCDIK_Joint_Data> ccdik_data_chain; - NodePath target_node; - ObjectID target_node_cache; - - NodePath tip_node; - ObjectID tip_node_cache; - - bool use_high_quality_solve = true; - - void update_target_cache(); - void update_tip_cache(); - - void _execute_ccdik_joint(int p_joint_idx, Node3D *p_target, Node3D *p_tip); - -protected: - static void _bind_methods(); - 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; - -public: - virtual void _execute(real_t p_delta) override; - virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override; - - void set_target_node(const NodePath &p_target_node); - NodePath get_target_node() const; - - void set_tip_node(const NodePath &p_tip_node); - NodePath get_tip_node() const; - - void set_use_high_quality_solve(bool p_solve); - bool get_use_high_quality_solve() const; - - String get_ccdik_joint_bone_name(int p_joint_idx) const; - void set_ccdik_joint_bone_name(int p_joint_idx, String p_bone_name); - int get_ccdik_joint_bone_index(int p_joint_idx) const; - void set_ccdik_joint_bone_index(int p_joint_idx, int p_bone_idx); - int get_ccdik_joint_ccdik_axis(int p_joint_idx) const; - void set_ccdik_joint_ccdik_axis(int p_joint_idx, int p_axis); - bool get_ccdik_joint_enable_constraint(int p_joint_idx) const; - void set_ccdik_joint_enable_constraint(int p_joint_idx, bool p_enable); - real_t get_ccdik_joint_constraint_angle_min(int p_joint_idx) const; - void set_ccdik_joint_constraint_angle_min(int p_joint_idx, real_t p_angle_min); - real_t get_ccdik_joint_constraint_angle_max(int p_joint_idx) const; - void set_ccdik_joint_constraint_angle_max(int p_joint_idx, real_t p_angle_max); - bool get_ccdik_joint_constraint_invert(int p_joint_idx) const; - void set_ccdik_joint_constraint_invert(int p_joint_idx, bool p_invert); - - int get_ccdik_data_chain_length(); - void set_ccdik_data_chain_length(int p_new_length); - - SkeletonModification3DCCDIK(); - ~SkeletonModification3DCCDIK(); -}; - -#endif // SKELETON_MODIFICATION_3D_CCDIK_H diff --git a/scene/resources/skeleton_modification_3d_fabrik.cpp b/scene/resources/skeleton_modification_3d_fabrik.cpp deleted file mode 100644 index 9fb7ade155..0000000000 --- a/scene/resources/skeleton_modification_3d_fabrik.cpp +++ /dev/null @@ -1,628 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_fabrik.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 "scene/resources/skeleton_modification_3d_fabrik.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -bool SkeletonModification3DFABRIK::_set(const StringName &p_path, const Variant &p_value) { - String path = p_path; - - if (path.begins_with("joint_data/")) { - int fabrik_data_size = fabrik_data_chain.size(); - int which = path.get_slicec('/', 1).to_int(); - String what = path.get_slicec('/', 2); - ERR_FAIL_INDEX_V(which, fabrik_data_size, false); - - if (what == "bone_name") { - set_fabrik_joint_bone_name(which, p_value); - } else if (what == "bone_index") { - set_fabrik_joint_bone_index(which, p_value); - } else if (what == "length") { - set_fabrik_joint_length(which, p_value); - } else if (what == "magnet_position") { - set_fabrik_joint_magnet(which, p_value); - } else if (what == "auto_calculate_length") { - set_fabrik_joint_auto_calculate_length(which, p_value); - } else if (what == "use_tip_node") { - set_fabrik_joint_use_tip_node(which, p_value); - } else if (what == "tip_node") { - set_fabrik_joint_tip_node(which, p_value); - } else if (what == "use_target_basis") { - set_fabrik_joint_use_target_basis(which, p_value); - } else if (what == "roll") { - set_fabrik_joint_roll(which, Math::deg_to_rad(real_t(p_value))); - } - return true; - } - return true; -} - -bool SkeletonModification3DFABRIK::_get(const StringName &p_path, Variant &r_ret) const { - String path = p_path; - - if (path.begins_with("joint_data/")) { - const int fabrik_data_size = fabrik_data_chain.size(); - int which = path.get_slicec('/', 1).to_int(); - String what = path.get_slicec('/', 2); - ERR_FAIL_INDEX_V(which, fabrik_data_size, false); - - if (what == "bone_name") { - r_ret = get_fabrik_joint_bone_name(which); - } else if (what == "bone_index") { - r_ret = get_fabrik_joint_bone_index(which); - } else if (what == "length") { - r_ret = get_fabrik_joint_length(which); - } else if (what == "magnet_position") { - r_ret = get_fabrik_joint_magnet(which); - } else if (what == "auto_calculate_length") { - r_ret = get_fabrik_joint_auto_calculate_length(which); - } else if (what == "use_tip_node") { - r_ret = get_fabrik_joint_use_tip_node(which); - } else if (what == "tip_node") { - r_ret = get_fabrik_joint_tip_node(which); - } else if (what == "use_target_basis") { - r_ret = get_fabrik_joint_use_target_basis(which); - } else if (what == "roll") { - r_ret = Math::rad_to_deg(get_fabrik_joint_roll(which)); - } - return true; - } - return true; -} - -void SkeletonModification3DFABRIK::_get_property_list(List<PropertyInfo> *p_list) const { - for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) { - String base_string = "joint_data/" + itos(i) + "/"; - - p_list->push_back(PropertyInfo(Variant::STRING_NAME, base_string + "bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "roll", PROPERTY_HINT_RANGE, "-360,360,0.01", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "auto_calculate_length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - - if (!fabrik_data_chain[i].auto_calculate_length) { - p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - } else { - p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_tip_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - if (fabrik_data_chain[i].use_tip_node) { - p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "tip_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D", PROPERTY_USAGE_DEFAULT)); - } - } - - // Cannot apply magnet to the origin of the chain, as it will not do anything. - if (i > 0) { - p_list->push_back(PropertyInfo(Variant::VECTOR3, base_string + "magnet_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - } - // Only give the override basis option on the last bone in the chain, so only include it for the last bone. - if (i == fabrik_data_chain.size() - 1) { - p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_target_basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - } - } -} - -void SkeletonModification3DFABRIK::_execute(real_t p_delta) { - ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, - "Modification is not setup and therefore cannot execute!"); - if (!enabled) { - return; - } - - if (target_node_cache.is_null()) { - _print_execution_error(true, "Target cache is out of date. Attempting to update..."); - update_target_cache(); - return; - } - - if (_print_execution_error(fabrik_data_chain.size() <= 1, "FABRIK requires at least two joints to operate. Cannot execute modification!")) { - return; - } - - Node3D *node_target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache)); - if (_print_execution_error(!node_target || !node_target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) { - return; - } - - // Make sure the transform cache is the correct size - if (fabrik_transforms.size() != fabrik_data_chain.size()) { - fabrik_transforms.resize(fabrik_data_chain.size()); - } - - // Verify that all joints have a valid bone ID, and that all bone lengths are zero or more - // Also, while we are here, apply magnet positions. - for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) { - if (_print_execution_error(fabrik_data_chain[i].bone_idx < 0, "FABRIK Joint " + itos(i) + " has an invalid bone ID. Cannot execute!")) { - return; - } - - if (fabrik_data_chain[i].length < 0 && fabrik_data_chain[i].auto_calculate_length) { - fabrik_joint_auto_calculate_length(i); - } - if (_print_execution_error(fabrik_data_chain[i].length < 0, "FABRIK Joint " + itos(i) + " has an invalid joint length. Cannot execute!")) { - return; - } - fabrik_transforms[i] = stack->skeleton->get_bone_global_pose(fabrik_data_chain[i].bone_idx); - - // Apply magnet positions: - if (stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx) >= 0) { - int parent_bone_idx = stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx); - Transform3D conversion_transform = (stack->skeleton->get_bone_global_pose(parent_bone_idx)); - fabrik_transforms[i].origin += conversion_transform.basis.xform_inv(fabrik_data_chain[i].magnet_position); - } else { - fabrik_transforms[i].origin += fabrik_data_chain[i].magnet_position; - } - } - Transform3D origin_global_pose_trans = stack->skeleton->get_bone_global_pose_no_override(fabrik_data_chain[0].bone_idx); - - target_global_pose = stack->skeleton->world_transform_to_global_pose(node_target->get_global_transform()); - origin_global_pose = origin_global_pose_trans; - - final_joint_idx = fabrik_data_chain.size() - 1; - real_t target_distance = fabrik_transforms[final_joint_idx].origin.distance_to(target_global_pose.origin); - chain_iterations = 0; - - while (target_distance > chain_tolerance) { - chain_backwards(); - chain_forwards(); - - // update the target distance - target_distance = fabrik_transforms[final_joint_idx].origin.distance_to(target_global_pose.origin); - - // update chain iterations - chain_iterations += 1; - if (chain_iterations >= chain_max_iterations) { - break; - } - } - chain_apply(); - - execution_error_found = false; -} - -void SkeletonModification3DFABRIK::chain_backwards() { - int final_bone_idx = fabrik_data_chain[final_joint_idx].bone_idx; - Transform3D final_joint_trans = fabrik_transforms[final_joint_idx]; - - // Get the direction the final bone is facing in. - stack->skeleton->update_bone_rest_forward_vector(final_bone_idx); - Transform3D final_bone_direction_trans = final_joint_trans.looking_at(target_global_pose.origin, Vector3(0, 1, 0)); - final_bone_direction_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(final_bone_idx, final_bone_direction_trans.basis); - Vector3 direction = final_bone_direction_trans.basis.xform(stack->skeleton->get_bone_axis_forward_vector(final_bone_idx)).normalized(); - - // If set to override, then use the target's Basis rather than the bone's - if (fabrik_data_chain[final_joint_idx].use_target_basis) { - direction = target_global_pose.basis.xform(stack->skeleton->get_bone_axis_forward_vector(final_bone_idx)).normalized(); - } - - // set the position of the final joint to the target position - final_joint_trans.origin = target_global_pose.origin - (direction * fabrik_data_chain[final_joint_idx].length); - fabrik_transforms[final_joint_idx] = final_joint_trans; - - // for all other joints, move them towards the target - int i = final_joint_idx; - while (i >= 1) { - Transform3D next_bone_trans = fabrik_transforms[i]; - i -= 1; - Transform3D current_trans = fabrik_transforms[i]; - - real_t length = fabrik_data_chain[i].length / (current_trans.origin.distance_to(next_bone_trans.origin)); - current_trans.origin = next_bone_trans.origin.lerp(current_trans.origin, length); - - // Save the result - fabrik_transforms[i] = current_trans; - } -} - -void SkeletonModification3DFABRIK::chain_forwards() { - // Set root at the initial position. - Transform3D root_transform = fabrik_transforms[0]; - - root_transform.origin = origin_global_pose.origin; - fabrik_transforms[0] = origin_global_pose; - - for (uint32_t i = 0; i < fabrik_data_chain.size() - 1; i++) { - Transform3D current_trans = fabrik_transforms[i]; - Transform3D next_bone_trans = fabrik_transforms[i + 1]; - - real_t length = fabrik_data_chain[i].length / (next_bone_trans.origin.distance_to(current_trans.origin)); - next_bone_trans.origin = current_trans.origin.lerp(next_bone_trans.origin, length); - - // Save the result - fabrik_transforms[i + 1] = next_bone_trans; - } -} - -void SkeletonModification3DFABRIK::chain_apply() { - for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) { - int current_bone_idx = fabrik_data_chain[i].bone_idx; - Transform3D current_trans = fabrik_transforms[i]; - - // If this is the last bone in the chain... - if (i == fabrik_data_chain.size() - 1) { - if (fabrik_data_chain[i].use_target_basis == false) { // Point to target... - // Get the forward direction that the basis is facing in right now. - stack->skeleton->update_bone_rest_forward_vector(current_bone_idx); - Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(current_bone_idx); - // Rotate the bone towards the target: - current_trans.basis.rotate_to_align(forward_vector, current_trans.origin.direction_to(target_global_pose.origin)); - current_trans.basis.rotate_local(forward_vector, fabrik_data_chain[i].roll); - } else { // Use the target's Basis... - current_trans.basis = target_global_pose.basis.orthonormalized().scaled(current_trans.basis.get_scale()); - } - } else { // every other bone in the chain... - Transform3D next_trans = fabrik_transforms[i + 1]; - - // Get the forward direction that the basis is facing in right now. - stack->skeleton->update_bone_rest_forward_vector(current_bone_idx); - Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(current_bone_idx); - // Rotate the bone towards the next bone in the chain: - current_trans.basis.rotate_to_align(forward_vector, current_trans.origin.direction_to(next_trans.origin)); - current_trans.basis.rotate_local(forward_vector, fabrik_data_chain[i].roll); - } - stack->skeleton->set_bone_local_pose_override(current_bone_idx, stack->skeleton->global_pose_to_local_pose(current_bone_idx, current_trans), stack->strength, true); - } - - // Update all the bones so the next modification has up-to-date data. - stack->skeleton->force_update_all_bone_transforms(); -} - -void SkeletonModification3DFABRIK::_setup_modification(SkeletonModificationStack3D *p_stack) { - stack = p_stack; - if (stack != nullptr) { - is_setup = true; - execution_error_found = false; - update_target_cache(); - - for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) { - update_joint_tip_cache(i); - } - } -} - -void SkeletonModification3DFABRIK::update_target_cache() { - if (!is_setup || !stack) { - _print_execution_error(true, "Cannot update target cache: modification is not properly setup!"); - return; - } - target_node_cache = ObjectID(); - if (stack->skeleton) { - if (stack->skeleton->is_inside_tree() && target_node.is_empty() == false) { - if (stack->skeleton->has_node(target_node)) { - Node *node = stack->skeleton->get_node(target_node); - ERR_FAIL_COND_MSG(!node || stack->skeleton == node, - "Cannot update target cache: node is this modification's skeleton or cannot be found!"); - ERR_FAIL_COND_MSG(!node->is_inside_tree(), - "Cannot update target cache: node is not in the scene tree!"); - target_node_cache = node->get_instance_id(); - - execution_error_found = false; - } - } - } -} - -void SkeletonModification3DFABRIK::update_joint_tip_cache(int p_joint_idx) { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX_MSG(p_joint_idx, bone_chain_size, "FABRIK joint not found"); - if (!is_setup || !stack) { - _print_execution_error(true, "Cannot update tip cache: modification is not properly setup!"); - return; - } - fabrik_data_chain[p_joint_idx].tip_node_cache = ObjectID(); - if (stack->skeleton) { - if (stack->skeleton->is_inside_tree() && fabrik_data_chain[p_joint_idx].tip_node.is_empty() == false) { - if (stack->skeleton->has_node(fabrik_data_chain[p_joint_idx].tip_node)) { - Node *node = stack->skeleton->get_node(fabrik_data_chain[p_joint_idx].tip_node); - ERR_FAIL_COND_MSG(!node || stack->skeleton == node, - "Cannot update tip cache for joint " + itos(p_joint_idx) + ": node is this modification's skeleton or cannot be found!"); - ERR_FAIL_COND_MSG(!node->is_inside_tree(), - "Cannot update tip cache for joint " + itos(p_joint_idx) + ": node is not in scene tree!"); - fabrik_data_chain[p_joint_idx].tip_node_cache = node->get_instance_id(); - - execution_error_found = false; - } - } - } -} - -void SkeletonModification3DFABRIK::set_target_node(const NodePath &p_target_node) { - target_node = p_target_node; - update_target_cache(); -} - -NodePath SkeletonModification3DFABRIK::get_target_node() const { - return target_node; -} - -int SkeletonModification3DFABRIK::get_fabrik_data_chain_length() { - return fabrik_data_chain.size(); -} - -void SkeletonModification3DFABRIK::set_fabrik_data_chain_length(int p_length) { - ERR_FAIL_COND(p_length < 0); - fabrik_data_chain.resize(p_length); - fabrik_transforms.resize(p_length); - execution_error_found = false; - notify_property_list_changed(); -} - -real_t SkeletonModification3DFABRIK::get_chain_tolerance() { - return chain_tolerance; -} - -void SkeletonModification3DFABRIK::set_chain_tolerance(real_t p_tolerance) { - ERR_FAIL_COND_MSG(p_tolerance <= 0, "FABRIK chain tolerance must be more than zero!"); - chain_tolerance = p_tolerance; -} - -int SkeletonModification3DFABRIK::get_chain_max_iterations() { - return chain_max_iterations; -} -void SkeletonModification3DFABRIK::set_chain_max_iterations(int p_iterations) { - ERR_FAIL_COND_MSG(p_iterations <= 0, "FABRIK chain iterations must be at least one. Set enabled to false to disable the FABRIK chain."); - chain_max_iterations = p_iterations; -} - -// FABRIK joint data functions -String SkeletonModification3DFABRIK::get_fabrik_joint_bone_name(int p_joint_idx) const { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, String()); - return fabrik_data_chain[p_joint_idx].bone_name; -} - -void SkeletonModification3DFABRIK::set_fabrik_joint_bone_name(int p_joint_idx, String p_bone_name) { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - fabrik_data_chain[p_joint_idx].bone_name = p_bone_name; - - if (stack) { - if (stack->skeleton) { - fabrik_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(p_bone_name); - } - } - execution_error_found = false; - notify_property_list_changed(); -} - -int SkeletonModification3DFABRIK::get_fabrik_joint_bone_index(int p_joint_idx) const { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1); - return fabrik_data_chain[p_joint_idx].bone_idx; -} - -void SkeletonModification3DFABRIK::set_fabrik_joint_bone_index(int p_joint_idx, int p_bone_idx) { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!"); - fabrik_data_chain[p_joint_idx].bone_idx = p_bone_idx; - - if (stack) { - if (stack->skeleton) { - fabrik_data_chain[p_joint_idx].bone_name = stack->skeleton->get_bone_name(p_bone_idx); - } - } - execution_error_found = false; - notify_property_list_changed(); -} - -real_t SkeletonModification3DFABRIK::get_fabrik_joint_length(int p_joint_idx) const { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1); - return fabrik_data_chain[p_joint_idx].length; -} - -void SkeletonModification3DFABRIK::set_fabrik_joint_length(int p_joint_idx, real_t p_bone_length) { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - ERR_FAIL_COND_MSG(p_bone_length < 0, "FABRIK joint length cannot be less than zero!"); - - if (!is_setup) { - fabrik_data_chain[p_joint_idx].length = p_bone_length; - return; - } - - if (fabrik_data_chain[p_joint_idx].auto_calculate_length) { - WARN_PRINT("FABRIK Length not set: auto calculate length is enabled for this joint!"); - fabrik_joint_auto_calculate_length(p_joint_idx); - } else { - fabrik_data_chain[p_joint_idx].length = p_bone_length; - } - - execution_error_found = false; -} - -Vector3 SkeletonModification3DFABRIK::get_fabrik_joint_magnet(int p_joint_idx) const { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, Vector3()); - return fabrik_data_chain[p_joint_idx].magnet_position; -} - -void SkeletonModification3DFABRIK::set_fabrik_joint_magnet(int p_joint_idx, Vector3 p_magnet) { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - fabrik_data_chain[p_joint_idx].magnet_position = p_magnet; -} - -bool SkeletonModification3DFABRIK::get_fabrik_joint_auto_calculate_length(int p_joint_idx) const { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false); - return fabrik_data_chain[p_joint_idx].auto_calculate_length; -} - -void SkeletonModification3DFABRIK::set_fabrik_joint_auto_calculate_length(int p_joint_idx, bool p_auto_calculate) { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - fabrik_data_chain[p_joint_idx].auto_calculate_length = p_auto_calculate; - fabrik_joint_auto_calculate_length(p_joint_idx); - notify_property_list_changed(); -} - -void SkeletonModification3DFABRIK::fabrik_joint_auto_calculate_length(int p_joint_idx) { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - if (!fabrik_data_chain[p_joint_idx].auto_calculate_length) { - return; - } - - if (!stack || !stack->skeleton || !is_setup) { - _print_execution_error(true, "Cannot auto calculate joint length: modification is not properly setup!"); - return; - } - ERR_FAIL_INDEX_MSG(fabrik_data_chain[p_joint_idx].bone_idx, stack->skeleton->get_bone_count(), - "Bone for joint " + itos(p_joint_idx) + " is not set or points to an unknown bone!"); - - if (fabrik_data_chain[p_joint_idx].use_tip_node) { // Use the tip node to update joint length. - - update_joint_tip_cache(p_joint_idx); - - Node3D *tip_node = Object::cast_to<Node3D>(ObjectDB::get_instance(fabrik_data_chain[p_joint_idx].tip_node_cache)); - ERR_FAIL_COND_MSG(!tip_node, "Tip node for joint " + itos(p_joint_idx) + "is not a Node3D-based node. Cannot calculate length..."); - ERR_FAIL_COND_MSG(!tip_node->is_inside_tree(), "Tip node for joint " + itos(p_joint_idx) + "is not in the scene tree. Cannot calculate length..."); - - Transform3D node_trans = tip_node->get_global_transform(); - node_trans = stack->skeleton->world_transform_to_global_pose(node_trans); - //node_trans = stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, node_trans); - //fabrik_data_chain[p_joint_idx].length = node_trans.origin.length(); - - fabrik_data_chain[p_joint_idx].length = stack->skeleton->get_bone_global_pose(fabrik_data_chain[p_joint_idx].bone_idx).origin.distance_to(node_trans.origin); - - } else { // Use child bone(s) to update joint length, if possible - Vector<int> bone_children = stack->skeleton->get_bone_children(fabrik_data_chain[p_joint_idx].bone_idx); - if (bone_children.size() <= 0) { - ERR_FAIL_MSG("Cannot calculate length for joint " + itos(p_joint_idx) + "joint uses leaf bone. \nPlease manually set the bone length or use a tip node!"); - return; - } - - Transform3D bone_trans = stack->skeleton->get_bone_global_pose(fabrik_data_chain[p_joint_idx].bone_idx); - - real_t final_length = 0; - for (int i = 0; i < bone_children.size(); i++) { - Transform3D child_transform = stack->skeleton->get_bone_global_pose(bone_children[i]); - final_length += bone_trans.origin.distance_to(child_transform.origin); - //final_length += stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, child_transform).origin.length(); - } - fabrik_data_chain[p_joint_idx].length = final_length / bone_children.size(); - } - execution_error_found = false; - notify_property_list_changed(); -} - -bool SkeletonModification3DFABRIK::get_fabrik_joint_use_tip_node(int p_joint_idx) const { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false); - return fabrik_data_chain[p_joint_idx].use_tip_node; -} - -void SkeletonModification3DFABRIK::set_fabrik_joint_use_tip_node(int p_joint_idx, bool p_use_tip_node) { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - fabrik_data_chain[p_joint_idx].use_tip_node = p_use_tip_node; - notify_property_list_changed(); -} - -NodePath SkeletonModification3DFABRIK::get_fabrik_joint_tip_node(int p_joint_idx) const { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, NodePath()); - return fabrik_data_chain[p_joint_idx].tip_node; -} - -void SkeletonModification3DFABRIK::set_fabrik_joint_tip_node(int p_joint_idx, NodePath p_tip_node) { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - fabrik_data_chain[p_joint_idx].tip_node = p_tip_node; - update_joint_tip_cache(p_joint_idx); -} - -bool SkeletonModification3DFABRIK::get_fabrik_joint_use_target_basis(int p_joint_idx) const { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false); - return fabrik_data_chain[p_joint_idx].use_target_basis; -} - -void SkeletonModification3DFABRIK::set_fabrik_joint_use_target_basis(int p_joint_idx, bool p_use_target_basis) { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - fabrik_data_chain[p_joint_idx].use_target_basis = p_use_target_basis; -} - -real_t SkeletonModification3DFABRIK::get_fabrik_joint_roll(int p_joint_idx) const { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, 0.0); - return fabrik_data_chain[p_joint_idx].roll; -} - -void SkeletonModification3DFABRIK::set_fabrik_joint_roll(int p_joint_idx, real_t p_roll) { - const int bone_chain_size = fabrik_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - fabrik_data_chain[p_joint_idx].roll = p_roll; -} - -void SkeletonModification3DFABRIK::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DFABRIK::set_target_node); - ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DFABRIK::get_target_node); - ClassDB::bind_method(D_METHOD("set_fabrik_data_chain_length", "length"), &SkeletonModification3DFABRIK::set_fabrik_data_chain_length); - ClassDB::bind_method(D_METHOD("get_fabrik_data_chain_length"), &SkeletonModification3DFABRIK::get_fabrik_data_chain_length); - ClassDB::bind_method(D_METHOD("set_chain_tolerance", "tolerance"), &SkeletonModification3DFABRIK::set_chain_tolerance); - ClassDB::bind_method(D_METHOD("get_chain_tolerance"), &SkeletonModification3DFABRIK::get_chain_tolerance); - ClassDB::bind_method(D_METHOD("set_chain_max_iterations", "max_iterations"), &SkeletonModification3DFABRIK::set_chain_max_iterations); - ClassDB::bind_method(D_METHOD("get_chain_max_iterations"), &SkeletonModification3DFABRIK::get_chain_max_iterations); - - // FABRIK joint data functions - ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone_name", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_bone_name); - ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone_name", "joint_idx", "bone_name"), &SkeletonModification3DFABRIK::set_fabrik_joint_bone_name); - ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone_index", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_bone_index); - ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone_index", "joint_idx", "bone_index"), &SkeletonModification3DFABRIK::set_fabrik_joint_bone_index); - ClassDB::bind_method(D_METHOD("get_fabrik_joint_length", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_length); - ClassDB::bind_method(D_METHOD("set_fabrik_joint_length", "joint_idx", "length"), &SkeletonModification3DFABRIK::set_fabrik_joint_length); - ClassDB::bind_method(D_METHOD("get_fabrik_joint_magnet", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_magnet); - ClassDB::bind_method(D_METHOD("set_fabrik_joint_magnet", "joint_idx", "magnet_position"), &SkeletonModification3DFABRIK::set_fabrik_joint_magnet); - ClassDB::bind_method(D_METHOD("get_fabrik_joint_auto_calculate_length", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_auto_calculate_length); - ClassDB::bind_method(D_METHOD("set_fabrik_joint_auto_calculate_length", "joint_idx", "auto_calculate_length"), &SkeletonModification3DFABRIK::set_fabrik_joint_auto_calculate_length); - ClassDB::bind_method(D_METHOD("fabrik_joint_auto_calculate_length", "joint_idx"), &SkeletonModification3DFABRIK::fabrik_joint_auto_calculate_length); - ClassDB::bind_method(D_METHOD("get_fabrik_joint_use_tip_node", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_use_tip_node); - ClassDB::bind_method(D_METHOD("set_fabrik_joint_use_tip_node", "joint_idx", "use_tip_node"), &SkeletonModification3DFABRIK::set_fabrik_joint_use_tip_node); - ClassDB::bind_method(D_METHOD("get_fabrik_joint_tip_node", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_tip_node); - ClassDB::bind_method(D_METHOD("set_fabrik_joint_tip_node", "joint_idx", "tip_node"), &SkeletonModification3DFABRIK::set_fabrik_joint_tip_node); - ClassDB::bind_method(D_METHOD("get_fabrik_joint_use_target_basis", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_use_target_basis); - ClassDB::bind_method(D_METHOD("set_fabrik_joint_use_target_basis", "joint_idx", "use_target_basis"), &SkeletonModification3DFABRIK::set_fabrik_joint_use_target_basis); - - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "fabrik_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_fabrik_data_chain_length", "get_fabrik_data_chain_length"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "chain_tolerance", PROPERTY_HINT_RANGE, "0,100,0.001"), "set_chain_tolerance", "get_chain_tolerance"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "chain_max_iterations", PROPERTY_HINT_RANGE, "1,50,1"), "set_chain_max_iterations", "get_chain_max_iterations"); -} - -SkeletonModification3DFABRIK::SkeletonModification3DFABRIK() { - stack = nullptr; - is_setup = false; - enabled = true; -} - -SkeletonModification3DFABRIK::~SkeletonModification3DFABRIK() { -} diff --git a/scene/resources/skeleton_modification_3d_fabrik.h b/scene/resources/skeleton_modification_3d_fabrik.h deleted file mode 100644 index c834658093..0000000000 --- a/scene/resources/skeleton_modification_3d_fabrik.h +++ /dev/null @@ -1,124 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_fabrik.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 SKELETON_MODIFICATION_3D_FABRIK_H -#define SKELETON_MODIFICATION_3D_FABRIK_H - -#include "core/templates/local_vector.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -class SkeletonModification3DFABRIK : public SkeletonModification3D { - GDCLASS(SkeletonModification3DFABRIK, SkeletonModification3D); - -private: - struct FABRIK_Joint_Data { - String bone_name = ""; - int bone_idx = -1; - real_t length = -1; - Vector3 magnet_position = Vector3(0, 0, 0); - - bool auto_calculate_length = true; - bool use_tip_node = false; - NodePath tip_node; - ObjectID tip_node_cache; - - bool use_target_basis = false; - real_t roll = 0; - }; - - LocalVector<FABRIK_Joint_Data> fabrik_data_chain; - LocalVector<Transform3D> fabrik_transforms; - - NodePath target_node; - ObjectID target_node_cache; - - real_t chain_tolerance = 0.01; - int chain_max_iterations = 10; - int chain_iterations = 0; - - void update_target_cache(); - void update_joint_tip_cache(int p_joint_idx); - - int final_joint_idx = 0; - Transform3D target_global_pose; - Transform3D origin_global_pose; - - void chain_backwards(); - void chain_forwards(); - void chain_apply(); - -protected: - static void _bind_methods(); - 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; - -public: - virtual void _execute(real_t p_delta) override; - virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override; - - void set_target_node(const NodePath &p_target_node); - NodePath get_target_node() const; - - int get_fabrik_data_chain_length(); - void set_fabrik_data_chain_length(int p_new_length); - - real_t get_chain_tolerance(); - void set_chain_tolerance(real_t p_tolerance); - - int get_chain_max_iterations(); - void set_chain_max_iterations(int p_iterations); - - String get_fabrik_joint_bone_name(int p_joint_idx) const; - void set_fabrik_joint_bone_name(int p_joint_idx, String p_bone_name); - int get_fabrik_joint_bone_index(int p_joint_idx) const; - void set_fabrik_joint_bone_index(int p_joint_idx, int p_bone_idx); - real_t get_fabrik_joint_length(int p_joint_idx) const; - void set_fabrik_joint_length(int p_joint_idx, real_t p_bone_length); - Vector3 get_fabrik_joint_magnet(int p_joint_idx) const; - void set_fabrik_joint_magnet(int p_joint_idx, Vector3 p_magnet); - bool get_fabrik_joint_auto_calculate_length(int p_joint_idx) const; - void set_fabrik_joint_auto_calculate_length(int p_joint_idx, bool p_auto_calculate); - void fabrik_joint_auto_calculate_length(int p_joint_idx); - bool get_fabrik_joint_use_tip_node(int p_joint_idx) const; - void set_fabrik_joint_use_tip_node(int p_joint_idx, bool p_use_tip_node); - NodePath get_fabrik_joint_tip_node(int p_joint_idx) const; - void set_fabrik_joint_tip_node(int p_joint_idx, NodePath p_tip_node); - bool get_fabrik_joint_use_target_basis(int p_joint_idx) const; - void set_fabrik_joint_use_target_basis(int p_joint_idx, bool p_use_basis); - real_t get_fabrik_joint_roll(int p_joint_idx) const; - void set_fabrik_joint_roll(int p_joint_idx, real_t p_roll); - - SkeletonModification3DFABRIK(); - ~SkeletonModification3DFABRIK(); -}; - -#endif // SKELETON_MODIFICATION_3D_FABRIK_H diff --git a/scene/resources/skeleton_modification_3d_jiggle.cpp b/scene/resources/skeleton_modification_3d_jiggle.cpp deleted file mode 100644 index 2cfc7fb10f..0000000000 --- a/scene/resources/skeleton_modification_3d_jiggle.cpp +++ /dev/null @@ -1,582 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_jiggle.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 "scene/resources/skeleton_modification_3d_jiggle.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -bool SkeletonModification3DJiggle::_set(const StringName &p_path, const Variant &p_value) { - String path = p_path; - - if (path.begins_with("joint_data/")) { - const int jiggle_size = jiggle_data_chain.size(); - int which = path.get_slicec('/', 1).to_int(); - String what = path.get_slicec('/', 2); - ERR_FAIL_INDEX_V(which, jiggle_size, false); - - if (what == "bone_name") { - set_jiggle_joint_bone_name(which, p_value); - } else if (what == "bone_index") { - set_jiggle_joint_bone_index(which, p_value); - } else if (what == "override_defaults") { - set_jiggle_joint_override(which, p_value); - } else if (what == "stiffness") { - set_jiggle_joint_stiffness(which, p_value); - } else if (what == "mass") { - set_jiggle_joint_mass(which, p_value); - } else if (what == "damping") { - set_jiggle_joint_damping(which, p_value); - } else if (what == "use_gravity") { - set_jiggle_joint_use_gravity(which, p_value); - } else if (what == "gravity") { - set_jiggle_joint_gravity(which, p_value); - } else if (what == "roll") { - set_jiggle_joint_roll(which, Math::deg_to_rad(real_t(p_value))); - } - return true; - } else { - if (path == "use_colliders") { - set_use_colliders(p_value); - } else if (path == "collision_mask") { - set_collision_mask(p_value); - } - return true; - } - return true; -} - -bool SkeletonModification3DJiggle::_get(const StringName &p_path, Variant &r_ret) const { - String path = p_path; - - if (path.begins_with("joint_data/")) { - const int jiggle_size = jiggle_data_chain.size(); - int which = path.get_slicec('/', 1).to_int(); - String what = path.get_slicec('/', 2); - ERR_FAIL_INDEX_V(which, jiggle_size, false); - - if (what == "bone_name") { - r_ret = get_jiggle_joint_bone_name(which); - } else if (what == "bone_index") { - r_ret = get_jiggle_joint_bone_index(which); - } else if (what == "override_defaults") { - r_ret = get_jiggle_joint_override(which); - } else if (what == "stiffness") { - r_ret = get_jiggle_joint_stiffness(which); - } else if (what == "mass") { - r_ret = get_jiggle_joint_mass(which); - } else if (what == "damping") { - r_ret = get_jiggle_joint_damping(which); - } else if (what == "use_gravity") { - r_ret = get_jiggle_joint_use_gravity(which); - } else if (what == "gravity") { - r_ret = get_jiggle_joint_gravity(which); - } else if (what == "roll") { - r_ret = Math::rad_to_deg(get_jiggle_joint_roll(which)); - } - return true; - } else { - if (path == "use_colliders") { - r_ret = get_use_colliders(); - } else if (path == "collision_mask") { - r_ret = get_collision_mask(); - } - return true; - } - return true; -} - -void SkeletonModification3DJiggle::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::BOOL, "use_colliders", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - if (use_colliders) { - p_list->push_back(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS, "", PROPERTY_USAGE_DEFAULT)); - } - - for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) { - String base_string = "joint_data/" + itos(i) + "/"; - - p_list->push_back(PropertyInfo(Variant::STRING_NAME, base_string + "bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "roll", PROPERTY_HINT_RANGE, "-360,360,0.01", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "override_defaults", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - - if (jiggle_data_chain[i].override_defaults) { - p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "stiffness", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "mass", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - if (jiggle_data_chain[i].use_gravity) { - p_list->push_back(PropertyInfo(Variant::VECTOR3, base_string + "gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - } - } - } -} - -void SkeletonModification3DJiggle::_execute(real_t p_delta) { - ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, - "Modification is not setup and therefore cannot execute!"); - if (!enabled) { - return; - } - if (target_node_cache.is_null()) { - _print_execution_error(true, "Target cache is out of date. Attempting to update..."); - update_cache(); - return; - } - Node3D *target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache)); - _print_execution_error(!target || !target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!"); - - for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) { - _execute_jiggle_joint(i, target, p_delta); - } - - execution_error_found = false; -} - -void SkeletonModification3DJiggle::_execute_jiggle_joint(int p_joint_idx, Node3D *p_target, real_t p_delta) { - // Adopted from: https://wiki.unity3d.com/index.php/JiggleBone - // With modifications by TwistedTwigleg. - - if (jiggle_data_chain[p_joint_idx].bone_idx <= -2) { - jiggle_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(jiggle_data_chain[p_joint_idx].bone_name); - } - if (_print_execution_error( - jiggle_data_chain[p_joint_idx].bone_idx < 0 || jiggle_data_chain[p_joint_idx].bone_idx > stack->skeleton->get_bone_count(), - "Jiggle joint " + itos(p_joint_idx) + " bone index is invalid. Cannot execute modification!")) { - return; - } - - Transform3D bone_local_pos = stack->skeleton->get_bone_local_pose_override(jiggle_data_chain[p_joint_idx].bone_idx); - if (bone_local_pos == Transform3D()) { - bone_local_pos = stack->skeleton->get_bone_pose(jiggle_data_chain[p_joint_idx].bone_idx); - } - - Transform3D new_bone_trans = stack->skeleton->local_pose_to_global_pose(jiggle_data_chain[p_joint_idx].bone_idx, bone_local_pos); - Vector3 target_position = stack->skeleton->world_transform_to_global_pose(p_target->get_global_transform()).origin; - - jiggle_data_chain[p_joint_idx].force = (target_position - jiggle_data_chain[p_joint_idx].dynamic_position) * jiggle_data_chain[p_joint_idx].stiffness * p_delta; - - if (jiggle_data_chain[p_joint_idx].use_gravity) { - Vector3 gravity_to_apply = new_bone_trans.basis.inverse().xform(jiggle_data_chain[p_joint_idx].gravity); - jiggle_data_chain[p_joint_idx].force += gravity_to_apply * p_delta; - } - - jiggle_data_chain[p_joint_idx].acceleration = jiggle_data_chain[p_joint_idx].force / jiggle_data_chain[p_joint_idx].mass; - jiggle_data_chain[p_joint_idx].velocity += jiggle_data_chain[p_joint_idx].acceleration * (1 - jiggle_data_chain[p_joint_idx].damping); - - jiggle_data_chain[p_joint_idx].dynamic_position += jiggle_data_chain[p_joint_idx].velocity + jiggle_data_chain[p_joint_idx].force; - jiggle_data_chain[p_joint_idx].dynamic_position += new_bone_trans.origin - jiggle_data_chain[p_joint_idx].last_position; - jiggle_data_chain[p_joint_idx].last_position = new_bone_trans.origin; - - // Collision detection/response - if (use_colliders) { - if (execution_mode == SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_physics_process) { - Ref<World3D> world_3d = stack->skeleton->get_world_3d(); - ERR_FAIL_COND(world_3d.is_null()); - PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world_3d->get_space()); - PhysicsDirectSpaceState3D::RayResult ray_result; - - // Convert to world transforms, which is what the physics server needs - Transform3D new_bone_trans_world = stack->skeleton->global_pose_to_world_transform(new_bone_trans); - Transform3D dynamic_position_world = stack->skeleton->global_pose_to_world_transform(Transform3D(Basis(), jiggle_data_chain[p_joint_idx].dynamic_position)); - - PhysicsDirectSpaceState3D::RayParameters ray_params; - ray_params.from = new_bone_trans_world.origin; - ray_params.to = dynamic_position_world.get_origin(); - ray_params.collision_mask = collision_mask; - - bool ray_hit = space_state->intersect_ray(ray_params, ray_result); - - if (ray_hit) { - jiggle_data_chain[p_joint_idx].dynamic_position = jiggle_data_chain[p_joint_idx].last_noncollision_position; - jiggle_data_chain[p_joint_idx].acceleration = Vector3(0, 0, 0); - jiggle_data_chain[p_joint_idx].velocity = Vector3(0, 0, 0); - } else { - jiggle_data_chain[p_joint_idx].last_noncollision_position = jiggle_data_chain[p_joint_idx].dynamic_position; - } - - } else { - WARN_PRINT_ONCE("Jiggle modifier: You cannot detect colliders without the stack mode being set to _physics_process!"); - } - } - - // Get the forward direction that the basis is facing in right now. - stack->skeleton->update_bone_rest_forward_vector(jiggle_data_chain[p_joint_idx].bone_idx); - Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(jiggle_data_chain[p_joint_idx].bone_idx); - - // Rotate the bone using the dynamic position! - new_bone_trans.basis.rotate_to_align(forward_vector, new_bone_trans.origin.direction_to(jiggle_data_chain[p_joint_idx].dynamic_position)); - - // Roll - new_bone_trans.basis.rotate_local(forward_vector, jiggle_data_chain[p_joint_idx].roll); - - new_bone_trans = stack->skeleton->global_pose_to_local_pose(jiggle_data_chain[p_joint_idx].bone_idx, new_bone_trans); - stack->skeleton->set_bone_local_pose_override(jiggle_data_chain[p_joint_idx].bone_idx, new_bone_trans, stack->strength, true); - stack->skeleton->force_update_bone_children_transforms(jiggle_data_chain[p_joint_idx].bone_idx); -} - -void SkeletonModification3DJiggle::_update_jiggle_joint_data() { - for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) { - if (!jiggle_data_chain[i].override_defaults) { - set_jiggle_joint_stiffness(i, stiffness); - set_jiggle_joint_mass(i, mass); - set_jiggle_joint_damping(i, damping); - set_jiggle_joint_use_gravity(i, use_gravity); - set_jiggle_joint_gravity(i, gravity); - } - } -} - -void SkeletonModification3DJiggle::_setup_modification(SkeletonModificationStack3D *p_stack) { - stack = p_stack; - - if (stack) { - is_setup = true; - execution_error_found = false; - - if (stack->skeleton) { - for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) { - int bone_idx = jiggle_data_chain[i].bone_idx; - if (bone_idx > 0 && bone_idx < stack->skeleton->get_bone_count()) { - jiggle_data_chain[i].dynamic_position = stack->skeleton->local_pose_to_global_pose(bone_idx, stack->skeleton->get_bone_local_pose_override(bone_idx)).origin; - } - } - } - - update_cache(); - } -} - -void SkeletonModification3DJiggle::update_cache() { - if (!is_setup || !stack) { - _print_execution_error(true, "Cannot update target cache: modification is not properly setup!"); - return; - } - - target_node_cache = ObjectID(); - if (stack->skeleton) { - if (stack->skeleton->is_inside_tree()) { - if (stack->skeleton->has_node(target_node)) { - Node *node = stack->skeleton->get_node(target_node); - ERR_FAIL_COND_MSG(!node || stack->skeleton == node, - "Cannot update target cache: node is this modification's skeleton or cannot be found!"); - ERR_FAIL_COND_MSG(!node->is_inside_tree(), - "Cannot update target cache: node is not in the scene tree!"); - target_node_cache = node->get_instance_id(); - - execution_error_found = false; - } - } - } -} - -void SkeletonModification3DJiggle::set_target_node(const NodePath &p_target_node) { - target_node = p_target_node; - update_cache(); -} - -NodePath SkeletonModification3DJiggle::get_target_node() const { - return target_node; -} - -void SkeletonModification3DJiggle::set_stiffness(real_t p_stiffness) { - ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!"); - stiffness = p_stiffness; - _update_jiggle_joint_data(); -} - -real_t SkeletonModification3DJiggle::get_stiffness() const { - return stiffness; -} - -void SkeletonModification3DJiggle::set_mass(real_t p_mass) { - ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!"); - mass = p_mass; - _update_jiggle_joint_data(); -} - -real_t SkeletonModification3DJiggle::get_mass() const { - return mass; -} - -void SkeletonModification3DJiggle::set_damping(real_t p_damping) { - ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!"); - ERR_FAIL_COND_MSG(p_damping > 1, "Damping cannot be more than one!"); - damping = p_damping; - _update_jiggle_joint_data(); -} - -real_t SkeletonModification3DJiggle::get_damping() const { - return damping; -} - -void SkeletonModification3DJiggle::set_use_gravity(bool p_use_gravity) { - use_gravity = p_use_gravity; - _update_jiggle_joint_data(); -} - -bool SkeletonModification3DJiggle::get_use_gravity() const { - return use_gravity; -} - -void SkeletonModification3DJiggle::set_gravity(Vector3 p_gravity) { - gravity = p_gravity; - _update_jiggle_joint_data(); -} - -Vector3 SkeletonModification3DJiggle::get_gravity() const { - return gravity; -} - -void SkeletonModification3DJiggle::set_use_colliders(bool p_use_collider) { - use_colliders = p_use_collider; - notify_property_list_changed(); -} - -bool SkeletonModification3DJiggle::get_use_colliders() const { - return use_colliders; -} - -void SkeletonModification3DJiggle::set_collision_mask(int p_mask) { - collision_mask = p_mask; -} - -int SkeletonModification3DJiggle::get_collision_mask() const { - return collision_mask; -} - -// Jiggle joint data functions -int SkeletonModification3DJiggle::get_jiggle_data_chain_length() { - return jiggle_data_chain.size(); -} - -void SkeletonModification3DJiggle::set_jiggle_data_chain_length(int p_length) { - ERR_FAIL_COND(p_length < 0); - jiggle_data_chain.resize(p_length); - execution_error_found = false; - notify_property_list_changed(); -} - -void SkeletonModification3DJiggle::set_jiggle_joint_bone_name(int p_joint_idx, String p_name) { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - - jiggle_data_chain[p_joint_idx].bone_name = p_name; - if (stack && stack->skeleton) { - jiggle_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(p_name); - } - execution_error_found = false; - notify_property_list_changed(); -} - -String SkeletonModification3DJiggle::get_jiggle_joint_bone_name(int p_joint_idx) const { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, ""); - return jiggle_data_chain[p_joint_idx].bone_name; -} - -int SkeletonModification3DJiggle::get_jiggle_joint_bone_index(int p_joint_idx) const { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1); - return jiggle_data_chain[p_joint_idx].bone_idx; -} - -void SkeletonModification3DJiggle::set_jiggle_joint_bone_index(int p_joint_idx, int p_bone_idx) { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!"); - jiggle_data_chain[p_joint_idx].bone_idx = p_bone_idx; - - if (stack) { - if (stack->skeleton) { - jiggle_data_chain[p_joint_idx].bone_name = stack->skeleton->get_bone_name(p_bone_idx); - } - } - execution_error_found = false; - notify_property_list_changed(); -} - -void SkeletonModification3DJiggle::set_jiggle_joint_override(int p_joint_idx, bool p_override) { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - jiggle_data_chain[p_joint_idx].override_defaults = p_override; - _update_jiggle_joint_data(); - notify_property_list_changed(); -} - -bool SkeletonModification3DJiggle::get_jiggle_joint_override(int p_joint_idx) const { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false); - return jiggle_data_chain[p_joint_idx].override_defaults; -} - -void SkeletonModification3DJiggle::set_jiggle_joint_stiffness(int p_joint_idx, real_t p_stiffness) { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!"); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - jiggle_data_chain[p_joint_idx].stiffness = p_stiffness; -} - -real_t SkeletonModification3DJiggle::get_jiggle_joint_stiffness(int p_joint_idx) const { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1); - return jiggle_data_chain[p_joint_idx].stiffness; -} - -void SkeletonModification3DJiggle::set_jiggle_joint_mass(int p_joint_idx, real_t p_mass) { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!"); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - jiggle_data_chain[p_joint_idx].mass = p_mass; -} - -real_t SkeletonModification3DJiggle::get_jiggle_joint_mass(int p_joint_idx) const { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1); - return jiggle_data_chain[p_joint_idx].mass; -} - -void SkeletonModification3DJiggle::set_jiggle_joint_damping(int p_joint_idx, real_t p_damping) { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!"); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - jiggle_data_chain[p_joint_idx].damping = p_damping; -} - -real_t SkeletonModification3DJiggle::get_jiggle_joint_damping(int p_joint_idx) const { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1); - return jiggle_data_chain[p_joint_idx].damping; -} - -void SkeletonModification3DJiggle::set_jiggle_joint_use_gravity(int p_joint_idx, bool p_use_gravity) { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - jiggle_data_chain[p_joint_idx].use_gravity = p_use_gravity; - notify_property_list_changed(); -} - -bool SkeletonModification3DJiggle::get_jiggle_joint_use_gravity(int p_joint_idx) const { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false); - return jiggle_data_chain[p_joint_idx].use_gravity; -} - -void SkeletonModification3DJiggle::set_jiggle_joint_gravity(int p_joint_idx, Vector3 p_gravity) { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - jiggle_data_chain[p_joint_idx].gravity = p_gravity; -} - -Vector3 SkeletonModification3DJiggle::get_jiggle_joint_gravity(int p_joint_idx) const { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, Vector3(0, 0, 0)); - return jiggle_data_chain[p_joint_idx].gravity; -} - -void SkeletonModification3DJiggle::set_jiggle_joint_roll(int p_joint_idx, real_t p_roll) { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX(p_joint_idx, bone_chain_size); - jiggle_data_chain[p_joint_idx].roll = p_roll; -} - -real_t SkeletonModification3DJiggle::get_jiggle_joint_roll(int p_joint_idx) const { - const int bone_chain_size = jiggle_data_chain.size(); - ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, 0.0); - return jiggle_data_chain[p_joint_idx].roll; -} - -void SkeletonModification3DJiggle::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DJiggle::set_target_node); - ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DJiggle::get_target_node); - - ClassDB::bind_method(D_METHOD("set_jiggle_data_chain_length", "length"), &SkeletonModification3DJiggle::set_jiggle_data_chain_length); - ClassDB::bind_method(D_METHOD("get_jiggle_data_chain_length"), &SkeletonModification3DJiggle::get_jiggle_data_chain_length); - - ClassDB::bind_method(D_METHOD("set_stiffness", "stiffness"), &SkeletonModification3DJiggle::set_stiffness); - ClassDB::bind_method(D_METHOD("get_stiffness"), &SkeletonModification3DJiggle::get_stiffness); - ClassDB::bind_method(D_METHOD("set_mass", "mass"), &SkeletonModification3DJiggle::set_mass); - ClassDB::bind_method(D_METHOD("get_mass"), &SkeletonModification3DJiggle::get_mass); - ClassDB::bind_method(D_METHOD("set_damping", "damping"), &SkeletonModification3DJiggle::set_damping); - ClassDB::bind_method(D_METHOD("get_damping"), &SkeletonModification3DJiggle::get_damping); - ClassDB::bind_method(D_METHOD("set_use_gravity", "use_gravity"), &SkeletonModification3DJiggle::set_use_gravity); - ClassDB::bind_method(D_METHOD("get_use_gravity"), &SkeletonModification3DJiggle::get_use_gravity); - ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &SkeletonModification3DJiggle::set_gravity); - ClassDB::bind_method(D_METHOD("get_gravity"), &SkeletonModification3DJiggle::get_gravity); - - ClassDB::bind_method(D_METHOD("set_use_colliders", "use_colliders"), &SkeletonModification3DJiggle::set_use_colliders); - ClassDB::bind_method(D_METHOD("get_use_colliders"), &SkeletonModification3DJiggle::get_use_colliders); - ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SkeletonModification3DJiggle::set_collision_mask); - ClassDB::bind_method(D_METHOD("get_collision_mask"), &SkeletonModification3DJiggle::get_collision_mask); - - // Jiggle joint data functions - ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone_name", "joint_idx", "name"), &SkeletonModification3DJiggle::set_jiggle_joint_bone_name); - ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone_name", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_bone_name); - ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone_index", "joint_idx", "bone_idx"), &SkeletonModification3DJiggle::set_jiggle_joint_bone_index); - ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone_index", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_bone_index); - ClassDB::bind_method(D_METHOD("set_jiggle_joint_override", "joint_idx", "override"), &SkeletonModification3DJiggle::set_jiggle_joint_override); - ClassDB::bind_method(D_METHOD("get_jiggle_joint_override", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_override); - ClassDB::bind_method(D_METHOD("set_jiggle_joint_stiffness", "joint_idx", "stiffness"), &SkeletonModification3DJiggle::set_jiggle_joint_stiffness); - ClassDB::bind_method(D_METHOD("get_jiggle_joint_stiffness", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_stiffness); - ClassDB::bind_method(D_METHOD("set_jiggle_joint_mass", "joint_idx", "mass"), &SkeletonModification3DJiggle::set_jiggle_joint_mass); - ClassDB::bind_method(D_METHOD("get_jiggle_joint_mass", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_mass); - ClassDB::bind_method(D_METHOD("set_jiggle_joint_damping", "joint_idx", "damping"), &SkeletonModification3DJiggle::set_jiggle_joint_damping); - ClassDB::bind_method(D_METHOD("get_jiggle_joint_damping", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_damping); - ClassDB::bind_method(D_METHOD("set_jiggle_joint_use_gravity", "joint_idx", "use_gravity"), &SkeletonModification3DJiggle::set_jiggle_joint_use_gravity); - ClassDB::bind_method(D_METHOD("get_jiggle_joint_use_gravity", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_use_gravity); - ClassDB::bind_method(D_METHOD("set_jiggle_joint_gravity", "joint_idx", "gravity"), &SkeletonModification3DJiggle::set_jiggle_joint_gravity); - ClassDB::bind_method(D_METHOD("get_jiggle_joint_gravity", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_gravity); - ClassDB::bind_method(D_METHOD("set_jiggle_joint_roll", "joint_idx", "roll"), &SkeletonModification3DJiggle::set_jiggle_joint_roll); - ClassDB::bind_method(D_METHOD("get_jiggle_joint_roll", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_roll); - - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "jiggle_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_jiggle_data_chain_length", "get_jiggle_data_chain_length"); - ADD_GROUP("Default Joint Settings", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stiffness"), "set_stiffness", "get_stiffness"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass"), "set_mass", "get_mass"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01"), "set_damping", "get_damping"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_gravity"), "set_use_gravity", "get_use_gravity"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity"); - ADD_GROUP("", ""); -} - -SkeletonModification3DJiggle::SkeletonModification3DJiggle() { - stack = nullptr; - is_setup = false; - jiggle_data_chain = Vector<Jiggle_Joint_Data>(); - stiffness = 3; - mass = 0.75; - damping = 0.75; - use_gravity = false; - gravity = Vector3(0, -6.0, 0); - enabled = true; -} - -SkeletonModification3DJiggle::~SkeletonModification3DJiggle() { -} diff --git a/scene/resources/skeleton_modification_3d_jiggle.h b/scene/resources/skeleton_modification_3d_jiggle.h deleted file mode 100644 index cca620a72d..0000000000 --- a/scene/resources/skeleton_modification_3d_jiggle.h +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_jiggle.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 SKELETON_MODIFICATION_3D_JIGGLE_H -#define SKELETON_MODIFICATION_3D_JIGGLE_H - -#include "core/templates/local_vector.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -class SkeletonModification3DJiggle : public SkeletonModification3D { - GDCLASS(SkeletonModification3DJiggle, SkeletonModification3D); - -private: - struct Jiggle_Joint_Data { - String bone_name = ""; - int bone_idx = -1; - - bool override_defaults = false; - real_t stiffness = 3; - real_t mass = 0.75; - real_t damping = 0.75; - bool use_gravity = false; - Vector3 gravity = Vector3(0, -6.0, 0); - real_t roll = 0; - - Vector3 cached_rotation = Vector3(0, 0, 0); - Vector3 force = Vector3(0, 0, 0); - Vector3 acceleration = Vector3(0, 0, 0); - Vector3 velocity = Vector3(0, 0, 0); - Vector3 last_position = Vector3(0, 0, 0); - Vector3 dynamic_position = Vector3(0, 0, 0); - - Vector3 last_noncollision_position = Vector3(0, 0, 0); - }; - - NodePath target_node; - ObjectID target_node_cache; - LocalVector<Jiggle_Joint_Data> jiggle_data_chain; - - real_t stiffness = 3; - real_t mass = 0.75; - real_t damping = 0.75; - bool use_gravity = false; - Vector3 gravity = Vector3(0, -6.0, 0); - - bool use_colliders = false; - uint32_t collision_mask = 1; - - void update_cache(); - void _execute_jiggle_joint(int p_joint_idx, Node3D *p_target, real_t p_delta); - void _update_jiggle_joint_data(); - -protected: - static void _bind_methods(); - 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; - -public: - virtual void _execute(real_t p_delta) override; - virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override; - - void set_target_node(const NodePath &p_target_node); - NodePath get_target_node() const; - - void set_stiffness(real_t p_stiffness); - real_t get_stiffness() const; - void set_mass(real_t p_mass); - real_t get_mass() const; - void set_damping(real_t p_damping); - real_t get_damping() const; - - void set_use_gravity(bool p_use_gravity); - bool get_use_gravity() const; - void set_gravity(Vector3 p_gravity); - Vector3 get_gravity() const; - - void set_use_colliders(bool p_use_colliders); - bool get_use_colliders() const; - void set_collision_mask(int p_mask); - int get_collision_mask() const; - - int get_jiggle_data_chain_length(); - void set_jiggle_data_chain_length(int p_new_length); - - void set_jiggle_joint_bone_name(int p_joint_idx, String p_name); - String get_jiggle_joint_bone_name(int p_joint_idx) const; - void set_jiggle_joint_bone_index(int p_joint_idx, int p_idx); - int get_jiggle_joint_bone_index(int p_joint_idx) const; - - void set_jiggle_joint_override(int p_joint_idx, bool p_override); - bool get_jiggle_joint_override(int p_joint_idx) const; - void set_jiggle_joint_stiffness(int p_joint_idx, real_t p_stiffness); - real_t get_jiggle_joint_stiffness(int p_joint_idx) const; - void set_jiggle_joint_mass(int p_joint_idx, real_t p_mass); - real_t get_jiggle_joint_mass(int p_joint_idx) const; - void set_jiggle_joint_damping(int p_joint_idx, real_t p_damping); - real_t get_jiggle_joint_damping(int p_joint_idx) const; - void set_jiggle_joint_use_gravity(int p_joint_idx, bool p_use_gravity); - bool get_jiggle_joint_use_gravity(int p_joint_idx) const; - void set_jiggle_joint_gravity(int p_joint_idx, Vector3 p_gravity); - Vector3 get_jiggle_joint_gravity(int p_joint_idx) const; - void set_jiggle_joint_roll(int p_joint_idx, real_t p_roll); - real_t get_jiggle_joint_roll(int p_joint_idx) const; - - SkeletonModification3DJiggle(); - ~SkeletonModification3DJiggle(); -}; - -#endif // SKELETON_MODIFICATION_3D_JIGGLE_H diff --git a/scene/resources/skeleton_modification_3d_lookat.cpp b/scene/resources/skeleton_modification_3d_lookat.cpp deleted file mode 100644 index 57eedeb64e..0000000000 --- a/scene/resources/skeleton_modification_3d_lookat.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_lookat.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 "scene/resources/skeleton_modification_3d_lookat.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -bool SkeletonModification3DLookAt::_set(const StringName &p_path, const Variant &p_value) { - if (p_path == "lock_rotation_to_plane") { - set_lock_rotation_to_plane(p_value); - } else if (p_path == "lock_rotation_plane") { - set_lock_rotation_plane(p_value); - } else if (p_path == "additional_rotation") { - Vector3 tmp = p_value; - tmp.x = Math::deg_to_rad(tmp.x); - tmp.y = Math::deg_to_rad(tmp.y); - tmp.z = Math::deg_to_rad(tmp.z); - set_additional_rotation(tmp); - } - - return true; -} - -bool SkeletonModification3DLookAt::_get(const StringName &p_path, Variant &r_ret) const { - if (p_path == "lock_rotation_to_plane") { - r_ret = get_lock_rotation_to_plane(); - } else if (p_path == "lock_rotation_plane") { - r_ret = get_lock_rotation_plane(); - } else if (p_path == "additional_rotation") { - Vector3 tmp = get_additional_rotation(); - tmp.x = Math::rad_to_deg(tmp.x); - tmp.y = Math::rad_to_deg(tmp.y); - tmp.z = Math::rad_to_deg(tmp.z); - r_ret = tmp; - } - - return true; -} - -void SkeletonModification3DLookAt::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::BOOL, "lock_rotation_to_plane", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - if (lock_rotation_to_plane) { - p_list->push_back(PropertyInfo(Variant::INT, "lock_rotation_plane", PROPERTY_HINT_ENUM, "X plane,Y plane,Z plane", PROPERTY_USAGE_DEFAULT)); - } - p_list->push_back(PropertyInfo(Variant::VECTOR3, "additional_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); -} - -void SkeletonModification3DLookAt::_execute(real_t p_delta) { - ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, - "Modification is not setup and therefore cannot execute!"); - if (!enabled) { - return; - } - - if (target_node_cache.is_null()) { - _print_execution_error(true, "Target cache is out of date. Attempting to update..."); - update_cache(); - return; - } - - if (bone_idx <= -2) { - bone_idx = stack->skeleton->find_bone(bone_name); - } - - Node3D *target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache)); - if (_print_execution_error(!target || !target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) { - return; - } - if (_print_execution_error(bone_idx <= -1, "Bone index is invalid. Cannot execute modification!")) { - return; - } - Transform3D new_bone_trans = stack->skeleton->get_bone_local_pose_override(bone_idx); - if (new_bone_trans == Transform3D()) { - new_bone_trans = stack->skeleton->get_bone_pose(bone_idx); - } - Vector3 target_pos = stack->skeleton->global_pose_to_local_pose(bone_idx, stack->skeleton->world_transform_to_global_pose(target->get_global_transform())).origin; - - // Lock the rotation to a plane relative to the bone by changing the target position - if (lock_rotation_to_plane) { - if (lock_rotation_plane == ROTATION_PLANE::ROTATION_PLANE_X) { - target_pos.x = new_bone_trans.origin.x; - } else if (lock_rotation_plane == ROTATION_PLANE::ROTATION_PLANE_Y) { - target_pos.y = new_bone_trans.origin.y; - } else if (lock_rotation_plane == ROTATION_PLANE::ROTATION_PLANE_Z) { - target_pos.z = new_bone_trans.origin.z; - } - } - - // Look at the target! - new_bone_trans = new_bone_trans.looking_at(target_pos, Vector3(0, 1, 0)); - // Convert from Z-forward to whatever direction the bone faces. - stack->skeleton->update_bone_rest_forward_vector(bone_idx); - new_bone_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(bone_idx, new_bone_trans.basis); - - // Apply additional rotation - new_bone_trans.basis.rotate_local(Vector3(1, 0, 0), additional_rotation.x); - new_bone_trans.basis.rotate_local(Vector3(0, 1, 0), additional_rotation.y); - new_bone_trans.basis.rotate_local(Vector3(0, 0, 1), additional_rotation.z); - - stack->skeleton->set_bone_local_pose_override(bone_idx, new_bone_trans, stack->strength, true); - stack->skeleton->force_update_bone_children_transforms(bone_idx); - - // If we completed it successfully, then we can set execution_error_found to false - execution_error_found = false; -} - -void SkeletonModification3DLookAt::_setup_modification(SkeletonModificationStack3D *p_stack) { - stack = p_stack; - - if (stack != nullptr) { - is_setup = true; - execution_error_found = false; - update_cache(); - } -} - -void SkeletonModification3DLookAt::set_bone_name(String p_name) { - bone_name = p_name; - if (stack) { - if (stack->skeleton) { - bone_idx = stack->skeleton->find_bone(bone_name); - } - } - execution_error_found = false; - notify_property_list_changed(); -} - -String SkeletonModification3DLookAt::get_bone_name() const { - return bone_name; -} - -int SkeletonModification3DLookAt::get_bone_index() const { - return bone_idx; -} - -void SkeletonModification3DLookAt::set_bone_index(int p_bone_idx) { - ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!"); - bone_idx = p_bone_idx; - - if (stack) { - if (stack->skeleton) { - bone_name = stack->skeleton->get_bone_name(p_bone_idx); - } - } - execution_error_found = false; - notify_property_list_changed(); -} - -void SkeletonModification3DLookAt::update_cache() { - if (!is_setup || !stack) { - _print_execution_error(true, "Cannot update target cache: modification is not properly setup!"); - return; - } - - target_node_cache = ObjectID(); - if (stack->skeleton) { - if (stack->skeleton->is_inside_tree()) { - if (stack->skeleton->has_node(target_node)) { - Node *node = stack->skeleton->get_node(target_node); - ERR_FAIL_COND_MSG(!node || stack->skeleton == node, - "Cannot update target cache: Node is this modification's skeleton or cannot be found!"); - ERR_FAIL_COND_MSG(!node->is_inside_tree(), - "Cannot update target cache: Node is not in the scene tree!"); - target_node_cache = node->get_instance_id(); - - execution_error_found = false; - } - } - } -} - -void SkeletonModification3DLookAt::set_target_node(const NodePath &p_target_node) { - target_node = p_target_node; - update_cache(); -} - -NodePath SkeletonModification3DLookAt::get_target_node() const { - return target_node; -} - -Vector3 SkeletonModification3DLookAt::get_additional_rotation() const { - return additional_rotation; -} - -void SkeletonModification3DLookAt::set_additional_rotation(Vector3 p_offset) { - additional_rotation = p_offset; -} - -bool SkeletonModification3DLookAt::get_lock_rotation_to_plane() const { - return lock_rotation_plane; -} - -void SkeletonModification3DLookAt::set_lock_rotation_to_plane(bool p_lock_rotation) { - lock_rotation_to_plane = p_lock_rotation; - notify_property_list_changed(); -} - -int SkeletonModification3DLookAt::get_lock_rotation_plane() const { - return lock_rotation_plane; -} - -void SkeletonModification3DLookAt::set_lock_rotation_plane(int p_plane) { - lock_rotation_plane = p_plane; -} - -void SkeletonModification3DLookAt::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_bone_name", "name"), &SkeletonModification3DLookAt::set_bone_name); - ClassDB::bind_method(D_METHOD("get_bone_name"), &SkeletonModification3DLookAt::get_bone_name); - - ClassDB::bind_method(D_METHOD("set_bone_index", "bone_idx"), &SkeletonModification3DLookAt::set_bone_index); - ClassDB::bind_method(D_METHOD("get_bone_index"), &SkeletonModification3DLookAt::get_bone_index); - - ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DLookAt::set_target_node); - ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DLookAt::get_target_node); - - ClassDB::bind_method(D_METHOD("set_additional_rotation", "additional_rotation"), &SkeletonModification3DLookAt::set_additional_rotation); - ClassDB::bind_method(D_METHOD("get_additional_rotation"), &SkeletonModification3DLookAt::get_additional_rotation); - - ClassDB::bind_method(D_METHOD("set_lock_rotation_to_plane", "lock_to_plane"), &SkeletonModification3DLookAt::set_lock_rotation_to_plane); - ClassDB::bind_method(D_METHOD("get_lock_rotation_to_plane"), &SkeletonModification3DLookAt::get_lock_rotation_to_plane); - ClassDB::bind_method(D_METHOD("set_lock_rotation_plane", "plane"), &SkeletonModification3DLookAt::set_lock_rotation_plane); - ClassDB::bind_method(D_METHOD("get_lock_rotation_plane"), &SkeletonModification3DLookAt::get_lock_rotation_plane); - - ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_index"), "set_bone_index", "get_bone_index"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node"); -} - -SkeletonModification3DLookAt::SkeletonModification3DLookAt() { - stack = nullptr; - is_setup = false; - bone_name = ""; - bone_idx = -2; - additional_rotation = Vector3(); - lock_rotation_to_plane = false; - enabled = true; -} - -SkeletonModification3DLookAt::~SkeletonModification3DLookAt() { -} diff --git a/scene/resources/skeleton_modification_3d_lookat.h b/scene/resources/skeleton_modification_3d_lookat.h deleted file mode 100644 index 9a25ac530d..0000000000 --- a/scene/resources/skeleton_modification_3d_lookat.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_lookat.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 SKELETON_MODIFICATION_3D_LOOKAT_H -#define SKELETON_MODIFICATION_3D_LOOKAT_H - -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -class SkeletonModification3DLookAt : public SkeletonModification3D { - GDCLASS(SkeletonModification3DLookAt, SkeletonModification3D); - -private: - String bone_name = ""; - int bone_idx = -1; - NodePath target_node; - ObjectID target_node_cache; - - Vector3 additional_rotation = Vector3(1, 0, 0); - bool lock_rotation_to_plane = false; - int lock_rotation_plane = ROTATION_PLANE_X; - - void update_cache(); - -protected: - static void _bind_methods(); - 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; - -public: - enum ROTATION_PLANE { - ROTATION_PLANE_X, - ROTATION_PLANE_Y, - ROTATION_PLANE_Z - }; - - virtual void _execute(real_t p_delta) override; - virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override; - - void set_bone_name(String p_name); - String get_bone_name() const; - - void set_bone_index(int p_idx); - int get_bone_index() const; - - void set_target_node(const NodePath &p_target_node); - NodePath get_target_node() const; - - void set_additional_rotation(Vector3 p_offset); - Vector3 get_additional_rotation() const; - - void set_lock_rotation_to_plane(bool p_lock_to_plane); - bool get_lock_rotation_to_plane() const; - void set_lock_rotation_plane(int p_plane); - int get_lock_rotation_plane() const; - - SkeletonModification3DLookAt(); - ~SkeletonModification3DLookAt(); -}; - -#endif // SKELETON_MODIFICATION_3D_LOOKAT_H diff --git a/scene/resources/skeleton_modification_3d_stackholder.cpp b/scene/resources/skeleton_modification_3d_stackholder.cpp deleted file mode 100644 index 1598badb30..0000000000 --- a/scene/resources/skeleton_modification_3d_stackholder.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_stackholder.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 "scene/resources/skeleton_modification_3d_stackholder.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -bool SkeletonModification3DStackHolder::_set(const StringName &p_path, const Variant &p_value) { - String path = p_path; - - if (path == "held_modification_stack") { - set_held_modification_stack(p_value); - } - return true; -} - -bool SkeletonModification3DStackHolder::_get(const StringName &p_path, Variant &r_ret) const { - String path = p_path; - - if (path == "held_modification_stack") { - r_ret = get_held_modification_stack(); - } - return true; -} - -void SkeletonModification3DStackHolder::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::OBJECT, "held_modification_stack", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModificationStack3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); -} - -void SkeletonModification3DStackHolder::_execute(real_t p_delta) { - ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, - "Modification is not setup and therefore cannot execute!"); - - if (held_modification_stack.is_valid()) { - held_modification_stack->execute(p_delta, execution_mode); - } -} - -void SkeletonModification3DStackHolder::_setup_modification(SkeletonModificationStack3D *p_stack) { - stack = p_stack; - - if (stack != nullptr) { - is_setup = true; - - if (held_modification_stack.is_valid()) { - held_modification_stack->set_skeleton(stack->get_skeleton()); - held_modification_stack->setup(); - } - } -} - -void SkeletonModification3DStackHolder::set_held_modification_stack(Ref<SkeletonModificationStack3D> p_held_stack) { - held_modification_stack = p_held_stack; - - if (is_setup && held_modification_stack.is_valid()) { - held_modification_stack->set_skeleton(stack->get_skeleton()); - held_modification_stack->setup(); - } -} - -Ref<SkeletonModificationStack3D> SkeletonModification3DStackHolder::get_held_modification_stack() const { - return held_modification_stack; -} - -void SkeletonModification3DStackHolder::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_held_modification_stack", "held_modification_stack"), &SkeletonModification3DStackHolder::set_held_modification_stack); - ClassDB::bind_method(D_METHOD("get_held_modification_stack"), &SkeletonModification3DStackHolder::get_held_modification_stack); -} - -SkeletonModification3DStackHolder::SkeletonModification3DStackHolder() { - stack = nullptr; - is_setup = false; - enabled = true; -} - -SkeletonModification3DStackHolder::~SkeletonModification3DStackHolder() { -} diff --git a/scene/resources/skeleton_modification_3d_stackholder.h b/scene/resources/skeleton_modification_3d_stackholder.h deleted file mode 100644 index da39044f97..0000000000 --- a/scene/resources/skeleton_modification_3d_stackholder.h +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_stackholder.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 SKELETON_MODIFICATION_3D_STACKHOLDER_H -#define SKELETON_MODIFICATION_3D_STACKHOLDER_H - -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -class SkeletonModification3DStackHolder : public SkeletonModification3D { - GDCLASS(SkeletonModification3DStackHolder, SkeletonModification3D); - -protected: - static void _bind_methods(); - 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; - -public: - Ref<SkeletonModificationStack3D> held_modification_stack; - - virtual void _execute(real_t p_delta) override; - virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override; - - void set_held_modification_stack(Ref<SkeletonModificationStack3D> p_held_stack); - Ref<SkeletonModificationStack3D> get_held_modification_stack() const; - - SkeletonModification3DStackHolder(); - ~SkeletonModification3DStackHolder(); -}; - -#endif // SKELETON_MODIFICATION_3D_STACKHOLDER_H diff --git a/scene/resources/skeleton_modification_3d_twoboneik.cpp b/scene/resources/skeleton_modification_3d_twoboneik.cpp deleted file mode 100644 index 7d5b4d2b55..0000000000 --- a/scene/resources/skeleton_modification_3d_twoboneik.cpp +++ /dev/null @@ -1,617 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_twoboneik.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 "scene/resources/skeleton_modification_3d_twoboneik.h" -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -bool SkeletonModification3DTwoBoneIK::_set(const StringName &p_path, const Variant &p_value) { - String path = p_path; - - if (path == "use_tip_node") { - set_use_tip_node(p_value); - } else if (path == "tip_node") { - set_tip_node(p_value); - } else if (path == "auto_calculate_joint_length") { - set_auto_calculate_joint_length(p_value); - } else if (path == "use_pole_node") { - set_use_pole_node(p_value); - } else if (path == "pole_node") { - set_pole_node(p_value); - } else if (path == "joint_one_length") { - set_joint_one_length(p_value); - } else if (path == "joint_two_length") { - set_joint_two_length(p_value); - } else if (path == "joint_one/bone_name") { - set_joint_one_bone_name(p_value); - } else if (path == "joint_one/bone_idx") { - set_joint_one_bone_idx(p_value); - } else if (path == "joint_one/roll") { - set_joint_one_roll(Math::deg_to_rad(real_t(p_value))); - } else if (path == "joint_two/bone_name") { - set_joint_two_bone_name(p_value); - } else if (path == "joint_two/bone_idx") { - set_joint_two_bone_idx(p_value); - } else if (path == "joint_two/roll") { - set_joint_two_roll(Math::deg_to_rad(real_t(p_value))); - } - - return true; -} - -bool SkeletonModification3DTwoBoneIK::_get(const StringName &p_path, Variant &r_ret) const { - String path = p_path; - - if (path == "use_tip_node") { - r_ret = get_use_tip_node(); - } else if (path == "tip_node") { - r_ret = get_tip_node(); - } else if (path == "auto_calculate_joint_length") { - r_ret = get_auto_calculate_joint_length(); - } else if (path == "use_pole_node") { - r_ret = get_use_pole_node(); - } else if (path == "pole_node") { - r_ret = get_pole_node(); - } else if (path == "joint_one_length") { - r_ret = get_joint_one_length(); - } else if (path == "joint_two_length") { - r_ret = get_joint_two_length(); - } else if (path == "joint_one/bone_name") { - r_ret = get_joint_one_bone_name(); - } else if (path == "joint_one/bone_idx") { - r_ret = get_joint_one_bone_idx(); - } else if (path == "joint_one/roll") { - r_ret = Math::rad_to_deg(get_joint_one_roll()); - } else if (path == "joint_two/bone_name") { - r_ret = get_joint_two_bone_name(); - } else if (path == "joint_two/bone_idx") { - r_ret = get_joint_two_bone_idx(); - } else if (path == "joint_two/roll") { - r_ret = Math::rad_to_deg(get_joint_two_roll()); - } - - return true; -} - -void SkeletonModification3DTwoBoneIK::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::BOOL, "use_tip_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - if (use_tip_node) { - p_list->push_back(PropertyInfo(Variant::NODE_PATH, "tip_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D", PROPERTY_USAGE_DEFAULT)); - } - - p_list->push_back(PropertyInfo(Variant::BOOL, "auto_calculate_joint_length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - if (!auto_calculate_joint_length) { - p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_one_length", PROPERTY_HINT_RANGE, "-1, 10000, 0.001", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_two_length", PROPERTY_HINT_RANGE, "-1, 10000, 0.001", PROPERTY_USAGE_DEFAULT)); - } - - p_list->push_back(PropertyInfo(Variant::BOOL, "use_pole_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - if (use_pole_node) { - p_list->push_back(PropertyInfo(Variant::NODE_PATH, "pole_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D", PROPERTY_USAGE_DEFAULT)); - } - - p_list->push_back(PropertyInfo(Variant::STRING_NAME, "joint_one/bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::INT, "joint_one/bone_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_one/roll", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT)); - - p_list->push_back(PropertyInfo(Variant::STRING_NAME, "joint_two/bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::INT, "joint_two/bone_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_two/roll", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT)); -} - -void SkeletonModification3DTwoBoneIK::_execute(real_t p_delta) { - ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, - "Modification is not setup and therefore cannot execute!"); - - if (!enabled) { - return; - } - - if (_print_execution_error(joint_one_bone_idx < 0 || joint_two_bone_idx < 0, - "One (or more) of the bones in the modification have invalid bone indexes. Cannot execute modification!")) { - return; - } - - if (target_node_cache.is_null()) { - _print_execution_error(true, "Target cache is out of date. Attempting to update..."); - update_cache_target(); - return; - } - - // Update joint lengths (if needed) - if (auto_calculate_joint_length && (joint_one_length < 0 || joint_two_length < 0)) { - calculate_joint_lengths(); - } - - // Adopted from the links below: - // http://theorangeduck.com/page/simple-two-joint - // https://www.alanzucconi.com/2018/05/02/ik-2d-2/ - // With modifications by TwistedTwigleg - Node3D *target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache)); - if (_print_execution_error(!target || !target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) { - return; - } - Transform3D target_trans = stack->skeleton->world_transform_to_global_pose(target->get_global_transform()); - - Transform3D bone_one_trans; - Transform3D bone_two_trans; - - // Make the first joint look at the pole, and the second look at the target. That way, the - // TwoBoneIK solver has to really only handle extension/contraction, which should make it align with the pole. - if (use_pole_node) { - if (pole_node_cache.is_null()) { - _print_execution_error(true, "Pole cache is out of date. Attempting to update..."); - update_cache_pole(); - return; - } - - Node3D *pole = Object::cast_to<Node3D>(ObjectDB::get_instance(pole_node_cache)); - if (_print_execution_error(!pole || !pole->is_inside_tree(), "Pole node is not in the scene tree. Cannot execute modification!")) { - return; - } - Transform3D pole_trans = stack->skeleton->world_transform_to_global_pose(pole->get_global_transform()); - - Transform3D bone_one_local_pos = stack->skeleton->get_bone_local_pose_override(joint_one_bone_idx); - if (bone_one_local_pos == Transform3D()) { - bone_one_local_pos = stack->skeleton->get_bone_pose(joint_one_bone_idx); - } - Transform3D bone_two_local_pos = stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx); - if (bone_two_local_pos == Transform3D()) { - bone_two_local_pos = stack->skeleton->get_bone_pose(joint_two_bone_idx); - } - - bone_one_trans = stack->skeleton->local_pose_to_global_pose(joint_one_bone_idx, bone_one_local_pos); - bone_one_trans = bone_one_trans.looking_at(pole_trans.origin, Vector3(0, 1, 0)); - bone_one_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(joint_one_bone_idx, bone_one_trans.basis); - stack->skeleton->update_bone_rest_forward_vector(joint_one_bone_idx); - bone_one_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_one_bone_idx), joint_one_roll); - stack->skeleton->set_bone_local_pose_override(joint_one_bone_idx, stack->skeleton->global_pose_to_local_pose(joint_one_bone_idx, bone_one_trans), stack->strength, true); - stack->skeleton->force_update_bone_children_transforms(joint_one_bone_idx); - - bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, bone_two_local_pos); - bone_two_trans = bone_two_trans.looking_at(target_trans.origin, Vector3(0, 1, 0)); - bone_two_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(joint_two_bone_idx, bone_two_trans.basis); - stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx); - bone_two_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx), joint_two_roll); - stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, stack->skeleton->global_pose_to_local_pose(joint_two_bone_idx, bone_two_trans), stack->strength, true); - stack->skeleton->force_update_bone_children_transforms(joint_two_bone_idx); - } else { - Transform3D bone_one_local_pos = stack->skeleton->get_bone_local_pose_override(joint_one_bone_idx); - if (bone_one_local_pos == Transform3D()) { - bone_one_local_pos = stack->skeleton->get_bone_pose(joint_one_bone_idx); - } - Transform3D bone_two_local_pos = stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx); - if (bone_two_local_pos == Transform3D()) { - bone_two_local_pos = stack->skeleton->get_bone_pose(joint_two_bone_idx); - } - - bone_one_trans = stack->skeleton->local_pose_to_global_pose(joint_one_bone_idx, bone_one_local_pos); - bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, bone_two_local_pos); - } - - Transform3D bone_two_tip_trans; - if (use_tip_node) { - if (tip_node_cache.is_null()) { - _print_execution_error(true, "Tip cache is out of date. Attempting to update..."); - update_cache_tip(); - return; - } - Node3D *tip = Object::cast_to<Node3D>(ObjectDB::get_instance(tip_node_cache)); - if (_print_execution_error(!tip || !tip->is_inside_tree(), "Tip node is not in the scene tree. Cannot execute modification!")) { - return; - } - bone_two_tip_trans = stack->skeleton->world_transform_to_global_pose(tip->get_global_transform()); - } else { - stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx); - bone_two_tip_trans = bone_two_trans; - bone_two_tip_trans.origin += bone_two_trans.basis.xform(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx)).normalized() * joint_two_length; - } - - real_t joint_one_to_target_length = bone_one_trans.origin.distance_to(target_trans.origin); - if (joint_one_length + joint_two_length < joint_one_to_target_length) { - // Set the target *just* out of reach to straighten the bones - joint_one_to_target_length = joint_one_length + joint_two_length + 0.01; - } else if (joint_one_to_target_length < joint_one_length) { - // Place the target in reach so the solver doesn't do crazy things - joint_one_to_target_length = joint_one_length; - } - - // Get the square lengths for all three sides of the triangle we'll use to calculate the angles - real_t sqr_one_length = joint_one_length * joint_one_length; - real_t sqr_two_length = joint_two_length * joint_two_length; - real_t sqr_three_length = joint_one_to_target_length * joint_one_to_target_length; - - // Calculate the angles for the first joint using the law of cosigns - real_t ac_ab_0 = Math::acos(CLAMP(bone_two_tip_trans.origin.direction_to(bone_one_trans.origin).dot(bone_two_trans.origin.direction_to(bone_one_trans.origin)), -1, 1)); - real_t ac_at_0 = Math::acos(CLAMP(bone_one_trans.origin.direction_to(bone_two_tip_trans.origin).dot(bone_one_trans.origin.direction_to(target_trans.origin)), -1, 1)); - real_t ac_ab_1 = Math::acos(CLAMP((sqr_two_length - sqr_one_length - sqr_three_length) / (-2.0 * joint_one_length * joint_one_to_target_length), -1, 1)); - - // Calculate the angles of rotation. Angle 0 is the extension/contraction axis, while angle 1 is the rotation axis to align the triangle to the target - Vector3 axis_0 = bone_one_trans.origin.direction_to(bone_two_tip_trans.origin).cross(bone_one_trans.origin.direction_to(bone_two_trans.origin)); - Vector3 axis_1 = bone_one_trans.origin.direction_to(bone_two_tip_trans.origin).cross(bone_one_trans.origin.direction_to(target_trans.origin)); - - // Make a quaternion with the delta rotation needed to rotate the first joint into alignment and apply it to the transform. - Quaternion bone_one_quat = bone_one_trans.basis.get_rotation_quaternion(); - Quaternion rot_0 = Quaternion(bone_one_quat.inverse().xform(axis_0).normalized(), (ac_ab_1 - ac_ab_0)); - Quaternion rot_2 = Quaternion(bone_one_quat.inverse().xform(axis_1).normalized(), ac_at_0); - bone_one_trans.basis.set_quaternion(bone_one_quat * (rot_0 * rot_2)); - - stack->skeleton->update_bone_rest_forward_vector(joint_one_bone_idx); - bone_one_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_one_bone_idx), joint_one_roll); - - // Apply the rotation to the first joint - bone_one_trans = stack->skeleton->global_pose_to_local_pose(joint_one_bone_idx, bone_one_trans); - bone_one_trans.origin = Vector3(0, 0, 0); - stack->skeleton->set_bone_local_pose_override(joint_one_bone_idx, bone_one_trans, stack->strength, true); - stack->skeleton->force_update_bone_children_transforms(joint_one_bone_idx); - - if (use_pole_node) { - // Update bone_two_trans so its at the latest position, with the rotation of bone_one_trans taken into account, then look at the target. - bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx)); - stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx); - Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx); - bone_two_trans.basis.rotate_to_align(forward_vector, bone_two_trans.origin.direction_to(target_trans.origin)); - - stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx); - bone_two_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx), joint_two_roll); - - bone_two_trans = stack->skeleton->global_pose_to_local_pose(joint_two_bone_idx, bone_two_trans); - stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, bone_two_trans, stack->strength, true); - stack->skeleton->force_update_bone_children_transforms(joint_two_bone_idx); - } else { - // Calculate the angles for the second joint using the law of cosigns, make a quaternion with the delta rotation needed to rotate the joint into - // alignment, and then apply it to the second joint. - real_t ba_bc_0 = Math::acos(CLAMP(bone_two_trans.origin.direction_to(bone_one_trans.origin).dot(bone_two_trans.origin.direction_to(bone_two_tip_trans.origin)), -1, 1)); - real_t ba_bc_1 = Math::acos(CLAMP((sqr_three_length - sqr_one_length - sqr_two_length) / (-2.0 * joint_one_length * joint_two_length), -1, 1)); - Quaternion bone_two_quat = bone_two_trans.basis.get_rotation_quaternion(); - Quaternion rot_1 = Quaternion(bone_two_quat.inverse().xform(axis_0).normalized(), (ba_bc_1 - ba_bc_0)); - bone_two_trans.basis.set_quaternion(bone_two_quat * rot_1); - - stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx); - bone_two_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx), joint_two_roll); - - bone_two_trans = stack->skeleton->global_pose_to_local_pose(joint_two_bone_idx, bone_two_trans); - bone_two_trans.origin = Vector3(0, 0, 0); - stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, bone_two_trans, stack->strength, true); - stack->skeleton->force_update_bone_children_transforms(joint_two_bone_idx); - } -} - -void SkeletonModification3DTwoBoneIK::_setup_modification(SkeletonModificationStack3D *p_stack) { - stack = p_stack; - - if (stack != nullptr) { - is_setup = true; - execution_error_found = false; - update_cache_target(); - update_cache_tip(); - } -} - -void SkeletonModification3DTwoBoneIK::update_cache_target() { - if (!is_setup || !stack) { - _print_execution_error(true, "Cannot update target cache: modification is not properly setup!"); - return; - } - - target_node_cache = ObjectID(); - if (stack->skeleton) { - if (stack->skeleton->is_inside_tree() && target_node.is_empty() == false) { - if (stack->skeleton->has_node(target_node)) { - Node *node = stack->skeleton->get_node(target_node); - ERR_FAIL_COND_MSG(!node || stack->skeleton == node, - "Cannot update target cache: Target node is this modification's skeleton or cannot be found. Cannot execute modification"); - ERR_FAIL_COND_MSG(!node->is_inside_tree(), - "Cannot update target cache: Target node is not in the scene tree. Cannot execute modification!"); - target_node_cache = node->get_instance_id(); - - execution_error_found = false; - } - } - } -} - -void SkeletonModification3DTwoBoneIK::update_cache_tip() { - if (!is_setup || !stack) { - _print_execution_error(true, "Cannot update tip cache: modification is not properly setup!"); - return; - } - - tip_node_cache = ObjectID(); - if (stack->skeleton) { - if (stack->skeleton->is_inside_tree()) { - if (stack->skeleton->has_node(tip_node)) { - Node *node = stack->skeleton->get_node(tip_node); - ERR_FAIL_COND_MSG(!node || stack->skeleton == node, - "Cannot update tip cache: Tip node is this modification's skeleton or cannot be found!"); - ERR_FAIL_COND_MSG(!node->is_inside_tree(), - "Cannot update tip cache: Tip node is not in the scene tree. Cannot execute modification!"); - tip_node_cache = node->get_instance_id(); - - execution_error_found = false; - } - } - } -} - -void SkeletonModification3DTwoBoneIK::update_cache_pole() { - if (!is_setup || !stack) { - _print_execution_error(true, "Cannot update pole cache: modification is not properly setup!"); - return; - } - - pole_node_cache = ObjectID(); - if (stack->skeleton) { - if (stack->skeleton->is_inside_tree()) { - if (stack->skeleton->has_node(pole_node)) { - Node *node = stack->skeleton->get_node(pole_node); - ERR_FAIL_COND_MSG(!node || stack->skeleton == node, - "Cannot update pole cache: Pole node is this modification's skeleton or cannot be found!"); - ERR_FAIL_COND_MSG(!node->is_inside_tree(), - "Cannot update pole cache: Pole node is not in the scene tree. Cannot execute modification!"); - pole_node_cache = node->get_instance_id(); - - execution_error_found = false; - } - } - } -} - -void SkeletonModification3DTwoBoneIK::set_target_node(const NodePath &p_target_node) { - target_node = p_target_node; - update_cache_target(); -} - -NodePath SkeletonModification3DTwoBoneIK::get_target_node() const { - return target_node; -} - -void SkeletonModification3DTwoBoneIK::set_use_tip_node(const bool p_use_tip_node) { - use_tip_node = p_use_tip_node; - notify_property_list_changed(); -} - -bool SkeletonModification3DTwoBoneIK::get_use_tip_node() const { - return use_tip_node; -} - -void SkeletonModification3DTwoBoneIK::set_tip_node(const NodePath &p_tip_node) { - tip_node = p_tip_node; - update_cache_tip(); -} - -NodePath SkeletonModification3DTwoBoneIK::get_tip_node() const { - return tip_node; -} - -void SkeletonModification3DTwoBoneIK::set_use_pole_node(const bool p_use_pole_node) { - use_pole_node = p_use_pole_node; - notify_property_list_changed(); -} - -bool SkeletonModification3DTwoBoneIK::get_use_pole_node() const { - return use_pole_node; -} - -void SkeletonModification3DTwoBoneIK::set_pole_node(const NodePath &p_pole_node) { - pole_node = p_pole_node; - update_cache_pole(); -} - -NodePath SkeletonModification3DTwoBoneIK::get_pole_node() const { - return pole_node; -} - -void SkeletonModification3DTwoBoneIK::set_auto_calculate_joint_length(bool p_calculate) { - auto_calculate_joint_length = p_calculate; - if (p_calculate) { - calculate_joint_lengths(); - } - notify_property_list_changed(); -} - -bool SkeletonModification3DTwoBoneIK::get_auto_calculate_joint_length() const { - return auto_calculate_joint_length; -} - -void SkeletonModification3DTwoBoneIK::calculate_joint_lengths() { - if (!is_setup) { - return; // fail silently, as we likely just loaded the scene. - } - ERR_FAIL_COND_MSG(!stack || stack->skeleton == nullptr, - "Modification is not setup and therefore cannot calculate joint lengths!"); - ERR_FAIL_COND_MSG(joint_one_bone_idx <= -1 || joint_two_bone_idx <= -1, - "One of the bones in the TwoBoneIK modification are not set! Cannot calculate joint lengths!"); - - Transform3D bone_one_rest_trans = stack->skeleton->get_bone_global_pose(joint_one_bone_idx); - Transform3D bone_two_rest_trans = stack->skeleton->get_bone_global_pose(joint_two_bone_idx); - - joint_one_length = bone_one_rest_trans.origin.distance_to(bone_two_rest_trans.origin); - - if (use_tip_node) { - if (tip_node_cache.is_null()) { - update_cache_tip(); - WARN_PRINT("Tip cache is out of date. Updating..."); - } - - Node3D *tip = Object::cast_to<Node3D>(ObjectDB::get_instance(tip_node_cache)); - if (tip) { - Transform3D bone_tip_trans = stack->skeleton->world_transform_to_global_pose(tip->get_global_transform()); - joint_two_length = bone_two_rest_trans.origin.distance_to(bone_tip_trans.origin); - } - } else { - // Attempt to use children bones to get the length - Vector<int> bone_two_children = stack->skeleton->get_bone_children(joint_two_bone_idx); - if (bone_two_children.size() > 0) { - joint_two_length = 0; - for (int i = 0; i < bone_two_children.size(); i++) { - joint_two_length += bone_two_rest_trans.origin.distance_to( - stack->skeleton->get_bone_global_pose(bone_two_children[i]).origin); - } - joint_two_length = joint_two_length / bone_two_children.size(); - } else { - WARN_PRINT("TwoBoneIK modification: Cannot auto calculate length for joint 2! Auto setting the length to 1..."); - joint_two_length = 1.0; - } - } - execution_error_found = false; -} - -void SkeletonModification3DTwoBoneIK::set_joint_one_bone_name(String p_bone_name) { - joint_one_bone_name = p_bone_name; - if (stack && stack->skeleton) { - joint_one_bone_idx = stack->skeleton->find_bone(p_bone_name); - } - execution_error_found = false; - notify_property_list_changed(); -} - -String SkeletonModification3DTwoBoneIK::get_joint_one_bone_name() const { - return joint_one_bone_name; -} - -void SkeletonModification3DTwoBoneIK::set_joint_one_bone_idx(int p_bone_idx) { - joint_one_bone_idx = p_bone_idx; - if (stack && stack->skeleton) { - joint_one_bone_name = stack->skeleton->get_bone_name(p_bone_idx); - } - execution_error_found = false; - notify_property_list_changed(); -} - -int SkeletonModification3DTwoBoneIK::get_joint_one_bone_idx() const { - return joint_one_bone_idx; -} - -void SkeletonModification3DTwoBoneIK::set_joint_one_length(real_t p_length) { - joint_one_length = p_length; -} - -real_t SkeletonModification3DTwoBoneIK::get_joint_one_length() const { - return joint_one_length; -} - -void SkeletonModification3DTwoBoneIK::set_joint_two_bone_name(String p_bone_name) { - joint_two_bone_name = p_bone_name; - if (stack && stack->skeleton) { - joint_two_bone_idx = stack->skeleton->find_bone(p_bone_name); - } - execution_error_found = false; - notify_property_list_changed(); -} - -String SkeletonModification3DTwoBoneIK::get_joint_two_bone_name() const { - return joint_two_bone_name; -} - -void SkeletonModification3DTwoBoneIK::set_joint_two_bone_idx(int p_bone_idx) { - joint_two_bone_idx = p_bone_idx; - if (stack && stack->skeleton) { - joint_two_bone_name = stack->skeleton->get_bone_name(p_bone_idx); - } - execution_error_found = false; - notify_property_list_changed(); -} - -int SkeletonModification3DTwoBoneIK::get_joint_two_bone_idx() const { - return joint_two_bone_idx; -} - -void SkeletonModification3DTwoBoneIK::set_joint_two_length(real_t p_length) { - joint_two_length = p_length; -} - -real_t SkeletonModification3DTwoBoneIK::get_joint_two_length() const { - return joint_two_length; -} - -void SkeletonModification3DTwoBoneIK::set_joint_one_roll(real_t p_roll) { - joint_one_roll = p_roll; -} - -real_t SkeletonModification3DTwoBoneIK::get_joint_one_roll() const { - return joint_one_roll; -} - -void SkeletonModification3DTwoBoneIK::set_joint_two_roll(real_t p_roll) { - joint_two_roll = p_roll; -} - -real_t SkeletonModification3DTwoBoneIK::get_joint_two_roll() const { - return joint_two_roll; -} - -void SkeletonModification3DTwoBoneIK::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DTwoBoneIK::set_target_node); - ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DTwoBoneIK::get_target_node); - - ClassDB::bind_method(D_METHOD("set_use_pole_node", "use_pole_node"), &SkeletonModification3DTwoBoneIK::set_use_pole_node); - ClassDB::bind_method(D_METHOD("get_use_pole_node"), &SkeletonModification3DTwoBoneIK::get_use_pole_node); - ClassDB::bind_method(D_METHOD("set_pole_node", "pole_nodepath"), &SkeletonModification3DTwoBoneIK::set_pole_node); - ClassDB::bind_method(D_METHOD("get_pole_node"), &SkeletonModification3DTwoBoneIK::get_pole_node); - - ClassDB::bind_method(D_METHOD("set_use_tip_node", "use_tip_node"), &SkeletonModification3DTwoBoneIK::set_use_tip_node); - ClassDB::bind_method(D_METHOD("get_use_tip_node"), &SkeletonModification3DTwoBoneIK::get_use_tip_node); - ClassDB::bind_method(D_METHOD("set_tip_node", "tip_nodepath"), &SkeletonModification3DTwoBoneIK::set_tip_node); - ClassDB::bind_method(D_METHOD("get_tip_node"), &SkeletonModification3DTwoBoneIK::get_tip_node); - - ClassDB::bind_method(D_METHOD("set_auto_calculate_joint_length", "auto_calculate_joint_length"), &SkeletonModification3DTwoBoneIK::set_auto_calculate_joint_length); - ClassDB::bind_method(D_METHOD("get_auto_calculate_joint_length"), &SkeletonModification3DTwoBoneIK::get_auto_calculate_joint_length); - - ClassDB::bind_method(D_METHOD("set_joint_one_bone_name", "bone_name"), &SkeletonModification3DTwoBoneIK::set_joint_one_bone_name); - ClassDB::bind_method(D_METHOD("get_joint_one_bone_name"), &SkeletonModification3DTwoBoneIK::get_joint_one_bone_name); - ClassDB::bind_method(D_METHOD("set_joint_one_bone_idx", "bone_idx"), &SkeletonModification3DTwoBoneIK::set_joint_one_bone_idx); - ClassDB::bind_method(D_METHOD("get_joint_one_bone_idx"), &SkeletonModification3DTwoBoneIK::get_joint_one_bone_idx); - ClassDB::bind_method(D_METHOD("set_joint_one_length", "bone_length"), &SkeletonModification3DTwoBoneIK::set_joint_one_length); - ClassDB::bind_method(D_METHOD("get_joint_one_length"), &SkeletonModification3DTwoBoneIK::get_joint_one_length); - - ClassDB::bind_method(D_METHOD("set_joint_two_bone_name", "bone_name"), &SkeletonModification3DTwoBoneIK::set_joint_two_bone_name); - ClassDB::bind_method(D_METHOD("get_joint_two_bone_name"), &SkeletonModification3DTwoBoneIK::get_joint_two_bone_name); - ClassDB::bind_method(D_METHOD("set_joint_two_bone_idx", "bone_idx"), &SkeletonModification3DTwoBoneIK::set_joint_two_bone_idx); - ClassDB::bind_method(D_METHOD("get_joint_two_bone_idx"), &SkeletonModification3DTwoBoneIK::get_joint_two_bone_idx); - ClassDB::bind_method(D_METHOD("set_joint_two_length", "bone_length"), &SkeletonModification3DTwoBoneIK::set_joint_two_length); - ClassDB::bind_method(D_METHOD("get_joint_two_length"), &SkeletonModification3DTwoBoneIK::get_joint_two_length); - - ClassDB::bind_method(D_METHOD("set_joint_one_roll", "roll"), &SkeletonModification3DTwoBoneIK::set_joint_one_roll); - ClassDB::bind_method(D_METHOD("get_joint_one_roll"), &SkeletonModification3DTwoBoneIK::get_joint_one_roll); - ClassDB::bind_method(D_METHOD("set_joint_two_roll", "roll"), &SkeletonModification3DTwoBoneIK::set_joint_two_roll); - ClassDB::bind_method(D_METHOD("get_joint_two_roll"), &SkeletonModification3DTwoBoneIK::get_joint_two_roll); - - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node"); - ADD_GROUP("", ""); -} - -SkeletonModification3DTwoBoneIK::SkeletonModification3DTwoBoneIK() { - stack = nullptr; - is_setup = false; -} - -SkeletonModification3DTwoBoneIK::~SkeletonModification3DTwoBoneIK() { -} diff --git a/scene/resources/skeleton_modification_3d_twoboneik.h b/scene/resources/skeleton_modification_3d_twoboneik.h deleted file mode 100644 index 57481e0181..0000000000 --- a/scene/resources/skeleton_modification_3d_twoboneik.h +++ /dev/null @@ -1,118 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_3d_twoboneik.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 SKELETON_MODIFICATION_3D_TWOBONEIK_H -#define SKELETON_MODIFICATION_3D_TWOBONEIK_H - -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - -class SkeletonModification3DTwoBoneIK : public SkeletonModification3D { - GDCLASS(SkeletonModification3DTwoBoneIK, SkeletonModification3D); - -private: - NodePath target_node; - ObjectID target_node_cache; - - bool use_tip_node = false; - NodePath tip_node; - ObjectID tip_node_cache; - - bool use_pole_node = false; - NodePath pole_node; - ObjectID pole_node_cache; - - String joint_one_bone_name = ""; - int joint_one_bone_idx = -1; - String joint_two_bone_name = ""; - int joint_two_bone_idx = -1; - - bool auto_calculate_joint_length = false; - real_t joint_one_length = -1; - real_t joint_two_length = -1; - - real_t joint_one_roll = 0; - real_t joint_two_roll = 0; - - void update_cache_target(); - void update_cache_tip(); - void update_cache_pole(); - -protected: - static void _bind_methods(); - 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; - -public: - virtual void _execute(real_t p_delta) override; - virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override; - - void set_target_node(const NodePath &p_target_node); - NodePath get_target_node() const; - - void set_use_tip_node(const bool p_use_tip_node); - bool get_use_tip_node() const; - void set_tip_node(const NodePath &p_tip_node); - NodePath get_tip_node() const; - - void set_use_pole_node(const bool p_use_pole_node); - bool get_use_pole_node() const; - void set_pole_node(const NodePath &p_pole_node); - NodePath get_pole_node() const; - - void set_auto_calculate_joint_length(bool p_calculate); - bool get_auto_calculate_joint_length() const; - void calculate_joint_lengths(); - - void set_joint_one_bone_name(String p_bone_name); - String get_joint_one_bone_name() const; - void set_joint_one_bone_idx(int p_bone_idx); - int get_joint_one_bone_idx() const; - void set_joint_one_length(real_t p_length); - real_t get_joint_one_length() const; - - void set_joint_two_bone_name(String p_bone_name); - String get_joint_two_bone_name() const; - void set_joint_two_bone_idx(int p_bone_idx); - int get_joint_two_bone_idx() const; - void set_joint_two_length(real_t p_length); - real_t get_joint_two_length() const; - - void set_joint_one_roll(real_t p_roll); - real_t get_joint_one_roll() const; - void set_joint_two_roll(real_t p_roll); - real_t get_joint_two_roll() const; - - SkeletonModification3DTwoBoneIK(); - ~SkeletonModification3DTwoBoneIK(); -}; - -#endif // SKELETON_MODIFICATION_3D_TWOBONEIK_H diff --git a/scene/resources/skeleton_modification_stack_3d.cpp b/scene/resources/skeleton_modification_stack_3d.cpp deleted file mode 100644 index 32708e198a..0000000000 --- a/scene/resources/skeleton_modification_stack_3d.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_stack_3d.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 "skeleton_modification_stack_3d.h" -#include "scene/3d/skeleton_3d.h" - -/////////////////////////////////////// -// ModificationStack3D -/////////////////////////////////////// - -void SkeletonModificationStack3D::_get_property_list(List<PropertyInfo> *p_list) const { - for (uint32_t i = 0; i < modifications.size(); i++) { - p_list->push_back( - PropertyInfo(Variant::OBJECT, "modifications/" + itos(i), - PROPERTY_HINT_RESOURCE_TYPE, - "SkeletonModification3D", - PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); - } -} - -bool SkeletonModificationStack3D::_set(const StringName &p_path, const Variant &p_value) { - String path = p_path; - - if (path.begins_with("modifications/")) { - int mod_idx = path.get_slicec('/', 1).to_int(); - set_modification(mod_idx, p_value); - return true; - } - return true; -} - -bool SkeletonModificationStack3D::_get(const StringName &p_path, Variant &r_ret) const { - String path = p_path; - - if (path.begins_with("modifications/")) { - int mod_idx = path.get_slicec('/', 1).to_int(); - r_ret = get_modification(mod_idx); - return true; - } - return true; -} - -void SkeletonModificationStack3D::setup() { - if (is_setup) { - return; - } - - if (skeleton != nullptr) { - is_setup = true; - for (uint32_t i = 0; i < modifications.size(); i++) { - if (!modifications[i].is_valid()) { - continue; - } - modifications[i]->_setup_modification(this); - } - } else { - WARN_PRINT("Cannot setup SkeletonModificationStack3D: no skeleton set!"); - } -} - -void SkeletonModificationStack3D::execute(real_t p_delta, int p_execution_mode) { - ERR_FAIL_COND_MSG(!is_setup || skeleton == nullptr || is_queued_for_deletion(), - "Modification stack is not properly setup and therefore cannot execute!"); - - if (!skeleton->is_inside_tree()) { - ERR_PRINT_ONCE("Skeleton is not inside SceneTree! Cannot execute modification!"); - return; - } - - if (!enabled) { - return; - } - - for (uint32_t i = 0; i < modifications.size(); i++) { - if (!modifications[i].is_valid()) { - continue; - } - - if (modifications[i]->get_execution_mode() == p_execution_mode) { - modifications[i]->_execute(p_delta); - } - } -} - -void SkeletonModificationStack3D::enable_all_modifications(bool p_enabled) { - for (uint32_t i = 0; i < modifications.size(); i++) { - if (!modifications[i].is_valid()) { - continue; - } - modifications[i]->set_enabled(p_enabled); - } -} - -Ref<SkeletonModification3D> SkeletonModificationStack3D::get_modification(int p_mod_idx) const { - const int modifications_size = modifications.size(); - ERR_FAIL_INDEX_V(p_mod_idx, modifications_size, nullptr); - return modifications[p_mod_idx]; -} - -void SkeletonModificationStack3D::add_modification(Ref<SkeletonModification3D> p_mod) { - ERR_FAIL_NULL(p_mod); - p_mod->_setup_modification(this); - modifications.push_back(p_mod); -} - -void SkeletonModificationStack3D::delete_modification(int p_mod_idx) { - const int modifications_size = modifications.size(); - ERR_FAIL_INDEX(p_mod_idx, modifications_size); - modifications.remove_at(p_mod_idx); -} - -void SkeletonModificationStack3D::set_modification(int p_mod_idx, Ref<SkeletonModification3D> p_mod) { - const int modifications_size = modifications.size(); - ERR_FAIL_INDEX(p_mod_idx, modifications_size); - - if (p_mod == nullptr) { - modifications.remove_at(p_mod_idx); - } else { - p_mod->_setup_modification(this); - modifications[p_mod_idx] = p_mod; - } -} - -void SkeletonModificationStack3D::set_modification_count(int p_count) { - ERR_FAIL_COND_MSG(p_count < 0, "Modification count cannot be less than zero."); - modifications.resize(p_count); - notify_property_list_changed(); -} - -int SkeletonModificationStack3D::get_modification_count() const { - return modifications.size(); -} - -void SkeletonModificationStack3D::set_skeleton(Skeleton3D *p_skeleton) { - skeleton = p_skeleton; -} - -Skeleton3D *SkeletonModificationStack3D::get_skeleton() const { - return skeleton; -} - -bool SkeletonModificationStack3D::get_is_setup() const { - return is_setup; -} - -void SkeletonModificationStack3D::set_enabled(bool p_enabled) { - enabled = p_enabled; - - if (!enabled && is_setup && skeleton != nullptr) { - skeleton->clear_bones_local_pose_override(); - } -} - -bool SkeletonModificationStack3D::get_enabled() const { - return enabled; -} - -void SkeletonModificationStack3D::set_strength(real_t p_strength) { - ERR_FAIL_COND_MSG(p_strength < 0, "Strength cannot be less than zero!"); - ERR_FAIL_COND_MSG(p_strength > 1, "Strength cannot be more than one!"); - strength = p_strength; -} - -real_t SkeletonModificationStack3D::get_strength() const { - return strength; -} - -void SkeletonModificationStack3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("setup"), &SkeletonModificationStack3D::setup); - ClassDB::bind_method(D_METHOD("execute", "delta", "execution_mode"), &SkeletonModificationStack3D::execute); - - ClassDB::bind_method(D_METHOD("enable_all_modifications", "enabled"), &SkeletonModificationStack3D::enable_all_modifications); - ClassDB::bind_method(D_METHOD("get_modification", "mod_idx"), &SkeletonModificationStack3D::get_modification); - ClassDB::bind_method(D_METHOD("add_modification", "modification"), &SkeletonModificationStack3D::add_modification); - ClassDB::bind_method(D_METHOD("delete_modification", "mod_idx"), &SkeletonModificationStack3D::delete_modification); - ClassDB::bind_method(D_METHOD("set_modification", "mod_idx", "modification"), &SkeletonModificationStack3D::set_modification); - - ClassDB::bind_method(D_METHOD("set_modification_count", "count"), &SkeletonModificationStack3D::set_modification_count); - ClassDB::bind_method(D_METHOD("get_modification_count"), &SkeletonModificationStack3D::get_modification_count); - - ClassDB::bind_method(D_METHOD("get_is_setup"), &SkeletonModificationStack3D::get_is_setup); - - ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModificationStack3D::set_enabled); - ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModificationStack3D::get_enabled); - - ClassDB::bind_method(D_METHOD("set_strength", "strength"), &SkeletonModificationStack3D::set_strength); - ClassDB::bind_method(D_METHOD("get_strength"), &SkeletonModificationStack3D::get_strength); - - ClassDB::bind_method(D_METHOD("get_skeleton"), &SkeletonModificationStack3D::get_skeleton); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0, 1, 0.001"), "set_strength", "get_strength"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Modifications,modifications/"), "set_modification_count", "get_modification_count"); -} - -SkeletonModificationStack3D::SkeletonModificationStack3D() { -} diff --git a/scene/resources/skeleton_modification_stack_3d.h b/scene/resources/skeleton_modification_stack_3d.h deleted file mode 100644 index fd490c49e9..0000000000 --- a/scene/resources/skeleton_modification_stack_3d.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************/ -/* skeleton_modification_stack_3d.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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 SKELETON_MODIFICATION_STACK_3D_H -#define SKELETON_MODIFICATION_STACK_3D_H - -#include "core/templates/local_vector.h" -#include "scene/3d/skeleton_3d.h" - -class Skeleton3D; -class SkeletonModification3D; - -class SkeletonModificationStack3D : public Resource { - GDCLASS(SkeletonModificationStack3D, Resource); - friend class Skeleton3D; - friend class SkeletonModification3D; - -protected: - static void _bind_methods(); - virtual void _get_property_list(List<PropertyInfo> *p_list) const; - virtual bool _set(const StringName &p_path, const Variant &p_value); - virtual bool _get(const StringName &p_path, Variant &r_ret) const; - -public: - Skeleton3D *skeleton = nullptr; - bool is_setup = false; - bool enabled = false; - real_t strength = 1.0; - - enum EXECUTION_MODE { - execution_mode_process, - execution_mode_physics_process, - }; - - LocalVector<Ref<SkeletonModification3D>> modifications = LocalVector<Ref<SkeletonModification3D>>(); - int modifications_count = 0; - - virtual void setup(); - virtual void execute(real_t p_delta, int p_execution_mode); - - void enable_all_modifications(bool p_enable); - Ref<SkeletonModification3D> get_modification(int p_mod_idx) const; - void add_modification(Ref<SkeletonModification3D> p_mod); - void delete_modification(int p_mod_idx); - void set_modification(int p_mod_idx, Ref<SkeletonModification3D> p_mod); - - void set_modification_count(int p_count); - int get_modification_count() const; - - void set_skeleton(Skeleton3D *p_skeleton); - Skeleton3D *get_skeleton() const; - - bool get_is_setup() const; - - void set_enabled(bool p_enabled); - bool get_enabled() const; - - void set_strength(real_t p_strength); - real_t get_strength() const; - - SkeletonModificationStack3D(); -}; - -#endif // SKELETON_MODIFICATION_STACK_3D_H diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 82343e0402..39f14439f4 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -848,6 +848,7 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(WINDOW_FLAG_NO_FOCUS); BIND_ENUM_CONSTANT(WINDOW_FLAG_POPUP); BIND_ENUM_CONSTANT(WINDOW_FLAG_EXTEND_TO_TITLE); + BIND_ENUM_CONSTANT(WINDOW_FLAG_MOUSE_PASSTHROUGH); BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX); BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_ENTER); diff --git a/servers/display_server.h b/servers/display_server.h index f8ade60aca..aa30b25b65 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -311,6 +311,7 @@ public: WINDOW_FLAG_NO_FOCUS, WINDOW_FLAG_POPUP, WINDOW_FLAG_EXTEND_TO_TITLE, + WINDOW_FLAG_MOUSE_PASSTHROUGH, WINDOW_FLAG_MAX, }; @@ -323,6 +324,7 @@ public: WINDOW_FLAG_NO_FOCUS_BIT = (1 << WINDOW_FLAG_NO_FOCUS), WINDOW_FLAG_POPUP_BIT = (1 << WINDOW_FLAG_POPUP), WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE), + WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT = (1 << WINDOW_FLAG_MOUSE_PASSTHROUGH), }; virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 3510b415d8..55f88d9bf1 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -597,7 +597,7 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, Vector2 end_left; Vector2 end_right; - if (p_width > 1.001) { + if (p_width >= 0.0) { begin_left = p_from + t; begin_right = p_from - t; end_left = p_to + t; @@ -628,7 +628,7 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, // This value is empirically determined to provide good antialiasing quality // while not making lines appear too soft. float border_size = 1.25f; - if (p_width < 1.0f) { + if (0.0f <= p_width && p_width < 1.0f) { border_size *= p_width; } Vector2 dir2 = diff.normalized(); @@ -1077,7 +1077,7 @@ void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Poin ERR_FAIL_COND(p_points.size() < 2); // TODO: `canvas_item_add_line`(`multiline`, `polyline`) share logic, should factor out. - if (p_width <= 1) { + if (p_width < 0) { Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); @@ -1313,7 +1313,7 @@ void RendererCanvasCull::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_r style->axis_y = p_y_axis_mode; } -void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width) { +void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) { uint32_t pc = p_points.size(); ERR_FAIL_COND(pc == 0 || pc > 4); diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 4d0be48cc0..2494ddf631 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -221,9 +221,9 @@ public: void canvas_item_set_update_when_visible(RID p_item, bool p_update); - void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); + void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false); void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); - void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0); + void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0); void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color); void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false); @@ -231,7 +231,7 @@ public: void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0); void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)); void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode = RS::NINE_PATCH_STRETCH, RS::NinePatchAxisMode p_y_axis_mode = RS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1)); - void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0); + void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture); void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID()); void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1); void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID()); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 78d29e2a41..816248567b 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -251,7 +251,7 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe Size2i target_size = render_buffers->get_target_size(); Size2i internal_size = render_buffers->get_internal_size(); - // can't do our blit pass if resolutions don't match + // can't do our blit pass if resolutions don't match, this should already have been checked. ERR_FAIL_COND_V(target_size != internal_size, RID()); // - opaque pass @@ -715,20 +715,26 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color // setup rendering to render buffer screen_size = p_render_data->render_buffers->get_internal_size(); - if (rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES).is_null()) { - // can't do blit subpass + if (rb->get_scaling_3d_mode() != RS::VIEWPORT_SCALING_3D_MODE_OFF) { + // can't do blit subpass because we're scaling using_subpass_post_process = false; } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes))) { - // can't do blit subpass + // can't do blit subpass because we're using post processes using_subpass_post_process = false; } if (scene_state.used_screen_texture || scene_state.used_depth_texture) { - // can't use our last two subpasses + // can't use our last two subpasses because we're reading from screen texture or depth texture using_subpass_transparent = false; using_subpass_post_process = false; } + // We do this last because our get_color_fbs creates and caches the framebuffer if we need it. + if (using_subpass_post_process && rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES).is_null()) { + // can't do blit subpass because we don't have all subpasses + using_subpass_post_process = false; + } + if (using_subpass_post_process) { // all as subpasses framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 1d45db8eaf..2a87c4fa8d 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -539,7 +539,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.view_count = rb->get_view_count(); RID dest_fb; - if (fsr && can_use_effects && (internal_size.x != target_size.x || internal_size.y != target_size.y)) { + if (fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR) { // If we use FSR to upscale we need to write our result into an intermediate buffer. // Note that this is cached so we only create the texture the first time. RID dest_texture = rb->create_texture(SNAME("Tonemapper"), SNAME("destination"), _render_buffers_get_color_format(), RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT); @@ -556,10 +556,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende RD::get_singleton()->draw_command_end_label(); } - if (fsr && can_use_effects && (internal_size.x != target_size.x || internal_size.y != target_size.y)) { - // TODO Investigate? Does this work? We never write into our render target and we've already done so up above in our tonemapper. - // I think FSR should either work before our tonemapper or as an alternative of our tonemapper. - + if (fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR) { RD::get_singleton()->draw_command_begin_label("FSR 1.0 Upscale"); for (uint32_t v = 0; v < rb->get_view_count(); v++) { diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index 66ae1e8d1a..d631a89dd2 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -2685,6 +2685,14 @@ void MaterialStorage::material_free(RID p_rid) { Material *material = material_owner.get_or_null(p_rid); ERR_FAIL_COND(!material); + // Need to clear texture arrays to prevent spin locking of their RID's. + // This happens when the app is being closed. + for (KeyValue<StringName, Variant> &E : material->params) { + if (E.value.get_type() == Variant::ARRAY) { + Array(E.value).clear(); + } + } + material_set_shader(p_rid, RID()); //clean up shader material->dependency.deleted_notify(p_rid); diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp index d67a848a40..31377a10a0 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp @@ -96,7 +96,7 @@ void RenderSceneBuffersRD::cleanup() { named_textures.clear(); } -void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { +void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); @@ -104,12 +104,7 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna target_size = p_target_size; internal_size = p_internal_size; - - // FIXME, right now we do this because only our clustered renderer supports FSR upscale - // this does mean that with linear upscale if we use subpasses, we could get into trouble. - if (!can_be_storage) { - internal_size = target_size; - } + scaling_3d_mode = p_scaling_3d_mode; if (p_use_taa) { // Use negative mipmap LOD bias when TAA is enabled to compensate for loss of sharpness. @@ -193,6 +188,7 @@ void RenderSceneBuffersRD::configure_for_reflections(const Size2i p_reflection_s target_size = p_reflection_size; internal_size = p_reflection_size; render_target = RID(); + scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF; fsr_sharpness = 0.0; msaa_3d = RS::VIEWPORT_MSAA_DISABLED; screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h index ff946f410f..dc849fd56a 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h @@ -73,6 +73,7 @@ private: // The internal size of the textures we render 3D to in case we render at a lower resolution and upscale Size2i internal_size = Size2i(0, 0); + RS::ViewportScaling3DMode scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF; float fsr_sharpness = 0.2f; // Aliassing settings @@ -139,7 +140,7 @@ public: void set_vrs(RendererRD::VRS *p_vrs) { vrs = p_vrs; } void cleanup(); - virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override; + virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override; void configure_for_reflections(const Size2i p_reflection_size); virtual void set_fsr_sharpness(float p_fsr_sharpness) override; virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override; @@ -172,6 +173,7 @@ public: _FORCE_INLINE_ uint32_t get_view_count() const { return view_count; } _FORCE_INLINE_ Size2i get_internal_size() const { return internal_size; } _FORCE_INLINE_ Size2i get_target_size() const { return target_size; } + _FORCE_INLINE_ RS::ViewportScaling3DMode get_scaling_3d_mode() const { return scaling_3d_mode; } _FORCE_INLINE_ float get_fsr_sharpness() const { return fsr_sharpness; } _FORCE_INLINE_ RS::ViewportMSAA get_msaa_3d() const { return msaa_3d; } _FORCE_INLINE_ RS::ViewportScreenSpaceAA get_screen_space_aa() const { return screen_space_aa; } diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp index e2e6ea5aa2..a389e3e767 100644 --- a/servers/rendering/renderer_scene_render.cpp +++ b/servers/rendering/renderer_scene_render.cpp @@ -84,7 +84,7 @@ void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count Transform3D main_transform_inv = main_transform.inverse(); // 5. figure out far plane, this could use some improvement, we may have our far plane too close like this, not sure if this matters - Vector3 far_center = (planes[0][Projection::PLANE_FAR].center() + planes[1][Projection::PLANE_FAR].center()) * 0.5; + Vector3 far_center = (planes[0][Projection::PLANE_FAR].get_center() + planes[1][Projection::PLANE_FAR].get_center()) * 0.5; Plane far(-z, far_center); ///////////////////////////////////////////////////////////////////////////// diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 05a3fccf1c..b82019dd9d 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -115,9 +115,8 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { if (p_viewport->size.width == 0 || p_viewport->size.height == 0) { p_viewport->render_buffers.unref(); } else { - const float scaling_3d_scale = p_viewport->scaling_3d_scale; + float scaling_3d_scale = p_viewport->scaling_3d_scale; RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode; - bool scaling_enabled = true; if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && (scaling_3d_scale > 1.0)) { // FSR is not designed for downsampling. @@ -133,7 +132,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { } if (scaling_3d_scale == 1.0) { - scaling_enabled = false; + scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF; } int width; @@ -141,36 +140,37 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { int render_width; int render_height; - if (scaling_enabled) { - switch (scaling_3d_mode) { - case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR: - // Clamp 3D rendering resolution to reasonable values supported on most hardware. - // This prevents freezing the engine or outright crashing on lower-end GPUs. - width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384); - height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384); - render_width = width; - render_height = height; - break; - case RS::VIEWPORT_SCALING_3D_MODE_FSR: - width = p_viewport->size.width; - height = p_viewport->size.height; - render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling) - render_height = MAX(height * scaling_3d_scale, 1.0); - break; - default: - // This is an unknown mode. - WARN_PRINT_ONCE(vformat("Unknown scaling mode: %d. Disabling 3D resolution scaling.", scaling_3d_mode)); - width = p_viewport->size.width; - height = p_viewport->size.height; - render_width = width; - render_height = height; - break; - } - } else { - width = p_viewport->size.width; - height = p_viewport->size.height; - render_width = width; - render_height = height; + switch (scaling_3d_mode) { + case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR: + // Clamp 3D rendering resolution to reasonable values supported on most hardware. + // This prevents freezing the engine or outright crashing on lower-end GPUs. + width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384); + height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384); + render_width = width; + render_height = height; + break; + case RS::VIEWPORT_SCALING_3D_MODE_FSR: + width = p_viewport->size.width; + height = p_viewport->size.height; + render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling) + render_height = MAX(height * scaling_3d_scale, 1.0); + break; + case RS::VIEWPORT_SCALING_3D_MODE_OFF: + width = p_viewport->size.width; + height = p_viewport->size.height; + render_width = width; + render_height = height; + break; + default: + // This is an unknown mode. + WARN_PRINT_ONCE(vformat("Unknown scaling mode: %d. Disabling 3D resolution scaling.", scaling_3d_mode)); + scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF; + scaling_3d_scale = 1.0; + width = p_viewport->size.width; + height = p_viewport->size.height; + render_width = width; + render_height = height; + break; } p_viewport->internal_size = Size2(render_width, render_height); @@ -179,7 +179,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { // to compensate for the loss of sharpness. const float texture_mipmap_bias = log2f(MIN(scaling_3d_scale, 1.0)) + p_viewport->texture_mipmap_bias; - p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->view_count); + p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), scaling_3d_mode, p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->view_count); } } } diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp index 5967835d03..3678b70254 100644 --- a/servers/rendering/rendering_device_binds.cpp +++ b/servers/rendering/rendering_device_binds.cpp @@ -31,6 +31,8 @@ #include "rendering_device_binds.h" Error RDShaderFile::parse_versions_from_text(const String &p_text, const String p_defines, OpenIncludeFunction p_include_func, void *p_include_func_userdata) { + ERR_FAIL_NULL_V(RenderingDevice::get_singleton(), ERR_UNAVAILABLE); + Vector<String> lines = p_text.split("\n"); bool reading_versions = false; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index d053c60b85..8ac522bafe 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -854,7 +854,7 @@ public: FUNC8(canvas_item_add_msdf_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, int, float, float) FUNC5(canvas_item_add_lcd_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &) FUNC10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &) - FUNC6(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float) + FUNC5(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID) FUNC5(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID) FUNC9(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int) FUNC5(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID) diff --git a/servers/rendering/storage/render_scene_buffers.cpp b/servers/rendering/storage/render_scene_buffers.cpp index 1320199833..6369139aa6 100644 --- a/servers/rendering/storage/render_scene_buffers.cpp +++ b/servers/rendering/storage/render_scene_buffers.cpp @@ -34,8 +34,8 @@ void RenderSceneBuffers::_bind_methods() { ClassDB::bind_method(D_METHOD("configure", "render_target", "internal_size", "target_size", "fsr_sharpness", "texture_mipmap_bias", "msaa", "screen_space_aa", "use_taa", "use_debanding", "view_count"), &RenderSceneBuffers::configure); } -void RenderSceneBuffers::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { - GDVIRTUAL_CALL(_configure, p_render_target, p_internal_size, p_target_size, p_fsr_sharpness, p_texture_mipmap_bias, p_msaa, p_screen_space_aa, p_use_taa, p_use_debanding, p_view_count); +void RenderSceneBuffers::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { + GDVIRTUAL_CALL(_configure, p_render_target, p_internal_size, p_target_size, p_scaling_3d_mode, p_fsr_sharpness, p_texture_mipmap_bias, p_msaa, p_screen_space_aa, p_use_taa, p_use_debanding, p_view_count); }; void RenderSceneBuffers::set_fsr_sharpness(float p_fsr_sharpness) { diff --git a/servers/rendering/storage/render_scene_buffers.h b/servers/rendering/storage/render_scene_buffers.h index 83fc78ca1c..cf96a9f372 100644 --- a/servers/rendering/storage/render_scene_buffers.h +++ b/servers/rendering/storage/render_scene_buffers.h @@ -40,7 +40,7 @@ class RenderSceneBuffers : public RefCounted { protected: static void _bind_methods(); - GDVIRTUAL10(_configure, RID, Size2i, Size2i, float, float, RS::ViewportMSAA, RenderingServer::ViewportScreenSpaceAA, bool, bool, uint32_t) + GDVIRTUAL11(_configure, RID, Size2i, Size2i, RS::ViewportScaling3DMode, float, float, RS::ViewportMSAA, RenderingServer::ViewportScreenSpaceAA, bool, bool, uint32_t) GDVIRTUAL1(_set_fsr_sharpness, float) GDVIRTUAL1(_set_texture_mipmap_bias, float) GDVIRTUAL1(_set_use_debanding, bool) @@ -49,7 +49,7 @@ public: RenderSceneBuffers(){}; virtual ~RenderSceneBuffers(){}; - virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count); + virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count); // for those settings that are unlikely to require buffers to be recreated, we'll add setters virtual void set_fsr_sharpness(float p_fsr_sharpness); diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 14d8d035e2..e24b2af976 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2592,7 +2592,7 @@ void RenderingServer::_bind_methods() { /* Primitives */ - ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &RenderingServer::canvas_item_add_line, DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &RenderingServer::canvas_item_add_line, DEFVAL(-1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect); ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle); @@ -2601,7 +2601,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_item_add_lcd_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate"), &RenderingServer::canvas_item_add_lcd_texture_rect_region); ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1))); - ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width"), &RenderingServer::canvas_item_add_primitive, DEFVAL(1.0)); + ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture"), &RenderingServer::canvas_item_add_primitive); ClassDB::bind_method(D_METHOD("canvas_item_add_polygon", "item", "points", "colors", "uvs", "texture"), &RenderingServer::canvas_item_add_polygon, DEFVAL(Vector<Point2>()), DEFVAL(RID())); ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count"), &RenderingServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "transform", "modulate", "texture"), &RenderingServer::canvas_item_add_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(RID())); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 6efe28a847..4b51099ef0 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -802,7 +802,8 @@ public: enum ViewportScaling3DMode { VIEWPORT_SCALING_3D_MODE_BILINEAR, VIEWPORT_SCALING_3D_MODE_FSR, - VIEWPORT_SCALING_3D_MODE_MAX + VIEWPORT_SCALING_3D_MODE_MAX, + VIEWPORT_SCALING_3D_MODE_OFF = 255, // for internal use only }; virtual void viewport_set_use_xr(RID p_viewport, bool p_use_xr) = 0; @@ -1333,9 +1334,9 @@ public: NINE_PATCH_TILE_FIT, }; - virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false) = 0; + virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false) = 0; virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0; - virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0; + virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0) = 0; virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0; virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0; virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) = 0; @@ -1343,7 +1344,7 @@ public: virtual void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0) = 0; virtual void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)) = 0; virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1)) = 0; - virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0) = 0; + virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) = 0; virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID()) = 0; virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1) = 0; virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID()) = 0; diff --git a/tests/core/math/test_plane.h b/tests/core/math/test_plane.h index b2b857ca69..f784a29a17 100644 --- a/tests/core/math/test_plane.h +++ b/tests/core/math/test_plane.h @@ -87,8 +87,8 @@ TEST_CASE("[Plane] Plane-point operations") { const Plane y_facing_plane = Plane(0, 1, 0, 4); CHECK_MESSAGE( - plane.center().is_equal_approx(Vector3(32 * 3, 22 * 3, 16 * 3)), - "center() should return a vector pointing to the center of the plane."); + plane.get_center().is_equal_approx(Vector3(32 * 3, 22 * 3, 16 * 3)), + "get_center() should return a vector pointing to the center of the plane."); CHECK_MESSAGE( y_facing_plane.is_point_over(Vector3(0, 5, 0)), diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h index c68560000c..5447c99a64 100644 --- a/tests/scene/test_code_edit.h +++ b/tests/scene/test_code_edit.h @@ -2930,7 +2930,7 @@ TEST_CASE("[SceneTree][CodeEdit] completion") { code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test", "\"test"); code_edit->update_code_completion_options(); code_edit->confirm_code_completion(); - CHECK(code_edit->get_line(0) == "\"\"test\"\""); + CHECK(code_edit->get_line(0) == "\"\"test\""); CHECK(code_edit->get_caret_column() == 7); code_edit->undo(); diff --git a/tests/scene/test_curve_2d.h b/tests/scene/test_curve_2d.h new file mode 100644 index 0000000000..fc141f3d09 --- /dev/null +++ b/tests/scene/test_curve_2d.h @@ -0,0 +1,228 @@ +/**************************************************************************/ +/* test_curve_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 TEST_CURVE_2D_H +#define TEST_CURVE_2D_H + +#include "core/math/math_funcs.h" +#include "scene/resources/curve.h" + +#include "tests/test_macros.h" + +namespace TestCurve2D { + +void add_sample_curve_points(Ref<Curve2D> &curve) { + Vector2 p0 = Vector2(0, 0); + Vector2 p1 = Vector2(50, 0); + Vector2 p2 = Vector2(50, 50); + Vector2 p3 = Vector2(0, 50); + + Vector2 control0 = p1 - p0; + Vector2 control1 = p3 - p2; + + curve->add_point(p0, Vector2(), control0); + curve->add_point(p3, control1, Vector2()); +} + +TEST_CASE("[Curve2D] Default curve is empty") { + const Ref<Curve2D> curve = memnew(Curve2D); + CHECK(curve->get_point_count() == 0); +} + +TEST_CASE("[Curve2D] Point management") { + Ref<Curve2D> curve = memnew(Curve2D); + + SUBCASE("Functions for adding/removing points should behave as expected") { + curve->set_point_count(2); + CHECK(curve->get_point_count() == 2); + + curve->remove_point(0); + CHECK(curve->get_point_count() == 1); + + curve->add_point(Vector2()); + CHECK(curve->get_point_count() == 2); + + curve->clear_points(); + CHECK(curve->get_point_count() == 0); + } + + SUBCASE("Functions for changing single point properties should behave as expected") { + Vector2 new_in = Vector2(1, 1); + Vector2 new_out = Vector2(1, 1); + Vector2 new_pos = Vector2(1, 1); + + curve->add_point(Vector2()); + + CHECK(curve->get_point_in(0) != new_in); + curve->set_point_in(0, new_in); + CHECK(curve->get_point_in(0) == new_in); + + CHECK(curve->get_point_out(0) != new_out); + curve->set_point_out(0, new_out); + CHECK(curve->get_point_out(0) == new_out); + + CHECK(curve->get_point_position(0) != new_pos); + curve->set_point_position(0, new_pos); + CHECK(curve->get_point_position(0) == new_pos); + } +} + +TEST_CASE("[Curve2D] Baked") { + Ref<Curve2D> curve = memnew(Curve2D); + + SUBCASE("Single Point") { + curve->add_point(Vector2()); + + CHECK(curve->get_baked_length() == 0); + CHECK(curve->get_baked_points().size() == 1); + } + + SUBCASE("Straight line") { + curve->add_point(Vector2()); + curve->add_point(Vector2(0, 50)); + + CHECK(Math::is_equal_approx(curve->get_baked_length(), 50)); + CHECK(curve->get_baked_points().size() == 15); + } + + SUBCASE("BeziƩr Curve") { + add_sample_curve_points(curve); + + real_t len = curve->get_baked_length(); + real_t n_points = curve->get_baked_points().size(); + // Curve length should be bigger than a straight between points + CHECK(len > 50); + + SUBCASE("Increase bake interval") { + curve->set_bake_interval(10.0); + // Lower resolution should imply less points and smaller length + CHECK(curve->get_baked_length() < len); + CHECK(curve->get_baked_points().size() < n_points); + } + } +} + +TEST_CASE("[Curve2D] Sampling") { + // Sampling over a simple straight line to make assertions simpler + Ref<Curve2D> curve = memnew(Curve2D); + curve->add_point(Vector2()); + curve->add_point(Vector2(0, 50)); + + SUBCASE("sample") { + CHECK(curve->sample(0, 0) == Vector2(0, 0)); + CHECK(curve->sample(0, 0.5) == Vector2(0, 25)); + CHECK(curve->sample(0, 1) == Vector2(0, 50)); + } + + SUBCASE("samplef") { + CHECK(curve->samplef(0) == Vector2(0, 0)); + CHECK(curve->samplef(0.5) == Vector2(0, 25)); + CHECK(curve->samplef(1) == Vector2(0, 50)); + } + + SUBCASE("sample_baked") { + CHECK(curve->sample_baked(curve->get_closest_offset(Vector2(0, 0))) == Vector2(0, 0)); + CHECK(curve->sample_baked(curve->get_closest_offset(Vector2(0, 25))) == Vector2(0, 25)); + CHECK(curve->sample_baked(curve->get_closest_offset(Vector2(0, 50))) == Vector2(0, 50)); + } + + SUBCASE("sample_baked_with_rotation") { + const real_t pi = 3.14159; + Transform2D t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 0))); + CHECK(t.get_origin() == Vector2(0, 0)); + CHECK(Math::is_equal_approx(t.get_rotation(), pi)); + + t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 25))); + CHECK(t.get_origin() == Vector2(0, 25)); + CHECK(Math::is_equal_approx(t.get_rotation(), pi)); + + t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 50))); + CHECK(t.get_origin() == Vector2(0, 50)); + CHECK(Math::is_equal_approx(t.get_rotation(), pi)); + } + + SUBCASE("get_closest_point") { + CHECK(curve->get_closest_point(Vector2(0, 0)) == Vector2(0, 0)); + CHECK(curve->get_closest_point(Vector2(0, 25)) == Vector2(0, 25)); + CHECK(curve->get_closest_point(Vector2(50, 25)) == Vector2(0, 25)); + CHECK(curve->get_closest_point(Vector2(0, 50)) == Vector2(0, 50)); + CHECK(curve->get_closest_point(Vector2(50, 50)) == Vector2(0, 50)); + CHECK(curve->get_closest_point(Vector2(0, 100)) == Vector2(0, 50)); + } +} + +TEST_CASE("[Curve2D] Tessellation") { + Ref<Curve2D> curve = memnew(Curve2D); + add_sample_curve_points(curve); + + const int default_size = curve->tessellate().size(); + + SUBCASE("Increase to max stages should increase num of points") { + CHECK(curve->tessellate(6).size() > default_size); + } + + SUBCASE("Decrease to max stages should decrease num of points") { + CHECK(curve->tessellate(4).size() < default_size); + } + + SUBCASE("Increase to tolerance should decrease num of points") { + CHECK(curve->tessellate(5, 5).size() < default_size); + } + + SUBCASE("Decrease to tolerance should increase num of points") { + CHECK(curve->tessellate(5, 3).size() > default_size); + } + + SUBCASE("Adding a straight segment should only add the last point to tessellate return array") { + curve->add_point(Vector2(0, 100)); + PackedVector2Array tes = curve->tessellate(); + CHECK(tes.size() == default_size + 1); + CHECK(tes[tes.size() - 1] == Vector2(0, 100)); + CHECK(tes[tes.size() - 2] == Vector2(0, 50)); + } +} + +TEST_CASE("[Curve2D] Even length tessellation") { + Ref<Curve2D> curve = memnew(Curve2D); + add_sample_curve_points(curve); + + const int default_size = curve->tessellate_even_length().size(); + + // Default tessellate_even_length tolerance_length is 20.0, by adding a 100 units + // straight, we expect the total size to be increased by more than 5, + // that is, the algo will pick a length < 20.0 and will divide the straight as + // well as the curve as opposed to tessellate() which only adds the final point + curve->add_point(Vector2(0, 150)); + CHECK(curve->tessellate_even_length().size() > default_size + 5); +} + +} // namespace TestCurve2D + +#endif // TEST_CURVE_2D_H diff --git a/tests/scene/test_node.h b/tests/scene/test_node.h index 20c42d9fc2..0ddf027970 100644 --- a/tests/scene/test_node.h +++ b/tests/scene/test_node.h @@ -37,7 +37,7 @@ namespace TestNode { -TEST_CASE("[SceneTree][Node] Simple Add/Remove/Move/Find") { +TEST_CASE("[SceneTree][Node] Testing node operations with a very simple scene tree") { Node *node = memnew(Node); // Check initial scene tree setup. @@ -135,10 +135,30 @@ TEST_CASE("[SceneTree][Node] Simple Add/Remove/Move/Find") { CHECK(node->is_inside_tree()); } + SUBCASE("Node should be possible to reparent") { + node->reparent(SceneTree::get_singleton()->get_root()); + + Node *child = SceneTree::get_singleton()->get_root()->get_child(0); + CHECK_EQ(child, node); + CHECK(node->is_inside_tree()); + } + + SUBCASE("Node should be possible to duplicate") { + node->set_name("MyName"); + + Node *duplicate = node->duplicate(); + + CHECK_FALSE(node == duplicate); + CHECK_FALSE(duplicate->is_inside_tree()); + CHECK_EQ(duplicate->get_name(), node->get_name()); + + memdelete(duplicate); + } + memdelete(node); } -TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") { +TEST_CASE("[SceneTree][Node] Testing node operations with a more complex simple scene tree") { Node *node1 = memnew(Node); Node *node2 = memnew(Node); Node *node1_1 = memnew(Node); @@ -209,7 +229,7 @@ TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") { CHECK_EQ(child2, node1); } - SUBCASE("Nodes should be in the expected order when reparented") { + SUBCASE("Nodes should be in the expected order when reparented (remove/add)") { CHECK_EQ(node2->get_child_count(), 0); node1->remove_child(node1_1); @@ -227,6 +247,22 @@ TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") { CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4); } + SUBCASE("Nodes should be in the expected order when reparented") { + CHECK_EQ(node2->get_child_count(), 0); + + node1_1->reparent(node2); + + CHECK_EQ(node1->get_child_count(), 0); + CHECK_EQ(node2->get_child_count(), 1); + CHECK_EQ(node1_1->get_parent(), node2); + + Node *child = node2->get_child(0); + CHECK_EQ(child, node1_1); + + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2); + CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4); + } + SUBCASE("Nodes should be possible to find") { Node *child = SceneTree::get_singleton()->get_root()->find_child("NestedNode", true, false); CHECK_EQ(child, nullptr); @@ -315,6 +351,70 @@ TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") { CHECK_EQ(E->get(), node1_1); } + SUBCASE("Nodes added as siblings of another node should be right next to it") { + node1->remove_child(node1_1); + + node1->add_sibling(node1_1); + + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 3); + CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4); + + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(0), node1); + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(1), node1_1); + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(2), node2); + } + + SUBCASE("Replaced nodes should be be removed and the replacing node added") { + SceneTree::get_singleton()->get_root()->remove_child(node2); + + node1->replace_by(node2); + + CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1); + CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 3); + + CHECK_FALSE(node1->is_inside_tree()); + CHECK(node2->is_inside_tree()); + + CHECK_EQ(node1->get_parent(), nullptr); + CHECK_EQ(node2->get_parent(), SceneTree::get_singleton()->get_root()); + CHECK_EQ(node2->get_child_count(), 1); + CHECK_EQ(node2->get_child(0), node1_1); + } + + SUBCASE("Replacing nodes should keep the groups of the replaced nodes") { + SceneTree::get_singleton()->get_root()->remove_child(node2); + + node1->add_to_group("nodes"); + node1->replace_by(node2, true); + + List<Node *> nodes; + SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes); + CHECK_EQ(nodes.size(), 1); + + List<Node *>::Element *E = nodes.front(); + CHECK_EQ(E->get(), node2); + } + + SUBCASE("Duplicating a node should also duplicate the children") { + node1->set_name("MyName1"); + node1_1->set_name("MyName1_1"); + Node *duplicate1 = node1->duplicate(); + + CHECK_EQ(duplicate1->get_child_count(), node1->get_child_count()); + Node *duplicate1_1 = duplicate1->get_child(0); + + CHECK_EQ(duplicate1_1->get_child_count(), node1_1->get_child_count()); + + CHECK_EQ(duplicate1->get_name(), node1->get_name()); + CHECK_EQ(duplicate1_1->get_name(), node1_1->get_name()); + + CHECK_FALSE(duplicate1->is_inside_tree()); + CHECK_FALSE(duplicate1_1->is_inside_tree()); + + memdelete(duplicate1_1); + memdelete(duplicate1); + } + memdelete(node1_1); memdelete(node1); memdelete(node2); diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 85a271fc9c..8c563f94ac 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -91,6 +91,7 @@ #include "tests/scene/test_bit_map.h" #include "tests/scene/test_code_edit.h" #include "tests/scene/test_curve.h" +#include "tests/scene/test_curve_2d.h" #include "tests/scene/test_gradient.h" #include "tests/scene/test_node.h" #include "tests/scene/test_path_2d.h" |