You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Rework AnimationNode process for retrieving the semantic time info
This commit is contained in:
@@ -44,7 +44,26 @@ StringName AnimationNodeAnimation::get_animation() const {
|
||||
Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = nullptr;
|
||||
|
||||
void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||
AnimationNode::get_parameter_list(r_list);
|
||||
}
|
||||
|
||||
AnimationNode::NodeTimeInfo AnimationNodeAnimation::get_node_time_info() const {
|
||||
NodeTimeInfo nti;
|
||||
if (!process_state->tree->has_animation(animation)) {
|
||||
return nti;
|
||||
}
|
||||
|
||||
if (use_custom_timeline) {
|
||||
nti.length = timeline_length;
|
||||
nti.loop_mode = loop_mode;
|
||||
} else {
|
||||
Ref<Animation> anim = process_state->tree->get_animation(animation);
|
||||
nti.length = (double)anim->get_length();
|
||||
nti.loop_mode = anim->get_loop_mode();
|
||||
}
|
||||
nti.position = get_parameter(current_position);
|
||||
|
||||
return nti;
|
||||
}
|
||||
|
||||
void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const {
|
||||
@@ -62,11 +81,34 @@ void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const
|
||||
p_property.hint_string = anims;
|
||||
}
|
||||
}
|
||||
|
||||
if (!use_custom_timeline) {
|
||||
if (p_property.name == "timeline_length" || p_property.name == "start_offset" || p_property.name == "loop_mode" || p_property.name == "stretch_time_scale") {
|
||||
p_property.usage = PROPERTY_USAGE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double AnimationNodeAnimation::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
double cur_time = get_parameter(time);
|
||||
AnimationNode::NodeTimeInfo AnimationNodeAnimation::process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
process_state->is_testing = p_test_only;
|
||||
|
||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||
if (p_playback_info.seeked) {
|
||||
pi.delta = get_node_time_info().position - p_playback_info.time;
|
||||
} else {
|
||||
pi.time = get_node_time_info().position + (backward ? -p_playback_info.delta : p_playback_info.delta);
|
||||
}
|
||||
|
||||
NodeTimeInfo nti = _process(pi, p_test_only);
|
||||
|
||||
if (!p_test_only) {
|
||||
set_node_time_info(nti);
|
||||
}
|
||||
|
||||
return nti;
|
||||
}
|
||||
|
||||
AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
if (!process_state->tree->has_animation(animation)) {
|
||||
AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(node_state.parent);
|
||||
if (tree) {
|
||||
@@ -77,87 +119,129 @@ double AnimationNodeAnimation::_process(const AnimationMixer::PlaybackInfo p_pla
|
||||
make_invalid(vformat(RTR("Animation not found: '%s'"), animation));
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NodeTimeInfo();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
NodeTimeInfo cur_nti = get_node_time_info();
|
||||
double cur_len = cur_nti.length;
|
||||
double cur_time = p_playback_info.time;
|
||||
double cur_delta = p_playback_info.delta;
|
||||
|
||||
Animation::LoopMode cur_loop_mode = cur_nti.loop_mode;
|
||||
double prev_time = cur_nti.position;
|
||||
|
||||
Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
|
||||
bool node_backward = play_mode == PLAY_MODE_BACKWARD;
|
||||
|
||||
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 {
|
||||
p_time *= backward ? -1.0 : 1.0;
|
||||
cur_time = cur_time + p_time;
|
||||
step = p_time;
|
||||
}
|
||||
bool is_just_looped = false;
|
||||
|
||||
bool is_looping = false;
|
||||
if (anim->get_loop_mode() == Animation::LOOP_PINGPONG) {
|
||||
if (!Math::is_zero_approx(anim_size)) {
|
||||
if (prev_time >= 0 && cur_time < 0) {
|
||||
backward = !backward;
|
||||
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
|
||||
// 1. Progress for AnimationNode.
|
||||
if (cur_loop_mode != Animation::LOOP_NONE) {
|
||||
if (cur_loop_mode == Animation::LOOP_LINEAR) {
|
||||
if (!Math::is_zero_approx(cur_len)) {
|
||||
if (prev_time <= cur_len && cur_time > cur_len) {
|
||||
is_just_looped = true; // Don't break with negative timescale since remain will not be 0.
|
||||
}
|
||||
cur_time = Math::fposmod(cur_time, cur_len);
|
||||
}
|
||||
if (prev_time <= anim_size && cur_time > anim_size) {
|
||||
backward = !backward;
|
||||
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
|
||||
backward = false;
|
||||
} else {
|
||||
if (!Math::is_zero_approx(cur_len)) {
|
||||
if (prev_time >= 0 && cur_time < 0) {
|
||||
backward = !backward;
|
||||
} else if (prev_time <= cur_len && cur_time > cur_len) {
|
||||
backward = !backward;
|
||||
is_just_looped = true; // Don't break with negative timescale since remain will not be 0.
|
||||
}
|
||||
cur_time = Math::pingpong(cur_time, cur_len);
|
||||
}
|
||||
cur_time = Math::pingpong(cur_time, anim_size);
|
||||
}
|
||||
is_looping = true;
|
||||
} 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;
|
||||
is_looping = true;
|
||||
} else {
|
||||
if (cur_time < 0) {
|
||||
step += cur_time;
|
||||
cur_delta += cur_time;
|
||||
cur_time = 0;
|
||||
} else if (cur_time > anim_size) {
|
||||
step += anim_size - cur_time;
|
||||
cur_time = anim_size;
|
||||
} else if (cur_time > cur_len) {
|
||||
cur_delta += cur_time - cur_len;
|
||||
cur_time = cur_len;
|
||||
}
|
||||
backward = false;
|
||||
|
||||
// If ended, don't progress animation. So set delta to 0.
|
||||
if (p_time > 0) {
|
||||
// If ended, don't progress AnimationNode. So set delta to 0.
|
||||
if (!Math::is_zero_approx(cur_delta)) {
|
||||
if (play_mode == PLAY_MODE_FORWARD) {
|
||||
if (prev_time >= anim_size) {
|
||||
step = 0;
|
||||
if (prev_time >= cur_len) {
|
||||
cur_delta = 0;
|
||||
}
|
||||
} else {
|
||||
if (prev_time <= 0) {
|
||||
step = 0;
|
||||
cur_delta = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. For return, store "AnimationNode" time info here, not "Animation" time info as below.
|
||||
NodeTimeInfo nti;
|
||||
nti.length = cur_len;
|
||||
nti.position = cur_time;
|
||||
nti.delta = cur_delta;
|
||||
nti.loop_mode = cur_loop_mode;
|
||||
nti.is_just_looped = is_just_looped;
|
||||
|
||||
// 3. Progress for Animation.
|
||||
double prev_playback_time = prev_time - start_offset;
|
||||
double cur_playback_time = cur_time - start_offset;
|
||||
if (stretch_time_scale) {
|
||||
double mlt = anim_size / cur_len;
|
||||
cur_playback_time *= mlt;
|
||||
cur_delta *= mlt;
|
||||
}
|
||||
if (cur_loop_mode == Animation::LOOP_LINEAR) {
|
||||
if (!Math::is_zero_approx(anim_size)) {
|
||||
prev_playback_time = Math::fposmod(prev_playback_time, anim_size);
|
||||
cur_playback_time = Math::fposmod(cur_playback_time, anim_size);
|
||||
if (prev_playback_time >= 0 && cur_playback_time < 0) {
|
||||
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
|
||||
}
|
||||
if (prev_playback_time <= anim_size && cur_playback_time > anim_size) {
|
||||
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
|
||||
}
|
||||
}
|
||||
} else if (cur_loop_mode == Animation::LOOP_PINGPONG) {
|
||||
if (!Math::is_zero_approx(anim_size)) {
|
||||
if (Math::fposmod(cur_playback_time, anim_size * 2.0) >= anim_size) {
|
||||
cur_delta = -cur_delta; // Needed for retrieveing discrete keys correctly.
|
||||
}
|
||||
prev_playback_time = Math::pingpong(prev_playback_time, anim_size);
|
||||
cur_playback_time = Math::pingpong(cur_playback_time, anim_size);
|
||||
if (prev_playback_time >= 0 && cur_playback_time < 0) {
|
||||
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
|
||||
}
|
||||
if (prev_playback_time <= anim_size && cur_playback_time > anim_size) {
|
||||
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (cur_playback_time < 0) {
|
||||
cur_playback_time = 0;
|
||||
} else if (cur_playback_time > anim_size) {
|
||||
cur_playback_time = anim_size;
|
||||
}
|
||||
|
||||
// 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 (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) {
|
||||
if (p_seek && !p_is_external_seeking && cur_playback_time == 0) {
|
||||
process_state->tree->call_deferred(SNAME("emit_signal"), "animation_started", animation);
|
||||
}
|
||||
// Finished.
|
||||
if (prev_time < anim_size && cur_time >= anim_size) {
|
||||
if (prev_time - start_offset < anim_size && cur_playback_time >= anim_size) {
|
||||
process_state->tree->call_deferred(SNAME("emit_signal"), "animation_finished", animation);
|
||||
}
|
||||
}
|
||||
@@ -166,19 +250,18 @@ double AnimationNodeAnimation::_process(const AnimationMixer::PlaybackInfo p_pla
|
||||
if (!p_test_only) {
|
||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||
if (play_mode == PLAY_MODE_FORWARD) {
|
||||
pi.time = cur_time;
|
||||
pi.delta = step;
|
||||
pi.time = cur_playback_time;
|
||||
pi.delta = cur_delta;
|
||||
} else {
|
||||
pi.time = anim_size - cur_time;
|
||||
pi.delta = -step;
|
||||
pi.time = anim_size - cur_playback_time;
|
||||
pi.delta = -cur_delta;
|
||||
}
|
||||
pi.weight = 1.0;
|
||||
pi.looped_flag = looped_flag;
|
||||
blend_animation(animation, pi);
|
||||
}
|
||||
set_parameter(time, cur_time);
|
||||
|
||||
return is_looping ? HUGE_LENGTH : anim_size - cur_time;
|
||||
return nti;
|
||||
}
|
||||
|
||||
String AnimationNodeAnimation::get_caption() const {
|
||||
@@ -201,6 +284,48 @@ bool AnimationNodeAnimation::is_backward() const {
|
||||
return backward;
|
||||
}
|
||||
|
||||
void AnimationNodeAnimation::set_use_custom_timeline(bool p_use_custom_timeline) {
|
||||
use_custom_timeline = p_use_custom_timeline;
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
bool AnimationNodeAnimation::is_using_custom_timeline() const {
|
||||
return use_custom_timeline;
|
||||
}
|
||||
|
||||
void AnimationNodeAnimation::set_timeline_length(double p_length) {
|
||||
timeline_length = p_length;
|
||||
}
|
||||
|
||||
double AnimationNodeAnimation::get_timeline_length() const {
|
||||
return timeline_length;
|
||||
}
|
||||
|
||||
void AnimationNodeAnimation::set_stretch_time_scale(bool p_strech_time_scale) {
|
||||
stretch_time_scale = p_strech_time_scale;
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
bool AnimationNodeAnimation::is_stretching_time_scale() const {
|
||||
return stretch_time_scale;
|
||||
}
|
||||
|
||||
void AnimationNodeAnimation::set_start_offset(double p_offset) {
|
||||
start_offset = p_offset;
|
||||
}
|
||||
|
||||
double AnimationNodeAnimation::get_start_offset() const {
|
||||
return start_offset;
|
||||
}
|
||||
|
||||
void AnimationNodeAnimation::set_loop_mode(Animation::LoopMode p_loop_mode) {
|
||||
loop_mode = p_loop_mode;
|
||||
}
|
||||
|
||||
Animation::LoopMode AnimationNodeAnimation::get_loop_mode() const {
|
||||
return loop_mode;
|
||||
}
|
||||
|
||||
void AnimationNodeAnimation::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_animation", "name"), &AnimationNodeAnimation::set_animation);
|
||||
ClassDB::bind_method(D_METHOD("get_animation"), &AnimationNodeAnimation::get_animation);
|
||||
@@ -208,8 +333,28 @@ void AnimationNodeAnimation::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_play_mode", "mode"), &AnimationNodeAnimation::set_play_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_play_mode"), &AnimationNodeAnimation::get_play_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_use_custom_timeline", "use_custom_timeline"), &AnimationNodeAnimation::set_use_custom_timeline);
|
||||
ClassDB::bind_method(D_METHOD("is_using_custom_timeline"), &AnimationNodeAnimation::is_using_custom_timeline);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_timeline_length", "timeline_length"), &AnimationNodeAnimation::set_timeline_length);
|
||||
ClassDB::bind_method(D_METHOD("get_timeline_length"), &AnimationNodeAnimation::get_timeline_length);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stretch_time_scale", "stretch_time_scale"), &AnimationNodeAnimation::set_stretch_time_scale);
|
||||
ClassDB::bind_method(D_METHOD("is_stretching_time_scale"), &AnimationNodeAnimation::is_stretching_time_scale);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_start_offset", "start_offset"), &AnimationNodeAnimation::set_start_offset);
|
||||
ClassDB::bind_method(D_METHOD("get_start_offset"), &AnimationNodeAnimation::get_start_offset);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_loop_mode", "loop_mode"), &AnimationNodeAnimation::set_loop_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_loop_mode"), &AnimationNodeAnimation::get_loop_mode);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "play_mode", PROPERTY_HINT_ENUM, "Forward,Backward"), "set_play_mode", "get_play_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_custom_timeline"), "set_use_custom_timeline", "is_using_custom_timeline");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "timeline_length", PROPERTY_HINT_RANGE, "0.001,60,0.001,or_greater,or_less,hide_slider,suffix:s"), "set_timeline_length", "get_timeline_length");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch_time_scale"), "set_stretch_time_scale", "is_stretching_time_scale");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "start_offset", PROPERTY_HINT_RANGE, "-60,60,0.001,or_greater,or_less,hide_slider,suffix:s"), "set_start_offset", "get_start_offset");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Ping-Pong"), "set_loop_mode", "get_loop_mode");
|
||||
|
||||
BIND_ENUM_CONSTANT(PLAY_MODE_FORWARD);
|
||||
BIND_ENUM_CONSTANT(PLAY_MODE_BACKWARD);
|
||||
@@ -240,16 +385,21 @@ AnimationNodeSync::AnimationNodeSync() {
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
AnimationNode::get_parameter_list(r_list);
|
||||
r_list->push_back(PropertyInfo(Variant::BOOL, active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY));
|
||||
r_list->push_back(PropertyInfo(Variant::BOOL, internal_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY));
|
||||
r_list->push_back(PropertyInfo(Variant::INT, request, PROPERTY_HINT_ENUM, ",Fire,Abort,Fade Out"));
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, fade_in_remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, fade_out_remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||
}
|
||||
|
||||
Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const {
|
||||
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
|
||||
if (ret != Variant()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (p_parameter == request) {
|
||||
return ONE_SHOT_REQUEST_NONE;
|
||||
} else if (p_parameter == active || p_parameter == internal_active) {
|
||||
@@ -262,6 +412,10 @@ Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_pa
|
||||
}
|
||||
|
||||
bool AnimationNodeOneShot::is_parameter_read_only(const StringName &p_parameter) const {
|
||||
if (AnimationNode::is_parameter_read_only(p_parameter)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (p_parameter == active || p_parameter == internal_active) {
|
||||
return true;
|
||||
}
|
||||
@@ -332,6 +486,14 @@ AnimationNodeOneShot::MixMode AnimationNodeOneShot::get_mix_mode() const {
|
||||
return mix;
|
||||
}
|
||||
|
||||
void AnimationNodeOneShot::set_break_loop_at_end(bool p_enable) {
|
||||
break_loop_at_end = p_enable;
|
||||
}
|
||||
|
||||
bool AnimationNodeOneShot::is_loop_broken_at_end() const {
|
||||
return break_loop_at_end;
|
||||
}
|
||||
|
||||
String AnimationNodeOneShot::get_caption() const {
|
||||
return "OneShot";
|
||||
}
|
||||
@@ -340,14 +502,14 @@ bool AnimationNodeOneShot::has_filter() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
AnimationNode::NodeTimeInfo 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);
|
||||
double cur_time = get_parameter(time);
|
||||
double cur_remaining = get_parameter(remaining);
|
||||
double cur_fade_out_remaining = get_parameter(fade_out_remaining);
|
||||
NodeTimeInfo cur_nti = get_node_time_info();
|
||||
double cur_time_to_restart = get_parameter(time_to_restart);
|
||||
double cur_fade_in_remaining = get_parameter(fade_in_remaining);
|
||||
double cur_fade_out_remaining = get_parameter(fade_out_remaining);
|
||||
|
||||
set_parameter(request, ONE_SHOT_REQUEST_NONE);
|
||||
|
||||
@@ -356,6 +518,8 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb
|
||||
bool is_fading_out = cur_active == true && cur_internal_active == false;
|
||||
|
||||
double p_time = p_playback_info.time;
|
||||
double p_delta = p_playback_info.delta;
|
||||
double abs_delta = Math::abs(p_delta);
|
||||
bool p_seek = p_playback_info.seeked;
|
||||
bool p_is_external_seeking = p_playback_info.is_external_seeking;
|
||||
|
||||
@@ -374,6 +538,7 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb
|
||||
// Request fading.
|
||||
is_fading_out = true;
|
||||
cur_fade_out_remaining = fade_out;
|
||||
cur_fade_in_remaining = 0;
|
||||
} else {
|
||||
// Shot is ended, do nothing.
|
||||
is_shooting = false;
|
||||
@@ -382,7 +547,7 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb
|
||||
set_parameter(time_to_restart, -1);
|
||||
} else if (!do_start && !cur_active) {
|
||||
if (cur_time_to_restart >= 0.0 && !p_seek) {
|
||||
cur_time_to_restart -= p_time;
|
||||
cur_time_to_restart -= abs_delta;
|
||||
if (cur_time_to_restart < 0) {
|
||||
do_start = true; // Restart.
|
||||
}
|
||||
@@ -413,8 +578,11 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb
|
||||
}
|
||||
|
||||
if (do_start) {
|
||||
cur_time = 0;
|
||||
os_seek = true;
|
||||
if (!cur_internal_active) {
|
||||
cur_fade_in_remaining = fade_in; // If already active, don't fade-in again.
|
||||
}
|
||||
cur_internal_active = true;
|
||||
set_parameter(request, ONE_SHOT_REQUEST_NONE);
|
||||
set_parameter(internal_active, true);
|
||||
set_parameter(active, true);
|
||||
@@ -422,20 +590,17 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb
|
||||
|
||||
real_t blend = 1.0;
|
||||
bool use_blend = sync;
|
||||
if (cur_time < fade_in) {
|
||||
|
||||
if (cur_fade_in_remaining > 0) {
|
||||
if (fade_in > 0) {
|
||||
use_blend = true;
|
||||
blend = cur_time / fade_in;
|
||||
blend = (fade_in - cur_fade_in_remaining) / fade_in;
|
||||
if (fade_in_curve.is_valid()) {
|
||||
blend = fade_in_curve->sample(blend);
|
||||
}
|
||||
} else {
|
||||
blend = 0; // Should not happen.
|
||||
}
|
||||
} else if (!do_start && !is_fading_out && cur_remaining <= fade_out) {
|
||||
is_fading_out = true;
|
||||
cur_fade_out_remaining = cur_remaining;
|
||||
set_parameter(internal_active, false);
|
||||
}
|
||||
|
||||
if (is_fading_out) {
|
||||
@@ -451,34 +616,36 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb
|
||||
}
|
||||
|
||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||
double main_rem = 0.0;
|
||||
NodeTimeInfo main_nti;
|
||||
if (mix == MIX_MODE_ADD) {
|
||||
pi.weight = 1.0;
|
||||
main_rem = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only);
|
||||
main_nti = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only);
|
||||
} else {
|
||||
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.
|
||||
main_nti = 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;
|
||||
if (do_start) {
|
||||
pi.time = 0;
|
||||
} else if (os_seek) {
|
||||
pi.time = cur_nti.position;
|
||||
}
|
||||
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;
|
||||
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) {
|
||||
is_fading_out = true;
|
||||
cur_fade_out_remaining = os_nti.get_remain(break_loop_at_end);
|
||||
cur_fade_in_remaining = 0;
|
||||
set_parameter(internal_active, false);
|
||||
}
|
||||
|
||||
if (p_seek) {
|
||||
cur_time = p_time;
|
||||
} else {
|
||||
cur_time += p_time;
|
||||
cur_remaining = os_rem;
|
||||
cur_fade_out_remaining -= p_time;
|
||||
if (cur_remaining <= 0 || (is_fading_out && cur_fade_out_remaining <= 0)) {
|
||||
if (!p_seek) {
|
||||
if (os_nti.get_remain(break_loop_at_end) <= 0 || (is_fading_out && cur_fade_out_remaining <= 0)) {
|
||||
set_parameter(internal_active, false);
|
||||
set_parameter(active, false);
|
||||
if (auto_restart) {
|
||||
@@ -486,13 +653,17 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb
|
||||
set_parameter(time_to_restart, restart_sec);
|
||||
}
|
||||
}
|
||||
double d = Math::abs(os_nti.delta);
|
||||
if (!do_start) {
|
||||
cur_fade_in_remaining = MAX(0, cur_fade_in_remaining - d); // Don't consider seeked delta by restart.
|
||||
}
|
||||
cur_fade_out_remaining = MAX(0, cur_fade_out_remaining - d);
|
||||
}
|
||||
|
||||
set_parameter(time, cur_time);
|
||||
set_parameter(remaining, cur_remaining);
|
||||
set_parameter(fade_in_remaining, cur_fade_in_remaining);
|
||||
set_parameter(fade_out_remaining, cur_fade_out_remaining);
|
||||
|
||||
return MAX(main_rem, cur_remaining);
|
||||
return cur_internal_active ? os_nti : main_nti;
|
||||
}
|
||||
|
||||
void AnimationNodeOneShot::_bind_methods() {
|
||||
@@ -508,6 +679,9 @@ void AnimationNodeOneShot::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_fadeout_curve", "curve"), &AnimationNodeOneShot::set_fade_out_curve);
|
||||
ClassDB::bind_method(D_METHOD("get_fadeout_curve"), &AnimationNodeOneShot::get_fade_out_curve);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_break_loop_at_end", "enable"), &AnimationNodeOneShot::set_break_loop_at_end);
|
||||
ClassDB::bind_method(D_METHOD("is_loop_broken_at_end"), &AnimationNodeOneShot::is_loop_broken_at_end);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_autorestart", "active"), &AnimationNodeOneShot::set_auto_restart_enabled);
|
||||
ClassDB::bind_method(D_METHOD("has_autorestart"), &AnimationNodeOneShot::is_auto_restart_enabled);
|
||||
|
||||
@@ -526,6 +700,7 @@ void AnimationNodeOneShot::_bind_methods() {
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fadein_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_fadein_curve", "get_fadein_curve");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadeout_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_fadeout_time", "get_fadeout_time");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fadeout_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_fadeout_curve", "get_fadeout_curve");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "break_loop_at_end"), "set_break_loop_at_end", "is_loop_broken_at_end");
|
||||
|
||||
ADD_GROUP("Auto Restart", "autorestart_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autorestart"), "set_autorestart", "has_autorestart");
|
||||
@@ -550,10 +725,16 @@ AnimationNodeOneShot::AnimationNodeOneShot() {
|
||||
////////////////////////////////////////////////
|
||||
|
||||
void AnimationNodeAdd2::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
AnimationNode::get_parameter_list(r_list);
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, add_amount, PROPERTY_HINT_RANGE, "0,1,0.01,or_less,or_greater"));
|
||||
}
|
||||
|
||||
Variant AnimationNodeAdd2::get_parameter_default_value(const StringName &p_parameter) const {
|
||||
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
|
||||
if (ret != Variant()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -565,16 +746,16 @@ bool AnimationNodeAdd2::has_filter() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
double AnimationNodeAdd2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
AnimationNode::NodeTimeInfo AnimationNodeAdd2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
double amount = get_parameter(add_amount);
|
||||
|
||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||
pi.weight = 1.0;
|
||||
double rem0 = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only);
|
||||
NodeTimeInfo nti = 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;
|
||||
return nti;
|
||||
}
|
||||
|
||||
void AnimationNodeAdd2::_bind_methods() {
|
||||
@@ -588,10 +769,16 @@ AnimationNodeAdd2::AnimationNodeAdd2() {
|
||||
////////////////////////////////////////////////
|
||||
|
||||
void AnimationNodeAdd3::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
AnimationNode::get_parameter_list(r_list);
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, add_amount, PROPERTY_HINT_RANGE, "-1,1,0.01,or_less,or_greater"));
|
||||
}
|
||||
|
||||
Variant AnimationNodeAdd3::get_parameter_default_value(const StringName &p_parameter) const {
|
||||
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
|
||||
if (ret != Variant()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -603,18 +790,18 @@ bool AnimationNodeAdd3::has_filter() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
double AnimationNodeAdd3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
AnimationNode::NodeTimeInfo AnimationNodeAdd3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
double amount = get_parameter(add_amount);
|
||||
|
||||
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);
|
||||
NodeTimeInfo nti = 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;
|
||||
return nti;
|
||||
}
|
||||
|
||||
void AnimationNodeAdd3::_bind_methods() {
|
||||
@@ -629,10 +816,16 @@ AnimationNodeAdd3::AnimationNodeAdd3() {
|
||||
/////////////////////////////////////////////
|
||||
|
||||
void AnimationNodeBlend2::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
AnimationNode::get_parameter_list(r_list);
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_amount, PROPERTY_HINT_RANGE, "0,1,0.01,or_less,or_greater"));
|
||||
}
|
||||
|
||||
Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const {
|
||||
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
|
||||
if (ret != Variant()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0; // For blend amount.
|
||||
}
|
||||
|
||||
@@ -640,16 +833,16 @@ String AnimationNodeBlend2::get_caption() const {
|
||||
return "Blend2";
|
||||
}
|
||||
|
||||
double AnimationNodeBlend2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
AnimationNode::NodeTimeInfo AnimationNodeBlend2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
double amount = get_parameter(blend_amount);
|
||||
|
||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||
pi.weight = 1.0 - amount;
|
||||
double rem0 = blend_input(0, pi, FILTER_BLEND, sync, p_test_only);
|
||||
NodeTimeInfo nti0 = 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);
|
||||
NodeTimeInfo nti1 = blend_input(1, pi, FILTER_PASS, sync, p_test_only);
|
||||
|
||||
return amount > 0.5 ? rem1 : rem0; // Hacky but good enough.
|
||||
return amount > 0.5 ? nti1 : nti0; // Hacky but good enough.
|
||||
}
|
||||
|
||||
bool AnimationNodeBlend2::has_filter() const {
|
||||
@@ -667,10 +860,16 @@ AnimationNodeBlend2::AnimationNodeBlend2() {
|
||||
//////////////////////////////////////
|
||||
|
||||
void AnimationNodeBlend3::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
AnimationNode::get_parameter_list(r_list);
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_amount, PROPERTY_HINT_RANGE, "-1,1,0.01,or_less,or_greater"));
|
||||
}
|
||||
|
||||
Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const {
|
||||
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
|
||||
if (ret != Variant()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0; // For blend amount.
|
||||
}
|
||||
|
||||
@@ -678,18 +877,18 @@ String AnimationNodeBlend3::get_caption() const {
|
||||
return "Blend3";
|
||||
}
|
||||
|
||||
double AnimationNodeBlend3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
AnimationNode::NodeTimeInfo AnimationNodeBlend3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
double amount = get_parameter(blend_amount);
|
||||
|
||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||
pi.weight = MAX(0, -amount);
|
||||
double rem0 = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only);
|
||||
NodeTimeInfo nti0 = 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);
|
||||
NodeTimeInfo nti1 = 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);
|
||||
NodeTimeInfo nti2 = blend_input(2, pi, FILTER_IGNORE, sync, p_test_only);
|
||||
|
||||
return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); // Hacky but good enough.
|
||||
return amount > 0.5 ? nti2 : (amount < -0.5 ? nti0 : nti1); // Hacky but good enough.
|
||||
}
|
||||
|
||||
void AnimationNodeBlend3::_bind_methods() {
|
||||
@@ -704,10 +903,16 @@ AnimationNodeBlend3::AnimationNodeBlend3() {
|
||||
////////////////////////////////////////////////
|
||||
|
||||
void AnimationNodeSub2::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
AnimationNode::get_parameter_list(r_list);
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, sub_amount, PROPERTY_HINT_RANGE, "0,1,0.01,or_less,or_greater"));
|
||||
}
|
||||
|
||||
Variant AnimationNodeSub2::get_parameter_default_value(const StringName &p_parameter) const {
|
||||
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
|
||||
if (ret != Variant()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -719,7 +924,7 @@ bool AnimationNodeSub2::has_filter() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
double AnimationNodeSub2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
AnimationNode::NodeTimeInfo AnimationNodeSub2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
double amount = get_parameter(sub_amount);
|
||||
|
||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||
@@ -742,10 +947,16 @@ AnimationNodeSub2::AnimationNodeSub2() {
|
||||
/////////////////////////////////
|
||||
|
||||
void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
AnimationNode::get_parameter_list(r_list);
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_less,or_greater"));
|
||||
}
|
||||
|
||||
Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const {
|
||||
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
|
||||
if (ret != Variant()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 1.0; // Initial timescale.
|
||||
}
|
||||
|
||||
@@ -753,13 +964,13 @@ String AnimationNodeTimeScale::get_caption() const {
|
||||
return "TimeScale";
|
||||
}
|
||||
|
||||
double AnimationNodeTimeScale::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
AnimationNode::NodeTimeInfo AnimationNodeTimeScale::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
double cur_scale = get_parameter(scale);
|
||||
|
||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||
pi.weight = 1.0;
|
||||
if (!pi.seeked) {
|
||||
pi.time *= cur_scale;
|
||||
pi.delta *= cur_scale;
|
||||
}
|
||||
|
||||
return blend_input(0, pi, FILTER_IGNORE, true, p_test_only);
|
||||
@@ -775,10 +986,16 @@ AnimationNodeTimeScale::AnimationNodeTimeScale() {
|
||||
////////////////////////////////////
|
||||
|
||||
void AnimationNodeTimeSeek::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
AnimationNode::get_parameter_list(r_list);
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, seek_pos_request, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater")); // It will be reset to -1 after seeking the position immediately.
|
||||
}
|
||||
|
||||
Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const {
|
||||
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
|
||||
if (ret != Variant()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -1.0; // Initial seek request.
|
||||
}
|
||||
|
||||
@@ -786,7 +1003,7 @@ String AnimationNodeTimeSeek::get_caption() const {
|
||||
return "TimeSeek";
|
||||
}
|
||||
|
||||
double AnimationNodeTimeSeek::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
double cur_seek_pos = get_parameter(seek_pos_request);
|
||||
|
||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||
@@ -833,6 +1050,8 @@ bool AnimationNodeTransition::_set(const StringName &p_path, const Variant &p_va
|
||||
set_input_name(which, p_value);
|
||||
} else if (what == "auto_advance") {
|
||||
set_input_as_auto_advance(which, p_value);
|
||||
} else if (what == "break_loop_at_end") {
|
||||
set_input_break_loop_at_end(which, p_value);
|
||||
} else if (what == "reset") {
|
||||
set_input_reset(which, p_value);
|
||||
} else {
|
||||
@@ -858,6 +1077,8 @@ bool AnimationNodeTransition::_get(const StringName &p_path, Variant &r_ret) con
|
||||
r_ret = get_input_name(which);
|
||||
} else if (what == "auto_advance") {
|
||||
r_ret = is_input_set_as_auto_advance(which);
|
||||
} else if (what == "break_loop_at_end") {
|
||||
r_ret = is_input_loop_broken_at_end(which);
|
||||
} else if (what == "reset") {
|
||||
r_ret = is_input_reset(which);
|
||||
} else {
|
||||
@@ -868,6 +1089,7 @@ bool AnimationNodeTransition::_get(const StringName &p_path, Variant &r_ret) con
|
||||
}
|
||||
|
||||
void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
AnimationNode::get_parameter_list(r_list);
|
||||
String anims;
|
||||
for (int i = 0; i < get_input_count(); i++) {
|
||||
if (i > 0) {
|
||||
@@ -880,12 +1102,16 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con
|
||||
r_list->push_back(PropertyInfo(Variant::STRING, transition_request, PROPERTY_HINT_ENUM, anims)); // For transition request. It will be cleared after setting the value immediately.
|
||||
r_list->push_back(PropertyInfo(Variant::INT, current_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY)); // To avoid finding the index every frame, use this internally.
|
||||
r_list->push_back(PropertyInfo(Variant::INT, prev_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, prev_xfading, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||
}
|
||||
|
||||
Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
|
||||
if (p_parameter == time || p_parameter == prev_xfading) {
|
||||
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
|
||||
if (ret != Variant()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (p_parameter == prev_xfading) {
|
||||
return 0.0;
|
||||
} else if (p_parameter == prev_index || p_parameter == current_index) {
|
||||
return -1;
|
||||
@@ -895,6 +1121,10 @@ Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p
|
||||
}
|
||||
|
||||
bool AnimationNodeTransition::is_parameter_read_only(const StringName &p_parameter) const {
|
||||
if (AnimationNode::is_parameter_read_only(p_parameter)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (p_parameter == current_state || p_parameter == current_index) {
|
||||
return true;
|
||||
}
|
||||
@@ -947,6 +1177,16 @@ bool AnimationNodeTransition::is_input_set_as_auto_advance(int p_input) const {
|
||||
return input_data[p_input].auto_advance;
|
||||
}
|
||||
|
||||
void AnimationNodeTransition::set_input_break_loop_at_end(int p_input, bool p_enable) {
|
||||
ERR_FAIL_INDEX(p_input, get_input_count());
|
||||
input_data.write[p_input].break_loop_at_end = p_enable;
|
||||
}
|
||||
|
||||
bool AnimationNodeTransition::is_input_loop_broken_at_end(int p_input) const {
|
||||
ERR_FAIL_INDEX_V(p_input, get_input_count(), false);
|
||||
return input_data[p_input].break_loop_at_end;
|
||||
}
|
||||
|
||||
void AnimationNodeTransition::set_input_reset(int p_input, bool p_enable) {
|
||||
ERR_FAIL_INDEX(p_input, get_input_count());
|
||||
input_data.write[p_input].reset = p_enable;
|
||||
@@ -981,12 +1221,12 @@ bool AnimationNodeTransition::is_allow_transition_to_self() const {
|
||||
return allow_transition_to_self;
|
||||
}
|
||||
|
||||
double AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
AnimationNode::NodeTimeInfo 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);
|
||||
|
||||
double cur_time = get_parameter(time);
|
||||
NodeTimeInfo cur_nti = get_node_time_info();
|
||||
double cur_prev_xfading = get_parameter(prev_xfading);
|
||||
|
||||
bool switched = false;
|
||||
@@ -1052,7 +1292,6 @@ double AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_pl
|
||||
|
||||
// Special case for restart.
|
||||
if (restart) {
|
||||
set_parameter(time, 0);
|
||||
pi.time = 0;
|
||||
pi.seeked = true;
|
||||
pi.weight = 1.0;
|
||||
@@ -1061,16 +1300,12 @@ double AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_pl
|
||||
|
||||
if (switched) {
|
||||
cur_prev_xfading = xfade_time;
|
||||
cur_time = 0;
|
||||
}
|
||||
|
||||
if (cur_current_index < 0 || cur_current_index >= get_input_count() || cur_prev_index >= get_input_count()) {
|
||||
return 0;
|
||||
return NodeTimeInfo();
|
||||
}
|
||||
|
||||
double rem = 0.0;
|
||||
double abs_time = Math::abs(p_time);
|
||||
|
||||
if (sync) {
|
||||
pi.weight = 0;
|
||||
for (int i = 0; i < get_input_count(); i++) {
|
||||
@@ -1081,20 +1316,11 @@ double AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_pl
|
||||
}
|
||||
|
||||
if (cur_prev_index < 0) { // Process current animation, check for transition.
|
||||
|
||||
pi.weight = 1.0;
|
||||
rem = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only);
|
||||
|
||||
if (p_seek) {
|
||||
cur_time = abs_time;
|
||||
} else {
|
||||
cur_time += abs_time;
|
||||
}
|
||||
|
||||
if (input_data[cur_current_index].auto_advance && rem <= xfade_time) {
|
||||
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) {
|
||||
set_parameter(transition_request, get_input_name((cur_current_index + 1) % get_input_count()));
|
||||
}
|
||||
|
||||
} else { // Cross-fading from prev to current.
|
||||
|
||||
real_t blend = 0.0;
|
||||
@@ -1117,33 +1343,30 @@ double AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_pl
|
||||
pi.time = 0;
|
||||
pi.seeked = true;
|
||||
}
|
||||
rem = 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);
|
||||
|
||||
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 {
|
||||
cur_time += abs_time;
|
||||
cur_prev_xfading -= abs_time;
|
||||
if (cur_prev_xfading < 0) {
|
||||
if (!p_seek) {
|
||||
if (cur_prev_xfading <= 0) {
|
||||
set_parameter(prev_index, -1);
|
||||
}
|
||||
cur_prev_xfading -= Math::abs(p_playback_info.delta);
|
||||
}
|
||||
}
|
||||
|
||||
set_parameter(time, cur_time);
|
||||
set_parameter(prev_xfading, cur_prev_xfading);
|
||||
|
||||
return rem;
|
||||
return cur_nti;
|
||||
}
|
||||
|
||||
void AnimationNodeTransition::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
for (int i = 0; i < get_input_count(); i++) {
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL));
|
||||
p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/auto_advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL));
|
||||
p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/break_loop_at_end", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL));
|
||||
p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/reset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL));
|
||||
}
|
||||
}
|
||||
@@ -1154,6 +1377,9 @@ void AnimationNodeTransition::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_input_as_auto_advance", "input", "enable"), &AnimationNodeTransition::set_input_as_auto_advance);
|
||||
ClassDB::bind_method(D_METHOD("is_input_set_as_auto_advance", "input"), &AnimationNodeTransition::is_input_set_as_auto_advance);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_input_break_loop_at_end", "input", "enable"), &AnimationNodeTransition::set_input_break_loop_at_end);
|
||||
ClassDB::bind_method(D_METHOD("is_input_loop_broken_at_end", "input"), &AnimationNodeTransition::is_input_loop_broken_at_end);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_input_reset", "input", "enable"), &AnimationNodeTransition::set_input_reset);
|
||||
ClassDB::bind_method(D_METHOD("is_input_reset", "input"), &AnimationNodeTransition::is_input_reset);
|
||||
|
||||
@@ -1181,7 +1407,7 @@ String AnimationNodeOutput::get_caption() const {
|
||||
return "Output";
|
||||
}
|
||||
|
||||
double AnimationNodeOutput::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
AnimationNode::NodeTimeInfo 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);
|
||||
@@ -1400,10 +1626,10 @@ String AnimationNodeBlendTree::get_caption() const {
|
||||
return "BlendTree";
|
||||
}
|
||||
|
||||
double AnimationNodeBlendTree::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
AnimationNode::NodeTimeInfo AnimationNodeBlendTree::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
|
||||
Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
|
||||
node_state.connections = nodes[SceneStringNames::get_singleton()->output].connections;
|
||||
ERR_FAIL_COND_V(output.is_null(), 0);
|
||||
ERR_FAIL_COND_V(output.is_null(), NodeTimeInfo());
|
||||
|
||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||
pi.weight = 1.0;
|
||||
|
||||
Reference in New Issue
Block a user