summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/camera_2d.cpp78
-rw-r--r--scene/2d/camera_2d.h6
-rw-r--r--scene/2d/navigation_agent_2d.cpp162
-rw-r--r--scene/2d/navigation_agent_2d.h31
-rw-r--r--scene/3d/bone_attachment_3d.cpp5
-rw-r--r--scene/3d/navigation_agent_3d.cpp180
-rw-r--r--scene/3d/navigation_agent_3d.h30
-rw-r--r--scene/animation/animation_blend_space_1d.cpp180
-rw-r--r--scene/animation/animation_blend_space_1d.h17
-rw-r--r--scene/animation/animation_tree.cpp2
-rw-r--r--scene/gui/control.cpp6
-rw-r--r--scene/gui/control.h3
-rw-r--r--scene/main/canvas_item.cpp17
-rw-r--r--scene/main/canvas_item.h3
-rw-r--r--scene/main/viewport.cpp30
-rw-r--r--scene/main/viewport.h1
-rw-r--r--scene/main/window.cpp18
-rw-r--r--scene/main/window.h2
-rw-r--r--scene/resources/world_2d.cpp22
-rw-r--r--scene/resources/world_2d.h2
-rw-r--r--scene/resources/world_3d.cpp24
-rw-r--r--scene/resources/world_3d.h2
22 files changed, 686 insertions, 135 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 71b8fdb539..49c5501e77 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -50,7 +50,7 @@ void Camera2D::_update_scroll() {
return;
}
- if (current) {
+ if (is_current()) {
ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id));
Transform2D xform = get_camera_transform();
@@ -241,10 +241,6 @@ void Camera2D::_notification(int p_what) {
viewport = get_viewport();
}
- if (is_current()) {
- viewport->_camera_2d_set(this);
- }
-
canvas = get_canvas();
RID vp = viewport->get_viewport_rid();
@@ -254,6 +250,10 @@ void Camera2D::_notification(int p_what) {
add_to_group(group_name);
add_to_group(canvas_group_name);
+ if (enabled && !viewport->get_camera_2d()) {
+ make_current();
+ }
+
_update_process_callback();
first = true;
_update_scroll();
@@ -261,11 +261,7 @@ void Camera2D::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
if (is_current()) {
- if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
- viewport->set_canvas_transform(Transform2D());
- clear_current();
- current = true;
- }
+ clear_current();
}
remove_from_group(group_name);
remove_from_group(canvas_group_name);
@@ -397,19 +393,31 @@ void Camera2D::set_process_callback(Camera2DProcessCallback p_mode) {
_update_process_callback();
}
+void Camera2D::set_enabled(bool p_enabled) {
+ enabled = p_enabled;
+
+ if (enabled && is_inside_tree() && !viewport->get_camera_2d()) {
+ make_current();
+ } else if (!enabled && is_current()) {
+ clear_current();
+ }
+}
+
+bool Camera2D::is_enabled() const {
+ return enabled;
+}
+
Camera2D::Camera2DProcessCallback Camera2D::get_process_callback() const {
return process_callback;
}
void Camera2D::_make_current(Object *p_which) {
if (p_which == this) {
- current = true;
if (is_inside_tree()) {
get_viewport()->_camera_2d_set(this);
queue_redraw();
}
} else {
- current = false;
if (is_inside_tree()) {
if (get_viewport()->get_camera_2d() == this) {
get_viewport()->_camera_2d_set(nullptr);
@@ -419,43 +427,32 @@ void Camera2D::_make_current(Object *p_which) {
}
}
-void Camera2D::set_current(bool p_current) {
- if (p_current) {
- make_current();
- } else {
- if (current) {
- clear_current();
- }
- }
-}
-
void Camera2D::_update_process_internal_for_smoothing() {
bool is_not_in_scene_or_editor = !(is_inside_tree() && Engine::get_singleton()->is_editor_hint());
bool is_any_smoothing_valid = position_smoothing_speed > 0 || rotation_smoothing_speed > 0;
- bool enabled = is_any_smoothing_valid && is_not_in_scene_or_editor;
- set_process_internal(enabled);
-}
-
-bool Camera2D::is_current() const {
- return current;
+ bool enable = is_any_smoothing_valid && is_not_in_scene_or_editor;
+ set_process_internal(enable);
}
void Camera2D::make_current() {
- if (is_inside_tree()) {
- get_tree()->call_group(group_name, "_make_current", this);
- } else {
- current = true;
- }
+ ERR_FAIL_COND(!enabled || !is_inside_tree());
+ get_tree()->call_group(group_name, "_make_current", this);
_update_scroll();
}
void Camera2D::clear_current() {
- if (is_inside_tree()) {
- get_tree()->call_group(group_name, "_make_current", (Object *)nullptr);
- } else {
- current = false;
+ ERR_FAIL_COND(!is_current());
+ if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
+ viewport->assign_next_enabled_camera_2d(group_name);
+ }
+}
+
+bool Camera2D::is_current() const {
+ if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
+ return viewport->get_camera_2d() == this;
}
+ return false;
}
void Camera2D::set_limit(Side p_side, int p_limit) {
@@ -715,7 +712,10 @@ void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_process_callback", "mode"), &Camera2D::set_process_callback);
ClassDB::bind_method(D_METHOD("get_process_callback"), &Camera2D::get_process_callback);
- ClassDB::bind_method(D_METHOD("set_current", "current"), &Camera2D::set_current);
+ ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &Camera2D::set_enabled);
+ ClassDB::bind_method(D_METHOD("is_enabled"), &Camera2D::is_enabled);
+
+ ClassDB::bind_method(D_METHOD("make_current"), &Camera2D::make_current);
ClassDB::bind_method(D_METHOD("is_current"), &Camera2D::is_current);
ClassDB::bind_method(D_METHOD("_make_current"), &Camera2D::_make_current);
@@ -779,7 +779,7 @@ void Camera2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_mode", PROPERTY_HINT_ENUM, "Fixed TopLeft,Drag Center"), "set_anchor_mode", "get_anchor_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_rotation"), "set_ignore_rotation", "is_ignoring_rotation");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom", PROPERTY_HINT_LINK), "set_zoom", "get_zoom");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport");
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback");
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 304b4ceaa6..7a77266db8 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -64,7 +64,7 @@ protected:
Vector2 zoom_scale = Vector2(1, 1);
AnchorMode anchor_mode = ANCHOR_MODE_DRAG_CENTER;
bool ignore_rotation = true;
- bool current = false;
+ bool enabled = true;
real_t position_smoothing_speed = 5.0;
bool follow_smoothing_enabled = false;
@@ -88,7 +88,6 @@ protected:
void _update_scroll();
void _make_current(Object *p_which);
- void set_current(bool p_current);
void _set_old_smoothing(real_t p_enable);
@@ -155,6 +154,9 @@ public:
void set_process_callback(Camera2DProcessCallback p_mode);
Camera2DProcessCallback get_process_callback() const;
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const;
+
void make_current();
void clear_current();
bool is_current() const;
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index e73b6e7e23..380a684c9b 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -108,6 +108,26 @@ void NavigationAgent2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.1,10,0.01,suffix:s"), "set_time_horizon", "get_time_horizon");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:px/s"), "set_max_speed", "get_max_speed");
+#ifdef DEBUG_ENABLED
+ ClassDB::bind_method(D_METHOD("set_debug_enabled", "enabled"), &NavigationAgent2D::set_debug_enabled);
+ ClassDB::bind_method(D_METHOD("get_debug_enabled"), &NavigationAgent2D::get_debug_enabled);
+ ClassDB::bind_method(D_METHOD("set_debug_use_custom", "enabled"), &NavigationAgent2D::set_debug_use_custom);
+ ClassDB::bind_method(D_METHOD("get_debug_use_custom"), &NavigationAgent2D::get_debug_use_custom);
+ ClassDB::bind_method(D_METHOD("set_debug_path_custom_color", "color"), &NavigationAgent2D::set_debug_path_custom_color);
+ ClassDB::bind_method(D_METHOD("get_debug_path_custom_color"), &NavigationAgent2D::get_debug_path_custom_color);
+ ClassDB::bind_method(D_METHOD("set_debug_path_custom_point_size", "point_size"), &NavigationAgent2D::set_debug_path_custom_point_size);
+ ClassDB::bind_method(D_METHOD("get_debug_path_custom_point_size"), &NavigationAgent2D::get_debug_path_custom_point_size);
+ ClassDB::bind_method(D_METHOD("set_debug_path_custom_line_width", "line_width"), &NavigationAgent2D::set_debug_path_custom_line_width);
+ ClassDB::bind_method(D_METHOD("get_debug_path_custom_line_width"), &NavigationAgent2D::get_debug_path_custom_line_width);
+
+ ADD_GROUP("Debug", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_enabled"), "set_debug_enabled", "get_debug_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_use_custom"), "set_debug_use_custom", "get_debug_use_custom");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_path_custom_color"), "set_debug_path_custom_color", "get_debug_path_custom_color");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "debug_path_custom_point_size", PROPERTY_HINT_RANGE, "1,50,1,suffix:px"), "set_debug_path_custom_point_size", "get_debug_path_custom_point_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "debug_path_custom_line_width", PROPERTY_HINT_RANGE, "1,50,1,suffix:px"), "set_debug_path_custom_line_width", "get_debug_path_custom_line_width");
+#endif // DEBUG_ENABLED
+
ADD_SIGNAL(MethodInfo("path_changed"));
ADD_SIGNAL(MethodInfo("target_reached"));
ADD_SIGNAL(MethodInfo("waypoint_reached", PropertyInfo(Variant::DICTIONARY, "details")));
@@ -123,6 +143,12 @@ void NavigationAgent2D::_notification(int p_what) {
// cannot use READY as ready does not get called if Node is readded to SceneTree
set_agent_parent(get_parent());
set_physics_process_internal(true);
+
+#ifdef DEBUG_ENABLED
+ if (NavigationServer2D::get_singleton()->get_debug_enabled()) {
+ debug_path_dirty = true;
+ }
+#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_PARENTED: {
@@ -165,6 +191,12 @@ void NavigationAgent2D::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
agent_parent = nullptr;
set_physics_process_internal(false);
+
+#ifdef DEBUG_ENABLED
+ if (debug_path_instance.is_valid()) {
+ RenderingServer::get_singleton()->canvas_item_set_visible(debug_path_instance, false);
+ }
+#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@@ -176,6 +208,12 @@ void NavigationAgent2D::_notification(int p_what) {
}
_check_distance_to_target();
}
+
+#ifdef DEBUG_ENABLED
+ if (debug_path_dirty) {
+ _update_debug_path();
+ }
+#endif // DEBUG_ENABLED
} break;
}
}
@@ -194,12 +232,25 @@ NavigationAgent2D::NavigationAgent2D() {
navigation_result = Ref<NavigationPathQueryResult2D>();
navigation_result.instantiate();
+
+#ifdef DEBUG_ENABLED
+ NavigationServer2D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent2D::_navigation_debug_changed));
+#endif // DEBUG_ENABLED
}
NavigationAgent2D::~NavigationAgent2D() {
ERR_FAIL_NULL(NavigationServer2D::get_singleton());
NavigationServer2D::get_singleton()->free(agent);
agent = RID(); // Pointless
+
+#ifdef DEBUG_ENABLED
+ NavigationServer2D::get_singleton()->disconnect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent2D::_navigation_debug_changed));
+
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ if (debug_path_instance.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_path_instance);
+ }
+#endif // DEBUG_ENABLED
}
void NavigationAgent2D::set_avoidance_enabled(bool p_enabled) {
@@ -463,6 +514,9 @@ void NavigationAgent2D::update_navigation() {
}
NavigationServer2D::get_singleton()->query_path(navigation_query, navigation_result);
+#ifdef DEBUG_ENABLED
+ debug_path_dirty = true;
+#endif // DEBUG_ENABLED
navigation_finished = false;
navigation_path_index = 0;
emit_signal(SNAME("path_changed"));
@@ -549,3 +603,111 @@ void NavigationAgent2D::_check_distance_to_target() {
}
}
}
+
+////////DEBUG////////////////////////////////////////////////////////////
+
+#ifdef DEBUG_ENABLED
+void NavigationAgent2D::set_debug_enabled(bool p_enabled) {
+ debug_enabled = p_enabled;
+ debug_path_dirty = true;
+}
+
+bool NavigationAgent2D::get_debug_enabled() const {
+ return debug_enabled;
+}
+
+void NavigationAgent2D::set_debug_use_custom(bool p_enabled) {
+ debug_use_custom = p_enabled;
+ debug_path_dirty = true;
+}
+
+bool NavigationAgent2D::get_debug_use_custom() const {
+ return debug_use_custom;
+}
+
+void NavigationAgent2D::set_debug_path_custom_color(Color p_color) {
+ debug_path_custom_color = p_color;
+ debug_path_dirty = true;
+}
+
+Color NavigationAgent2D::get_debug_path_custom_color() const {
+ return debug_path_custom_color;
+}
+
+void NavigationAgent2D::set_debug_path_custom_point_size(float p_point_size) {
+ debug_path_custom_point_size = MAX(0.1, p_point_size);
+ debug_path_dirty = true;
+}
+
+float NavigationAgent2D::get_debug_path_custom_point_size() const {
+ return debug_path_custom_point_size;
+}
+
+void NavigationAgent2D::set_debug_path_custom_line_width(float p_line_width) {
+ debug_path_custom_line_width = p_line_width;
+ debug_path_dirty = true;
+}
+
+float NavigationAgent2D::get_debug_path_custom_line_width() const {
+ return debug_path_custom_line_width;
+}
+
+void NavigationAgent2D::_navigation_debug_changed() {
+ debug_path_dirty = true;
+}
+
+void NavigationAgent2D::_update_debug_path() {
+ if (!debug_path_dirty) {
+ return;
+ }
+ debug_path_dirty = false;
+
+ if (!debug_path_instance.is_valid()) {
+ debug_path_instance = RenderingServer::get_singleton()->canvas_item_create();
+ }
+
+ RenderingServer::get_singleton()->canvas_item_clear(debug_path_instance);
+
+ if (!(debug_enabled && NavigationServer2D::get_singleton()->get_debug_navigation_enable_agent_paths())) {
+ return;
+ }
+
+ if (!(agent_parent && agent_parent->is_inside_tree())) {
+ return;
+ }
+
+ RenderingServer::get_singleton()->canvas_item_set_parent(debug_path_instance, agent_parent->get_canvas());
+ RenderingServer::get_singleton()->canvas_item_set_visible(debug_path_instance, agent_parent->is_visible_in_tree());
+
+ const Vector<Vector2> &navigation_path = navigation_result->get_path();
+
+ if (navigation_path.size() <= 1) {
+ return;
+ }
+
+ Color debug_path_color = NavigationServer2D::get_singleton()->get_debug_navigation_agent_path_color();
+ if (debug_use_custom) {
+ debug_path_color = debug_path_custom_color;
+ }
+
+ Vector<Color> debug_path_colors;
+ debug_path_colors.resize(navigation_path.size());
+ debug_path_colors.fill(debug_path_color);
+
+ RenderingServer::get_singleton()->canvas_item_add_polyline(debug_path_instance, navigation_path, debug_path_colors, debug_path_custom_line_width, false);
+
+ float point_size = NavigationServer2D::get_singleton()->get_debug_navigation_agent_path_point_size();
+ float half_point_size = point_size * 0.5;
+
+ if (debug_use_custom) {
+ point_size = debug_path_custom_point_size;
+ half_point_size = debug_path_custom_point_size * 0.5;
+ }
+
+ for (int i = 0; i < navigation_path.size(); i++) {
+ const Vector2 &vert = navigation_path[i];
+ Rect2 path_point_rect = Rect2(vert.x - half_point_size, vert.y - half_point_size, point_size, point_size);
+ RenderingServer::get_singleton()->canvas_item_add_rect(debug_path_instance, path_point_rect, debug_path_color);
+ }
+}
+#endif // DEBUG_ENABLED
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index 9787bb1bdb..8f4a373327 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -74,6 +74,20 @@ class NavigationAgent2D : public Node {
// No initialized on purpose
uint32_t update_frame_id = 0;
+#ifdef DEBUG_ENABLED
+ bool debug_enabled = false;
+ bool debug_path_dirty = true;
+ RID debug_path_instance;
+ float debug_path_custom_point_size = 4.0;
+ float debug_path_custom_line_width = 1.0;
+ bool debug_use_custom = false;
+ Color debug_path_custom_color = Color(1.0, 1.0, 1.0, 1.0);
+
+private:
+ void _navigation_debug_changed();
+ void _update_debug_path();
+#endif // DEBUG_ENABLED
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -169,6 +183,23 @@ public:
PackedStringArray get_configuration_warnings() const override;
+#ifdef DEBUG_ENABLED
+ void set_debug_enabled(bool p_enabled);
+ bool get_debug_enabled() const;
+
+ void set_debug_use_custom(bool p_enabled);
+ bool get_debug_use_custom() const;
+
+ void set_debug_path_custom_color(Color p_color);
+ Color get_debug_path_custom_color() const;
+
+ void set_debug_path_custom_point_size(float p_point_size);
+ float get_debug_path_custom_point_size() const;
+
+ void set_debug_path_custom_line_width(float p_line_width);
+ float get_debug_path_custom_line_width() const;
+#endif // DEBUG_ENABLED
+
private:
void update_navigation();
void _request_repath();
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index fe7f6837f0..ba5ff02862 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -81,11 +81,6 @@ bool BoneAttachment3D::_get(const StringName &p_path, Variant &r_ret) const {
}
void BoneAttachment3D::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::BOOL, "override_pose", PROPERTY_HINT_NONE, ""));
- if (override_pose) {
- p_list->push_back(PropertyInfo(Variant::INT, "override_mode", PROPERTY_HINT_ENUM, "Global Pose Override,Local Pose Override,Custom Pose"));
- }
-
p_list->push_back(PropertyInfo(Variant::BOOL, "use_external_skeleton", PROPERTY_HINT_NONE, ""));
if (use_external_skeleton) {
p_list->push_back(PropertyInfo(Variant::NODE_PATH, "external_skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"));
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 4aa6e61ec5..5db8611d72 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -120,6 +120,23 @@ void NavigationAgent3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("link_reached", PropertyInfo(Variant::DICTIONARY, "details")));
ADD_SIGNAL(MethodInfo("navigation_finished"));
ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR3, "safe_velocity")));
+
+#ifdef DEBUG_ENABLED
+ ClassDB::bind_method(D_METHOD("set_debug_enabled", "enabled"), &NavigationAgent3D::set_debug_enabled);
+ ClassDB::bind_method(D_METHOD("get_debug_enabled"), &NavigationAgent3D::get_debug_enabled);
+ ClassDB::bind_method(D_METHOD("set_debug_use_custom", "enabled"), &NavigationAgent3D::set_debug_use_custom);
+ ClassDB::bind_method(D_METHOD("get_debug_use_custom"), &NavigationAgent3D::get_debug_use_custom);
+ ClassDB::bind_method(D_METHOD("set_debug_path_custom_color", "color"), &NavigationAgent3D::set_debug_path_custom_color);
+ ClassDB::bind_method(D_METHOD("get_debug_path_custom_color"), &NavigationAgent3D::get_debug_path_custom_color);
+ ClassDB::bind_method(D_METHOD("set_debug_path_custom_point_size", "point_size"), &NavigationAgent3D::set_debug_path_custom_point_size);
+ ClassDB::bind_method(D_METHOD("get_debug_path_custom_point_size"), &NavigationAgent3D::get_debug_path_custom_point_size);
+
+ ADD_GROUP("Debug", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_enabled"), "set_debug_enabled", "get_debug_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_use_custom"), "set_debug_use_custom", "get_debug_use_custom");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_path_custom_color"), "set_debug_path_custom_color", "get_debug_path_custom_color");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "debug_path_custom_point_size", PROPERTY_HINT_RANGE, "1,50,1,suffix:px"), "set_debug_path_custom_point_size", "get_debug_path_custom_point_size");
+#endif // DEBUG_ENABLED
}
void NavigationAgent3D::_notification(int p_what) {
@@ -129,6 +146,12 @@ void NavigationAgent3D::_notification(int p_what) {
// cannot use READY as ready does not get called if Node is readded to SceneTree
set_agent_parent(get_parent());
set_physics_process_internal(true);
+
+#ifdef DEBUG_ENABLED
+ if (NavigationServer3D::get_singleton()->get_debug_enabled()) {
+ debug_path_dirty = true;
+ }
+#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_PARENTED: {
@@ -151,6 +174,12 @@ void NavigationAgent3D::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
set_agent_parent(nullptr);
set_physics_process_internal(false);
+
+#ifdef DEBUG_ENABLED
+ if (debug_path_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_path_instance, false);
+ }
+#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_PAUSED: {
@@ -182,6 +211,11 @@ void NavigationAgent3D::_notification(int p_what) {
}
_check_distance_to_target();
}
+#ifdef DEBUG_ENABLED
+ if (debug_path_dirty) {
+ _update_debug_path();
+ }
+#endif // DEBUG_ENABLED
} break;
}
}
@@ -201,12 +235,28 @@ NavigationAgent3D::NavigationAgent3D() {
navigation_result = Ref<NavigationPathQueryResult3D>();
navigation_result.instantiate();
+
+#ifdef DEBUG_ENABLED
+ NavigationServer3D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent3D::_navigation_debug_changed));
+#endif // DEBUG_ENABLED
}
NavigationAgent3D::~NavigationAgent3D() {
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
NavigationServer3D::get_singleton()->free(agent);
agent = RID(); // Pointless
+
+#ifdef DEBUG_ENABLED
+ NavigationServer3D::get_singleton()->disconnect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent3D::_navigation_debug_changed));
+
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ if (debug_path_instance.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_path_instance);
+ }
+ if (debug_path_mesh.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_path_mesh->get_rid());
+ }
+#endif // DEBUG_ENABLED
}
void NavigationAgent3D::set_avoidance_enabled(bool p_enabled) {
@@ -480,6 +530,9 @@ void NavigationAgent3D::update_navigation() {
}
NavigationServer3D::get_singleton()->query_path(navigation_query, navigation_result);
+#ifdef DEBUG_ENABLED
+ debug_path_dirty = true;
+#endif // DEBUG_ENABLED
navigation_finished = false;
navigation_path_index = 0;
emit_signal(SNAME("path_changed"));
@@ -566,3 +619,130 @@ void NavigationAgent3D::_check_distance_to_target() {
}
}
}
+
+////////DEBUG////////////////////////////////////////////////////////////
+
+#ifdef DEBUG_ENABLED
+void NavigationAgent3D::set_debug_enabled(bool p_enabled) {
+ debug_enabled = p_enabled;
+ debug_path_dirty = true;
+}
+
+bool NavigationAgent3D::get_debug_enabled() const {
+ return debug_enabled;
+}
+
+void NavigationAgent3D::set_debug_use_custom(bool p_enabled) {
+ debug_use_custom = p_enabled;
+ debug_path_dirty = true;
+}
+
+bool NavigationAgent3D::get_debug_use_custom() const {
+ return debug_use_custom;
+}
+
+void NavigationAgent3D::set_debug_path_custom_color(Color p_color) {
+ debug_path_custom_color = p_color;
+ debug_path_dirty = true;
+}
+
+Color NavigationAgent3D::get_debug_path_custom_color() const {
+ return debug_path_custom_color;
+}
+
+void NavigationAgent3D::set_debug_path_custom_point_size(float p_point_size) {
+ debug_path_custom_point_size = p_point_size;
+ debug_path_dirty = true;
+}
+
+float NavigationAgent3D::get_debug_path_custom_point_size() const {
+ return debug_path_custom_point_size;
+}
+
+void NavigationAgent3D::_navigation_debug_changed() {
+ debug_path_dirty = true;
+}
+
+void NavigationAgent3D::_update_debug_path() {
+ if (!debug_path_dirty) {
+ return;
+ }
+ debug_path_dirty = false;
+
+ if (!debug_path_instance.is_valid()) {
+ debug_path_instance = RenderingServer::get_singleton()->instance_create();
+ }
+
+ if (!debug_path_mesh.is_valid()) {
+ debug_path_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ }
+
+ debug_path_mesh->clear_surfaces();
+
+ if (!(debug_enabled && NavigationServer3D::get_singleton()->get_debug_navigation_enable_agent_paths())) {
+ return;
+ }
+
+ if (!(agent_parent && agent_parent->is_inside_tree())) {
+ return;
+ }
+
+ const Vector<Vector3> &navigation_path = navigation_result->get_path();
+
+ if (navigation_path.size() <= 1) {
+ return;
+ }
+
+ Vector<Vector3> debug_path_lines_vertex_array;
+
+ for (int i = 0; i < navigation_path.size() - 1; i++) {
+ debug_path_lines_vertex_array.push_back(navigation_path[i]);
+ debug_path_lines_vertex_array.push_back(navigation_path[i + 1]);
+ }
+
+ Array debug_path_lines_mesh_array;
+ debug_path_lines_mesh_array.resize(Mesh::ARRAY_MAX);
+ debug_path_lines_mesh_array[Mesh::ARRAY_VERTEX] = debug_path_lines_vertex_array;
+
+ debug_path_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, debug_path_lines_mesh_array);
+
+ Ref<StandardMaterial3D> debug_agent_path_line_material = NavigationServer3D::get_singleton()->get_debug_navigation_agent_path_line_material();
+ if (debug_use_custom) {
+ if (!debug_agent_path_line_custom_material.is_valid()) {
+ debug_agent_path_line_custom_material = debug_agent_path_line_material->duplicate();
+ }
+ debug_agent_path_line_custom_material->set_albedo(debug_path_custom_color);
+ debug_path_mesh->surface_set_material(0, debug_agent_path_line_custom_material);
+ } else {
+ debug_path_mesh->surface_set_material(0, debug_agent_path_line_material);
+ }
+
+ Vector<Vector3> debug_path_points_vertex_array;
+
+ for (int i = 0; i < navigation_path.size(); i++) {
+ debug_path_points_vertex_array.push_back(navigation_path[i]);
+ }
+
+ Array debug_path_points_mesh_array;
+ debug_path_points_mesh_array.resize(Mesh::ARRAY_MAX);
+ debug_path_points_mesh_array[Mesh::ARRAY_VERTEX] = debug_path_lines_vertex_array;
+
+ debug_path_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, debug_path_points_mesh_array);
+
+ Ref<StandardMaterial3D> debug_agent_path_point_material = NavigationServer3D::get_singleton()->get_debug_navigation_agent_path_point_material();
+ if (debug_use_custom) {
+ if (!debug_agent_path_point_custom_material.is_valid()) {
+ debug_agent_path_point_custom_material = debug_agent_path_point_material->duplicate();
+ }
+ debug_agent_path_point_custom_material->set_albedo(debug_path_custom_color);
+ debug_agent_path_point_custom_material->set_point_size(debug_path_custom_point_size);
+ debug_path_mesh->surface_set_material(1, debug_agent_path_point_custom_material);
+ } else {
+ debug_path_mesh->surface_set_material(1, debug_agent_path_point_material);
+ }
+
+ RS::get_singleton()->instance_set_base(debug_path_instance, debug_path_mesh->get_rid());
+ RS::get_singleton()->instance_set_scenario(debug_path_instance, agent_parent->get_world_3d()->get_scenario());
+ RS::get_singleton()->instance_set_visible(debug_path_instance, agent_parent->is_visible_in_tree());
+}
+#endif // DEBUG_ENABLED
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index 12f83ce6a8..98bf395d7c 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -76,6 +76,22 @@ class NavigationAgent3D : public Node {
// No initialized on purpose
uint32_t update_frame_id = 0;
+#ifdef DEBUG_ENABLED
+ bool debug_enabled = false;
+ bool debug_path_dirty = true;
+ RID debug_path_instance;
+ Ref<ArrayMesh> debug_path_mesh;
+ float debug_path_custom_point_size = 4.0;
+ bool debug_use_custom = false;
+ Color debug_path_custom_color = Color(1.0, 1.0, 1.0, 1.0);
+ Ref<StandardMaterial3D> debug_agent_path_line_custom_material;
+ Ref<StandardMaterial3D> debug_agent_path_point_custom_material;
+
+private:
+ void _navigation_debug_changed();
+ void _update_debug_path();
+#endif // DEBUG_ENABLED
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -181,6 +197,20 @@ public:
PackedStringArray get_configuration_warnings() const override;
+#ifdef DEBUG_ENABLED
+ void set_debug_enabled(bool p_enabled);
+ bool get_debug_enabled() const;
+
+ void set_debug_use_custom(bool p_enabled);
+ bool get_debug_use_custom() const;
+
+ void set_debug_path_custom_color(Color p_color);
+ Color get_debug_path_custom_color() const;
+
+ void set_debug_path_custom_point_size(float p_point_size);
+ float get_debug_path_custom_point_size() const;
+#endif // DEBUG_ENABLED
+
private:
void update_navigation();
void _request_repath();
diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp
index a2028b8de8..d28a6fcc04 100644
--- a/scene/animation/animation_blend_space_1d.cpp
+++ b/scene/animation/animation_blend_space_1d.cpp
@@ -30,12 +30,20 @@
#include "animation_blend_space_1d.h"
+#include "animation_blend_tree.h"
+
void AnimationNodeBlendSpace1D::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_position));
+ r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
+ r_list->push_back(PropertyInfo(Variant::FLOAT, length_internal, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
}
Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName &p_parameter) const {
- return 0;
+ if (p_parameter == closest) {
+ return -1;
+ } else {
+ return 0;
+ }
}
Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) {
@@ -77,6 +85,9 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_value_label", "text"), &AnimationNodeBlendSpace1D::set_value_label);
ClassDB::bind_method(D_METHOD("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label);
+ ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &AnimationNodeBlendSpace1D::set_blend_mode);
+ ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace1D::get_blend_mode);
+
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace1D::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace1D::is_using_sync);
@@ -91,7 +102,12 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_space", "get_max_space");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_value_label", "get_value_label");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NO_EDITOR), "set_blend_mode", "get_blend_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_sync", "is_using_sync");
+
+ BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED);
+ BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE);
+ BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE_CARRY);
}
void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
@@ -214,6 +230,14 @@ String AnimationNodeBlendSpace1D::get_value_label() const {
return value_label;
}
+void AnimationNodeBlendSpace1D::set_blend_mode(BlendMode p_blend_mode) {
+ blend_mode = p_blend_mode;
+}
+
+AnimationNodeBlendSpace1D::BlendMode AnimationNodeBlendSpace1D::get_blend_mode() const {
+ return blend_mode;
+}
+
void AnimationNodeBlendSpace1D::set_use_sync(bool p_sync) {
sync = p_sync;
}
@@ -241,79 +265,125 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_is_
}
double blend_pos = get_parameter(blend_position);
+ int cur_closest = get_parameter(closest);
+ double cur_length_internal = get_parameter(length_internal);
+ double max_time_remaining = 0.0;
- float weights[MAX_BLEND_POINTS] = {};
+ if (blend_mode == BLEND_MODE_INTERPOLATED) {
+ float weights[MAX_BLEND_POINTS] = {};
+
+ int point_lower = -1;
+ float pos_lower = 0.0;
+ int point_higher = -1;
+ float pos_higher = 0.0;
+
+ // find the closest two points to blend between
+ for (int i = 0; i < blend_points_used; i++) {
+ float pos = blend_points[i].position;
+
+ if (pos <= blend_pos) {
+ if (point_lower == -1) {
+ point_lower = i;
+ pos_lower = pos;
+ } else if ((blend_pos - pos) < (blend_pos - pos_lower)) {
+ point_lower = i;
+ pos_lower = pos;
+ }
+ } else {
+ if (point_higher == -1) {
+ point_higher = i;
+ pos_higher = pos;
+ } else if ((pos - blend_pos) < (pos_higher - blend_pos)) {
+ point_higher = i;
+ pos_higher = pos;
+ }
+ }
+ }
- int point_lower = -1;
- float pos_lower = 0.0;
- int point_higher = -1;
- float pos_higher = 0.0;
+ // fill in weights
- // find the closest two points to blend between
- for (int i = 0; i < blend_points_used; i++) {
- float pos = blend_points[i].position;
-
- if (pos <= blend_pos) {
- if (point_lower == -1) {
- point_lower = i;
- pos_lower = pos;
- } else if ((blend_pos - pos) < (blend_pos - pos_lower)) {
- point_lower = i;
- pos_lower = pos;
- }
+ if (point_lower == -1 && point_higher != -1) {
+ // we are on the left side, no other point to the left
+ // we just play the next point.
+
+ weights[point_higher] = 1.0;
+ } else if (point_higher == -1) {
+ // we are on the right side, no other point to the right
+ // we just play the previous point
+
+ weights[point_lower] = 1.0;
} else {
- if (point_higher == -1) {
- point_higher = i;
- pos_higher = pos;
- } else if ((pos - blend_pos) < (pos_higher - blend_pos)) {
- point_higher = i;
- pos_higher = pos;
- }
- }
- }
+ // we are between two points.
+ // figure out weights, then blend the animations
- // fill in weights
+ float distance_between_points = pos_higher - pos_lower;
- if (point_lower == -1 && point_higher != -1) {
- // we are on the left side, no other point to the left
- // we just play the next point.
+ float current_pos_inbetween = blend_pos - pos_lower;
- weights[point_higher] = 1.0;
- } else if (point_higher == -1) {
- // we are on the right side, no other point to the right
- // we just play the previous point
+ float blend_percentage = current_pos_inbetween / distance_between_points;
- weights[point_lower] = 1.0;
- } else {
- // we are between two points.
- // figure out weights, then blend the animations
+ float blend_lower = 1.0 - blend_percentage;
+ float blend_higher = blend_percentage;
- float distance_between_points = pos_higher - pos_lower;
+ weights[point_lower] = blend_lower;
+ weights[point_higher] = blend_higher;
+ }
- float current_pos_inbetween = blend_pos - pos_lower;
+ // actually blend the animations now
- float blend_percentage = current_pos_inbetween / distance_between_points;
+ for (int i = 0; i < blend_points_used; i++) {
+ if (i == point_lower || i == point_higher) {
+ double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true);
+ max_time_remaining = MAX(max_time_remaining, remaining);
+ } else if (sync) {
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
+ }
+ }
+ } else {
+ int new_closest = -1;
+ double new_closest_dist = 1e20;
+
+ for (int i = 0; i < blend_points_used; i++) {
+ double d = abs(blend_points[i].position - blend_pos);
+ if (d < new_closest_dist) {
+ new_closest = i;
+ new_closest_dist = d;
+ }
+ }
- float blend_lower = 1.0 - blend_percentage;
- float blend_higher = blend_percentage;
+ if (new_closest != cur_closest && new_closest != -1) {
+ double from = 0.0;
+ if (blend_mode == BLEND_MODE_DISCRETE_CARRY && cur_closest != -1) {
+ //for ping-pong loop
+ Ref<AnimationNodeAnimation> na_c = static_cast<Ref<AnimationNodeAnimation>>(blend_points[cur_closest].node);
+ Ref<AnimationNodeAnimation> na_n = static_cast<Ref<AnimationNodeAnimation>>(blend_points[new_closest].node);
+ if (!na_c.is_null() && !na_n.is_null()) {
+ na_n->set_backward(na_c->is_backward());
+ }
+ //see how much animation remains
+ from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_is_external_seeking, 0.0, FILTER_IGNORE, true);
+ }
- weights[point_lower] = blend_lower;
- weights[point_higher] = blend_higher;
- }
+ max_time_remaining = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
+ cur_length_internal = from + max_time_remaining;
- // actually blend the animations now
+ cur_closest = new_closest;
- double max_time_remaining = 0.0;
+ } else {
+ max_time_remaining = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
+ }
- for (int i = 0; i < blend_points_used; i++) {
- if (i == point_lower || i == point_higher) {
- double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true);
- max_time_remaining = MAX(max_time_remaining, remaining);
- } else if (sync) {
- blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
+ if (sync) {
+ for (int i = 0; i < blend_points_used; i++) {
+ if (i != cur_closest) {
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
+ }
+ }
}
}
+ set_parameter(this->closest, cur_closest);
+ set_parameter(this->length_internal, cur_length_internal);
return max_time_remaining;
}
diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h
index af93783c0d..a1e9a7a764 100644
--- a/scene/animation/animation_blend_space_1d.h
+++ b/scene/animation/animation_blend_space_1d.h
@@ -36,6 +36,14 @@
class AnimationNodeBlendSpace1D : public AnimationRootNode {
GDCLASS(AnimationNodeBlendSpace1D, AnimationRootNode);
+public:
+ enum BlendMode {
+ BLEND_MODE_INTERPOLATED,
+ BLEND_MODE_DISCRETE,
+ BLEND_MODE_DISCRETE_CARRY,
+ };
+
+protected:
enum {
MAX_BLEND_POINTS = 64
};
@@ -61,6 +69,10 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
void _tree_changed();
StringName blend_position = "blend_position";
+ StringName closest = "closest";
+ StringName length_internal = "length_internal";
+
+ BlendMode blend_mode = BLEND_MODE_INTERPOLATED;
protected:
bool sync = false;
@@ -95,6 +107,9 @@ public:
void set_value_label(const String &p_label);
String get_value_label() const;
+ void set_blend_mode(BlendMode p_blend_mode);
+ BlendMode get_blend_mode() const;
+
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -107,4 +122,6 @@ public:
~AnimationNodeBlendSpace1D();
};
+VARIANT_ENUM_CAST(AnimationNodeBlendSpace1D::BlendMode)
+
#endif // ANIMATION_BLEND_SPACE_1D_H
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 1c1f94c986..fa72bbc593 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -1861,6 +1861,8 @@ void AnimationTree::_setup_animation_player() {
return;
}
+ cache_valid = false;
+
AnimationPlayer *new_player = nullptr;
if (!animation_player.is_empty()) {
new_player = Object::cast_to<AnimationPlayer>(get_node_or_null(animation_player));
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index f7c056316d..6f5e2cf058 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -692,6 +692,12 @@ Transform2D Control::get_transform() const {
return xform;
}
+void Control::_toplevel_changed_on_parent() {
+ // Update root control status.
+ _notification(NOTIFICATION_EXIT_CANVAS);
+ _notification(NOTIFICATION_ENTER_CANVAS);
+}
+
/// Anchors and offsets.
void Control::_set_anchor(Side p_side, real_t p_anchor) {
diff --git a/scene/gui/control.h b/scene/gui/control.h
index a93a88e5b4..5977f4dbea 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -292,6 +292,9 @@ private:
void _update_minimum_size();
void _size_changed();
+ void _toplevel_changed() override{}; // Controls don't need to do anything, only other CanvasItems.
+ void _toplevel_changed_on_parent() override;
+
void _clear_size_warning();
// Input events.
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 35176f0edd..cde3503bdf 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -400,11 +400,28 @@ void CanvasItem::set_as_top_level(bool p_top_level) {
_exit_canvas();
top_level = p_top_level;
+ _toplevel_changed();
_enter_canvas();
_notify_transform();
}
+void CanvasItem::_toplevel_changed() {
+ // Inform children that toplevel status has changed on a parent.
+ int childs = get_child_count();
+ for (int i = 0; i < childs; i++) {
+ CanvasItem *child = Object::cast_to<CanvasItem>(get_child(i));
+ if (child) {
+ child->_toplevel_changed_on_parent();
+ }
+ }
+}
+
+void CanvasItem::_toplevel_changed_on_parent() {
+ // Inform children that toplevel status has changed on a parent.
+ _toplevel_changed();
+}
+
bool CanvasItem::is_set_as_top_level() const {
return top_level;
}
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 1c84ea338a..1ddfaa288c 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -125,6 +125,9 @@ private:
void _propagate_visibility_changed(bool p_parent_visible_in_tree);
void _handle_visibility_change(bool p_visible);
+ virtual void _toplevel_changed();
+ virtual void _toplevel_changed_on_parent();
+
void _redraw_callback();
void _enter_canvas();
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 48cff5aa8e..b6bcbe04a3 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1045,6 +1045,25 @@ Transform2D Viewport::get_final_transform() const {
return _get_input_pre_xform().affine_inverse() * stretch_transform * global_canvas_transform;
}
+void Viewport::assign_next_enabled_camera_2d(const StringName &p_camera_group) {
+ List<Node *> camera_list;
+ get_tree()->get_nodes_in_group(p_camera_group, &camera_list);
+
+ Camera2D *new_camera = nullptr;
+ for (const Node *E : camera_list) {
+ const Camera2D *cam = Object::cast_to<Camera2D>(E);
+ if (cam->is_enabled()) {
+ new_camera = const_cast<Camera2D *>(cam);
+ break;
+ }
+ }
+
+ _camera_2d_set(new_camera);
+ if (!camera_2d) {
+ set_canvas_transform(Transform2D());
+ }
+}
+
void Viewport::_update_canvas_items(Node *p_node) {
if (p_node != this) {
Window *w = Object::cast_to<Window>(p_node);
@@ -1110,14 +1129,11 @@ Viewport::PositionalShadowAtlasQuadrantSubdiv Viewport::get_positional_shadow_at
}
Transform2D Viewport::_get_input_pre_xform() const {
- Transform2D pre_xf;
-
- if (to_screen_rect.size.x != 0 && to_screen_rect.size.y != 0) {
- pre_xf.columns[2] = -to_screen_rect.position;
- pre_xf.scale(Vector2(size) / to_screen_rect.size);
+ const Window *this_window = Object::cast_to<Window>(this);
+ if (this_window) {
+ return this_window->window_transform.affine_inverse();
}
-
- return pre_xf;
+ return Transform2D();
}
Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index d5d5201e9a..e081013fde 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -511,6 +511,7 @@ public:
Transform2D get_global_canvas_transform() const;
Transform2D get_final_transform() const;
+ void assign_next_enabled_camera_2d(const StringName &p_camera_group);
void gui_set_root_order_dirty();
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 869d12b4df..b1f2bc65dc 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -907,6 +907,7 @@ void Window::_update_viewport_size() {
Rect2i attach_to_screen_rect(Point2i(), size);
Transform2D stretch_transform_new;
float font_oversampling = 1.0;
+ window_transform = Transform2D();
if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) {
font_oversampling = content_scale_factor;
@@ -993,11 +994,18 @@ void Window::_update_viewport_size() {
Size2 scale = Vector2(screen_size) / Vector2(final_size_override);
stretch_transform_new.scale(scale);
+ window_transform.translate_local(margin);
} break;
case CONTENT_SCALE_MODE_VIEWPORT: {
final_size = (viewport_size / content_scale_factor).floor();
attach_to_screen_rect = Rect2(margin, screen_size);
+ window_transform.translate_local(margin);
+ if (final_size.x != 0 && final_size.y != 0) {
+ Transform2D scale_transform;
+ scale_transform.scale(Vector2(attach_to_screen_rect.size) / Vector2(final_size));
+ window_transform *= scale_transform;
+ }
} break;
}
}
@@ -2127,13 +2135,13 @@ Transform2D Window::get_popup_base_transform() const {
if (is_embedding_subwindows()) {
return Transform2D();
}
- Transform2D window_transform;
- window_transform.set_origin(get_position());
- window_transform *= Viewport::get_screen_transform();
+ Transform2D popup_base_transform;
+ popup_base_transform.set_origin(get_position());
+ popup_base_transform *= Viewport::get_screen_transform();
if (_get_embedder()) {
- return _get_embedder()->get_popup_base_transform() * window_transform;
+ return _get_embedder()->get_popup_base_transform() * popup_base_transform;
}
- return window_transform;
+ return popup_base_transform;
}
void Window::_bind_methods() {
diff --git a/scene/main/window.h b/scene/main/window.h
index 182caf5f0c..1730de0b33 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -173,6 +173,8 @@ private:
Viewport *embedder = nullptr;
+ Transform2D window_transform;
+
friend class Viewport; //friend back, can call the methods below
void _window_input(const Ref<InputEvent> &p_ev);
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index 2a70139bcb..c7304da358 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -43,6 +43,14 @@ RID World2D::get_canvas() const {
}
RID World2D::get_space() const {
+ if (space.is_null()) {
+ space = PhysicsServer2D::get_singleton()->space_create();
+ PhysicsServer2D::get_singleton()->space_set_active(space, true);
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_GET("physics/2d/default_gravity"));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_GET("physics/2d/default_gravity_vector"));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_LINEAR_DAMP, GLOBAL_GET("physics/2d/default_linear_damp"));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_GET("physics/2d/default_angular_damp"));
+ }
return space;
}
@@ -71,19 +79,11 @@ void World2D::_bind_methods() {
}
PhysicsDirectSpaceState2D *World2D::get_direct_space_state() {
- return PhysicsServer2D::get_singleton()->space_get_direct_state(space);
+ return PhysicsServer2D::get_singleton()->space_get_direct_state(get_space());
}
World2D::World2D() {
canvas = RenderingServer::get_singleton()->canvas_create();
-
- // Create and configure space2D to be more friendly with pixels than meters
- space = PhysicsServer2D::get_singleton()->space_create();
- PhysicsServer2D::get_singleton()->space_set_active(space, true);
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF_BASIC("physics/2d/default_gravity", 980.0));
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF_BASIC("physics/2d/default_gravity_vector", Vector2(0, 1)));
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/2d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), 0.1));
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/2d/default_angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), 1.0));
}
World2D::~World2D() {
@@ -91,7 +91,9 @@ World2D::~World2D() {
ERR_FAIL_NULL(PhysicsServer2D::get_singleton());
ERR_FAIL_NULL(NavigationServer2D::get_singleton());
RenderingServer::get_singleton()->free(canvas);
- PhysicsServer2D::get_singleton()->free(space);
+ if (space.is_valid()) {
+ PhysicsServer2D::get_singleton()->free(space);
+ }
if (navigation_map.is_valid()) {
NavigationServer2D::get_singleton()->free(navigation_map);
}
diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h
index f02dddd2fe..0b3b9df7dc 100644
--- a/scene/resources/world_2d.h
+++ b/scene/resources/world_2d.h
@@ -43,7 +43,7 @@ class World2D : public Resource {
GDCLASS(World2D, Resource);
RID canvas;
- RID space;
+ mutable RID space;
mutable RID navigation_map;
HashSet<Viewport *> viewports;
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index cc4d261c0d..82c056d5ee 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -51,6 +51,14 @@ void World3D::_remove_camera(Camera3D *p_camera) {
}
RID World3D::get_space() const {
+ if (space.is_null()) {
+ space = PhysicsServer3D::get_singleton()->space_create();
+ PhysicsServer3D::get_singleton()->space_set_active(space, true);
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_GET("physics/3d/default_gravity"));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_GET("physics/3d/default_gravity_vector"));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, GLOBAL_GET("physics/3d/default_linear_damp"));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_GET("physics/3d/default_angular_damp"));
+ }
return space;
}
@@ -121,7 +129,7 @@ Ref<CameraAttributes> World3D::get_camera_attributes() const {
}
PhysicsDirectSpaceState3D *World3D::get_direct_space_state() {
- return PhysicsServer3D::get_singleton()->space_get_direct_state(space);
+ return PhysicsServer3D::get_singleton()->space_get_direct_state(get_space());
}
void World3D::_bind_methods() {
@@ -145,22 +153,18 @@ void World3D::_bind_methods() {
}
World3D::World3D() {
- space = PhysicsServer3D::get_singleton()->space_create();
scenario = RenderingServer::get_singleton()->scenario_create();
-
- PhysicsServer3D::get_singleton()->space_set_active(space, true);
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_DEF_BASIC("physics/3d/default_gravity", 9.8));
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF_BASIC("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/default_linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), 0.1));
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/default_angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), 0.1));
}
World3D::~World3D() {
- ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
ERR_FAIL_NULL(RenderingServer::get_singleton());
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
- PhysicsServer3D::get_singleton()->free(space);
+
RenderingServer::get_singleton()->free(scenario);
+ if (space.is_valid()) {
+ PhysicsServer3D::get_singleton()->free(space);
+ }
if (navigation_map.is_valid()) {
NavigationServer3D::get_singleton()->free(navigation_map);
}
diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h
index ad17daf466..518fff64e2 100644
--- a/scene/resources/world_3d.h
+++ b/scene/resources/world_3d.h
@@ -45,8 +45,8 @@ class World3D : public Resource {
GDCLASS(World3D, Resource);
private:
- RID space;
RID scenario;
+ mutable RID space;
mutable RID navigation_map;
Ref<Environment> environment;