summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/audio_stream_player_2d.cpp3
-rw-r--r--scene/2d/navigation_region_2d.cpp4
-rw-r--r--scene/2d/node_2d.cpp12
-rw-r--r--scene/2d/node_2d.h1
-rw-r--r--scene/2d/physics_body_2d.cpp18
-rw-r--r--scene/2d/physics_body_2d.h4
-rw-r--r--scene/2d/polygon_2d.cpp4
-rw-r--r--scene/2d/tile_map.cpp37
-rw-r--r--scene/2d/tile_map.h2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp3
-rw-r--r--scene/3d/collision_object_3d.cpp1
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp4
-rw-r--r--scene/3d/mesh_instance_3d.cpp6
-rw-r--r--scene/3d/physics_body_3d.cpp16
-rw-r--r--scene/3d/physics_body_3d.h4
-rw-r--r--scene/3d/soft_body_3d.cpp4
-rw-r--r--scene/3d/spring_arm_3d.cpp1
-rw-r--r--scene/animation/animation_blend_space_1d.cpp10
-rw-r--r--scene/animation/animation_blend_space_1d.h2
-rw-r--r--scene/animation/animation_blend_space_2d.cpp22
-rw-r--r--scene/animation/animation_blend_space_2d.h2
-rw-r--r--scene/animation/animation_blend_tree.cpp109
-rw-r--r--scene/animation/animation_blend_tree.h24
-rw-r--r--scene/animation/animation_node_state_machine.cpp22
-rw-r--r--scene/animation/animation_node_state_machine.h4
-rw-r--r--scene/animation/animation_player.cpp9
-rw-r--r--scene/animation/animation_tree.cpp245
-rw-r--r--scene/animation/animation_tree.h24
-rw-r--r--scene/animation/root_motion_view.cpp8
-rw-r--r--scene/gui/color_picker.cpp6
-rw-r--r--scene/gui/control.cpp2
-rw-r--r--scene/gui/dialogs.cpp2
-rw-r--r--scene/gui/graph_edit.cpp2
-rw-r--r--scene/gui/rich_text_label.cpp6
-rw-r--r--scene/gui/split_container.cpp3
-rw-r--r--scene/gui/subviewport_container.cpp12
-rw-r--r--scene/gui/subviewport_container.h3
-rw-r--r--scene/gui/tab_bar.cpp3
-rw-r--r--scene/gui/text_edit.cpp2
-rw-r--r--scene/gui/texture_button.cpp50
-rw-r--r--scene/gui/texture_button.h20
-rw-r--r--scene/main/canvas_layer.cpp2
-rw-r--r--scene/main/http_request.cpp49
-rw-r--r--scene/main/node.cpp14
-rw-r--r--scene/main/node.h1
-rw-r--r--scene/main/scene_tree.cpp23
-rw-r--r--scene/main/scene_tree.h2
-rw-r--r--scene/main/viewport.cpp4
-rw-r--r--scene/main/viewport.h4
-rw-r--r--scene/resources/animation.cpp279
-rw-r--r--scene/resources/animation.h26
-rw-r--r--scene/resources/bit_map.cpp101
-rw-r--r--scene/resources/camera_attributes.cpp4
-rw-r--r--scene/resources/curve.cpp245
-rw-r--r--scene/resources/curve.h7
-rw-r--r--scene/resources/default_theme/default_theme.cpp3
-rw-r--r--scene/resources/font.cpp12
-rw-r--r--scene/resources/importer_mesh.cpp4
-rw-r--r--scene/resources/importer_mesh.h2
-rw-r--r--scene/resources/label_settings.cpp6
-rw-r--r--scene/resources/mesh.cpp6
-rw-r--r--scene/resources/mesh.h9
-rw-r--r--scene/resources/primitive_meshes.cpp8
-rw-r--r--scene/resources/tile_set.cpp1
-rw-r--r--scene/scene_string_names.cpp2
-rw-r--r--scene/scene_string_names.h2
66 files changed, 660 insertions, 872 deletions
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 9ac3083718..2ded209180 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -284,6 +284,9 @@ bool AudioStreamPlayer2D::is_playing() const {
return true;
}
}
+ if (setplay.get() >= 0) {
+ return true; // play() has been called this frame, but no playback exists just yet.
+ }
return false;
}
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 6e8ecb13b1..13d371042b 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -296,7 +296,9 @@ void NavigationPolygon::make_polygons_from_outlines() {
TPPLPartition tpart;
if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
- ERR_PRINT("NavigationPolygon: Convex partition failed!");
+ ERR_PRINT("NavigationPolygon: Convex partition failed! Failed to convert outlines to a valid NavigationMesh."
+ "\nNavigationPolygon outlines can not overlap vertices or edges inside same outline or with other outlines or have any intersections."
+ "\nAdd the outmost and largest outline first. To add holes inside this outline add the smaller outlines with opposite winding order.");
return;
}
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 2518069b78..84bfc48a43 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -30,6 +30,8 @@
#include "node_2d.h"
+#include "scene/main/viewport.h"
+
#ifdef TOOLS_ENABLED
Dictionary Node2D::_edit_get_state() const {
Dictionary state;
@@ -389,6 +391,16 @@ bool Node2D::is_y_sort_enabled() const {
return y_sort_enabled;
}
+void Node2D::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_MOVED_IN_PARENT: {
+ if (get_viewport()) {
+ get_viewport()->gui_set_root_order_dirty();
+ }
+ } break;
+ }
+}
+
void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_position", "position"), &Node2D::set_position);
ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Node2D::set_rotation);
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index 0d8a31e6bb..04bbdf639d 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -53,6 +53,7 @@ class Node2D : public CanvasItem {
void _update_xform_values();
protected:
+ void _notification(int p_notification);
static void _bind_methods();
public:
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 0f3e6c7529..7f5b5d1ea4 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -34,8 +34,8 @@
#include "scene/scene_string_names.h"
void PhysicsBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "motion", "test_only", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "motion", "collision", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
@@ -54,8 +54,8 @@ PhysicsBody2D::~PhysicsBody2D() {
}
}
-Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_distance, bool p_test_only, real_t p_margin, bool p_recovery_as_collision) {
- PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_distance, p_margin);
+Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin, bool p_recovery_as_collision) {
+ PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_motion, p_margin);
parameters.recovery_as_collision = p_recovery_as_collision;
PhysicsServer2D::MotionResult result;
@@ -128,7 +128,7 @@ bool PhysicsBody2D::move_and_collide(const PhysicsServer2D::MotionParameters &p_
return colliding;
}
-bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision, real_t p_margin, bool p_recovery_as_collision) {
+bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision, real_t p_margin, bool p_recovery_as_collision) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer2D::MotionResult *r = nullptr;
@@ -140,7 +140,7 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distan
r = &temp_result;
}
- PhysicsServer2D::MotionParameters parameters(p_from, p_distance, p_margin);
+ PhysicsServer2D::MotionParameters parameters(p_from, p_motion, p_margin);
parameters.recovery_as_collision = p_recovery_as_collision;
return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r);
@@ -162,14 +162,14 @@ TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {
void PhysicsBody2D::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node);
- ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two objects of PhysicsBody2D type.");
+ ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two nodes that inherit from PhysicsBody2D.");
PhysicsServer2D::get_singleton()->body_add_collision_exception(get_rid(), physics_body->get_rid());
}
void PhysicsBody2D::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node);
- ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two objects of PhysicsBody2D type.");
+ ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two nodes that inherit from PhysicsBody2D.");
PhysicsServer2D::get_singleton()->body_remove_collision_exception(get_rid(), physics_body->get_rid());
}
@@ -1761,7 +1761,7 @@ void CharacterBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater,suffix:px"), "set_floor_snap_length", "get_floor_snap_length");
- ADD_GROUP("Moving Platform", "platform");
+ ADD_GROUP("Moving Platform", "platform_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_on_leave", PROPERTY_HINT_ENUM, "Add Velocity,Add Upward Velocity,Do Nothing", PROPERTY_USAGE_DEFAULT), "set_platform_on_leave", "get_platform_on_leave");
ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_floor_layers", "get_platform_floor_layers");
ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_wall_layers", "get_platform_wall_layers");
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 932ec1de16..504e1dc333 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -47,11 +47,11 @@ protected:
Ref<KinematicCollision2D> motion_cache;
- Ref<KinematicCollision2D> _move(const Vector2 &p_distance, bool p_test_only = false, real_t p_margin = 0.08, bool p_recovery_as_collision = false);
+ Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_test_only = false, real_t p_margin = 0.08, bool p_recovery_as_collision = false);
public:
bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true);
- bool test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08, bool p_recovery_as_collision = false);
+ bool test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08, bool p_recovery_as_collision = false);
TypedArray<PhysicsBody2D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 5e77902977..e41664b006 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -114,7 +114,7 @@ void Polygon2D::_notification(int p_what) {
ObjectID new_skeleton_id;
- if (skeleton_node) {
+ if (skeleton_node && !invert && bone_weights.size()) {
RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton());
new_skeleton_id = skeleton_node->get_instance_id();
} else {
@@ -663,5 +663,7 @@ Polygon2D::Polygon2D() {
}
Polygon2D::~Polygon2D() {
+ // This will free the internally-allocated mesh instance, if allocated.
+ RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID());
RS::get_singleton()->free(mesh);
}
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 40e8818262..0159e9f313 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1859,11 +1859,13 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
while (q_list_element) {
TileMapQuadrant &q = *q_list_element->self();
- // Clear the scenes.
- for (const KeyValue<Vector2i, String> &E : q.scenes) {
- Node *node = get_node_or_null(E.value);
- if (node) {
- node->queue_free();
+ // Clear the scenes if instance cache was cleared.
+ if (instantiated_scenes.is_empty()) {
+ for (const KeyValue<Vector2i, String> &E : q.scenes) {
+ Node *node = get_node_or_null(E.value);
+ if (node) {
+ node->queue_free();
+ }
}
}
@@ -1871,6 +1873,15 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
// Recreate the scenes.
for (const Vector2i &E_cell : q.cells) {
+ Vector3i cell_coords = Vector3i(q.layer, E_cell.x, E_cell.y);
+ if (instantiated_scenes.has(cell_coords)) {
+ // Skip scene if the instance was cached (to avoid recreating scenes unnecessarily).
+ continue;
+ }
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ instantiated_scenes.insert(cell_coords);
+ }
+
const TileMapCell &c = get_cell(q.layer, E_cell, true);
TileSetSource *source;
@@ -1907,15 +1918,16 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
}
void TileMap::_scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
- // Clear the scenes.
- for (const KeyValue<Vector2i, String> &E : p_quadrant->scenes) {
- Node *node = get_node_or_null(E.value);
- if (node) {
- node->queue_free();
+ // Clear the scenes if instance cache was cleared.
+ if (instantiated_scenes.is_empty()) {
+ for (const KeyValue<Vector2i, String> &E : p_quadrant->scenes) {
+ Node *node = get_node_or_null(E.value);
+ if (node) {
+ node->queue_free();
+ }
}
+ p_quadrant->scenes.clear();
}
-
- p_quadrant->scenes.clear();
}
void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
@@ -4037,6 +4049,7 @@ void TileMap::_bind_methods() {
void TileMap::_tile_set_changed() {
emit_signal(SNAME("changed"));
_tile_set_changed_deferred_update_needed = true;
+ instantiated_scenes.clear();
call_deferred(SNAME("_tile_set_changed_deferred_update"));
}
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index eaf100631e..68a5d3c80b 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -236,6 +236,8 @@ private:
void _clear_layer_internals(int p_layer);
void _clear_internals();
+ HashSet<Vector3i> instantiated_scenes;
+
// Rect caching.
void _recompute_rect_cache();
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index b9d95672fe..75e840c24b 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -606,6 +606,9 @@ bool AudioStreamPlayer3D::is_playing() const {
return true;
}
}
+ if (setplay.get() >= 0) {
+ return true; // play() has been called this frame, but no playback exists just yet.
+ }
return false;
}
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index ca23fe03a2..66546092f2 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -30,6 +30,7 @@
#include "collision_object_3d.h"
+#include "scene/resources/shape_3d.h"
#include "scene/scene_string_names.h"
void CollisionObject3D::_notification(int p_what) {
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index 2c5df48b75..476820b1c4 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -347,7 +347,9 @@ void GPUParticlesCollisionSDF3D::_compute_sdf(ComputeSDFParams *params) {
WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &GPUParticlesCollisionSDF3D::_compute_sdf_z, params, params->size.z);
while (!WorkerThreadPool::get_singleton()->is_group_task_completed(group_task)) {
OS::get_singleton()->delay_usec(10000);
- bake_step_function(WorkerThreadPool::get_singleton()->get_group_processed_element_count(group_task) * 100 / params->size.z, "Baking SDF");
+ if (bake_step_function) {
+ bake_step_function(WorkerThreadPool::get_singleton()->get_group_processed_element_count(group_task) * 100 / params->size.z, "Baking SDF");
+ }
}
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
}
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index d4f60503c2..04d164ba88 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -33,6 +33,8 @@
#include "collision_shape_3d.h"
#include "core/core_string_names.h"
#include "physics_body_3d.h"
+#include "scene/resources/concave_polygon_shape_3d.h"
+#include "scene/resources/convex_polygon_shape_3d.h"
bool MeshInstance3D::_set(const StringName &p_name, const Variant &p_value) {
//this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else.
@@ -224,7 +226,7 @@ Node *MeshInstance3D::create_trimesh_collision_node() {
return nullptr;
}
- Ref<Shape3D> shape = mesh->create_trimesh_shape();
+ Ref<ConcavePolygonShape3D> shape = mesh->create_trimesh_shape();
if (shape.is_null()) {
return nullptr;
}
@@ -254,7 +256,7 @@ Node *MeshInstance3D::create_convex_collision_node(bool p_clean, bool p_simplify
return nullptr;
}
- Ref<Shape3D> shape = mesh->create_convex_shape(p_clean, p_simplify);
+ Ref<ConvexPolygonShape3D> shape = mesh->create_convex_shape(p_clean, p_simplify);
if (shape.is_null()) {
return nullptr;
}
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index d9fa37ce74..d29f337fc8 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -34,8 +34,8 @@
#include "scene/scene_string_names.h"
void PhysicsBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(false), DEFVAL(1));
- ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(false), DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "motion", "test_only", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(false), DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "motion", "collision", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(false), DEFVAL(1));
ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock);
ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock);
@@ -80,19 +80,19 @@ TypedArray<PhysicsBody3D> PhysicsBody3D::get_collision_exceptions() {
void PhysicsBody3D::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
- ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
+ ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D).");
PhysicsServer3D::get_singleton()->body_add_collision_exception(get_rid(), collision_object->get_rid());
}
void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
- ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
+ ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D).");
PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
-Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_distance, bool p_test_only, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) {
- PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_distance, p_margin);
+Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) {
+ PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_motion, p_margin);
parameters.max_collisions = p_max_collisions;
parameters.recovery_as_collision = p_recovery_as_collision;
@@ -169,7 +169,7 @@ bool PhysicsBody3D::move_and_collide(const PhysicsServer3D::MotionParameters &p_
return colliding;
}
-bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) {
+bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer3D::MotionResult *r = nullptr;
@@ -181,7 +181,7 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_distan
r = &temp_result;
}
- PhysicsServer3D::MotionParameters parameters(p_from, p_distance, p_margin);
+ PhysicsServer3D::MotionParameters parameters(p_from, p_motion, p_margin);
parameters.recovery_as_collision = p_recovery_as_collision;
return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r);
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 4b874b91d9..36b7ce774c 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -50,11 +50,11 @@ protected:
uint16_t locked_axis = 0;
- Ref<KinematicCollision3D> _move(const Vector3 &p_distance, bool p_test_only = false, real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1);
+ Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_test_only = false, real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1);
public:
bool move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true);
- bool test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1);
+ bool test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1);
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 83e3369423..1814baa9e9 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -607,14 +607,14 @@ TypedArray<PhysicsBody3D> SoftBody3D::get_collision_exceptions() {
void SoftBody3D::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
- ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
+ ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D).");
PhysicsServer3D::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid());
}
void SoftBody3D::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
- ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
+ ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D).");
PhysicsServer3D::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid());
}
diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp
index f855fce318..6d8ce06524 100644
--- a/scene/3d/spring_arm_3d.cpp
+++ b/scene/3d/spring_arm_3d.cpp
@@ -31,6 +31,7 @@
#include "spring_arm_3d.h"
#include "scene/3d/camera_3d.h"
+#include "scene/resources/shape_3d.h"
void SpringArm3D::_notification(int p_what) {
switch (p_what) {
diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp
index f30aea3bdd..4b325ee464 100644
--- a/scene/animation/animation_blend_space_1d.cpp
+++ b/scene/animation/animation_blend_space_1d.cpp
@@ -230,14 +230,14 @@ void AnimationNodeBlendSpace1D::_add_blend_point(int p_index, const Ref<Animatio
}
}
-double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_is_external_seeking) {
if (blend_points_used == 0) {
return 0.0;
}
if (blend_points_used == 1) {
// only one point available, just play that animation
- return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
+ return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
}
double blend_pos = get_parameter(blend_position);
@@ -307,10 +307,10 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_see
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_seek_root, weights[i], FILTER_IGNORE, true);
+ 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 {
- blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+ } else if (sync) {
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
}
}
diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h
index 1876ccebc7..30cfe52c8e 100644
--- a/scene/animation/animation_blend_space_1d.h
+++ b/scene/animation/animation_blend_space_1d.h
@@ -98,7 +98,7 @@ public:
void set_use_sync(bool p_sync);
bool is_using_sync() const;
- double process(double p_time, bool p_seek, bool p_seek_root) override;
+ double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
String get_caption() const override;
Ref<AnimationNode> get_child_by_name(const StringName &p_name) override;
diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp
index 0d8b7ba8f7..4e20429ac9 100644
--- a/scene/animation/animation_blend_space_2d.cpp
+++ b/scene/animation/animation_blend_space_2d.cpp
@@ -432,7 +432,7 @@ void AnimationNodeBlendSpace2D::_blend_triangle(const Vector2 &p_pos, const Vect
r_weights[2] = w;
}
-double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_is_external_seeking) {
_update_triangles();
Vector2 blend_pos = get_parameter(blend_position);
@@ -502,7 +502,7 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see
for (int j = 0; j < 3; j++) {
if (i == triangle_points[j]) {
//blend with the given weight
- double t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, blend_weights[j], FILTER_IGNORE, true);
+ double t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, blend_weights[j], FILTER_IGNORE, true);
if (first || t < mind) {
mind = t;
first = false;
@@ -512,8 +512,8 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see
}
}
- if (!found) {
- blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+ if (sync && !found) {
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
}
}
} else {
@@ -538,21 +538,23 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see
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_seek_root, 0.0, FILTER_IGNORE, true);
+ 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);
}
- mind = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_seek_root, 1.0, FILTER_IGNORE, true);
+ mind = 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 + mind;
cur_closest = new_closest;
} else {
- mind = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
+ mind = 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 != cur_closest) {
- blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+ if (sync) {
+ for (int i = 0; i < blend_points_used; i++) {
+ if (i != cur_closest) {
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
+ }
}
}
}
diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h
index 250189f202..41854f73a4 100644
--- a/scene/animation/animation_blend_space_2d.h
+++ b/scene/animation/animation_blend_space_2d.h
@@ -128,7 +128,7 @@ public:
void set_y_label(const String &p_label);
String get_y_label() const;
- virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
+ virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
virtual String get_caption() const override;
Vector2 get_closest_point(const Vector2 &p_point);
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 0c91729a6f..015b5b27e3 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -64,7 +64,7 @@ void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const
}
}
-double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_external_seeking) {
AnimationPlayer *ap = state->player;
ERR_FAIL_COND_V(!ap, 0);
@@ -115,12 +115,13 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_seek_r
}
cur_time = Math::pingpong(cur_time, anim_size);
}
+ } else if (anim->get_loop_mode() == Animation::LOOP_LINEAR) {
+ if (!Math::is_zero_approx(anim_size)) {
+ cur_time = Math::fposmod(cur_time, anim_size);
+ }
+ backward = false;
} else {
- if (anim->get_loop_mode() == Animation::LOOP_LINEAR) {
- if (!Math::is_zero_approx(anim_size)) {
- cur_time = Math::fposmod(cur_time, anim_size);
- }
- } else if (cur_time < 0) {
+ if (cur_time < 0) {
step += cur_time;
cur_time = 0;
} else if (cur_time > anim_size) {
@@ -128,12 +129,25 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_seek_r
cur_time = anim_size;
}
backward = false;
+
+ // If ended, don't progress animation. So set delta to 0.
+ if (p_time > 0) {
+ if (play_mode == PLAY_MODE_FORWARD) {
+ if (prev_time >= anim_size) {
+ step = 0;
+ }
+ } else {
+ if (prev_time <= 0) {
+ step = 0;
+ }
+ }
+ }
}
if (play_mode == PLAY_MODE_FORWARD) {
- blend_animation(animation, cur_time, step, p_seek, p_seek_root, 1.0, pingponged);
+ blend_animation(animation, cur_time, step, p_seek, p_is_external_seeking, 1.0, pingponged);
} else {
- blend_animation(animation, anim_size - cur_time, -step, p_seek, p_seek_root, 1.0, pingponged);
+ blend_animation(animation, anim_size - cur_time, -step, p_seek, p_is_external_seeking, 1.0, pingponged);
}
set_parameter(time, cur_time);
@@ -273,7 +287,7 @@ bool AnimationNodeOneShot::has_filter() const {
return true;
}
-double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_external_seeking) {
bool cur_active = get_parameter(active);
bool cur_prev_active = get_parameter(prev_active);
double cur_time = get_parameter(time);
@@ -296,7 +310,7 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_roo
}
if (!cur_active) {
- return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
+ return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
}
}
@@ -333,12 +347,12 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_roo
double main_rem;
if (mix == MIX_MODE_ADD) {
- main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
+ main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
} else {
- main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_BLEND, sync);
+ main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - blend, FILTER_BLEND, sync);
}
- double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_seek_root, blend, FILTER_PASS, true);
+ double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_is_external_seeking, blend, FILTER_PASS, true);
if (do_start) {
cur_remaining = os_rem;
@@ -420,10 +434,10 @@ bool AnimationNodeAdd2::has_filter() const {
return true;
}
-double AnimationNodeAdd2::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeAdd2::process(double p_time, bool p_seek, bool p_is_external_seeking) {
double amount = get_parameter(add_amount);
- double rem0 = blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
- blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, sync);
+ double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
+ blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync);
return rem0;
}
@@ -454,11 +468,11 @@ bool AnimationNodeAdd3::has_filter() const {
return true;
}
-double AnimationNodeAdd3::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeAdd3::process(double p_time, bool p_seek, bool p_is_external_seeking) {
double amount = get_parameter(add_amount);
- blend_input(0, p_time, p_seek, p_seek_root, MAX(0, -amount), FILTER_PASS, sync);
- double rem0 = blend_input(1, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
- blend_input(2, p_time, p_seek, p_seek_root, MAX(0, amount), FILTER_PASS, sync);
+ blend_input(0, p_time, p_seek, p_is_external_seeking, MAX(0, -amount), FILTER_PASS, sync);
+ double rem0 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
+ blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_PASS, sync);
return rem0;
}
@@ -486,11 +500,11 @@ String AnimationNodeBlend2::get_caption() const {
return "Blend2";
}
-double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_is_external_seeking) {
double amount = get_parameter(blend_amount);
- double rem0 = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - amount, FILTER_BLEND, sync);
- double rem1 = blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, sync);
+ double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - amount, FILTER_BLEND, sync);
+ double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync);
return amount > 0.5 ? rem1 : rem0; //hacky but good enough
}
@@ -521,11 +535,11 @@ String AnimationNodeBlend3::get_caption() const {
return "Blend3";
}
-double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_is_external_seeking) {
double amount = get_parameter(blend_amount);
- double rem0 = blend_input(0, p_time, p_seek, p_seek_root, MAX(0, -amount), FILTER_IGNORE, sync);
- double rem1 = blend_input(1, p_time, p_seek, p_seek_root, 1.0 - ABS(amount), FILTER_IGNORE, sync);
- double rem2 = blend_input(2, p_time, p_seek, p_seek_root, MAX(0, amount), FILTER_IGNORE, sync);
+ double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, MAX(0, -amount), FILTER_IGNORE, sync);
+ double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0 - ABS(amount), FILTER_IGNORE, sync);
+ double rem2 = blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_IGNORE, sync);
return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); //hacky but good enough
}
@@ -553,12 +567,12 @@ String AnimationNodeTimeScale::get_caption() const {
return "TimeScale";
}
-double AnimationNodeTimeScale::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeTimeScale::process(double p_time, bool p_seek, bool p_is_external_seeking) {
double cur_scale = get_parameter(scale);
if (p_seek) {
- return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true);
+ return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
} else {
- return blend_input(0, p_time * cur_scale, false, p_seek_root, 1.0, FILTER_IGNORE, true);
+ return blend_input(0, p_time * cur_scale, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
}
}
@@ -583,16 +597,16 @@ String AnimationNodeTimeSeek::get_caption() const {
return "Seek";
}
-double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_is_external_seeking) {
double cur_seek_pos = get_parameter(seek_pos);
if (p_seek) {
- return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true);
+ return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
} else if (cur_seek_pos >= 0) {
double ret = blend_input(0, cur_seek_pos, true, true, 1.0, FILTER_IGNORE, true);
set_parameter(seek_pos, -1.0); //reset
return ret;
} else {
- return blend_input(0, p_time, false, p_seek_root, 1.0, FILTER_IGNORE, true);
+ return blend_input(0, p_time, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
}
}
@@ -700,7 +714,7 @@ bool AnimationNodeTransition::is_from_start() const {
return from_start;
}
-double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_external_seeking) {
int cur_current = get_parameter(current);
int cur_prev = get_parameter(prev);
int cur_prev_current = get_parameter(prev_current);
@@ -726,15 +740,17 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
double rem = 0.0;
- for (int i = 0; i < enabled_inputs; i++) {
- if (i != cur_current && i != cur_prev) {
- blend_input(i, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+ if (sync) {
+ for (int i = 0; i < enabled_inputs; i++) {
+ if (i != cur_current && i != cur_prev) {
+ blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
+ }
}
}
if (cur_prev < 0) { // process current animation, check for transition
- rem = blend_input(cur_current, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
+ rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
if (p_seek) {
cur_time = p_time;
@@ -754,17 +770,16 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
}
if (from_start && !p_seek && switched) { //just switched, seek to start of current
-
- rem = blend_input(cur_current, 0, true, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
+ rem = blend_input(cur_current, 0, true, p_is_external_seeking, 1.0 - blend, FILTER_IGNORE, true);
} else {
- rem = blend_input(cur_current, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
+ rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, 1.0 - blend, FILTER_IGNORE, true);
}
if (p_seek) {
- blend_input(cur_prev, p_time, true, p_seek_root, blend, FILTER_IGNORE, true);
+ blend_input(cur_prev, p_time, true, p_is_external_seeking, blend, FILTER_IGNORE, true);
cur_time = p_time;
} else {
- blend_input(cur_prev, p_time, false, p_seek_root, blend, FILTER_IGNORE, true);
+ blend_input(cur_prev, p_time, false, p_is_external_seeking, blend, FILTER_IGNORE, true);
cur_time += p_time;
cur_prev_xfading -= p_time;
if (cur_prev_xfading < 0) {
@@ -833,8 +848,8 @@ String AnimationNodeOutput::get_caption() const {
return "Output";
}
-double AnimationNodeOutput::process(double p_time, bool p_seek, bool p_seek_root) {
- return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
+double AnimationNodeOutput::process(double p_time, bool p_seek, bool p_is_external_seeking) {
+ return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
}
AnimationNodeOutput::AnimationNodeOutput() {
@@ -1046,9 +1061,9 @@ String AnimationNodeBlendTree::get_caption() const {
return "BlendTree";
}
-double AnimationNodeBlendTree::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeBlendTree::process(double p_time, bool p_seek, bool p_is_external_seeking) {
Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
- return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
+ return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
}
void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index 1c31718259..52bf67b8f5 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -53,7 +53,7 @@ public:
static Vector<String> (*get_editable_animation_list)();
virtual String get_caption() const override;
- virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
+ virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
void set_animation(const StringName &p_name);
StringName get_animation() const;
@@ -72,7 +72,7 @@ protected:
private:
PlayMode play_mode = PLAY_MODE_FORWARD;
- bool backward = false;
+ bool backward = false; // Only used by pingpong animation.
};
VARIANT_ENUM_CAST(AnimationNodeAnimation::PlayMode)
@@ -148,7 +148,7 @@ public:
MixMode get_mix_mode() const;
virtual bool has_filter() const override;
- virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
+ virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
AnimationNodeOneShot();
};
@@ -170,7 +170,7 @@ public:
virtual String get_caption() const override;
virtual bool has_filter() const override;
- virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
+ virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
AnimationNodeAdd2();
};
@@ -190,7 +190,7 @@ public:
virtual String get_caption() const override;
virtual bool has_filter() const override;
- virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
+ virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
AnimationNodeAdd3();
};
@@ -208,7 +208,7 @@ public:
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
virtual String get_caption() const override;
- virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
+ virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
virtual bool has_filter() const override;
AnimationNodeBlend2();
@@ -228,7 +228,7 @@ public:
virtual String get_caption() const override;
- double process(double p_time, bool p_seek, bool p_seek_root) override;
+ double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
AnimationNodeBlend3();
};
@@ -246,7 +246,7 @@ public:
virtual String get_caption() const override;
- double process(double p_time, bool p_seek, bool p_seek_root) override;
+ double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
AnimationNodeTimeScale();
};
@@ -265,7 +265,7 @@ public:
virtual String get_caption() const override;
- double process(double p_time, bool p_seek, bool p_seek_root) override;
+ double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
AnimationNodeTimeSeek();
};
@@ -331,7 +331,7 @@ public:
void set_from_start(bool p_from_start);
bool is_from_start() const;
- double process(double p_time, bool p_seek, bool p_seek_root) override;
+ double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
AnimationNodeTransition();
};
@@ -341,7 +341,7 @@ class AnimationNodeOutput : public AnimationNode {
public:
virtual String get_caption() const override;
- virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
+ virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
AnimationNodeOutput();
};
@@ -410,7 +410,7 @@ public:
void get_node_connections(List<NodeConnection> *r_connections) const;
virtual String get_caption() const override;
- virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
+ virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
void get_node_list(List<StringName> *r_list);
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 8291df8036..360f16de02 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -332,11 +332,11 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
return true;
}
-double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking) {
if (p_time == -1) {
Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node;
if (anodesm.is_valid()) {
- p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
+ p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true);
}
playing = false;
return 0;
@@ -405,7 +405,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
current = p_state_machine->start_node;
}
- len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 1.0, AnimationNode::FILTER_IGNORE, true);
+ len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 1.0, AnimationNode::FILTER_IGNORE, true);
pos_current = 0;
}
@@ -433,10 +433,10 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
if (current_curve.is_valid()) {
fade_blend = current_curve->sample(fade_blend);
}
- float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_seek_root, fade_blend, AnimationNode::FILTER_IGNORE, true);
+ float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, fade_blend, AnimationNode::FILTER_IGNORE, true);
if (fading_from != StringName()) {
- p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_seek_root, 1.0 - fade_blend, AnimationNode::FILTER_IGNORE, true);
+ p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, 1.0 - fade_blend, AnimationNode::FILTER_IGNORE, true);
}
//guess playback position
@@ -593,19 +593,19 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
{ // if the current node is a state machine, update the "playing" variable to false by passing -1 in p_time
Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node;
if (anodesm.is_valid()) {
- p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
+ p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true);
}
}
current = next;
if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
- len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
+ len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true);
pos_current = MIN(pos_current, len_current);
- p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
+ p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true);
} else {
- len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
+ len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true);
pos_current = 0;
}
@@ -1133,11 +1133,11 @@ Vector2 AnimationNodeStateMachine::get_graph_offset() const {
return graph_offset;
}
-double AnimationNodeStateMachine::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNodeStateMachine::process(double p_time, bool p_seek, bool p_is_external_seeking) {
Ref<AnimationNodeStateMachinePlayback> playback_new = get_parameter(playback);
ERR_FAIL_COND_V(playback_new.is_null(), 0.0);
- return playback_new->process(this, p_time, p_seek, p_seek_root);
+ return playback_new->process(this, p_time, p_seek, p_is_external_seeking);
}
String AnimationNodeStateMachine::get_caption() const {
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index cdb4c7528a..0dfe5a3a43 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -133,7 +133,7 @@ class AnimationNodeStateMachinePlayback : public Resource {
bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel);
- double process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_seek_root);
+ double process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking);
bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const;
@@ -239,7 +239,7 @@ public:
void set_graph_offset(const Vector2 &p_offset);
Vector2 get_graph_offset() const;
- virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
+ virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
virtual String get_caption() const override;
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) override;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 59930a3fbb..45eeff71f2 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -683,7 +683,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} else if (p_is_current && p_delta != 0) {
List<int> indices;
- a->value_track_get_key_indices(i, p_time, p_delta, &indices, p_pingponged);
+ a->track_get_key_indices_in_range(i, p_time, p_delta, &indices, p_pingponged);
for (int &F : indices) {
Variant value = a->track_get_key_value(i, F);
@@ -742,8 +742,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
}
List<int> indices;
-
- a->method_track_get_key_indices(i, p_time, p_delta, &indices, p_pingponged);
+ a->track_get_key_indices_in_range(i, p_time, p_delta, &indices, p_pingponged);
for (int &E : indices) {
StringName method = a->method_track_get_name(i, E);
@@ -1442,11 +1441,11 @@ void AnimationPlayer::remove_animation_library(const StringName &p_name) {
}
void AnimationPlayer::_ref_anim(const Ref<Animation> &p_anim) {
- Ref<Animation>(p_anim)->connect(SceneStringNames::get_singleton()->tracks_changed, callable_mp(this, &AnimationPlayer::_animation_changed), CONNECT_REFERENCE_COUNTED);
+ Ref<Animation>(p_anim)->connect("changed", callable_mp(this, &AnimationPlayer::_animation_changed), CONNECT_REFERENCE_COUNTED);
}
void AnimationPlayer::_unref_anim(const Ref<Animation> &p_anim) {
- Ref<Animation>(p_anim)->disconnect(SceneStringNames::get_singleton()->tracks_changed, callable_mp(this, &AnimationPlayer::_animation_changed));
+ Ref<Animation>(p_anim)->disconnect("changed", callable_mp(this, &AnimationPlayer::_animation_changed));
}
void AnimationPlayer::rename_animation_library(const StringName &p_name, const StringName &p_new_name) {
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 517908077d..50165773d0 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -86,7 +86,7 @@ void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
}
}
-void AnimationNode::blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_seek_root, real_t p_blend, int p_pingponged) {
+void AnimationNode::blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, int p_pingponged) {
ERR_FAIL_COND(!state);
ERR_FAIL_COND(!state->player->has_animation(p_animation));
@@ -113,18 +113,18 @@ void AnimationNode::blend_animation(const StringName &p_animation, double p_time
anim_state.animation = animation;
anim_state.seeked = p_seeked;
anim_state.pingponged = p_pingponged;
- anim_state.seek_root = p_seek_root;
+ anim_state.is_external_seeking = p_is_external_seeking;
state->animation_states.push_back(anim_state);
}
-double AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_seek_root, const Vector<StringName> &p_connections) {
+double AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_is_external_seeking, const Vector<StringName> &p_connections) {
base_path = p_base_path;
parent = p_parent;
connections = p_connections;
state = p_state;
- double t = process(p_time, p_seek, p_seek_root);
+ double t = process(p_time, p_seek, p_is_external_seeking);
state = nullptr;
parent = nullptr;
@@ -148,7 +148,7 @@ void AnimationNode::make_invalid(const String &p_reason) {
state->invalid_reasons += String::utf8("• ") + p_reason;
}
-double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_sync) {
+double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync) {
ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
ERR_FAIL_COND_V(!state, 0);
@@ -167,7 +167,7 @@ double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool
//inputs.write[p_input].last_pass = state->last_pass;
real_t activity = 0.0;
- double ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_seek_root, p_blend, p_filter, p_sync, &activity);
+ double ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_is_external_seeking, p_blend, p_filter, p_sync, &activity);
Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path);
@@ -178,11 +178,11 @@ double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool
return ret;
}
-double AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_sync) {
- return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_seek_root, p_blend, p_filter, p_sync);
+double AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync) {
+ return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_is_external_seeking, p_blend, p_filter, p_sync);
}
-double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter, bool p_sync, real_t *r_max) {
+double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync, real_t *r_max) {
ERR_FAIL_COND_V(!p_node.is_valid(), 0);
ERR_FAIL_COND_V(!state, 0);
@@ -221,7 +221,7 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri
}
blendw[i] = blendr[i] * p_blend;
- if (blendw[i] > CMP_EPSILON) {
+ if (!Math::is_zero_approx(blendw[i])) {
any_valid = true;
}
}
@@ -236,7 +236,7 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri
}
blendw[i] = blendr[i] * p_blend;
- if (blendw[i] > CMP_EPSILON) {
+ if (!Math::is_zero_approx(blendw[i])) {
any_valid = true;
}
}
@@ -252,7 +252,7 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri
blendw[i] = blendr[i]; //not filtered, do not blend
}
- if (blendw[i] > CMP_EPSILON) {
+ if (!Math::is_zero_approx(blendw[i])) {
any_valid = true;
}
}
@@ -263,7 +263,7 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri
for (int i = 0; i < blend_count; i++) {
//regular blend
blendw[i] = blendr[i] * p_blend;
- if (blendw[i] > CMP_EPSILON) {
+ if (!Math::is_zero_approx(blendw[i])) {
any_valid = true;
}
}
@@ -289,15 +289,12 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri
new_path = String(parent->base_path) + String(p_subpath) + "/";
}
- // If tracks for blending don't exist for one of the animations, Rest or RESET animation is blended as init animation instead.
- // Then blend weight is 0 means that the init animation blend weight is 1.
- // In that case, processing only the animation with the lacking track will not process the lacking track, and will not properly apply the Reset value.
- // This means that all tracks which the animations in the branch that may be blended have must be processed.
- // Therefore, the blending process must be executed even if the blend weight is 0.
+ // This process, which depends on p_sync is needed to process sync correctly in the case of
+ // that a synced AnimationNodeSync exists under the un-synced AnimationNodeSync.
if (!p_seek && !p_sync && !any_valid) {
- return p_node->_pre_process(new_path, new_parent, state, 0, p_seek, p_seek_root, p_connections);
+ return p_node->_pre_process(new_path, new_parent, state, 0, p_seek, p_is_external_seeking, p_connections);
}
- return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_seek_root, p_connections);
+ return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_is_external_seeking, p_connections);
}
int AnimationNode::get_input_count() const {
@@ -338,9 +335,9 @@ void AnimationNode::remove_input(int p_index) {
emit_changed();
}
-double AnimationNode::process(double p_time, bool p_seek, bool p_seek_root) {
+double AnimationNode::process(double p_time, bool p_seek, bool p_is_external_seeking) {
double ret = 0;
- GDVIRTUAL_CALL(_process, p_time, p_seek, p_seek_root, ret);
+ GDVIRTUAL_CALL(_process, p_time, p_seek, p_is_external_seeking, ret);
return ret;
}
@@ -416,9 +413,9 @@ void AnimationNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_filters", "filters"), &AnimationNode::_set_filters);
ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);
- ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "seek_root", "blend", "pingponged"), &AnimationNode::blend_animation, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "seek_root", "blend", "filter", "sync"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "seek_root", "blend", "filter", "sync"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "is_external_seeking", "blend", "pingponged"), &AnimationNode::blend_animation, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "is_external_seeking", "blend", "filter", "sync"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "is_external_seeking", "blend", "filter", "sync"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
ClassDB::bind_method(D_METHOD("set_parameter", "name", "value"), &AnimationNode::set_parameter);
ClassDB::bind_method(D_METHOD("get_parameter", "name"), &AnimationNode::get_parameter);
@@ -430,7 +427,7 @@ void AnimationNode::_bind_methods() {
GDVIRTUAL_BIND(_get_parameter_list);
GDVIRTUAL_BIND(_get_child_by_name, "name");
GDVIRTUAL_BIND(_get_parameter_default_value, "parameter");
- GDVIRTUAL_BIND(_process, "time", "seek", "seek_root");
+ GDVIRTUAL_BIND(_process, "time", "seek", "is_external_seeking");
GDVIRTUAL_BIND(_get_caption);
GDVIRTUAL_BIND(_has_filter);
@@ -589,6 +586,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
track_value->object = child;
}
+ track_value->is_discrete = anim->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE || anim->value_track_get_update_mode(i) == Animation::UPDATE_TRIGGER;
track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
track_value->subpath = leftover_path;
@@ -596,6 +594,13 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
track = track_value;
+ // If a value track without a key is cached first, the initial value cannot be determined.
+ // It is a corner case, but which may cause problems with blending.
+ ERR_CONTINUE_MSG(anim->track_get_key_count(i) == 0, "AnimationTree: '" + String(E) + "', value track: '" + String(path) + "' must have at least one key to cache for blending.");
+ track_value->init_value = anim->track_get_key_value(i, 0);
+ track_value->init_value.zero();
+
+ // If there is a Reset Animation, it takes precedence by overwriting.
if (has_reset_anim) {
int rt = reset_anim->find_track(path, track_type);
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
@@ -795,8 +800,18 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
}
} else if (track_cache_type == Animation::TYPE_VALUE) {
// If it has at least one angle interpolation, it also uses angle interpolation for blending.
- TrackCacheValue *track_value = memnew(TrackCacheValue);
+ TrackCacheValue *track_value = static_cast<TrackCacheValue *>(track);
+ bool was_discrete = track_value->is_discrete;
+ bool was_using_angle = track_value->is_using_angle;
+ track_value->is_discrete |= anim->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE || anim->value_track_get_update_mode(i) == Animation::UPDATE_TRIGGER;
track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
+
+ if (was_discrete != track_value->is_discrete) {
+ WARN_PRINT_ONCE("Tracks with different update modes are blended. Blending prioritizes Discrete/Trigger mode, so other update mode tracks will not be blended.");
+ }
+ if (was_using_angle != track_value->is_using_angle) {
+ WARN_PRINT_ONCE("Tracks for rotation with different interpolation types are blended. Blending prioritizes angle interpolation, so the blending result uses the shortest path referenced to the initial (RESET animation) value.");
+ }
}
track->setup_pass = setup_pass;
@@ -868,7 +883,9 @@ void AnimationTree::_process_graph(double p_delta) {
_update_properties(); //if properties need updating, update them
//check all tracks, see if they need modification
- root_motion_transform = Transform3D();
+ root_motion_position = Vector3(0, 0, 0);
+ root_motion_rotation = Quaternion(0, 0, 0, 1);
+ root_motion_scale = Vector3(0, 0, 0);
if (!root.is_valid()) {
ERR_PRINT("AnimationTree: root AnimationNode is not set, disabling playback.");
@@ -955,8 +972,44 @@ void AnimationTree::_process_graph(double p_delta) {
if (!state.valid) {
return; //state is not valid. do nothing.
}
- //apply value/transform/bezier blends to track caches and execute method/audio/animation tracks
+ // Init all value/transform/blend/bezier tracks that track_cache has.
+ {
+ for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
+ TrackCache *track = K.value;
+
+ switch (track->type) {
+ case Animation::TYPE_POSITION_3D: {
+ TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
+ if (track->root_motion) {
+ t->loc = Vector3(0, 0, 0);
+ t->rot = Quaternion(0, 0, 0, 1);
+ t->scale = Vector3(1, 1, 1);
+ } else {
+ t->loc = t->init_loc;
+ t->rot = t->init_rot;
+ t->scale = t->init_scale;
+ }
+ } break;
+ case Animation::TYPE_BLEND_SHAPE: {
+ TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);
+ t->value = t->init_value;
+ } break;
+ case Animation::TYPE_VALUE: {
+ TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
+ t->value = t->init_value;
+ } break;
+ case Animation::TYPE_BEZIER: {
+ TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
+ t->value = t->init_value;
+ } break;
+ default: {
+ } break;
+ }
+ }
+ }
+
+ // Apply value/transform/blend/bezier blends to track caches and execute method/audio/animation tracks.
{
bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint();
@@ -967,9 +1020,10 @@ void AnimationTree::_process_graph(double p_delta) {
real_t weight = as.blend;
bool seeked = as.seeked;
int pingponged = as.pingponged;
+ bool is_external_seeking = as.is_external_seeking;
#ifndef _3D_DISABLED
- bool backward = signbit(delta);
- bool calc_root = !seeked || as.seek_root;
+ bool backward = signbit(delta); // This flag is required only for the root motion since it calculates the difference between the previous and current frames.
+ bool calc_root = !seeked || is_external_seeking;
#endif // _3D_DISABLED
for (int i = 0; i < a->get_track_count(); i++) {
@@ -978,37 +1032,29 @@ void AnimationTree::_process_graph(double p_delta) {
}
NodePath path = a->track_get_path(i);
-
ERR_CONTINUE(!track_cache.has(path));
-
TrackCache *track = track_cache[path];
+ ERR_CONTINUE(!state.track_map.has(path));
+ int blend_idx = state.track_map[path];
+ ERR_CONTINUE(blend_idx < 0 || blend_idx >= state.track_count);
+ real_t blend = (*as.track_blends)[blend_idx] * weight;
+ if (Math::is_zero_approx(blend)) {
+ continue; // Nothing to blend.
+ }
+
Animation::TrackType ttype = a->track_get_type(i);
if (ttype != Animation::TYPE_POSITION_3D && ttype != Animation::TYPE_ROTATION_3D && ttype != Animation::TYPE_SCALE_3D && track->type != ttype) {
//broken animation, but avoid error spamming
continue;
}
-
track->root_motion = root_motion_track == path;
- ERR_CONTINUE(!state.track_map.has(path));
- int blend_idx = state.track_map[path];
-
- ERR_CONTINUE(blend_idx < 0 || blend_idx >= state.track_count);
-
- real_t blend = (*as.track_blends)[blend_idx] * weight;
-
switch (ttype) {
case Animation::TYPE_POSITION_3D: {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion && calc_root) {
- if (t->process_pass != process_pass) {
- t->process_pass = process_pass;
- t->loc = Vector3(0, 0, 0);
- t->rot = Quaternion(0, 0, 0, 1);
- t->scale = Vector3(0, 0, 0);
- }
double prev_time = time - delta;
if (!backward) {
if (prev_time < 0) {
@@ -1084,12 +1130,6 @@ void AnimationTree::_process_graph(double p_delta) {
prev_time = !backward ? 0 : (double)a->get_length();
} else {
- if (t->process_pass != process_pass) {
- t->process_pass = process_pass;
- t->loc = t->init_loc;
- t->rot = t->init_rot;
- t->scale = t->init_scale;
- }
Vector3 loc;
Error err = a->position_track_interpolate(i, time, &loc);
@@ -1106,12 +1146,6 @@ void AnimationTree::_process_graph(double p_delta) {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion && calc_root) {
- if (t->process_pass != process_pass) {
- t->process_pass = process_pass;
- t->loc = Vector3(0, 0, 0);
- t->rot = Quaternion(0, 0, 0, 1);
- t->scale = Vector3(0, 0, 0);
- }
double prev_time = time - delta;
if (!backward) {
if (prev_time < 0) {
@@ -1186,12 +1220,6 @@ void AnimationTree::_process_graph(double p_delta) {
prev_time = !backward ? 0 : (double)a->get_length();
} else {
- if (t->process_pass != process_pass) {
- t->process_pass = process_pass;
- t->loc = t->init_loc;
- t->rot = t->init_rot;
- t->scale = t->init_scale;
- }
Quaternion rot;
Error err = a->rotation_track_interpolate(i, time, &rot);
@@ -1208,12 +1236,6 @@ void AnimationTree::_process_graph(double p_delta) {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion && calc_root) {
- if (t->process_pass != process_pass) {
- t->process_pass = process_pass;
- t->loc = Vector3(0, 0, 0);
- t->rot = Quaternion(0, 0, 0, 1);
- t->scale = Vector3(0, 0, 0);
- }
double prev_time = time - delta;
if (!backward) {
if (prev_time < 0) {
@@ -1289,12 +1311,6 @@ void AnimationTree::_process_graph(double p_delta) {
prev_time = !backward ? 0 : (double)a->get_length();
} else {
- if (t->process_pass != process_pass) {
- t->process_pass = process_pass;
- t->loc = t->init_loc;
- t->rot = t->init_rot;
- t->scale = t->init_scale;
- }
Vector3 scale;
Error err = a->scale_track_interpolate(i, time, &scale);
@@ -1311,11 +1327,6 @@ void AnimationTree::_process_graph(double p_delta) {
#ifndef _3D_DISABLED
TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);
- if (t->process_pass != process_pass) {
- t->process_pass = process_pass;
- t->value = t->init_value;
- }
-
float value;
Error err = a->blend_shape_track_interpolate(i, time, &value);
@@ -1342,15 +1353,6 @@ void AnimationTree::_process_graph(double p_delta) {
continue;
}
- if (t->process_pass != process_pass) {
- t->process_pass = process_pass;
- if (!t->init_value) {
- t->init_value = value;
- t->init_value.zero();
- }
- t->value = t->init_value;
- }
-
// Special case for angle interpolation.
if (t->is_using_angle) {
// For blending consistency, it prevents rotation of more than 180 degrees from init_value.
@@ -1379,12 +1381,8 @@ void AnimationTree::_process_graph(double p_delta) {
}
}
} else {
- if (blend < CMP_EPSILON) {
- continue; //nothing to blend
- }
-
if (seeked) {
- int idx = a->track_find_key(i, time);
+ int idx = a->track_find_key(i, time, !is_external_seeking);
if (idx < 0) {
continue;
}
@@ -1393,7 +1391,7 @@ void AnimationTree::_process_graph(double p_delta) {
t->object->set_indexed(t->subpath, value);
} else {
List<int> indices;
- a->value_track_get_key_indices(i, time, delta, &indices, pingponged);
+ a->track_get_key_indices_in_range(i, time, delta, &indices, pingponged);
for (int &F : indices) {
Variant value = a->track_get_key_value(i, F);
value = _post_process_key_value(a, i, value, t->object);
@@ -1404,13 +1402,10 @@ void AnimationTree::_process_graph(double p_delta) {
} break;
case Animation::TYPE_METHOD: {
- if (blend < CMP_EPSILON) {
- continue; //nothing to blend
- }
TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track);
if (seeked) {
- int idx = a->track_find_key(i, time);
+ int idx = a->track_find_key(i, time, !is_external_seeking);
if (idx < 0) {
continue;
}
@@ -1421,7 +1416,7 @@ void AnimationTree::_process_graph(double p_delta) {
}
} else {
List<int> indices;
- a->method_track_get_key_indices(i, time, delta, &indices, pingponged);
+ a->track_get_key_indices_in_range(i, time, delta, &indices, pingponged);
for (int &F : indices) {
StringName method = a->method_track_get_name(i, F);
Vector<Variant> params = a->method_track_get_params(i, F);
@@ -1437,22 +1432,14 @@ void AnimationTree::_process_graph(double p_delta) {
real_t bezier = a->bezier_track_interpolate(i, time);
bezier = _post_process_key_value(a, i, bezier, t->object);
- if (t->process_pass != process_pass) {
- t->process_pass = process_pass;
- t->value = t->init_value;
- }
-
t->value += (bezier - t->init_value) * blend;
} break;
case Animation::TYPE_AUDIO: {
- if (blend < CMP_EPSILON) {
- continue; //nothing to blend
- }
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
if (seeked) {
//find whatever should be playing
- int idx = a->track_find_key(i, time);
+ int idx = a->track_find_key(i, time, !is_external_seeking);
if (idx < 0) {
continue;
}
@@ -1555,9 +1542,6 @@ void AnimationTree::_process_graph(double p_delta) {
t->object->call(SNAME("set_volume_db"), db);
} break;
case Animation::TYPE_ANIMATION: {
- if (blend < CMP_EPSILON) {
- continue; //nothing to blend
- }
TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track);
AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t->object);
@@ -1568,7 +1552,7 @@ void AnimationTree::_process_graph(double p_delta) {
if (seeked) {
//seek
- int idx = a->track_find_key(i, time);
+ int idx = a->track_find_key(i, time, !is_external_seeking);
if (idx < 0) {
continue;
}
@@ -1639,9 +1623,6 @@ void AnimationTree::_process_graph(double p_delta) {
// finally, set the tracks
for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
TrackCache *track = K.value;
- if (track->process_pass != process_pass) {
- continue; //not processed, ignore
- }
switch (track->type) {
case Animation::TYPE_POSITION_3D: {
@@ -1649,11 +1630,9 @@ void AnimationTree::_process_graph(double p_delta) {
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (t->root_motion) {
- Transform3D xform;
- xform.origin = t->loc;
- xform.basis.set_quaternion_scale(t->rot, Vector3(1, 1, 1) + t->scale);
-
- root_motion_transform = xform;
+ root_motion_position = root_motion_rotation.xform_inv(t->loc);
+ root_motion_rotation = t->rot;
+ root_motion_scale = t->scale - Vector3(1, 1, 1);
} else if (t->skeleton && t->bone_idx >= 0) {
if (t->loc_used) {
@@ -1691,6 +1670,10 @@ void AnimationTree::_process_graph(double p_delta) {
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
+ if (t->is_discrete) {
+ break; // Don't overwrite the value set by UPDATE_DISCRETE or UPDATE_TRIGGER.
+ }
+
if (t->init_value.get_type() == Variant::BOOL) {
t->object->set_indexed(t->subpath, t->value.operator real_t() >= 0.5);
} else {
@@ -1862,8 +1845,16 @@ NodePath AnimationTree::get_root_motion_track() const {
return root_motion_track;
}
-Transform3D AnimationTree::get_root_motion_transform() const {
- return root_motion_transform;
+Vector3 AnimationTree::get_root_motion_position() const {
+ return root_motion_position;
+}
+
+Quaternion AnimationTree::get_root_motion_rotation() const {
+ return root_motion_rotation;
+}
+
+Vector3 AnimationTree::get_root_motion_scale() const {
+ return root_motion_scale;
}
void AnimationTree::_tree_changed() {
@@ -2021,7 +2012,9 @@ void AnimationTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationTree::set_root_motion_track);
ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationTree::get_root_motion_track);
- ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform);
+ ClassDB::bind_method(D_METHOD("get_root_motion_position"), &AnimationTree::get_root_motion_position);
+ ClassDB::bind_method(D_METHOD("get_root_motion_rotation"), &AnimationTree::get_root_motion_rotation);
+ ClassDB::bind_method(D_METHOD("get_root_motion_scale"), &AnimationTree::get_root_motion_scale);
ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties);
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 96c1279f82..a4b0f992dc 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -68,7 +68,7 @@ public:
const Vector<real_t> *track_blends = nullptr;
real_t blend = 0.0;
bool seeked = false;
- bool seek_root = false;
+ bool is_external_seeking = false;
int pingponged = 0;
};
@@ -86,7 +86,7 @@ public:
Vector<real_t> blends;
State *state = nullptr;
- double _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_seek_root, const Vector<StringName> &p_connections);
+ double _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_is_external_seeking, const Vector<StringName> &p_connections);
//all this is temporary
StringName base_path;
@@ -99,12 +99,12 @@ public:
Array _get_filters() const;
void _set_filters(const Array &p_filters);
friend class AnimationNodeBlendTree;
- double _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, real_t *r_max = nullptr);
+ double _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, real_t *r_max = nullptr);
protected:
- void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_seek_root, real_t p_blend, int p_pingponged = 0);
- double blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true);
- double blend_input(int p_input, double p_time, bool p_seek, bool p_seek_root, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true);
+ void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, int p_pingponged = 0);
+ double blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true);
+ double blend_input(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true);
void make_invalid(const String &p_reason);
AnimationTree *get_animation_tree() const;
@@ -135,7 +135,7 @@ public:
virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
- virtual double process(double p_time, bool p_seek, bool p_seek_root);
+ virtual double process(double p_time, bool p_seek, bool p_is_external_seeking);
virtual String get_caption() const;
int get_input_count() const;
@@ -190,7 +190,6 @@ private:
struct TrackCache {
bool root_motion = false;
uint64_t setup_pass = 0;
- uint64_t process_pass = 0;
Animation::TrackType type = Animation::TrackType::TYPE_ANIMATION;
Object *object = nullptr;
ObjectID object_id;
@@ -233,6 +232,7 @@ private:
Variant init_value;
Variant value;
Vector<StringName> subpath;
+ bool is_discrete = false;
bool is_using_angle = false;
TrackCacheValue() { type = Animation::TYPE_VALUE; }
};
@@ -294,7 +294,9 @@ private:
bool started = true;
NodePath root_motion_track;
- Transform3D root_motion_transform;
+ Vector3 root_motion_position = Vector3(0, 0, 0);
+ Quaternion root_motion_rotation = Quaternion(0, 0, 0, 1);
+ Vector3 root_motion_scale = Vector3(0, 0, 0);
friend class AnimationNode;
bool properties_dirty = true;
@@ -350,7 +352,9 @@ public:
void set_root_motion_track(const NodePath &p_track);
NodePath get_root_motion_track() const;
- Transform3D get_root_motion_transform() const;
+ Vector3 get_root_motion_position() const;
+ Quaternion get_root_motion_rotation() const;
+ Vector3 get_root_motion_scale() const;
real_t get_connection_activity(const StringName &p_path, int p_connection) const;
void advance(double p_time);
diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp
index 47f08219a9..a6ccb4a576 100644
--- a/scene/animation/root_motion_view.cpp
+++ b/scene/animation/root_motion_view.cpp
@@ -103,7 +103,8 @@ void RootMotionView::_notification(int p_what) {
set_physics_process_internal(false);
}
- transform = tree->get_root_motion_transform();
+ transform.origin = tree->get_root_motion_position();
+ transform.basis = tree->get_root_motion_rotation(); // Scale is meaningless.
}
}
@@ -113,9 +114,8 @@ void RootMotionView::_notification(int p_what) {
first = false;
- transform.orthonormalize(); //don't want scale, too imprecise
-
- accumulated = accumulated * transform;
+ accumulated.origin += transform.origin;
+ accumulated.basis *= transform.basis;
accumulated.origin.x = Math::fposmod(accumulated.origin.x, cell_size);
if (zero_y) {
accumulated.origin.y = 0;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 724e5bcaf6..eb9f9039b7 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -959,7 +959,7 @@ void ColorPicker::_sample_draw() {
// Draw both old and new colors for easier comparison (only if spawned from a ColorPickerButton).
const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95));
- if (display_old_color && old_color.a < 1.0) {
+ if (old_color.a < 1.0) {
sample->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), rect_old, true);
}
@@ -1088,7 +1088,9 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
} else if (p_which == 1) {
if (actual_shape == SHAPE_HSV_RECTANGLE) {
Ref<Texture2D> hue = get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
- c->draw_texture_rect(hue, Rect2(Point2(), c->get_size()));
+ c->draw_set_transform(Point2(), -Math_PI / 2, Size2(c->get_size().x, -c->get_size().y));
+ c->draw_texture_rect(hue, Rect2(Point2(), Size2(1, 1)));
+ c->draw_set_transform(Point2(), 0, Size2(1, 1));
int y = c->get_size().y - c->get_size().y * (1.0 - h);
Color col;
col.set_hsv(h, 1, 1);
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 4e76f72921..92ee21a916 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2935,7 +2935,7 @@ void Control::_notification(int p_notification) {
queue_redraw();
if (data.RI) {
- get_viewport()->_gui_set_root_order_dirty();
+ get_viewport()->gui_set_root_order_dirty();
}
} break;
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index bf4dd3d245..0d265719ec 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -377,7 +377,7 @@ void AcceptDialog::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "ok_button_text"), "set_ok_button_text", "get_ok_button_text");
- ADD_GROUP("Dialog", "dialog");
+ ADD_GROUP("Dialog", "dialog_");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "dialog_text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_hide_on_ok"), "set_hide_on_ok", "get_hide_on_ok");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_close_on_escape"), "set_close_on_escape", "get_close_on_escape");
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 46b712379d..40792dd43f 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -2406,7 +2406,7 @@ void GraphEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom_step"), "set_zoom_step", "get_zoom_step");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_zoom_label"), "set_show_zoom_label", "is_showing_zoom_label");
- ADD_GROUP("Minimap", "minimap");
+ ADD_GROUP("Minimap", "minimap_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "minimap_enabled"), "set_minimap_enabled", "is_minimap_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimap_size", PROPERTY_HINT_NONE, "suffix:px"), "set_minimap_size", "get_minimap_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "minimap_opacity"), "set_minimap_opacity", "get_minimap_opacity");
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 889610e071..642a94b23e 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -3860,6 +3860,10 @@ void RichTextLabel::append_text(const String &p_bbcode) {
Color color2 = Color::from_string(subtag_b[1], fallback_color);
set_cell_row_background_color(color1, color2);
}
+ if (subtag_b.size() == 1) {
+ Color color1 = Color::from_string(subtag_a[1], fallback_color);
+ set_cell_row_background_color(color1, color1);
+ }
}
}
}
@@ -5392,7 +5396,7 @@ void RichTextLabel::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
ADD_GROUP("Markup", "");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "RichTextEffect"), (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("RichTextEffect"), (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta_underlined"), "set_meta_underline", "is_meta_underlined");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hint_underlined"), "set_hint_underline", "is_hint_underlined");
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 2ca1d6239e..9830b41389 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -71,7 +71,7 @@ void SplitContainerDragger::gui_input(const Ref<InputEvent> &p_event) {
Vector2i in_parent_pos = get_transform().xform(mm->get_position());
if (!sc->vertical && is_layout_rtl()) {
- sc->split_offset = drag_ofs - ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from);
+ sc->split_offset = drag_ofs - (in_parent_pos.x - drag_from);
} else {
sc->split_offset = drag_ofs + ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from);
}
@@ -194,7 +194,6 @@ void SplitContainer::_compute_middle_sep(bool p_clamp) {
// Clamp the split_offset if requested.
if (p_clamp) {
split_offset -= wished_middle_sep - middle_sep;
- p_clamp = false;
}
}
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index 3ad84cbc6d..f3d9a22342 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -227,6 +227,18 @@ void SubViewportContainer::unhandled_input(const Ref<InputEvent> &p_event) {
}
}
+void SubViewportContainer::add_child_notify(Node *p_child) {
+ if (Object::cast_to<SubViewport>(p_child)) {
+ queue_redraw();
+ }
+}
+
+void SubViewportContainer::remove_child_notify(Node *p_child) {
+ if (Object::cast_to<SubViewport>(p_child)) {
+ queue_redraw();
+ }
+}
+
PackedStringArray SubViewportContainer::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings();
diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h
index 63a58b5f07..fdd8fe9486 100644
--- a/scene/gui/subviewport_container.h
+++ b/scene/gui/subviewport_container.h
@@ -44,6 +44,9 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ virtual void add_child_notify(Node *p_child) override;
+ virtual void remove_child_notify(Node *p_child) override;
+
public:
void set_stretch(bool p_enable);
bool is_stretch_enabled() const;
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index cf6681f809..f87829cf71 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -385,9 +385,6 @@ void TabBar::_notification(int p_what) {
if (tabs[i].disabled) {
sb = theme_cache.tab_disabled_style;
col = theme_cache.font_disabled_color;
- } else if (i == current) {
- sb = theme_cache.tab_selected_style;
- col = theme_cache.font_selected_color;
} else {
sb = theme_cache.tab_unselected_style;
col = theme_cache.font_unselected_color;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 56f7281721..cce9fa4f34 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -4234,7 +4234,7 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_
if (!p_allow_out_of_bounds) {
return Point2i(-1, -1);
}
- return Point2i(text[row].size(), row);
+ return Point2i(text[row].length(), row);
}
int col = 0;
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index ad12757921..ccdf56c1d7 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -250,11 +250,11 @@ void TextureButton::_notification(int p_what) {
}
void TextureButton::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_normal_texture", "texture"), &TextureButton::set_normal_texture);
- ClassDB::bind_method(D_METHOD("set_pressed_texture", "texture"), &TextureButton::set_pressed_texture);
- ClassDB::bind_method(D_METHOD("set_hover_texture", "texture"), &TextureButton::set_hover_texture);
- ClassDB::bind_method(D_METHOD("set_disabled_texture", "texture"), &TextureButton::set_disabled_texture);
- ClassDB::bind_method(D_METHOD("set_focused_texture", "texture"), &TextureButton::set_focused_texture);
+ ClassDB::bind_method(D_METHOD("set_texture_normal", "texture"), &TextureButton::set_texture_normal);
+ ClassDB::bind_method(D_METHOD("set_texture_pressed", "texture"), &TextureButton::set_texture_pressed);
+ ClassDB::bind_method(D_METHOD("set_texture_hover", "texture"), &TextureButton::set_texture_hover);
+ ClassDB::bind_method(D_METHOD("set_texture_disabled", "texture"), &TextureButton::set_texture_disabled);
+ ClassDB::bind_method(D_METHOD("set_texture_focused", "texture"), &TextureButton::set_texture_focused);
ClassDB::bind_method(D_METHOD("set_click_mask", "mask"), &TextureButton::set_click_mask);
ClassDB::bind_method(D_METHOD("set_ignore_texture_size", "ignore"), &TextureButton::set_ignore_texture_size);
ClassDB::bind_method(D_METHOD("set_stretch_mode", "mode"), &TextureButton::set_stretch_mode);
@@ -263,21 +263,21 @@ void TextureButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flip_v", "enable"), &TextureButton::set_flip_v);
ClassDB::bind_method(D_METHOD("is_flipped_v"), &TextureButton::is_flipped_v);
- ClassDB::bind_method(D_METHOD("get_normal_texture"), &TextureButton::get_normal_texture);
- ClassDB::bind_method(D_METHOD("get_pressed_texture"), &TextureButton::get_pressed_texture);
- ClassDB::bind_method(D_METHOD("get_hover_texture"), &TextureButton::get_hover_texture);
- ClassDB::bind_method(D_METHOD("get_disabled_texture"), &TextureButton::get_disabled_texture);
- ClassDB::bind_method(D_METHOD("get_focused_texture"), &TextureButton::get_focused_texture);
+ ClassDB::bind_method(D_METHOD("get_texture_normal"), &TextureButton::get_texture_normal);
+ ClassDB::bind_method(D_METHOD("get_texture_pressed"), &TextureButton::get_texture_pressed);
+ ClassDB::bind_method(D_METHOD("get_texture_hover"), &TextureButton::get_texture_hover);
+ ClassDB::bind_method(D_METHOD("get_texture_disabled"), &TextureButton::get_texture_disabled);
+ ClassDB::bind_method(D_METHOD("get_texture_focused"), &TextureButton::get_texture_focused);
ClassDB::bind_method(D_METHOD("get_click_mask"), &TextureButton::get_click_mask);
ClassDB::bind_method(D_METHOD("get_ignore_texture_size"), &TextureButton::get_ignore_texture_size);
ClassDB::bind_method(D_METHOD("get_stretch_mode"), &TextureButton::get_stretch_mode);
ADD_GROUP("Textures", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_texture", "get_normal_texture");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_pressed_texture", "get_pressed_texture");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_hover", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_hover_texture", "get_hover_texture");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_disabled", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_disabled_texture", "get_disabled_texture");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_focused", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_focused_texture", "get_focused_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_normal", "get_texture_normal");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_pressed", "get_texture_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_hover", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_hover", "get_texture_hover");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_disabled", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_disabled", "get_texture_disabled");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_focused", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_focused", "get_texture_focused");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_click_mask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_click_mask", "get_click_mask");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_texture_size", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_ignore_texture_size", "get_ignore_texture_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode");
@@ -293,7 +293,7 @@ void TextureButton::_bind_methods() {
BIND_ENUM_CONSTANT(STRETCH_KEEP_ASPECT_COVERED);
}
-void TextureButton::set_normal_texture(const Ref<Texture2D> &p_normal) {
+void TextureButton::set_texture_normal(const Ref<Texture2D> &p_normal) {
if (normal == p_normal) {
return;
}
@@ -303,7 +303,7 @@ void TextureButton::set_normal_texture(const Ref<Texture2D> &p_normal) {
update_minimum_size();
}
-void TextureButton::set_pressed_texture(const Ref<Texture2D> &p_pressed) {
+void TextureButton::set_texture_pressed(const Ref<Texture2D> &p_pressed) {
if (pressed == p_pressed) {
return;
}
@@ -313,7 +313,7 @@ void TextureButton::set_pressed_texture(const Ref<Texture2D> &p_pressed) {
update_minimum_size();
}
-void TextureButton::set_hover_texture(const Ref<Texture2D> &p_hover) {
+void TextureButton::set_texture_hover(const Ref<Texture2D> &p_hover) {
if (hover == p_hover) {
return;
}
@@ -323,7 +323,7 @@ void TextureButton::set_hover_texture(const Ref<Texture2D> &p_hover) {
update_minimum_size();
}
-void TextureButton::set_disabled_texture(const Ref<Texture2D> &p_disabled) {
+void TextureButton::set_texture_disabled(const Ref<Texture2D> &p_disabled) {
if (disabled == p_disabled) {
return;
}
@@ -341,19 +341,19 @@ void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) {
update_minimum_size();
}
-Ref<Texture2D> TextureButton::get_normal_texture() const {
+Ref<Texture2D> TextureButton::get_texture_normal() const {
return normal;
}
-Ref<Texture2D> TextureButton::get_pressed_texture() const {
+Ref<Texture2D> TextureButton::get_texture_pressed() const {
return pressed;
}
-Ref<Texture2D> TextureButton::get_hover_texture() const {
+Ref<Texture2D> TextureButton::get_texture_hover() const {
return hover;
}
-Ref<Texture2D> TextureButton::get_disabled_texture() const {
+Ref<Texture2D> TextureButton::get_texture_disabled() const {
return disabled;
}
@@ -361,11 +361,11 @@ Ref<BitMap> TextureButton::get_click_mask() const {
return click_mask;
}
-Ref<Texture2D> TextureButton::get_focused_texture() const {
+Ref<Texture2D> TextureButton::get_texture_focused() const {
return focused;
};
-void TextureButton::set_focused_texture(const Ref<Texture2D> &p_focused) {
+void TextureButton::set_texture_focused(const Ref<Texture2D> &p_focused) {
focused = p_focused;
};
diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h
index 9f6f7c1515..4b6d5b5bec 100644
--- a/scene/gui/texture_button.h
+++ b/scene/gui/texture_button.h
@@ -71,18 +71,18 @@ protected:
static void _bind_methods();
public:
- void set_normal_texture(const Ref<Texture2D> &p_normal);
- void set_pressed_texture(const Ref<Texture2D> &p_pressed);
- void set_hover_texture(const Ref<Texture2D> &p_hover);
- void set_disabled_texture(const Ref<Texture2D> &p_disabled);
- void set_focused_texture(const Ref<Texture2D> &p_focused);
+ void set_texture_normal(const Ref<Texture2D> &p_normal);
+ void set_texture_pressed(const Ref<Texture2D> &p_pressed);
+ void set_texture_hover(const Ref<Texture2D> &p_hover);
+ void set_texture_disabled(const Ref<Texture2D> &p_disabled);
+ void set_texture_focused(const Ref<Texture2D> &p_focused);
void set_click_mask(const Ref<BitMap> &p_click_mask);
- Ref<Texture2D> get_normal_texture() const;
- Ref<Texture2D> get_pressed_texture() const;
- Ref<Texture2D> get_hover_texture() const;
- Ref<Texture2D> get_disabled_texture() const;
- Ref<Texture2D> get_focused_texture() const;
+ Ref<Texture2D> get_texture_normal() const;
+ Ref<Texture2D> get_texture_pressed() const;
+ Ref<Texture2D> get_texture_hover() const;
+ Ref<Texture2D> get_texture_disabled() const;
+ Ref<Texture2D> get_texture_focused() const;
Ref<BitMap> get_click_mask() const;
bool get_ignore_texture_size() const;
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index be5788739b..5fde18721a 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -38,7 +38,7 @@ void CanvasLayer::set_layer(int p_xform) {
layer = p_xform;
if (viewport.is_valid()) {
RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
- vp->_gui_set_root_order_dirty();
+ vp->gui_set_root_order_dirty();
}
}
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 2c395ec07d..62f362553f 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -276,10 +276,10 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
}
if (content_encoding == "gzip") {
decompressor.instantiate();
- decompressor->start_decompression(false, get_download_chunk_size() * 2);
+ decompressor->start_decompression(false, get_download_chunk_size());
} else if (content_encoding == "deflate") {
decompressor.instantiate();
- decompressor->start_decompression(true, get_download_chunk_size() * 2);
+ decompressor->start_decompression(true, get_download_chunk_size());
}
return false;
@@ -390,19 +390,38 @@ bool HTTPRequest::_update_connection() {
return false;
}
- PackedByteArray chunk = client->read_response_body_chunk();
- downloaded.add(chunk.size());
-
- // Decompress chunk if needed.
- if (decompressor.is_valid()) {
- Error err = decompressor->put_data(chunk.ptr(), chunk.size());
- if (err == OK) {
- chunk.resize(decompressor->get_available_bytes());
- err = decompressor->get_data(chunk.ptrw(), chunk.size());
- }
- if (err != OK) {
- _defer_done(RESULT_BODY_DECOMPRESS_FAILED, response_code, response_headers, PackedByteArray());
- return true;
+ PackedByteArray chunk;
+ if (decompressor.is_null()) {
+ // Chunk can be read directly.
+ chunk = client->read_response_body_chunk();
+ downloaded.add(chunk.size());
+ } else {
+ // Chunk is the result of decompression.
+ PackedByteArray compressed = client->read_response_body_chunk();
+ downloaded.add(compressed.size());
+
+ int pos = 0;
+ int left = compressed.size();
+ while (left) {
+ int w = 0;
+ Error err = decompressor->put_partial_data(compressed.ptr() + pos, left, w);
+ if (err == OK) {
+ PackedByteArray dc;
+ dc.resize(decompressor->get_available_bytes());
+ err = decompressor->get_data(dc.ptrw(), dc.size());
+ chunk.append_array(dc);
+ }
+ if (err != OK) {
+ _defer_done(RESULT_BODY_DECOMPRESS_FAILED, response_code, response_headers, PackedByteArray());
+ return true;
+ }
+ // We need this check here because a "zip bomb" could result in a chunk of few kilos decompressing into gigabytes of data.
+ if (body_size_limit >= 0 && final_body_size.get() + chunk.size() > body_size_limit) {
+ _defer_done(RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
+ return true;
+ }
+ pos += w;
+ left -= w;
}
}
final_body_size.add(chunk.size());
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 220ec39c16..680c4cd7e4 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -349,7 +349,7 @@ void Node::move_child(Node *p_child, int p_index) {
}
void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) {
- ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup).");
+ ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `move_child()` failed. Consider using `move_child.call_deferred(child, index)` instead (or `popup.call_deferred()` if this is from a popup).");
// Specifying one place beyond the end
// means the same as moving to the last index
@@ -1130,7 +1130,7 @@ void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_i
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(p_child->is_ancestor_of(this), vformat("Can't add child '%s' to '%s' as it would result in a cyclic dependency since '%s' is already a parent of '%s'.", p_child->get_name(), get_name(), p_child->get_name(), get_name()));
#endif
- ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_node() failed. Consider using call_deferred(\"add_child\", child) instead.");
+ ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_child()` failed. Consider using `add_child.call_deferred(child)` instead.");
_validate_child_name(p_child, p_force_readable_name);
_add_child_nocheck(p_child, p_child->data.name);
@@ -1150,7 +1150,7 @@ void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) {
ERR_FAIL_NULL(p_sibling);
ERR_FAIL_NULL(data.parent);
ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself!
- ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_sibling() failed. Consider using call_deferred(\"add_sibling\", sibling) instead.");
+ ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_sibling()` failed. Consider using `add_sibling.call_deferred(sibling)` instead.");
InternalMode internal = INTERNAL_MODE_DISABLED;
if (_is_internal_front()) { // The sibling will have the same internal status.
@@ -1165,7 +1165,7 @@ void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) {
void Node::remove_child(Node *p_child) {
ERR_FAIL_NULL(p_child);
- ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, remove_node() failed. Consider using call_deferred(\"remove_child\", child) instead.");
+ ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `remove_child()` failed. Consider using `remove_child.call_deferred(child)` instead.");
int child_count = data.children.size();
Node **children = data.children.ptrw();
@@ -2608,10 +2608,6 @@ static void _Node_debug_sn(Object *p_obj) {
}
#endif // DEBUG_ENABLED
-void Node::_print_orphan_nodes() {
- print_orphan_nodes();
-}
-
void Node::print_orphan_nodes() {
#ifdef DEBUG_ENABLED
ObjectDB::debug_objects(_Node_debug_sn);
@@ -2783,6 +2779,7 @@ void Node::_bind_methods() {
GLOBAL_DEF("editor/node_naming/name_casing", NAME_CASING_PASCAL_CASE);
ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_casing", PropertyInfo(Variant::INT, "editor/node_naming/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"));
+ ClassDB::bind_static_method("Node", D_METHOD("print_orphan_nodes"), &Node::print_orphan_nodes);
ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "force_readable_name"), &Node::add_sibling, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_name", "name"), &Node::set_name);
@@ -2840,7 +2837,6 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Node::set_process_mode);
ClassDB::bind_method(D_METHOD("get_process_mode"), &Node::get_process_mode);
ClassDB::bind_method(D_METHOD("can_process"), &Node::can_process);
- ClassDB::bind_method(D_METHOD("print_orphan_nodes"), &Node::_print_orphan_nodes);
ClassDB::bind_method(D_METHOD("set_display_folded", "fold"), &Node::set_display_folded);
ClassDB::bind_method(D_METHOD("is_displayed_folded"), &Node::is_displayed_folded);
diff --git a/scene/main/node.h b/scene/main/node.h
index 8a2e6d3d65..574f5063e8 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -173,7 +173,6 @@ private:
void _propagate_ready();
void _propagate_exit_tree();
void _propagate_after_exit_tree();
- void _print_orphan_nodes();
void _propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification);
void _propagate_groups_dirty();
Array _get_node_and_resource(const NodePath &p_path);
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 81a4e3073b..ceb5b76ff2 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -123,9 +123,6 @@ void SceneTree::tree_changed() {
void SceneTree::node_added(Node *p_node) {
emit_signal(node_added_name, p_node);
- if (call_lock > 0) {
- call_skip.erase(p_node->get_instance_id());
- }
}
void SceneTree::node_removed(Node *p_node) {
@@ -134,7 +131,7 @@ void SceneTree::node_removed(Node *p_node) {
}
emit_signal(node_removed_name, p_node);
if (call_lock > 0) {
- call_skip.insert(p_node->get_instance_id());
+ call_skip.insert(p_node);
}
}
@@ -264,7 +261,7 @@ void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_gro
if (p_call_flags & GROUP_CALL_REVERSE) {
for (int i = gr_node_count - 1; i >= 0; i--) {
- if (call_lock && call_skip.has(gr_nodes[i]->get_instance_id())) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
@@ -278,7 +275,7 @@ void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_gro
} else {
for (int i = 0; i < gr_node_count; i++) {
- if (call_lock && call_skip.has(gr_nodes[i]->get_instance_id())) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
@@ -317,7 +314,7 @@ void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_gr
if (p_call_flags & GROUP_CALL_REVERSE) {
for (int i = gr_node_count - 1; i >= 0; i--) {
- if (call_lock && call_skip.has(gr_nodes[i]->get_instance_id())) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
@@ -330,7 +327,7 @@ void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_gr
} else {
for (int i = 0; i < gr_node_count; i++) {
- if (call_lock && call_skip.has(gr_nodes[i]->get_instance_id())) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
@@ -368,7 +365,7 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group
if (p_call_flags & GROUP_CALL_REVERSE) {
for (int i = gr_node_count - 1; i >= 0; i--) {
- if (call_lock && call_skip.has(gr_nodes[i]->get_instance_id())) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
@@ -381,7 +378,7 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group
} else {
for (int i = 0; i < gr_node_count; i++) {
- if (call_lock && call_skip.has(gr_nodes[i]->get_instance_id())) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
@@ -857,7 +854,7 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
for (int i = 0; i < gr_node_count; i++) {
Node *n = gr_nodes[i];
- if (call_lock && call_skip.has(n->get_instance_id())) {
+ if (call_lock && call_skip.has(n)) {
continue;
}
@@ -907,7 +904,7 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
}
Node *n = gr_nodes[i];
- if (call_lock && call_skip.has(n->get_instance_id())) {
+ if (call_lock && call_skip.has(n)) {
continue;
}
@@ -1450,7 +1447,7 @@ SceneTree::SceneTree() {
ProjectSettings::get_singleton()->set_custom_property_info("rendering/vrs/texture",
PropertyInfo(Variant::STRING,
"rendering/vrs/texture",
- PROPERTY_HINT_FILE, "*.png"));
+ PROPERTY_HINT_FILE, "*.bmp,*.png,*.tga,*.webp"));
if (vrs_mode == 1 && !vrs_texture_path.is_empty()) {
Ref<Image> vrs_image;
vrs_image.instantiate();
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index d4fcb288ae..a460e40597 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -135,7 +135,7 @@ private:
// Safety for when a node is deleted while a group is being called.
int call_lock = 0;
- HashSet<ObjectID> call_skip; // Skip erased nodes. Store ID instead of pointer to avoid false positives when node is freed and a new node is allocated at the pointed address.
+ HashSet<Node *> call_skip; // Skip erased nodes.
List<ObjectID> delete_queue;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 9e440405af..7430a0a835 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -362,6 +362,7 @@ void Viewport::_notification(int p_what) {
current_canvas = find_world_2d()->get_canvas();
RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, current_canvas, canvas_transform);
RenderingServer::get_singleton()->viewport_set_canvas_cull_mask(viewport, canvas_cull_mask);
_update_audio_listener_2d();
#ifndef _3D_DISABLED
@@ -491,6 +492,7 @@ void Viewport::_notification(int p_what) {
} break;
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
+ _gui_cancel_tooltip();
_drop_physics_mouseover();
if (gui.mouse_focus && !gui.forced_mouse_focus) {
_drop_mouse_focus();
@@ -2095,7 +2097,7 @@ List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) {
return gui.roots.push_back(p_control);
}
-void Viewport::_gui_set_root_order_dirty() {
+void Viewport::gui_set_root_order_dirty() {
gui.roots_order_dirty = true;
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index dc69ec24d8..5659ee4000 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -456,8 +456,6 @@ private:
void _update_canvas_items(Node *p_node);
- void _gui_set_root_order_dirty();
-
friend class Window;
void _sub_window_update_order();
@@ -514,6 +512,8 @@ public:
Transform2D get_final_transform() const;
+ void gui_set_root_order_dirty();
+
void set_transparent_background(bool p_enable);
bool has_transparent_background() const;
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index ef619c9893..ed9a709382 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -888,7 +888,6 @@ int Animation::add_track(TrackType p_type, int p_at_pos) {
}
}
emit_changed();
- emit_signal(SceneStringNames::get_singleton()->tracks_changed);
return p_at_pos;
}
@@ -951,7 +950,6 @@ void Animation::remove_track(int p_track) {
memdelete(t);
tracks.remove_at(p_track);
emit_changed();
- emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
int Animation::get_track_count() const {
@@ -967,7 +965,6 @@ void Animation::track_set_path(int p_track, const NodePath &p_path) {
ERR_FAIL_INDEX(p_track, tracks.size());
tracks[p_track]->path = p_path;
emit_changed();
- emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
NodePath Animation::track_get_path(int p_track) const {
@@ -2467,7 +2464,6 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol
ERR_FAIL_COND_V(idx == -2, T());
- bool result = true;
int next = 0;
real_t c = 0.0;
// prepare for all cases of interpolation
@@ -2599,10 +2595,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol
}
if (p_ok) {
- *p_ok = result;
- }
- if (!result) {
- return T();
+ *p_ok = true;
}
real_t tr = p_keys[idx].transition;
@@ -2712,106 +2705,6 @@ Variant Animation::value_track_interpolate(int p_track, double p_time) const {
return Variant();
}
-void Animation::_value_track_get_key_indices_in_range(const ValueTrack *vt, double from_time, double to_time, List<int> *p_indices) const {
- if (from_time != length && to_time == length) {
- to_time = length + CMP_EPSILON; //include a little more if at the end
- }
- int to = _find(vt->values, to_time);
-
- if (to >= 0 && from_time == to_time && vt->values[to].time == from_time) {
- //find exact (0 delta), return if found
- p_indices->push_back(to);
- return;
- }
- // can't really send the events == time, will be sent in the next frame.
- // if event>=len then it will probably never be requested by the anim player.
-
- if (to >= 0 && vt->values[to].time >= to_time) {
- to--;
- }
-
- if (to < 0) {
- return; // not bother
- }
-
- int from = _find(vt->values, from_time);
-
- // position in the right first event.+
- if (from < 0 || vt->values[from].time < from_time) {
- from++;
- }
-
- int max = vt->values.size();
-
- for (int i = from; i <= to; i++) {
- ERR_CONTINUE(i < 0 || i >= max); // shouldn't happen
- p_indices->push_back(i);
- }
-}
-
-void Animation::value_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged) const {
- ERR_FAIL_INDEX(p_track, tracks.size());
- Track *t = tracks[p_track];
- ERR_FAIL_COND(t->type != TYPE_VALUE);
-
- ValueTrack *vt = static_cast<ValueTrack *>(t);
-
- double from_time = p_time - p_delta;
- double to_time = p_time;
-
- if (from_time > to_time) {
- SWAP(from_time, to_time);
- }
-
- switch (loop_mode) {
- case LOOP_NONE: {
- if (from_time < 0) {
- from_time = 0;
- }
- if (from_time > length) {
- from_time = length;
- }
-
- if (to_time < 0) {
- to_time = 0;
- }
- if (to_time > length) {
- to_time = length;
- }
- } break;
- case LOOP_LINEAR: {
- from_time = Math::fposmod(from_time, length);
- to_time = Math::fposmod(to_time, length);
-
- if (from_time > to_time) {
- // handle loop by splitting
- _value_track_get_key_indices_in_range(vt, from_time, length, p_indices);
- _value_track_get_key_indices_in_range(vt, 0, to_time, p_indices);
- return;
- }
- } break;
- case LOOP_PINGPONG: {
- from_time = Math::pingpong(from_time, length);
- to_time = Math::pingpong(to_time, length);
-
- if (p_pingponged == -1) {
- // handle loop by splitting
- _value_track_get_key_indices_in_range(vt, 0, from_time, p_indices);
- _value_track_get_key_indices_in_range(vt, 0, to_time, p_indices);
- return;
- }
- if (p_pingponged == 1) {
- // handle loop by splitting
- _value_track_get_key_indices_in_range(vt, from_time, length, p_indices);
- _value_track_get_key_indices_in_range(vt, to_time, length, p_indices);
- return;
- }
- } break;
- }
-
- _value_track_get_key_indices_in_range(vt, from_time, to_time, p_indices);
-}
-
void Animation::value_track_set_update_mode(int p_track, UpdateMode p_mode) {
ERR_FAIL_INDEX(p_track, tracks.size());
Track *t = tracks[p_track];
@@ -2834,7 +2727,7 @@ Animation::UpdateMode Animation::value_track_get_update_mode(int p_track) const
template <class T>
void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices) const {
- if (from_time != length && to_time == length) {
+ if (to_time == length) {
to_time = length + CMP_EPSILON; //include a little more if at the end
}
@@ -2868,6 +2761,11 @@ void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, double
void Animation::track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged) const {
ERR_FAIL_INDEX(p_track, tracks.size());
+
+ if (p_delta == 0) {
+ return; // Prevent to get key continuously.
+ }
+
const Track *t = tracks[p_track];
double from_time = p_time - p_delta;
@@ -2984,86 +2882,88 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
if ((int)Math::floor(abs(p_delta) / length) % 2 == 0) {
if (p_pingponged == -1) {
// handle loop by splitting
+ to_time = MAX(CMP_EPSILON, to_time); // To avoid overlapping keys at the turnaround point, one of the point will needs to be shifted slightly.
switch (t->type) {
case TYPE_POSITION_3D: {
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
if (tt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, from_time, p_indices);
- _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, to_time, p_indices);
+ _get_compressed_key_indices_in_range<3>(tt->compressed_track, CMP_EPSILON, to_time, p_indices);
} else {
_track_get_key_indices_in_range(tt->positions, 0, from_time, p_indices);
- _track_get_key_indices_in_range(tt->positions, 0, to_time, p_indices);
+ _track_get_key_indices_in_range(tt->positions, CMP_EPSILON, to_time, p_indices);
}
} break;
case TYPE_ROTATION_3D: {
const RotationTrack *rt = static_cast<const RotationTrack *>(t);
if (rt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, from_time, p_indices);
- _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, to_time, p_indices);
+ _get_compressed_key_indices_in_range<3>(rt->compressed_track, CMP_EPSILON, to_time, p_indices);
} else {
_track_get_key_indices_in_range(rt->rotations, 0, from_time, p_indices);
- _track_get_key_indices_in_range(rt->rotations, 0, to_time, p_indices);
+ _track_get_key_indices_in_range(rt->rotations, CMP_EPSILON, to_time, p_indices);
}
} break;
case TYPE_SCALE_3D: {
const ScaleTrack *st = static_cast<const ScaleTrack *>(t);
if (st->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(st->compressed_track, 0, from_time, p_indices);
- _get_compressed_key_indices_in_range<3>(st->compressed_track, 0, to_time, p_indices);
+ _get_compressed_key_indices_in_range<3>(st->compressed_track, CMP_EPSILON, to_time, p_indices);
} else {
_track_get_key_indices_in_range(st->scales, 0, from_time, p_indices);
- _track_get_key_indices_in_range(st->scales, 0, to_time, p_indices);
+ _track_get_key_indices_in_range(st->scales, CMP_EPSILON, to_time, p_indices);
}
} break;
case TYPE_BLEND_SHAPE: {
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
if (bst->compressed_track >= 0) {
_get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, from_time, p_indices);
- _get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, to_time, p_indices);
+ _get_compressed_key_indices_in_range<1>(bst->compressed_track, CMP_EPSILON, to_time, p_indices);
} else {
_track_get_key_indices_in_range(bst->blend_shapes, 0, from_time, p_indices);
- _track_get_key_indices_in_range(bst->blend_shapes, 0, to_time, p_indices);
+ _track_get_key_indices_in_range(bst->blend_shapes, CMP_EPSILON, to_time, p_indices);
}
} break;
case TYPE_VALUE: {
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
_track_get_key_indices_in_range(vt->values, 0, from_time, p_indices);
- _track_get_key_indices_in_range(vt->values, 0, to_time, p_indices);
+ _track_get_key_indices_in_range(vt->values, CMP_EPSILON, to_time, p_indices);
} break;
case TYPE_METHOD: {
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
_track_get_key_indices_in_range(mt->methods, 0, from_time, p_indices);
- _track_get_key_indices_in_range(mt->methods, 0, to_time, p_indices);
+ _track_get_key_indices_in_range(mt->methods, CMP_EPSILON, to_time, p_indices);
} break;
case TYPE_BEZIER: {
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
_track_get_key_indices_in_range(bz->values, 0, from_time, p_indices);
- _track_get_key_indices_in_range(bz->values, 0, to_time, p_indices);
+ _track_get_key_indices_in_range(bz->values, CMP_EPSILON, to_time, p_indices);
} break;
case TYPE_AUDIO: {
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
_track_get_key_indices_in_range(ad->values, 0, from_time, p_indices);
- _track_get_key_indices_in_range(ad->values, 0, to_time, p_indices);
+ _track_get_key_indices_in_range(ad->values, CMP_EPSILON, to_time, p_indices);
} break;
case TYPE_ANIMATION: {
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
_track_get_key_indices_in_range(an->values, 0, from_time, p_indices);
- _track_get_key_indices_in_range(an->values, 0, to_time, p_indices);
+ _track_get_key_indices_in_range(an->values, CMP_EPSILON, to_time, p_indices);
} break;
}
return;
}
if (p_pingponged == 1) {
// handle loop by splitting
+ to_time = MIN(length - CMP_EPSILON, to_time);
switch (t->type) {
case TYPE_POSITION_3D: {
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
if (tt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, length, p_indices);
- _get_compressed_key_indices_in_range<3>(tt->compressed_track, to_time, length, p_indices);
+ _get_compressed_key_indices_in_range<3>(tt->compressed_track, to_time, length - CMP_EPSILON, p_indices);
} else {
_track_get_key_indices_in_range(tt->positions, from_time, length, p_indices);
- _track_get_key_indices_in_range(tt->positions, to_time, length, p_indices);
+ _track_get_key_indices_in_range(tt->positions, to_time, length - CMP_EPSILON, p_indices);
}
} break;
case TYPE_ROTATION_3D: {
@@ -3073,7 +2973,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
_get_compressed_key_indices_in_range<3>(rt->compressed_track, to_time, length, p_indices);
} else {
_track_get_key_indices_in_range(rt->rotations, from_time, length, p_indices);
- _track_get_key_indices_in_range(rt->rotations, to_time, length, p_indices);
+ _track_get_key_indices_in_range(rt->rotations, to_time, length - CMP_EPSILON, p_indices);
}
} break;
case TYPE_SCALE_3D: {
@@ -3083,43 +2983,43 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
_get_compressed_key_indices_in_range<3>(st->compressed_track, to_time, length, p_indices);
} else {
_track_get_key_indices_in_range(st->scales, from_time, length, p_indices);
- _track_get_key_indices_in_range(st->scales, to_time, length, p_indices);
+ _track_get_key_indices_in_range(st->scales, to_time, length - CMP_EPSILON, p_indices);
}
} break;
case TYPE_BLEND_SHAPE: {
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
if (bst->compressed_track >= 0) {
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices);
- _get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length, p_indices);
+ _get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length - CMP_EPSILON, p_indices);
} else {
_track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices);
- _track_get_key_indices_in_range(bst->blend_shapes, to_time, length, p_indices);
+ _track_get_key_indices_in_range(bst->blend_shapes, to_time, length - CMP_EPSILON, p_indices);
}
} break;
case TYPE_VALUE: {
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
_track_get_key_indices_in_range(vt->values, from_time, length, p_indices);
- _track_get_key_indices_in_range(vt->values, to_time, length, p_indices);
+ _track_get_key_indices_in_range(vt->values, to_time, length - CMP_EPSILON, p_indices);
} break;
case TYPE_METHOD: {
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
_track_get_key_indices_in_range(mt->methods, from_time, length, p_indices);
- _track_get_key_indices_in_range(mt->methods, to_time, length, p_indices);
+ _track_get_key_indices_in_range(mt->methods, to_time, length - CMP_EPSILON, p_indices);
} break;
case TYPE_BEZIER: {
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
_track_get_key_indices_in_range(bz->values, from_time, length, p_indices);
- _track_get_key_indices_in_range(bz->values, to_time, length, p_indices);
+ _track_get_key_indices_in_range(bz->values, to_time, length - CMP_EPSILON, p_indices);
} break;
case TYPE_AUDIO: {
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
_track_get_key_indices_in_range(ad->values, from_time, length, p_indices);
- _track_get_key_indices_in_range(ad->values, to_time, length, p_indices);
+ _track_get_key_indices_in_range(ad->values, to_time, length - CMP_EPSILON, p_indices);
} break;
case TYPE_ANIMATION: {
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
_track_get_key_indices_in_range(an->values, from_time, length, p_indices);
- _track_get_key_indices_in_range(an->values, to_time, length, p_indices);
+ _track_get_key_indices_in_range(an->values, to_time, length - CMP_EPSILON, p_indices);
} break;
}
return;
@@ -3184,110 +3084,6 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
}
}
-void Animation::_method_track_get_key_indices_in_range(const MethodTrack *mt, double from_time, double to_time, List<int> *p_indices) const {
- if (from_time != length && to_time == length) {
- to_time = length + CMP_EPSILON; //include a little more if at the end
- }
-
- int to = _find(mt->methods, to_time);
-
- // can't really send the events == time, will be sent in the next frame.
- // if event>=len then it will probably never be requested by the anim player.
-
- if (to >= 0 && mt->methods[to].time >= to_time) {
- to--;
- }
-
- if (to < 0) {
- return; // not bother
- }
-
- int from = _find(mt->methods, from_time);
-
- // position in the right first event.+
- if (from < 0 || mt->methods[from].time < from_time) {
- from++;
- }
-
- int max = mt->methods.size();
-
- for (int i = from; i <= to; i++) {
- ERR_CONTINUE(i < 0 || i >= max); // shouldn't happen
- p_indices->push_back(i);
- }
-}
-
-void Animation::method_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged) const {
- ERR_FAIL_INDEX(p_track, tracks.size());
- Track *t = tracks[p_track];
- ERR_FAIL_COND(t->type != TYPE_METHOD);
-
- MethodTrack *mt = static_cast<MethodTrack *>(t);
-
- double from_time = p_time - p_delta;
- double to_time = p_time;
-
- if (from_time > to_time) {
- SWAP(from_time, to_time);
- }
-
- switch (loop_mode) {
- case LOOP_NONE: {
- if (from_time < 0) {
- from_time = 0;
- }
- if (from_time > length) {
- from_time = length;
- }
-
- if (to_time < 0) {
- to_time = 0;
- }
- if (to_time > length) {
- to_time = length;
- }
- } break;
- case LOOP_LINEAR: {
- if (from_time > length || from_time < 0) {
- from_time = Math::fposmod(from_time, length);
- }
- if (to_time > length || to_time < 0) {
- to_time = Math::fposmod(to_time, length);
- }
-
- if (from_time > to_time) {
- // handle loop by splitting
- _method_track_get_key_indices_in_range(mt, from_time, length, p_indices);
- _method_track_get_key_indices_in_range(mt, 0, to_time, p_indices);
- return;
- }
- } break;
- case LOOP_PINGPONG: {
- if (from_time > length || from_time < 0) {
- from_time = Math::pingpong(from_time, length);
- }
- if (to_time > length || to_time < 0) {
- to_time = Math::pingpong(to_time, length);
- }
-
- if (p_pingponged == -1) {
- _method_track_get_key_indices_in_range(mt, 0, from_time, p_indices);
- _method_track_get_key_indices_in_range(mt, 0, to_time, p_indices);
- return;
- }
- if (p_pingponged == 1) {
- _method_track_get_key_indices_in_range(mt, from_time, length, p_indices);
- _method_track_get_key_indices_in_range(mt, to_time, length, p_indices);
- return;
- }
- } break;
- default:
- break;
- }
-
- _method_track_get_key_indices_in_range(mt, from_time, to_time, p_indices);
-}
-
Vector<Variant> Animation::method_track_get_params(int p_track, int p_key_idx) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), Vector<Variant>());
Track *t = tracks[p_track];
@@ -3834,7 +3630,6 @@ void Animation::track_move_up(int p_track) {
}
emit_changed();
- emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
void Animation::track_move_down(int p_track) {
@@ -3843,7 +3638,6 @@ void Animation::track_move_down(int p_track) {
}
emit_changed();
- emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
void Animation::track_move_to(int p_track, int p_to_index) {
@@ -3859,7 +3653,6 @@ void Animation::track_move_to(int p_track, int p_to_index) {
tracks.insert(p_to_index > p_track ? p_to_index - 1 : p_to_index, track);
emit_changed();
- emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
void Animation::track_swap(int p_track, int p_with_track) {
@@ -3871,7 +3664,6 @@ void Animation::track_swap(int p_track, int p_with_track) {
SWAP(tracks.write[p_track], tracks.write[p_with_track]);
emit_changed();
- emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
void Animation::set_step(real_t p_step) {
@@ -3952,10 +3744,8 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("value_track_set_update_mode", "track_idx", "mode"), &Animation::value_track_set_update_mode);
ClassDB::bind_method(D_METHOD("value_track_get_update_mode", "track_idx"), &Animation::value_track_get_update_mode);
- ClassDB::bind_method(D_METHOD("value_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_value_track_get_key_indices);
ClassDB::bind_method(D_METHOD("value_track_interpolate", "track_idx", "time_sec"), &Animation::value_track_interpolate);
- ClassDB::bind_method(D_METHOD("method_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_method_track_get_key_indices);
ClassDB::bind_method(D_METHOD("method_track_get_name", "track_idx", "key_idx"), &Animation::method_track_get_name);
ClassDB::bind_method(D_METHOD("method_track_get_params", "track_idx", "key_idx"), &Animation::method_track_get_params);
@@ -4001,8 +3791,6 @@ void Animation::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Ping-Pong"), "set_loop_mode", "get_loop_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step", PROPERTY_HINT_RANGE, "0,4096,0.001,suffix:s"), "set_step", "get_step");
- ADD_SIGNAL(MethodInfo("tracks_changed"));
-
BIND_ENUM_CONSTANT(TYPE_VALUE);
BIND_ENUM_CONSTANT(TYPE_POSITION_3D);
BIND_ENUM_CONSTANT(TYPE_ROTATION_3D);
@@ -4041,7 +3829,6 @@ void Animation::clear() {
compression.pages.clear();
compression.fps = 120;
emit_changed();
- emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
bool Animation::_float_track_optimize_key(const TKey<float> t0, const TKey<float> t1, const TKey<float> t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) {
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 49c8fa4c22..6c1ca3cd05 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -252,9 +252,6 @@ private:
template <class T>
_FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices) const;
- _FORCE_INLINE_ void _value_track_get_key_indices_in_range(const ValueTrack *vt, double from_time, double to_time, List<int> *p_indices) const;
- _FORCE_INLINE_ void _method_track_get_key_indices_in_range(const MethodTrack *mt, double from_time, double to_time, List<int> *p_indices) const;
-
double length = 1.0;
real_t step = 0.1;
LoopMode loop_mode = LOOP_NONE;
@@ -345,27 +342,6 @@ private:
// bind helpers
private:
- Vector<int> _value_track_get_key_indices(int p_track, double p_time, double p_delta) const {
- List<int> idxs;
- value_track_get_key_indices(p_track, p_time, p_delta, &idxs);
- Vector<int> idxr;
-
- for (int &E : idxs) {
- idxr.push_back(E);
- }
- return idxr;
- }
- Vector<int> _method_track_get_key_indices(int p_track, double p_time, double p_delta) const {
- List<int> idxs;
- method_track_get_key_indices(p_track, p_time, p_delta, &idxs);
- Vector<int> idxr;
-
- for (int &E : idxs) {
- idxr.push_back(E);
- }
- return idxr;
- }
-
bool _float_track_optimize_key(const TKey<float> t0, const TKey<float> t1, const TKey<float> t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error);
bool _vector2_track_optimize_key(const TKey<Vector2> t0, const TKey<Vector2> t1, const TKey<Vector2> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
bool _vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<Vector3> t1, const TKey<Vector3> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
@@ -470,11 +446,9 @@ public:
bool track_get_interpolation_loop_wrap(int p_track) const;
Variant value_track_interpolate(int p_track, double p_time) const;
- void value_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged = 0) const;
void value_track_set_update_mode(int p_track, UpdateMode p_mode);
UpdateMode value_track_get_update_mode(int p_track) const;
- void method_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged = 0) const;
Vector<Variant> method_track_get_params(int p_track, int p_key_idx) const;
StringName method_track_get_name(int p_track, int p_key_idx) const;
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 4afc82576d..0df61871d8 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -169,14 +169,6 @@ Dictionary BitMap::_get_data() const {
return d;
}
-struct CrossStackEntry {
- Point2i cross;
- Vector<int> ranges;
-
- _FORCE_INLINE_ bool operator==(const CrossStackEntry &p_other) const { return cross == p_other.cross; }
- _FORCE_INLINE_ bool operator!=(const CrossStackEntry &p_other) const { return cross != p_other.cross; }
-};
-
Vector<Vector<Vector2>> BitMap::_march_square(const Rect2i &p_rect, const Point2i &p_start) const {
int stepx = 0;
int stepy = 0;
@@ -188,14 +180,11 @@ Vector<Vector<Vector2>> BitMap::_march_square(const Rect2i &p_rect, const Point2
int cury = starty;
unsigned int count = 0;
- Vector<CrossStackEntry> cross_stack;
- int cross_stack_size = 0;
+ HashMap<Point2i, int> cross_map;
- // Add starting point to stack as the default entry.
- cross_stack.push_back({ Point2i(-1, -1), Vector<int>({ 0 }) });
- cross_stack_size++;
+ Vector<Vector2> _points;
+ int points_size = 0;
- Vector<Point2i> _points;
Vector<Vector<Vector2>> ret;
// Add starting entry at start of return.
@@ -326,52 +315,25 @@ Vector<Vector<Vector2>> BitMap::_march_square(const Rect2i &p_rect, const Point2
// Handle crossing points.
if (sv == 6 || sv == 9) {
- const int new_index = _points.size() - 1;
-
- // Add previous point to last stack entry.
- cross_stack.write[cross_stack_size - 1].ranges.push_back(new_index);
-
- // Create temporary entry to maybe insert, for searching.
- const CrossStackEntry new_entry = { _points[new_index], Vector<int>({ new_index }) };
-
- // Attempt to find matching entry.
- const int found = cross_stack.rfind(new_entry, cross_stack_size - 1);
+ const Point2i cur_pos(curx, cury);
- if (found != -1) {
- Vector<Vector2> tmp;
+ // Find if this point has occured before.
+ if (HashMap<Point2i, int>::Iterator found = cross_map.find(cur_pos)) {
+ // Add points after the previous crossing to the result.
+ ret.push_back(_points.slice(found->value + 1, points_size));
- // Iterate over entries between end of stack and found, adding ranges to result.
- for (int i = found; i < cross_stack_size; i++) {
- const Vector<int> &ranges = cross_stack[i].ranges;
+ // Remove points after crossing point.
+ points_size = found->value + 1;
- for (int j = 0; j < ranges.size() / 2; j++) {
- int first = ranges[2 * j];
- const int last = ranges[2 * j + 1];
-
- int new_pos = tmp.size();
-
- tmp.resize(tmp.size() + (last - first));
-
- Vector2 *tmp_ptrw = tmp.ptrw();
-
- for (; first < last; first++, new_pos++) {
- tmp_ptrw[new_pos].x = (float)(_points[first].x - p_rect.position.x);
- tmp_ptrw[new_pos].y = (float)(_points[first].y - p_rect.position.y);
- }
- }
+ // Erase trailing map elements.
+ while (cross_map.last() != found) {
+ cross_map.remove(cross_map.last());
}
- ret.push_back(tmp);
-
- // Shrink stack.
- cross_stack_size = found;
-
- // Add previous point to last stack entry.
- cross_stack.write[cross_stack_size - 1].ranges.push_back(new_index);
+ cross_map.erase(cur_pos);
} else {
- cross_stack.resize(MAX(cross_stack_size + 1, cross_stack.size()));
- cross_stack.set(cross_stack_size, new_entry);
- cross_stack_size++;
+ // Add crossing point to map.
+ cross_map.insert(cur_pos, points_size - 1);
}
}
@@ -381,10 +343,11 @@ Vector<Vector<Vector2>> BitMap::_march_square(const Rect2i &p_rect, const Point2
curx += stepx;
cury += stepy;
if (stepx == prevx && stepy == prevy) {
- _points.write[_points.size() - 1].x = curx;
- _points.write[_points.size() - 1].y = cury;
+ _points.set(points_size - 1, Vector2(curx, cury) - p_rect.position);
} else {
- _points.push_back(Point2i(curx, cury));
+ _points.resize(MAX(points_size + 1, _points.size()));
+ _points.set(points_size, Vector2(curx, cury) - p_rect.position);
+ points_size++;
}
count++;
@@ -394,28 +357,10 @@ Vector<Vector<Vector2>> BitMap::_march_square(const Rect2i &p_rect, const Point2
ERR_FAIL_COND_V((int)count > width * height, Vector<Vector<Vector2>>());
} while (curx != startx || cury != starty);
- // Add last position to last stack entry.
- cross_stack.write[cross_stack_size - 1].ranges.push_back(_points.size());
-
- for (int i = 0; i < cross_stack_size; i++) {
- const Vector<int> &ranges = cross_stack[i].ranges;
-
- for (int j = 0; j < ranges.size() / 2; j++) {
- int first = ranges[2 * j];
- const int last = ranges[2 * j + 1];
-
- int new_pos = ret[0].size();
+ // Add remaining points to result.
+ _points.resize(points_size);
- ret.write[0].resize(ret[0].size() + (last - first));
-
- Vector2 *tmp_ptrw = ret.write[0].ptrw();
-
- for (; first < last; first++, new_pos++) {
- tmp_ptrw[new_pos].x = (float)(_points[first].x - p_rect.position.x);
- tmp_ptrw[new_pos].y = (float)(_points[first].y - p_rect.position.y);
- }
- }
- }
+ ret.set(0, _points);
return ret;
}
diff --git a/scene/resources/camera_attributes.cpp b/scene/resources/camera_attributes.cpp
index 3c322f32b6..8e4876e01f 100644
--- a/scene/resources/camera_attributes.cpp
+++ b/scene/resources/camera_attributes.cpp
@@ -120,7 +120,7 @@ void CameraAttributes::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_auto_exposure_scale", "exposure_grey"), &CameraAttributes::set_auto_exposure_scale);
ClassDB::bind_method(D_METHOD("get_auto_exposure_scale"), &CameraAttributes::get_auto_exposure_scale);
- ADD_GROUP("Exposure", "exposure");
+ ADD_GROUP("Exposure", "exposure_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_sensitivity", PROPERTY_HINT_RANGE, "0.1,32000.0,0.1,suffix:ISO"), "set_exposure_sensitivity", "get_exposure_sensitivity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_multiplier", PROPERTY_HINT_RANGE, "0.0,2048.0,0.001"), "set_exposure_multiplier", "get_exposure_multiplier");
@@ -472,7 +472,7 @@ void CameraAttributesPhysical::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp,suffix:m"), "set_near", "get_near");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp,suffix:m"), "set_far", "get_far");
- ADD_GROUP("Exposure", "exposure");
+ ADD_GROUP("Exposure", "exposure_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_aperture", PROPERTY_HINT_RANGE, "0.5,64.0,0.01,exp,suffix:f-stop"), "set_aperture", "get_aperture");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_shutter_speed", PROPERTY_HINT_RANGE, "0.1,8000.0,0.001,suffix:1/s"), "set_shutter_speed", "get_shutter_speed");
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 0c36abc148..9289c5da4a 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -1403,6 +1403,22 @@ void Curve3D::_bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, re
}
}
+void Curve3D::_bake_segment3d_even_length(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_length) const {
+ Vector3 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
+ Vector3 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
+
+ size_t length = beg.distance_to(end);
+
+ if (length > p_length && p_depth < p_max_depth) {
+ real_t mp = (p_begin + p_end) * 0.5;
+ Vector3 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
+ r_bake[mp] = mid;
+
+ _bake_segment3d(r_bake, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_length);
+ _bake_segment3d(r_bake, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_length);
+ }
+}
+
void Curve3D::_bake() const {
if (!baked_cache_dirty) {
return;
@@ -1416,6 +1432,7 @@ void Curve3D::_bake() const {
baked_tilt_cache.clear();
baked_dist_cache.clear();
+ baked_forward_vector_cache.clear();
baked_up_vector_cache.clear();
return;
}
@@ -1427,10 +1444,12 @@ void Curve3D::_bake() const {
baked_tilt_cache.set(0, points[0].tilt);
baked_dist_cache.resize(1);
baked_dist_cache.set(0, 0.0);
+ baked_forward_vector_cache.resize(1);
+ baked_forward_vector_cache.set(0, Vector3(0.0, 0.0, 1.0));
if (up_vector_enabled) {
baked_up_vector_cache.resize(1);
- baked_up_vector_cache.set(0, Vector3(0, 1, 0));
+ baked_up_vector_cache.set(0, Vector3(0.0, 1.0, 0.0));
} else {
baked_up_vector_cache.clear();
}
@@ -1438,101 +1457,52 @@ void Curve3D::_bake() const {
return;
}
- Vector3 position = points[0].position;
- real_t dist = 0.0;
- List<Plane> pointlist; // Abuse Plane for (position, dist)
- List<real_t> distlist;
-
- // Start always from origin.
- pointlist.push_back(Plane(position, points[0].tilt));
- distlist.push_back(0.0);
-
- // Step 1: Sample points
- const real_t step = 0.1; // At least 10 substeps ought to be enough?
- for (int i = 0; i < points.size() - 1; i++) {
- real_t p = 0.0;
-
- while (p < 1.0) {
- real_t np = p + step;
- if (np > 1.0) {
- np = 1.0;
- }
-
- Vector3 npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, np);
- real_t d = position.distance_to(npp);
-
- if (d > bake_interval) {
- // OK! between P and NP there _has_ to be Something, let's go searching!
-
- const int iterations = 10; // Lots of detail!
-
- real_t low = p;
- real_t hi = np;
- real_t mid = low + (hi - low) * 0.5;
-
- for (int j = 0; j < iterations; j++) {
- npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, mid);
- d = position.distance_to(npp);
-
- if (bake_interval < d) {
- hi = mid;
- } else {
- low = mid;
- }
- mid = low + (hi - low) * 0.5;
- }
-
- position = npp;
- p = mid;
- Plane post;
- post.normal = position;
- post.d = Math::lerp(points[i].tilt, points[i + 1].tilt, mid);
- dist += d;
+ // Step 1: Tesselate curve to (almost) even length segments
+ {
+ Vector<RBMap<real_t, Vector3>> midpoints = _tessellate_even_length(10, bake_interval);
- pointlist.push_back(post);
- distlist.push_back(dist);
- } else {
- p = np;
- }
+ int pc = 1;
+ for (int i = 0; i < points.size() - 1; i++) {
+ pc++;
+ pc += midpoints[i].size();
}
- Vector3 npp = points[i + 1].position;
- real_t d = position.distance_to(npp);
-
- if (d > CMP_EPSILON) { // Avoid the degenerate case of two very close points.
- position = npp;
- Plane post;
- post.normal = position;
- post.d = points[i + 1].tilt;
-
- dist += d;
+ baked_point_cache.resize(pc);
+ baked_tilt_cache.resize(pc);
+ baked_dist_cache.resize(pc);
+ baked_forward_vector_cache.resize(pc);
+
+ Vector3 *bpw = baked_point_cache.ptrw();
+ real_t *btw = baked_tilt_cache.ptrw();
+ Vector3 *bfw = baked_forward_vector_cache.ptrw();
+
+ // Collect positions and sample tilts and tangents for each baked points.
+ bpw[0] = points[0].position;
+ bfw[0] = points[0].position.bezier_derivative(points[0].position + points[0].out, points[1].position + points[1].in, points[1].position, 0.0).normalized();
+ btw[0] = points[0].tilt;
+ int pidx = 0;
+
+ for (int i = 0; i < points.size() - 1; i++) {
+ for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
+ pidx++;
+ bpw[pidx] = E.value;
+ bfw[pidx] = points[i].position.bezier_derivative(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key).normalized();
+ btw[pidx] = Math::lerp(points[i].tilt, points[i + 1].tilt, E.key);
+ }
- pointlist.push_back(post);
- distlist.push_back(dist);
+ pidx++;
+ bpw[pidx] = points[i + 1].position;
+ bfw[pidx] = points[i].position.bezier_derivative(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0).normalized();
+ btw[pidx] = points[i + 1].tilt;
}
- }
-
- baked_max_ofs = dist;
-
- const int point_count = pointlist.size();
- {
- baked_point_cache.resize(point_count);
- Vector3 *w = baked_point_cache.ptrw();
-
- baked_tilt_cache.resize(point_count);
- real_t *wt = baked_tilt_cache.ptrw();
-
- baked_dist_cache.resize(point_count);
- real_t *wd = baked_dist_cache.ptrw();
-
- int idx = 0;
- for (const Plane &E : pointlist) {
- w[idx] = E.normal;
- wt[idx] = E.d;
- wd[idx] = distlist[idx];
- idx++;
+ // Recalculate the baked distances.
+ real_t *bdw = baked_dist_cache.ptrw();
+ bdw[0] = 0.0;
+ for (int i = 0; i < pc - 1; i++) {
+ bdw[i + 1] = bdw[i] + bpw[i].distance_to(bpw[i + 1]);
}
+ baked_max_ofs = bdw[pc - 1];
}
if (!up_vector_enabled) {
@@ -1545,14 +1515,12 @@ void Curve3D::_bake() const {
// See Dougan, Carl. "The parallel transport frame." Game Programming Gems 2 (2001): 215-219.
// for an example discussing about why not the Frenet frame.
{
- PackedVector3Array forward_vectors;
+ int point_count = baked_point_cache.size();
baked_up_vector_cache.resize(point_count);
- forward_vectors.resize(point_count);
-
Vector3 *up_write = baked_up_vector_cache.ptrw();
- Vector3 *forward_write = forward_vectors.ptrw();
+ const Vector3 *forward_ptr = baked_forward_vector_cache.ptr();
const Vector3 *points_ptr = baked_point_cache.ptr();
Basis frame; // X-right, Y-up, Z-forward.
@@ -1560,28 +1528,20 @@ void Curve3D::_bake() const {
// Set the initial frame based on Y-up rule.
{
- Vector3 up(0, 1, 0);
- Vector3 forward = (points_ptr[1] - points_ptr[0]).normalized();
- if (forward.is_equal_approx(Vector3())) {
- forward = Vector3(1, 0, 0);
- }
+ Vector3 forward = forward_ptr[0];
- if (abs(forward.dot(up)) > 1.0 - UNIT_EPSILON) {
- frame_prev = Basis::looking_at(-forward, up);
- } else {
+ if (abs(forward.dot(Vector3(0, 1, 0))) > 1.0 - UNIT_EPSILON) {
frame_prev = Basis::looking_at(-forward, Vector3(1, 0, 0));
+ } else {
+ frame_prev = Basis::looking_at(-forward, Vector3(0, 1, 0));
}
up_write[0] = frame_prev.get_column(1);
- forward_write[0] = frame_prev.get_column(2);
}
// Calculate the Parallel Transport Frame.
for (int idx = 1; idx < point_count; idx++) {
- Vector3 forward = (points_ptr[idx] - points_ptr[idx - 1]).normalized();
- if (forward.is_equal_approx(Vector3())) {
- forward = frame_prev.get_column(2);
- }
+ Vector3 forward = forward_ptr[idx];
Basis rotate;
rotate.rotate_to_align(frame_prev.get_column(2), forward);
@@ -1589,8 +1549,6 @@ void Curve3D::_bake() const {
frame.orthonormalize(); // guard against float error accumulation
up_write[idx] = frame.get_column(1);
- forward_write[idx] = frame.get_column(2);
-
frame_prev = frame;
}
@@ -1601,8 +1559,8 @@ void Curve3D::_bake() const {
is_loop = false;
}
- real_t dot = forward_write[0].dot(forward_write[point_count - 1]);
- if (dot < 1.0 - 0.01) { // Alignment should not be too tight, or it dosen't work for coarse bake interval
+ real_t dot = forward_ptr[0].dot(forward_ptr[point_count - 1]);
+ if (dot < 1.0 - UNIT_EPSILON) { // Alignment should not be too tight, or it dosen't work for coarse bake interval.
is_loop = false;
}
}
@@ -1612,17 +1570,17 @@ void Curve3D::_bake() const {
const Vector3 up_start = up_write[0];
const Vector3 up_end = up_write[point_count - 1];
- real_t sign = SIGN(up_end.cross(up_start).dot(forward_write[0]));
+ real_t sign = SIGN(up_end.cross(up_start).dot(forward_ptr[0]));
real_t full_angle = Quaternion(up_end, up_start).get_angle();
- if (abs(full_angle) < UNIT_EPSILON) {
+ if (abs(full_angle) < CMP_EPSILON) {
return;
} else {
const real_t *dists = baked_dist_cache.ptr();
for (int idx = 1; idx < point_count; idx++) {
const real_t frac = dists[idx] / baked_max_ofs;
const real_t angle = Math::lerp((real_t)0.0, full_angle, frac);
- Basis twist(forward_write[idx] * sign, angle);
+ Basis twist(forward_ptr[idx] * sign, angle);
up_write[idx] = twist.xform(up_write[idx]);
}
@@ -1720,22 +1678,14 @@ Basis Curve3D::_sample_posture(Interval p_interval, bool p_apply_tilt) const {
int idx = p_interval.idx;
real_t frac = p_interval.frac;
- Vector3 forward_begin;
- Vector3 forward_end;
- if (idx == 0) {
- forward_begin = (baked_point_cache[1] - baked_point_cache[0]).normalized();
- forward_end = (baked_point_cache[1] - baked_point_cache[0]).normalized();
- } else {
- forward_begin = (baked_point_cache[idx] - baked_point_cache[idx - 1]).normalized();
- forward_end = (baked_point_cache[idx + 1] - baked_point_cache[idx]).normalized();
- }
+ Vector3 forward_begin = baked_forward_vector_cache[idx];
+ Vector3 forward_end = baked_forward_vector_cache[idx + 1];
Vector3 up_begin;
Vector3 up_end;
if (up_vector_enabled) {
- const Vector3 *up_ptr = baked_up_vector_cache.ptr();
- up_begin = up_ptr[idx];
- up_end = up_ptr[idx + 1];
+ up_begin = baked_up_vector_cache[idx];
+ up_end = baked_up_vector_cache[idx + 1];
} else {
up_begin = Vector3(0.0, 1.0, 0.0);
up_end = Vector3(0.0, 1.0, 0.0);
@@ -2046,6 +1996,50 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
return tess;
}
+Vector<RBMap<real_t, Vector3>> Curve3D::_tessellate_even_length(int p_max_stages, real_t p_length) const {
+ Vector<RBMap<real_t, Vector3>> midpoints;
+ ERR_FAIL_COND_V_MSG(points.size() < 2, midpoints, "Curve must have at least 2 control point");
+
+ midpoints.resize(points.size() - 1);
+
+ for (int i = 0; i < points.size() - 1; i++) {
+ _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_length);
+ }
+ return midpoints;
+}
+
+PackedVector3Array Curve3D::tessellate_even_length(int p_max_stages, real_t p_length) const {
+ PackedVector3Array tess;
+
+ Vector<RBMap<real_t, Vector3>> midpoints = _tessellate_even_length(p_max_stages, p_length);
+ if (midpoints.size() == 0) {
+ return tess;
+ }
+
+ int pc = 1;
+ for (int i = 0; i < points.size() - 1; i++) {
+ pc++;
+ pc += midpoints[i].size();
+ }
+
+ tess.resize(pc);
+ Vector3 *bpw = tess.ptrw();
+ bpw[0] = points[0].position;
+ int pidx = 0;
+
+ for (int i = 0; i < points.size() - 1; i++) {
+ for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
+ pidx++;
+ bpw[pidx] = E.value;
+ }
+
+ pidx++;
+ bpw[pidx] = points[i + 1].position;
+ }
+
+ return tess;
+}
+
bool Curve3D::_set(const StringName &p_name, const Variant &p_value) {
Vector<String> components = String(p_name).split("/", true, 2);
if (components.size() >= 2 && components[0].begins_with("point_") && components[0].trim_prefix("point_").is_valid_int()) {
@@ -2146,6 +2140,7 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve3D::get_closest_point);
ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve3D::get_closest_offset);
ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve3D::tessellate, DEFVAL(5), DEFVAL(4));
+ ClassDB::bind_method(D_METHOD("tessellate_even_length", "max_stages", "tolerance_length"), &Curve3D::tessellate_even_length, DEFVAL(5), DEFVAL(0.2));
ClassDB::bind_method(D_METHOD("_get_data"), &Curve3D::_get_data);
ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve3D::_set_data);
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index d0c813f262..88c3cf3ae6 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -242,6 +242,7 @@ class Curve3D : public Resource {
mutable PackedVector3Array baked_point_cache;
mutable Vector<real_t> baked_tilt_cache;
mutable PackedVector3Array baked_up_vector_cache;
+ mutable PackedVector3Array baked_forward_vector_cache;
mutable Vector<real_t> baked_dist_cache;
mutable real_t baked_max_ofs = 0.0;
@@ -262,6 +263,7 @@ class Curve3D : public Resource {
bool up_vector_enabled = true;
void _bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const;
+ void _bake_segment3d_even_length(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_length) const;
Dictionary _get_data() const;
void _set_data(const Dictionary &p_data);
@@ -272,6 +274,8 @@ class Curve3D : public Resource {
void _add_point(const Vector3 &p_position, const Vector3 &p_in = Vector3(), const Vector3 &p_out = Vector3(), int p_atpos = -1);
void _remove_point(int p_index);
+ Vector<RBMap<real_t, Vector3>> _tessellate_even_length(int p_max_stages = 5, real_t p_length = 0.2) const;
+
protected:
static void _bind_methods();
@@ -309,7 +313,8 @@ public:
Vector3 get_closest_point(const Vector3 &p_to_point) const;
real_t get_closest_offset(const Vector3 &p_to_point) const;
- PackedVector3Array tessellate(int p_max_stages = 5, real_t p_tolerance = 4) const; //useful for display
+ PackedVector3Array tessellate(int p_max_stages = 5, real_t p_tolerance = 4) const; // Useful for display.
+ PackedVector3Array tessellate_even_length(int p_max_stages = 5, real_t p_length = 0.2) const; // Useful for baking.
Curve3D();
};
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 894936acd7..f179b4b818 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -84,7 +84,8 @@ static Ref<ImageTexture> generate_icon(int p_index) {
// with integer scales.
const bool upsample = !Math::is_equal_approx(Math::round(scale), scale);
ImageLoaderSVG img_loader;
- img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, HashMap<Color, Color>());
+ Error err = img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, HashMap<Color, Color>());
+ ERR_FAIL_COND_V_MSG(err != OK, Ref<ImageTexture>(), "Failed generating icon, unsupported or invalid SVG data in default theme.");
#endif
return ImageTexture::create_from_image(img);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 84814d939b..af51d6539e 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -1016,7 +1016,7 @@ void FontFile::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_oversampling", "get_oversampling");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_fixed_size", "get_fixed_size");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "opentype_feature_overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_opentype_feature_overrides", "get_opentype_feature_overrides");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font"), PROPERTY_USAGE_STORAGE), "set_fallbacks", "get_fallbacks");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font"), PROPERTY_USAGE_STORAGE), "set_fallbacks", "get_fallbacks");
}
bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
@@ -2603,18 +2603,18 @@ void FontVariation::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_spacing", "spacing", "value"), &FontVariation::set_spacing);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_base_font", "get_base_font");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), "set_fallbacks", "get_fallbacks");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")), "set_fallbacks", "get_fallbacks");
- ADD_GROUP("Variation", "variation");
+ ADD_GROUP("Variation", "variation_");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "variation_opentype"), "set_variation_opentype", "get_variation_opentype");
ADD_PROPERTY(PropertyInfo(Variant::INT, "variation_face_index"), "set_variation_face_index", "get_variation_face_index");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "variation_embolden", PROPERTY_HINT_RANGE, "-2,2,0.01"), "set_variation_embolden", "get_variation_embolden");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "variation_transform", PROPERTY_HINT_NONE, "suffix:px"), "set_variation_transform", "get_variation_transform");
- ADD_GROUP("OpenType Features", "opentype");
+ ADD_GROUP("OpenType Features", "opentype_");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "opentype_features"), "set_opentype_features", "get_opentype_features");
- ADD_GROUP("Extra Spacing", "spacing");
+ ADD_GROUP("Extra Spacing", "spacing_");
ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_glyph", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_GLYPH);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_space", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_SPACE);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_top", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_TOP);
@@ -2868,7 +2868,7 @@ void SystemFont::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel"), "set_subpixel_positioning", "get_subpixel_positioning");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field"), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), "set_oversampling", "get_oversampling");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), "set_fallbacks", "get_fallbacks");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")), "set_fallbacks", "get_fallbacks");
}
void SystemFont::_update_rids() const {
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index cec5569345..d1278f9340 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -971,10 +971,10 @@ Vector<Ref<Shape3D>> ImporterMesh::convex_decompose(const Mesh::ConvexDecomposit
return ret;
}
-Ref<Shape3D> ImporterMesh::create_trimesh_shape() const {
+Ref<ConcavePolygonShape3D> ImporterMesh::create_trimesh_shape() const {
Vector<Face3> faces = get_faces();
if (faces.size() == 0) {
- return Ref<Shape3D>();
+ return Ref<ConcavePolygonShape3D>();
}
Vector<Vector3> face_points;
diff --git a/scene/resources/importer_mesh.h b/scene/resources/importer_mesh.h
index 088a77edd1..bbd6498fcf 100644
--- a/scene/resources/importer_mesh.h
+++ b/scene/resources/importer_mesh.h
@@ -119,7 +119,7 @@ public:
Vector<Face3> get_faces() const;
Vector<Ref<Shape3D>> convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const;
- Ref<Shape3D> create_trimesh_shape() const;
+ Ref<ConcavePolygonShape3D> create_trimesh_shape() const;
Ref<NavigationMesh> create_navigation_mesh();
Error lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache);
diff --git a/scene/resources/label_settings.cpp b/scene/resources/label_settings.cpp
index ef380a68f9..c49620ce27 100644
--- a/scene/resources/label_settings.cpp
+++ b/scene/resources/label_settings.cpp
@@ -66,16 +66,16 @@ void LabelSettings::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "line_spacing", PROPERTY_HINT_NONE, "suffix:px"), "set_line_spacing", "get_line_spacing");
- ADD_GROUP("Font", "font");
+ ADD_GROUP("Font", "font_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_font", "get_font");
ADD_PROPERTY(PropertyInfo(Variant::INT, "font_size", PROPERTY_HINT_RANGE, "1,1024,1,or_greater,suffix:px"), "set_font_size", "get_font_size");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "font_color"), "set_font_color", "get_font_color");
- ADD_GROUP("Outline", "outline");
+ ADD_GROUP("Outline", "outline_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_size", PROPERTY_HINT_RANGE, "0,127,1,or_greater,suffix:px"), "set_outline_size", "get_outline_size");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "outline_color"), "set_outline_color", "get_outline_color");
- ADD_GROUP("Shadow", "shadow");
+ ADD_GROUP("Shadow", "shadow_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_size", PROPERTY_HINT_RANGE, "0,127,1,or_greater,suffix:px"), "set_shadow_size", "get_shadow_size");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shadow_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_shadow_offset", "get_shadow_offset");
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index d1e300e057..4f68a6f69b 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -388,7 +388,7 @@ Vector<Face3> Mesh::get_surface_faces(int p_surface) const {
return Vector<Face3>();
}
-Ref<Shape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const {
+Ref<ConvexPolygonShape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const {
if (p_simplify) {
ConvexDecompositionSettings settings;
settings.max_convex_hulls = 1;
@@ -425,10 +425,10 @@ Ref<Shape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const {
return shape;
}
-Ref<Shape3D> Mesh::create_trimesh_shape() const {
+Ref<ConcavePolygonShape3D> Mesh::create_trimesh_shape() const {
Vector<Face3> faces = get_faces();
if (faces.size() == 0) {
- return Ref<Shape3D>();
+ return Ref<ConcavePolygonShape3D>();
}
Vector<Vector3> face_points;
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 5ed4164117..6f995280e8 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -35,9 +35,12 @@
#include "core/math/face3.h"
#include "core/math/triangle_mesh.h"
#include "scene/resources/material.h"
-#include "scene/resources/shape_3d.h"
#include "servers/rendering_server.h"
+class ConcavePolygonShape3D;
+class ConvexPolygonShape3D;
+class Shape3D;
+
class Mesh : public Resource {
GDCLASS(Mesh, Resource);
@@ -211,8 +214,8 @@ public:
static ConvexDecompositionFunc convex_decomposition_function;
Vector<Ref<Shape3D>> convex_decompose(const ConvexDecompositionSettings &p_settings) const;
- Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
- Ref<Shape3D> create_trimesh_shape() const;
+ Ref<ConvexPolygonShape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
+ Ref<ConcavePolygonShape3D> create_trimesh_shape() const;
virtual int get_builtin_bind_pose_count() const;
virtual Transform3D get_builtin_bind_pose(int p_index) const;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 4c6d533c72..2e8fcb3717 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -2779,13 +2779,7 @@ void TextMesh::_generate_glyph_mesh_data(const GlyphMeshKey &p_key, const Glyph
real_t step = CLAMP(curve_step / (p0 - p3).length(), 0.01, 0.5);
real_t t = step;
while (t < 1.0) {
- real_t omt = (1.0 - t);
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = t * t;
- real_t t3 = t2 * t;
-
- Vector2 point = p0 * omt3 + p1 * omt2 * t * 3.0 + p2 * omt * t2 * 3.0 + p3 * t3;
+ Vector2 point = p0.bezier_interpolate(p1, p2, p3, t);
Vector2 p = point * pixel_size + origin;
polygon.push_back(ContourPoint(p, false));
t += step;
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index d4ad81614d..9d2537bb4d 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -4363,6 +4363,7 @@ int TileSetAtlasSource::create_alternative_tile(const Vector2i p_atlas_coords, i
tiles[p_atlas_coords].alternatives[new_alternative_id] = memnew(TileData);
tiles[p_atlas_coords].alternatives[new_alternative_id]->set_tile_set(tile_set);
tiles[p_atlas_coords].alternatives[new_alternative_id]->set_allow_transform(true);
+ tiles[p_atlas_coords].alternatives[new_alternative_id]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
tiles[p_atlas_coords].alternatives[new_alternative_id]->notify_property_list_changed();
tiles[p_atlas_coords].alternatives_ids.append(new_alternative_id);
tiles[p_atlas_coords].alternatives_ids.sort();
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index a15c03d675..bc7918c662 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -206,8 +206,6 @@ SceneStringNames::SceneStringNames() {
theme_changed = StaticCString::create("theme_changed");
parameters_base_path = "parameters/";
- tracks_changed = "tracks_changed";
-
shader_overrides_group = StaticCString::create("_shader_overrides_group_");
shader_overrides_group_active = StaticCString::create("_shader_overrides_group_active_");
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 5589ab327f..7ff866cacd 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -209,8 +209,6 @@ public:
StringName parameters_base_path;
- StringName tracks_changed;
-
StringName _window_group;
StringName _window_input;
StringName _window_unhandled_input;