Refactor process of animation to retrive keys more exactly

This commit is contained in:
Silc Renew 2022-11-29 18:51:45 +09:00
parent 0bb1e89fb7
commit 1fc3833617
10 changed files with 394 additions and 275 deletions

View File

@ -616,5 +616,14 @@
<constant name="LOOP_PINGPONG" value="2" enum="LoopMode">
Repeats playback and reverse playback at both ends of the animation.
</constant>
<constant name="LOOPED_FLAG_NONE" value="0" enum="LoopedFlag">
This flag indicates that the animation proceeds without any looping.
</constant>
<constant name="LOOPED_FLAG_END" value="1" enum="LoopedFlag">
This flag indicates that the animation has reached the end of the animation and just after loop processed.
</constant>
<constant name="LOOPED_FLAG_START" value="2" enum="LoopedFlag">
This flag indicates that the animation has reached the start of the animation and just after loop processed.
</constant>
</constants>
</class>

View File

@ -75,9 +75,10 @@
<param index="3" name="seeked" type="bool" />
<param index="4" name="is_external_seeking" type="bool" />
<param index="5" name="blend" type="float" />
<param index="6" name="pingponged" type="int" default="0" />
<param index="6" name="looped_flag" type="int" enum="Animation.LoopedFlag" default="0" />
<description>
Blend an animation by [param blend] amount (name must be valid in the linked [AnimationPlayer]). A [param time] and [param delta] may be passed, as well as whether [param seeked] happened.
A [param looped_flag] is used by internal processing immediately after the loop. See also [enum Animation.LoopedFlag].
</description>
</method>
<method name="blend_input">

View File

@ -87,36 +87,38 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_ext
double anim_size = (double)anim->get_length();
double step = 0.0;
double prev_time = cur_time;
int pingponged = 0;
bool current_backward = signbit(p_time);
Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
bool node_backward = play_mode == PLAY_MODE_BACKWARD;
if (p_seek) {
step = p_time - cur_time;
cur_time = p_time;
} else {
p_time *= backward ? -1.0 : 1.0;
if (!(cur_time == anim_size && !current_backward) && !(cur_time == 0 && current_backward)) {
cur_time = cur_time + p_time;
step = p_time;
}
cur_time = cur_time + p_time;
step = p_time;
}
if (anim->get_loop_mode() == Animation::LOOP_PINGPONG) {
if (!Math::is_zero_approx(anim_size)) {
if ((int)Math::floor(abs(cur_time - prev_time) / anim_size) % 2 == 0) {
if (prev_time >= 0 && cur_time < 0) {
backward = !backward;
pingponged = -1;
}
if (prev_time <= anim_size && cur_time > anim_size) {
backward = !backward;
pingponged = 1;
}
if (prev_time >= 0 && cur_time < 0) {
backward = !backward;
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
}
if (prev_time <= anim_size && cur_time > anim_size) {
backward = !backward;
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
}
cur_time = Math::pingpong(cur_time, anim_size);
}
} else if (anim->get_loop_mode() == Animation::LOOP_LINEAR) {
if (!Math::is_zero_approx(anim_size)) {
if (prev_time >= 0 && cur_time < 0) {
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
}
if (prev_time <= anim_size && cur_time > anim_size) {
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
}
cur_time = Math::fposmod(cur_time, anim_size);
}
backward = false;
@ -145,9 +147,9 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_ext
}
if (play_mode == PLAY_MODE_FORWARD) {
blend_animation(animation, cur_time, step, p_seek, p_is_external_seeking, 1.0, pingponged);
blend_animation(animation, cur_time, step, p_seek, p_is_external_seeking, 1.0, looped_flag);
} else {
blend_animation(animation, anim_size - cur_time, -step, p_seek, p_is_external_seeking, 1.0, pingponged);
blend_animation(animation, anim_size - cur_time, -step, p_seek, p_is_external_seeking, 1.0, looped_flag);
}
set_parameter(time, cur_time);
@ -309,9 +311,7 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_exter
set_parameter(time_to_restart, cur_time_to_restart);
}
if (!cur_active) {
return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
}
return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
}
bool os_seek = p_seek;
@ -349,10 +349,9 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_exter
if (mix == MIX_MODE_ADD) {
main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
} else {
main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - blend, FILTER_BLEND, sync);
main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - blend, FILTER_BLEND, sync); // Unlike below, processing this edge is a corner case.
}
double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_is_external_seeking, blend, FILTER_PASS, true);
double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_is_external_seeking, MAX(CMP_EPSILON, blend), FILTER_PASS, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
if (do_start) {
cur_remaining = os_rem;
@ -769,17 +768,18 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
blend = xfade_curve->sample(blend);
}
// Blend values must be more than CMP_EPSILON to process discrete keys in edge.
if (from_start && !p_seek && switched) { //just switched, seek to start of current
rem = blend_input(cur_current, 0, true, p_is_external_seeking, 1.0 - blend, FILTER_IGNORE, true);
rem = blend_input(cur_current, 0, true, p_is_external_seeking, MAX(CMP_EPSILON, 1.0 - blend), FILTER_IGNORE, true);
} else {
rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, 1.0 - blend, FILTER_IGNORE, true);
rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, MAX(CMP_EPSILON, 1.0 - blend), FILTER_IGNORE, true);
}
if (p_seek) {
blend_input(cur_prev, p_time, true, p_is_external_seeking, blend, FILTER_IGNORE, true);
blend_input(cur_prev, p_time, true, p_is_external_seeking, MAX(CMP_EPSILON, blend), FILTER_IGNORE, true);
cur_time = p_time;
} else {
blend_input(cur_prev, p_time, false, p_is_external_seeking, blend, FILTER_IGNORE, true);
blend_input(cur_prev, p_time, false, p_is_external_seeking, MAX(CMP_EPSILON, blend), FILTER_IGNORE, true);
cur_time += p_time;
cur_prev_xfading -= p_time;
if (cur_prev_xfading < 0) {

View File

@ -433,10 +433,10 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
if (current_curve.is_valid()) {
fade_blend = current_curve->sample(fade_blend);
}
float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, fade_blend, AnimationNode::FILTER_IGNORE, true);
float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, MAX(CMP_EPSILON, fade_blend), AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
if (fading_from != StringName()) {
p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, 1.0 - fade_blend, AnimationNode::FILTER_IGNORE, true);
p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, MAX(CMP_EPSILON, 1.0 - fade_blend), AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
}
//guess playback position
@ -599,13 +599,11 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
current = next;
len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, CMP_EPSILON, AnimationNode::FILTER_IGNORE, true); // Process next node's first key in here.
if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true);
pos_current = MIN(pos_current, len_current);
p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true);
} else {
len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true);
pos_current = 0;
}

