diff options
Diffstat (limited to 'scene/animation/animation_blend_tree.cpp')
-rw-r--r-- | scene/animation/animation_blend_tree.cpp | 206 |
1 files changed, 139 insertions, 67 deletions
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index b9cbd3cf94..6ed61b4f26 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -64,14 +64,11 @@ void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const } } -double AnimationNodeAnimation::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { - AnimationPlayer *ap = state->player; - ERR_FAIL_NULL_V(ap, 0); - +double AnimationNodeAnimation::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double cur_time = get_parameter(time); - if (!ap->has_animation(animation)) { - AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent); + if (!process_state->tree->has_animation(animation)) { + AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(node_state.parent); if (tree) { String node_name = tree->get_node_name(Ref<AnimationNodeAnimation>(this)); make_invalid(vformat(RTR("On BlendTree node '%s', animation not found: '%s'"), node_name, animation)); @@ -83,14 +80,18 @@ double AnimationNodeAnimation::_process(double p_time, bool p_seek, bool p_is_ex return 0; } - Ref<Animation> anim = ap->get_animation(animation); + Ref<Animation> anim = process_state->tree->get_animation(animation); double anim_size = (double)anim->get_length(); double step = 0.0; double prev_time = cur_time; Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE; bool node_backward = play_mode == PLAY_MODE_BACKWARD; - if (p_seek) { + double p_time = p_playback_info.time; + bool p_seek = p_playback_info.seeked; + bool p_is_external_seeking = p_playback_info.is_external_seeking; + + if (p_playback_info.seeked) { step = p_time - cur_time; cur_time = p_time; } else { @@ -150,24 +151,30 @@ double AnimationNodeAnimation::_process(double p_time, bool p_seek, bool p_is_ex // Emit start & finish signal. Internally, the detections are the same for backward. // We should use call_deferred since the track keys are still being processed. - if (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. if (p_seek && !p_is_external_seeking && cur_time == 0) { - state->tree->call_deferred(SNAME("emit_signal"), "animation_started", animation); + process_state->tree->call_deferred(SNAME("emit_signal"), "animation_started", animation); } // Finished. if (prev_time < anim_size && cur_time >= anim_size) { - state->tree->call_deferred(SNAME("emit_signal"), "animation_finished", animation); + process_state->tree->call_deferred(SNAME("emit_signal"), "animation_finished", animation); } } } if (!p_test_only) { + AnimationMixer::PlaybackInfo pi = p_playback_info; if (play_mode == PLAY_MODE_FORWARD) { - blend_animation(animation, cur_time, step, p_seek, p_is_external_seeking, 1.0, looped_flag); + pi.time = cur_time; + pi.delta = step; } else { - blend_animation(animation, anim_size - cur_time, -step, p_seek, p_is_external_seeking, 1.0, looped_flag); + pi.time = anim_size - cur_time; + pi.delta = -step; } + pi.weight = 1.0; + pi.looped_flag = looped_flag; + blend_animation(animation, pi); } set_parameter(time, cur_time); @@ -333,7 +340,7 @@ bool AnimationNodeOneShot::has_filter() const { return true; } -double AnimationNodeOneShot::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { +double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { OneShotRequest cur_request = static_cast<OneShotRequest>((int)get_parameter(request)); bool cur_active = get_parameter(active); bool cur_internal_active = get_parameter(internal_active); @@ -348,6 +355,10 @@ double AnimationNodeOneShot::_process(double p_time, bool p_seek, bool p_is_exte bool clear_remaining_fade = false; bool is_fading_out = cur_active == true && cur_internal_active == false; + double p_time = p_playback_info.time; + bool p_seek = p_playback_info.seeked; + bool p_is_external_seeking = p_playback_info.is_external_seeking; + if (p_time == 0 && p_seek && !p_is_external_seeking) { clear_remaining_fade = true; // Reset occurs. } @@ -396,7 +407,9 @@ double AnimationNodeOneShot::_process(double p_time, bool p_seek, bool p_is_exte } if (!is_shooting) { - return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync, p_test_only); + AnimationMixer::PlaybackInfo pi = p_playback_info; + pi.weight = 1.0; + return blend_input(0, pi, FILTER_IGNORE, sync, p_test_only); } if (do_start) { @@ -437,13 +450,23 @@ double AnimationNodeOneShot::_process(double p_time, bool p_seek, bool p_is_exte } } + AnimationMixer::PlaybackInfo pi = p_playback_info; double main_rem = 0.0; if (mix == MIX_MODE_ADD) { - main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync, p_test_only); + pi.weight = 1.0; + main_rem = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only); } else { - main_rem = blend_input(0, p_time, use_blend && p_seek, p_is_external_seeking, 1.0 - blend, FILTER_BLEND, sync, p_test_only); // Unlike below, processing this edge is a corner case. + pi.seeked &= use_blend; + pi.weight = 1.0 - blend; + main_rem = blend_input(0, pi, FILTER_BLEND, sync, p_test_only); // Unlike below, processing this edge is a corner case. + } + pi = p_playback_info; + if (os_seek) { + pi.time = cur_time; } - double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_PASS, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. + pi.seeked = os_seek; + pi.weight = Math::is_zero_approx(blend) ? CMP_EPSILON : blend; + double os_rem = 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 (do_start) { cur_remaining = os_rem; @@ -542,10 +565,14 @@ bool AnimationNodeAdd2::has_filter() const { return true; } -double AnimationNodeAdd2::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { +double AnimationNodeAdd2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double amount = get_parameter(add_amount); - double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync, p_test_only); - blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync, p_test_only); + + AnimationMixer::PlaybackInfo pi = p_playback_info; + pi.weight = 1.0; + double rem0 = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only); + pi.weight = amount; + blend_input(1, pi, FILTER_PASS, sync, p_test_only); return rem0; } @@ -576,11 +603,16 @@ bool AnimationNodeAdd3::has_filter() const { return true; } -double AnimationNodeAdd3::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { +double AnimationNodeAdd3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double amount = get_parameter(add_amount); - blend_input(0, p_time, p_seek, p_is_external_seeking, MAX(0, -amount), FILTER_PASS, sync, p_test_only); - double rem0 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync, p_test_only); - blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_PASS, sync, p_test_only); + + AnimationMixer::PlaybackInfo pi = p_playback_info; + pi.weight = MAX(0, -amount); + blend_input(0, pi, FILTER_PASS, sync, p_test_only); + pi.weight = 1.0; + double rem0 = blend_input(1, pi, FILTER_IGNORE, sync, p_test_only); + pi.weight = MAX(0, amount); + blend_input(2, pi, FILTER_PASS, sync, p_test_only); return rem0; } @@ -608,11 +640,14 @@ String AnimationNodeBlend2::get_caption() const { return "Blend2"; } -double AnimationNodeBlend2::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { +double AnimationNodeBlend2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double amount = get_parameter(blend_amount); - double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - amount, FILTER_BLEND, sync, p_test_only); - double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync, p_test_only); + AnimationMixer::PlaybackInfo pi = p_playback_info; + pi.weight = 1.0 - amount; + double rem0 = blend_input(0, pi, FILTER_BLEND, sync, p_test_only); + pi.weight = amount; + double rem1 = blend_input(1, pi, FILTER_PASS, sync, p_test_only); return amount > 0.5 ? rem1 : rem0; // Hacky but good enough. } @@ -643,11 +678,16 @@ String AnimationNodeBlend3::get_caption() const { return "Blend3"; } -double AnimationNodeBlend3::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { +double AnimationNodeBlend3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double amount = get_parameter(blend_amount); - double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, MAX(0, -amount), FILTER_IGNORE, sync, p_test_only); - double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0 - ABS(amount), FILTER_IGNORE, sync, p_test_only); - double rem2 = blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_IGNORE, sync, p_test_only); + + AnimationMixer::PlaybackInfo pi = p_playback_info; + pi.weight = MAX(0, -amount); + double rem0 = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only); + pi.weight = 1.0 - ABS(amount); + double rem1 = blend_input(1, pi, FILTER_IGNORE, sync, p_test_only); + pi.weight = MAX(0, amount); + double rem2 = blend_input(2, pi, FILTER_IGNORE, sync, p_test_only); return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); // Hacky but good enough. } @@ -679,11 +719,16 @@ bool AnimationNodeSub2::has_filter() const { return true; } -double AnimationNodeSub2::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { +double AnimationNodeSub2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double amount = get_parameter(sub_amount); + + AnimationMixer::PlaybackInfo pi = p_playback_info; // Out = Sub.Transform3D^(-1) * In.Transform3D - blend_input(1, p_time, p_seek, p_is_external_seeking, -amount, FILTER_PASS, sync, p_test_only); - return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync, p_test_only); + pi.weight = -amount; + blend_input(1, pi, FILTER_PASS, sync, p_test_only); + pi.weight = 1.0; + + return blend_input(0, pi, FILTER_IGNORE, sync, p_test_only); } void AnimationNodeSub2::_bind_methods() { @@ -708,13 +753,16 @@ String AnimationNodeTimeScale::get_caption() const { return "TimeScale"; } -double AnimationNodeTimeScale::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { +double AnimationNodeTimeScale::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double cur_scale = get_parameter(scale); - if (p_seek) { - return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only); - } else { - return blend_input(0, p_time * cur_scale, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only); + + AnimationMixer::PlaybackInfo pi = p_playback_info; + pi.weight = 1.0; + if (!pi.seeked) { + pi.time *= cur_scale; } + + return blend_input(0, pi, FILTER_IGNORE, true, p_test_only); } void AnimationNodeTimeScale::_bind_methods() { @@ -738,17 +786,19 @@ String AnimationNodeTimeSeek::get_caption() const { return "TimeSeek"; } -double AnimationNodeTimeSeek::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { +double AnimationNodeTimeSeek::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double cur_seek_pos = get_parameter(seek_pos_request); - if (p_seek) { - return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only); - } else if (cur_seek_pos >= 0) { - double ret = blend_input(0, cur_seek_pos, true, true, 1.0, FILTER_IGNORE, true, p_test_only); + + AnimationMixer::PlaybackInfo pi = p_playback_info; + pi.weight = 1.0; + if (cur_seek_pos >= 0) { + pi.time = cur_seek_pos; + pi.seeked = true; + pi.is_external_seeking = true; set_parameter(seek_pos_request, -1.0); // Reset. - return ret; - } else { - return blend_input(0, p_time, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only); } + + return blend_input(0, pi, FILTER_IGNORE, true, p_test_only); } void AnimationNodeTimeSeek::_bind_methods() { @@ -931,7 +981,7 @@ bool AnimationNodeTransition::is_allow_transition_to_self() const { return allow_transition_to_self; } -double AnimationNodeTransition::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { +double AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { String cur_transition_request = get_parameter(transition_request); int cur_current_index = get_parameter(current_index); int cur_prev_index = get_parameter(prev_index); @@ -959,6 +1009,10 @@ double AnimationNodeTransition::_process(double p_time, bool p_seek, bool p_is_e pending_update = false; } + double p_time = p_playback_info.time; + bool p_seek = p_playback_info.seeked; + bool p_is_external_seeking = p_playback_info.is_external_seeking; + if (p_time == 0 && p_seek && !p_is_external_seeking) { clear_remaining_fade = true; // Reset occurs. } @@ -994,10 +1048,15 @@ double AnimationNodeTransition::_process(double p_time, bool p_seek, bool p_is_e set_parameter(prev_index, -1); } + AnimationMixer::PlaybackInfo pi = p_playback_info; + // Special case for restart. if (restart) { set_parameter(time, 0); - return blend_input(cur_current_index, 0, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only); + pi.time = 0; + pi.seeked = true; + pi.weight = 1.0; + return blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only); } if (switched) { @@ -1013,16 +1072,18 @@ double AnimationNodeTransition::_process(double p_time, bool p_seek, bool p_is_e double abs_time = Math::abs(p_time); if (sync) { + pi.weight = 0; for (int i = 0; i < get_input_count(); i++) { if (i != cur_current_index && i != cur_prev_index) { - blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true, p_test_only); + blend_input(i, pi, FILTER_IGNORE, true, p_test_only); } } } if (cur_prev_index < 0) { // Process current animation, check for transition. - rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only); + pi.weight = 1.0; + rem = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only); if (p_seek) { cur_time = abs_time; @@ -1051,13 +1112,17 @@ double AnimationNodeTransition::_process(double p_time, bool p_seek, bool p_is_e } // Blend values must be more than CMP_EPSILON to process discrete keys in edge. + pi.weight = blend_inv; if (input_data[cur_current_index].reset && !p_seek && switched) { // Just switched, seek to start of current. - rem = blend_input(cur_current_index, 0, true, p_is_external_seeking, blend_inv, FILTER_IGNORE, true, p_test_only); - } else { - rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, blend_inv, FILTER_IGNORE, true, p_test_only); + pi.time = 0; + pi.seeked = true; } + rem = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only); - blend_input(cur_prev_index, p_time, use_blend && p_seek, p_is_external_seeking, blend, FILTER_IGNORE, true, p_test_only); + pi = p_playback_info; + pi.seeked &= use_blend; + pi.weight = blend; + blend_input(cur_prev_index, pi, FILTER_IGNORE, true, p_test_only); if (p_seek) { cur_time = abs_time; } else { @@ -1116,8 +1181,10 @@ String AnimationNodeOutput::get_caption() const { return "Output"; } -double AnimationNodeOutput::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { - return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only); +double AnimationNodeOutput::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { + AnimationMixer::PlaybackInfo pi = p_playback_info; + pi.weight = 1.0; + return blend_input(0, pi, FILTER_IGNORE, true, p_test_only); } AnimationNodeOutput::AnimationNodeOutput() { @@ -1140,9 +1207,9 @@ void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNod emit_changed(); emit_signal(SNAME("tree_changed")); - p_node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendTree::_tree_changed), CONNECT_REFERENCE_COUNTED); - p_node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_renamed), CONNECT_REFERENCE_COUNTED); - p_node->connect("animation_node_removed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_removed), CONNECT_REFERENCE_COUNTED); + p_node->connect(SNAME("tree_changed"), callable_mp(this, &AnimationNodeBlendTree::_tree_changed), CONNECT_REFERENCE_COUNTED); + p_node->connect(SNAME("animation_node_renamed"), callable_mp(this, &AnimationNodeBlendTree::_animation_node_renamed), CONNECT_REFERENCE_COUNTED); + p_node->connect(SNAME("animation_node_removed"), callable_mp(this, &AnimationNodeBlendTree::_animation_node_removed), CONNECT_REFERENCE_COUNTED); p_node->connect_changed(callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_name), CONNECT_REFERENCE_COUNTED); } @@ -1202,9 +1269,9 @@ void AnimationNodeBlendTree::remove_node(const StringName &p_name) { { Ref<AnimationNode> node = nodes[p_name].node; - node->disconnect("tree_changed", callable_mp(this, &AnimationNodeBlendTree::_tree_changed)); - node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_renamed)); - node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_removed)); + node->disconnect(SNAME("tree_changed"), callable_mp(this, &AnimationNodeBlendTree::_tree_changed)); + node->disconnect(SNAME("animation_node_renamed"), callable_mp(this, &AnimationNodeBlendTree::_animation_node_renamed)); + node->disconnect(SNAME("animation_node_removed"), callable_mp(this, &AnimationNodeBlendTree::_animation_node_removed)); node->disconnect_changed(callable_mp(this, &AnimationNodeBlendTree::_node_changed)); } @@ -1333,9 +1400,14 @@ String AnimationNodeBlendTree::get_caption() const { return "BlendTree"; } -double AnimationNodeBlendTree::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) { +double AnimationNodeBlendTree::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node; - return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true, nullptr, p_test_only); + node_state.connections = nodes[SceneStringNames::get_singleton()->output].connections; + + AnimationMixer::PlaybackInfo pi = p_playback_info; + pi.weight = 1.0; + + return _blend_node(output, "output", this, pi, FILTER_IGNORE, true, p_test_only, nullptr); } void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) { @@ -1496,7 +1568,7 @@ void AnimationNodeBlendTree::_bind_methods() { BIND_CONSTANT(CONNECTION_ERROR_SAME_NODE); BIND_CONSTANT(CONNECTION_ERROR_CONNECTION_EXISTS); - ADD_SIGNAL(MethodInfo("node_changed", PropertyInfo(Variant::STRING_NAME, "node_name"))); + ADD_SIGNAL(MethodInfo(SNAME("node_changed"), PropertyInfo(Variant::STRING_NAME, "node_name"))); } void AnimationNodeBlendTree::_initialize_node_tree() { |