summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/camera_2d.cpp2
-rw-r--r--scene/2d/path_2d.cpp1
-rw-r--r--scene/3d/path_3d.cpp1
-rw-r--r--scene/3d/skeleton_3d.cpp4
-rw-r--r--scene/animation/animation_blend_space_1d.cpp23
-rw-r--r--scene/animation/animation_blend_space_1d.h5
-rw-r--r--scene/animation/animation_blend_space_2d.cpp29
-rw-r--r--scene/animation/animation_blend_space_2d.h5
-rw-r--r--scene/animation/animation_blend_tree.cpp157
-rw-r--r--scene/animation/animation_blend_tree.h64
-rw-r--r--scene/animation/animation_node_state_machine.cpp12
-rw-r--r--scene/animation/animation_tree.cpp20
-rw-r--r--scene/animation/animation_tree.h6
-rw-r--r--scene/gui/slider.cpp14
-rw-r--r--scene/gui/slider.h8
-rw-r--r--scene/gui/spin_box.cpp2
-rw-r--r--scene/gui/spin_box.h4
-rw-r--r--scene/gui/tab_container.cpp9
-rw-r--r--scene/gui/tab_container.h1
-rw-r--r--scene/main/scene_tree.cpp24
-rw-r--r--scene/main/scene_tree.h4
-rw-r--r--scene/main/viewport.cpp55
-rw-r--r--scene/main/viewport.h21
-rw-r--r--scene/register_scene_types.cpp1
-rw-r--r--scene/resources/bone_map.cpp9
-rw-r--r--scene/resources/bone_map.h1
-rw-r--r--scene/resources/gradient.h8
-rw-r--r--scene/resources/skeleton_profile.cpp311
-rw-r--r--scene/resources/skeleton_profile.h31
-rw-r--r--scene/resources/texture.cpp2
-rw-r--r--scene/resources/visual_shader.cpp57
-rw-r--r--scene/resources/visual_shader.h11
32 files changed, 686 insertions, 216 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 2616d1f09e..76b354805c 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -439,7 +439,7 @@ void Camera2D::clear_current() {
void Camera2D::set_limit(Side p_side, int p_limit) {
ERR_FAIL_INDEX((int)p_side, 4);
limit[p_side] = p_limit;
- update();
+ _update_scroll();
}
int Camera2D::get_limit(Side p_side) const {
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 8eb48ffb30..9862c4bfb1 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -304,6 +304,7 @@ void PathFollow2D::_bind_methods() {
}
void PathFollow2D::set_offset(real_t p_offset) {
+ ERR_FAIL_COND(!isfinite(p_offset));
offset = p_offset;
if (path) {
if (path->get_curve().is_valid()) {
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index f53e783fbd..1f10337b4c 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -397,6 +397,7 @@ void PathFollow3D::_bind_methods() {
}
void PathFollow3D::set_offset(real_t p_offset) {
+ ERR_FAIL_COND(!isfinite(p_offset));
prev_offset = offset;
offset = p_offset;
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index fbd5f31dd5..b342660b85 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -639,6 +639,7 @@ void Skeleton3D::remove_bone_child(int p_bone, int p_child) {
}
Vector<int> Skeleton3D::get_parentless_bones() {
+ _update_process_order();
return parentless_bones;
}
@@ -765,8 +766,6 @@ void Skeleton3D::_make_dirty() {
}
void Skeleton3D::localize_rests() {
- _update_process_order();
-
Vector<int> bones_to_process = get_parentless_bones();
while (bones_to_process.size() > 0) {
int current_bone_idx = bones_to_process[0];
@@ -958,7 +957,6 @@ Ref<Skin> Skeleton3D::create_skin_from_rest_transforms() {
skin.instantiate();
skin->set_bind_count(bones.size());
- _update_process_order(); // Just in case.
// Pose changed, rebuild cache of inverses.
const Bone *bonesptr = bones.ptr();
diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp
index 594f98410e..d9a5adc883 100644
--- a/scene/animation/animation_blend_space_1d.cpp
+++ b/scene/animation/animation_blend_space_1d.cpp
@@ -78,6 +78,9 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_value_label", "text"), &AnimationNodeBlendSpace1D::set_value_label);
ClassDB::bind_method(D_METHOD("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label);
+ ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace1D::set_use_sync);
+ ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace1D::is_using_sync);
+
ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace1D::_add_blend_point);
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
@@ -89,6 +92,7 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_space", "get_max_space");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_value_label", "get_value_label");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_sync", "is_using_sync");
}
void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
@@ -211,6 +215,14 @@ String AnimationNodeBlendSpace1D::get_value_label() const {
return value_label;
}
+void AnimationNodeBlendSpace1D::set_use_sync(bool p_sync) {
+ sync = p_sync;
+}
+
+bool AnimationNodeBlendSpace1D::is_using_sync() const {
+ return sync;
+}
+
void AnimationNodeBlendSpace1D::_add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node) {
if (p_index == blend_points_used) {
add_blend_point(p_node, 0);
@@ -226,7 +238,7 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_see
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, false);
+ return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
}
double blend_pos = get_parameter(blend_position);
@@ -295,9 +307,12 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_see
double max_time_remaining = 0.0;
for (int i = 0; i < blend_points_used; i++) {
- double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, weights[i], FILTER_IGNORE, false);
-
- max_time_remaining = MAX(max_time_remaining, remaining);
+ 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);
+ 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);
+ }
}
return max_time_remaining;
diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h
index b2075c8c93..346e8a3a2f 100644
--- a/scene/animation/animation_blend_space_1d.h
+++ b/scene/animation/animation_blend_space_1d.h
@@ -63,6 +63,8 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
StringName blend_position = "blend_position";
protected:
+ bool sync = false;
+
virtual void _validate_property(PropertyInfo &property) const override;
static void _bind_methods();
@@ -93,6 +95,9 @@ public:
void set_value_label(const String &p_label);
String get_value_label() const;
+ 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;
String get_caption() const override;
diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp
index acdce2d7de..0f77befd9d 100644
--- a/scene/animation/animation_blend_space_2d.cpp
+++ b/scene/animation/animation_blend_space_2d.cpp
@@ -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, false);
+ 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);
if (first || t < mind) {
mind = t;
first = false;
@@ -513,8 +513,7 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see
}
if (!found) {
- //ignore
- blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, false);
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
}
}
} else {
@@ -539,16 +538,22 @@ 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 = length_internal - blend_node(blend_points[closest].name, blend_points[closest].node, p_time, false, p_seek_root, 0.0, FILTER_IGNORE, false);
+ from = length_internal - blend_node(blend_points[closest].name, blend_points[closest].node, p_time, false, p_seek_root, 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, false);
+ mind = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_seek_root, 1.0, FILTER_IGNORE, true);
length_internal = from + mind;
closest = new_closest;
} else {
- mind = blend_node(blend_points[closest].name, blend_points[closest].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, false);
+ mind = blend_node(blend_points[closest].name, blend_points[closest].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
+ }
+
+ for (int i = 0; i < blend_points_used; i++) {
+ if (i != closest) {
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+ }
}
}
@@ -604,6 +609,14 @@ AnimationNodeBlendSpace2D::BlendMode AnimationNodeBlendSpace2D::get_blend_mode()
return blend_mode;
}
+void AnimationNodeBlendSpace2D::set_use_sync(bool p_sync) {
+ sync = p_sync;
+}
+
+bool AnimationNodeBlendSpace2D::is_using_sync() const {
+ return sync;
+}
+
void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace2D::set_blend_point_position);
@@ -644,6 +657,9 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &AnimationNodeBlendSpace2D::set_blend_mode);
ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace2D::get_blend_mode);
+ ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace2D::set_use_sync);
+ ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace2D::is_using_sync);
+
ClassDB::bind_method(D_METHOD("_update_triangles"), &AnimationNodeBlendSpace2D::_update_triangles);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_auto_triangles", "get_auto_triangles");
@@ -661,6 +677,7 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "x_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_x_label", "get_x_label");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_y_label", "get_y_label");
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NO_EDITOR), "set_blend_mode", "get_blend_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_sync", "is_using_sync");
ADD_SIGNAL(MethodInfo("triangles_updated"));
BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED);
diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h
index 01f53ed25a..689b96e356 100644
--- a/scene/animation/animation_blend_space_2d.h
+++ b/scene/animation/animation_blend_space_2d.h
@@ -88,6 +88,8 @@ protected:
void _tree_changed();
protected:
+ bool sync = false;
+
virtual void _validate_property(PropertyInfo &property) const override;
static void _bind_methods();
@@ -137,6 +139,9 @@ public:
void set_blend_mode(BlendMode p_blend_mode);
BlendMode get_blend_mode() const;
+ void set_use_sync(bool p_sync);
+ bool is_using_sync() const;
+
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) override;
AnimationNodeBlendSpace2D();
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 4f6975deb1..d0aac931c0 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -179,6 +179,26 @@ AnimationNodeAnimation::AnimationNodeAnimation() {
////////////////////////////////////////////////////////
+void AnimationNodeSync::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeSync::set_use_sync);
+ ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeSync::is_using_sync);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
+}
+
+void AnimationNodeSync::set_use_sync(bool p_sync) {
+ sync = p_sync;
+}
+
+bool AnimationNodeSync::is_using_sync() const {
+ return sync;
+}
+
+AnimationNodeSync::AnimationNodeSync() {
+}
+
+////////////////////////////////////////////////////////
+
void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::BOOL, active));
r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
@@ -276,7 +296,7 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_roo
}
if (!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_seek_root, 1.0, FILTER_IGNORE, sync);
}
}
@@ -313,12 +333,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_seek_root, 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_seek_root, 1.0 - blend, FILTER_BLEND, sync);
}
- double os_rem = blend_input(1, os_seek ? time : p_time, os_seek, p_seek_root, blend, FILTER_PASS, false);
+ double os_rem = blend_input(1, os_seek ? time : p_time, os_seek, p_seek_root, blend, FILTER_PASS, true);
if (do_start) {
remaining = os_rem;
@@ -343,14 +363,6 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_roo
return MAX(main_rem, remaining);
}
-void AnimationNodeOneShot::set_use_sync(bool p_sync) {
- sync = p_sync;
-}
-
-bool AnimationNodeOneShot::is_using_sync() const {
- return sync;
-}
-
void AnimationNodeOneShot::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fadein_time", "time"), &AnimationNodeOneShot::set_fadein_time);
ClassDB::bind_method(D_METHOD("get_fadein_time"), &AnimationNodeOneShot::get_fadein_time);
@@ -370,9 +382,6 @@ void AnimationNodeOneShot::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mix_mode", "mode"), &AnimationNodeOneShot::set_mix_mode);
ClassDB::bind_method(D_METHOD("get_mix_mode"), &AnimationNodeOneShot::get_mix_mode);
- ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeOneShot::set_use_sync);
- ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeOneShot::is_using_sync);
-
ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_mode", PROPERTY_HINT_ENUM, "Blend,Add"), "set_mix_mode", "get_mix_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadein_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_fadein_time", "get_fadein_time");
@@ -384,9 +393,6 @@ void AnimationNodeOneShot::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_delay", "get_autorestart_delay");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_random_delay", "get_autorestart_random_delay");
- ADD_GROUP("", "");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
-
BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
BIND_ENUM_CONSTANT(MIX_MODE_ADD);
}
@@ -410,31 +416,19 @@ String AnimationNodeAdd2::get_caption() const {
return "Add2";
}
-void AnimationNodeAdd2::set_use_sync(bool p_sync) {
- sync = p_sync;
-}
-
-bool AnimationNodeAdd2::is_using_sync() const {
- return sync;
-}
-
bool AnimationNodeAdd2::has_filter() const {
return true;
}
double AnimationNodeAdd2::process(double p_time, bool p_seek, bool p_seek_root) {
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_seek_root, 1.0, FILTER_IGNORE, sync);
+ blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, sync);
return rem0;
}
void AnimationNodeAdd2::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd2::set_use_sync);
- ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd2::is_using_sync);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeAdd2::AnimationNodeAdd2() {
@@ -456,32 +450,20 @@ String AnimationNodeAdd3::get_caption() const {
return "Add3";
}
-void AnimationNodeAdd3::set_use_sync(bool p_sync) {
- sync = p_sync;
-}
-
-bool AnimationNodeAdd3::is_using_sync() const {
- return sync;
-}
-
bool AnimationNodeAdd3::has_filter() const {
return true;
}
double AnimationNodeAdd3::process(double p_time, bool p_seek, bool p_seek_root) {
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_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);
return rem0;
}
void AnimationNodeAdd3::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd3::set_use_sync);
- ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd3::is_using_sync);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeAdd3::AnimationNodeAdd3() {
@@ -507,29 +489,17 @@ String AnimationNodeBlend2::get_caption() const {
double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_seek_root) {
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_seek_root, 1.0 - amount, FILTER_BLEND, sync);
+ double rem1 = blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, sync);
return amount > 0.5 ? rem1 : rem0; //hacky but good enough
}
-void AnimationNodeBlend2::set_use_sync(bool p_sync) {
- sync = p_sync;
-}
-
-bool AnimationNodeBlend2::is_using_sync() const {
- return sync;
-}
-
bool AnimationNodeBlend2::has_filter() const {
return true;
}
void AnimationNodeBlend2::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend2::set_use_sync);
- ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend2::is_using_sync);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeBlend2::AnimationNodeBlend2() {
@@ -551,35 +521,22 @@ String AnimationNodeBlend3::get_caption() const {
return "Blend3";
}
-void AnimationNodeBlend3::set_use_sync(bool p_sync) {
- sync = p_sync;
-}
-
-bool AnimationNodeBlend3::is_using_sync() const {
- return sync;
-}
-
double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_seek_root) {
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_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);
return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); //hacky but good enough
}
void AnimationNodeBlend3::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend3::set_use_sync);
- ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend3::is_using_sync);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeBlend3::AnimationNodeBlend3() {
add_input("-blend");
add_input("in");
add_input("+blend");
- sync = false;
}
/////////////////////////////////
@@ -599,9 +556,9 @@ String AnimationNodeTimeScale::get_caption() const {
double AnimationNodeTimeScale::process(double p_time, bool p_seek, bool p_seek_root) {
double scale = get_parameter(this->scale);
if (p_seek) {
- return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, false);
+ return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true);
} else {
- return blend_input(0, p_time * scale, false, p_seek_root, 1.0, FILTER_IGNORE, false);
+ return blend_input(0, p_time * scale, false, p_seek_root, 1.0, FILTER_IGNORE, true);
}
}
@@ -629,13 +586,13 @@ String AnimationNodeTimeSeek::get_caption() const {
double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_seek_root) {
double seek_pos = get_parameter(this->seek_pos);
if (p_seek) {
- return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, false);
+ return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true);
} else if (seek_pos >= 0) {
- double ret = blend_input(0, seek_pos, true, true, 1.0, FILTER_IGNORE, false);
+ double ret = blend_input(0, seek_pos, true, true, 1.0, FILTER_IGNORE, true);
set_parameter(this->seek_pos, -1.0); //reset
return ret;
} else {
- return blend_input(0, p_time, false, p_seek_root, 1.0, FILTER_IGNORE, false);
+ return blend_input(0, p_time, false, p_seek_root, 1.0, FILTER_IGNORE, true);
}
}
@@ -727,6 +684,14 @@ float AnimationNodeTransition::get_cross_fade_time() const {
return xfade;
}
+void AnimationNodeTransition::set_from_start(bool p_from_start) {
+ from_start = p_from_start;
+}
+
+bool AnimationNodeTransition::is_from_start() const {
+ return from_start;
+}
+
double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_root) {
int current = get_parameter(this->current);
int prev = get_parameter(this->prev);
@@ -753,9 +718,15 @@ 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 != current && i != prev) {
+ blend_input(i, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+ }
+ }
+
if (prev < 0) { // process current animation, check for transition
- rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, false);
+ rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
if (p_seek) {
time = p_time;
@@ -771,18 +742,18 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
float blend = xfade == 0 ? 0 : (prev_xfading / xfade);
- if (!p_seek && switched) { //just switched, seek to start of current
+ if (from_start && !p_seek && switched) { //just switched, seek to start of current
- rem = blend_input(current, 0, true, p_seek_root, 1.0 - blend, FILTER_IGNORE, false);
+ rem = blend_input(current, 0, true, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
} else {
- rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_IGNORE, false);
+ rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
}
- if (p_seek) { // don't seek prev animation
- blend_input(prev, 0, false, p_seek_root, blend, FILTER_IGNORE, false);
+ if (p_seek) {
+ blend_input(prev, p_time, true, p_seek_root, blend, FILTER_IGNORE, true);
time = p_time;
} else {
- blend_input(prev, p_time, false, p_seek_root, blend, FILTER_IGNORE, false);
+ blend_input(prev, p_time, false, p_seek_root, blend, FILTER_IGNORE, true);
time += p_time;
prev_xfading -= p_time;
if (prev_xfading < 0) {
@@ -824,8 +795,12 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time);
ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time);
+ ClassDB::bind_method(D_METHOD("set_from_start", "from_start"), &AnimationNodeTransition::set_from_start);
+ ClassDB::bind_method(D_METHOD("is_from_start"), &AnimationNodeTransition::is_from_start);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_cross_fade_time", "get_cross_fade_time");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "from_start"), "set_from_start", "is_from_start");
for (int i = 0; i < MAX_INPUTS; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_caption", "get_input_caption", i);
@@ -846,7 +821,7 @@ String AnimationNodeOutput::get_caption() const {
}
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);
+ return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
}
AnimationNodeOutput::AnimationNodeOutput() {
@@ -1060,7 +1035,7 @@ String AnimationNodeBlendTree::get_caption() const {
double AnimationNodeBlendTree::process(double p_time, bool p_seek, bool p_seek_root) {
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);
+ return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_seek_root, 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 0a2305b8d6..d35ff04f30 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -77,8 +77,23 @@ private:
VARIANT_ENUM_CAST(AnimationNodeAnimation::PlayMode)
-class AnimationNodeOneShot : public AnimationNode {
- GDCLASS(AnimationNodeOneShot, AnimationNode);
+class AnimationNodeSync : public AnimationNode {
+ GDCLASS(AnimationNodeSync, AnimationNode);
+
+protected:
+ bool sync = false;
+
+ static void _bind_methods();
+
+public:
+ void set_use_sync(bool p_sync);
+ bool is_using_sync() const;
+
+ AnimationNodeSync();
+};
+
+class AnimationNodeOneShot : public AnimationNodeSync {
+ GDCLASS(AnimationNodeOneShot, AnimationNodeSync);
public:
enum MixMode {
@@ -95,8 +110,6 @@ private:
float autorestart_random_delay = 0.0;
MixMode mix = MIX_MODE_BLEND;
- bool sync = false;
-
/* bool active;
bool do_start;
float time;
@@ -134,9 +147,6 @@ public:
void set_mix_mode(MixMode p_mix);
MixMode get_mix_mode() const;
- void set_use_sync(bool p_sync);
- bool is_using_sync() const;
-
virtual bool has_filter() const override;
virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
@@ -145,11 +155,10 @@ public:
VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode)
-class AnimationNodeAdd2 : public AnimationNode {
- GDCLASS(AnimationNodeAdd2, AnimationNode);
+class AnimationNodeAdd2 : public AnimationNodeSync {
+ GDCLASS(AnimationNodeAdd2, AnimationNodeSync);
StringName add_amount = PNAME("add_amount");
- bool sync = false;
protected:
static void _bind_methods();
@@ -160,20 +169,16 @@ public:
virtual String get_caption() const override;
- void set_use_sync(bool p_sync);
- bool is_using_sync() const;
-
virtual bool has_filter() const override;
virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
AnimationNodeAdd2();
};
-class AnimationNodeAdd3 : public AnimationNode {
- GDCLASS(AnimationNodeAdd3, AnimationNode);
+class AnimationNodeAdd3 : public AnimationNodeSync {
+ GDCLASS(AnimationNodeAdd3, AnimationNodeSync);
StringName add_amount = PNAME("add_amount");
- bool sync = false;
protected:
static void _bind_methods();
@@ -184,20 +189,16 @@ public:
virtual String get_caption() const override;
- void set_use_sync(bool p_sync);
- bool is_using_sync() const;
-
virtual bool has_filter() const override;
virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
AnimationNodeAdd3();
};
-class AnimationNodeBlend2 : public AnimationNode {
- GDCLASS(AnimationNodeBlend2, AnimationNode);
+class AnimationNodeBlend2 : public AnimationNodeSync {
+ GDCLASS(AnimationNodeBlend2, AnimationNodeSync);
StringName blend_amount = PNAME("blend_amount");
- bool sync = false;
protected:
static void _bind_methods();
@@ -209,18 +210,14 @@ public:
virtual String get_caption() const override;
virtual double process(double p_time, bool p_seek, bool p_seek_root) override;
- void set_use_sync(bool p_sync);
- bool is_using_sync() const;
-
virtual bool has_filter() const override;
AnimationNodeBlend2();
};
-class AnimationNodeBlend3 : public AnimationNode {
- GDCLASS(AnimationNodeBlend3, AnimationNode);
+class AnimationNodeBlend3 : public AnimationNodeSync {
+ GDCLASS(AnimationNodeBlend3, AnimationNodeSync);
StringName blend_amount = PNAME("blend_amount");
- bool sync;
protected:
static void _bind_methods();
@@ -231,9 +228,6 @@ public:
virtual String get_caption() const override;
- 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;
AnimationNodeBlend3();
};
@@ -276,8 +270,8 @@ public:
AnimationNodeTimeSeek();
};
-class AnimationNodeTransition : public AnimationNode {
- GDCLASS(AnimationNodeTransition, AnimationNode);
+class AnimationNodeTransition : public AnimationNodeSync {
+ GDCLASS(AnimationNodeTransition, AnimationNodeSync);
enum {
MAX_INPUTS = 32
@@ -304,6 +298,7 @@ class AnimationNodeTransition : public AnimationNode {
StringName prev_current = "prev_current";
float xfade = 0.0;
+ bool from_start = true;
void _update_inputs();
@@ -329,6 +324,9 @@ public:
void set_cross_fade_time(float p_fade);
float get_cross_fade_time() const;
+ 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;
AnimationNodeTransition();
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 2ee7f4fa43..fe08e849a1 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -395,7 +395,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, false);
+ 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);
pos_current = 0;
}
@@ -420,10 +420,10 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
}
- 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, false);
+ float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_seek_root, fade_blend, AnimationNode::FILTER_IGNORE, true);
if (fading_from != StringName()) {
- 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, false);
+ 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);
}
//guess playback position
@@ -577,12 +577,12 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
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, false);
+ len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 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, false);
+ p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_seek_root, 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, false);
+ len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
pos_current = 0;
}
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 8c8822ac3f..4b80f571ae 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -150,7 +150,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_optimize) {
+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) {
ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
ERR_FAIL_COND_V(!state, 0);
@@ -169,7 +169,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_optimize, &activity);
+ 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);
Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path);
@@ -180,11 +180,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_optimize) {
- return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_seek_root, p_blend, p_filter, p_optimize);
+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_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_optimize, 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_seek_root, 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);
@@ -292,9 +292,11 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri
}
// 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.
+ // 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.
- if (!p_seek && p_optimize && !any_valid) {
+ 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, p_time, p_seek, p_seek_root, p_connections);
@@ -428,8 +430,8 @@ void AnimationNode::_bind_methods() {
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", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "seek_root", "blend", "filter", "optimize"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
+ 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("set_parameter", "name", "value"), &AnimationNode::set_parameter);
ClassDB::bind_method(D_METHOD("get_parameter", "name"), &AnimationNode::get_parameter);
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 0bfe615c9b..4f9a330a89 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -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_optimize = 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_seek_root, 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_optimize = 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_optimize = true);
+ 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 make_invalid(const String &p_reason);
AnimationTree *get_animation_tree() const;
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 4b680f72cf..64c07007dc 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -96,15 +96,15 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
if (grab.active) {
Size2i size = get_size();
Ref<Texture2D> grabber = get_theme_icon(SNAME("grabber"));
- float motion = (orientation == VERTICAL ? mm->get_position().y : mm->get_position().x) - grab.pos;
+ double motion = (orientation == VERTICAL ? mm->get_position().y : mm->get_position().x) - grab.pos;
if (orientation == VERTICAL) {
motion = -motion;
}
- float areasize = orientation == VERTICAL ? size.height - grabber->get_size().height : size.width - grabber->get_size().width;
+ double areasize = orientation == VERTICAL ? size.height - grabber->get_size().height : size.width - grabber->get_size().width;
if (areasize <= 0) {
return;
}
- float umotion = motion / float(areasize);
+ double umotion = motion / double(areasize);
set_as_ratio(grab.uvalue + umotion);
}
}
@@ -180,7 +180,7 @@ void Slider::_notification(int p_what) {
if (orientation == VERTICAL) {
int widget_width = style->get_minimum_size().width + style->get_center_size().width;
- float areasize = size.height - grabber->get_size().height;
+ double areasize = size.height - grabber->get_size().height;
style->draw(ci, Rect2i(Point2i(size.width / 2 - widget_width / 2, 0), Size2i(widget_width, size.height)));
grabber_area->draw(ci, Rect2i(Point2i((size.width - widget_width) / 2, size.height - areasize * ratio - grabber->get_size().height / 2), Size2i(widget_width, areasize * ratio + grabber->get_size().height / 2)));
@@ -197,7 +197,7 @@ void Slider::_notification(int p_what) {
grabber->draw(ci, Point2i(size.width / 2 - grabber->get_size().width / 2, size.height - ratio * areasize - grabber->get_size().height));
} else {
int widget_height = style->get_minimum_size().height + style->get_center_size().height;
- float areasize = size.width - grabber->get_size().width;
+ double areasize = size.width - grabber->get_size().width;
style->draw(ci, Rect2i(Point2i(0, (size.height - widget_height) / 2), Size2i(size.width, widget_height)));
grabber_area->draw(ci, Rect2i(Point2i(0, (size.height - widget_height) / 2), Size2i(areasize * ratio + grabber->get_size().width / 2, widget_height)));
@@ -218,11 +218,11 @@ void Slider::_notification(int p_what) {
}
}
-void Slider::set_custom_step(float p_custom_step) {
+void Slider::set_custom_step(double p_custom_step) {
custom_step = p_custom_step;
}
-float Slider::get_custom_step() const {
+double Slider::get_custom_step() const {
return custom_step;
}
diff --git a/scene/gui/slider.h b/scene/gui/slider.h
index 5fbfee2aec..5abaee27aa 100644
--- a/scene/gui/slider.h
+++ b/scene/gui/slider.h
@@ -38,14 +38,14 @@ class Slider : public Range {
struct Grab {
int pos = 0;
- float uvalue = 0.0;
+ double uvalue = 0.0;
bool active = false;
} grab;
int ticks = 0;
bool mouse_inside = false;
Orientation orientation;
- float custom_step = -1.0;
+ double custom_step = -1.0;
bool editable = true;
bool scrollable = true;
@@ -58,8 +58,8 @@ protected:
public:
virtual Size2 get_minimum_size() const override;
- void set_custom_step(float p_custom_step);
- float get_custom_step() const;
+ void set_custom_step(double p_custom_step);
+ double get_custom_step() const;
void set_ticks(int p_count);
int get_ticks() const;
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 890e349afb..7924bb13e9 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -167,7 +167,7 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
if (drag.enabled) {
drag.diff_y += mm->get_relative().y;
- float diff_y = -0.01 * Math::pow(ABS(drag.diff_y), 1.8f) * SIGN(drag.diff_y);
+ double diff_y = -0.01 * Math::pow(ABS(drag.diff_y), 1.8) * SIGN(drag.diff_y);
set_value(CLAMP(drag.base_val + get_step() * diff_y, get_min(), get_max()));
} else if (drag.allowed && drag.capture_pos.distance_to(mm->get_position()) > 2) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index d118b28334..1b1abbcf8e 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -56,11 +56,11 @@ class SpinBox : public Range {
void _line_edit_input(const Ref<InputEvent> &p_event);
struct Drag {
- float base_val = 0.0;
+ double base_val = 0.0;
bool allowed = false;
bool enabled = false;
Vector2 capture_pos;
- float diff_y = 0.0;
+ double diff_y = 0.0;
} drag;
void _line_edit_focus_exit();
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index fa929344d4..08db07c425 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -312,7 +312,7 @@ Vector<Control *> TabContainer::_get_tab_controls() const {
Vector<Control *> controls;
for (int i = 0; i < get_child_count(); i++) {
Control *control = Object::cast_to<Control>(get_child(i));
- if (!control || control->is_set_as_top_level() || control == tab_bar) {
+ if (!control || control->is_set_as_top_level() || control == tab_bar || control == child_removing) {
continue;
}
@@ -549,7 +549,12 @@ void TabContainer::remove_child_notify(Node *p_child) {
return;
}
- tab_bar->remove_tab(get_tab_idx_from_control(c));
+ int idx = get_tab_idx_from_control(c);
+
+ // Before this, the tab control has not changed; after this, the tab control has changed.
+ child_removing = p_child;
+ tab_bar->remove_tab(idx);
+ child_removing = nullptr;
_update_margins();
if (get_tab_count() == 0) {
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index 9adaa0d844..60c8130939 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -46,6 +46,7 @@ class TabContainer : public Container {
bool drag_to_rearrange_enabled = false;
bool use_hidden_tabs_for_min_size = false;
bool theme_changing = false;
+ Node *child_removing = nullptr;
int _get_top_margin() const;
Vector<Control *> _get_tab_controls() const;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index e40850641a..66482f65dc 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -34,6 +34,7 @@
#include "core/debugger/engine_debugger.h"
#include "core/input/input.h"
#include "core/io/dir_access.h"
+#include "core/io/image_loader.h"
#include "core/io/marshalls.h"
#include "core/io/resource_loader.h"
#include "core/multiplayer/multiplayer_api.h"
@@ -1446,6 +1447,29 @@ SceneTree::SceneTree() {
bool snap_2d_vertices = GLOBAL_DEF("rendering/2d/snap/snap_2d_vertices_to_pixel", false);
root->set_snap_2d_vertices_to_pixel(snap_2d_vertices);
+ // We setup VRS for the main viewport here, in the editor this will have little effect.
+ const int vrs_mode = GLOBAL_DEF("rendering/vrs/mode", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/vrs/mode", PropertyInfo(Variant::INT, "rendering/vrs/mode", PROPERTY_HINT_ENUM, String::utf8("Disabled,Texture,XR")));
+ root->set_vrs_mode(Viewport::VRSMode(vrs_mode));
+ const String vrs_texture_path = String(GLOBAL_DEF("rendering/vrs/texture", String())).strip_edges();
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/vrs/texture",
+ PropertyInfo(Variant::STRING,
+ "rendering/vrs/texture",
+ PROPERTY_HINT_FILE, "*.png"));
+ if (vrs_mode == 1 && !vrs_texture_path.is_empty()) {
+ Ref<Image> vrs_image;
+ vrs_image.instantiate();
+ Error load_err = ImageLoader::load_image(vrs_texture_path, vrs_image);
+ if (load_err) {
+ ERR_PRINT("Non-existing or invalid VRS texture at '" + vrs_texture_path + "'.");
+ } else {
+ Ref<ImageTexture> vrs_texture;
+ vrs_texture.instantiate();
+ vrs_texture->create_from_image(vrs_image);
+ root->set_vrs_texture(vrs_texture);
+ }
+ }
+
int shadowmap_size = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_size", 4096);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_size", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_size", PROPERTY_HINT_RANGE, "256,16384"));
GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_size.mobile", 2048);
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index a34aa8e2cd..a512feacc8 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -90,8 +90,8 @@ private:
Window *root = nullptr;
uint64_t tree_version = 1;
- double physics_process_time = 1.0;
- double process_time = 1.0;
+ double physics_process_time = 0.0;
+ double process_time = 0.0;
bool accept_quit = true;
bool quit_on_go_back = true;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 92bda3a64a..0031abd953 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -3080,6 +3080,41 @@ Viewport::DefaultCanvasItemTextureRepeat Viewport::get_default_canvas_item_textu
return default_canvas_item_texture_repeat;
}
+void Viewport::set_vrs_mode(Viewport::VRSMode p_vrs_mode) {
+ // Note, set this even if not supported on this hardware, it will only be used if it is but we want to save the value as set by the user.
+ vrs_mode = p_vrs_mode;
+
+ switch (p_vrs_mode) {
+ case VRS_TEXTURE: {
+ RS::get_singleton()->viewport_set_vrs_mode(viewport, RS::VIEWPORT_VRS_TEXTURE);
+ } break;
+ case VRS_XR: {
+ RS::get_singleton()->viewport_set_vrs_mode(viewport, RS::VIEWPORT_VRS_XR);
+ } break;
+ default: {
+ RS::get_singleton()->viewport_set_vrs_mode(viewport, RS::VIEWPORT_VRS_DISABLED);
+ } break;
+ }
+
+ notify_property_list_changed();
+}
+
+Viewport::VRSMode Viewport::get_vrs_mode() const {
+ return vrs_mode;
+}
+
+void Viewport::set_vrs_texture(Ref<Texture2D> p_texture) {
+ vrs_texture = p_texture;
+
+ // TODO need to add something here in case the RID changes
+ RID tex = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RS::get_singleton()->viewport_set_vrs_texture(viewport, tex);
+}
+
+Ref<Texture2D> Viewport::get_vrs_texture() const {
+ return vrs_texture;
+}
+
DisplayServer::WindowID Viewport::get_window_id() const {
return DisplayServer::MAIN_WINDOW_ID;
}
@@ -3741,6 +3776,12 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fsr_mipmap_bias", "fsr_mipmap_bias"), &Viewport::set_fsr_mipmap_bias);
ClassDB::bind_method(D_METHOD("get_fsr_mipmap_bias"), &Viewport::get_fsr_mipmap_bias);
+ ClassDB::bind_method(D_METHOD("set_vrs_mode", "mode"), &Viewport::set_vrs_mode);
+ ClassDB::bind_method(D_METHOD("get_vrs_mode"), &Viewport::get_vrs_mode);
+
+ ClassDB::bind_method(D_METHOD("set_vrs_texture", "texture"), &Viewport::set_vrs_texture);
+ ClassDB::bind_method(D_METHOD("get_vrs_texture"), &Viewport::get_vrs_texture);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d");
@@ -3766,6 +3807,9 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fsr_mipmap_bias", PROPERTY_HINT_RANGE, "-2,2,0.1"), "set_fsr_mipmap_bias", "get_fsr_mipmap_bias");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fsr_sharpness", PROPERTY_HINT_RANGE, "0,2,0.1"), "set_fsr_sharpness", "get_fsr_sharpness");
#endif
+ ADD_GROUP("Variable Rate Shading", "vrs_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "vrs_mode", PROPERTY_HINT_ENUM, "Disabled,Texture,Depth buffer,XR"), "set_vrs_mode", "get_vrs_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "vrs_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_vrs_texture", "get_vrs_texture");
ADD_GROUP("Canvas Items", "canvas_item_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirror"), "set_default_canvas_item_texture_repeat", "get_default_canvas_item_texture_repeat");
@@ -3876,6 +3920,17 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(SDF_SCALE_50_PERCENT);
BIND_ENUM_CONSTANT(SDF_SCALE_25_PERCENT);
BIND_ENUM_CONSTANT(SDF_SCALE_MAX);
+
+ BIND_ENUM_CONSTANT(VRS_DISABLED);
+ BIND_ENUM_CONSTANT(VRS_TEXTURE);
+ BIND_ENUM_CONSTANT(VRS_XR);
+ BIND_ENUM_CONSTANT(VRS_MAX);
+}
+
+void Viewport::_validate_property(PropertyInfo &property) const {
+ if (vrs_mode != VRS_TEXTURE && (property.name == "vrs_texture")) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
Viewport::Viewport() {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 617b01ac91..a43e3f3ee2 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -197,6 +197,13 @@ public:
SUBWINDOW_CANVAS_LAYER = 1024
};
+ enum VRSMode {
+ VRS_DISABLED,
+ VRS_TEXTURE,
+ VRS_XR,
+ VRS_MAX
+ };
+
private:
friend class ViewportTexture;
@@ -333,6 +340,10 @@ private:
RID canvas_item;
};
+ // VRS
+ VRSMode vrs_mode = VRS_DISABLED;
+ Ref<Texture2D> vrs_texture;
+
struct GUI {
// info used when this is a window
@@ -604,6 +615,14 @@ public:
void set_default_canvas_item_texture_repeat(DefaultCanvasItemTextureRepeat p_repeat);
DefaultCanvasItemTextureRepeat get_default_canvas_item_texture_repeat() const;
+ // VRS
+
+ void set_vrs_mode(VRSMode p_vrs_mode);
+ VRSMode get_vrs_mode() const;
+
+ void set_vrs_texture(Ref<Texture2D> p_texture);
+ Ref<Texture2D> get_vrs_texture() const;
+
virtual DisplayServer::WindowID get_window_id() const = 0;
void set_embedding_subwindows(bool p_embed);
@@ -690,6 +709,7 @@ public:
bool is_using_xr();
#endif // _3D_DISABLED
+ virtual void _validate_property(PropertyInfo &property) const override;
Viewport();
~Viewport();
};
@@ -752,6 +772,7 @@ VARIANT_ENUM_CAST(Viewport::ScreenSpaceAA);
VARIANT_ENUM_CAST(Viewport::DebugDraw);
VARIANT_ENUM_CAST(Viewport::SDFScale);
VARIANT_ENUM_CAST(Viewport::SDFOversize);
+VARIANT_ENUM_CAST(Viewport::VRSMode);
VARIANT_ENUM_CAST(SubViewport::ClearMode);
VARIANT_ENUM_CAST(Viewport::RenderInfo);
VARIANT_ENUM_CAST(Viewport::RenderInfoType);
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 5c5b60df63..f462e36758 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -439,6 +439,7 @@ void register_scene_types() {
GDREGISTER_CLASS(AnimationNodeStateMachine);
GDREGISTER_CLASS(AnimationNodeStateMachinePlayback);
+ GDREGISTER_CLASS(AnimationNodeSync);
GDREGISTER_CLASS(AnimationNodeStateMachineTransition);
GDREGISTER_CLASS(AnimationNodeOutput);
GDREGISTER_CLASS(AnimationNodeOneShot);
diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp
index ce030934fa..aff917b2d4 100644
--- a/scene/resources/bone_map.cpp
+++ b/scene/resources/bone_map.cpp
@@ -50,6 +50,14 @@ bool BoneMap::_get(const StringName &p_path, Variant &r_ret) const {
return true;
}
+void BoneMap::_get_property_list(List<PropertyInfo> *p_list) const {
+ HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
+ while (E) {
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_map/" + E->key, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
+ ++E;
+ }
+}
+
Ref<SkeletonProfile> BoneMap::get_profile() const {
return profile;
}
@@ -153,6 +161,7 @@ void BoneMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("find_profile_bone_name", "skeleton_bone_name"), &BoneMap::find_profile_bone_name);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "profile", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonProfile"), "set_profile", "get_profile");
+ ADD_ARRAY("bonemap", "bonemap");
ADD_SIGNAL(MethodInfo("bone_map_updated"));
ADD_SIGNAL(MethodInfo("profile_updated"));
diff --git a/scene/resources/bone_map.h b/scene/resources/bone_map.h
index 4b7928015d..17452dfc73 100644
--- a/scene/resources/bone_map.h
+++ b/scene/resources/bone_map.h
@@ -46,6 +46,7 @@ protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
virtual void _validate_property(PropertyInfo &property) const override;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
public:
diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h
index 2b04ead0af..e4bac15e4b 100644
--- a/scene/resources/gradient.h
+++ b/scene/resources/gradient.h
@@ -157,10 +157,10 @@ public:
const Point &pointP3 = points[p3];
float x = (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset);
- float r = Math::cubic_interpolate(pointP0.color.r, pointFirst.color.r, pointSecond.color.r, pointP3.color.r, x);
- float g = Math::cubic_interpolate(pointP0.color.g, pointFirst.color.g, pointSecond.color.g, pointP3.color.g, x);
- float b = Math::cubic_interpolate(pointP0.color.b, pointFirst.color.b, pointSecond.color.b, pointP3.color.b, x);
- float a = Math::cubic_interpolate(pointP0.color.a, pointFirst.color.a, pointSecond.color.a, pointP3.color.a, x);
+ float r = Math::cubic_interpolate(pointFirst.color.r, pointSecond.color.r, pointP0.color.r, pointP3.color.r, x);
+ float g = Math::cubic_interpolate(pointFirst.color.g, pointSecond.color.g, pointP0.color.g, pointP3.color.g, x);
+ float b = Math::cubic_interpolate(pointFirst.color.b, pointSecond.color.b, pointP0.color.b, pointP3.color.b, x);
+ float a = Math::cubic_interpolate(pointFirst.color.a, pointSecond.color.a, pointP0.color.a, pointP3.color.a, x);
return Color(r, g, b, a);
} break;
diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp
index 05d48f9545..0714de470c 100644
--- a/scene/resources/skeleton_profile.cpp
+++ b/scene/resources/skeleton_profile.cpp
@@ -34,7 +34,7 @@ bool SkeletonProfile::_set(const StringName &p_path, const Variant &p_value) {
ERR_FAIL_COND_V(is_read_only, false);
String path = p_path;
- if (path.begins_with("group/")) {
+ if (path.begins_with("groups/")) {
int which = path.get_slicec('/', 1).to_int();
String what = path.get_slicec('/', 2);
ERR_FAIL_INDEX_V(which, groups.size(), false);
@@ -43,23 +43,35 @@ bool SkeletonProfile::_set(const StringName &p_path, const Variant &p_value) {
set_group_name(which, p_value);
} else if (what == "texture") {
set_texture(which, p_value);
+ } else {
+ return false;
}
- return true;
}
- if (path.begins_with("bone/")) {
+ if (path.begins_with("bones/")) {
int which = path.get_slicec('/', 1).to_int();
String what = path.get_slicec('/', 2);
ERR_FAIL_INDEX_V(which, bones.size(), false);
if (what == "bone_name") {
set_bone_name(which, p_value);
+ } else if (what == "bone_parent") {
+ set_bone_parent(which, p_value);
+ } else if (what == "tail_direction") {
+ set_tail_direction(which, static_cast<TailDirection>((int)p_value));
+ } else if (what == "bone_tail") {
+ set_bone_tail(which, p_value);
+ } else if (what == "reference_pose") {
+ set_reference_pose(which, p_value);
} else if (what == "handle_offset") {
set_handle_offset(which, p_value);
} else if (what == "group") {
set_group(which, p_value);
+ } else if (what == "require") {
+ set_require(which, p_value);
+ } else {
+ return false;
}
- return true;
}
return true;
}
@@ -67,7 +79,7 @@ bool SkeletonProfile::_set(const StringName &p_path, const Variant &p_value) {
bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const {
String path = p_path;
- if (path.begins_with("group/")) {
+ if (path.begins_with("groups/")) {
int which = path.get_slicec('/', 1).to_int();
String what = path.get_slicec('/', 2);
ERR_FAIL_INDEX_V(which, groups.size(), false);
@@ -76,23 +88,35 @@ bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const {
r_ret = get_group_name(which);
} else if (what == "texture") {
r_ret = get_texture(which);
+ } else {
+ return false;
}
- return true;
}
- if (path.begins_with("bone/")) {
+ if (path.begins_with("bones/")) {
int which = path.get_slicec('/', 1).to_int();
String what = path.get_slicec('/', 2);
ERR_FAIL_INDEX_V(which, bones.size(), false);
if (what == "bone_name") {
r_ret = get_bone_name(which);
+ } else if (what == "bone_parent") {
+ r_ret = get_bone_parent(which);
+ } else if (what == "tail_direction") {
+ r_ret = get_tail_direction(which);
+ } else if (what == "bone_tail") {
+ r_ret = get_bone_tail(which);
+ } else if (what == "reference_pose") {
+ r_ret = get_reference_pose(which);
} else if (what == "handle_offset") {
r_ret = get_handle_offset(which);
} else if (what == "group") {
r_ret = get_group(which);
+ } else if (what == "require") {
+ r_ret = is_require(which);
+ } else {
+ return false;
}
- return true;
}
return true;
}
@@ -104,6 +128,13 @@ void SkeletonProfile::_validate_property(PropertyInfo &property) const {
return;
}
}
+
+ PackedStringArray split = property.name.split("/");
+ if (split.size() == 3 && split[0] == "bones") {
+ if (split[2] == "bone_tail" && get_tail_direction(split[1].to_int()) != TAIL_DIRECTION_SPECIFIC_CHILD) {
+ property.usage = PROPERTY_USAGE_NONE;
+ }
+ }
}
void SkeletonProfile::_get_property_list(List<PropertyInfo> *p_list) const {
@@ -112,7 +143,7 @@ void SkeletonProfile::_get_property_list(List<PropertyInfo> *p_list) const {
}
String group_names = "";
for (int i = 0; i < groups.size(); i++) {
- String path = "group/" + itos(i) + "/";
+ String path = "groups/" + itos(i) + "/";
p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "group_name"));
p_list->push_back(PropertyInfo(Variant::OBJECT, path + "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
if (i > 0) {
@@ -121,10 +152,19 @@ void SkeletonProfile::_get_property_list(List<PropertyInfo> *p_list) const {
group_names = group_names + groups[i].group_name;
}
for (int i = 0; i < bones.size(); i++) {
- String path = "bone/" + itos(i) + "/";
+ String path = "bones/" + itos(i) + "/";
p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "bone_name"));
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "bone_parent"));
+ p_list->push_back(PropertyInfo(Variant::INT, path + "tail_direction", PROPERTY_HINT_ENUM, "AverageChildren,SpecificChild,End"));
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "bone_tail"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, path + "reference_pose"));
p_list->push_back(PropertyInfo(Variant::VECTOR2, path + "handle_offset"));
p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "group", PROPERTY_HINT_ENUM, group_names));
+ p_list->push_back(PropertyInfo(Variant::BOOL, path + "require"));
+ }
+
+ for (PropertyInfo &E : *p_list) {
+ _validate_property(E);
}
}
@@ -184,6 +224,18 @@ void SkeletonProfile::set_bone_size(int p_size) {
notify_property_list_changed();
}
+int SkeletonProfile::find_bone(StringName p_bone_name) const {
+ if (p_bone_name == StringName()) {
+ return -1;
+ }
+ for (int i = 0; i < bones.size(); i++) {
+ if (bones[i].bone_name == p_bone_name) {
+ return i;
+ }
+ }
+ return -1;
+}
+
StringName SkeletonProfile::get_bone_name(int p_bone_idx) const {
ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
return bones[p_bone_idx].bone_name;
@@ -198,6 +250,63 @@ void SkeletonProfile::set_bone_name(int p_bone_idx, const StringName p_bone_name
emit_signal("profile_updated");
}
+StringName SkeletonProfile::get_bone_parent(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
+ return bones[p_bone_idx].bone_parent;
+}
+
+void SkeletonProfile::set_bone_parent(int p_bone_idx, const StringName p_bone_parent) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].bone_parent = p_bone_parent;
+ emit_signal("profile_updated");
+}
+
+SkeletonProfile::TailDirection SkeletonProfile::get_tail_direction(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), TAIL_DIRECTION_AVERAGE_CHILDREN);
+ return bones[p_bone_idx].tail_direction;
+}
+
+void SkeletonProfile::set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].tail_direction = p_tail_direction;
+ emit_signal("profile_updated");
+ notify_property_list_changed();
+}
+
+StringName SkeletonProfile::get_bone_tail(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
+ return bones[p_bone_idx].bone_tail;
+}
+
+void SkeletonProfile::set_bone_tail(int p_bone_idx, const StringName p_bone_tail) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].bone_tail = p_bone_tail;
+ emit_signal("profile_updated");
+}
+
+Transform3D SkeletonProfile::get_reference_pose(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), Transform3D());
+ return bones[p_bone_idx].reference_pose;
+}
+
+void SkeletonProfile::set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].reference_pose = p_reference_pose;
+ emit_signal("profile_updated");
+}
+
Vector2 SkeletonProfile::get_handle_offset(int p_bone_idx) const {
ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), Vector2());
return bones[p_bone_idx].handle_offset;
@@ -226,6 +335,20 @@ void SkeletonProfile::set_group(int p_bone_idx, const StringName p_group) {
emit_signal("profile_updated");
}
+bool SkeletonProfile::is_require(int p_bone_idx) const {
+ ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), false);
+ return bones[p_bone_idx].require;
+}
+
+void SkeletonProfile::set_require(int p_bone_idx, const bool p_require) {
+ if (is_read_only) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_bone_idx, bones.size());
+ bones.write[p_bone_idx].require = p_require;
+ emit_signal("profile_updated");
+}
+
bool SkeletonProfile::has_bone(StringName p_bone_name) {
bool is_found = false;
for (int i = 0; i < bones.size(); i++) {
@@ -250,19 +373,37 @@ void SkeletonProfile::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_size", "size"), &SkeletonProfile::set_bone_size);
ClassDB::bind_method(D_METHOD("get_bone_size"), &SkeletonProfile::get_bone_size);
+ ClassDB::bind_method(D_METHOD("find_bone", "bone_name"), &SkeletonProfile::find_bone);
+
ClassDB::bind_method(D_METHOD("get_bone_name", "bone_idx"), &SkeletonProfile::get_bone_name);
ClassDB::bind_method(D_METHOD("set_bone_name", "bone_idx", "bone_name"), &SkeletonProfile::set_bone_name);
+ ClassDB::bind_method(D_METHOD("get_bone_parent", "bone_idx"), &SkeletonProfile::get_bone_parent);
+ ClassDB::bind_method(D_METHOD("set_bone_parent", "bone_idx", "bone_parent"), &SkeletonProfile::set_bone_parent);
+
+ ClassDB::bind_method(D_METHOD("get_tail_direction", "bone_idx"), &SkeletonProfile::get_tail_direction);
+ ClassDB::bind_method(D_METHOD("set_tail_direction", "bone_idx", "tail_direction"), &SkeletonProfile::set_tail_direction);
+
+ ClassDB::bind_method(D_METHOD("get_bone_tail", "bone_idx"), &SkeletonProfile::get_bone_tail);
+ ClassDB::bind_method(D_METHOD("set_bone_tail", "bone_idx", "bone_tail"), &SkeletonProfile::set_bone_tail);
+
+ ClassDB::bind_method(D_METHOD("get_reference_pose", "bone_idx"), &SkeletonProfile::get_reference_pose);
+ ClassDB::bind_method(D_METHOD("set_reference_pose", "bone_idx", "bone_name"), &SkeletonProfile::set_reference_pose);
+
ClassDB::bind_method(D_METHOD("get_handle_offset", "bone_idx"), &SkeletonProfile::get_handle_offset);
ClassDB::bind_method(D_METHOD("set_handle_offset", "bone_idx", "handle_offset"), &SkeletonProfile::set_handle_offset);
ClassDB::bind_method(D_METHOD("get_group", "bone_idx"), &SkeletonProfile::get_group);
ClassDB::bind_method(D_METHOD("set_group", "bone_idx", "group"), &SkeletonProfile::set_group);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "group_size", PROPERTY_HINT_RANGE, "0,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Groups,group/"), "set_group_size", "get_group_size");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_size", PROPERTY_HINT_RANGE, "0,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Bones,bone/"), "set_bone_size", "get_bone_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "group_size", PROPERTY_HINT_RANGE, "0,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Groups,groups/"), "set_group_size", "get_group_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_size", PROPERTY_HINT_RANGE, "0,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Bones,bones/"), "set_bone_size", "get_bone_size");
ADD_SIGNAL(MethodInfo("profile_updated"));
+
+ BIND_ENUM_CONSTANT(TAIL_DIRECTION_AVERAGE_CHILDREN);
+ BIND_ENUM_CONSTANT(TAIL_DIRECTION_SPECIFIC_CHILD);
+ BIND_ENUM_CONSTANT(TAIL_DIRECTION_END);
}
SkeletonProfile::SkeletonProfile() {
@@ -284,226 +425,364 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.resize(56);
bones.write[0].bone_name = "Root";
+ bones.write[0].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
bones.write[0].handle_offset = Vector2(0.5, 0.91);
bones.write[0].group = "Body";
bones.write[1].bone_name = "Hips";
+ bones.write[1].bone_parent = "Root";
+ bones.write[1].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[1].bone_tail = "Spine";
+ bones.write[1].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.75, 0);
bones.write[1].handle_offset = Vector2(0.5, 0.5);
bones.write[1].group = "Body";
+ bones.write[1].require = true;
bones.write[2].bone_name = "Spine";
+ bones.write[2].bone_parent = "Hips";
+ bones.write[2].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
bones.write[2].handle_offset = Vector2(0.5, 0.43);
bones.write[2].group = "Body";
+ bones.write[2].require = true;
bones.write[3].bone_name = "Chest";
+ bones.write[3].bone_parent = "Spine";
+ bones.write[3].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
bones.write[3].handle_offset = Vector2(0.5, 0.36);
bones.write[3].group = "Body";
bones.write[4].bone_name = "UpperChest";
+ bones.write[4].bone_parent = "Chest";
+ bones.write[4].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
bones.write[4].handle_offset = Vector2(0.5, 0.29);
bones.write[4].group = "Body";
bones.write[5].bone_name = "Neck";
+ bones.write[5].bone_parent = "UpperChest";
+ bones.write[5].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[5].bone_tail = "Head";
+ bones.write[5].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
bones.write[5].handle_offset = Vector2(0.5, 0.23);
bones.write[5].group = "Body";
+ bones.write[5].require = true;
bones.write[6].bone_name = "Head";
+ bones.write[6].bone_parent = "Neck";
+ bones.write[6].tail_direction = TAIL_DIRECTION_END;
+ bones.write[6].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
bones.write[6].handle_offset = Vector2(0.5, 0.18);
bones.write[6].group = "Body";
+ bones.write[6].require = true;
bones.write[7].bone_name = "LeftEye";
+ bones.write[7].bone_parent = "Head";
+ bones.write[7].reference_pose = Transform3D(1, 0, 0, 0, 0, -1, 0, 1, 0, 0.05, 0.15, 0);
bones.write[7].handle_offset = Vector2(0.6, 0.46);
bones.write[7].group = "Face";
bones.write[8].bone_name = "RightEye";
+ bones.write[8].bone_parent = "Head";
+ bones.write[8].reference_pose = Transform3D(1, 0, 0, 0, 0, -1, 0, 1, 0, -0.05, 0.15, 0);
bones.write[8].handle_offset = Vector2(0.37, 0.46);
bones.write[8].group = "Face";
bones.write[9].bone_name = "Jaw";
+ bones.write[9].bone_parent = "Head";
+ bones.write[9].reference_pose = Transform3D(-1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0.05, 0.05);
bones.write[9].handle_offset = Vector2(0.46, 0.75);
bones.write[9].group = "Face";
bones.write[10].bone_name = "LeftShoulder";
+ bones.write[10].bone_parent = "UpperChest";
+ bones.write[10].reference_pose = Transform3D(0, 1, 0, 0, 0, 1, 1, 0, 0, 0.05, 0.1, 0);
bones.write[10].handle_offset = Vector2(0.55, 0.235);
bones.write[10].group = "Body";
+ bones.write[10].require = true;
bones.write[11].bone_name = "LeftUpperArm";
+ bones.write[11].bone_parent = "LeftShoulder";
+ bones.write[11].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0);
bones.write[11].handle_offset = Vector2(0.6, 0.24);
bones.write[11].group = "Body";
+ bones.write[11].require = true;
bones.write[12].bone_name = "LeftLowerArm";
+ bones.write[12].bone_parent = "LeftUpperArm";
+ bones.write[12].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0);
bones.write[12].handle_offset = Vector2(0.7, 0.24);
bones.write[12].group = "Body";
+ bones.write[12].require = true;
bones.write[13].bone_name = "LeftHand";
+ bones.write[13].bone_parent = "LeftLowerArm";
+ bones.write[13].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[13].bone_tail = "LeftMiddleProximal";
+ bones.write[13].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0);
bones.write[13].handle_offset = Vector2(0.82, 0.235);
bones.write[13].group = "Body";
+ bones.write[13].require = true;
- bones.write[14].bone_name = "LeftThumbProximal";
+ bones.write[14].bone_name = "LeftThumbMetacarpal";
+ bones.write[14].bone_parent = "LeftHand";
+ bones.write[14].reference_pose = Transform3D(0, -0.577, 0.816, 0.707, 0.577, 0.408, -0.707, 0.577, 0.408, -0.025, 0, 0);
bones.write[14].handle_offset = Vector2(0.4, 0.8);
bones.write[14].group = "LeftHand";
- bones.write[15].bone_name = "LeftThumbIntermediate";
+ bones.write[15].bone_name = "LeftThumbProximal";
+ bones.write[15].bone_parent = "LeftThumbMetacarpal";
+ bones.write[15].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
bones.write[15].handle_offset = Vector2(0.3, 0.69);
bones.write[15].group = "LeftHand";
bones.write[16].bone_name = "LeftThumbDistal";
+ bones.write[16].bone_parent = "LeftThumbProximal";
+ bones.write[16].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
bones.write[16].handle_offset = Vector2(0.23, 0.555);
bones.write[16].group = "LeftHand";
bones.write[17].bone_name = "LeftIndexProximal";
+ bones.write[17].bone_parent = "LeftHand";
+ bones.write[17].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.025, 0.075, 0);
bones.write[17].handle_offset = Vector2(0.413, 0.52);
bones.write[17].group = "LeftHand";
bones.write[18].bone_name = "LeftIndexIntermediate";
+ bones.write[18].bone_parent = "LeftIndexProximal";
+ bones.write[18].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
bones.write[18].handle_offset = Vector2(0.403, 0.36);
bones.write[18].group = "LeftHand";
bones.write[19].bone_name = "LeftIndexDistal";
+ bones.write[19].bone_parent = "LeftIndexIntermediate";
+ bones.write[19].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
bones.write[19].handle_offset = Vector2(0.403, 0.255);
bones.write[19].group = "LeftHand";
bones.write[20].bone_name = "LeftMiddleProximal";
+ bones.write[20].bone_parent = "LeftHand";
+ bones.write[20].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
bones.write[20].handle_offset = Vector2(0.5, 0.51);
bones.write[20].group = "LeftHand";
bones.write[21].bone_name = "LeftMiddleIntermediate";
+ bones.write[21].bone_parent = "LeftMiddleProximal";
+ bones.write[21].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
bones.write[21].handle_offset = Vector2(0.5, 0.345);
bones.write[21].group = "LeftHand";
bones.write[22].bone_name = "LeftMiddleDistal";
+ bones.write[22].bone_parent = "LeftMiddleIntermediate";
+ bones.write[22].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
bones.write[22].handle_offset = Vector2(0.5, 0.22);
bones.write[22].group = "LeftHand";
bones.write[23].bone_name = "LeftRingProximal";
+ bones.write[23].bone_parent = "LeftHand";
+ bones.write[23].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.025, 0.075, 0);
bones.write[23].handle_offset = Vector2(0.586, 0.52);
bones.write[23].group = "LeftHand";
bones.write[24].bone_name = "LeftRingIntermediate";
+ bones.write[24].bone_parent = "LeftRingProximal";
+ bones.write[24].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
bones.write[24].handle_offset = Vector2(0.59, 0.36);
bones.write[24].group = "LeftHand";
bones.write[25].bone_name = "LeftRingDistal";
+ bones.write[25].bone_parent = "LeftRingIntermediate";
+ bones.write[25].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
bones.write[25].handle_offset = Vector2(0.591, 0.25);
bones.write[25].group = "LeftHand";
bones.write[26].bone_name = "LeftLittleProximal";
+ bones.write[26].bone_parent = "LeftHand";
+ bones.write[26].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.05, 0.05, 0);
bones.write[26].handle_offset = Vector2(0.663, 0.543);
bones.write[26].group = "LeftHand";
bones.write[27].bone_name = "LeftLittleIntermediate";
+ bones.write[27].bone_parent = "LeftLittleProximal";
+ bones.write[27].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
bones.write[27].handle_offset = Vector2(0.672, 0.415);
bones.write[27].group = "LeftHand";
bones.write[28].bone_name = "LeftLittleDistal";
+ bones.write[28].bone_parent = "LeftLittleIntermediate";
+ bones.write[28].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
bones.write[28].handle_offset = Vector2(0.672, 0.32);
bones.write[28].group = "LeftHand";
bones.write[29].bone_name = "RightShoulder";
+ bones.write[29].bone_parent = "UpperChest";
+ bones.write[29].reference_pose = Transform3D(0, -1, 0, 0, 0, 1, -1, 0, 0, -0.05, 0.1, 0);
bones.write[29].handle_offset = Vector2(0.45, 0.235);
bones.write[29].group = "Body";
+ bones.write[29].require = true;
bones.write[30].bone_name = "RightUpperArm";
+ bones.write[30].bone_parent = "RightShoulder";
+ bones.write[30].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0);
bones.write[30].handle_offset = Vector2(0.4, 0.24);
bones.write[30].group = "Body";
+ bones.write[30].require = true;
bones.write[31].bone_name = "RightLowerArm";
+ bones.write[31].bone_parent = "RightUpperArm";
+ bones.write[31].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0);
bones.write[31].handle_offset = Vector2(0.3, 0.24);
bones.write[31].group = "Body";
+ bones.write[31].require = true;
bones.write[32].bone_name = "RightHand";
+ bones.write[32].bone_parent = "RightLowerArm";
+ bones.write[32].tail_direction = TAIL_DIRECTION_SPECIFIC_CHILD;
+ bones.write[32].bone_tail = "RightMiddleProximal";
+ bones.write[32].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0);
bones.write[32].handle_offset = Vector2(0.18, 0.235);
bones.write[32].group = "Body";
+ bones.write[32].require = true;
- bones.write[33].bone_name = "RightThumbProximal";
+ bones.write[33].bone_name = "RightThumbMetacarpal";
+ bones.write[33].bone_parent = "RightHand";
+ bones.write[33].reference_pose = Transform3D(0, 0.577, -0.816, -0.707, 0.577, 0.408, 0.707, 0.577, 0.408, 0.025, 0, 0);
bones.write[33].handle_offset = Vector2(0.6, 0.8);
bones.write[33].group = "RightHand";
- bones.write[34].bone_name = "RightThumbIntermediate";
+ bones.write[34].bone_name = "RightThumbProximal";
+ bones.write[34].bone_parent = "RightThumbMetacarpal";
+ bones.write[34].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
bones.write[34].handle_offset = Vector2(0.7, 0.69);
bones.write[34].group = "RightHand";
bones.write[35].bone_name = "RightThumbDistal";
+ bones.write[35].bone_parent = "RightThumbProximal";
+ bones.write[35].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.043, 0);
bones.write[35].handle_offset = Vector2(0.77, 0.555);
bones.write[35].group = "RightHand";
bones.write[36].bone_name = "RightIndexProximal";
+ bones.write[36].bone_parent = "RightHand";
+ bones.write[36].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.025, 0.075, 0);
bones.write[36].handle_offset = Vector2(0.587, 0.52);
bones.write[36].group = "RightHand";
bones.write[37].bone_name = "RightIndexIntermediate";
+ bones.write[37].bone_parent = "RightIndexProximal";
+ bones.write[37].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
bones.write[37].handle_offset = Vector2(0.597, 0.36);
bones.write[37].group = "RightHand";
bones.write[38].bone_name = "RightIndexDistal";
+ bones.write[38].bone_parent = "RightIndexIntermediate";
+ bones.write[38].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
bones.write[38].handle_offset = Vector2(0.597, 0.255);
bones.write[38].group = "RightHand";
bones.write[39].bone_name = "RightMiddleProximal";
+ bones.write[39].bone_parent = "RightHand";
+ bones.write[39].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
bones.write[39].handle_offset = Vector2(0.5, 0.51);
bones.write[39].group = "RightHand";
bones.write[40].bone_name = "RightMiddleIntermediate";
+ bones.write[40].bone_parent = "RightMiddleProximal";
+ bones.write[40].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0);
bones.write[40].handle_offset = Vector2(0.5, 0.345);
bones.write[40].group = "RightHand";
bones.write[41].bone_name = "RightMiddleDistal";
+ bones.write[41].bone_parent = "RightMiddleIntermediate";
+ bones.write[41].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
bones.write[41].handle_offset = Vector2(0.5, 0.22);
bones.write[41].group = "RightHand";
bones.write[42].bone_name = "RightRingProximal";
+ bones.write[42].bone_parent = "RightHand";
+ bones.write[42].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.025, 0.075, 0);
bones.write[42].handle_offset = Vector2(0.414, 0.52);
bones.write[42].group = "RightHand";
bones.write[43].bone_name = "RightRingIntermediate";
+ bones.write[43].bone_parent = "RightRingProximal";
+ bones.write[43].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
bones.write[43].handle_offset = Vector2(0.41, 0.36);
bones.write[43].group = "RightHand";
bones.write[44].bone_name = "RightRingDistal";
+ bones.write[44].bone_parent = "RightRingIntermediate";
+ bones.write[44].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
bones.write[44].handle_offset = Vector2(0.409, 0.25);
bones.write[44].group = "RightHand";
bones.write[45].bone_name = "RightLittleProximal";
+ bones.write[45].bone_parent = "RightHand";
+ bones.write[45].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.05, 0.05, 0);
bones.write[45].handle_offset = Vector2(0.337, 0.543);
bones.write[45].group = "RightHand";
bones.write[46].bone_name = "RightLittleIntermediate";
+ bones.write[46].bone_parent = "RightLittleProximal";
+ bones.write[46].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0);
bones.write[46].handle_offset = Vector2(0.328, 0.415);
bones.write[46].group = "RightHand";
bones.write[47].bone_name = "RightLittleDistal";
+ bones.write[47].bone_parent = "RightLittleIntermediate";
+ bones.write[47].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.025, 0);
bones.write[47].handle_offset = Vector2(0.328, 0.32);
bones.write[47].group = "RightHand";
bones.write[48].bone_name = "LeftUpperLeg";
+ bones.write[48].bone_parent = "Hips";
+ bones.write[48].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, 0.1, 0, 0);
bones.write[48].handle_offset = Vector2(0.549, 0.49);
bones.write[48].group = "Body";
+ bones.write[48].require = true;
bones.write[49].bone_name = "LeftLowerLeg";
+ bones.write[49].bone_parent = "LeftUpperLeg";
+ bones.write[49].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0);
bones.write[49].handle_offset = Vector2(0.548, 0.683);
bones.write[49].group = "Body";
+ bones.write[49].require = true;
bones.write[50].bone_name = "LeftFoot";
+ bones.write[50].bone_parent = "LeftLowerLeg";
+ bones.write[50].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0);
bones.write[50].handle_offset = Vector2(0.545, 0.9);
bones.write[50].group = "Body";
+ bones.write[50].require = true;
bones.write[51].bone_name = "LeftToes";
+ bones.write[51].bone_parent = "LeftFoot";
+ bones.write[51].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.15, 0);
bones.write[51].handle_offset = Vector2(0.545, 0.95);
bones.write[51].group = "Body";
bones.write[52].bone_name = "RightUpperLeg";
+ bones.write[52].bone_parent = "Hips";
+ bones.write[52].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, -0.1, 0, 0);
bones.write[52].handle_offset = Vector2(0.451, 0.49);
bones.write[52].group = "Body";
+ bones.write[52].require = true;
bones.write[53].bone_name = "RightLowerLeg";
+ bones.write[53].bone_parent = "RightUpperLeg";
+ bones.write[53].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0);
bones.write[53].handle_offset = Vector2(0.452, 0.683);
bones.write[53].group = "Body";
+ bones.write[53].require = true;
bones.write[54].bone_name = "RightFoot";
+ bones.write[54].bone_parent = "RightLowerLeg";
+ bones.write[54].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0);
bones.write[54].handle_offset = Vector2(0.455, 0.9);
bones.write[54].group = "Body";
+ bones.write[54].require = true;
bones.write[55].bone_name = "RightToes";
+ bones.write[55].bone_parent = "RightFoot";
+ bones.write[55].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.15, 0);
bones.write[55].handle_offset = Vector2(0.455, 0.95);
bones.write[55].group = "Body";
}
diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h
index 920aaa2b8d..d305311538 100644
--- a/scene/resources/skeleton_profile.h
+++ b/scene/resources/skeleton_profile.h
@@ -36,6 +36,13 @@
class SkeletonProfile : public Resource {
GDCLASS(SkeletonProfile, Resource);
+public:
+ enum TailDirection {
+ TAIL_DIRECTION_AVERAGE_CHILDREN,
+ TAIL_DIRECTION_SPECIFIC_CHILD,
+ TAIL_DIRECTION_END
+ };
+
protected:
// Note: SkeletonProfileHumanoid which extends SkeletonProfile exists to unify standard bone names.
// That is what is_read_only is for, so don't make it public.
@@ -48,8 +55,13 @@ protected:
struct SkeletonProfileBone {
StringName bone_name;
+ StringName bone_parent;
+ TailDirection tail_direction = TAIL_DIRECTION_AVERAGE_CHILDREN;
+ StringName bone_tail;
+ Transform3D reference_pose;
Vector2 handle_offset;
StringName group;
+ bool require = false;
};
Vector<SkeletonProfileGroup> groups;
@@ -74,15 +86,32 @@ public:
int get_bone_size();
void set_bone_size(int p_size);
+ int find_bone(const StringName p_bone_name) const;
+
StringName get_bone_name(int p_bone_idx) const;
void set_bone_name(int p_bone_idx, const StringName p_bone_name);
+ StringName get_bone_parent(int p_bone_idx) const;
+ void set_bone_parent(int p_bone_idx, const StringName p_bone_parent);
+
+ TailDirection get_tail_direction(int p_bone_idx) const;
+ void set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction);
+
+ StringName get_bone_tail(int p_bone_idx) const;
+ void set_bone_tail(int p_bone_idx, const StringName p_bone_tail);
+
+ Transform3D get_reference_pose(int p_bone_idx) const;
+ void set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose);
+
Vector2 get_handle_offset(int p_bone_idx) const;
void set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset);
StringName get_group(int p_bone_idx) const;
void set_group(int p_bone_idx, const StringName p_group);
+ bool is_require(int p_bone_idx) const;
+ void set_require(int p_bone_idx, const bool p_require);
+
bool has_bone(StringName p_bone_name);
SkeletonProfile();
@@ -97,4 +126,6 @@ public:
~SkeletonProfileHumanoid();
};
+VARIANT_ENUM_CAST(SkeletonProfile::TailDirection);
+
#endif // SKELETON_PROFILE_H
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 8c175e9ced..3a8f50c3c3 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -2157,7 +2157,7 @@ void GradientTexture1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &GradientTexture1D::_update);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient");
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,16384,suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
}
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index b8eac6de00..b68cce9dda 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -30,6 +30,7 @@
#include "visual_shader.h"
+#include "core/templates/rb_map.h"
#include "core/templates/vmap.h"
#include "servers/rendering/shader_types.h"
#include "visual_shader_nodes.h"
@@ -3189,18 +3190,18 @@ VisualShaderNodeInput::VisualShaderNodeInput() {
////////////// UniformRef
-List<VisualShaderNodeUniformRef::Uniform> uniforms;
+RBMap<RID, List<VisualShaderNodeUniformRef::Uniform>> uniforms;
-void VisualShaderNodeUniformRef::add_uniform(const String &p_name, UniformType p_type) {
- uniforms.push_back({ p_name, p_type });
+void VisualShaderNodeUniformRef::add_uniform(RID p_shader_rid, const String &p_name, UniformType p_type) {
+ uniforms[p_shader_rid].push_back({ p_name, p_type });
}
-void VisualShaderNodeUniformRef::clear_uniforms() {
- uniforms.clear();
+void VisualShaderNodeUniformRef::clear_uniforms(RID p_shader_rid) {
+ uniforms[p_shader_rid].clear();
}
-bool VisualShaderNodeUniformRef::has_uniform(const String &p_name) {
- for (const VisualShaderNodeUniformRef::Uniform &E : uniforms) {
+bool VisualShaderNodeUniformRef::has_uniform(RID p_shader_rid, const String &p_name) {
+ for (const VisualShaderNodeUniformRef::Uniform &E : uniforms[p_shader_rid]) {
if (E.name == p_name) {
return true;
}
@@ -3313,14 +3314,24 @@ String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
return "";
}
+void VisualShaderNodeUniformRef::set_shader_rid(const RID &p_shader_rid) {
+ shader_rid = p_shader_rid;
+}
+
void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) {
uniform_name = p_name;
+ if (shader_rid.is_valid()) {
+ update_uniform_type();
+ }
+ emit_changed();
+}
+
+void VisualShaderNodeUniformRef::update_uniform_type() {
if (uniform_name != "[None]") {
uniform_type = get_uniform_type_by_name(uniform_name);
} else {
uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
}
- emit_changed();
}
String VisualShaderNodeUniformRef::get_uniform_name() const {
@@ -3328,35 +3339,45 @@ String VisualShaderNodeUniformRef::get_uniform_name() const {
}
int VisualShaderNodeUniformRef::get_uniforms_count() const {
- return uniforms.size();
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), 0);
+
+ return uniforms[shader_rid].size();
}
String VisualShaderNodeUniformRef::get_uniform_name_by_index(int p_idx) const {
- if (p_idx >= 0 && p_idx < uniforms.size()) {
- return uniforms[p_idx].name;
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), String());
+
+ if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
+ return uniforms[shader_rid][p_idx].name;
}
return "";
}
VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_name(const String &p_name) const {
- for (int i = 0; i < uniforms.size(); i++) {
- if (uniforms[i].name == p_name) {
- return uniforms[i].type;
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), UNIFORM_TYPE_FLOAT);
+
+ for (int i = 0; i < uniforms[shader_rid].size(); i++) {
+ if (uniforms[shader_rid][i].name == p_name) {
+ return uniforms[shader_rid][i].type;
}
}
return UniformType::UNIFORM_TYPE_FLOAT;
}
VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_index(int p_idx) const {
- if (p_idx >= 0 && p_idx < uniforms.size()) {
- return uniforms[p_idx].type;
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), UNIFORM_TYPE_FLOAT);
+
+ if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
+ return uniforms[shader_rid][p_idx].type;
}
return UniformType::UNIFORM_TYPE_FLOAT;
}
VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_by_index(int p_idx) const {
- if (p_idx >= 0 && p_idx < uniforms.size()) {
- switch (uniforms[p_idx].type) {
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), PORT_TYPE_SCALAR);
+
+ if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
+ switch (uniforms[shader_rid][p_idx].type) {
case UniformType::UNIFORM_TYPE_FLOAT:
return PORT_TYPE_SCALAR;
case UniformType::UNIFORM_TYPE_INT:
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index afd84e49cc..7ca4e5fc4a 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -561,6 +561,7 @@ public:
};
private:
+ RID shader_rid;
String uniform_name = "[None]";
UniformType uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
@@ -568,9 +569,9 @@ protected:
static void _bind_methods();
public:
- static void add_uniform(const String &p_name, UniformType p_type);
- static void clear_uniforms();
- static bool has_uniform(const String &p_name);
+ static void add_uniform(RID p_shader_rid, const String &p_name, UniformType p_type);
+ static void clear_uniforms(RID p_shader_rid);
+ static bool has_uniform(RID p_shader_rid, const String &p_name);
public:
virtual String get_caption() const override;
@@ -583,9 +584,13 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ void set_shader_rid(const RID &p_shader);
+
void set_uniform_name(const String &p_name);
String get_uniform_name() const;
+ void update_uniform_type();
+
void _set_uniform_type(int p_uniform_type);
int _get_uniform_type() const;