View File

@ -468,7 +468,7 @@ Variant AnimationPlayer::_post_process_key_value(const Ref<Animation> &p_anim, i
return p_value;
}
void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double p_time, double p_delta, float p_interp, bool p_is_current, bool p_seeked, bool p_started, int p_pingponged) {
void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double p_prev_time, double p_time, double p_delta, float p_interp, bool p_is_current, bool p_seeked, bool p_started, Animation::LoopedFlag p_looped_flag) {
_ensure_node_caches(p_anim);
ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count());
@ -683,7 +683,13 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} else if (p_is_current && p_delta != 0) {
List<int> indices;
a->track_get_key_indices_in_range(i, p_time, p_delta, &indices, p_pingponged);
if (p_started) {
int first_key = a->track_find_key(i, p_prev_time, true);
if (first_key >= 0) {
indices.push_back(first_key);
}
}
a->track_get_key_indices_in_range(i, p_time, p_delta, &indices, p_looped_flag);
for (int &F : indices) {
Variant value = a->track_get_key_value(i, F);
@ -742,7 +748,13 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
}
List<int> indices;
a->track_get_key_indices_in_range(i, p_time, p_delta, &indices, p_pingponged);
if (p_started) {
int first_key = a->track_find_key(i, p_prev_time, true);
if (first_key >= 0) {
indices.push_back(first_key);
}
}
a->track_get_key_indices_in_range(i, p_time, p_delta, &indices, p_looped_flag);
for (int &E : indices) {
StringName method = a->method_track_get_name(i, E);
@ -832,7 +844,13 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} else {
//find stuff to play
List<int> to_play;
a->track_get_key_indices_in_range(i, p_time, p_delta, &to_play, p_pingponged);
if (p_started) {
int first_key = a->track_find_key(i, p_prev_time, true);
if (first_key >= 0) {
to_play.push_back(first_key);
}
}
a->track_get_key_indices_in_range(i, p_time, p_delta, &to_play, p_looped_flag);
if (to_play.size()) {
int idx = to_play.back()->get();
@ -939,7 +957,13 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} else {
//find stuff to play
List<int> to_play;
a->track_get_key_indices_in_range(i, p_time, p_delta, &to_play, p_pingponged);
if (p_started) {
int first_key = a->track_find_key(i, p_prev_time, true);
if (first_key >= 0) {
to_play.push_back(first_key);
}
}
a->track_get_key_indices_in_range(i, p_time, p_delta, &to_play, p_looped_flag);
if (to_play.size()) {
int idx = to_play.back()->get();
@ -969,7 +993,7 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, double p_delta,
double next_pos = cd.pos + delta;
real_t len = cd.from->animation->get_length();
int pingponged = 0;
Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
switch (cd.from->animation->get_loop_mode()) {
case Animation::LOOP_NONE: {
@ -998,44 +1022,33 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, double p_delta,
} break;
case Animation::LOOP_LINEAR: {
double looped_next_pos = Math::fposmod(next_pos, (double)len);
if (looped_next_pos == 0 && next_pos != 0) {
// Loop multiples of the length to it, rather than 0
// so state at time=length is previewable in the editor
next_pos = len;
} else {
next_pos = looped_next_pos;
if (next_pos < 0 && cd.pos >= 0) {
looped_flag = Animation::LOOPED_FLAG_START;
}
if (next_pos > len && cd.pos <= len) {
looped_flag = Animation::LOOPED_FLAG_END;
}
next_pos = Math::fposmod(next_pos, (double)len);
} break;
case Animation::LOOP_PINGPONG: {
if ((int)Math::floor(abs(next_pos - cd.pos) / len) % 2 == 0) {
if (next_pos < 0 && cd.pos >= 0) {
cd.speed_scale *= -1.0;
pingponged = -1;
}
if (next_pos > len && cd.pos <= len) {
cd.speed_scale *= -1.0;
pingponged = 1;
}
if (next_pos < 0 && cd.pos >= 0) {
cd.speed_scale *= -1.0;
looped_flag = Animation::LOOPED_FLAG_START;
}
double looped_next_pos = Math::pingpong(next_pos, (double)len);
if (looped_next_pos == 0 && next_pos != 0) {
// Loop multiples of the length to it, rather than 0
// so state at time=length is previewable in the editor
next_pos = len;
} else {
next_pos = looped_next_pos;
if (next_pos > len && cd.pos <= len) {
cd.speed_scale *= -1.0;
looped_flag = Animation::LOOPED_FLAG_END;
}
next_pos = Math::pingpong(next_pos, (double)len);
} break;
default:
break;
}
_animation_process_animation(cd.from, cd.pos, next_pos, delta, p_blend, &cd == &playback.current, p_seeked, p_started, looped_flag);
cd.pos = next_pos;
_animation_process_animation(cd.from, cd.pos, delta, p_blend, &cd == &playback.current, p_seeked, p_started, pingponged);
}
void AnimationPlayer::_animation_process2(double p_delta, bool p_started) {

View File

@ -268,7 +268,7 @@ private:
NodePath root;
void _animation_process_animation(AnimationData *p_anim, double p_time, double p_delta, float p_interp, bool p_is_current = true, bool p_seeked = false, bool p_started = false, int p_pingponged = 0);
void _animation_process_animation(AnimationData *p_anim, double p_prev_time, double p_time, double p_delta, float p_interp, bool p_is_current = true, bool p_seeked = false, bool p_started = false, Animation::LoopedFlag p_looped_flag = Animation::LOOPED_FLAG_NONE);
void _ensure_node_caches(AnimationData *p_anim, Node *p_root_override = nullptr);
void _animation_process_data(PlaybackData &cd, double p_delta, float p_blend, bool p_seeked, bool p_started);

View File

@ -86,7 +86,7 @@ void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
}
}
void AnimationNode::blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, int p_pingponged) {
void AnimationNode::blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, Animation::LoopedFlag p_looped_flag) {
ERR_FAIL_COND(!state);
ERR_FAIL_COND(!state->player->has_animation(p_animation));
@ -112,7 +112,7 @@ void AnimationNode::blend_animation(const StringName &p_animation, double p_time
anim_state.time = p_time;
anim_state.animation = animation;
anim_state.seeked = p_seeked;
anim_state.pingponged = p_pingponged;
anim_state.looped_flag = p_looped_flag;
anim_state.is_external_seeking = p_is_external_seeking;
state->animation_states.push_back(anim_state);
@ -413,7 +413,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", "is_external_seeking", "blend", "pingponged"), &AnimationNode::blend_animation, DEFVAL(0));
ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "is_external_seeking", "blend", "looped_flag"), &AnimationNode::blend_animation, DEFVAL(Animation::LOOPED_FLAG_NONE));
ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "is_external_seeking", "blend", "filter", "sync"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "is_external_seeking", "blend", "filter", "sync"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
@ -1019,7 +1019,7 @@ void AnimationTree::_process_graph(double p_delta) {
double delta = as.delta;
real_t weight = as.blend;
bool seeked = as.seeked;
int pingponged = as.pingponged;
Animation::LoopedFlag looped_flag = as.looped_flag;
bool is_external_seeking = as.is_external_seeking;
#ifndef _3D_DISABLED
bool backward = signbit(delta); // This flag is required only for the root motion since it calculates the difference between the previous and current frames.
@ -1391,7 +1391,7 @@ void AnimationTree::_process_graph(double p_delta) {
t->object->set_indexed(t->subpath, value);
} else {
List<int> indices;
a->track_get_key_indices_in_range(i, time, delta, &indices, pingponged);
a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);
for (int &F : indices) {
Variant value = a->track_get_key_value(i, F);
value = _post_process_key_value(a, i, value, t->object);
@ -1416,7 +1416,7 @@ void AnimationTree::_process_graph(double p_delta) {
}
} else {
List<int> indices;
a->track_get_key_indices_in_range(i, time, delta, &indices, pingponged);
a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);
for (int &F : indices) {
StringName method = a->method_track_get_name(i, F);
Vector<Variant> params = a->method_track_get_params(i, F);
@ -1479,7 +1479,7 @@ void AnimationTree::_process_graph(double p_delta) {
} else {
//find stuff to play
List<int> to_play;
a->track_get_key_indices_in_range(i, time, delta, &to_play, pingponged);
a->track_get_key_indices_in_range(i, time, delta, &to_play, looped_flag);
if (to_play.size()) {
int idx = to_play.back()->get();
@ -1594,7 +1594,7 @@ void AnimationTree::_process_graph(double p_delta) {
} else {
//find stuff to play
List<int> to_play;
a->track_get_key_indices_in_range(i, time, delta, &to_play, pingponged);
a->track_get_key_indices_in_range(i, time, delta, &to_play, looped_flag);
if (to_play.size()) {
int idx = to_play.back()->get();

View File

@ -69,7 +69,7 @@ public:
real_t blend = 0.0;
bool seeked = false;
bool is_external_seeking = false;
int pingponged = 0;
Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
};
struct State {
@ -102,7 +102,7 @@ public:
double _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, real_t *r_max = nullptr);
protected:
void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, int p_pingponged = 0);
void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, Animation::LoopedFlag p_looped_flag = Animation::LOOPED_FLAG_NONE);
double blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true);
double blend_input(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true);

View File

@ -2726,40 +2726,60 @@ Animation::UpdateMode Animation::value_track_get_update_mode(int p_track) const
}
template <class T>
void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices) const {
if (to_time == length) {
to_time = length + CMP_EPSILON; //include a little more if at the end
void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices, bool p_is_backward) const {
int len = p_array.size();
if (len == 0) {
return;
}
int to = _find(p_array, to_time);
int from = 0;
int to = len - 1;
// can't really send the events == time, will be sent in the next frame.
// if event>=len then it will probably never be requested by the anim player.
if (to >= 0 && p_array[to].time >= to_time) {
to--;
if (!p_is_backward) {
while (p_array[from].time < from_time || Math::is_equal_approx(p_array[from].time, from_time)) {
from++;
if (to < from) {
return;
}
}
while (p_array[to].time > to_time && !Math::is_equal_approx(p_array[to].time, to_time)) {
to--;
if (to < from) {
return;
}
}
} else {
while (p_array[from].time < from_time && !Math::is_equal_approx(p_array[from].time, from_time)) {
from++;
if (to < from) {
return;
}
}
while (p_array[to].time > to_time || Math::is_equal_approx(p_array[to].time, to_time)) {
to--;
if (to < from) {
return;
}
}
}
if (to < 0) {
return; // not bother
if (from == to) {
p_indices->push_back(from);
return;
}
int from = _find(p_array, from_time);
// position in the right first event.+
if (from < 0 || p_array[from].time < from_time) {
from++;
}
int max = p_array.size();
for (int i = from; i <= to; i++) {
ERR_CONTINUE(i < 0 || i >= max); // shouldn't happen
p_indices->push_back(i);
if (!p_is_backward) {
for (int i = from; i <= to; i++) {
p_indices->push_back(i);
}
} else {
for (int i = to; i >= to; i--) {
p_indices->push_back(i);
}
}
}
void Animation::track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged) const {
void Animation::track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices, Animation::LoopedFlag p_looped_flag) const {
ERR_FAIL_INDEX(p_track, tracks.size());
if (p_delta == 0) {
@ -2771,7 +2791,9 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
double from_time = p_time - p_delta;
double to_time = p_time;
bool is_backward = false;
if (from_time > to_time) {
is_backward = true;
SWAP(from_time, to_time);
}
@ -2800,7 +2822,10 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
}
if (from_time > to_time) {
// handle loop by splitting
// Handle loop by splitting.
double anim_end = length + CMP_EPSILON;
double anim_start = -CMP_EPSILON;
switch (t->type) {
case TYPE_POSITION_3D: {
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
@ -2808,8 +2833,13 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
_get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, to_time, p_indices);
} else {
_track_get_key_indices_in_range(tt->positions, from_time, length, p_indices);
_track_get_key_indices_in_range(tt->positions, 0, to_time, p_indices);
if (!is_backward) {
_track_get_key_indices_in_range(tt->positions, from_time, anim_end, p_indices, is_backward);
_track_get_key_indices_in_range(tt->positions, anim_start, to_time, p_indices, is_backward);
} else {
_track_get_key_indices_in_range(tt->positions, anim_start, to_time, p_indices, is_backward);
_track_get_key_indices_in_range(tt->positions, from_time, anim_end, p_indices, is_backward);
}
}
} break;
case TYPE_ROTATION_3D: {
@ -2818,8 +2848,13 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
_get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, to_time, p_indices);
} else {
_track_get_key_indices_in_range(rt->rotations, from_time, length, p_indices);
_track_get_key_indices_in_range(rt->rotations, 0, to_time, p_indices);
if (!is_backward) {
_track_get_key_indices_in_range(rt->rotations, from_time, anim_end, p_indices, is_backward);
_track_get_key_indices_in_range(rt->rotations, anim_start, to_time, p_indices, is_backward);
} else {
_track_get_key_indices_in_range(rt->rotations, anim_start, to_time, p_indices, is_backward);
_track_get_key_indices_in_range(rt->rotations, from_time, anim_end, p_indices, is_backward);
}
}
} break;
case TYPE_SCALE_3D: {
@ -2828,8 +2863,13 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
_get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<3>(st->compressed_track, 0, to_time, p_indices);
} else {
_track_get_key_indices_in_range(st->scales, from_time, length, p_indices);
_track_get_key_indices_in_range(st->scales, 0, to_time, p_indices);
if (!is_backward) {
_track_get_key_indices_in_range(st->scales, from_time, anim_end, p_indices, is_backward);
_track_get_key_indices_in_range(st->scales, anim_start, to_time, p_indices, is_backward);
} else {
_track_get_key_indices_in_range(st->scales, anim_start, to_time, p_indices, is_backward);
_track_get_key_indices_in_range(st->scales, from_time, anim_end, p_indices, is_backward);
}
}
} break;
case TYPE_BLEND_SHAPE: {
@ -2838,38 +2878,83 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, to_time, p_indices);
} else {
_track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices);
_track_get_key_indices_in_range(bst->blend_shapes, 0, to_time, p_indices);
if (!is_backward) {
_track_get_key_indices_in_range(bst->blend_shapes, from_time, anim_end, p_indices, is_backward);
_track_get_key_indices_in_range(bst->blend_shapes, anim_start, to_time, p_indices, is_backward);
} else {
_track_get_key_indices_in_range(bst->blend_shapes, anim_start, to_time, p_indices, is_backward);
_track_get_key_indices_in_range(bst->blend_shapes, from_time, anim_end, p_indices, is_backward);
}
}
} break;
case TYPE_VALUE: {
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
_track_get_key_indices_in_range(vt->values, from_time, length, p_indices);
_track_get_key_indices_in_range(vt->values, 0, to_time, p_indices);
if (!is_backward) {
_track_get_key_indices_in_range(vt->values, from_time, anim_end, p_indices, is_backward);
_track_get_key_indices_in_range(vt->values, anim_start, to_time, p_indices, is_backward);
} else {
_track_get_key_indices_in_range(vt->values, anim_start, to_time, p_indices, is_backward);
_track_get_key_indices_in_range(vt->values, from_time, anim_end, p_indices, is_backward);
}
} break;
case TYPE_METHOD: {
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
_track_get_key_indices_in_range(mt->methods, from_time, length, p_indices);
_track_get_key_indices_in_range(mt->methods, 0, to_time, p_indices);
if (!is_backward) {
_track_get_key_indices_in_range(mt->methods, from_time, anim_end, p_indices, is_backward);
_track_get_key_indices_in_range(mt->methods, anim_start, to_time, p_indices, is_backward);
} else {
_track_get_key_indices_in_range(mt->methods, anim_start, to_time, p_indices, is_backward);
_track_get_key_indices_in_range(mt->methods, from_time, anim_end, p_indices, is_backward);
}
} break;
case TYPE_BEZIER: {
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
_track_get_key_indices_in_range(bz->values, from_time, length, p_indices);
_track_get_key_indices_in_range(bz->values, 0, to_time, p_indices);
if (!is_backward) {
_track_get_key_indices_in_range(bz->values, from_time, anim_end, p_indices, is_backward);
_track_get_key_indices_in_range(bz->values, anim_start, to_time, p_indices, is_backward);
} else {
_track_get_key_indices_in_range(bz->values, anim_start, to_time, p_indices, is_backward);
_track_get_key_indices_in_range(bz->values, from_time, anim_end, p_indices, is_backward);
}
} break;
case TYPE_AUDIO: {
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
_track_get_key_indices_in_range(ad->values, from_time, length, p_indices);
_track_get_key_indices_in_range(ad->values, 0, to_time, p_indices);
if (!is_backward) {
_track_get_key_indices_in_range(ad->values, from_time, anim_end, p_indices, is_backward);
_track_get_key_indices_in_range(ad->values, anim_start, to_time, p_indices, is_backward);
} else {
_track_get_key_indices_in_range(ad->values, anim_start, to_time, p_indices, is_backward);
_track_get_key_indices_in_range(ad->values, from_time, anim_end, p_indices, is_backward);
}
} break;
case TYPE_ANIMATION: {
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
_track_get_key_indices_in_range(an->values, from_time, length, p_indices);
_track_get_key_indices_in_range(an->values, 0, to_time, p_indices);
if (!is_backward) {
_track_get_key_indices_in_range(an->values, from_time, anim_end, p_indices, is_backward);
_track_get_key_indices_in_range(an->values, anim_start, to_time, p_indices, is_backward);
} else {
_track_get_key_indices_in_range(an->values, anim_start, to_time, p_indices, is_backward);
_track_get_key_indices_in_range(an->values, from_time, anim_end, p_indices, is_backward);
}
} break;
}
return;
}
// Not from_time > to_time but most recent of looping...
if (p_looped_flag != Animation::LOOPED_FLAG_NONE) {
if (!is_backward && Math::is_equal_approx(from_time, 0)) {
int edge = track_find_key(p_track, 0, true);
if (edge >= 0) {
p_indices->push_back(edge);
}
} else if (is_backward && Math::is_equal_approx(to_time, length)) {
int edge = track_find_key(p_track, length, true);
if (edge >= 0) {
p_indices->push_back(edge);
}
}
}
} break;
case LOOP_PINGPONG: {
if (from_time > length || from_time < 0) {
@ -2879,162 +2964,164 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
to_time = Math::pingpong(to_time, length);
}
if ((int)Math::floor(abs(p_delta) / length) % 2 == 0) {
if (p_pingponged == -1) {
// handle loop by splitting
to_time = MAX(CMP_EPSILON, to_time); // To avoid overlapping keys at the turnaround point, one of the point will needs to be shifted slightly.
switch (t->type) {
case TYPE_POSITION_3D: {
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
if (tt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, from_time, p_indices);
_get_compressed_key_indices_in_range<3>(tt->compressed_track, CMP_EPSILON, to_time, p_indices);
} else {
_track_get_key_indices_in_range(tt->positions, 0, from_time, p_indices);
_track_get_key_indices_in_range(tt->positions, CMP_EPSILON, to_time, p_indices);
}
} break;
case TYPE_ROTATION_3D: {
const RotationTrack *rt = static_cast<const RotationTrack *>(t);
if (rt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, from_time, p_indices);
_get_compressed_key_indices_in_range<3>(rt->compressed_track, CMP_EPSILON, to_time, p_indices);
} else {
_track_get_key_indices_in_range(rt->rotations, 0, from_time, p_indices);
_track_get_key_indices_in_range(rt->rotations, CMP_EPSILON, to_time, p_indices);
}
} break;
case TYPE_SCALE_3D: {
const ScaleTrack *st = static_cast<const ScaleTrack *>(t);
if (st->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(st->compressed_track, 0, from_time, p_indices);
_get_compressed_key_indices_in_range<3>(st->compressed_track, CMP_EPSILON, to_time, p_indices);
} else {
_track_get_key_indices_in_range(st->scales, 0, from_time, p_indices);
_track_get_key_indices_in_range(st->scales, CMP_EPSILON, to_time, p_indices);
}
} break;
case TYPE_BLEND_SHAPE: {
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
if (bst->compressed_track >= 0) {
_get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, from_time, p_indices);
_get_compressed_key_indices_in_range<1>(bst->compressed_track, CMP_EPSILON, to_time, p_indices);
} else {
_track_get_key_indices_in_range(bst->blend_shapes, 0, from_time, p_indices);
_track_get_key_indices_in_range(bst->blend_shapes, CMP_EPSILON, to_time, p_indices);
}
} break;
case TYPE_VALUE: {
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
_track_get_key_indices_in_range(vt->values, 0, from_time, p_indices);
_track_get_key_indices_in_range(vt->values, CMP_EPSILON, to_time, p_indices);
} break;
case TYPE_METHOD: {
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
_track_get_key_indices_in_range(mt->methods, 0, from_time, p_indices);
_track_get_key_indices_in_range(mt->methods, CMP_EPSILON, to_time, p_indices);
} break;
case TYPE_BEZIER: {
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
_track_get_key_indices_in_range(bz->values, 0, from_time, p_indices);
_track_get_key_indices_in_range(bz->values, CMP_EPSILON, to_time, p_indices);
} break;
case TYPE_AUDIO: {
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
_track_get_key_indices_in_range(ad->values, 0, from_time, p_indices);
_track_get_key_indices_in_range(ad->values, CMP_EPSILON, to_time, p_indices);
} break;
case TYPE_ANIMATION: {
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
_track_get_key_indices_in_range(an->values, 0, from_time, p_indices);
_track_get_key_indices_in_range(an->values, CMP_EPSILON, to_time, p_indices);
} break;
}
return;
if (p_looped_flag == Animation::LOOPED_FLAG_START) {
// Handle loop by splitting.
switch (t->type) {
case TYPE_POSITION_3D: {
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
if (tt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, from_time, p_indices);
_get_compressed_key_indices_in_range<3>(tt->compressed_track, CMP_EPSILON, to_time, p_indices);
} else {
_track_get_key_indices_in_range(tt->positions, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(tt->positions, 0, to_time, p_indices, false);
}
} break;
case TYPE_ROTATION_3D: {
const RotationTrack *rt = static_cast<const RotationTrack *>(t);
if (rt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, from_time, p_indices);
_get_compressed_key_indices_in_range<3>(rt->compressed_track, CMP_EPSILON, to_time, p_indices);
} else {
_track_get_key_indices_in_range(rt->rotations, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(rt->rotations, 0, to_time, p_indices, false);
}
} break;
case TYPE_SCALE_3D: {
const ScaleTrack *st = static_cast<const ScaleTrack *>(t);
if (st->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(st->compressed_track, 0, from_time, p_indices);
_get_compressed_key_indices_in_range<3>(st->compressed_track, 0, to_time, p_indices);
} else {
_track_get_key_indices_in_range(st->scales, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(st->scales, 0, to_time, p_indices, false);
}
} break;
case TYPE_BLEND_SHAPE: {
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
if (bst->compressed_track >= 0) {
_get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, from_time, p_indices);
_get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, to_time, p_indices);
} else {
_track_get_key_indices_in_range(bst->blend_shapes, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(bst->blend_shapes, 0, to_time, p_indices, false);
}
} break;
case TYPE_VALUE: {
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
_track_get_key_indices_in_range(vt->values, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(vt->values, 0, to_time, p_indices, false);
} break;
case TYPE_METHOD: {
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
_track_get_key_indices_in_range(mt->methods, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(mt->methods, 0, to_time, p_indices, false);
} break;
case TYPE_BEZIER: {
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
_track_get_key_indices_in_range(bz->values, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(bz->values, 0, to_time, p_indices, false);
} break;
case TYPE_AUDIO: {
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
_track_get_key_indices_in_range(ad->values, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(ad->values, 0, to_time, p_indices, false);
} break;
case TYPE_ANIMATION: {
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
_track_get_key_indices_in_range(an->values, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(an->values, 0, to_time, p_indices, false);
} break;
}
if (p_pingponged == 1) {
// handle loop by splitting
to_time = MIN(length - CMP_EPSILON, to_time);
switch (t->type) {
case TYPE_POSITION_3D: {
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
if (tt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<3>(tt->compressed_track, to_time, length - CMP_EPSILON, p_indices);
} else {
_track_get_key_indices_in_range(tt->positions, from_time, length, p_indices);
_track_get_key_indices_in_range(tt->positions, to_time, length - CMP_EPSILON, p_indices);
}
} break;
case TYPE_ROTATION_3D: {
const RotationTrack *rt = static_cast<const RotationTrack *>(t);
if (rt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<3>(rt->compressed_track, to_time, length, p_indices);
} else {
_track_get_key_indices_in_range(rt->rotations, from_time, length, p_indices);
_track_get_key_indices_in_range(rt->rotations, to_time, length - CMP_EPSILON, p_indices);
}
} break;
case TYPE_SCALE_3D: {
const ScaleTrack *st = static_cast<const ScaleTrack *>(t);
if (st->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<3>(st->compressed_track, to_time, length, p_indices);
} else {
_track_get_key_indices_in_range(st->scales, from_time, length, p_indices);
_track_get_key_indices_in_range(st->scales, to_time, length - CMP_EPSILON, p_indices);
}
} break;
case TYPE_BLEND_SHAPE: {
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
if (bst->compressed_track >= 0) {
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length - CMP_EPSILON, p_indices);
} else {
_track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices);
_track_get_key_indices_in_range(bst->blend_shapes, to_time, length - CMP_EPSILON, p_indices);
}
} break;
case TYPE_VALUE: {
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
_track_get_key_indices_in_range(vt->values, from_time, length, p_indices);
_track_get_key_indices_in_range(vt->values, to_time, length - CMP_EPSILON, p_indices);
} break;
case TYPE_METHOD: {
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
_track_get_key_indices_in_range(mt->methods, from_time, length, p_indices);
_track_get_key_indices_in_range(mt->methods, to_time, length - CMP_EPSILON, p_indices);
} break;
case TYPE_BEZIER: {
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
_track_get_key_indices_in_range(bz->values, from_time, length, p_indices);
_track_get_key_indices_in_range(bz->values, to_time, length - CMP_EPSILON, p_indices);
} break;
case TYPE_AUDIO: {
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
_track_get_key_indices_in_range(ad->values, from_time, length, p_indices);
_track_get_key_indices_in_range(ad->values, to_time, length - CMP_EPSILON, p_indices);
} break;
case TYPE_ANIMATION: {
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
_track_get_key_indices_in_range(an->values, from_time, length, p_indices);
_track_get_key_indices_in_range(an->values, to_time, length - CMP_EPSILON, p_indices);
} break;
}
return;
return;
}
if (p_looped_flag == Animation::LOOPED_FLAG_END) {
// Handle loop by splitting.
switch (t->type) {
case TYPE_POSITION_3D: {
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
if (tt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<3>(tt->compressed_track, to_time, length, p_indices);
} else {
_track_get_key_indices_in_range(tt->positions, from_time, length, p_indices, false);
_track_get_key_indices_in_range(tt->positions, to_time, length, p_indices, true);
}
} break;
case TYPE_ROTATION_3D: {
const RotationTrack *rt = static_cast<const RotationTrack *>(t);
if (rt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<3>(rt->compressed_track, to_time, length, p_indices);
} else {
_track_get_key_indices_in_range(rt->rotations, from_time, length, p_indices, false);
_track_get_key_indices_in_range(rt->rotations, to_time, length, p_indices, true);
}
} break;
case TYPE_SCALE_3D: {
const ScaleTrack *st = static_cast<const ScaleTrack *>(t);
if (st->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<3>(st->compressed_track, to_time, length, p_indices);
} else {
_track_get_key_indices_in_range(st->scales, from_time, length, p_indices, false);
_track_get_key_indices_in_range(st->scales, to_time, length, p_indices, true);
}
} break;
case TYPE_BLEND_SHAPE: {
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
if (bst->compressed_track >= 0) {
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length - CMP_EPSILON, p_indices);
} else {
_track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices, false);
_track_get_key_indices_in_range(bst->blend_shapes, to_time, length, p_indices, true);
}
} break;
case TYPE_VALUE: {
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
_track_get_key_indices_in_range(vt->values, from_time, length, p_indices, false);
_track_get_key_indices_in_range(vt->values, to_time, length, p_indices, true);
} break;
case TYPE_METHOD: {
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
_track_get_key_indices_in_range(mt->methods, from_time, length, p_indices, false);
_track_get_key_indices_in_range(mt->methods, to_time, length, p_indices, true);
} break;
case TYPE_BEZIER: {
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
_track_get_key_indices_in_range(bz->values, from_time, length, p_indices, false);
_track_get_key_indices_in_range(bz->values, to_time, length, p_indices, true);
} break;
case TYPE_AUDIO: {
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
_track_get_key_indices_in_range(ad->values, from_time, length, p_indices, false);
_track_get_key_indices_in_range(ad->values, to_time, length, p_indices, true);
} break;
case TYPE_ANIMATION: {
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
_track_get_key_indices_in_range(an->values, from_time, length, p_indices, false);
_track_get_key_indices_in_range(an->values, to_time, length, p_indices, true);
} break;
}
return;
}
// The edge will be pingponged in the next frame and processed there, so let's ignore it now...
if (!is_backward && Math::is_equal_approx(to_time, length)) {
to_time = length - CMP_EPSILON;
} else if (is_backward && Math::is_equal_approx(from_time, 0)) {
from_time = CMP_EPSILON;
}
} break;
}
switch (t->type) {
case TYPE_POSITION_3D: {
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
if (tt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, to_time - from_time, p_indices);
} else {
_track_get_key_indices_in_range(tt->positions, from_time, to_time, p_indices);
_track_get_key_indices_in_range(tt->positions, from_time, to_time, p_indices, is_backward);
}
} break;
case TYPE_ROTATION_3D: {
@ -3042,7 +3129,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
if (rt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, to_time - from_time, p_indices);
} else {
_track_get_key_indices_in_range(rt->rotations, from_time, to_time, p_indices);
_track_get_key_indices_in_range(rt->rotations, from_time, to_time, p_indices, is_backward);
}
} break;
case TYPE_SCALE_3D: {
@ -3050,7 +3137,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
if (st->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, to_time - from_time, p_indices);
} else {
_track_get_key_indices_in_range(st->scales, from_time, to_time, p_indices);
_track_get_key_indices_in_range(st->scales, from_time, to_time, p_indices, is_backward);
}
} break;
case TYPE_BLEND_SHAPE: {
@ -3058,28 +3145,28 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
if (bst->compressed_track >= 0) {
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, to_time - from_time, p_indices);
} else {
_track_get_key_indices_in_range(bst->blend_shapes, from_time, to_time, p_indices);
_track_get_key_indices_in_range(bst->blend_shapes, from_time, to_time, p_indices, is_backward);
}
} break;
case TYPE_VALUE: {
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
_track_get_key_indices_in_range(vt->values, from_time, to_time, p_indices);
_track_get_key_indices_in_range(vt->values, from_time, to_time, p_indices, is_backward);
} break;
case TYPE_METHOD: {
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
_track_get_key_indices_in_range(mt->methods, from_time, to_time, p_indices);
_track_get_key_indices_in_range(mt->methods, from_time, to_time, p_indices, is_backward);
} break;
case TYPE_BEZIER: {
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
_track_get_key_indices_in_range(bz->values, from_time, to_time, p_indices);
_track_get_key_indices_in_range(bz->values, from_time, to_time, p_indices, is_backward);
} break;
case TYPE_AUDIO: {
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
_track_get_key_indices_in_range(ad->values, from_time, to_time, p_indices);
_track_get_key_indices_in_range(ad->values, from_time, to_time, p_indices, is_backward);
} break;
case TYPE_ANIMATION: {
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
_track_get_key_indices_in_range(an->values, from_time, to_time, p_indices);
_track_get_key_indices_in_range(an->values, from_time, to_time, p_indices, is_backward);
} break;
}
}
@ -3815,6 +3902,10 @@ void Animation::_bind_methods() {
BIND_ENUM_CONSTANT(LOOP_NONE);
BIND_ENUM_CONSTANT(LOOP_LINEAR);
BIND_ENUM_CONSTANT(LOOP_PINGPONG);
BIND_ENUM_CONSTANT(LOOPED_FLAG_NONE);
BIND_ENUM_CONSTANT(LOOPED_FLAG_END);
BIND_ENUM_CONSTANT(LOOPED_FLAG_START);
}
void Animation::clear() {
@ -5798,7 +5889,8 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float
}
}
Animation::Animation() {}
Animation::Animation() {
}
Animation::~Animation() {
for (int i = 0; i < tracks.size(); i++) {

View File

@ -74,6 +74,12 @@ public:
LOOP_PINGPONG,
};
enum LoopedFlag {
LOOPED_FLAG_NONE,
LOOPED_FLAG_END,
LOOPED_FLAG_START,
};
#ifdef TOOLS_ENABLED
enum HandleMode {
HANDLE_MODE_FREE,
@ -250,12 +256,11 @@ private:
_FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward = false) const;
template <class T>
_FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices) const;
_FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices, bool p_is_backward) const;
double length = 1.0;
real_t step = 0.1;
LoopMode loop_mode = LOOP_NONE;
int pingponged = 0;
/* Animation compression page format (version 1):
*
@ -454,7 +459,7 @@ public:
void copy_track(int p_track, Ref<Animation> p_to_animation);
void track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged = 0) const;
void track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices, Animation::LoopedFlag p_looped_flag = Animation::LOOPED_FLAG_NONE) const;
void set_length(real_t p_length);
real_t get_length() const;
@ -484,6 +489,7 @@ VARIANT_ENUM_CAST(Animation::TrackType);
VARIANT_ENUM_CAST(Animation::InterpolationType);
VARIANT_ENUM_CAST(Animation::UpdateMode);
VARIANT_ENUM_CAST(Animation::LoopMode);
VARIANT_ENUM_CAST(Animation::LoopedFlag);
#ifdef TOOLS_ENABLED
VARIANT_ENUM_CAST(Animation::HandleMode);
VARIANT_ENUM_CAST(Animation::HandleSetMode);