Merge pull request #94554 from TokageItLab/approx-animation-compare
Add approximate comparing static methods to Animation and make Animation code use them
This commit is contained in:
commit
2966199647
6 changed files with 93 additions and 72 deletions
|
@ -144,7 +144,7 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
|
||||||
if (cur_loop_mode != Animation::LOOP_NONE) {
|
if (cur_loop_mode != Animation::LOOP_NONE) {
|
||||||
if (cur_loop_mode == Animation::LOOP_LINEAR) {
|
if (cur_loop_mode == Animation::LOOP_LINEAR) {
|
||||||
if (!Math::is_zero_approx(cur_len)) {
|
if (!Math::is_zero_approx(cur_len)) {
|
||||||
if (prev_time <= cur_len && cur_time > cur_len) {
|
if (Animation::is_less_or_equal_approx(prev_time, cur_len) && Animation::is_greater_approx(cur_time, cur_len)) {
|
||||||
is_just_looped = true; // Don't break with negative timescale since remain will not be 0.
|
is_just_looped = true; // Don't break with negative timescale since remain will not be 0.
|
||||||
}
|
}
|
||||||
cur_time = Math::fposmod(cur_time, cur_len);
|
cur_time = Math::fposmod(cur_time, cur_len);
|
||||||
|
@ -152,9 +152,9 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
|
||||||
backward = false;
|
backward = false;
|
||||||
} else {
|
} else {
|
||||||
if (!Math::is_zero_approx(cur_len)) {
|
if (!Math::is_zero_approx(cur_len)) {
|
||||||
if (prev_time >= 0 && cur_time < 0) {
|
if (Animation::is_greater_or_equal_approx(prev_time, 0) && Animation::is_less_approx(cur_time, 0)) {
|
||||||
backward = !backward;
|
backward = !backward;
|
||||||
} else if (prev_time <= cur_len && cur_time > cur_len) {
|
} else if (Animation::is_less_or_equal_approx(prev_time, cur_len) && Animation::is_greater_approx(cur_time, cur_len)) {
|
||||||
backward = !backward;
|
backward = !backward;
|
||||||
is_just_looped = true; // Don't break with negative timescale since remain will not be 0.
|
is_just_looped = true; // Don't break with negative timescale since remain will not be 0.
|
||||||
}
|
}
|
||||||
|
@ -162,10 +162,10 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cur_time < 0) {
|
if (Animation::is_less_approx(cur_time, 0)) {
|
||||||
cur_delta += cur_time;
|
cur_delta += cur_time;
|
||||||
cur_time = 0;
|
cur_time = 0;
|
||||||
} else if (cur_time > cur_len) {
|
} else if (Animation::is_greater_approx(cur_time, cur_len)) {
|
||||||
cur_delta += cur_time - cur_len;
|
cur_delta += cur_time - cur_len;
|
||||||
cur_time = cur_len;
|
cur_time = cur_len;
|
||||||
}
|
}
|
||||||
|
@ -173,11 +173,11 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
|
||||||
// If ended, don't progress AnimationNode. So set delta to 0.
|
// If ended, don't progress AnimationNode. So set delta to 0.
|
||||||
if (!Math::is_zero_approx(cur_delta)) {
|
if (!Math::is_zero_approx(cur_delta)) {
|
||||||
if (play_mode == PLAY_MODE_FORWARD) {
|
if (play_mode == PLAY_MODE_FORWARD) {
|
||||||
if (prev_time >= cur_len) {
|
if (Animation::is_greater_or_equal_approx(prev_time, cur_len)) {
|
||||||
cur_delta = 0;
|
cur_delta = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (prev_time <= 0) {
|
if (Animation::is_less_or_equal_approx(prev_time, 0)) {
|
||||||
cur_delta = 0;
|
cur_delta = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,6 +197,7 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
|
||||||
double cur_playback_time = cur_time + start_offset;
|
double cur_playback_time = cur_time + start_offset;
|
||||||
if (stretch_time_scale) {
|
if (stretch_time_scale) {
|
||||||
double mlt = anim_size / cur_len;
|
double mlt = anim_size / cur_len;
|
||||||
|
prev_playback_time *= mlt;
|
||||||
cur_playback_time *= mlt;
|
cur_playback_time *= mlt;
|
||||||
cur_delta *= mlt;
|
cur_delta *= mlt;
|
||||||
}
|
}
|
||||||
|
@ -204,31 +205,31 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
|
||||||
if (!Math::is_zero_approx(anim_size)) {
|
if (!Math::is_zero_approx(anim_size)) {
|
||||||
prev_playback_time = Math::fposmod(prev_playback_time, anim_size);
|
prev_playback_time = Math::fposmod(prev_playback_time, anim_size);
|
||||||
cur_playback_time = Math::fposmod(cur_playback_time, anim_size);
|
cur_playback_time = Math::fposmod(cur_playback_time, anim_size);
|
||||||
if (prev_playback_time >= 0 && cur_playback_time < 0) {
|
if (Animation::is_greater_or_equal_approx(prev_playback_time, 0) && Animation::is_less_approx(cur_playback_time, 0)) {
|
||||||
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
|
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
|
||||||
}
|
}
|
||||||
if (prev_playback_time <= anim_size && cur_playback_time > anim_size) {
|
if (Animation::is_less_or_equal_approx(prev_playback_time, anim_size) && Animation::is_greater_approx(cur_playback_time, anim_size)) {
|
||||||
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
|
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (cur_loop_mode == Animation::LOOP_PINGPONG) {
|
} else if (cur_loop_mode == Animation::LOOP_PINGPONG) {
|
||||||
if (!Math::is_zero_approx(anim_size)) {
|
if (!Math::is_zero_approx(anim_size)) {
|
||||||
if (Math::fposmod(cur_playback_time, anim_size * 2.0) >= anim_size) {
|
if (Animation::is_greater_or_equal_approx(Math::fposmod(cur_playback_time, anim_size * 2.0), anim_size)) {
|
||||||
cur_delta = -cur_delta; // Needed for retrieving discrete keys correctly.
|
cur_delta = -cur_delta; // Needed for retrieving discrete keys correctly.
|
||||||
}
|
}
|
||||||
prev_playback_time = Math::pingpong(prev_playback_time, anim_size);
|
prev_playback_time = Math::pingpong(prev_playback_time, anim_size);
|
||||||
cur_playback_time = Math::pingpong(cur_playback_time, anim_size);
|
cur_playback_time = Math::pingpong(cur_playback_time, anim_size);
|
||||||
if (prev_playback_time >= 0 && cur_playback_time < 0) {
|
if (Animation::is_greater_or_equal_approx(prev_playback_time, 0) && Animation::is_less_approx(cur_playback_time, 0)) {
|
||||||
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
|
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
|
||||||
}
|
}
|
||||||
if (prev_playback_time <= anim_size && cur_playback_time > anim_size) {
|
if (Animation::is_less_or_equal_approx(prev_playback_time, anim_size) && Animation::is_greater_approx(cur_playback_time, anim_size)) {
|
||||||
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
|
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cur_playback_time < 0) {
|
if (Animation::is_less_approx(cur_playback_time, 0)) {
|
||||||
cur_playback_time = 0;
|
cur_playback_time = 0;
|
||||||
} else if (cur_playback_time > anim_size) {
|
} else if (Animation::is_greater_approx(cur_playback_time, anim_size)) {
|
||||||
cur_playback_time = anim_size;
|
cur_playback_time = anim_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,11 +237,11 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
|
||||||
// We should use call_deferred since the track keys are still being processed.
|
// We should use call_deferred since the track keys are still being processed.
|
||||||
if (process_state->tree && !p_test_only) {
|
if (process_state->tree && !p_test_only) {
|
||||||
// AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection.
|
// AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection.
|
||||||
if (p_seek && !p_is_external_seeking && cur_playback_time == 0) {
|
if (p_seek && !p_is_external_seeking && Math::is_zero_approx(cur_playback_time)) {
|
||||||
process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_started), animation);
|
process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_started), animation);
|
||||||
}
|
}
|
||||||
// Finished.
|
// Finished.
|
||||||
if (prev_time + start_offset < anim_size && cur_playback_time >= anim_size) {
|
if (Animation::is_less_approx(prev_playback_time, anim_size) && Animation::is_greater_or_equal_approx(cur_playback_time, anim_size)) {
|
||||||
process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_finished), animation);
|
process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_finished), animation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -522,7 +523,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
|
||||||
bool p_seek = p_playback_info.seeked;
|
bool p_seek = p_playback_info.seeked;
|
||||||
bool p_is_external_seeking = p_playback_info.is_external_seeking;
|
bool p_is_external_seeking = p_playback_info.is_external_seeking;
|
||||||
|
|
||||||
if (p_time == 0 && p_seek && !p_is_external_seeking) {
|
if (Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking) {
|
||||||
clear_remaining_fade = true; // Reset occurs.
|
clear_remaining_fade = true; // Reset occurs.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,9 +546,9 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
|
||||||
set_parameter(internal_active, false);
|
set_parameter(internal_active, false);
|
||||||
set_parameter(time_to_restart, -1);
|
set_parameter(time_to_restart, -1);
|
||||||
} else if (!do_start && !cur_active) {
|
} else if (!do_start && !cur_active) {
|
||||||
if (cur_time_to_restart >= 0.0 && !p_seek) {
|
if (Animation::is_greater_or_equal_approx(cur_time_to_restart, 0) && !p_seek) {
|
||||||
cur_time_to_restart -= abs_delta;
|
cur_time_to_restart -= abs_delta;
|
||||||
if (cur_time_to_restart < 0) {
|
if (Animation::is_less_approx(cur_time_to_restart, 0)) {
|
||||||
do_start = true; // Restart.
|
do_start = true; // Restart.
|
||||||
}
|
}
|
||||||
set_parameter(time_to_restart, cur_time_to_restart);
|
set_parameter(time_to_restart, cur_time_to_restart);
|
||||||
|
@ -590,8 +591,8 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
|
||||||
real_t blend = 1.0;
|
real_t blend = 1.0;
|
||||||
bool use_blend = sync;
|
bool use_blend = sync;
|
||||||
|
|
||||||
if (cur_fade_in_remaining > 0) {
|
if (Animation::is_greater_approx(cur_fade_in_remaining, 0)) {
|
||||||
if (fade_in > 0) {
|
if (Animation::is_greater_approx(fade_in, 0)) {
|
||||||
use_blend = true;
|
use_blend = true;
|
||||||
blend = (fade_in - cur_fade_in_remaining) / fade_in;
|
blend = (fade_in - cur_fade_in_remaining) / fade_in;
|
||||||
if (fade_in_curve.is_valid()) {
|
if (fade_in_curve.is_valid()) {
|
||||||
|
@ -604,7 +605,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
|
||||||
|
|
||||||
if (is_fading_out) {
|
if (is_fading_out) {
|
||||||
use_blend = true;
|
use_blend = true;
|
||||||
if (fade_out > 0) {
|
if (Animation::is_greater_approx(fade_out, 0)) {
|
||||||
blend = cur_fade_out_remaining / fade_out;
|
blend = cur_fade_out_remaining / fade_out;
|
||||||
if (fade_out_curve.is_valid()) {
|
if (fade_out_curve.is_valid()) {
|
||||||
blend = 1.0 - fade_out_curve->sample(1.0 - blend);
|
blend = 1.0 - fade_out_curve->sample(1.0 - blend);
|
||||||
|
@ -636,7 +637,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
|
||||||
|
|
||||||
NodeTimeInfo os_nti = blend_input(1, pi, FILTER_PASS, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
NodeTimeInfo os_nti = blend_input(1, pi, FILTER_PASS, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
||||||
|
|
||||||
if (cur_fade_in_remaining <= 0 && !do_start && !is_fading_out && os_nti.get_remain(break_loop_at_end) <= fade_out) {
|
if (Animation::is_less_or_equal_approx(cur_fade_in_remaining, 0) && !do_start && !is_fading_out && Animation::is_less_or_equal_approx(os_nti.get_remain(break_loop_at_end), fade_out)) {
|
||||||
is_fading_out = true;
|
is_fading_out = true;
|
||||||
cur_fade_out_remaining = os_nti.get_remain(break_loop_at_end);
|
cur_fade_out_remaining = os_nti.get_remain(break_loop_at_end);
|
||||||
cur_fade_in_remaining = 0;
|
cur_fade_in_remaining = 0;
|
||||||
|
@ -644,7 +645,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p_seek) {
|
if (!p_seek) {
|
||||||
if (os_nti.get_remain(break_loop_at_end) <= 0 || (is_fading_out && cur_fade_out_remaining <= 0)) {
|
if (Animation::is_less_or_equal_approx(os_nti.get_remain(break_loop_at_end), 0) || (is_fading_out && Animation::is_less_or_equal_approx(cur_fade_out_remaining, 0))) {
|
||||||
set_parameter(internal_active, false);
|
set_parameter(internal_active, false);
|
||||||
set_parameter(active, false);
|
set_parameter(active, false);
|
||||||
if (auto_restart) {
|
if (auto_restart) {
|
||||||
|
@ -1007,7 +1008,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer
|
||||||
|
|
||||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||||
pi.weight = 1.0;
|
pi.weight = 1.0;
|
||||||
if (cur_seek_pos >= 0) {
|
if (Animation::is_greater_or_equal_approx(cur_seek_pos, 0)) {
|
||||||
pi.time = cur_seek_pos;
|
pi.time = cur_seek_pos;
|
||||||
pi.seeked = true;
|
pi.seeked = true;
|
||||||
pi.is_external_seeking = true;
|
pi.is_external_seeking = true;
|
||||||
|
@ -1252,7 +1253,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(const AnimationMix
|
||||||
bool p_seek = p_playback_info.seeked;
|
bool p_seek = p_playback_info.seeked;
|
||||||
bool p_is_external_seeking = p_playback_info.is_external_seeking;
|
bool p_is_external_seeking = p_playback_info.is_external_seeking;
|
||||||
|
|
||||||
if (p_time == 0 && p_seek && !p_is_external_seeking) {
|
if (Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking) {
|
||||||
clear_remaining_fade = true; // Reset occurs.
|
clear_remaining_fade = true; // Reset occurs.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1317,7 +1318,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(const AnimationMix
|
||||||
if (cur_prev_index < 0) { // Process current animation, check for transition.
|
if (cur_prev_index < 0) { // Process current animation, check for transition.
|
||||||
pi.weight = 1.0;
|
pi.weight = 1.0;
|
||||||
cur_nti = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only);
|
cur_nti = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only);
|
||||||
if (input_data[cur_current_index].auto_advance && cur_nti.get_remain(input_data[cur_current_index].break_loop_at_end) <= xfade_time) {
|
if (input_data[cur_current_index].auto_advance && Animation::is_less_or_equal_approx(cur_nti.get_remain(input_data[cur_current_index].break_loop_at_end), xfade_time)) {
|
||||||
set_parameter(transition_request, get_input_name((cur_current_index + 1) % get_input_count()));
|
set_parameter(transition_request, get_input_name((cur_current_index + 1) % get_input_count()));
|
||||||
}
|
}
|
||||||
} else { // Cross-fading from prev to current.
|
} else { // Cross-fading from prev to current.
|
||||||
|
@ -1349,7 +1350,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(const AnimationMix
|
||||||
pi.weight = blend;
|
pi.weight = blend;
|
||||||
blend_input(cur_prev_index, pi, FILTER_IGNORE, true, p_test_only);
|
blend_input(cur_prev_index, pi, FILTER_IGNORE, true, p_test_only);
|
||||||
if (!p_seek) {
|
if (!p_seek) {
|
||||||
if (cur_prev_xfading <= 0) {
|
if (Animation::is_less_or_equal_approx(cur_prev_xfading, 0)) {
|
||||||
set_parameter(prev_index, -1);
|
set_parameter(prev_index, -1);
|
||||||
}
|
}
|
||||||
cur_prev_xfading -= Math::abs(p_playback_info.delta);
|
cur_prev_xfading -= Math::abs(p_playback_info.delta);
|
||||||
|
|
|
@ -1049,7 +1049,7 @@ void AnimationMixer::blend_capture(double p_delta) {
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_cache.remain -= p_delta * capture_cache.step;
|
capture_cache.remain -= p_delta * capture_cache.step;
|
||||||
if (capture_cache.remain <= 0.0) {
|
if (Animation::is_less_or_equal_approx(capture_cache.remain, 0)) {
|
||||||
capture_cache.clear();
|
capture_cache.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1156,7 +1156,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
if (track->root_motion && calc_root) {
|
if (track->root_motion && calc_root) {
|
||||||
double prev_time = time - delta;
|
double prev_time = time - delta;
|
||||||
if (!backward) {
|
if (!backward) {
|
||||||
if (prev_time < 0) {
|
if (Animation::is_less_approx(prev_time, 0)) {
|
||||||
switch (a->get_loop_mode()) {
|
switch (a->get_loop_mode()) {
|
||||||
case Animation::LOOP_NONE: {
|
case Animation::LOOP_NONE: {
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
|
@ -1172,7 +1172,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (prev_time > a->get_length()) {
|
if (Animation::is_greater_approx(prev_time, (double)a->get_length())) {
|
||||||
switch (a->get_loop_mode()) {
|
switch (a->get_loop_mode()) {
|
||||||
case Animation::LOOP_NONE: {
|
case Animation::LOOP_NONE: {
|
||||||
prev_time = (double)a->get_length();
|
prev_time = (double)a->get_length();
|
||||||
|
@ -1190,7 +1190,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
}
|
}
|
||||||
Vector3 loc[2];
|
Vector3 loc[2];
|
||||||
if (!backward) {
|
if (!backward) {
|
||||||
if (prev_time > time) {
|
if (Animation::is_greater_approx(prev_time, time)) {
|
||||||
Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
|
Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1202,7 +1202,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (prev_time < time) {
|
if (Animation::is_less_approx(prev_time, time)) {
|
||||||
Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
|
Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1244,7 +1244,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
if (track->root_motion && calc_root) {
|
if (track->root_motion && calc_root) {
|
||||||
double prev_time = time - delta;
|
double prev_time = time - delta;
|
||||||
if (!backward) {
|
if (!backward) {
|
||||||
if (prev_time < 0) {
|
if (Animation::is_less_approx(prev_time, 0)) {
|
||||||
switch (a->get_loop_mode()) {
|
switch (a->get_loop_mode()) {
|
||||||
case Animation::LOOP_NONE: {
|
case Animation::LOOP_NONE: {
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
|
@ -1260,7 +1260,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (prev_time > a->get_length()) {
|
if (Animation::is_greater_approx(prev_time, (double)a->get_length())) {
|
||||||
switch (a->get_loop_mode()) {
|
switch (a->get_loop_mode()) {
|
||||||
case Animation::LOOP_NONE: {
|
case Animation::LOOP_NONE: {
|
||||||
prev_time = (double)a->get_length();
|
prev_time = (double)a->get_length();
|
||||||
|
@ -1278,7 +1278,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
}
|
}
|
||||||
Quaternion rot[2];
|
Quaternion rot[2];
|
||||||
if (!backward) {
|
if (!backward) {
|
||||||
if (prev_time > time) {
|
if (Animation::is_greater_approx(prev_time, time)) {
|
||||||
Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);
|
Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1290,7 +1290,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (prev_time < time) {
|
if (Animation::is_less_approx(prev_time, time)) {
|
||||||
Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);
|
Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1331,7 +1331,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
if (track->root_motion && calc_root) {
|
if (track->root_motion && calc_root) {
|
||||||
double prev_time = time - delta;
|
double prev_time = time - delta;
|
||||||
if (!backward) {
|
if (!backward) {
|
||||||
if (prev_time < 0) {
|
if (Animation::is_less_approx(prev_time, 0)) {
|
||||||
switch (a->get_loop_mode()) {
|
switch (a->get_loop_mode()) {
|
||||||
case Animation::LOOP_NONE: {
|
case Animation::LOOP_NONE: {
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
|
@ -1347,7 +1347,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (prev_time > a->get_length()) {
|
if (Animation::is_greater_approx(prev_time, (double)a->get_length())) {
|
||||||
switch (a->get_loop_mode()) {
|
switch (a->get_loop_mode()) {
|
||||||
case Animation::LOOP_NONE: {
|
case Animation::LOOP_NONE: {
|
||||||
prev_time = (double)a->get_length();
|
prev_time = (double)a->get_length();
|
||||||
|
@ -1365,7 +1365,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
}
|
}
|
||||||
Vector3 scale[2];
|
Vector3 scale[2];
|
||||||
if (!backward) {
|
if (!backward) {
|
||||||
if (prev_time > time) {
|
if (Animation::is_greater_approx(prev_time, time)) {
|
||||||
Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);
|
Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1377,7 +1377,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
prev_time = 0;
|
prev_time = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (prev_time < time) {
|
if (Animation::is_less_approx(prev_time, time)) {
|
||||||
Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);
|
Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1635,7 +1635,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
PlayingAudioStreamInfo pasi;
|
PlayingAudioStreamInfo pasi;
|
||||||
pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs, 0, 1.0, t->playback_type, t->bus);
|
pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs, 0, 1.0, t->playback_type, t->bus);
|
||||||
pasi.start = time;
|
pasi.start = time;
|
||||||
if (len && end_ofs > 0) { // Force an end at a time.
|
if (len && Animation::is_greater_approx(end_ofs, 0)) { // Force an end at a time.
|
||||||
pasi.len = len - start_ofs - end_ofs;
|
pasi.len = len - start_ofs - end_ofs;
|
||||||
} else {
|
} else {
|
||||||
pasi.len = 0;
|
pasi.len = 0;
|
||||||
|
@ -1671,7 +1671,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
||||||
double at_anim_pos = 0.0;
|
double at_anim_pos = 0.0;
|
||||||
switch (anim->get_loop_mode()) {
|
switch (anim->get_loop_mode()) {
|
||||||
case Animation::LOOP_NONE: {
|
case Animation::LOOP_NONE: {
|
||||||
if (!is_external_seeking && ((!backward && time >= pos + (double)anim->get_length()) || (backward && time <= pos))) {
|
if (!is_external_seeking && ((!backward && Animation::is_greater_or_equal_approx(time, pos + (double)anim->get_length())) || (backward && Animation::is_less_or_equal_approx(time, pos)))) {
|
||||||
continue; // Do nothing if current time is outside of length when started.
|
continue; // Do nothing if current time is outside of length when started.
|
||||||
}
|
}
|
||||||
at_anim_pos = MIN((double)anim->get_length(), time - pos); // Seek to end.
|
at_anim_pos = MIN((double)anim->get_length(), time - pos); // Seek to end.
|
||||||
|
@ -1841,23 +1841,23 @@ void AnimationMixer::_blend_apply() {
|
||||||
}
|
}
|
||||||
if (!track_info.loop) {
|
if (!track_info.loop) {
|
||||||
if (!track_info.backward) {
|
if (!track_info.backward) {
|
||||||
if (track_info.time < pasi.start) {
|
if (Animation::is_less_approx(track_info.time, pasi.start)) {
|
||||||
stop = true;
|
stop = true;
|
||||||
}
|
}
|
||||||
} else if (track_info.backward) {
|
} else if (track_info.backward) {
|
||||||
if (track_info.time > pasi.start) {
|
if (Animation::is_greater_approx(track_info.time, pasi.start)) {
|
||||||
stop = true;
|
stop = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pasi.len > 0) {
|
if (Animation::is_greater_approx(pasi.len, 0)) {
|
||||||
double len = 0.0;
|
double len = 0.0;
|
||||||
if (!track_info.backward) {
|
if (!track_info.backward) {
|
||||||
len = pasi.start > track_info.time ? (track_info.length - pasi.start) + track_info.time : track_info.time - pasi.start;
|
len = Animation::is_greater_approx(pasi.start, track_info.time) ? (track_info.length - pasi.start) + track_info.time : track_info.time - pasi.start;
|
||||||
} else {
|
} else {
|
||||||
len = pasi.start < track_info.time ? (track_info.length - track_info.time) + pasi.start : pasi.start - track_info.time;
|
len = Animation::is_less_approx(pasi.start, track_info.time) ? (track_info.length - track_info.time) + pasi.start : pasi.start - track_info.time;
|
||||||
}
|
}
|
||||||
if (len > pasi.len) {
|
if (Animation::is_greater_approx(len, pasi.len)) {
|
||||||
stop = true;
|
stop = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -702,7 +702,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
|
||||||
bool p_is_external_seeking = p_playback_info.is_external_seeking;
|
bool p_is_external_seeking = p_playback_info.is_external_seeking;
|
||||||
|
|
||||||
// Check seek to 0 (means reset) by parent AnimationNode.
|
// Check seek to 0 (means reset) by parent AnimationNode.
|
||||||
if (p_time == 0 && p_seek && !p_is_external_seeking) {
|
if (Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking) {
|
||||||
if (p_state_machine->state_machine_type != AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED || is_end() || !playing) {
|
if (p_state_machine->state_machine_type != AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED || is_end() || !playing) {
|
||||||
// Restart state machine.
|
// Restart state machine.
|
||||||
if (p_state_machine->get_state_machine_type() != AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) {
|
if (p_state_machine->get_state_machine_type() != AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) {
|
||||||
|
@ -873,7 +873,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
|
||||||
}
|
}
|
||||||
fadeing_from_nti = p_state_machine->blend_node(p_state_machine->states[fading_from].node, fading_from, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
fadeing_from_nti = p_state_machine->blend_node(p_state_machine->states[fading_from].node, fading_from, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
||||||
|
|
||||||
if (fading_pos >= fading_time) {
|
if (Animation::is_greater_or_equal_approx(fading_pos, fading_time)) {
|
||||||
// Finish fading.
|
// Finish fading.
|
||||||
fading_from = StringName();
|
fading_from = StringName();
|
||||||
fadeing_from_nti = AnimationNode::NodeTimeInfo();
|
fadeing_from_nti = AnimationNode::NodeTimeInfo();
|
||||||
|
@ -887,7 +887,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
|
||||||
if (will_end || ((p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) && !p_state_machine->has_transition_from(current))) {
|
if (will_end || ((p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) && !p_state_machine->has_transition_from(current))) {
|
||||||
// There is no next transition.
|
// There is no next transition.
|
||||||
if (fading_from != StringName()) {
|
if (fading_from != StringName()) {
|
||||||
return current_nti.get_remain() > fadeing_from_nti.get_remain() ? current_nti : fadeing_from_nti;
|
return Animation::is_greater_approx(current_nti.get_remain(), fadeing_from_nti.get_remain()) ? current_nti : fadeing_from_nti;
|
||||||
}
|
}
|
||||||
return current_nti;
|
return current_nti;
|
||||||
}
|
}
|
||||||
|
@ -1015,7 +1015,7 @@ bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current != AnimationNodeStateMachine::START_NODE && p_next.switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_AT_END) {
|
if (current != AnimationNodeStateMachine::START_NODE && p_next.switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_AT_END) {
|
||||||
return current_nti.get_remain(p_next.break_loop_at_end) <= p_next.xfade;
|
return Animation::is_less_or_equal_approx(current_nti.get_remain(p_next.break_loop_at_end), p_next.xfade);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,35 +164,35 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f
|
||||||
double delta = p_started ? 0 : p_delta * speed;
|
double delta = p_started ? 0 : p_delta * speed;
|
||||||
double next_pos = cd.pos + delta;
|
double next_pos = cd.pos + delta;
|
||||||
|
|
||||||
real_t len = cd.from->animation->get_length();
|
double len = cd.from->animation->get_length();
|
||||||
Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
|
Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
|
||||||
|
|
||||||
switch (cd.from->animation->get_loop_mode()) {
|
switch (cd.from->animation->get_loop_mode()) {
|
||||||
case Animation::LOOP_NONE: {
|
case Animation::LOOP_NONE: {
|
||||||
if (next_pos < 0) {
|
if (Animation::is_less_approx(next_pos, 0)) {
|
||||||
next_pos = 0;
|
next_pos = 0;
|
||||||
} else if (next_pos > len) {
|
} else if (Animation::is_greater_approx(next_pos, len)) {
|
||||||
next_pos = len;
|
next_pos = len;
|
||||||
}
|
}
|
||||||
delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here).
|
delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here).
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Animation::LOOP_LINEAR: {
|
case Animation::LOOP_LINEAR: {
|
||||||
if (next_pos < 0 && cd.pos >= 0) {
|
if (Animation::is_less_approx(next_pos, 0) && Animation::is_greater_or_equal_approx(cd.pos, 0)) {
|
||||||
looped_flag = Animation::LOOPED_FLAG_START;
|
looped_flag = Animation::LOOPED_FLAG_START;
|
||||||
}
|
}
|
||||||
if (next_pos > len && cd.pos <= len) {
|
if (Animation::is_greater_approx(next_pos, len) && Animation::is_less_or_equal_approx(cd.pos, len)) {
|
||||||
looped_flag = Animation::LOOPED_FLAG_END;
|
looped_flag = Animation::LOOPED_FLAG_END;
|
||||||
}
|
}
|
||||||
next_pos = Math::fposmod(next_pos, (double)len);
|
next_pos = Math::fposmod(next_pos, (double)len);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Animation::LOOP_PINGPONG: {
|
case Animation::LOOP_PINGPONG: {
|
||||||
if (next_pos < 0 && cd.pos >= 0) {
|
if (Animation::is_less_approx(next_pos, 0) && Animation::is_greater_or_equal_approx(cd.pos, 0)) {
|
||||||
cd.speed_scale *= -1.0;
|
cd.speed_scale *= -1.0;
|
||||||
looped_flag = Animation::LOOPED_FLAG_START;
|
looped_flag = Animation::LOOPED_FLAG_START;
|
||||||
}
|
}
|
||||||
if (next_pos > len && cd.pos <= len) {
|
if (Animation::is_greater_approx(next_pos, len) && Animation::is_less_or_equal_approx(cd.pos, len)) {
|
||||||
cd.speed_scale *= -1.0;
|
cd.speed_scale *= -1.0;
|
||||||
looped_flag = Animation::LOOPED_FLAG_END;
|
looped_flag = Animation::LOOPED_FLAG_END;
|
||||||
}
|
}
|
||||||
|
@ -209,16 +209,16 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f
|
||||||
// End detection.
|
// End detection.
|
||||||
if (p_is_current) {
|
if (p_is_current) {
|
||||||
if (cd.from->animation->get_loop_mode() == Animation::LOOP_NONE) {
|
if (cd.from->animation->get_loop_mode() == Animation::LOOP_NONE) {
|
||||||
if (!backwards && prev_pos <= len && next_pos == len) {
|
if (!backwards && Animation::is_less_or_equal_approx(prev_pos, len) && Math::is_equal_approx(next_pos, len)) {
|
||||||
// Playback finished.
|
// Playback finished.
|
||||||
end_reached = true;
|
end_reached = true;
|
||||||
end_notify = prev_pos < len; // Notify only if not already at the end.
|
end_notify = Animation::is_less_approx(prev_pos, len); // Notify only if not already at the end.
|
||||||
p_blend = 1.0;
|
p_blend = 1.0;
|
||||||
}
|
}
|
||||||
if (backwards && prev_pos >= 0 && next_pos == 0) {
|
if (backwards && Animation::is_greater_or_equal_approx(prev_pos, 0) && Math::is_equal_approx(next_pos, 0)) {
|
||||||
// Playback finished.
|
// Playback finished.
|
||||||
end_reached = true;
|
end_reached = true;
|
||||||
end_notify = prev_pos > 0; // Notify only if not already at the beginning.
|
end_notify = Animation::is_greater_approx(prev_pos, 0); // Notify only if not already at the beginning.
|
||||||
p_blend = 1.0;
|
p_blend = 1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,7 +277,7 @@ void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) {
|
||||||
for (List<Blend>::Element *E = c.blend.front(); E; E = E->next()) {
|
for (List<Blend>::Element *E = c.blend.front(); E; E = E->next()) {
|
||||||
Blend &b = E->get();
|
Blend &b = E->get();
|
||||||
b.blend_left = MAX(0, b.blend_left - Math::absf(speed_scale * p_delta) / b.blend_time);
|
b.blend_left = MAX(0, b.blend_left - Math::absf(speed_scale * p_delta) / b.blend_time);
|
||||||
if (b.blend_left <= 0) {
|
if (Animation::is_less_or_equal_approx(b.blend_left, 0)) {
|
||||||
to_erase.push_back(E);
|
to_erase.push_back(E);
|
||||||
b.blend_left = CMP_EPSILON; // May want to play last frame.
|
b.blend_left = CMP_EPSILON; // May want to play last frame.
|
||||||
}
|
}
|
||||||
|
@ -401,7 +401,7 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo
|
||||||
bk.from = c.current.from->name;
|
bk.from = c.current.from->name;
|
||||||
bk.to = name;
|
bk.to = name;
|
||||||
|
|
||||||
if (p_custom_blend >= 0) {
|
if (Animation::is_greater_or_equal_approx(p_custom_blend, 0)) {
|
||||||
blend_time = p_custom_blend;
|
blend_time = p_custom_blend;
|
||||||
} else if (blend_times.has(bk)) {
|
} else if (blend_times.has(bk)) {
|
||||||
blend_time = blend_times[bk];
|
blend_time = blend_times[bk];
|
||||||
|
@ -419,10 +419,10 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_custom_blend < 0 && blend_time == 0 && default_blend_time) {
|
if (Animation::is_less_approx(p_custom_blend, 0) && Math::is_zero_approx(blend_time) && default_blend_time) {
|
||||||
blend_time = default_blend_time;
|
blend_time = default_blend_time;
|
||||||
}
|
}
|
||||||
if (blend_time > 0) {
|
if (Animation::is_greater_approx(blend_time, 0)) {
|
||||||
Blend b;
|
Blend b;
|
||||||
b.data = c.current;
|
b.data = c.current;
|
||||||
b.blend_left = get_current_blend_amount();
|
b.blend_left = get_current_blend_amount();
|
||||||
|
@ -449,10 +449,10 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo
|
||||||
c.assigned = name;
|
c.assigned = name;
|
||||||
emit_signal(SNAME("current_animation_changed"), c.assigned);
|
emit_signal(SNAME("current_animation_changed"), c.assigned);
|
||||||
} else {
|
} else {
|
||||||
if (p_from_end && c.current.pos == 0) {
|
if (p_from_end && Math::is_zero_approx(c.current.pos)) {
|
||||||
// Animation reset but played backwards, set position to the end.
|
// Animation reset but played backwards, set position to the end.
|
||||||
seek_internal(c.current.from->animation->get_length(), true, true, true);
|
seek_internal(c.current.from->animation->get_length(), true, true, true);
|
||||||
} else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) {
|
} else if (!p_from_end && Math::is_equal_approx(c.current.pos, (double)c.current.from->animation->get_length())) {
|
||||||
// Animation resumed but already ended, set position to the beginning.
|
// Animation resumed but already ended, set position to the beginning.
|
||||||
seek_internal(0, true, true, true);
|
seek_internal(0, true, true, true);
|
||||||
} else if (playing) {
|
} else if (playing) {
|
||||||
|
@ -585,7 +585,7 @@ void AnimationPlayer::seek_internal(double p_time, bool p_update, bool p_update_
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_backward = p_time < playback.current.pos;
|
bool is_backward = Animation::is_less_approx(p_time, playback.current.pos);
|
||||||
|
|
||||||
_check_immediately_after_start();
|
_check_immediately_after_start();
|
||||||
|
|
||||||
|
@ -708,7 +708,7 @@ void AnimationPlayer::set_blend_time(const StringName &p_animation1, const Strin
|
||||||
BlendKey bk;
|
BlendKey bk;
|
||||||
bk.from = p_animation1;
|
bk.from = p_animation1;
|
||||||
bk.to = p_animation2;
|
bk.to = p_animation2;
|
||||||
if (p_time == 0) {
|
if (Math::is_zero_approx(p_time)) {
|
||||||
blend_times.erase(bk);
|
blend_times.erase(bk);
|
||||||
} else {
|
} else {
|
||||||
blend_times[bk] = p_time;
|
blend_times[bk] = p_time;
|
||||||
|
|
|
@ -87,6 +87,10 @@ public:
|
||||||
if (p_break_loop && is_just_looped) {
|
if (p_break_loop && is_just_looped) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
double remain = length - position;
|
||||||
|
if (Math::is_zero_approx(remain)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return length - position;
|
return length - position;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -527,6 +527,22 @@ public:
|
||||||
static Variant interpolate_variant(const Variant &a, const Variant &b, float c, bool p_snap_array_element = false);
|
static Variant interpolate_variant(const Variant &a, const Variant &b, float c, bool p_snap_array_element = false);
|
||||||
static Variant cubic_interpolate_in_time_variant(const Variant &pre_a, const Variant &a, const Variant &b, const Variant &post_b, float c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t, bool p_snap_array_element = false);
|
static Variant cubic_interpolate_in_time_variant(const Variant &pre_a, const Variant &a, const Variant &b, const Variant &post_b, float c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t, bool p_snap_array_element = false);
|
||||||
|
|
||||||
|
static bool is_less_or_equal_approx(double a, double b) {
|
||||||
|
return a < b || Math::is_equal_approx(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_less_approx(double a, double b) {
|
||||||
|
return a < b && !Math::is_equal_approx(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_greater_or_equal_approx(double a, double b) {
|
||||||
|
return a > b || Math::is_equal_approx(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_greater_approx(double a, double b) {
|
||||||
|
return a > b && !Math::is_equal_approx(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
static TrackType get_cache_type(TrackType p_type);
|
static TrackType get_cache_type(TrackType p_type);
|
||||||
|
|
||||||
Animation();
|
Animation();
|
||||||
|
|
Loading…
Reference in a new issue