summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/static_checks.yml4
-rw-r--r--SConstruct2
-rw-r--r--core/math/vector2i.h2
-rw-r--r--core/math/vector3i.h2
-rw-r--r--core/math/vector4.cpp19
-rw-r--r--core/math/vector4i.cpp10
-rw-r--r--core/math/vector4i.h2
-rw-r--r--core/variant/variant_parser.cpp2
-rw-r--r--doc/classes/GraphNode.xml10
-rw-r--r--doc/classes/ParallaxLayer.xml1
-rw-r--r--doc/classes/PhysicsDirectBodyState2DExtension.xml249
-rw-r--r--doc/classes/PhysicsDirectSpaceState2DExtension.xml91
-rw-r--r--doc/classes/PhysicsServer2D.xml2
-rw-r--r--doc/classes/PhysicsServer2DExtension.xml777
-rw-r--r--doc/classes/ProjectSettings.xml3
-rw-r--r--doc/classes/SceneTree.xml7
-rw-r--r--doc/classes/Vector4.xml2
-rw-r--r--doc/classes/Vector4i.xml61
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp13
-rw-r--r--drivers/vulkan/vulkan_context.cpp2
-rw-r--r--editor/editor_spin_slider.cpp2
-rw-r--r--editor/import/post_import_plugin_skeleton_renamer.cpp2
-rw-r--r--editor/import/post_import_plugin_skeleton_rest_fixer.cpp348
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp12
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp29
-rw-r--r--editor/scene_tree_dock.cpp48
-rw-r--r--editor/scene_tree_dock.h4
-rw-r--r--main/main.cpp8
-rwxr-xr-xmisc/scripts/file_format.sh27
-rw-r--r--modules/gltf/extensions/gltf_light.cpp1
-rw-r--r--modules/gltf/structures/gltf_camera.cpp1
-rw-r--r--modules/mono/README.md10
-rwxr-xr-xmodules/mono/build_scripts/build_assemblies.py14
-rw-r--r--modules/mono/csharp_script.cpp64
-rw-r--r--modules/mono/csharp_script.h3
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets4
-rw-r--r--modules/mono/editor/bindings_generator.cpp2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs57
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj1
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj1
-rw-r--r--platform/linuxbsd/display_server_x11.cpp73
-rw-r--r--platform/linuxbsd/display_server_x11.h3
-rw-r--r--platform/linuxbsd/gl_manager_x11.cpp28
-rw-r--r--platform/linuxbsd/gl_manager_x11.h3
-rw-r--r--platform/macos/detect.py8
-rw-r--r--platform/windows/display_server_windows.cpp25
-rw-r--r--platform/windows/display_server_windows.h5
-rw-r--r--scene/3d/lightmap_gi.cpp1
-rw-r--r--scene/3d/shape_cast_3d.cpp6
-rw-r--r--scene/gui/graph_edit.cpp88
-rw-r--r--scene/gui/graph_edit.h2
-rw-r--r--scene/gui/graph_node.cpp8
-rw-r--r--scene/gui/split_container.cpp88
-rw-r--r--scene/gui/split_container.h2
-rw-r--r--scene/main/scene_tree.cpp80
-rw-r--r--scene/main/scene_tree.h7
-rw-r--r--scene/main/window.cpp4
-rw-r--r--scene/resources/visual_shader_nodes.cpp14
-rw-r--r--scene/resources/visual_shader_nodes.h3
-rw-r--r--servers/extensions/physics_server_2d_extension.cpp294
-rw-r--r--servers/extensions/physics_server_2d_extension.h462
-rw-r--r--servers/physics_server_2d.cpp2
-rw-r--r--servers/physics_server_2d.h1
-rw-r--r--servers/register_server_types.cpp11
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.h1
67 files changed, 2676 insertions, 447 deletions
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index 3e84702d7f..5b4de06e9e 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -24,8 +24,8 @@ jobs:
- name: Install dependencies
run: |
- sudo apt-get install -qq dos2unix recode clang-format-13 libxml2-utils
- sudo update-alternatives --remove-all clang-format
+ sudo apt-get install -qq dos2unix recode clang-format-13 libxml2-utils python3-pip moreutils
+ sudo update-alternatives --remove-all clang-format || true
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-13 100
sudo pip3 install black==22.3.0 pygments pytest
diff --git a/SConstruct b/SConstruct
index 46942ca3b4..5ad4b614ca 100644
--- a/SConstruct
+++ b/SConstruct
@@ -167,7 +167,7 @@ opts.Add("p", "Platform (alias for 'platform')", "")
opts.Add(BoolVariable("tools", "Build the tools (a.k.a. the Godot editor)", True))
opts.Add(EnumVariable("target", "Compilation target", "debug", ("debug", "release_debug", "release")))
opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectures, architecture_aliases))
-opts.Add(EnumVariable("float", "Floating-point precision", "default", ("default", "32", "64")))
+opts.Add(EnumVariable("float", "Floating-point precision", "32", ("32", "64")))
opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size", "none")))
opts.Add(BoolVariable("production", "Set defaults to build Godot for use in production", False))
opts.Add(BoolVariable("use_lto", "Use link-time optimization", False))
diff --git a/core/math/vector2i.h b/core/math/vector2i.h
index 13b70031bd..0245900a3b 100644
--- a/core/math/vector2i.h
+++ b/core/math/vector2i.h
@@ -115,7 +115,7 @@ struct _NO_DISCARD_ Vector2i {
real_t aspect() const { return width / (real_t)height; }
Vector2i sign() const { return Vector2i(SIGN(x), SIGN(y)); }
- Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); }
+ Vector2i abs() const { return Vector2i(Math::abs(x), Math::abs(y)); }
Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const;
operator String() const;
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index b49c1142ed..825ce40318 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -128,7 +128,7 @@ double Vector3i::length() const {
}
Vector3i Vector3i::abs() const {
- return Vector3i(ABS(x), ABS(y), ABS(z));
+ return Vector3i(Math::abs(x), Math::abs(y), Math::abs(z));
}
Vector3i Vector3i::sign() const {
diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp
index fb651fafce..3c25f454a3 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -80,15 +80,26 @@ real_t Vector4::length() const {
}
void Vector4::normalize() {
- *this /= length();
+ real_t lengthsq = length_squared();
+ if (lengthsq == 0) {
+ x = y = z = w = 0;
+ } else {
+ real_t length = Math::sqrt(lengthsq);
+ x /= length;
+ y /= length;
+ z /= length;
+ w /= length;
+ }
}
Vector4 Vector4::normalized() const {
- return *this / length();
+ Vector4 v = *this;
+ v.normalize();
+ return v;
}
bool Vector4::is_normalized() const {
- return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); // Use less epsilon.
+ return Math::is_equal_approx(length_squared(), (real_t)1, (real_t)UNIT_EPSILON);
}
real_t Vector4::distance_to(const Vector4 &p_to) const {
@@ -187,3 +198,5 @@ Vector4 Vector4::clamp(const Vector4 &p_min, const Vector4 &p_max) const {
Vector4::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")";
}
+
+static_assert(sizeof(Vector4) == 4 * sizeof(real_t));
diff --git a/core/math/vector4i.cpp b/core/math/vector4i.cpp
index 2dc5b74202..a89b802675 100644
--- a/core/math/vector4i.cpp
+++ b/core/math/vector4i.cpp
@@ -84,8 +84,10 @@ Vector4i::operator Vector4() const {
}
Vector4i::Vector4i(const Vector4 &p_vec4) {
- x = p_vec4.x;
- y = p_vec4.y;
- z = p_vec4.z;
- w = p_vec4.w;
+ x = (int32_t)p_vec4.x;
+ y = (int32_t)p_vec4.y;
+ z = (int32_t)p_vec4.z;
+ w = (int32_t)p_vec4.w;
}
+
+static_assert(sizeof(Vector4i) == 4 * sizeof(int32_t));
diff --git a/core/math/vector4i.h b/core/math/vector4i.h
index 37d905878f..d08e40d754 100644
--- a/core/math/vector4i.h
+++ b/core/math/vector4i.h
@@ -132,7 +132,7 @@ double Vector4i::length() const {
}
Vector4i Vector4i::abs() const {
- return Vector4i(ABS(x), ABS(y), ABS(z), ABS(w));
+ return Vector4i(Math::abs(x), Math::abs(y), Math::abs(z), Math::abs(w));
}
Vector4i Vector4i::sign() const {
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index 34653310b1..8151ff2102 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -1680,7 +1680,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
} break;
case Variant::OBJECT: {
- Object *obj = p_variant;
+ Object *obj = p_variant.get_validated_object();
if (!obj) {
p_store_string_func(p_store_string_ud, "null");
diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml
index ebd4525b19..a80dd0d47f 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -265,6 +265,11 @@
Emitted when the GraphNode is requested to be closed. Happens on clicking the close button (see [member show_close]).
</description>
</signal>
+ <signal name="deselected">
+ <description>
+ Emitted when the GraphNode is deselected.
+ </description>
+ </signal>
<signal name="dragged">
<param index="0" name="from" type="Vector2" />
<param index="1" name="to" type="Vector2" />
@@ -288,6 +293,11 @@
Emitted when the GraphNode is requested to be resized. Happens on dragging the resizer handle (see [member resizable]).
</description>
</signal>
+ <signal name="selected">
+ <description>
+ Emitted when the GraphNode is selected.
+ </description>
+ </signal>
<signal name="slot_updated">
<param index="0" name="idx" type="int" />
<description>
diff --git a/doc/classes/ParallaxLayer.xml b/doc/classes/ParallaxLayer.xml
index 7e7c2d11ec..51a10f732d 100644
--- a/doc/classes/ParallaxLayer.xml
+++ b/doc/classes/ParallaxLayer.xml
@@ -13,6 +13,7 @@
<members>
<member name="motion_mirroring" type="Vector2" setter="set_mirroring" getter="get_mirroring" default="Vector2(0, 0)">
The ParallaxLayer's [Texture2D] mirroring. Useful for creating an infinite scrolling background. If an axis is set to [code]0[/code], the [Texture2D] will not be mirrored.
+ If the length of the viewport axis is bigger than twice the mirrored axis size, it will not repeat infinitely, as the parallax layer only draws 2 instances of the texture at any one time.
</member>
<member name="motion_offset" type="Vector2" setter="set_motion_offset" getter="get_motion_offset" default="Vector2(0, 0)">
The ParallaxLayer's offset relative to the parent ParallaxBackground's [member ParallaxBackground.scroll_offset].
diff --git a/doc/classes/PhysicsDirectBodyState2DExtension.xml b/doc/classes/PhysicsDirectBodyState2DExtension.xml
new file mode 100644
index 0000000000..8fd34c1243
--- /dev/null
+++ b/doc/classes/PhysicsDirectBodyState2DExtension.xml
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsDirectBodyState2DExtension" inherits="PhysicsDirectBodyState2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_add_constant_central_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_add_constant_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="force" type="Vector2" />
+ <param index="1" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_add_constant_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_central_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_central_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="impulse" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="force" type="Vector2" />
+ <param index="1" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="impulse" type="Vector2" />
+ <param index="1" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_torque_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="impulse" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_angular_velocity" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_center_of_mass" qualifiers="virtual const">
+ <return type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_center_of_mass_local" qualifiers="virtual const">
+ <return type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_constant_force" qualifiers="virtual const">
+ <return type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_constant_torque" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider" qualifiers="virtual const">
+ <return type="RID" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider_id" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider_object" qualifiers="virtual const">
+ <return type="Object" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider_position" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider_shape" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider_velocity_at_position" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_count" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_local_normal" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_local_position" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_local_shape" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_inverse_inertia" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_inverse_mass" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_linear_velocity" qualifiers="virtual const">
+ <return type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_space_state" qualifiers="virtual">
+ <return type="PhysicsDirectSpaceState2D" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_step" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_total_angular_damp" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_total_gravity" qualifiers="virtual const">
+ <return type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_total_linear_damp" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_transform" qualifiers="virtual const">
+ <return type="Transform2D" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_velocity_at_local_position" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="local_position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_integrate_forces" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="_is_sleeping" qualifiers="virtual const">
+ <return type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_angular_velocity" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="velocity" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_constant_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_constant_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_linear_velocity" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="velocity" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_sleep_state" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="enabled" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_transform" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="transform" type="Transform2D" />
+ <description>
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/PhysicsDirectSpaceState2DExtension.xml b/doc/classes/PhysicsDirectSpaceState2DExtension.xml
new file mode 100644
index 0000000000..3235793853
--- /dev/null
+++ b/doc/classes/PhysicsDirectSpaceState2DExtension.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsDirectSpaceState2DExtension" inherits="PhysicsDirectSpaceState2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_cast_motion" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
+ <param index="2" name="motion" type="Vector2" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="closest_safe" type="float*" />
+ <param index="8" name="closest_unsafe" type="float*" />
+ <description>
+ </description>
+ </method>
+ <method name="_collide_shape" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
+ <param index="2" name="motion" type="Vector2" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="results" type="void*" />
+ <param index="8" name="max_results" type="int" />
+ <param index="9" name="result_count" type="int32_t*" />
+ <description>
+ </description>
+ </method>
+ <method name="_intersect_point" qualifiers="virtual">
+ <return type="int" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="canvas_instance_id" type="int" />
+ <param index="2" name="collision_mask" type="int" />
+ <param index="3" name="collide_with_bodies" type="bool" />
+ <param index="4" name="collide_with_areas" type="bool" />
+ <param index="5" name="results" type="PhysicsServer2DExtensionShapeResult*" />
+ <param index="6" name="max_results" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_intersect_ray" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="from" type="Vector2" />
+ <param index="1" name="to" type="Vector2" />
+ <param index="2" name="collision_mask" type="int" />
+ <param index="3" name="collide_with_bodies" type="bool" />
+ <param index="4" name="collide_with_areas" type="bool" />
+ <param index="5" name="hit_from_inside" type="bool" />
+ <param index="6" name="result" type="PhysicsServer2DExtensionRayResult*" />
+ <description>
+ </description>
+ </method>
+ <method name="_intersect_shape" qualifiers="virtual">
+ <return type="int" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
+ <param index="2" name="motion" type="Vector2" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="result" type="PhysicsServer2DExtensionShapeResult*" />
+ <param index="8" name="max_results" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_rest_info" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
+ <param index="2" name="motion" type="Vector2" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="rest_info" type="PhysicsServer2DExtensionShapeRestInfo*" />
+ <description>
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index 5ae7423a71..4b588033c0 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -1058,6 +1058,8 @@
</constant>
<constant name="JOINT_PARAM_MAX_FORCE" value="2" enum="JointParam">
</constant>
+ <constant name="PIN_JOINT_SOFTNESS" value="0" enum="PinJointParam">
+ </constant>
<constant name="DAMPED_SPRING_REST_LENGTH" value="0" enum="DampedSpringParam">
Sets the resting length of the spring joint. The joint will always try to go to back this length when pulled apart.
</constant>
diff --git a/doc/classes/PhysicsServer2DExtension.xml b/doc/classes/PhysicsServer2DExtension.xml
new file mode 100644
index 0000000000..2659d3221f
--- /dev/null
+++ b/doc/classes/PhysicsServer2DExtension.xml
@@ -0,0 +1,777 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsServer2DExtension" inherits="PhysicsServer2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_area_add_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape" type="RID" />
+ <param index="2" name="transform" type="Transform2D" />
+ <param index="3" name="disabled" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_attach_canvas_instance_id" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="id" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_attach_object_instance_id" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="id" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_clear_shapes" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_canvas_instance_id" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_object_instance_id" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_param" qualifiers="virtual const">
+ <return type="Variant" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_shape" qualifiers="virtual const">
+ <return type="RID" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_shape_count" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_shape_transform" qualifiers="virtual const">
+ <return type="Transform2D" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_space" qualifiers="virtual const">
+ <return type="RID" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_transform" qualifiers="virtual const">
+ <return type="Transform2D" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_remove_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_area_monitor_callback" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="callback" type="Callable" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_collision_layer" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="layer" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_collision_mask" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="mask" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_monitor_callback" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="callback" type="Callable" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_monitorable" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="monitorable" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter" />
+ <param index="2" name="value" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="shape" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_shape_disabled" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_shape_transform" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="transform" type="Transform2D" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_space" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="space" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_transform" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_add_collision_exception" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="excepted_body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_add_constant_central_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_add_constant_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <param index="2" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_add_constant_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_add_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape" type="RID" />
+ <param index="2" name="transform" type="Transform2D" />
+ <param index="3" name="disabled" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_central_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_central_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <param index="2" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector2" />
+ <param index="2" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_torque_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_attach_canvas_instance_id" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="id" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_attach_object_instance_id" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="id" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_clear_shapes" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_canvas_instance_id" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_collision_layer" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_collision_mask" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_collision_priority" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_constant_force" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_constant_torque" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_continuous_collision_detection_mode" qualifiers="virtual const">
+ <return type="int" enum="PhysicsServer2D.CCDMode" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_direct_state" qualifiers="virtual">
+ <return type="PhysicsDirectBodyState2D" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_max_contacts_reported" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_mode" qualifiers="virtual const">
+ <return type="int" enum="PhysicsServer2D.BodyMode" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_object_instance_id" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_param" qualifiers="virtual const">
+ <return type="Variant" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_shape" qualifiers="virtual const">
+ <return type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_shape_count" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_shape_transform" qualifiers="virtual const">
+ <return type="Transform2D" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_space" qualifiers="virtual const">
+ <return type="RID" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_state" qualifiers="virtual const">
+ <return type="Variant" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="state" type="int" enum="PhysicsServer2D.BodyState" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_is_omitting_force_integration" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_remove_collision_exception" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="excepted_body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_remove_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_reset_mass_properties" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_axis_velocity" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="axis_velocity" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_collision_layer" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="layer" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_collision_mask" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mask" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_collision_priority" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="priority" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_constant_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_constant_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_continuous_collision_detection_mode" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mode" type="int" enum="PhysicsServer2D.CCDMode" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_force_integration_callback" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="callable" type="Callable" />
+ <param index="2" name="userdata" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_max_contacts_reported" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="amount" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_mode" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mode" type="int" enum="PhysicsServer2D.BodyMode" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_omit_force_integration" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" />
+ <param index="2" name="value" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="shape" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_shape_as_one_way_collision" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="enable" type="bool" />
+ <param index="3" name="margin" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_shape_disabled" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_shape_transform" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="transform" type="Transform2D" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_space" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="space" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_state" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="state" type="int" enum="PhysicsServer2D.BodyState" />
+ <param index="2" name="value" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_test_motion" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="from" type="Transform2D" />
+ <param index="2" name="motion" type="Vector2" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collide_separation_ray" type="bool" />
+ <param index="5" name="recovery_as_collision" type="bool" />
+ <param index="6" name="result" type="PhysicsServer2DExtensionMotionResult*" />
+ <description>
+ </description>
+ </method>
+ <method name="_capsule_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_circle_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_concave_polygon_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_convex_polygon_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_damped_spring_joint_get_param" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.DampedSpringParam" />
+ <description>
+ </description>
+ </method>
+ <method name="_damped_spring_joint_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.DampedSpringParam" />
+ <param index="2" name="value" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_free_rid" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="rid" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_process_info" qualifiers="virtual">
+ <return type="int" />
+ <param index="0" name="process_info" type="int" enum="PhysicsServer2D.ProcessInfo" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_clear" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_get_param" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.JointParam" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_get_type" qualifiers="virtual const">
+ <return type="int" enum="PhysicsServer2D.JointType" />
+ <param index="0" name="joint" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_make_damped_spring" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="anchor_a" type="Vector2" />
+ <param index="2" name="anchor_b" type="Vector2" />
+ <param index="3" name="body_a" type="RID" />
+ <param index="4" name="body_b" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_make_groove" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="a_groove1" type="Vector2" />
+ <param index="2" name="a_groove2" type="Vector2" />
+ <param index="3" name="b_anchor" type="Vector2" />
+ <param index="4" name="body_a" type="RID" />
+ <param index="5" name="body_b" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_make_pin" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="anchor" type="Vector2" />
+ <param index="2" name="body_a" type="RID" />
+ <param index="3" name="body_b" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.JointParam" />
+ <param index="2" name="value" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_pin_joint_get_param" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.PinJointParam" />
+ <description>
+ </description>
+ </method>
+ <method name="_pin_joint_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.PinJointParam" />
+ <param index="2" name="value" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_rectangle_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_segment_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_separation_ray_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_active" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="active" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_shape_get_data" qualifiers="virtual const">
+ <return type="Variant" />
+ <param index="0" name="shape" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_shape_get_type" qualifiers="virtual const">
+ <return type="int" enum="PhysicsServer2D.ShapeType" />
+ <param index="0" name="shape" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_shape_set_data" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="shape" type="RID" />
+ <param index="1" name="data" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_get_direct_state" qualifiers="virtual">
+ <return type="PhysicsDirectSpaceState2D" />
+ <param index="0" name="space" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_get_param" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_is_active" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="space" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_set_active" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="active" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter" />
+ <param index="2" name="value" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_world_boundary_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 47837cd9e1..1145798240 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -557,6 +557,9 @@
<member name="display/window/ios/hide_home_indicator" type="bool" setter="" getter="" default="true">
If [code]true[/code], the home indicator is hidden automatically. This only affects iOS devices without a physical home button.
</member>
+ <member name="display/window/per_pixel_transparency/allowed" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], allows per-pixel transparency for the window background. This affects performance, so leave it on [code]false[/code] unless you need it.
+ </member>
<member name="display/window/size/always_on_top" type="bool" setter="" getter="" default="false">
Forces the main window to be always on top.
[b]Note:[/b] This setting is ignored on iOS, Android, and Web.
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index 417703ff01..221e627e35 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -58,8 +58,13 @@
<return type="SceneTreeTimer" />
<param index="0" name="time_sec" type="float" />
<param index="1" name="process_always" type="bool" default="true" />
+ <param index="2" name="process_in_physics" type="bool" default="false" />
+ <param index="3" name="ignore_time_scale" type="bool" default="false" />
<description>
- Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree]. If [param process_always] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
+ Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree].
+ If [code]process_always[/code] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
+ If [code]process_in_physics[/code] is set to [code]true[/code], will update the [SceneTreeTimer] during the physics frame instead of the process frame (fixed framerate processing).
+ If [code]ignore_time_scale[/code] is set to [code]true[/code], will ignore [member Engine.time_scale] and update the [SceneTreeTimer] with the actual frame delta.
Commonly used to create a one-shot delay timer as in the following example:
[codeblocks]
[gdscript]
diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml
index 743e2c2fcc..fdc93f82ec 100644
--- a/doc/classes/Vector4.xml
+++ b/doc/classes/Vector4.xml
@@ -28,7 +28,7 @@
<return type="Vector4" />
<param index="0" name="from" type="Vector4i" />
<description>
- Constructs a new [Vector4] from [Vector4i].
+ Constructs a new [Vector4] from the given [Vector4i].
</description>
</constructor>
<constructor name="Vector4">
diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml
index 9a36c3c4fa..3eea93ce1f 100644
--- a/doc/classes/Vector4i.xml
+++ b/doc/classes/Vector4i.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Vector4i" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Vector used for 4D math using integer coordinates.
</brief_description>
<description>
+ 4-element structure that can be used to represent 4D grid coordinates or sets of integers.
+ It uses integer coordinates. See [Vector4] for its floating-point counterpart.
</description>
<tutorials>
</tutorials>
@@ -10,18 +13,21 @@
<constructor name="Vector4i">
<return type="Vector4i" />
<description>
+ Constructs a default-initialized [Vector4i] with all components set to [code]0[/code].
</description>
</constructor>
<constructor name="Vector4i">
<return type="Vector4i" />
<param index="0" name="from" type="Vector4i" />
<description>
+ Constructs a [Vector4i] as a copy of the given [Vector4i].
</description>
</constructor>
<constructor name="Vector4i">
<return type="Vector4i" />
<param index="0" name="from" type="Vector4" />
<description>
+ Constructs a new [Vector4i] from the given [Vector4].
</description>
</constructor>
<constructor name="Vector4i">
@@ -31,6 +37,7 @@
<param index="2" name="z" type="int" />
<param index="3" name="w" type="int" />
<description>
+ Returns a [Vector4i] with the given components.
</description>
</constructor>
</constructors>
@@ -38,6 +45,7 @@
<method name="abs" qualifiers="const">
<return type="Vector4i" />
<description>
+ Returns a new vector with all components in absolute values (i.e. positive).
</description>
</method>
<method name="clamp" qualifiers="const">
@@ -45,56 +53,72 @@
<param index="0" name="min" type="Vector4i" />
<param index="1" name="max" type="Vector4i" />
<description>
+ Returns a new vector with all components clamped between the components of [param min] and [param max], by running [method @GlobalScope.clamp] on each component.
</description>
</method>
<method name="length" qualifiers="const">
<return type="float" />
<description>
+ Returns the length (magnitude) of this vector.
</description>
</method>
<method name="length_squared" qualifiers="const">
<return type="int" />
<description>
+ Returns the squared length (squared magnitude) of this vector. This method runs faster than [method length].
</description>
</method>
<method name="max_axis_index" qualifiers="const">
<return type="int" />
<description>
+ Returns the axis of the vector's highest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_X].
</description>
</method>
<method name="min_axis_index" qualifiers="const">
<return type="int" />
<description>
+ Returns the axis of the vector's lowest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_W].
</description>
</method>
<method name="sign" qualifiers="const">
<return type="Vector4i" />
<description>
+ Returns a new vector with each component set to one or negative one, depending on the signs of the components, or zero if the component is zero, by calling [method @GlobalScope.sign] on each component.
</description>
</method>
</methods>
<members>
<member name="w" type="int" setter="" getter="" default="0">
+ The vector's W component. Also accessible by using the index position [code][3][/code].
</member>
<member name="x" type="int" setter="" getter="" default="0">
+ The vector's X component. Also accessible by using the index position [code][0][/code].
</member>
<member name="y" type="int" setter="" getter="" default="0">
+ The vector's Y component. Also accessible by using the index position [code][1][/code].
</member>
<member name="z" type="int" setter="" getter="" default="0">
+ The vector's Z component. Also accessible by using the index position [code][2][/code].
</member>
</members>
<constants>
<constant name="AXIS_X" value="0">
+ Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="AXIS_Y" value="1">
+ Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="AXIS_Z" value="2">
+ Enumerated value for the Z axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="AXIS_W" value="3">
+ Enumerated value for the W axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="ZERO" value="Vector4i(0, 0, 0, 0)">
+ Zero vector, a vector with all components set to [code]0[/code].
</constant>
<constant name="ONE" value="Vector4i(1, 1, 1, 1)">
+ One vector, a vector with all components set to [code]1[/code].
</constant>
</constants>
<operators>
@@ -102,6 +126,7 @@
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Returns [code]true[/code] if the vectors are not equal.
</description>
</operator>
<operator name="operator %">
@@ -120,94 +145,130 @@
<return type="Vector4i" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Multiplies each component of the [Vector4i] by the components of the given [Vector4i].
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) * Vector4i(3, 4, 5, 6)) # Prints "(30, 80, 150, 240)"
+ [/codeblock]
</description>
</operator>
<operator name="operator *">
<return type="Vector4" />
<param index="0" name="right" type="float" />
<description>
+ Multiplies each component of the [Vector4i] by the given [float].
+ Returns a Vector4 value due to floating-point operations.
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) * 2) # Prints "(20, 40, 60, 80)"
+ [/codeblock]
</description>
</operator>
<operator name="operator *">
<return type="Vector4i" />
<param index="0" name="right" type="int" />
<description>
+ Multiplies each component of the [Vector4i] by the given [int].
</description>
</operator>
<operator name="operator +">
<return type="Vector4i" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Adds each component of the [Vector4i] by the components of the given [Vector4i].
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) + Vector4i(3, 4, 5, 6)) # Prints "(13, 24, 35, 46)"
+ [/codeblock]
</description>
</operator>
<operator name="operator -">
<return type="Vector4i" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Subtracts each component of the [Vector4i] by the components of the given [Vector4i].
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) - Vector4i(3, 4, 5, 6)) # Prints "(7, 16, 25, 34)"
+ [/codeblock]
</description>
</operator>
<operator name="operator /">
<return type="Vector4i" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Divides each component of the [Vector4i] by the components of the given [Vector4i].
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) / Vector4i(2, 5, 3, 4)) # Prints "(5, 4, 10, 10)"
+ [/codeblock]
</description>
</operator>
<operator name="operator /">
<return type="Vector4" />
<param index="0" name="right" type="float" />
<description>
+ Divides each component of the [Vector4i] by the given [float].
+ Returns a Vector4 value due to floating-point operations.
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) / 2 # Prints "(5, 10, 15, 20)"
+ [/codeblock]
</description>
</operator>
<operator name="operator /">
<return type="Vector4i" />
<param index="0" name="right" type="int" />
<description>
+ Divides each component of the [Vector4i] by the given [int].
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Compares two [Vector4i] vectors by first checking if the X value of the left vector is less than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Compares two [Vector4i] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Returns [code]true[/code] if the vectors are exactly equal.
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Compares two [Vector4i] vectors by first checking if the X value of the left vector is greater than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Compares two [Vector4i] vectors by first checking if the X value of the left vector is greater than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator []">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
+ Access vector components using their [param index]. [code]v[0][/code] is equivalent to [code]v.x[/code], [code]v[1][/code] is equivalent to [code]v.y[/code], [code]v[2][/code] is equivalent to [code]v.z[/code], and [code]v[3][/code] is equivalent to [code]v.w[/code].
</description>
</operator>
<operator name="operator unary+">
<return type="Vector4i" />
<description>
+ Returns the same value as if the [code]+[/code] was not there. Unary [code]+[/code] does nothing, but sometimes it can make your code more readable.
</description>
</operator>
<operator name="operator unary-">
<return type="Vector4i" />
<description>
+ Returns the negative value of the [Vector4i]. This is the same as writing [code]Vector4i(-v.x, -v.y, -v.z, -v.w)[/code]. This operation flips the direction of the vector while keeping the same magnitude.
</description>
</operator>
</operators>
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 7537636356..cc96294ca5 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -108,19 +108,6 @@ void RasterizerGLES3::begin_frame(double frame_step) {
}
void RasterizerGLES3::end_frame(bool p_swap_buffers) {
- // if (OS::get_singleton()->is_layered_allowed()) {
- // if (!OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
- //clear alpha
- // glColorMask(false, false, false, true);
- // glClearColor(0.5, 0, 0, 1);
- // glClear(GL_COLOR_BUFFER_BIT);
- // glColorMask(true, true, true, true);
- // }
- // }
-
- // glClearColor(1, 0, 0, 1);
- // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-
if (p_swap_buffers) {
DisplayServer::get_singleton()->swap_buffers();
} else {
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index b52179b4f3..99ef57abae 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -1706,10 +1706,10 @@ Error VulkanContext::_update_swap_chain(Window *window) {
// Find a supported composite alpha mode - one of these is guaranteed to be set.
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = {
- VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
};
for (uint32_t i = 0; i < ARRAY_SIZE(compositeAlphaFlags); i++) {
if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 33632649c8..58020cf682 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -42,7 +42,7 @@ String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const {
#else
Key key = Key::CTRL;
#endif
- return TS->format_number(rtos(get_value())) + "\n\n" + vformat(TTR("Hold %s to round to integers. Hold Shift for more precise changes."), find_keycode_name(key));
+ return TS->format_number(rtos(get_value())) + "\n\n" + vformat(TTR("Hold %s to round to integers.\nHold Shift for more precise changes."), find_keycode_name(key));
}
return TS->format_number(rtos(get_value()));
}
diff --git a/editor/import/post_import_plugin_skeleton_renamer.cpp b/editor/import/post_import_plugin_skeleton_renamer.cpp
index 69c0a047e4..72ccb832c7 100644
--- a/editor/import/post_import_plugin_skeleton_renamer.cpp
+++ b/editor/import/post_import_plugin_skeleton_renamer.cpp
@@ -143,7 +143,7 @@ void PostImportPluginSkeletonRenamer::internal_process(InternalImportCategory p_
// Make unique skeleton.
if (bool(p_options["retarget/bone_renamer/unique_node/make_unique"])) {
String unique_name = String(p_options["retarget/bone_renamer/unique_node/skeleton_name"]);
- ERR_FAIL_COND_MSG(unique_name == String(), "Skeleton unique name cannot be empty.");
+ ERR_FAIL_COND_MSG(unique_name.is_empty(), "Skeleton unique name cannot be empty.");
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
while (nodes.size()) {
diff --git a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
index 6f775c7ea8..a5ef2e7f97 100644
--- a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
+++ b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
@@ -90,16 +90,9 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
- // Apply node transforms.
+ // Get global transform.
+ Transform3D global_transform;
if (bool(p_options["retarget/rest_fixer/apply_node_transforms"])) {
- LocalVector<Transform3D> old_skeleton_rest;
- LocalVector<Transform3D> old_skeleton_global_rest;
- for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
- old_skeleton_rest.push_back(src_skeleton->get_bone_rest(i));
- old_skeleton_global_rest.push_back(src_skeleton->get_bone_global_rest(i));
- }
-
- Transform3D global_transform;
Node *pr = src_skeleton;
while (pr) {
Node3D *pr3d = Object::cast_to<Node3D>(pr);
@@ -109,6 +102,47 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
pr = pr->get_parent();
}
+ global_transform.origin = Vector3(); // Translation by a Node is not a bone animation, so the retargeted model should be at the origin.
+ }
+
+ // Calc IBM difference.
+ LocalVector<Vector<Transform3D>> ibm_diffs;
+ {
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D");
+ while (nodes.size()) {
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back());
+ ERR_CONTINUE(!mi);
+
+ Ref<Skin> skin = mi->get_skin();
+ ERR_CONTINUE(!skin.is_valid());
+
+ Node *node = mi->get_node(mi->get_skeleton_path());
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!mesh_skeleton || mesh_skeleton != src_skeleton) {
+ continue;
+ }
+
+ Vector<Transform3D> ibm_diff;
+ ibm_diff.resize(src_skeleton->get_bone_count());
+ Transform3D *ibm_diff_w = ibm_diff.ptrw();
+
+ int skin_len = skin->get_bind_count();
+ for (int i = 0; i < skin_len; i++) {
+ StringName bn = skin->get_bind_name(i);
+ int bone_idx = src_skeleton->find_bone(bn);
+ if (bone_idx >= 0) {
+ ibm_diff_w[bone_idx] = global_transform * src_skeleton->get_bone_global_rest(bone_idx) * skin->get_bind_pose(i);
+ }
+ }
+
+ ibm_diffs.push_back(ibm_diff);
+ }
+ }
+
+ // Apply node transforms.
+ if (bool(p_options["retarget/rest_fixer/apply_node_transforms"])) {
Vector3 scl = global_transform.basis.get_scale_local();
Vector<int> bones_to_process = src_skeleton->get_parentless_bones();
@@ -148,38 +182,42 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
String track_path = String(anim->track_get_path(i).get_concatenated_names());
Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
- if (node) {
- Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
- if (track_skeleton && track_skeleton == src_skeleton) {
- StringName bn = anim->track_get_path(i).get_subname(0);
- if (bn) {
- int bone_idx = src_skeleton->find_bone(bn);
- int key_len = anim->track_get_key_count(i);
- if (anim->track_get_type(i) == Animation::TYPE_POSITION_3D) {
- if (bones_to_process.has(bone_idx)) {
- for (int j = 0; j < key_len; j++) {
- Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
- anim->track_set_key_value(i, j, global_transform.basis.xform(ps) + global_transform.origin);
- }
- } else {
- for (int j = 0; j < key_len; j++) {
- Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
- anim->track_set_key_value(i, j, ps * scl);
- }
- }
- } else if (bones_to_process.has(bone_idx)) {
- if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
- for (int j = 0; j < key_len; j++) {
- Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j));
- anim->track_set_key_value(i, j, global_transform.basis.get_rotation_quaternion() * qt);
- }
- } else {
- for (int j = 0; j < key_len; j++) {
- Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j)));
- anim->track_set_key_value(i, j, (global_transform.basis * sc).get_scale());
- }
- }
- }
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ StringName bn = anim->track_get_path(i).get_subname(0);
+ if (!bn) {
+ continue;
+ }
+
+ int bone_idx = src_skeleton->find_bone(bn);
+ int key_len = anim->track_get_key_count(i);
+ if (anim->track_get_type(i) == Animation::TYPE_POSITION_3D) {
+ if (bones_to_process.has(bone_idx)) {
+ for (int j = 0; j < key_len; j++) {
+ Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, global_transform.basis.xform(ps) + global_transform.origin);
+ }
+ } else {
+ for (int j = 0; j < key_len; j++) {
+ Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, ps * scl);
+ }
+ }
+ } else if (bones_to_process.has(bone_idx)) {
+ if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
+ for (int j = 0; j < key_len; j++) {
+ Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, global_transform.basis.get_rotation_quaternion() * qt);
+ }
+ } else {
+ for (int j = 0; j < key_len; j++) {
+ Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j)));
+ anim->track_set_key_value(i, j, (global_transform.basis * sc).get_scale());
}
}
}
@@ -220,24 +258,26 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
- if (found_skeleton) {
- // Search and insert rot track if it doesn't exist.
- for (int prof_idx = 0; prof_idx < prof_skeleton->get_bone_count(); prof_idx++) {
- String bone_name = is_renamed ? prof_skeleton->get_bone_name(prof_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_idx)));
- if (bone_name == String()) {
- continue;
- }
- int src_idx = src_skeleton->find_bone(bone_name);
- if (src_idx == -1) {
- continue;
- }
- String insert_path = track_path + ":" + bone_name;
- int rot_track = anim->find_track(insert_path, Animation::TYPE_ROTATION_3D);
- if (rot_track == -1) {
- int track = anim->add_track(Animation::TYPE_ROTATION_3D);
- anim->track_set_path(track, insert_path);
- anim->rotation_track_insert_key(track, 0, src_skeleton->get_bone_rest(src_idx).basis.get_rotation_quaternion());
- }
+ if (!found_skeleton) {
+ continue;
+ }
+
+ // Search and insert rot track if it doesn't exist.
+ for (int prof_idx = 0; prof_idx < prof_skeleton->get_bone_count(); prof_idx++) {
+ String bone_name = is_renamed ? prof_skeleton->get_bone_name(prof_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_idx)));
+ if (bone_name.is_empty()) {
+ continue;
+ }
+ int src_idx = src_skeleton->find_bone(bone_name);
+ if (src_idx == -1) {
+ continue;
+ }
+ String insert_path = track_path + ":" + bone_name;
+ int rot_track = anim->find_track(insert_path, Animation::TYPE_ROTATION_3D);
+ if (rot_track == -1) {
+ int track = anim->add_track(Animation::TYPE_ROTATION_3D);
+ anim->track_set_path(track, insert_path);
+ anim->rotation_track_insert_key(track, 0, src_skeleton->get_bone_rest(src_idx).basis.get_rotation_quaternion());
}
}
}
@@ -385,19 +425,23 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
String track_path = String(anim->track_get_path(i).get_concatenated_names());
Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
- if (node) {
- Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
- if (track_skeleton && track_skeleton == src_skeleton) {
- StringName bn = anim->track_get_path(i).get_concatenated_subnames();
- if (bn == scale_base_bone_name) {
- int key_len = anim->track_get_key_count(i);
- for (int j = 0; j < key_len; j++) {
- Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
- pos.y += base_adjustment;
- anim->track_set_key_value(i, j, pos);
- }
- }
- }
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ StringName bn = anim->track_get_path(i).get_concatenated_subnames();
+ if (bn != scale_base_bone_name) {
+ continue;
+ }
+
+ int key_len = anim->track_get_key_count(i);
+ for (int j = 0; j < key_len; j++) {
+ Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ pos.y += base_adjustment;
+ anim->track_set_key_value(i, j, pos);
}
}
}
@@ -441,16 +485,18 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
String track_path = String(anim->track_get_path(i).get_concatenated_names());
Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
- if (node) {
- Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
- if (track_skeleton && track_skeleton == src_skeleton) {
- real_t mlt = 1 / src_skeleton->get_motion_scale();
- int key_len = anim->track_get_key_count(i);
- for (int j = 0; j < key_len; j++) {
- Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
- anim->track_set_key_value(i, j, pos * mlt);
- }
- }
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ real_t mlt = 1 / src_skeleton->get_motion_scale();
+ int key_len = anim->track_get_key_count(i);
+ for (int j = 0; j < key_len; j++) {
+ Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, pos * mlt);
}
}
}
@@ -518,6 +564,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
while (nodes.size()) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
+ ERR_CONTINUE(!ap);
List<StringName> anims;
ap->get_animation_list(&anims);
for (const StringName &name : anims) {
@@ -534,53 +581,57 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
String track_path = String(anim->track_get_path(i).get_concatenated_names());
Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
- if (node) {
- Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
- if (track_skeleton && track_skeleton == src_skeleton) {
- StringName bn = anim->track_get_path(i).get_subname(0);
- if (bn) {
- int bone_idx = src_skeleton->find_bone(bn);
-
- Transform3D old_rest = old_skeleton_rest[bone_idx];
- Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx);
- Transform3D old_pg;
- Transform3D new_pg;
- int parent_idx = src_skeleton->get_bone_parent(bone_idx);
- if (parent_idx >= 0) {
- old_pg = old_skeleton_global_rest[parent_idx];
- new_pg = src_skeleton->get_bone_global_rest(parent_idx);
- }
-
- int key_len = anim->track_get_key_count(i);
- if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
- Quaternion old_rest_q = old_rest.basis.get_rotation_quaternion();
- Quaternion new_rest_q = new_rest.basis.get_rotation_quaternion();
- Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
- Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
- for (int j = 0; j < key_len; j++) {
- Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j));
- anim->track_set_key_value(i, j, new_pg_q.inverse() * old_pg_q * qt * old_rest_q.inverse() * old_pg_q.inverse() * new_pg_q * new_rest_q);
- }
- } else if (anim->track_get_type(i) == Animation::TYPE_SCALE_3D) {
- Basis old_rest_b = old_rest.basis;
- Basis new_rest_b = new_rest.basis;
- Basis old_pg_b = old_pg.basis;
- Basis new_pg_b = new_pg.basis;
- for (int j = 0; j < key_len; j++) {
- Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j)));
- anim->track_set_key_value(i, j, (new_pg_b.inverse() * old_pg_b * sc * old_rest_b.inverse() * old_pg_b.inverse() * new_pg_b * new_rest_b).get_scale());
- }
- } else {
- Vector3 old_rest_o = old_rest.origin;
- Vector3 new_rest_o = new_rest.origin;
- Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
- Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
- for (int j = 0; j < key_len; j++) {
- Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
- anim->track_set_key_value(i, j, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest_o)) + new_rest_o);
- }
- }
- }
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ StringName bn = anim->track_get_path(i).get_subname(0);
+ if (!bn) {
+ continue;
+ }
+
+ int bone_idx = src_skeleton->find_bone(bn);
+
+ Transform3D old_rest = old_skeleton_rest[bone_idx];
+ Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx);
+ Transform3D old_pg;
+ Transform3D new_pg;
+ int parent_idx = src_skeleton->get_bone_parent(bone_idx);
+ if (parent_idx >= 0) {
+ old_pg = old_skeleton_global_rest[parent_idx];
+ new_pg = src_skeleton->get_bone_global_rest(parent_idx);
+ }
+
+ int key_len = anim->track_get_key_count(i);
+ if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
+ Quaternion old_rest_q = old_rest.basis.get_rotation_quaternion();
+ Quaternion new_rest_q = new_rest.basis.get_rotation_quaternion();
+ Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
+ Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
+ for (int j = 0; j < key_len; j++) {
+ Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, new_pg_q.inverse() * old_pg_q * qt * old_rest_q.inverse() * old_pg_q.inverse() * new_pg_q * new_rest_q);
+ }
+ } else if (anim->track_get_type(i) == Animation::TYPE_SCALE_3D) {
+ Basis old_rest_b = old_rest.basis;
+ Basis new_rest_b = new_rest.basis;
+ Basis old_pg_b = old_pg.basis;
+ Basis new_pg_b = new_pg.basis;
+ for (int j = 0; j < key_len; j++) {
+ Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j)));
+ anim->track_set_key_value(i, j, (new_pg_b.inverse() * old_pg_b * sc * old_rest_b.inverse() * old_pg_b.inverse() * new_pg_b * new_rest_b).get_scale());
+ }
+ } else {
+ Vector3 old_rest_o = old_rest.origin;
+ Vector3 new_rest_o = new_rest.origin;
+ Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
+ Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
+ for (int j = 0; j < key_len; j++) {
+ Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest_o)) + new_rest_o);
}
}
}
@@ -595,26 +646,35 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
// Fix skin.
{
TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D");
+ int skin_idx = 0;
while (nodes.size()) {
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back());
+ ERR_CONTINUE(!mi);
+
Ref<Skin> skin = mi->get_skin();
- if (skin.is_valid()) {
- Node *node = mi->get_node(mi->get_skeleton_path());
- if (node) {
- Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
- if (mesh_skeleton && node == src_skeleton) {
- int skin_len = skin->get_bind_count();
- for (int i = 0; i < skin_len; i++) {
- StringName bn = skin->get_bind_name(i);
- int bone_idx = src_skeleton->find_bone(bn);
- if (bone_idx >= 0) {
- Transform3D new_rest = silhouette_diff[i] * src_skeleton->get_bone_global_rest(bone_idx);
- skin->set_bind_pose(i, new_rest.inverse());
- }
- }
- }
+ ERR_CONTINUE(!skin.is_valid());
+
+ Node *node = mi->get_node(mi->get_skeleton_path());
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!mesh_skeleton || mesh_skeleton != src_skeleton) {
+ continue;
+ }
+
+ Vector<Transform3D> ibm_diff = ibm_diffs[skin_idx];
+
+ int skin_len = skin->get_bind_count();
+ for (int i = 0; i < skin_len; i++) {
+ StringName bn = skin->get_bind_name(i);
+ int bone_idx = src_skeleton->find_bone(bn);
+ if (bone_idx >= 0) {
+ Transform3D new_rest = silhouette_diff[i] * src_skeleton->get_bone_global_rest(bone_idx);
+ skin->set_bind_pose(i, new_rest.inverse() * ibm_diff[bone_idx]);
}
}
+
+ skin_idx++;
}
}
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index 2809eb01cd..1a6106b4fb 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -1023,11 +1023,9 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
}
updating = true;
- undo_redo->create_action(TTR("Add Node"));
+ 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);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
connecting_to_node = name;
_add_transition(true);
undo_redo->commit_action();
@@ -1051,11 +1049,9 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
}
updating = true;
- undo_redo->create_action(TTR("Add Node"));
+ 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);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
connecting_to_node = name;
_add_transition(true);
undo_redo->commit_action();
@@ -1083,16 +1079,16 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
if (!p_nested_action) {
updating = true;
+ undo_redo->create_action(TTR("Add Transition"));
}
- undo_redo->create_action(TTR("Add Transition"));
undo_redo->add_do_method(state_machine.ptr(), "add_transition", connecting_from, connecting_to_node, tr);
undo_redo->add_undo_method(state_machine.ptr(), "remove_transition", connecting_from, connecting_to_node);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
if (!p_nested_action) {
+ undo_redo->commit_action();
updating = false;
}
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 15ae4ffcff..1facf04ca7 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -852,6 +852,20 @@ void Skeleton3DEditor::_notification(int p_what) {
update_joint_tree();
} break;
+ case NOTIFICATION_PREDELETE: {
+ if (skeleton) {
+ select_bone(-1); // Requires that the joint_tree has not been deleted.
+#ifdef TOOLS_ENABLED
+ skeleton->disconnect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible));
+ skeleton->disconnect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed));
+ skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo));
+ skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties));
+ skeleton->set_transform_gizmo_visible(true);
+#endif
+ handles_mesh_instance->get_parent()->remove_child(handles_mesh_instance);
+ }
+ edit_mode_toggled(false);
+ } break;
}
}
@@ -1066,18 +1080,7 @@ void Skeleton3DEditor::select_bone(int p_idx) {
}
Skeleton3DEditor::~Skeleton3DEditor() {
- if (skeleton) {
- select_bone(-1);
-#ifdef TOOLS_ENABLED
- skeleton->disconnect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible));
- skeleton->disconnect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed));
- skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo));
- skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties));
- skeleton->set_transform_gizmo_visible(true);
-#endif
- handles_mesh_instance->get_parent()->remove_child(handles_mesh_instance);
- }
- edit_mode_toggled(false);
+ singleton = nullptr;
handles_mesh_instance->queue_delete();
@@ -1128,7 +1131,7 @@ Skeleton3DEditorPlugin::Skeleton3DEditorPlugin() {
EditorPlugin::AfterGUIInput Skeleton3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
Node3DEditor *ne = Node3DEditor::get_singleton();
- if (se->is_edit_mode()) {
+ if (se && se->is_edit_mode()) {
const Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
if (ne->get_tool_mode() != Node3DEditor::TOOL_MODE_SELECT) {
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index e2265f2f83..cde4490cd3 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1255,16 +1255,14 @@ void SceneTreeDock::_notification(int p_what) {
// create_root_dialog
HBoxContainer *top_row = memnew(HBoxContainer);
- top_row->set_name("NodeShortcutsTopRow");
top_row->set_h_size_flags(SIZE_EXPAND_FILL);
Label *l = memnew(Label(TTR("Create Root Node:")));
l->set_theme_type_variation("HeaderSmall");
top_row->add_child(l);
top_row->add_spacer();
- Button *node_shortcuts_toggle = memnew(Button);
+ node_shortcuts_toggle = memnew(Button);
node_shortcuts_toggle->set_flat(true);
- node_shortcuts_toggle->set_name("NodeShortcutsToggle");
node_shortcuts_toggle->set_icon(get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons")));
node_shortcuts_toggle->set_toggle_mode(true);
node_shortcuts_toggle->set_tooltip_text(TTR("Switch to Favorite Nodes"));
@@ -1276,18 +1274,15 @@ void SceneTreeDock::_notification(int p_what) {
create_root_dialog->add_child(top_row);
ScrollContainer *scroll_container = memnew(ScrollContainer);
- scroll_container->set_name("NodeShortcutsScrollContainer");
create_root_dialog->add_child(scroll_container);
scroll_container->set_v_size_flags(SIZE_EXPAND_FILL);
scroll_container->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
VBoxContainer *node_shortcuts = memnew(VBoxContainer);
- node_shortcuts->set_name("NodeShortcuts");
scroll_container->add_child(node_shortcuts);
node_shortcuts->set_h_size_flags(SIZE_EXPAND_FILL);
- VBoxContainer *beginner_node_shortcuts = memnew(VBoxContainer);
- beginner_node_shortcuts->set_name("BeginnerNodeShortcuts");
+ beginner_node_shortcuts = memnew(VBoxContainer);
node_shortcuts->add_child(beginner_node_shortcuts);
button_2d = memnew(Button);
@@ -1308,8 +1303,7 @@ void SceneTreeDock::_notification(int p_what) {
button_ui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons")));
button_ui->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_USER_INTERFACE, false));
- VBoxContainer *favorite_node_shortcuts = memnew(VBoxContainer);
- favorite_node_shortcuts->set_name("FavoriteNodeShortcuts");
+ favorite_node_shortcuts = memnew(VBoxContainer);
node_shortcuts->add_child(favorite_node_shortcuts);
button_custom = memnew(Button);
@@ -3227,25 +3221,11 @@ void SceneTreeDock::_local_tree_selected() {
}
void SceneTreeDock::_update_create_root_dialog() {
- BaseButton *toggle = Object::cast_to<BaseButton>(create_root_dialog->get_node(String("NodeShortcutsTopRow/NodeShortcutsToggle")));
- Node *node_shortcuts = create_root_dialog->get_node(String("NodeShortcutsScrollContainer/NodeShortcuts"));
-
- if (!toggle || !node_shortcuts) {
- return;
- }
-
- Control *beginner_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("BeginnerNodeShortcuts")));
- Control *favorite_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("FavoriteNodeShortcuts")));
-
- if (!beginner_nodes || !favorite_nodes) {
- return;
- }
-
- EditorSettings::get_singleton()->set_setting("_use_favorites_root_selection", toggle->is_pressed());
+ EditorSettings::get_singleton()->set_setting("_use_favorites_root_selection", node_shortcuts_toggle->is_pressed());
EditorSettings::get_singleton()->save();
- if (toggle->is_pressed()) {
- for (int i = 0; i < favorite_nodes->get_child_count(); i++) {
- favorite_nodes->get_child(i)->queue_delete();
+ if (node_shortcuts_toggle->is_pressed()) {
+ for (int i = 0; i < favorite_node_shortcuts->get_child_count(); i++) {
+ favorite_node_shortcuts->get_child(i)->queue_delete();
}
Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites.Node"), FileAccess::READ);
@@ -3255,7 +3235,7 @@ void SceneTreeDock::_update_create_root_dialog() {
if (!l.is_empty()) {
Button *button = memnew(Button);
- favorite_nodes->add_child(button);
+ favorite_node_shortcuts->add_child(button);
button->set_text(l);
button->set_clip_text(true);
String name = l.get_slicec(' ', 0);
@@ -3268,14 +3248,14 @@ void SceneTreeDock::_update_create_root_dialog() {
}
}
- if (!favorite_nodes->is_visible_in_tree()) {
- favorite_nodes->show();
- beginner_nodes->hide();
+ if (!favorite_node_shortcuts->is_visible_in_tree()) {
+ favorite_node_shortcuts->show();
+ beginner_node_shortcuts->hide();
}
} else {
- if (!beginner_nodes->is_visible_in_tree()) {
- beginner_nodes->show();
- favorite_nodes->hide();
+ if (!beginner_node_shortcuts->is_visible_in_tree()) {
+ beginner_node_shortcuts->show();
+ favorite_node_shortcuts->hide();
}
button_clipboard->set_visible(!node_clipboard.is_empty());
}
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index e15865036b..dc228e1c93 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -119,6 +119,10 @@ class SceneTreeDock : public VBoxContainer {
Button *button_detach_script = nullptr;
MenuButton *button_tree_menu = nullptr;
+ Button *node_shortcuts_toggle = nullptr;
+ VBoxContainer *beginner_node_shortcuts = nullptr;
+ VBoxContainer *favorite_node_shortcuts = nullptr;
+
Button *button_2d = nullptr;
Button *button_3d = nullptr;
Button *button_ui = nullptr;
diff --git a/main/main.cpp b/main/main.cpp
index a0d2f594ac..650d1159e0 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1555,17 +1555,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF("internationalization/locale/include_text_server_data", false);
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", true);
-
- // FIXME: Restore support.
-#if 0
- //OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
- video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency/enabled", false);
-#endif
+ OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
if (editor || project_manager) {
// The editor and project manager always detect and use hiDPI if needed
OS::get_singleton()->_allow_hidpi = true;
- OS::get_singleton()->_allow_layered = false;
}
if (rtm == -1) {
diff --git a/misc/scripts/file_format.sh b/misc/scripts/file_format.sh
index 731b3ee005..1200b96ea0 100755
--- a/misc/scripts/file_format.sh
+++ b/misc/scripts/file_format.sh
@@ -41,7 +41,7 @@ while IFS= read -rd '' f; do
continue
fi
# Ensure that files are UTF-8 formatted.
- recode UTF-8 "$f" 2> /dev/null
+ isutf8 "$f" >> utf8-validation.txt 2>&1
# Ensure that files have LF line endings and do not contain a BOM.
dos2unix "$f" 2> /dev/null
# Remove trailing space characters and ensures that files end
@@ -51,15 +51,28 @@ done
diff=$(git diff --color)
-# If no diff has been generated all is OK, clean up, and exit.
-if [ -z "$diff" ] ; then
+# If no UTF-8 violations were collected and no diff has been
+# generated all is OK, clean up, and exit.
+if [ ! -s utf8-validation.txt ] && [ -z "$diff" ] ; then
printf "Files in this commit comply with the formatting rules.\n"
+ rm -f utf8-violations.txt
exit 0
fi
-# A diff has been created, notify the user, clean up, and exit.
-printf "\n*** The following differences were found between the code "
-printf "and the formatting rules:\n\n"
-echo "$diff"
+# Violations detected, notify the user, clean up, and exit.
+if [ -s utf8-validation.txt ]
+then
+ printf "\n*** The following files contain invalid UTF-8 character sequences:\n\n"
+ cat utf8-validation.txt
+ rm -f utf8-validation.txt
+fi
+
+if [ ! -z "$diff" ]
+then
+ printf "\n*** The following differences were found between the code "
+ printf "and the formatting rules:\n\n"
+ echo "$diff"
+fi
+
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
exit 1
diff --git a/modules/gltf/extensions/gltf_light.cpp b/modules/gltf/extensions/gltf_light.cpp
index ab5a15c671..6923c765cb 100644
--- a/modules/gltf/extensions/gltf_light.cpp
+++ b/modules/gltf/extensions/gltf_light.cpp
@@ -109,6 +109,7 @@ void GLTFLight::set_outer_cone_angle(float p_outer_cone_angle) {
Ref<GLTFLight> GLTFLight::from_node(const Light3D *p_light) {
Ref<GLTFLight> l;
l.instantiate();
+ ERR_FAIL_COND_V_MSG(!p_light, l, "Tried to create a GLTFLight from a Light3D node, but the given node was null.");
l->color = p_light->get_color();
if (cast_to<DirectionalLight3D>(p_light)) {
l->light_type = "directional";
diff --git a/modules/gltf/structures/gltf_camera.cpp b/modules/gltf/structures/gltf_camera.cpp
index 5069f39c4b..212b9b80c8 100644
--- a/modules/gltf/structures/gltf_camera.cpp
+++ b/modules/gltf/structures/gltf_camera.cpp
@@ -58,6 +58,7 @@ void GLTFCamera::_bind_methods() {
Ref<GLTFCamera> GLTFCamera::from_node(const Camera3D *p_camera) {
Ref<GLTFCamera> c;
c.instantiate();
+ ERR_FAIL_COND_V_MSG(!p_camera, c, "Tried to create a GLTFCamera from a Camera3D node, but the given node was null.");
c->set_perspective(p_camera->get_projection() == Camera3D::ProjectionType::PROJECTION_PERSPECTIVE);
// GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees.
c->set_fov(Math::deg_to_rad(p_camera->get_fov()));
diff --git a/modules/mono/README.md b/modules/mono/README.md
index ebbc6b0f80..366777cfc1 100644
--- a/modules/mono/README.md
+++ b/modules/mono/README.md
@@ -43,3 +43,13 @@ This option ensures the packages will be added to the specified local NuGet
source and that conflicting versions of the package are removed from the
NuGet cache. It's recommended to always use this option when building the
C# solutions during development to avoid mistakes.
+
+# Double Precision Support (REAL_T_IS_DOUBLE)
+
+Follow the above instructions but build Godot with the float=64 argument to scons
+
+When building the NuGet packages, specify `--float=64` - for example:
+```sh
+./modules/mono/build_scripts/build_assemblies.py --godot-output-dir ./bin \
+ --push-nupkgs-local ~/MyLocalNugetSource --float=64
+```
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py
index fa3be684bd..6f66ce9efa 100755
--- a/modules/mono/build_scripts/build_assemblies.py
+++ b/modules/mono/build_scripts/build_assemblies.py
@@ -195,7 +195,7 @@ def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: [str] = None):
return subprocess.call(args, env=msbuild_env)
-def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local):
+def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, float_size):
target_filenames = [
"GodotSharp.dll",
"GodotSharp.pdb",
@@ -216,6 +216,8 @@ def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local):
args = ["/restore", "/t:Build", "/p:Configuration=" + build_config, "/p:NoWarn=1591"]
if push_nupkgs_local:
args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
+ if float_size == "64":
+ args += ["/p:GodotFloat64=true"]
sln = os.path.join(module_dir, "glue/GodotSharp/GodotSharp.sln")
exit_code = run_msbuild(
@@ -256,9 +258,9 @@ def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local):
return 0
-def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, push_nupkgs_local):
+def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, push_nupkgs_local, float_size):
# Godot API
- exit_code = build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local)
+ exit_code = build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, float_size)
if exit_code != 0:
return exit_code
@@ -269,6 +271,8 @@ def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, p
)
if push_nupkgs_local:
args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
+ if float_size == "64":
+ args += ["/p:GodotFloat64=true"]
exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=args)
if exit_code != 0:
return exit_code
@@ -277,6 +281,8 @@ def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, p
args = ["/restore", "/t:Build", "/p:Configuration=Release"]
if push_nupkgs_local:
args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
+ if float_size == "64":
+ args += ["/p:GodotFloat64=true"]
sln = os.path.join(module_dir, "editor/Godot.NET.Sdk/Godot.NET.Sdk.sln")
exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=args)
if exit_code != 0:
@@ -300,6 +306,7 @@ def main():
parser.add_argument("--godot-platform", type=str, default="")
parser.add_argument("--mono-prefix", type=str, default="")
parser.add_argument("--push-nupkgs-local", type=str, default="")
+ parser.add_argument("--float", type=str, default="32", choices=["32", "64"], help="Floating-point precision")
args = parser.parse_args()
@@ -321,6 +328,7 @@ def main():
args.godot_platform,
args.dev_debug,
args.push_nupkgs_local,
+ args.float,
)
sys.exit(exit_code)
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 2e59987fe6..990a95821e 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -784,6 +784,13 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
for (Object *obj : script->instances) {
script->pending_reload_instances.insert(obj->get_instance_id());
+ // Since this script instance wasn't a placeholder, add it to the list of placeholders
+ // that will have to be eventually replaced with a script instance in case it turns into one.
+ // This list is not cleared after the reload and the collected instances only leave
+ // the list if the script is instantiated or if it was a tool script but becomes a
+ // non-tool script in a rebuild.
+ script->pending_replace_placeholders.insert(obj->get_instance_id());
+
RefCounted *rc = Object::cast_to<RefCounted>(obj);
if (rc) {
rc_instances.push_back(Ref<RefCounted>(rc));
@@ -836,6 +843,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
obj->set_script(Ref<RefCounted>()); // Remove script and existing script instances (placeholder are not removed before domain reload)
}
+ script->was_tool_before_reload = script->tool;
script->_clear();
}
@@ -924,24 +932,34 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
ScriptInstance *si = obj->get_script_instance();
+ // Check if the script must be instantiated or kept as a placeholder
+ // when the script may not be a tool (see #65266)
+ bool replace_placeholder = script->pending_replace_placeholders.has(obj->get_instance_id());
+ if (!script->is_tool() && script->was_tool_before_reload) {
+ // The script was a tool before the rebuild so the removal was intentional.
+ replace_placeholder = false;
+ script->pending_replace_placeholders.erase(obj->get_instance_id());
+ }
+
#ifdef TOOLS_ENABLED
if (si) {
// If the script instance is not null, then it must be a placeholder.
// Non-placeholder script instances are removed in godot_icall_Object_Disposed.
CRASH_COND(!si->is_placeholder());
- if (script->is_tool() || ScriptServer::is_scripting_enabled()) {
- // Replace placeholder with a script instance
+ if (replace_placeholder || script->is_tool() || ScriptServer::is_scripting_enabled()) {
+ // Replace placeholder with a script instance.
CSharpScript::StateBackup &state_backup = script->pending_reload_state[obj_id];
- // Backup placeholder script instance state before replacing it with a script instance
+ // Backup placeholder script instance state before replacing it with a script instance.
si->get_property_state(state_backup.properties);
ScriptInstance *script_instance = script->instance_create(obj);
if (script_instance) {
script->placeholders.erase(static_cast<PlaceHolderScriptInstance *>(si));
+ script->pending_replace_placeholders.erase(obj->get_instance_id());
obj->set_script_instance(script_instance);
}
}
@@ -951,8 +969,24 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
#else
CRASH_COND(si != nullptr);
#endif
- // Re-create script instance
- obj->set_script(script); // will create the script instance as well
+
+ // Re-create the script instance.
+ if (replace_placeholder || script->is_tool() || ScriptServer::is_scripting_enabled()) {
+ // Create script instance or replace placeholder with a script instance.
+ ScriptInstance *script_instance = script->instance_create(obj);
+
+ if (script_instance) {
+ script->pending_replace_placeholders.erase(obj->get_instance_id());
+ obj->set_script_instance(script_instance);
+ continue;
+ }
+ }
+ // The script instance could not be instantiated or wasn't in the list of placeholders to replace.
+ obj->set_script(script);
+#if DEBUG_ENABLED
+ // If we reached here, the instantiated script must be a placeholder.
+ CRASH_COND(!obj->get_script_instance()->is_placeholder());
+#endif
}
}
@@ -1754,20 +1788,16 @@ void CSharpInstance::mono_object_disposed_baseref(GCHandleIntPtr p_gchandle_to_f
}
void CSharpInstance::connect_event_signals() {
- CSharpScript *top = script.ptr();
- while (top != nullptr) {
- for (CSharpScript::EventSignalInfo &signal : top->get_script_event_signals()) {
- String signal_name = signal.name;
+ // The script signals list includes the signals declared in base scripts.
+ for (CSharpScript::EventSignalInfo &signal : script->get_script_event_signals()) {
+ String signal_name = signal.name;
- // TODO: Use pooling for ManagedCallable instances.
- EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name));
+ // TODO: Use pooling for ManagedCallable instances.
+ EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name));
- Callable callable(event_signal_callable);
- connected_event_signals.push_back(callable);
- owner->connect(signal_name, callable);
- }
-
- top = top->base_script.ptr();
+ Callable callable(event_signal_callable);
+ connected_event_signals.push_back(callable);
+ owner->connect(signal_name, callable);
}
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 3509a5c87d..f2844a051d 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -90,6 +90,9 @@ class CSharpScript : public Script {
HashSet<ObjectID> pending_reload_instances;
RBMap<ObjectID, StateBackup> pending_reload_state;
+
+ bool was_tool_before_reload = false;
+ HashSet<ObjectID> pending_replace_placeholders;
#endif
String source;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
index 59ce1da17b..0459257106 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
@@ -62,7 +62,7 @@
</PropertyGroup>
<PropertyGroup>
- <GodotRealTIsDouble Condition=" '$(GodotRealTIsDouble)' == '' ">false</GodotRealTIsDouble>
+ <GodotFloat64 Condition=" '$(GodotFloat64)' == '' ">false</GodotFloat64>
</PropertyGroup>
<!-- Godot DefineConstants. -->
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
index aad4ea4553..bff9760b32 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
@@ -10,9 +10,9 @@
<!--
Define constant to determine whether the real_t type in Godot is double precision or not.
By default this is false, like the official Godot builds. If someone is using a custom
- Godot build where real_t is double, they can override the GodotRealTIsDouble property.
+ Godot build where real_t is double, they can override the GodotFloat64 property.
-->
- <DefineConstants Condition=" '$(GodotRealTIsDouble)' == 'true' ">GODOT_REAL_T_IS_DOUBLE;$(DefineConstants)</DefineConstants>
+ <DefineConstants Condition=" '$(GodotFloat64)' == 'true' ">GODOT_REAL_T_IS_DOUBLE;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<!-- C# source generators -->
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 15a40c8ca5..c27bb959fe 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -113,7 +113,7 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) {
#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL ".ConvertSignalToManaged"
// Types that will be ignored by the generator and won't be available in C#.
-const Vector<String> ignored_types = { "PhysicsServer3DExtension" };
+const Vector<String> ignored_types = { "PhysicsServer2DExtension", "PhysicsServer3DExtension" };
void BindingsGenerator::TypeInterface::postsetup_enum_type(BindingsGenerator::TypeInterface &r_enum_itype) {
// C interface for enums is the same as that of 'uint32_t'. Remember to apply
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index 3884781988..092724a6b1 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -130,7 +130,6 @@ namespace Godot.Bridge
{
// Performance is not critical here as this will be replaced with source generators.
Type scriptType = _scriptTypeBiMap.GetScriptType(scriptPtr);
- var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
var ctor = scriptType
.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
@@ -151,6 +150,8 @@ namespace Godot.Bridge
}
}
+ var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
+
var parameters = ctor.GetParameters();
int paramCount = parameters.Length;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
index d1962c68cf..e2da41ff47 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
@@ -187,7 +187,7 @@ namespace Godot
(
Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight),
Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight),
- Mathf.CubicInterpolate(y, b.z, preA.z, postB.z, weight),
+ Mathf.CubicInterpolate(z, b.z, preA.z, postB.z, weight),
Mathf.CubicInterpolate(w, b.w, preA.w, postB.w, weight)
);
}
@@ -212,7 +212,7 @@ namespace Godot
(
Mathf.CubicInterpolateInTime(x, b.x, preA.x, postB.x, weight, t, preAT, postBT),
Mathf.CubicInterpolateInTime(y, b.y, preA.y, postB.y, weight, t, preAT, postBT),
- Mathf.CubicInterpolateInTime(y, b.z, preA.z, postB.z, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(z, b.z, preA.z, postB.z, weight, t, preAT, postBT),
Mathf.CubicInterpolateInTime(w, b.w, preA.w, postB.w, weight, t, preAT, postBT)
);
}
@@ -258,7 +258,7 @@ namespace Godot
/// <returns>The dot product of the two vectors.</returns>
public real_t Dot(Vector4 with)
{
- return (x * with.x) + (y * with.y) + (z * with.z) + (w + with.w);
+ return (x * with.x) + (y * with.y) + (z * with.z) + (w * with.w);
}
/// <summary>
@@ -455,6 +455,7 @@ namespace Godot
/// This can also be used to round to an arbitrary number of decimals.
/// </summary>
/// <param name="step">A vector value representing the step size to snap to.</param>
+ /// <returns>The snapped vector.</returns>
public Vector4 Snapped(Vector4 step)
{
return new Vector4(
@@ -632,6 +633,56 @@ namespace Godot
}
/// <summary>
+ /// Gets the remainder of each component of the <see cref="Vector4"/>
+ /// with the components of the given <see cref="real_t"/>.
+ /// This operation uses truncated division, which is often not desired
+ /// as it does not work well with negative numbers.
+ /// Consider using <see cref="PosMod(real_t)"/> instead
+ /// if you want to handle negative numbers.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.Print(new Vector4(10, -20, 30, 40) % 7); // Prints "(3, -6, 2, 5)"
+ /// </code>
+ /// </example>
+ /// <param name="vec">The dividend vector.</param>
+ /// <param name="divisor">The divisor value.</param>
+ /// <returns>The remainder vector.</returns>
+ public static Vector4 operator %(Vector4 vec, real_t divisor)
+ {
+ vec.x %= divisor;
+ vec.y %= divisor;
+ vec.z %= divisor;
+ vec.w %= divisor;
+ return vec;
+ }
+
+ /// <summary>
+ /// Gets the remainder of each component of the <see cref="Vector4"/>
+ /// with the components of the given <see cref="Vector4"/>.
+ /// This operation uses truncated division, which is often not desired
+ /// as it does not work well with negative numbers.
+ /// Consider using <see cref="PosMod(Vector4)"/> instead
+ /// if you want to handle negative numbers.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.Print(new Vector4(10, -20, 30, 10) % new Vector4(7, 8, 9, 10)); // Prints "(3, -4, 3, 0)"
+ /// </code>
+ /// </example>
+ /// <param name="vec">The dividend vector.</param>
+ /// <param name="divisorv">The divisor vector.</param>
+ /// <returns>The remainder vector.</returns>
+ public static Vector4 operator %(Vector4 vec, Vector4 divisorv)
+ {
+ vec.x %= divisorv.x;
+ vec.y %= divisorv.y;
+ vec.z %= divisorv.z;
+ vec.w %= divisorv.w;
+ return vec;
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if the vectors are exactly equal.
/// Note: Due to floating-point precision errors, consider using
/// <see cref="IsEqualApprox"/> instead, which is more reliable.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index aae7a5ebfa..5827d3e591 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -36,6 +36,7 @@
</ItemGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);GODOT</DefineConstants>
+ <DefineConstants Condition=" '$(GodotFloat64)' == 'true' ">REAL_T_IS_DOUBLE;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ReflectionAnalyzers" Version="0.1.22-dev" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" />
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
index ebf09aab7b..5d69ad8ec6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
@@ -25,6 +25,7 @@
</PropertyGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);GODOT</DefineConstants>
+ <DefineConstants Condition=" '$(GodotFloat64)' == 'true' ">REAL_T_IS_DOUBLE;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\GodotSharp\GodotSharp.csproj">
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index a329c7ee8c..c619e8eceb 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -2221,7 +2221,7 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
} break;
case WINDOW_FLAG_TRANSPARENT: {
- //todo reimplement
+ wd.layered_window = p_enabled;
} break;
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
@@ -2274,7 +2274,7 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co
return wd.on_top;
} break;
case WINDOW_FLAG_TRANSPARENT: {
- //todo reimplement
+ return wd.layered_window;
} break;
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
@@ -4426,13 +4426,41 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W
DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
//Create window
- long visualMask = VisualScreenMask;
- int numberOfVisuals;
- XVisualInfo vInfoTemplate = {};
- vInfoTemplate.screen = DefaultScreen(x11_display);
- XVisualInfo *visualInfo = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals);
+ XVisualInfo visualInfo;
+ bool vi_selected = false;
- Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, vInfoTemplate.screen), visualInfo->visual, AllocNone);
+#ifdef GLES3_ENABLED
+ if (gl_manager) {
+ visualInfo = gl_manager->get_vi(x11_display);
+ vi_selected = true;
+ }
+#endif
+
+ if (!vi_selected) {
+ long visualMask = VisualScreenMask;
+ int numberOfVisuals;
+ XVisualInfo vInfoTemplate = {};
+ vInfoTemplate.screen = DefaultScreen(x11_display);
+ XVisualInfo *vi_list = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals);
+ ERR_FAIL_COND_V(!vi_list, INVALID_WINDOW_ID);
+
+ visualInfo = vi_list[0];
+ if (OS::get_singleton()->is_layered_allowed()) {
+ for (int i = 0; i < numberOfVisuals; i++) {
+ XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi_list[i].visual);
+ if (!pict_format) {
+ continue;
+ }
+ visualInfo = vi_list[i];
+ if (pict_format->direct.alphaMask > 0) {
+ break;
+ }
+ }
+ }
+ XFree(vi_list);
+ }
+
+ Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, visualInfo.screen), visualInfo.visual, AllocNone);
XSetWindowAttributes windowAttributes = {};
windowAttributes.colormap = colormap;
@@ -4442,6 +4470,13 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
+ if (OS::get_singleton()->is_layered_allowed()) {
+ windowAttributes.background_pixmap = None;
+ windowAttributes.background_pixel = 0;
+ windowAttributes.border_pixmap = None;
+ valuemask |= CWBackPixel;
+ }
+
WindowID id = window_id_counter++;
WindowData &wd = windows[id];
@@ -4465,7 +4500,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
}
{
- wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes);
+ wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes);
// Enable receiving notification when the window is initialized (MapNotify)
// so the focus can be set at the right time.
@@ -4602,8 +4637,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
XSync(x11_display, False);
//XSetErrorHandler(oldHandler);
-
- XFree(visualInfo);
}
window_set_mode(p_mode, id);
@@ -4867,6 +4900,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
}
show_window(main_window);
+ XSync(x11_display, False);
+ _validate_mode_on_map(main_window);
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
@@ -5013,17 +5048,13 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
cursor_set_shape(CURSOR_BUSY);
- XEvent xevent;
- while (XPending(x11_display) > 0) {
- XNextEvent(x11_display, &xevent);
- if (xevent.type == ConfigureNotify) {
- _window_changed(&xevent);
- } else if (xevent.type == MapNotify) {
- // Have we failed to set fullscreen while the window was unmapped?
- _validate_mode_on_map(main_window);
- }
+ // Search the X11 event queue for ConfigureNotify events and process all
+ // that are currently queued early, so we can get the final window size
+ // for correctly drawing of the bootsplash.
+ XEvent config_event;
+ while (XCheckTypedEvent(x11_display, ConfigureNotify, &config_event)) {
+ _window_changed(&config_event);
}
-
events_thread.start(_poll_events_thread, this);
_update_real_mouse_position(windows[MAIN_WINDOW_ID]);
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index dd9ac088d9..ea03b2328c 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -159,6 +159,7 @@ class DisplayServerX11 : public DisplayServer {
bool minimized = false;
bool maximized = false;
bool is_popup = false;
+ bool layered_window = false;
Rect2i parent_safe_rect;
@@ -251,8 +252,6 @@ class DisplayServerX11 : public DisplayServer {
CursorShape current_cursor = CURSOR_ARROW;
HashMap<CursorShape, Vector<Variant>> cursors_cache;
- bool layered_window = false;
-
String rendering_driver;
void set_wm_fullscreen(bool p_enabled);
void set_wm_above(bool p_enabled);
diff --git a/platform/linuxbsd/gl_manager_x11.cpp b/platform/linuxbsd/gl_manager_x11.cpp
index d3fb1d6705..04c1df71fb 100644
--- a/platform/linuxbsd/gl_manager_x11.cpp
+++ b/platform/linuxbsd/gl_manager_x11.cpp
@@ -127,10 +127,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
GLXFBConfig fbconfig = nullptr;
XVisualInfo *vi = nullptr;
- gl_display.x_swa.event_mask = StructureNotifyMask;
- gl_display.x_swa.border_pixel = 0;
- gl_display.x_valuemask = CWBorderPixel | CWColormap | CWEventMask;
-
if (OS::get_singleton()->is_layered_allowed()) {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount);
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
@@ -156,12 +152,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
XFree(fbc);
ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED);
-
- gl_display.x_swa.background_pixmap = None;
- gl_display.x_swa.background_pixel = 0;
- gl_display.x_swa.border_pixmap = None;
- gl_display.x_valuemask |= CWBackPixel;
-
} else {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
@@ -189,8 +179,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
} break;
}
- gl_display.x_swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
-
XSync(x11_display, False);
XSetErrorHandler(oldHandler);
@@ -205,6 +193,10 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
return OK;
}
+XVisualInfo GLManager_X11::get_vi(Display *p_display) {
+ return _displays[_find_or_create_display(p_display)].x_vi;
+}
+
Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) {
// make sure vector is big enough...
// we can mirror the external vector, it is simpler
@@ -223,8 +215,6 @@ Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window
// the display could be invalid .. check NYI
GLDisplay &gl_display = _displays[win.gldisplay_id];
- //const XVisualInfo &vi = gl_display.x_vi;
- //XSetWindowAttributes &swa = gl_display.x_swa;
::Display *x11_display = gl_display.x11_display;
::Window &x11_window = win.x11_window;
@@ -315,6 +305,16 @@ void GLManager_X11::swap_buffers() {
return;
}
+ // On X11, when enabled, transparancy is always active, so clear alpha manually.
+ if (OS::get_singleton()->is_layered_allowed()) {
+ if (!DisplayServer::get_singleton()->window_get_flag(DisplayServer::WINDOW_FLAG_TRANSPARENT, _current_window->window_id)) {
+ glColorMask(false, false, false, true);
+ glClearColor(0, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColorMask(true, true, true, true);
+ }
+ }
+
// print_line("\tswap_buffers");
// only for debugging without drawing anything
diff --git a/platform/linuxbsd/gl_manager_x11.h b/platform/linuxbsd/gl_manager_x11.h
index fb2c74a2b6..4f78c45c88 100644
--- a/platform/linuxbsd/gl_manager_x11.h
+++ b/platform/linuxbsd/gl_manager_x11.h
@@ -68,8 +68,6 @@ private:
GLManager_X11_Private *context = nullptr;
::Display *x11_display;
XVisualInfo x_vi;
- XSetWindowAttributes x_swa;
- unsigned long x_valuemask;
};
// just for convenience, window and display struct
@@ -102,6 +100,7 @@ private:
Error _create_context(GLDisplay &gl_display);
public:
+ XVisualInfo get_vi(Display *p_display);
Error window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height);
void window_destroy(DisplayServer::WindowID p_window_id);
void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index e5bcb46b02..cfd3789b41 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -54,11 +54,13 @@ def get_mvk_sdk_path():
return [int_or_zero(i) for i in a.split(".")]
dirname = os.path.expanduser("~/VulkanSDK")
- files = os.listdir(dirname)
+ if not os.path.exists(dirname):
+ return ""
ver_file = "0.0.0.0"
ver_num = ver_parse(ver_file)
+ files = os.listdir(dirname)
for file in files:
if os.path.isdir(os.path.join(dirname, file)):
ver_comp = ver_parse(file)
@@ -145,7 +147,7 @@ def configure(env):
env.Append(LINKFLAGS=["-isysroot", "$MACOS_SDK_PATH"])
else: # osxcross build
- root = os.environ.get("OSXCROSS_ROOT", 0)
+ root = os.environ.get("OSXCROSS_ROOT", "")
if env["arch"] == "arm64":
basecmd = root + "/target/bin/arm64-apple-" + env["osxcross_sdk"] + "-"
else:
@@ -248,7 +250,7 @@ def configure(env):
env.Append(LINKFLAGS=["-L" + mvk_path])
if not mvk_found:
mvk_path = get_mvk_sdk_path()
- if os.path.isfile(os.path.join(mvk_path, "libMoltenVK.a")):
+ if mvk_path and os.path.isfile(os.path.join(mvk_path, "libMoltenVK.a")):
mvk_found = True
env.Append(LINKFLAGS=["-L" + mvk_path])
if not mvk_found:
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 6530846c15..b4949de3f7 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1312,7 +1312,28 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
_update_window_style(p_window);
} break;
case WINDOW_FLAG_TRANSPARENT: {
- // FIXME: Implement.
+ if (p_enabled) {
+ //enable per-pixel alpha
+
+ DWM_BLURBEHIND bb = { 0 };
+ HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
+ bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ bb.hRgnBlur = hRgn;
+ bb.fEnable = TRUE;
+ DwmEnableBlurBehindWindow(wd.hWnd, &bb);
+
+ wd.layered_window = true;
+ } else {
+ //disable per-pixel alpha
+ wd.layered_window = false;
+
+ DWM_BLURBEHIND bb = { 0 };
+ HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
+ bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ bb.hRgnBlur = hRgn;
+ bb.fEnable = FALSE;
+ DwmEnableBlurBehindWindow(wd.hWnd, &bb);
+ }
} break;
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
@@ -1344,7 +1365,7 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window
return wd.always_on_top;
} break;
case WINDOW_FLAG_TRANSPARENT: {
- // FIXME: Implement.
+ return wd.layered_window;
} break;
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index afdf78b380..dbc9821970 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -352,7 +352,6 @@ class DisplayServerWindows : public DisplayServer {
struct WindowData {
HWND hWnd;
- //layered window
Vector<Vector2> mpath;
@@ -392,10 +391,6 @@ class DisplayServerWindows : public DisplayServer {
Vector2 last_tilt;
bool last_pen_inverted = false;
- HBITMAP hBitmap; //DIB section for layered window
- uint8_t *dib_data = nullptr;
- Size2 dib_size;
- HDC hDC_dib;
Size2 min_size;
Size2 max_size;
int width = 0, height = 0;
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 32c112d21f..b0bccc4571 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -105,6 +105,7 @@ void LightmapGIData::_set_light_textures_data(const Array &p_data) {
Vector<Ref<Image>> images;
for (int i = 0; i < p_data.size(); i++) {
Ref<TextureLayered> texture = p_data[i];
+ ERR_FAIL_COND_MSG(texture.is_null(), vformat("Invalid TextureLayered at index %d.", i));
for (int j = 0; j < texture->get_layers(); j++) {
images.push_back(texture->get_layer_data(j));
}
diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/shape_cast_3d.cpp
index d324e09df5..a2fecf9c31 100644
--- a/scene/3d/shape_cast_3d.cpp
+++ b/scene/3d/shape_cast_3d.cpp
@@ -205,7 +205,7 @@ bool ShapeCast3D::is_enabled() const {
void ShapeCast3D::set_target_position(const Vector3 &p_point) {
target_position = p_point;
- if (is_inside_tree()) {
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
update_gizmos();
@@ -306,7 +306,7 @@ real_t ShapeCast3D::get_closest_collision_unsafe_fraction() const {
}
void ShapeCast3D::resource_changed(Ref<Resource> p_res) {
- if (is_inside_tree()) {
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
update_gizmos();
@@ -327,7 +327,7 @@ void ShapeCast3D::set_shape(const Ref<Shape3D> &p_shape) {
shape_rid = shape->get_rid();
}
- if (is_inside_tree()) {
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 8c16f8ca26..3efd465939 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -353,7 +353,20 @@ void GraphEdit::_graph_node_raised(Node *p_gn) {
} else {
gn->raise();
}
- emit_signal(SNAME("node_selected"), p_gn);
+}
+
+void GraphEdit::_graph_node_selected(Node *p_gn) {
+ GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_COND(!gn);
+
+ emit_signal(SNAME("node_selected"), gn);
+}
+
+void GraphEdit::_graph_node_deselected(Node *p_gn) {
+ GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_COND(!gn);
+
+ emit_signal(SNAME("node_deselected"), gn);
}
void GraphEdit::_graph_node_moved(Node *p_gn) {
@@ -383,6 +396,8 @@ void GraphEdit::add_child_notify(Node *p_child) {
if (gn) {
gn->set_scale(Vector2(zoom, zoom));
gn->connect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved).bind(gn));
+ gn->connect("selected", callable_mp(this, &GraphEdit::_graph_node_selected).bind(gn));
+ gn->connect("deselected", callable_mp(this, &GraphEdit::_graph_node_deselected).bind(gn));
gn->connect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated).bind(gn));
gn->connect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised).bind(gn));
gn->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw));
@@ -409,6 +424,8 @@ void GraphEdit::remove_child_notify(Node *p_child) {
GraphNode *gn = Object::cast_to<GraphNode>(p_child);
if (gn) {
gn->disconnect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved));
+ gn->disconnect("selected", callable_mp(this, &GraphEdit::_graph_node_selected));
+ gn->disconnect("deselected", callable_mp(this, &GraphEdit::_graph_node_deselected));
gn->disconnect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated));
gn->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised));
@@ -1170,24 +1187,9 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
bool in_box = r.intersects(box_selecting_rect);
if (in_box) {
- if (!gn->is_selected() && box_selection_mode_additive) {
- emit_signal(SNAME("node_selected"), gn);
- } else if (gn->is_selected() && !box_selection_mode_additive) {
- emit_signal(SNAME("node_deselected"), gn);
- }
- if (gn->is_selectable()) {
- gn->set_selected(box_selection_mode_additive);
- }
+ gn->set_selected(box_selection_mode_additive);
} else {
- bool select = (previous_selected.find(gn) != nullptr);
- if (gn->is_selected() && !select) {
- emit_signal(SNAME("node_deselected"), gn);
- } else if (!gn->is_selected() && select) {
- emit_signal(SNAME("node_selected"), gn);
- }
- if (gn->is_selectable()) {
- gn->set_selected(select);
- }
+ gn->set_selected(previous_selected.find(gn) != nullptr);
}
}
@@ -1206,13 +1208,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
continue;
}
- bool select = (gn->is_selectable() && previous_selected.find(gn) != nullptr);
- if (gn->is_selected() && !select) {
- emit_signal(SNAME("node_deselected"), gn);
- } else if (!gn->is_selected() && select) {
- emit_signal(SNAME("node_selected"), gn);
- }
- gn->set_selected(select);
+ gn->set_selected(previous_selected.find(gn) != nullptr);
}
top_layer->queue_redraw();
minimap->queue_redraw();
@@ -1235,7 +1231,6 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
Rect2 r = gn->get_rect();
r.size *= zoom;
if (r.has_point(b->get_position())) {
- emit_signal(SNAME("node_deselected"), gn);
gn->set_selected(false);
}
}
@@ -1270,18 +1265,21 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
if (b->get_button_index() == MouseButton::LEFT && b->is_pressed()) {
GraphNode *gn = nullptr;
+ // Find node which was clicked on.
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn_selected = Object::cast_to<GraphNode>(get_child(i));
- if (gn_selected) {
- if (gn_selected->is_resizing()) {
- continue;
- }
+ if (!gn_selected) {
+ continue;
+ }
- if (gn_selected->has_point((b->get_position() - gn_selected->get_position()) / zoom)) {
- gn = gn_selected;
- break;
- }
+ if (gn_selected->is_resizing()) {
+ continue;
+ }
+
+ if (gn_selected->has_point((b->get_position() - gn_selected->get_position()) / zoom)) {
+ gn = gn_selected;
+ break;
}
}
@@ -1290,26 +1288,22 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
return;
}
+ // Left-clicked on a node, select it.
dragging = true;
drag_accum = Vector2();
just_selected = !gn->is_selected();
if (!gn->is_selected() && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
- if (o_gn) {
- if (o_gn == gn) {
- o_gn->set_selected(o_gn->is_selectable());
- } else {
- if (o_gn->is_selected()) {
- emit_signal(SNAME("node_deselected"), o_gn);
- }
- o_gn->set_selected(false);
- }
+ if (!o_gn) {
+ continue;
}
+
+ o_gn->set_selected(o_gn == gn);
}
}
- gn->set_selected(gn->is_selectable());
+ gn->set_selected(true);
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (!o_gn) {
@@ -1332,6 +1326,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
return;
}
+ // Left-clicked on empty space, start box select.
box_selecting = true;
box_selecting_from = b->get_position();
if (b->is_ctrl_pressed()) {
@@ -1364,9 +1359,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
if (!gn2) {
continue;
}
- if (gn2->is_selected()) {
- emit_signal(SNAME("node_deselected"), gn2);
- }
+
gn2->set_selected(false);
}
}
@@ -1374,6 +1367,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
if (b->get_button_index() == MouseButton::LEFT && !b->is_pressed() && box_selecting) {
+ // Box selection ended. Nodes were selected during mouse movement.
box_selecting = false;
box_selecting_rect = Rect2();
previous_selected.clear();
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 0a0676699f..b6ce575009 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -186,6 +186,8 @@ private:
PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to);
void _draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom);
+ void _graph_node_selected(Node *p_gn);
+ void _graph_node_deselected(Node *p_gn);
void _graph_node_raised(Node *p_gn);
void _graph_node_moved(Node *p_gn);
void _graph_node_slot_updated(int p_index, Node *p_gn);
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 5976d9fc37..f441144a8e 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -736,11 +736,12 @@ Vector2 GraphNode::get_position_offset() const {
}
void GraphNode::set_selected(bool p_selected) {
- if (selected == p_selected) {
+ if (!is_selectable() || selected == p_selected) {
return;
}
selected = p_selected;
+ emit_signal(p_selected ? SNAME("selected") : SNAME("deselected"));
queue_redraw();
}
@@ -1012,6 +1013,9 @@ bool GraphNode::is_draggable() {
}
void GraphNode::set_selectable(bool p_selectable) {
+ if (!p_selectable) {
+ set_selected(false);
+ }
selectable = p_selectable;
}
@@ -1123,6 +1127,8 @@ void GraphNode::_bind_methods() {
ADD_GROUP("", "");
ADD_SIGNAL(MethodInfo("position_offset_changed"));
+ ADD_SIGNAL(MethodInfo("selected"));
+ ADD_SIGNAL(MethodInfo("deselected"));
ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "idx")));
ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::VECTOR2, "from"), PropertyInfo(Variant::VECTOR2, "to")));
ADD_SIGNAL(MethodInfo("raise_request"));
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 04bd5b3282..d4fea0d206 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -67,9 +67,51 @@ Ref<Texture2D> SplitContainer::_get_grabber_icon() const {
}
}
-void SplitContainer::_resort() {
+void SplitContainer::_compute_middle_sep(bool p_clamp) {
+ Control *first = _getch(0);
+ Control *second = _getch(1);
+
+ // Determine expanded children.
+ bool first_expanded = (vertical ? first->get_v_size_flags() : first->get_h_size_flags()) & SIZE_EXPAND;
+ bool second_expanded = (vertical ? second->get_v_size_flags() : second->get_h_size_flags()) & SIZE_EXPAND;
+
+ // Compute the minimum size.
int axis = vertical ? 1 : 0;
+ int size = get_size()[axis];
+ int ms_first = first->get_combined_minimum_size()[axis];
+ int ms_second = second->get_combined_minimum_size()[axis];
+
+ // Determine the separation between items.
+ Ref<Texture2D> g = get_theme_icon(SNAME("grabber"));
+ int sep = get_theme_constant(SNAME("separation"));
+ sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0;
+
+ // Compute the wished separation_point.
+ int wished_middle_sep = 0;
+ int split_offset_with_collapse = 0;
+ if (!collapsed) {
+ split_offset_with_collapse = split_offset;
+ }
+ if (first_expanded && second_expanded) {
+ float ratio = first->get_stretch_ratio() / (first->get_stretch_ratio() + second->get_stretch_ratio());
+ wished_middle_sep = size * ratio - sep / 2 + split_offset_with_collapse;
+ } else if (first_expanded) {
+ wished_middle_sep = size - sep + split_offset_with_collapse;
+ } else {
+ wished_middle_sep = split_offset_with_collapse;
+ }
+
+ // Clamp the middle sep to acceptatble values.
+ middle_sep = CLAMP(wished_middle_sep, ms_first, size - sep - ms_second);
+
+ // Clamp the split_offset if requested.
+ if (p_clamp) {
+ split_offset -= wished_middle_sep - middle_sep;
+ p_clamp = false;
+ }
+}
+void SplitContainer::_resort() {
Control *first = _getch(0);
Control *second = _getch(1);
@@ -83,41 +125,12 @@ void SplitContainer::_resort() {
return;
}
- // Determine expanded children
- bool first_expanded = (vertical ? first->get_v_size_flags() : first->get_h_size_flags()) & SIZE_EXPAND;
- bool second_expanded = (vertical ? second->get_v_size_flags() : second->get_h_size_flags()) & SIZE_EXPAND;
+ // If we have more that one.
+ _compute_middle_sep(false);
- // Determine the separation between items
Ref<Texture2D> g = _get_grabber_icon();
int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0;
- // Compute the minimum size
- Size2 ms_first = first->get_combined_minimum_size();
- Size2 ms_second = second->get_combined_minimum_size();
-
- // Compute the separator position without the split offset
- float ratio = first->get_stretch_ratio() / (first->get_stretch_ratio() + second->get_stretch_ratio());
- int no_offset_middle_sep = 0;
- if (first_expanded && second_expanded) {
- no_offset_middle_sep = get_size()[axis] * ratio - sep / 2;
- } else if (first_expanded) {
- no_offset_middle_sep = get_size()[axis] - ms_second[axis] - sep;
- } else {
- no_offset_middle_sep = ms_first[axis];
- }
-
- // Compute the final middle separation.
- middle_sep = no_offset_middle_sep;
- if (!collapsed) {
- int clamped_split_offset = CLAMP(split_offset, ms_first[axis] - no_offset_middle_sep, (get_size()[axis] - ms_second[axis] - sep) - no_offset_middle_sep);
- middle_sep += clamped_split_offset;
- if (should_clamp_split_offset) {
- split_offset = clamped_split_offset;
-
- should_clamp_split_offset = false;
- }
- }
-
if (vertical) {
fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(get_size().width, middle_sep)));
int sofs = middle_sep + sep;
@@ -248,12 +261,14 @@ void SplitContainer::gui_input(const Ref<InputEvent> &p_event) {
if (mb->is_pressed()) {
if (vertical) {
if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + theme_cache.separation) {
+ _compute_middle_sep(true);
dragging = true;
drag_from = mb->get_position().y;
drag_ofs = split_offset;
}
} else {
if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + theme_cache.separation) {
+ _compute_middle_sep(true);
dragging = true;
drag_from = mb->get_position().x;
drag_ofs = split_offset;
@@ -287,11 +302,11 @@ void SplitContainer::gui_input(const Ref<InputEvent> &p_event) {
}
if (!vertical && is_layout_rtl()) {
- split_offset = drag_ofs + (drag_from - (vertical ? mm->get_position().y : mm->get_position().x));
+ split_offset = drag_ofs - ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from);
} else {
split_offset = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from);
}
- should_clamp_split_offset = true;
+ _compute_middle_sep(true);
queue_sort();
emit_signal(SNAME("dragged"), get_split_offset());
}
@@ -332,8 +347,11 @@ int SplitContainer::get_split_offset() const {
}
void SplitContainer::clamp_split_offset() {
- should_clamp_split_offset = true;
+ if (!_getch(0) || !_getch(1)) {
+ return;
+ }
+ _compute_middle_sep(true);
queue_sort();
}
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index 8ab0779d4b..598b0ba485 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -44,7 +44,6 @@ public:
};
private:
- bool should_clamp_split_offset = false;
int split_offset = 0;
int middle_sep = 0;
bool vertical = false;
@@ -66,6 +65,7 @@ private:
Control *_getch(int p_idx) const;
Ref<Texture2D> _get_grabber_icon() const;
+ void _compute_middle_sep(bool p_clamp);
void _resort();
protected:
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 268b381029..25c9b33ff9 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -88,6 +88,14 @@ bool SceneTreeTimer::is_process_always() {
return process_always;
}
+void SceneTreeTimer::set_process_in_physics(bool p_process_in_physics) {
+ process_in_physics = p_process_in_physics;
+}
+
+bool SceneTreeTimer::is_process_in_physics() {
+ return process_in_physics;
+}
+
void SceneTreeTimer::set_ignore_time_scale(bool p_ignore) {
ignore_time_scale = p_ignore;
}
@@ -420,6 +428,8 @@ bool SceneTree::physics_process(double p_time) {
_flush_ugc();
MessageQueue::get_singleton()->flush(); //small little hack
+ process_timers(p_time, true); //go through timers
+
process_tweens(p_time, true);
flush_transform_notifications();
@@ -462,37 +472,7 @@ bool SceneTree::process(double p_time) {
_flush_delete_queue();
- //go through timers
-
- List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
-
- for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
- List<Ref<SceneTreeTimer>>::Element *N = E->next();
- if (paused && !E->get()->is_process_always()) {
- if (E == L) {
- break; //break on last, so if new timers were added during list traversal, ignore them.
- }
- E = N;
- continue;
- }
-
- double time_left = E->get()->get_time_left();
- if (E->get()->is_ignore_time_scale()) {
- time_left -= Engine::get_singleton()->get_process_step();
- } else {
- time_left -= p_time;
- }
- E->get()->set_time_left(time_left);
-
- if (time_left <= 0) {
- E->get()->emit_signal(SNAME("timeout"));
- timers.erase(E);
- }
- if (E == L) {
- break; //break on last, so if new timers were added during list traversal, ignore them.
- }
- E = N;
- }
+ process_timers(p_time, false); //go through timers
process_tweens(p_time, false);
@@ -530,6 +510,38 @@ bool SceneTree::process(double p_time) {
return _quit;
}
+void SceneTree::process_timers(float p_delta, bool p_physics_frame) {
+ List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
+
+ for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
+ List<Ref<SceneTreeTimer>>::Element *N = E->next();
+ if ((paused && !E->get()->is_process_always()) || (E->get()->is_process_in_physics() != p_physics_frame)) {
+ if (E == L) {
+ break; //break on last, so if new timers were added during list traversal, ignore them.
+ }
+ E = N;
+ continue;
+ }
+
+ double time_left = E->get()->get_time_left();
+ if (E->get()->is_ignore_time_scale()) {
+ time_left -= Engine::get_singleton()->get_process_step();
+ } else {
+ time_left -= p_delta;
+ }
+ E->get()->set_time_left(time_left);
+
+ if (time_left <= 0) {
+ E->get()->emit_signal(SNAME("timeout"));
+ timers.erase(E);
+ }
+ if (E == L) {
+ break; //break on last, so if new timers were added during list traversal, ignore them.
+ }
+ E = N;
+ }
+}
+
void SceneTree::process_tweens(float p_delta, bool p_physics) {
// This methods works similarly to how SceneTreeTimers are handled.
List<Ref<Tween>>::Element *L = tweens.back();
@@ -1157,11 +1169,13 @@ void SceneTree::add_current_scene(Node *p_current) {
root->add_child(p_current);
}
-Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always) {
+Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always, bool p_process_in_physics, bool p_ignore_time_scale) {
Ref<SceneTreeTimer> stt;
stt.instantiate();
stt->set_process_always(p_process_always);
stt->set_time_left(p_delay_sec);
+ stt->set_process_in_physics(p_process_in_physics);
+ stt->set_ignore_time_scale(p_ignore_time_scale);
timers.push_back(stt);
return stt;
}
@@ -1259,7 +1273,7 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause);
ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused);
- ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always"), &SceneTree::create_timer, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always", "process_in_physics", "ignore_time_scale"), &SceneTree::create_timer, DEFVAL(true), DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_tween"), &SceneTree::create_tween);
ClassDB::bind_method(D_METHOD("get_processed_tweens"), &SceneTree::get_processed_tweens);
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index e66363ab33..45653001ca 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -53,6 +53,7 @@ class SceneTreeTimer : public RefCounted {
double time_left = 0.0;
bool process_always = true;
+ bool process_in_physics = false;
bool ignore_time_scale = false;
protected:
@@ -65,6 +66,9 @@ public:
void set_process_always(bool p_process_always);
bool is_process_always();
+ void set_process_in_physics(bool p_process_in_physics);
+ bool is_process_in_physics();
+
void set_ignore_time_scale(bool p_ignore);
bool is_ignore_time_scale();
@@ -176,6 +180,7 @@ private:
void node_added(Node *p_node);
void node_removed(Node *p_node);
void node_renamed(Node *p_node);
+ void process_timers(float p_delta, bool p_physics_frame);
void process_tweens(float p_delta, bool p_physics_frame);
Group *add_to_group(const StringName &p_group, Node *p_node);
@@ -365,7 +370,7 @@ public:
Error change_scene_to(const Ref<PackedScene> &p_scene);
Error reload_current_scene();
- Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true);
+ Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true, bool p_process_in_physics = false, bool p_ignore_time_scale = false);
Ref<Tween> create_tween();
TypedArray<Tween> get_processed_tweens();
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 84e4162c00..04f56bb874 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -865,9 +865,7 @@ void Window::_notification(int p_what) {
RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
}
- // Need to defer here, because theme owner information might be set in
- // add_child_notify, which doesn't get called until right after this.
- call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED);
+ notification(NOTIFICATION_THEME_CHANGED);
} break;
case NOTIFICATION_THEME_CHANGED: {
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 72e55ac47d..5dfa25163b 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1636,10 +1636,14 @@ String VisualShaderNodeLinearSceneDepth::get_output_port_name(int p_port) const
return "linear depth";
}
+bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const {
+ return false;
+}
+
String VisualShaderNodeLinearSceneDepth::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
- code += " float _log_depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;\n";
+ code += " float _log_depth = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).x;\n";
code += " vec3 _depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, _log_depth);\n";
code += " vec4 _depth_view = INV_PROJECTION_MATRIX * vec4(_depth_ndc, 1.0);\n";
code += " _depth_view.xyz /= _depth_view.w;";
@@ -7194,6 +7198,10 @@ String VisualShaderNodeDistanceFade::get_output_port_name(int p_port) const {
return "amount";
}
+bool VisualShaderNodeDistanceFade::has_output_port_preview(int p_port) const {
+ return false;
+}
+
String VisualShaderNodeDistanceFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
code += vformat(" %s = clamp(smoothstep(%s, %s,-VERTEX.z),0.0,1.0);\n", p_output_vars[0], p_input_vars[0], p_input_vars[1]);
@@ -7235,6 +7243,10 @@ String VisualShaderNodeProximityFade::get_output_port_name(int p_port) const {
return "fade";
}
+bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const {
+ return false;
+}
+
String VisualShaderNodeProximityFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index ecba412fcb..4f18447333 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -636,6 +636,7 @@ public:
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
@@ -2643,6 +2644,7 @@ public:
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
@@ -2662,6 +2664,7 @@ public:
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
diff --git a/servers/extensions/physics_server_2d_extension.cpp b/servers/extensions/physics_server_2d_extension.cpp
new file mode 100644
index 0000000000..2ef4cd3352
--- /dev/null
+++ b/servers/extensions/physics_server_2d_extension.cpp
@@ -0,0 +1,294 @@
+/*************************************************************************/
+/* physics_server_2d_extension.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "physics_server_2d_extension.h"
+
+bool PhysicsDirectSpaceState2DExtension::is_body_excluded_from_query(const RID &p_body) const {
+ return exclude && exclude->has(p_body);
+}
+
+thread_local const HashSet<RID> *PhysicsDirectSpaceState2DExtension::exclude = nullptr;
+
+void PhysicsDirectSpaceState2DExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_intersect_ray, "from", "to", "collision_mask", "collide_with_bodies", "collide_with_areas", "hit_from_inside", "result");
+ GDVIRTUAL_BIND(_intersect_point, "position", "canvas_instance_id", "collision_mask", "collide_with_bodies", "collide_with_areas", "results", "max_results");
+ GDVIRTUAL_BIND(_intersect_shape, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "result", "max_results");
+ GDVIRTUAL_BIND(_cast_motion, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "closest_safe", "closest_unsafe");
+ GDVIRTUAL_BIND(_collide_shape, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "results", "max_results", "result_count");
+ GDVIRTUAL_BIND(_rest_info, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "rest_info");
+}
+
+PhysicsDirectSpaceState2DExtension::PhysicsDirectSpaceState2DExtension() {
+}
+
+void PhysicsDirectBodyState2DExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_total_gravity);
+ GDVIRTUAL_BIND(_get_total_linear_damp);
+ GDVIRTUAL_BIND(_get_total_angular_damp);
+
+ GDVIRTUAL_BIND(_get_center_of_mass);
+ GDVIRTUAL_BIND(_get_center_of_mass_local);
+ GDVIRTUAL_BIND(_get_inverse_mass);
+ GDVIRTUAL_BIND(_get_inverse_inertia);
+
+ GDVIRTUAL_BIND(_set_linear_velocity, "velocity");
+ GDVIRTUAL_BIND(_get_linear_velocity);
+
+ GDVIRTUAL_BIND(_set_angular_velocity, "velocity");
+ GDVIRTUAL_BIND(_get_angular_velocity);
+
+ GDVIRTUAL_BIND(_set_transform, "transform");
+ GDVIRTUAL_BIND(_get_transform);
+
+ GDVIRTUAL_BIND(_get_velocity_at_local_position, "local_position");
+
+ GDVIRTUAL_BIND(_apply_central_impulse, "impulse");
+ GDVIRTUAL_BIND(_apply_impulse, "impulse", "position");
+ GDVIRTUAL_BIND(_apply_torque_impulse, "impulse");
+
+ GDVIRTUAL_BIND(_apply_central_force, "force");
+ GDVIRTUAL_BIND(_apply_force, "force", "position");
+ GDVIRTUAL_BIND(_apply_torque, "torque");
+
+ GDVIRTUAL_BIND(_add_constant_central_force, "force");
+ GDVIRTUAL_BIND(_add_constant_force, "force", "position");
+ GDVIRTUAL_BIND(_add_constant_torque, "torque");
+
+ GDVIRTUAL_BIND(_set_constant_force, "force");
+ GDVIRTUAL_BIND(_get_constant_force);
+
+ GDVIRTUAL_BIND(_set_constant_torque, "torque");
+ GDVIRTUAL_BIND(_get_constant_torque);
+
+ GDVIRTUAL_BIND(_set_sleep_state, "enabled");
+ GDVIRTUAL_BIND(_is_sleeping);
+
+ GDVIRTUAL_BIND(_get_contact_count);
+
+ GDVIRTUAL_BIND(_get_contact_local_position, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_local_normal, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_local_shape, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider_position, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider_id, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider_object, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider_shape, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider_velocity_at_position, "contact_idx");
+
+ GDVIRTUAL_BIND(_get_step);
+ GDVIRTUAL_BIND(_integrate_forces);
+
+ GDVIRTUAL_BIND(_get_space_state);
+}
+
+PhysicsDirectBodyState2DExtension::PhysicsDirectBodyState2DExtension() {
+}
+
+thread_local const HashSet<RID> *PhysicsServer2DExtension::exclude_bodies = nullptr;
+thread_local const HashSet<ObjectID> *PhysicsServer2DExtension::exclude_objects = nullptr;
+
+bool PhysicsServer2DExtension::body_test_motion_is_excluding_body(RID p_body) const {
+ return exclude_bodies && exclude_bodies->has(p_body);
+}
+
+bool PhysicsServer2DExtension::body_test_motion_is_excluding_object(ObjectID p_object) const {
+ return exclude_objects && exclude_objects->has(p_object);
+}
+
+void PhysicsServer2DExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_world_boundary_shape_create);
+ GDVIRTUAL_BIND(_separation_ray_shape_create);
+ GDVIRTUAL_BIND(_segment_shape_create);
+ GDVIRTUAL_BIND(_circle_shape_create);
+ GDVIRTUAL_BIND(_rectangle_shape_create);
+ GDVIRTUAL_BIND(_capsule_shape_create);
+ GDVIRTUAL_BIND(_convex_polygon_shape_create);
+ GDVIRTUAL_BIND(_concave_polygon_shape_create);
+
+ GDVIRTUAL_BIND(_shape_set_data, "shape", "data");
+
+ GDVIRTUAL_BIND(_shape_get_type, "shape");
+ GDVIRTUAL_BIND(_shape_get_data, "shape");
+
+ GDVIRTUAL_BIND(_space_create);
+ GDVIRTUAL_BIND(_space_set_active, "space", "active");
+ GDVIRTUAL_BIND(_space_is_active, "space");
+ GDVIRTUAL_BIND(_space_set_param, "space", "param", "value");
+ GDVIRTUAL_BIND(_space_get_param, "space", "param");
+ GDVIRTUAL_BIND(_space_get_direct_state, "space");
+
+ GDVIRTUAL_BIND(_area_create);
+ GDVIRTUAL_BIND(_area_set_space, "area", "space");
+ GDVIRTUAL_BIND(_area_get_space, "area");
+
+ GDVIRTUAL_BIND(_area_add_shape, "area", "shape", "transform", "disabled");
+ GDVIRTUAL_BIND(_area_set_shape, "area", "shape_idx", "shape");
+ GDVIRTUAL_BIND(_area_set_shape_transform, "area", "shape_idx", "transform");
+ GDVIRTUAL_BIND(_area_set_shape_disabled, "area", "shape_idx", "disabled");
+
+ GDVIRTUAL_BIND(_area_get_shape_count, "area");
+ GDVIRTUAL_BIND(_area_get_shape, "area", "shape_idx");
+ GDVIRTUAL_BIND(_area_get_shape_transform, "area", "shape_idx");
+
+ GDVIRTUAL_BIND(_area_remove_shape, "area", "shape_idx");
+ GDVIRTUAL_BIND(_area_clear_shapes, "area");
+
+ GDVIRTUAL_BIND(_area_set_collision_layer, "area", "layer");
+ GDVIRTUAL_BIND(_area_set_collision_mask, "area", "mask");
+
+ GDVIRTUAL_BIND(_area_set_param, "area", "param", "value");
+ GDVIRTUAL_BIND(_area_set_transform, "area", "transform");
+
+ GDVIRTUAL_BIND(_area_get_param, "area", "param");
+ GDVIRTUAL_BIND(_area_get_transform, "area");
+
+ GDVIRTUAL_BIND(_area_attach_object_instance_id, "area", "id");
+ GDVIRTUAL_BIND(_area_get_object_instance_id, "area");
+
+ GDVIRTUAL_BIND(_area_attach_canvas_instance_id, "area", "id");
+ GDVIRTUAL_BIND(_area_get_canvas_instance_id, "area");
+
+ GDVIRTUAL_BIND(_area_set_monitor_callback, "area", "callback");
+ GDVIRTUAL_BIND(_area_set_area_monitor_callback, "area", "callback");
+ GDVIRTUAL_BIND(_area_set_monitorable, "area", "monitorable");
+
+ GDVIRTUAL_BIND(_body_create);
+
+ GDVIRTUAL_BIND(_body_set_space, "body", "space");
+ GDVIRTUAL_BIND(_body_get_space, "body");
+
+ GDVIRTUAL_BIND(_body_set_mode, "body", "mode");
+ GDVIRTUAL_BIND(_body_get_mode, "body");
+
+ GDVIRTUAL_BIND(_body_add_shape, "body", "shape", "transform", "disabled");
+ GDVIRTUAL_BIND(_body_set_shape, "body", "shape_idx", "shape");
+ GDVIRTUAL_BIND(_body_set_shape_transform, "body", "shape_idx", "transform");
+
+ GDVIRTUAL_BIND(_body_get_shape_count, "body");
+ GDVIRTUAL_BIND(_body_get_shape, "body", "shape_idx");
+ GDVIRTUAL_BIND(_body_get_shape_transform, "body", "shape_idx");
+
+ GDVIRTUAL_BIND(_body_remove_shape, "body", "shape_idx");
+ GDVIRTUAL_BIND(_body_clear_shapes, "body");
+
+ GDVIRTUAL_BIND(_body_set_shape_disabled, "body", "shape_idx", "disabled");
+ GDVIRTUAL_BIND(_body_set_shape_as_one_way_collision, "body", "shape_idx", "enable", "margin");
+
+ GDVIRTUAL_BIND(_body_attach_object_instance_id, "body", "id");
+ GDVIRTUAL_BIND(_body_get_object_instance_id, "body");
+
+ GDVIRTUAL_BIND(_body_attach_canvas_instance_id, "body", "id");
+ GDVIRTUAL_BIND(_body_get_canvas_instance_id, "body");
+
+ GDVIRTUAL_BIND(_body_set_continuous_collision_detection_mode, "body", "mode");
+ GDVIRTUAL_BIND(_body_get_continuous_collision_detection_mode, "body");
+
+ GDVIRTUAL_BIND(_body_set_collision_layer, "body", "layer");
+ GDVIRTUAL_BIND(_body_get_collision_layer, "body");
+
+ GDVIRTUAL_BIND(_body_set_collision_mask, "body", "mask");
+ GDVIRTUAL_BIND(_body_get_collision_mask, "body");
+
+ GDVIRTUAL_BIND(_body_set_collision_priority, "body", "priority");
+ GDVIRTUAL_BIND(_body_get_collision_priority, "body");
+
+ GDVIRTUAL_BIND(_body_set_param, "body", "param", "value");
+ GDVIRTUAL_BIND(_body_get_param, "body", "param");
+
+ GDVIRTUAL_BIND(_body_reset_mass_properties, "body");
+
+ GDVIRTUAL_BIND(_body_set_state, "body", "state", "value");
+ GDVIRTUAL_BIND(_body_get_state, "body", "state");
+
+ GDVIRTUAL_BIND(_body_apply_central_impulse, "body", "impulse");
+ GDVIRTUAL_BIND(_body_apply_torque_impulse, "body", "impulse");
+ GDVIRTUAL_BIND(_body_apply_impulse, "body", "impulse", "position");
+
+ GDVIRTUAL_BIND(_body_apply_central_force, "body", "force");
+ GDVIRTUAL_BIND(_body_apply_force, "body", "force", "position");
+ GDVIRTUAL_BIND(_body_apply_torque, "body", "torque");
+
+ GDVIRTUAL_BIND(_body_add_constant_central_force, "body", "force");
+ GDVIRTUAL_BIND(_body_add_constant_force, "body", "force", "position");
+ GDVIRTUAL_BIND(_body_add_constant_torque, "body", "torque");
+
+ GDVIRTUAL_BIND(_body_set_constant_force, "body", "force");
+ GDVIRTUAL_BIND(_body_get_constant_force, "body");
+
+ GDVIRTUAL_BIND(_body_set_constant_torque, "body", "torque");
+ GDVIRTUAL_BIND(_body_get_constant_torque, "body");
+
+ GDVIRTUAL_BIND(_body_set_axis_velocity, "body", "axis_velocity");
+
+ GDVIRTUAL_BIND(_body_add_collision_exception, "body", "excepted_body");
+ GDVIRTUAL_BIND(_body_remove_collision_exception, "body", "excepted_body");
+
+ GDVIRTUAL_BIND(_body_set_max_contacts_reported, "body", "amount");
+ GDVIRTUAL_BIND(_body_get_max_contacts_reported, "body");
+
+ GDVIRTUAL_BIND(_body_set_omit_force_integration, "body", "enable");
+ GDVIRTUAL_BIND(_body_is_omitting_force_integration, "body");
+
+ GDVIRTUAL_BIND(_body_set_force_integration_callback, "body", "callable", "userdata");
+
+ GDVIRTUAL_BIND(_body_test_motion, "body", "from", "motion", "margin", "collide_separation_ray", "recovery_as_collision", "result");
+
+ GDVIRTUAL_BIND(_body_get_direct_state, "body");
+
+ GDVIRTUAL_BIND(_joint_create);
+ GDVIRTUAL_BIND(_joint_clear, "joint");
+
+ GDVIRTUAL_BIND(_joint_set_param, "joint", "param", "value");
+ GDVIRTUAL_BIND(_joint_get_param, "joint", "param");
+
+ GDVIRTUAL_BIND(_joint_make_pin, "joint", "anchor", "body_a", "body_b");
+ GDVIRTUAL_BIND(_joint_make_groove, "joint", "a_groove1", "a_groove2", "b_anchor", "body_a", "body_b");
+ GDVIRTUAL_BIND(_joint_make_damped_spring, "joint", "anchor_a", "anchor_b", "body_a", "body_b");
+
+ GDVIRTUAL_BIND(_pin_joint_set_param, "joint", "param", "value");
+ GDVIRTUAL_BIND(_pin_joint_get_param, "joint", "param");
+
+ GDVIRTUAL_BIND(_damped_spring_joint_set_param, "joint", "param", "value");
+ GDVIRTUAL_BIND(_damped_spring_joint_get_param, "joint", "param");
+
+ GDVIRTUAL_BIND(_joint_get_type, "joint");
+
+ GDVIRTUAL_BIND(_free_rid, "rid");
+
+ GDVIRTUAL_BIND(_set_active, "active");
+
+ GDVIRTUAL_BIND(_get_process_info, "process_info");
+}
+
+PhysicsServer2DExtension::PhysicsServer2DExtension() {
+}
+
+PhysicsServer2DExtension::~PhysicsServer2DExtension() {
+}
diff --git a/servers/extensions/physics_server_2d_extension.h b/servers/extensions/physics_server_2d_extension.h
new file mode 100644
index 0000000000..4c83664b14
--- /dev/null
+++ b/servers/extensions/physics_server_2d_extension.h
@@ -0,0 +1,462 @@
+/*************************************************************************/
+/* physics_server_2d_extension.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PHYSICS_SERVER_2D_EXTENSION_H
+#define PHYSICS_SERVER_2D_EXTENSION_H
+
+#include "core/extension/ext_wrappers.gen.inc"
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language.h"
+#include "core/variant/native_ptr.h"
+#include "core/variant/type_info.h"
+#include "core/variant/typed_array.h"
+#include "servers/physics_server_2d.h"
+
+class PhysicsDirectBodyState2DExtension : public PhysicsDirectBodyState2D {
+ GDCLASS(PhysicsDirectBodyState2DExtension, PhysicsDirectBodyState2D);
+
+protected:
+ static void _bind_methods();
+
+public:
+ // The warning is valid, but unavoidable. If the function is not overridden it will error anyway.
+
+ EXBIND0RC(Vector2, get_total_gravity)
+ EXBIND0RC(real_t, get_total_angular_damp)
+ EXBIND0RC(real_t, get_total_linear_damp)
+
+ EXBIND0RC(Vector2, get_center_of_mass)
+ EXBIND0RC(Vector2, get_center_of_mass_local)
+ EXBIND0RC(real_t, get_inverse_mass)
+ EXBIND0RC(real_t, get_inverse_inertia)
+
+ EXBIND1(set_linear_velocity, const Vector2 &)
+ EXBIND0RC(Vector2, get_linear_velocity)
+
+ EXBIND1(set_angular_velocity, real_t)
+ EXBIND0RC(real_t, get_angular_velocity)
+
+ EXBIND1(set_transform, const Transform2D &)
+ EXBIND0RC(Transform2D, get_transform)
+
+ EXBIND1RC(Vector2, get_velocity_at_local_position, const Vector2 &)
+
+ EXBIND1(apply_central_impulse, const Vector2 &)
+ EXBIND1(apply_torque_impulse, real_t)
+ EXBIND2(apply_impulse, const Vector2 &, const Vector2 &)
+
+ EXBIND1(apply_central_force, const Vector2 &)
+ EXBIND2(apply_force, const Vector2 &, const Vector2 &)
+ EXBIND1(apply_torque, real_t)
+
+ EXBIND1(add_constant_central_force, const Vector2 &)
+ EXBIND2(add_constant_force, const Vector2 &, const Vector2 &)
+ EXBIND1(add_constant_torque, real_t)
+
+ EXBIND1(set_constant_force, const Vector2 &)
+ EXBIND0RC(Vector2, get_constant_force)
+
+ EXBIND1(set_constant_torque, real_t)
+ EXBIND0RC(real_t, get_constant_torque)
+
+ EXBIND1(set_sleep_state, bool)
+ EXBIND0RC(bool, is_sleeping)
+
+ EXBIND0RC(int, get_contact_count)
+
+ EXBIND1RC(Vector2, get_contact_local_position, int)
+ EXBIND1RC(Vector2, get_contact_local_normal, int)
+ EXBIND1RC(int, get_contact_local_shape, int)
+
+ EXBIND1RC(RID, get_contact_collider, int)
+ EXBIND1RC(Vector2, get_contact_collider_position, int)
+ EXBIND1RC(ObjectID, get_contact_collider_id, int)
+ EXBIND1RC(Object *, get_contact_collider_object, int)
+ EXBIND1RC(int, get_contact_collider_shape, int)
+ EXBIND1RC(Vector2, get_contact_collider_velocity_at_position, int)
+
+ EXBIND0RC(real_t, get_step)
+ EXBIND0(integrate_forces)
+
+ EXBIND0R(PhysicsDirectSpaceState2D *, get_space_state)
+
+ PhysicsDirectBodyState2DExtension();
+};
+
+typedef PhysicsDirectSpaceState2D::RayResult PhysicsServer2DExtensionRayResult;
+typedef PhysicsDirectSpaceState2D::ShapeResult PhysicsServer2DExtensionShapeResult;
+typedef PhysicsDirectSpaceState2D::ShapeRestInfo PhysicsServer2DExtensionShapeRestInfo;
+
+GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionRayResult)
+GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionShapeResult)
+GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionShapeRestInfo)
+
+class PhysicsDirectSpaceState2DExtension : public PhysicsDirectSpaceState2D {
+ GDCLASS(PhysicsDirectSpaceState2DExtension, PhysicsDirectSpaceState2D);
+
+ thread_local static const HashSet<RID> *exclude;
+
+protected:
+ static void _bind_methods();
+ bool is_body_excluded_from_query(const RID &p_body) const;
+
+ GDVIRTUAL7R(bool, _intersect_ray, const Vector2 &, const Vector2 &, uint32_t, bool, bool, bool, GDNativePtr<PhysicsServer2DExtensionRayResult>)
+ GDVIRTUAL7R(int, _intersect_point, const Vector2 &, ObjectID, uint32_t, bool, bool, GDNativePtr<PhysicsServer2DExtensionShapeResult>, int)
+ GDVIRTUAL9R(int, _intersect_shape, RID, const Transform2D &, const Vector2 &, real_t, uint32_t, bool, bool, GDNativePtr<PhysicsServer2DExtensionShapeResult>, int)
+ GDVIRTUAL9R(bool, _cast_motion, RID, const Transform2D &, const Vector2 &, real_t, uint32_t, bool, bool, GDNativePtr<real_t>, GDNativePtr<real_t>)
+ GDVIRTUAL10R(bool, _collide_shape, RID, const Transform2D &, const Vector2 &, real_t, uint32_t, bool, bool, GDNativePtr<Vector2>, int, GDNativePtr<int>)
+ GDVIRTUAL8R(bool, _rest_info, RID, const Transform2D &, const Vector2 &, real_t, uint32_t, bool, bool, GDNativePtr<PhysicsServer2DExtensionShapeRestInfo>)
+
+public:
+ virtual bool intersect_ray(const RayParameters &p_parameters, RayResult &r_result) override {
+ exclude = &p_parameters.exclude;
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_intersect_ray, p_parameters.from, p_parameters.to, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, p_parameters.hit_from_inside, &r_result, ret);
+ exclude = nullptr;
+ return ret;
+ }
+ virtual int intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) override {
+ exclude = &p_parameters.exclude;
+ int ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_intersect_point, p_parameters.position, p_parameters.canvas_instance_id, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, r_results, p_result_max, ret);
+ exclude = nullptr;
+ return ret;
+ }
+ virtual int intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) override {
+ exclude = &p_parameters.exclude;
+ int ret = 0;
+ GDVIRTUAL_REQUIRED_CALL(_intersect_shape, p_parameters.shape_rid, p_parameters.transform, p_parameters.motion, p_parameters.margin, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, r_results, p_result_max, ret);
+ exclude = nullptr;
+ return ret;
+ }
+ virtual bool cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe) override {
+ exclude = &p_parameters.exclude;
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_cast_motion, p_parameters.shape_rid, p_parameters.transform, p_parameters.motion, p_parameters.margin, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, &p_closest_safe, &p_closest_unsafe, ret);
+ exclude = nullptr;
+ return ret;
+ }
+ virtual bool collide_shape(const ShapeParameters &p_parameters, Vector2 *r_results, int p_result_max, int &r_result_count) override {
+ exclude = &p_parameters.exclude;
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_collide_shape, p_parameters.shape_rid, p_parameters.transform, p_parameters.motion, p_parameters.margin, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, r_results, p_result_max, &r_result_count, ret);
+ exclude = nullptr;
+ return ret;
+ }
+ virtual bool rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) override {
+ exclude = &p_parameters.exclude;
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_rest_info, p_parameters.shape_rid, p_parameters.transform, p_parameters.motion, p_parameters.margin, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, r_info, ret);
+ exclude = nullptr;
+ return ret;
+ }
+
+ PhysicsDirectSpaceState2DExtension();
+};
+
+typedef PhysicsServer2D::MotionResult PhysicsServer2DExtensionMotionResult;
+
+struct PhysicsServer2DExtensionStateCallback {
+ void *instance = nullptr;
+ void (*callback)(void *p_instance, PhysicsDirectBodyState2D *p_state);
+};
+
+GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionMotionResult)
+GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionStateCallback)
+
+class PhysicsServer2DExtension : public PhysicsServer2D {
+ GDCLASS(PhysicsServer2DExtension, PhysicsServer2D);
+
+protected:
+ static void _bind_methods();
+
+ GDVIRTUAL9R(bool, _shape_collide, RID, const Transform2D &, const Vector2 &, RID, const Transform2D &, const Vector2 &, GDNativePtr<Vector2>, int, GDNativePtr<int>)
+
+ GDVIRTUAL8R(bool, _body_collide_shape, RID, int, RID, const Transform2D &, const Vector2 &, GDNativePtr<Vector2>, int, GDNativePtr<int>)
+
+public:
+ // The warning is valid, but unavoidable. If the function is not overridden it will error anyway.
+
+ EXBIND0R(RID, world_boundary_shape_create)
+ EXBIND0R(RID, separation_ray_shape_create)
+ EXBIND0R(RID, segment_shape_create)
+ EXBIND0R(RID, circle_shape_create)
+ EXBIND0R(RID, rectangle_shape_create)
+ EXBIND0R(RID, capsule_shape_create)
+ EXBIND0R(RID, convex_polygon_shape_create)
+ EXBIND0R(RID, concave_polygon_shape_create)
+
+ EXBIND2(shape_set_data, RID, const Variant &)
+ EXBIND2(shape_set_custom_solver_bias, RID, real_t)
+
+ EXBIND1RC(ShapeType, shape_get_type, RID)
+ EXBIND1RC(Variant, shape_get_data, RID)
+ EXBIND1RC(real_t, shape_get_custom_solver_bias, RID)
+
+ virtual bool shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) override {
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_shape_collide, p_shape_A, p_xform_A, p_motion_A, p_shape_B, p_xform_B, p_motion_B, r_results, p_result_max, &r_result_count, ret);
+ return ret;
+ }
+
+ /* SPACE API */
+
+ EXBIND0R(RID, space_create)
+ EXBIND2(space_set_active, RID, bool)
+ EXBIND1RC(bool, space_is_active, RID)
+
+ EXBIND3(space_set_param, RID, SpaceParameter, real_t)
+ EXBIND2RC(real_t, space_get_param, RID, SpaceParameter)
+
+ EXBIND1R(PhysicsDirectSpaceState2D *, space_get_direct_state, RID)
+
+ EXBIND2(space_set_debug_contacts, RID, int)
+ EXBIND1RC(Vector<Vector2>, space_get_contacts, RID)
+ EXBIND1RC(int, space_get_contact_count, RID)
+
+ /* AREA API */
+
+ //EXBIND0RID(area);
+ EXBIND0R(RID, area_create)
+
+ EXBIND2(area_set_space, RID, RID)
+ EXBIND1RC(RID, area_get_space, RID)
+
+ EXBIND4(area_add_shape, RID, RID, const Transform2D &, bool)
+ EXBIND3(area_set_shape, RID, int, RID)
+ EXBIND3(area_set_shape_transform, RID, int, const Transform2D &)
+
+ EXBIND1RC(int, area_get_shape_count, RID)
+ EXBIND2RC(RID, area_get_shape, RID, int)
+ EXBIND2RC(Transform2D, area_get_shape_transform, RID, int)
+
+ EXBIND2(area_remove_shape, RID, int)
+ EXBIND1(area_clear_shapes, RID)
+
+ EXBIND3(area_set_shape_disabled, RID, int, bool)
+
+ EXBIND2(area_attach_object_instance_id, RID, ObjectID)
+ EXBIND1RC(ObjectID, area_get_object_instance_id, RID)
+
+ EXBIND2(area_attach_canvas_instance_id, RID, ObjectID)
+ EXBIND1RC(ObjectID, area_get_canvas_instance_id, RID)
+
+ EXBIND3(area_set_param, RID, AreaParameter, const Variant &)
+ EXBIND2(area_set_transform, RID, const Transform2D &)
+
+ EXBIND2RC(Variant, area_get_param, RID, AreaParameter)
+ EXBIND1RC(Transform2D, area_get_transform, RID)
+
+ EXBIND2(area_set_collision_mask, RID, uint32_t)
+ EXBIND2(area_set_collision_layer, RID, uint32_t)
+
+ EXBIND2(area_set_monitorable, RID, bool)
+ EXBIND2(area_set_pickable, RID, bool)
+
+ EXBIND2(area_set_monitor_callback, RID, const Callable &)
+ EXBIND2(area_set_area_monitor_callback, RID, const Callable &)
+
+ /* BODY API */
+
+ //EXBIND2RID(body,BodyMode,bool);
+ EXBIND0R(RID, body_create)
+
+ EXBIND2(body_set_space, RID, RID)
+ EXBIND1RC(RID, body_get_space, RID)
+
+ EXBIND2(body_set_mode, RID, BodyMode)
+ EXBIND1RC(BodyMode, body_get_mode, RID)
+
+ EXBIND4(body_add_shape, RID, RID, const Transform2D &, bool)
+ EXBIND3(body_set_shape, RID, int, RID)
+ EXBIND3(body_set_shape_transform, RID, int, const Transform2D &)
+
+ EXBIND1RC(int, body_get_shape_count, RID)
+ EXBIND2RC(RID, body_get_shape, RID, int)
+ EXBIND2RC(Transform2D, body_get_shape_transform, RID, int)
+
+ EXBIND3(body_set_shape_disabled, RID, int, bool)
+ EXBIND4(body_set_shape_as_one_way_collision, RID, int, bool, real_t)
+
+ EXBIND2(body_remove_shape, RID, int)
+ EXBIND1(body_clear_shapes, RID)
+
+ EXBIND2(body_attach_object_instance_id, RID, ObjectID)
+ EXBIND1RC(ObjectID, body_get_object_instance_id, RID)
+
+ EXBIND2(body_attach_canvas_instance_id, RID, ObjectID)
+ EXBIND1RC(ObjectID, body_get_canvas_instance_id, RID)
+
+ EXBIND2(body_set_continuous_collision_detection_mode, RID, CCDMode)
+ EXBIND1RC(CCDMode, body_get_continuous_collision_detection_mode, RID)
+
+ EXBIND2(body_set_collision_layer, RID, uint32_t)
+ EXBIND1RC(uint32_t, body_get_collision_layer, RID)
+
+ EXBIND2(body_set_collision_mask, RID, uint32_t)
+ EXBIND1RC(uint32_t, body_get_collision_mask, RID)
+
+ EXBIND2(body_set_collision_priority, RID, real_t)
+ EXBIND1RC(real_t, body_get_collision_priority, RID)
+
+ EXBIND3(body_set_param, RID, BodyParameter, const Variant &)
+ EXBIND2RC(Variant, body_get_param, RID, BodyParameter)
+
+ EXBIND1(body_reset_mass_properties, RID)
+
+ EXBIND3(body_set_state, RID, BodyState, const Variant &)
+ EXBIND2RC(Variant, body_get_state, RID, BodyState)
+
+ EXBIND2(body_apply_central_impulse, RID, const Vector2 &)
+ EXBIND2(body_apply_torque_impulse, RID, real_t)
+ EXBIND3(body_apply_impulse, RID, const Vector2 &, const Vector2 &)
+
+ EXBIND2(body_apply_central_force, RID, const Vector2 &)
+ EXBIND3(body_apply_force, RID, const Vector2 &, const Vector2 &)
+ EXBIND2(body_apply_torque, RID, real_t)
+
+ EXBIND2(body_add_constant_central_force, RID, const Vector2 &)
+ EXBIND3(body_add_constant_force, RID, const Vector2 &, const Vector2 &)
+ EXBIND2(body_add_constant_torque, RID, real_t)
+
+ EXBIND2(body_set_constant_force, RID, const Vector2 &)
+ EXBIND1RC(Vector2, body_get_constant_force, RID)
+
+ EXBIND2(body_set_constant_torque, RID, real_t)
+ EXBIND1RC(real_t, body_get_constant_torque, RID)
+
+ EXBIND2(body_set_axis_velocity, RID, const Vector2 &)
+
+ EXBIND2(body_add_collision_exception, RID, RID)
+ EXBIND2(body_remove_collision_exception, RID, RID)
+ GDVIRTUAL1RC(TypedArray<RID>, _body_get_collision_exceptions, RID)
+
+ void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override {
+ TypedArray<RID> ret;
+ GDVIRTUAL_REQUIRED_CALL(_body_get_collision_exceptions, p_body, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ p_exceptions->push_back(ret[i]);
+ }
+ }
+
+ EXBIND2(body_set_max_contacts_reported, RID, int)
+ EXBIND1RC(int, body_get_max_contacts_reported, RID)
+
+ EXBIND2(body_set_contacts_reported_depth_threshold, RID, real_t)
+ EXBIND1RC(real_t, body_get_contacts_reported_depth_threshold, RID)
+
+ EXBIND2(body_set_omit_force_integration, RID, bool)
+ EXBIND1RC(bool, body_is_omitting_force_integration, RID)
+
+ GDVIRTUAL2(_body_set_state_sync_callback, RID, GDNativePtr<PhysicsServer2DExtensionStateCallback>)
+ void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override {
+ PhysicsServer2DExtensionStateCallback callback;
+ callback.callback = p_callback;
+ callback.instance = p_instance;
+ GDVIRTUAL_REQUIRED_CALL(_body_set_state_sync_callback, p_body, &callback);
+ }
+ EXBIND3(body_set_force_integration_callback, RID, const Callable &, const Variant &)
+
+ virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override {
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_body_collide_shape, p_body, p_body_shape, p_shape, p_shape_xform, p_motion, r_results, p_result_max, &r_result_count, ret);
+ return ret;
+ }
+
+ EXBIND2(body_set_pickable, RID, bool)
+
+ EXBIND1R(PhysicsDirectBodyState2D *, body_get_direct_state, RID)
+
+ GDVIRTUAL7RC(bool, _body_test_motion, RID, const Transform2D &, const Vector2 &, real_t, bool, bool, GDNativePtr<PhysicsServer2DExtensionMotionResult>)
+
+ thread_local static const HashSet<RID> *exclude_bodies;
+ thread_local static const HashSet<ObjectID> *exclude_objects;
+
+ bool body_test_motion_is_excluding_body(RID p_body) const;
+ bool body_test_motion_is_excluding_object(ObjectID p_object) const;
+
+ bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override {
+ bool ret = false;
+ exclude_bodies = &p_parameters.exclude_bodies;
+ exclude_objects = &p_parameters.exclude_objects;
+ GDVIRTUAL_REQUIRED_CALL(_body_test_motion, p_body, p_parameters.from, p_parameters.motion, p_parameters.margin, p_parameters.collide_separation_ray, p_parameters.recovery_as_collision, r_result, ret);
+ exclude_bodies = nullptr;
+ exclude_objects = nullptr;
+ return ret;
+ }
+
+ /* JOINT API */
+
+ EXBIND0R(RID, joint_create)
+
+ EXBIND1(joint_clear, RID)
+
+ EXBIND3(joint_set_param, RID, JointParam, real_t)
+ EXBIND2RC(real_t, joint_get_param, RID, JointParam)
+
+ EXBIND2(joint_disable_collisions_between_bodies, RID, bool)
+ EXBIND1RC(bool, joint_is_disabled_collisions_between_bodies, RID)
+
+ EXBIND4(joint_make_pin, RID, const Vector2 &, RID, RID)
+ EXBIND6(joint_make_groove, RID, const Vector2 &, const Vector2 &, const Vector2 &, RID, RID)
+ EXBIND5(joint_make_damped_spring, RID, const Vector2 &, const Vector2 &, RID, RID)
+
+ EXBIND3(pin_joint_set_param, RID, PinJointParam, real_t)
+ EXBIND2RC(real_t, pin_joint_get_param, RID, PinJointParam)
+
+ EXBIND3(damped_spring_joint_set_param, RID, DampedSpringParam, real_t)
+ EXBIND2RC(real_t, damped_spring_joint_get_param, RID, DampedSpringParam)
+
+ EXBIND1RC(JointType, joint_get_type, RID)
+
+ /* MISC */
+
+ GDVIRTUAL1(_free_rid, RID)
+ virtual void free(RID p_rid) override {
+ GDVIRTUAL_REQUIRED_CALL(_free_rid, p_rid);
+ }
+
+ EXBIND1(set_active, bool)
+
+ EXBIND0(init)
+ EXBIND1(step, real_t)
+ EXBIND0(sync)
+ EXBIND0(flush_queries)
+ EXBIND0(end_sync)
+ EXBIND0(finish)
+
+ EXBIND0RC(bool, is_flushing_queries)
+ EXBIND1R(int, get_process_info, ProcessInfo)
+
+ PhysicsServer2DExtension();
+ ~PhysicsServer2DExtension();
+};
+
+#endif // PHYSICS_SERVER_2D_EXTENSION_H
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index 6424915b58..528ac18f88 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -850,6 +850,8 @@ void PhysicsServer2D::_bind_methods() {
BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_BIAS);
BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_FORCE);
+ BIND_ENUM_CONSTANT(PIN_JOINT_SOFTNESS);
+
BIND_ENUM_CONSTANT(DAMPED_SPRING_REST_LENGTH);
BIND_ENUM_CONSTANT(DAMPED_SPRING_STIFFNESS);
BIND_ENUM_CONSTANT(DAMPED_SPRING_DAMPING);
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index f7c44533bf..f1e05e7a46 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -820,6 +820,7 @@ VARIANT_ENUM_CAST(PhysicsServer2D::BodyState);
VARIANT_ENUM_CAST(PhysicsServer2D::CCDMode);
VARIANT_ENUM_CAST(PhysicsServer2D::JointParam);
VARIANT_ENUM_CAST(PhysicsServer2D::JointType);
+VARIANT_ENUM_CAST(PhysicsServer2D::PinJointParam);
VARIANT_ENUM_CAST(PhysicsServer2D::DampedSpringParam);
VARIANT_ENUM_CAST(PhysicsServer2D::AreaBodyStatus);
VARIANT_ENUM_CAST(PhysicsServer2D::ProcessInfo);
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index db473f6296..2e794683b9 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -72,6 +72,7 @@
#include "rendering/rendering_device.h"
#include "rendering/rendering_device_binds.h"
#include "rendering_server.h"
+#include "servers/extensions/physics_server_2d_extension.h"
#include "servers/extensions/physics_server_3d_extension.h"
#include "servers/rendering/shader_types.h"
#include "text/text_server_dummy.h"
@@ -133,6 +134,16 @@ void register_server_types() {
GDREGISTER_CLASS(AudioServer);
GDREGISTER_ABSTRACT_CLASS(PhysicsServer2D);
+ GDREGISTER_VIRTUAL_CLASS(PhysicsServer2DExtension);
+ GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState2DExtension);
+ GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState2DExtension);
+
+ GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionRayResult, "Vector2 position;Vector2 normal;RID rid;ObjectID collider_id;Object *collider;int shape");
+ GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeResult, "RID rid;ObjectID collider_id;Object *collider;int shape");
+ GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeRestInfo, "Vector2 point;Vector2 normal;RID rid;ObjectID collider_id;int shape;Vector2 linear_velocity");
+ GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionMotionResult, "Vector2 travel;Vector2 remainder;Vector2 collision_point;Vector2 collision_normal;Vector2 collider_velocity;real_t collision_depth;real_t collision_safe_fraction;real_t collision_unsafe_fraction;int collision_local_shape;ObjectID collider_id;RID collider;int collider_shape");
+ GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionStateCallback, "void *instance;void (*callback)(void *p_instance, PhysicsDirectBodyState2D *p_state)");
+
GDREGISTER_ABSTRACT_CLASS(PhysicsServer3D);
GDREGISTER_VIRTUAL_CLASS(PhysicsServer3DExtension);
GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState3DExtension);
diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h
index 1eb4fd854f..336049852d 100644
--- a/servers/rendering/dummy/storage/mesh_storage.h
+++ b/servers/rendering/dummy/storage/mesh_storage.h
@@ -81,6 +81,7 @@ public:
s->vertex_count = p_surface.vertex_count;
s->index_data = p_surface.index_data;
s->index_count = p_surface.index_count;
+ s->skin_data = p_surface.skin_data;
}
virtual int mesh_get_blend_shape_count(RID p_mesh) const override { return 0; }