Refactor process of animation to retrive keys more exactly
This commit is contained in:
parent
0bb1e89fb7
commit
1fc3833617
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue