|
@@ -30,12 +30,20 @@
|
|
|
|
|
|
#include "animation_blend_space_1d.h"
|
|
|
|
|
|
+#include "animation_blend_tree.h"
|
|
|
+
|
|
|
void AnimationNodeBlendSpace1D::get_parameter_list(List<PropertyInfo> *r_list) const {
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_position));
|
|
|
+ r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
|
|
+ r_list->push_back(PropertyInfo(Variant::FLOAT, length_internal, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
|
|
}
|
|
|
|
|
|
Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
- return 0;
|
|
|
+ if (p_parameter == closest) {
|
|
|
+ return -1;
|
|
|
+ } else {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) {
|
|
@@ -77,6 +85,9 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("set_value_label", "text"), &AnimationNodeBlendSpace1D::set_value_label);
|
|
|
ClassDB::bind_method(D_METHOD("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label);
|
|
|
|
|
|
+ ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &AnimationNodeBlendSpace1D::set_blend_mode);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace1D::get_blend_mode);
|
|
|
+
|
|
|
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace1D::set_use_sync);
|
|
|
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace1D::is_using_sync);
|
|
|
|
|
@@ -91,7 +102,12 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_space", "get_max_space");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_snap", "get_snap");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_value_label", "get_value_label");
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NO_EDITOR), "set_blend_mode", "get_blend_mode");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_sync", "is_using_sync");
|
|
|
+
|
|
|
+ BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED);
|
|
|
+ BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE);
|
|
|
+ BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE_CARRY);
|
|
|
}
|
|
|
|
|
|
void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
|
|
@@ -214,6 +230,14 @@ String AnimationNodeBlendSpace1D::get_value_label() const {
|
|
|
return value_label;
|
|
|
}
|
|
|
|
|
|
+void AnimationNodeBlendSpace1D::set_blend_mode(BlendMode p_blend_mode) {
|
|
|
+ blend_mode = p_blend_mode;
|
|
|
+}
|
|
|
+
|
|
|
+AnimationNodeBlendSpace1D::BlendMode AnimationNodeBlendSpace1D::get_blend_mode() const {
|
|
|
+ return blend_mode;
|
|
|
+}
|
|
|
+
|
|
|
void AnimationNodeBlendSpace1D::set_use_sync(bool p_sync) {
|
|
|
sync = p_sync;
|
|
|
}
|
|
@@ -241,79 +265,125 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_is_
|
|
|
}
|
|
|
|
|
|
double blend_pos = get_parameter(blend_position);
|
|
|
+ int cur_closest = get_parameter(closest);
|
|
|
+ double cur_length_internal = get_parameter(length_internal);
|
|
|
+ double max_time_remaining = 0.0;
|
|
|
|
|
|
- float weights[MAX_BLEND_POINTS] = {};
|
|
|
+ if (blend_mode == BLEND_MODE_INTERPOLATED) {
|
|
|
+ float weights[MAX_BLEND_POINTS] = {};
|
|
|
+
|
|
|
+ int point_lower = -1;
|
|
|
+ float pos_lower = 0.0;
|
|
|
+ int point_higher = -1;
|
|
|
+ float pos_higher = 0.0;
|
|
|
+
|
|
|
+ // find the closest two points to blend between
|
|
|
+ for (int i = 0; i < blend_points_used; i++) {
|
|
|
+ float pos = blend_points[i].position;
|
|
|
+
|
|
|
+ if (pos <= blend_pos) {
|
|
|
+ if (point_lower == -1) {
|
|
|
+ point_lower = i;
|
|
|
+ pos_lower = pos;
|
|
|
+ } else if ((blend_pos - pos) < (blend_pos - pos_lower)) {
|
|
|
+ point_lower = i;
|
|
|
+ pos_lower = pos;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (point_higher == -1) {
|
|
|
+ point_higher = i;
|
|
|
+ pos_higher = pos;
|
|
|
+ } else if ((pos - blend_pos) < (pos_higher - blend_pos)) {
|
|
|
+ point_higher = i;
|
|
|
+ pos_higher = pos;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- int point_lower = -1;
|
|
|
- float pos_lower = 0.0;
|
|
|
- int point_higher = -1;
|
|
|
- float pos_higher = 0.0;
|
|
|
+ // fill in weights
|
|
|
|
|
|
- // find the closest two points to blend between
|
|
|
- for (int i = 0; i < blend_points_used; i++) {
|
|
|
- float pos = blend_points[i].position;
|
|
|
-
|
|
|
- if (pos <= blend_pos) {
|
|
|
- if (point_lower == -1) {
|
|
|
- point_lower = i;
|
|
|
- pos_lower = pos;
|
|
|
- } else if ((blend_pos - pos) < (blend_pos - pos_lower)) {
|
|
|
- point_lower = i;
|
|
|
- pos_lower = pos;
|
|
|
- }
|
|
|
+ if (point_lower == -1 && point_higher != -1) {
|
|
|
+ // we are on the left side, no other point to the left
|
|
|
+ // we just play the next point.
|
|
|
+
|
|
|
+ weights[point_higher] = 1.0;
|
|
|
+ } else if (point_higher == -1) {
|
|
|
+ // we are on the right side, no other point to the right
|
|
|
+ // we just play the previous point
|
|
|
+
|
|
|
+ weights[point_lower] = 1.0;
|
|
|
} else {
|
|
|
- if (point_higher == -1) {
|
|
|
- point_higher = i;
|
|
|
- pos_higher = pos;
|
|
|
- } else if ((pos - blend_pos) < (pos_higher - blend_pos)) {
|
|
|
- point_higher = i;
|
|
|
- pos_higher = pos;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ // we are between two points.
|
|
|
+ // figure out weights, then blend the animations
|
|
|
|
|
|
- // fill in weights
|
|
|
+ float distance_between_points = pos_higher - pos_lower;
|
|
|
|
|
|
- if (point_lower == -1 && point_higher != -1) {
|
|
|
- // we are on the left side, no other point to the left
|
|
|
- // we just play the next point.
|
|
|
+ float current_pos_inbetween = blend_pos - pos_lower;
|
|
|
|
|
|
- weights[point_higher] = 1.0;
|
|
|
- } else if (point_higher == -1) {
|
|
|
- // we are on the right side, no other point to the right
|
|
|
- // we just play the previous point
|
|
|
+ float blend_percentage = current_pos_inbetween / distance_between_points;
|
|
|
|
|
|
- weights[point_lower] = 1.0;
|
|
|
- } else {
|
|
|
- // we are between two points.
|
|
|
- // figure out weights, then blend the animations
|
|
|
+ float blend_lower = 1.0 - blend_percentage;
|
|
|
+ float blend_higher = blend_percentage;
|
|
|
|
|
|
- float distance_between_points = pos_higher - pos_lower;
|
|
|
+ weights[point_lower] = blend_lower;
|
|
|
+ weights[point_higher] = blend_higher;
|
|
|
+ }
|
|
|
|
|
|
- float current_pos_inbetween = blend_pos - pos_lower;
|
|
|
+ // actually blend the animations now
|
|
|
|
|
|
- float blend_percentage = current_pos_inbetween / distance_between_points;
|
|
|
+ for (int i = 0; i < blend_points_used; i++) {
|
|
|
+ if (i == point_lower || i == point_higher) {
|
|
|
+ double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true);
|
|
|
+ max_time_remaining = MAX(max_time_remaining, remaining);
|
|
|
+ } else if (sync) {
|
|
|
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ int new_closest = -1;
|
|
|
+ double new_closest_dist = 1e20;
|
|
|
+
|
|
|
+ for (int i = 0; i < blend_points_used; i++) {
|
|
|
+ double d = abs(blend_points[i].position - blend_pos);
|
|
|
+ if (d < new_closest_dist) {
|
|
|
+ new_closest = i;
|
|
|
+ new_closest_dist = d;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- float blend_lower = 1.0 - blend_percentage;
|
|
|
- float blend_higher = blend_percentage;
|
|
|
+ if (new_closest != cur_closest && new_closest != -1) {
|
|
|
+ double from = 0.0;
|
|
|
+ if (blend_mode == BLEND_MODE_DISCRETE_CARRY && cur_closest != -1) {
|
|
|
+ //for ping-pong loop
|
|
|
+ Ref<AnimationNodeAnimation> na_c = static_cast<Ref<AnimationNodeAnimation>>(blend_points[cur_closest].node);
|
|
|
+ Ref<AnimationNodeAnimation> na_n = static_cast<Ref<AnimationNodeAnimation>>(blend_points[new_closest].node);
|
|
|
+ if (!na_c.is_null() && !na_n.is_null()) {
|
|
|
+ na_n->set_backward(na_c->is_backward());
|
|
|
+ }
|
|
|
+ //see how much animation remains
|
|
|
+ from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_is_external_seeking, 0.0, FILTER_IGNORE, true);
|
|
|
+ }
|
|
|
|
|
|
- weights[point_lower] = blend_lower;
|
|
|
- weights[point_higher] = blend_higher;
|
|
|
- }
|
|
|
+ max_time_remaining = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
|
|
+ cur_length_internal = from + max_time_remaining;
|
|
|
|
|
|
- // actually blend the animations now
|
|
|
+ cur_closest = new_closest;
|
|
|
|
|
|
- double max_time_remaining = 0.0;
|
|
|
+ } else {
|
|
|
+ max_time_remaining = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
|
|
+ }
|
|
|
|
|
|
- for (int i = 0; i < blend_points_used; i++) {
|
|
|
- if (i == point_lower || i == point_higher) {
|
|
|
- double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true);
|
|
|
- max_time_remaining = MAX(max_time_remaining, remaining);
|
|
|
- } else if (sync) {
|
|
|
- blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
|
|
+ if (sync) {
|
|
|
+ for (int i = 0; i < blend_points_used; i++) {
|
|
|
+ if (i != cur_closest) {
|
|
|
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ set_parameter(this->closest, cur_closest);
|
|
|
+ set_parameter(this->length_internal, cur_length_internal);
|
|
|
return max_time_remaining;
|
|
|
}
|
|
|
|