summaryrefslogtreecommitdiff
path: root/scene/animation/animation_tree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/animation/animation_tree.cpp')
-rw-r--r--scene/animation/animation_tree.cpp131
1 files changed, 97 insertions, 34 deletions
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 9ca8d478b1..7ea42e6df2 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -32,6 +32,7 @@
#include "animation_blend_tree.h"
#include "core/config/engine.h"
+#include "scene/resources/animation.h"
#include "scene/scene_string_names.h"
#include "servers/audio/audio_stream.h"
@@ -87,7 +88,7 @@ void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
}
}
-void AnimationNode::blend_animation(const StringName &p_animation, real_t p_time, real_t p_delta, bool p_seeked, real_t p_blend) {
+void AnimationNode::blend_animation(const StringName &p_animation, real_t p_time, real_t p_delta, bool p_seeked, real_t p_blend, int p_pingponged) {
ERR_FAIL_COND(!state);
ERR_FAIL_COND(!state->player->has_animation(p_animation));
@@ -113,6 +114,7 @@ void AnimationNode::blend_animation(const StringName &p_animation, real_t p_time
anim_state.time = p_time;
anim_state.animation = animation;
anim_state.seeked = p_seeked;
+ anim_state.pingponged = p_pingponged;
state->animation_states.push_back(anim_state);
}
@@ -418,7 +420,7 @@ void AnimationNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_filters", "filters"), &AnimationNode::_set_filters);
ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);
- ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "blend"), &AnimationNode::blend_animation);
+ ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "blend", "pingponged"), &AnimationNode::blend_animation, DEFVAL(0));
ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
@@ -824,6 +826,8 @@ void AnimationTree::_process_graph(real_t p_delta) {
double delta = as.delta;
real_t weight = as.blend;
bool seeked = as.seeked;
+ int pingponged = as.pingponged;
+ bool backward = signbit(delta);
for (int i = 0; i < a->get_track_count(); i++) {
NodePath path = a->track_get_path(i);
@@ -862,12 +866,38 @@ void AnimationTree::_process_graph(real_t p_delta) {
t->scale = Vector3(1, 1, 1);
}
- real_t prev_time = time - delta;
- if (prev_time < 0) {
- if (!a->has_loop()) {
- prev_time = 0;
- } else {
- prev_time = a->get_length() + prev_time;
+ double prev_time = time - delta;
+ if (!backward) {
+ if (prev_time < 0) {
+ switch (a->get_loop_mode()) {
+ case Animation::LoopMode::LOOP_NONE: {
+ prev_time = 0;
+ } break;
+ case Animation::LoopMode::LOOP_LINEAR: {
+ prev_time = Math::fposmod(prev_time, (double)a->get_length());
+ } break;
+ case Animation::LoopMode::LOOP_PINGPONG: {
+ prev_time = Math::pingpong(prev_time, (double)a->get_length());
+ } break;
+ default:
+ break;
+ }
+ }
+ } else {
+ if (prev_time > a->get_length()) {
+ switch (a->get_loop_mode()) {
+ case Animation::LoopMode::LOOP_NONE: {
+ prev_time = (double)a->get_length();
+ } break;
+ case Animation::LoopMode::LOOP_LINEAR: {
+ prev_time = Math::fposmod(prev_time, (double)a->get_length());
+ } break;
+ case Animation::LoopMode::LOOP_PINGPONG: {
+ prev_time = Math::pingpong(prev_time, (double)a->get_length());
+ } break;
+ default:
+ break;
+ }
}
}
@@ -875,20 +905,38 @@ void AnimationTree::_process_graph(real_t p_delta) {
Quaternion rot[2];
Vector3 scale[2];
- if (prev_time > time) {
- Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]);
- if (err != OK) {
- continue;
+ if (!backward) {
+ if (prev_time > time) {
+ Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]);
+ if (err != OK) {
+ continue;
+ }
+
+ a->transform_track_interpolate(i, (double)a->get_length(), &loc[1], &rot[1], &scale[1]);
+
+ t->loc += (loc[1] - loc[0]) * blend;
+ t->scale += (scale[1] - scale[0]) * blend;
+ Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
+ t->rot = (t->rot * q).normalized();
+
+ prev_time = 0;
}
+ } else {
+ if (prev_time < time) {
+ Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]);
+ if (err != OK) {
+ continue;
+ }
- a->transform_track_interpolate(i, a->get_length(), &loc[1], &rot[1], &scale[1]);
+ a->transform_track_interpolate(i, 0, &loc[1], &rot[1], &scale[1]);
- t->loc += (loc[1] - loc[0]) * blend;
- t->scale += (scale[1] - scale[0]) * blend;
- Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
- t->rot = (t->rot * q).normalized();
+ t->loc += (loc[1] - loc[0]) * blend;
+ t->scale += (scale[1] - scale[0]) * blend;
+ Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
+ t->rot = (t->rot * q).normalized();
- prev_time = 0;
+ prev_time = 0;
+ }
}
Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]);
@@ -903,8 +951,7 @@ void AnimationTree::_process_graph(real_t p_delta) {
Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
t->rot = (t->rot * q).normalized();
- prev_time = 0;
-
+ prev_time = !backward ? 0 : (double)a->get_length();
} else {
Vector3 loc;
Quaternion rot;
@@ -960,7 +1007,7 @@ void AnimationTree::_process_graph(real_t p_delta) {
} else {
List<int> indices;
- a->value_track_get_key_indices(i, time, delta, &indices);
+ a->value_track_get_key_indices(i, time, delta, &indices, pingponged);
for (int &F : indices) {
Variant value = a->track_get_key_value(i, F);
@@ -977,7 +1024,7 @@ void AnimationTree::_process_graph(real_t p_delta) {
List<int> indices;
- a->method_track_get_key_indices(i, time, delta, &indices);
+ a->method_track_get_key_indices(i, time, delta, &indices, pingponged);
for (int &F : indices) {
StringName method = a->method_track_get_name(i, F);
@@ -1060,7 +1107,7 @@ void AnimationTree::_process_graph(real_t p_delta) {
} else {
//find stuff to play
List<int> to_play;
- a->track_get_key_indices_in_range(i, time, delta, &to_play);
+ a->track_get_key_indices_in_range(i, time, delta, &to_play, pingponged);
if (to_play.size()) {
int idx = to_play.back()->get();
@@ -1088,12 +1135,20 @@ void AnimationTree::_process_graph(real_t p_delta) {
t->start = time;
}
} else if (t->playing) {
- bool loop = a->has_loop();
+ bool loop = a->get_loop_mode() != Animation::LoopMode::LOOP_NONE;
bool stop = false;
- if (!loop && time < t->start) {
- stop = true;
+ if (!loop) {
+ if (delta > 0) {
+ if (time < t->start) {
+ stop = true;
+ }
+ } else if (delta < 0) {
+ if (time > t->start) {
+ stop = true;
+ }
+ }
} else if (t->len > 0) {
real_t len = t->start > time ? (a->get_length() - t->start) + time : time - t->start;
@@ -1127,7 +1182,7 @@ void AnimationTree::_process_graph(real_t p_delta) {
continue;
}
- if (delta == 0 || seeked) {
+ if (seeked) {
//seek
int idx = a->track_find_key(i, time);
if (idx < 0) {
@@ -1143,12 +1198,20 @@ void AnimationTree::_process_graph(real_t p_delta) {
Ref<Animation> anim = player2->get_animation(anim_name);
- real_t at_anim_pos;
-
- if (anim->has_loop()) {
- at_anim_pos = Math::fposmod(time - pos, (double)anim->get_length()); //seek to loop
- } else {
- at_anim_pos = MAX(anim->get_length(), time - pos); //seek to end
+ real_t at_anim_pos = 0.0;
+
+ switch (anim->get_loop_mode()) {
+ case Animation::LoopMode::LOOP_NONE: {
+ at_anim_pos = MAX((double)anim->get_length(), time - pos); //seek to end
+ } break;
+ case Animation::LoopMode::LOOP_LINEAR: {
+ at_anim_pos = Math::fposmod(time - pos, (double)anim->get_length()); //seek to loop
+ } break;
+ case Animation::LoopMode::LOOP_PINGPONG: {
+ at_anim_pos = Math::pingpong(time - pos, (double)a->get_length());
+ } break;
+ default:
+ break;
}
if (player2->is_playing() || seeked) {
@@ -1163,7 +1226,7 @@ void AnimationTree::_process_graph(real_t p_delta) {
} else {
//find stuff to play
List<int> to_play;
- a->track_get_key_indices_in_range(i, time, delta, &to_play);
+ a->track_get_key_indices_in_range(i, time, delta, &to_play, pingponged);
if (to_play.size()) {
int idx = to_play.back()->get();