2018-08-29 22:38:13 +02:00
|
|
|
/*************************************************************************/
|
|
|
|
/* animation_blend_tree.cpp */
|
|
|
|
/*************************************************************************/
|
|
|
|
/* This file is part of: */
|
|
|
|
/* GODOT ENGINE */
|
|
|
|
/* https://godotengine.org */
|
|
|
|
/*************************************************************************/
|
2022-01-03 21:27:34 +01:00
|
|
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
|
|
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
2018-08-29 22:38:13 +02:00
|
|
|
/* */
|
|
|
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
|
|
/* a copy of this software and associated documentation files (the */
|
|
|
|
/* "Software"), to deal in the Software without restriction, including */
|
|
|
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
|
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
|
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
|
|
/* the following conditions: */
|
|
|
|
/* */
|
|
|
|
/* The above copyright notice and this permission notice shall be */
|
|
|
|
/* included in all copies or substantial portions of the Software. */
|
|
|
|
/* */
|
|
|
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
|
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
|
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
|
|
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
|
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
|
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
|
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
|
|
/*************************************************************************/
|
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
#include "animation_blend_tree.h"
|
2020-01-21 21:32:27 +01:00
|
|
|
|
2021-10-15 15:25:00 +02:00
|
|
|
#include "scene/resources/animation.h"
|
2018-06-19 03:10:48 +02:00
|
|
|
#include "scene/scene_string_names.h"
|
|
|
|
|
|
|
|
void AnimationNodeAnimation::set_animation(const StringName &p_name) {
|
|
|
|
animation = p_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringName AnimationNodeAnimation::get_animation() const {
|
|
|
|
return animation;
|
|
|
|
}
|
|
|
|
|
2020-04-02 01:20:12 +02:00
|
|
|
Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = nullptr;
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2018-11-08 20:51:45 +01:00
|
|
|
void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) const {
|
2021-07-01 03:24:34 +02:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
2018-11-08 20:51:45 +01:00
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2022-08-12 22:57:11 +02:00
|
|
|
void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const {
|
|
|
|
if (p_property.name == "animation" && get_editable_animation_list) {
|
2018-08-20 18:38:18 +02:00
|
|
|
Vector<String> names = get_editable_animation_list();
|
|
|
|
String anims;
|
|
|
|
for (int i = 0; i < names.size(); i++) {
|
|
|
|
if (i > 0) {
|
|
|
|
anims += ",";
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
2018-08-20 18:38:18 +02:00
|
|
|
anims += String(names[i]);
|
|
|
|
}
|
2021-12-09 10:42:46 +01:00
|
|
|
if (!anims.is_empty()) {
|
2022-08-12 22:57:11 +02:00
|
|
|
p_property.hint = PROPERTY_HINT_ENUM;
|
|
|
|
p_property.hint_string = anims;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_seek_root) {
|
2018-08-20 18:38:18 +02:00
|
|
|
AnimationPlayer *ap = state->player;
|
2018-06-19 03:10:48 +02:00
|
|
|
ERR_FAIL_COND_V(!ap, 0);
|
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
double cur_time = get_parameter(time);
|
2018-11-08 20:51:45 +01:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
if (!ap->has_animation(animation)) {
|
|
|
|
AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent);
|
|
|
|
if (tree) {
|
2022-09-29 11:53:28 +02:00
|
|
|
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));
|
2018-06-19 03:10:48 +02:00
|
|
|
|
|
|
|
} else {
|
|
|
|
make_invalid(vformat(RTR("Animation not found: '%s'"), animation));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Ref<Animation> anim = ap->get_animation(animation);
|
2021-10-15 15:25:00 +02:00
|
|
|
double anim_size = (double)anim->get_length();
|
|
|
|
double step = 0.0;
|
2022-09-29 11:53:28 +02:00
|
|
|
double prev_time = cur_time;
|
2021-10-15 15:25:00 +02:00
|
|
|
int pingponged = 0;
|
|
|
|
bool current_backward = signbit(p_time);
|
2018-11-08 20:51:45 +01:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
if (p_seek) {
|
2022-09-29 11:53:28 +02:00
|
|
|
step = p_time - cur_time;
|
|
|
|
cur_time = p_time;
|
2018-06-19 03:10:48 +02:00
|
|
|
} else {
|
2021-10-15 15:25:00 +02:00
|
|
|
p_time *= backward ? -1.0 : 1.0;
|
2022-09-29 11:53:28 +02:00
|
|
|
if (!(cur_time == anim_size && !current_backward) && !(cur_time == 0 && current_backward)) {
|
|
|
|
cur_time = cur_time + p_time;
|
2021-10-15 15:25:00 +02:00
|
|
|
step = p_time;
|
|
|
|
}
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
if (anim->get_loop_mode() == Animation::LOOP_PINGPONG) {
|
|
|
|
if (!Math::is_zero_approx(anim_size)) {
|
2022-09-29 11:53:28 +02:00
|
|
|
if ((int)Math::floor(abs(cur_time - prev_time) / anim_size) % 2 == 0) {
|
|
|
|
if (prev_time >= 0 && cur_time < 0) {
|
2021-10-15 15:25:00 +02:00
|
|
|
backward = !backward;
|
|
|
|
pingponged = -1;
|
|
|
|
}
|
2022-09-29 11:53:28 +02:00
|
|
|
if (prev_time <= anim_size && cur_time > anim_size) {
|
2021-10-15 15:25:00 +02:00
|
|
|
backward = !backward;
|
|
|
|
pingponged = 1;
|
|
|
|
}
|
|
|
|
}
|
2022-09-29 11:53:28 +02:00
|
|
|
cur_time = Math::pingpong(cur_time, anim_size);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
2021-10-15 15:25:00 +02:00
|
|
|
} else {
|
2022-05-04 20:53:48 +02:00
|
|
|
if (anim->get_loop_mode() == Animation::LOOP_LINEAR) {
|
|
|
|
if (!Math::is_zero_approx(anim_size)) {
|
2022-09-29 11:53:28 +02:00
|
|
|
cur_time = Math::fposmod(cur_time, anim_size);
|
2021-10-15 15:25:00 +02:00
|
|
|
}
|
2022-09-29 11:53:28 +02:00
|
|
|
} else if (cur_time < 0) {
|
|
|
|
step += cur_time;
|
|
|
|
cur_time = 0;
|
|
|
|
} else if (cur_time > anim_size) {
|
|
|
|
step += anim_size - cur_time;
|
|
|
|
cur_time = anim_size;
|
2021-10-15 15:25:00 +02:00
|
|
|
}
|
|
|
|
backward = false;
|
2021-04-24 22:47:03 +02:00
|
|
|
}
|
2021-10-12 00:27:50 +02:00
|
|
|
|
2021-10-15 15:25:00 +02:00
|
|
|
if (play_mode == PLAY_MODE_FORWARD) {
|
2022-09-29 11:53:28 +02:00
|
|
|
blend_animation(animation, cur_time, step, p_seek, p_seek_root, 1.0, pingponged);
|
2021-10-15 15:25:00 +02:00
|
|
|
} else {
|
2022-09-29 11:53:28 +02:00
|
|
|
blend_animation(animation, anim_size - cur_time, -step, p_seek, p_seek_root, 1.0, pingponged);
|
2021-10-15 15:25:00 +02:00
|
|
|
}
|
2022-09-29 11:53:28 +02:00
|
|
|
set_parameter(time, cur_time);
|
2018-11-08 20:51:45 +01:00
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
return anim_size - cur_time;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeAnimation::get_caption() const {
|
|
|
|
return "Animation";
|
|
|
|
}
|
|
|
|
|
2021-10-15 15:25:00 +02:00
|
|
|
void AnimationNodeAnimation::set_play_mode(PlayMode p_play_mode) {
|
|
|
|
play_mode = p_play_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeAnimation::PlayMode AnimationNodeAnimation::get_play_mode() const {
|
|
|
|
return play_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeAnimation::set_backward(bool p_backward) {
|
|
|
|
backward = p_backward;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeAnimation::is_backward() const {
|
|
|
|
return backward;
|
|
|
|
}
|
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
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);
|
|
|
|
|
2021-10-15 15:25:00 +02:00
|
|
|
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);
|
|
|
|
|
2020-02-20 22:58:05 +01:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation");
|
2021-10-15 15:25:00 +02:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "play_mode", PROPERTY_HINT_ENUM, "Forward,Backward"), "set_play_mode", "get_play_mode");
|
|
|
|
|
|
|
|
BIND_ENUM_CONSTANT(PLAY_MODE_FORWARD);
|
|
|
|
BIND_ENUM_CONSTANT(PLAY_MODE_BACKWARD);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeAnimation::AnimationNodeAnimation() {
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
|
|
|
2022-06-29 08:35:29 +02:00
|
|
|
void AnimationNodeSync::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeSync::set_use_sync);
|
|
|
|
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeSync::is_using_sync);
|
|
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeSync::set_use_sync(bool p_sync) {
|
|
|
|
sync = p_sync;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeSync::is_using_sync() const {
|
|
|
|
return sync;
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeSync::AnimationNodeSync() {
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
|
|
|
|
r_list->push_back(PropertyInfo(Variant::BOOL, active));
|
2021-07-01 03:24:34 +02:00
|
|
|
r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, 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, remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
2018-08-20 18:38:18 +02:00
|
|
|
}
|
2019-01-25 22:15:29 +01:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
if (p_parameter == active || p_parameter == prev_active) {
|
|
|
|
return false;
|
2019-01-25 22:15:29 +01:00
|
|
|
} else if (p_parameter == time_to_restart) {
|
|
|
|
return -1;
|
2018-08-20 18:38:18 +02:00
|
|
|
} else {
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-22 15:54:15 +02:00
|
|
|
void AnimationNodeOneShot::set_fadein_time(double p_time) {
|
2018-06-19 03:10:48 +02:00
|
|
|
fade_in = p_time;
|
|
|
|
}
|
|
|
|
|
2022-09-22 15:54:15 +02:00
|
|
|
void AnimationNodeOneShot::set_fadeout_time(double p_time) {
|
2018-06-19 03:10:48 +02:00
|
|
|
fade_out = p_time;
|
|
|
|
}
|
|
|
|
|
2022-09-22 15:54:15 +02:00
|
|
|
double AnimationNodeOneShot::get_fadein_time() const {
|
2018-06-19 03:10:48 +02:00
|
|
|
return fade_in;
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2022-09-22 15:54:15 +02:00
|
|
|
double AnimationNodeOneShot::get_fadeout_time() const {
|
2018-06-19 03:10:48 +02:00
|
|
|
return fade_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeOneShot::set_autorestart(bool p_active) {
|
|
|
|
autorestart = p_active;
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2022-09-22 15:54:15 +02:00
|
|
|
void AnimationNodeOneShot::set_autorestart_delay(double p_time) {
|
2018-06-19 03:10:48 +02:00
|
|
|
autorestart_delay = p_time;
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2022-09-22 15:54:15 +02:00
|
|
|
void AnimationNodeOneShot::set_autorestart_random_delay(double p_time) {
|
2018-06-19 03:10:48 +02:00
|
|
|
autorestart_random_delay = p_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeOneShot::has_autorestart() const {
|
|
|
|
return autorestart;
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2022-09-22 15:54:15 +02:00
|
|
|
double AnimationNodeOneShot::get_autorestart_delay() const {
|
2018-06-19 03:10:48 +02:00
|
|
|
return autorestart_delay;
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2022-09-22 15:54:15 +02:00
|
|
|
double AnimationNodeOneShot::get_autorestart_random_delay() const {
|
2018-06-19 03:10:48 +02:00
|
|
|
return autorestart_random_delay;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeOneShot::set_mix_mode(MixMode p_mix) {
|
|
|
|
mix = p_mix;
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
AnimationNodeOneShot::MixMode AnimationNodeOneShot::get_mix_mode() const {
|
|
|
|
return mix;
|
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeOneShot::get_caption() const {
|
|
|
|
return "OneShot";
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeOneShot::has_filter() const {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_root) {
|
2022-09-29 11:53:28 +02:00
|
|
|
bool cur_active = get_parameter(active);
|
|
|
|
bool cur_prev_active = get_parameter(prev_active);
|
|
|
|
double cur_time = get_parameter(time);
|
|
|
|
double cur_remaining = get_parameter(remaining);
|
|
|
|
double cur_time_to_restart = get_parameter(time_to_restart);
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
if (!cur_active) {
|
2018-06-19 03:10:48 +02:00
|
|
|
//make it as if this node doesn't exist, pass input 0 by.
|
2022-09-29 11:53:28 +02:00
|
|
|
if (cur_prev_active) {
|
|
|
|
set_parameter(prev_active, false);
|
2018-08-20 18:38:18 +02:00
|
|
|
}
|
2022-09-29 11:53:28 +02:00
|
|
|
if (cur_time_to_restart >= 0.0 && !p_seek) {
|
|
|
|
cur_time_to_restart -= p_time;
|
|
|
|
if (cur_time_to_restart < 0) {
|
2019-01-25 22:15:29 +01:00
|
|
|
//restart
|
2022-09-29 11:53:28 +02:00
|
|
|
set_parameter(active, true);
|
|
|
|
cur_active = true;
|
2019-01-25 22:15:29 +01:00
|
|
|
}
|
2022-09-29 11:53:28 +02:00
|
|
|
set_parameter(time_to_restart, cur_time_to_restart);
|
2019-01-25 22:15:29 +01:00
|
|
|
}
|
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
if (!cur_active) {
|
2022-06-29 08:35:29 +02:00
|
|
|
return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
|
2019-01-25 22:15:29 +01:00
|
|
|
}
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool os_seek = p_seek;
|
|
|
|
|
2020-05-14 16:41:43 +02:00
|
|
|
if (p_seek) {
|
2022-09-29 11:53:28 +02:00
|
|
|
cur_time = p_time;
|
2020-05-14 16:41:43 +02:00
|
|
|
}
|
2022-09-29 11:53:28 +02:00
|
|
|
bool do_start = !cur_prev_active;
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
if (do_start) {
|
2022-09-29 11:53:28 +02:00
|
|
|
cur_time = 0;
|
2018-06-19 03:10:48 +02:00
|
|
|
os_seek = true;
|
2022-09-29 11:53:28 +02:00
|
|
|
set_parameter(prev_active, true);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2022-09-22 15:54:15 +02:00
|
|
|
real_t blend;
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
if (cur_time < fade_in) {
|
2020-05-14 16:41:43 +02:00
|
|
|
if (fade_in > 0) {
|
2022-09-29 11:53:28 +02:00
|
|
|
blend = cur_time / fade_in;
|
2020-05-14 16:41:43 +02:00
|
|
|
} else {
|
2021-09-12 19:06:57 +02:00
|
|
|
blend = 0;
|
2020-05-14 16:41:43 +02:00
|
|
|
}
|
2022-09-29 11:53:28 +02:00
|
|
|
} else if (!do_start && cur_remaining <= fade_out) {
|
2021-09-12 19:06:57 +02:00
|
|
|
if (fade_out > 0) {
|
2022-09-29 11:53:28 +02:00
|
|
|
blend = (cur_remaining / fade_out);
|
2020-05-14 16:41:43 +02:00
|
|
|
} else {
|
2021-09-12 19:06:57 +02:00
|
|
|
blend = 0;
|
2020-05-14 16:41:43 +02:00
|
|
|
}
|
|
|
|
} else {
|
2018-06-19 03:10:48 +02:00
|
|
|
blend = 1.0;
|
2020-05-14 16:41:43 +02:00
|
|
|
}
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2021-09-12 19:06:57 +02:00
|
|
|
double main_rem;
|
2018-06-19 03:10:48 +02:00
|
|
|
if (mix == MIX_MODE_ADD) {
|
2022-06-29 08:35:29 +02:00
|
|
|
main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
|
2018-06-19 03:10:48 +02:00
|
|
|
} else {
|
2022-06-29 08:35:29 +02:00
|
|
|
main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_BLEND, sync);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_seek_root, blend, FILTER_PASS, true);
|
2018-06-19 03:10:48 +02:00
|
|
|
|
|
|
|
if (do_start) {
|
2022-09-29 11:53:28 +02:00
|
|
|
cur_remaining = os_rem;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!p_seek) {
|
2022-09-29 11:53:28 +02:00
|
|
|
cur_time += p_time;
|
|
|
|
cur_remaining = os_rem;
|
|
|
|
if (cur_remaining <= 0) {
|
|
|
|
set_parameter(active, false);
|
|
|
|
set_parameter(prev_active, false);
|
2019-01-25 22:15:29 +01:00
|
|
|
if (autorestart) {
|
2022-09-22 15:54:15 +02:00
|
|
|
double restart_sec = autorestart_delay + Math::randd() * autorestart_random_delay;
|
2022-09-29 11:53:28 +02:00
|
|
|
set_parameter(time_to_restart, restart_sec);
|
2019-01-25 22:15:29 +01:00
|
|
|
}
|
2018-08-20 18:38:18 +02:00
|
|
|
}
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
set_parameter(time, cur_time);
|
|
|
|
set_parameter(remaining, cur_remaining);
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
return MAX(main_rem, cur_remaining);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
void AnimationNodeOneShot::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("set_fadein_time", "time"), &AnimationNodeOneShot::set_fadein_time);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_fadein_time"), &AnimationNodeOneShot::get_fadein_time);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_fadeout_time", "time"), &AnimationNodeOneShot::set_fadeout_time);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_fadeout_time"), &AnimationNodeOneShot::get_fadeout_time);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_autorestart", "enable"), &AnimationNodeOneShot::set_autorestart);
|
|
|
|
ClassDB::bind_method(D_METHOD("has_autorestart"), &AnimationNodeOneShot::has_autorestart);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_autorestart_delay", "enable"), &AnimationNodeOneShot::set_autorestart_delay);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_autorestart_delay"), &AnimationNodeOneShot::get_autorestart_delay);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_autorestart_random_delay", "enable"), &AnimationNodeOneShot::set_autorestart_random_delay);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_autorestart_random_delay"), &AnimationNodeOneShot::get_autorestart_random_delay);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_mix_mode", "mode"), &AnimationNodeOneShot::set_mix_mode);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_mix_mode"), &AnimationNodeOneShot::get_mix_mode);
|
|
|
|
|
2020-04-16 23:21:11 +02:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_mode", PROPERTY_HINT_ENUM, "Blend,Add"), "set_mix_mode", "get_mix_mode");
|
|
|
|
|
2022-05-20 07:24:41 +02:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadein_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_fadein_time", "get_fadein_time");
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadeout_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_fadeout_time", "get_fadeout_time");
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2022-03-18 05:53:34 +01:00
|
|
|
ADD_GROUP("Auto Restart", "autorestart_");
|
2018-06-19 03:10:48 +02:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autorestart"), "set_autorestart", "has_autorestart");
|
|
|
|
|
2022-05-20 07:24:41 +02:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_delay", "get_autorestart_delay");
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_random_delay", "get_autorestart_random_delay");
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2019-10-02 09:57:12 +02:00
|
|
|
BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
|
|
|
|
BIND_ENUM_CONSTANT(MIX_MODE_ADD);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeOneShot::AnimationNodeOneShot() {
|
|
|
|
add_input("in");
|
|
|
|
add_input("shot");
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
void AnimationNodeAdd2::get_parameter_list(List<PropertyInfo> *r_list) const {
|
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, add_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Variant AnimationNodeAdd2::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 0;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2018-06-28 01:50:25 +02:00
|
|
|
String AnimationNodeAdd2::get_caption() const {
|
|
|
|
return "Add2";
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-06-28 01:50:25 +02:00
|
|
|
bool AnimationNodeAdd2::has_filter() const {
|
2018-06-19 03:10:48 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
double AnimationNodeAdd2::process(double p_time, bool p_seek, bool p_seek_root) {
|
2021-05-21 08:42:37 +02:00
|
|
|
double amount = get_parameter(add_amount);
|
2022-06-29 08:35:29 +02:00
|
|
|
double rem0 = blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
|
|
|
|
blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, sync);
|
2018-06-19 03:10:48 +02:00
|
|
|
|
|
|
|
return rem0;
|
|
|
|
}
|
|
|
|
|
2018-06-28 01:50:25 +02:00
|
|
|
void AnimationNodeAdd2::_bind_methods() {
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2018-06-28 01:50:25 +02:00
|
|
|
AnimationNodeAdd2::AnimationNodeAdd2() {
|
2018-06-19 03:10:48 +02:00
|
|
|
add_input("in");
|
|
|
|
add_input("add");
|
|
|
|
}
|
|
|
|
|
2018-06-28 01:50:25 +02:00
|
|
|
////////////////////////////////////////////////
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
void AnimationNodeAdd3::get_parameter_list(List<PropertyInfo> *r_list) const {
|
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, add_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
|
2018-06-28 01:50:25 +02:00
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Variant AnimationNodeAdd3::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 0;
|
2018-06-28 01:50:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeAdd3::get_caption() const {
|
|
|
|
return "Add3";
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-06-28 01:50:25 +02:00
|
|
|
bool AnimationNodeAdd3::has_filter() const {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
double AnimationNodeAdd3::process(double p_time, bool p_seek, bool p_seek_root) {
|
2021-05-21 08:42:37 +02:00
|
|
|
double amount = get_parameter(add_amount);
|
2022-06-29 08:35:29 +02:00
|
|
|
blend_input(0, p_time, p_seek, p_seek_root, MAX(0, -amount), FILTER_PASS, sync);
|
|
|
|
double rem0 = blend_input(1, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
|
|
|
|
blend_input(2, p_time, p_seek, p_seek_root, MAX(0, amount), FILTER_PASS, sync);
|
2018-06-28 01:50:25 +02:00
|
|
|
|
|
|
|
return rem0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeAdd3::_bind_methods() {
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeAdd3::AnimationNodeAdd3() {
|
|
|
|
add_input("-add");
|
|
|
|
add_input("in");
|
|
|
|
add_input("+add");
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
/////////////////////////////////////////////
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
void AnimationNodeBlend2::get_parameter_list(List<PropertyInfo> *r_list) const {
|
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 0; //for blend amount
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
String AnimationNodeBlend2::get_caption() const {
|
|
|
|
return "Blend2";
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_seek_root) {
|
2021-05-21 08:42:37 +02:00
|
|
|
double amount = get_parameter(blend_amount);
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2022-06-29 08:35:29 +02:00
|
|
|
double rem0 = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - amount, FILTER_BLEND, sync);
|
|
|
|
double rem1 = blend_input(1, p_time, p_seek, p_seek_root, amount, FILTER_PASS, sync);
|
2018-06-19 03:10:48 +02:00
|
|
|
|
|
|
|
return amount > 0.5 ? rem1 : rem0; //hacky but good enough
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeBlend2::has_filter() const {
|
|
|
|
return true;
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
void AnimationNodeBlend2::_bind_methods() {
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
AnimationNodeBlend2::AnimationNodeBlend2() {
|
|
|
|
add_input("in");
|
|
|
|
add_input("blend");
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
void AnimationNodeBlend3::get_parameter_list(List<PropertyInfo> *r_list) const {
|
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 0; //for blend amount
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeBlend3::get_caption() const {
|
|
|
|
return "Blend3";
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_seek_root) {
|
2021-05-21 08:42:37 +02:00
|
|
|
double amount = get_parameter(blend_amount);
|
2022-06-29 08:35:29 +02:00
|
|
|
double rem0 = blend_input(0, p_time, p_seek, p_seek_root, MAX(0, -amount), FILTER_IGNORE, sync);
|
|
|
|
double rem1 = blend_input(1, p_time, p_seek, p_seek_root, 1.0 - ABS(amount), FILTER_IGNORE, sync);
|
|
|
|
double rem2 = blend_input(2, p_time, p_seek, p_seek_root, MAX(0, amount), FILTER_IGNORE, sync);
|
2018-06-19 03:10:48 +02:00
|
|
|
|
|
|
|
return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); //hacky but good enough
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlend3::_bind_methods() {
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
AnimationNodeBlend3::AnimationNodeBlend3() {
|
|
|
|
add_input("-blend");
|
|
|
|
add_input("in");
|
|
|
|
add_input("+blend");
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const {
|
2022-03-27 19:16:03 +02:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_less,or_greater"));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 1.0; //initial timescale
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeTimeScale::get_caption() const {
|
|
|
|
return "TimeScale";
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
double AnimationNodeTimeScale::process(double p_time, bool p_seek, bool p_seek_root) {
|
2022-09-29 11:53:28 +02:00
|
|
|
double cur_scale = get_parameter(scale);
|
2018-06-19 03:10:48 +02:00
|
|
|
if (p_seek) {
|
2022-06-29 08:35:29 +02:00
|
|
|
return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true);
|
2018-06-19 03:10:48 +02:00
|
|
|
} else {
|
2022-09-29 11:53:28 +02:00
|
|
|
return blend_input(0, p_time * cur_scale, false, p_seek_root, 1.0, FILTER_IGNORE, true);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTimeScale::_bind_methods() {
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
AnimationNodeTimeScale::AnimationNodeTimeScale() {
|
|
|
|
add_input("in");
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
void AnimationNodeTimeSeek::get_parameter_list(List<PropertyInfo> *r_list) const {
|
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, seek_pos, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater"));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 1.0; //initial timescale
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeTimeSeek::get_caption() const {
|
|
|
|
return "Seek";
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_seek_root) {
|
2022-09-29 11:53:28 +02:00
|
|
|
double cur_seek_pos = get_parameter(seek_pos);
|
2018-06-19 03:10:48 +02:00
|
|
|
if (p_seek) {
|
2022-06-29 08:35:29 +02:00
|
|
|
return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true);
|
2022-09-29 11:53:28 +02:00
|
|
|
} else if (cur_seek_pos >= 0) {
|
|
|
|
double ret = blend_input(0, cur_seek_pos, true, true, 1.0, FILTER_IGNORE, true);
|
|
|
|
set_parameter(seek_pos, -1.0); //reset
|
2018-06-19 03:10:48 +02:00
|
|
|
return ret;
|
|
|
|
} else {
|
2022-06-29 08:35:29 +02:00
|
|
|
return blend_input(0, p_time, false, p_seek_root, 1.0, FILTER_IGNORE, true);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTimeSeek::_bind_methods() {
|
|
|
|
}
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
AnimationNodeTimeSeek::AnimationNodeTimeSeek() {
|
|
|
|
add_input("in");
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) const {
|
|
|
|
String anims;
|
|
|
|
for (int i = 0; i < enabled_inputs; i++) {
|
|
|
|
if (i > 0) {
|
|
|
|
anims += ",";
|
|
|
|
}
|
|
|
|
anims += inputs[i].name;
|
|
|
|
}
|
|
|
|
|
|
|
|
r_list->push_back(PropertyInfo(Variant::INT, current, PROPERTY_HINT_ENUM, anims));
|
2021-07-01 03:24:34 +02:00
|
|
|
r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
|
|
|
r_list->push_back(PropertyInfo(Variant::INT, prev, 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));
|
2018-08-20 18:38:18 +02:00
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
if (p_parameter == time || p_parameter == prev_xfading) {
|
|
|
|
return 0.0;
|
|
|
|
} else if (p_parameter == prev || p_parameter == prev_current) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
String AnimationNodeTransition::get_caption() const {
|
|
|
|
return "Transition";
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTransition::_update_inputs() {
|
|
|
|
while (get_input_count() < enabled_inputs) {
|
|
|
|
add_input(inputs[get_input_count()].name);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (get_input_count() > enabled_inputs) {
|
|
|
|
remove_input(get_input_count() - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTransition::set_enabled_inputs(int p_inputs) {
|
|
|
|
ERR_FAIL_INDEX(p_inputs, MAX_INPUTS);
|
|
|
|
enabled_inputs = p_inputs;
|
|
|
|
_update_inputs();
|
|
|
|
}
|
|
|
|
|
|
|
|
int AnimationNodeTransition::get_enabled_inputs() {
|
|
|
|
return enabled_inputs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTransition::set_input_as_auto_advance(int p_input, bool p_enable) {
|
|
|
|
ERR_FAIL_INDEX(p_input, MAX_INPUTS);
|
|
|
|
inputs[p_input].auto_advance = p_enable;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeTransition::is_input_set_as_auto_advance(int p_input) const {
|
|
|
|
ERR_FAIL_INDEX_V(p_input, MAX_INPUTS, false);
|
|
|
|
return inputs[p_input].auto_advance;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTransition::set_input_caption(int p_input, const String &p_name) {
|
|
|
|
ERR_FAIL_INDEX(p_input, MAX_INPUTS);
|
|
|
|
inputs[p_input].name = p_name;
|
|
|
|
set_input_name(p_input, p_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeTransition::get_input_caption(int p_input) const {
|
|
|
|
ERR_FAIL_INDEX_V(p_input, MAX_INPUTS, String());
|
|
|
|
return inputs[p_input].name;
|
|
|
|
}
|
|
|
|
|
2022-09-22 15:54:15 +02:00
|
|
|
void AnimationNodeTransition::set_xfade_time(double p_fade) {
|
2022-07-28 10:31:23 +02:00
|
|
|
xfade_time = p_fade;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2022-09-22 15:54:15 +02:00
|
|
|
double AnimationNodeTransition::get_xfade_time() const {
|
2022-07-28 10:31:23 +02:00
|
|
|
return xfade_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTransition::set_xfade_curve(const Ref<Curve> &p_curve) {
|
|
|
|
xfade_curve = p_curve;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ref<Curve> AnimationNodeTransition::get_xfade_curve() const {
|
|
|
|
return xfade_curve;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2022-06-29 08:35:29 +02:00
|
|
|
void AnimationNodeTransition::set_from_start(bool p_from_start) {
|
|
|
|
from_start = p_from_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeTransition::is_from_start() const {
|
|
|
|
return from_start;
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_root) {
|
2022-09-29 11:53:28 +02:00
|
|
|
int cur_current = get_parameter(current);
|
|
|
|
int cur_prev = get_parameter(prev);
|
|
|
|
int cur_prev_current = get_parameter(prev_current);
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
double cur_time = get_parameter(time);
|
|
|
|
double cur_prev_xfading = get_parameter(prev_xfading);
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
bool switched = cur_current != cur_prev_current;
|
2018-08-20 18:38:18 +02:00
|
|
|
|
|
|
|
if (switched) {
|
2022-09-29 11:53:28 +02:00
|
|
|
set_parameter(prev_current, cur_current);
|
|
|
|
set_parameter(prev, cur_prev_current);
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
cur_prev = cur_prev_current;
|
|
|
|
cur_prev_xfading = xfade_time;
|
|
|
|
cur_time = 0;
|
2018-08-20 18:38:18 +02:00
|
|
|
switched = true;
|
|
|
|
}
|
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
if (cur_current < 0 || cur_current >= enabled_inputs || cur_prev >= enabled_inputs) {
|
2018-08-20 18:38:18 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-01-27 03:52:39 +01:00
|
|
|
double rem = 0.0;
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2022-06-29 08:35:29 +02:00
|
|
|
for (int i = 0; i < enabled_inputs; i++) {
|
2022-09-29 11:53:28 +02:00
|
|
|
if (i != cur_current && i != cur_prev) {
|
2022-06-29 08:35:29 +02:00
|
|
|
blend_input(i, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
if (cur_prev < 0) { // process current animation, check for transition
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
rem = blend_input(cur_current, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2020-05-14 16:41:43 +02:00
|
|
|
if (p_seek) {
|
2022-09-29 11:53:28 +02:00
|
|
|
cur_time = p_time;
|
2020-05-14 16:41:43 +02:00
|
|
|
} else {
|
2022-09-29 11:53:28 +02:00
|
|
|
cur_time += p_time;
|
2020-05-14 16:41:43 +02:00
|
|
|
}
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
if (inputs[cur_current].auto_advance && rem <= xfade_time) {
|
|
|
|
set_parameter(current, (cur_current + 1) % enabled_inputs);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
} else { // cross-fading from prev to current
|
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
real_t blend = xfade_time == 0 ? 0 : (cur_prev_xfading / xfade_time);
|
2022-07-28 10:31:23 +02:00
|
|
|
if (xfade_curve.is_valid()) {
|
2022-07-24 18:47:57 +02:00
|
|
|
blend = xfade_curve->sample(blend);
|
2022-07-28 10:31:23 +02:00
|
|
|
}
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2022-06-29 08:35:29 +02:00
|
|
|
if (from_start && !p_seek && switched) { //just switched, seek to start of current
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
rem = blend_input(cur_current, 0, true, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
|
2018-06-19 03:10:48 +02:00
|
|
|
} else {
|
2022-09-29 11:53:28 +02:00
|
|
|
rem = blend_input(cur_current, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2022-06-29 08:35:29 +02:00
|
|
|
if (p_seek) {
|
2022-09-29 11:53:28 +02:00
|
|
|
blend_input(cur_prev, p_time, true, p_seek_root, blend, FILTER_IGNORE, true);
|
|
|
|
cur_time = p_time;
|
2018-06-19 03:10:48 +02:00
|
|
|
} else {
|
2022-09-29 11:53:28 +02:00
|
|
|
blend_input(cur_prev, p_time, false, p_seek_root, blend, FILTER_IGNORE, true);
|
|
|
|
cur_time += p_time;
|
|
|
|
cur_prev_xfading -= p_time;
|
|
|
|
if (cur_prev_xfading < 0) {
|
|
|
|
set_parameter(prev, -1);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2022-09-29 11:53:28 +02:00
|
|
|
set_parameter(time, cur_time);
|
|
|
|
set_parameter(prev_xfading, cur_prev_xfading);
|
2018-08-20 18:38:18 +02:00
|
|
|
|
|
|
|
return rem;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2022-08-12 22:57:11 +02:00
|
|
|
void AnimationNodeTransition::_validate_property(PropertyInfo &p_property) const {
|
|
|
|
if (p_property.name.begins_with("input_")) {
|
|
|
|
String n = p_property.name.get_slicec('/', 0).get_slicec('_', 1);
|
2018-06-19 03:10:48 +02:00
|
|
|
if (n != "count") {
|
|
|
|
int idx = n.to_int();
|
|
|
|
if (idx >= enabled_inputs) {
|
2022-08-12 22:57:11 +02:00
|
|
|
p_property.usage = PROPERTY_USAGE_NONE;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTransition::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("set_enabled_inputs", "amount"), &AnimationNodeTransition::set_enabled_inputs);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_enabled_inputs"), &AnimationNodeTransition::get_enabled_inputs);
|
|
|
|
|
|
|
|
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_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
|
|
|
|
|
2022-07-28 10:31:23 +02:00
|
|
|
ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeTransition::set_xfade_curve);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeTransition::get_xfade_curve);
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2022-06-29 08:35:29 +02:00
|
|
|
ClassDB::bind_method(D_METHOD("set_from_start", "from_start"), &AnimationNodeTransition::set_from_start);
|
|
|
|
ClassDB::bind_method(D_METHOD("is_from_start"), &AnimationNodeTransition::is_from_start);
|
|
|
|
|
2022-04-05 19:11:06 +02:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_inputs", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
|
2022-07-28 10:31:23 +02:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
|
2022-06-29 08:35:29 +02:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "from_start"), "set_from_start", "is_from_start");
|
2018-06-19 03:10:48 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < MAX_INPUTS; i++) {
|
2020-01-23 11:14:14 +01:00
|
|
|
ADD_PROPERTYI(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_caption", "get_input_caption", i);
|
|
|
|
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/auto_advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_as_auto_advance", "is_input_set_as_auto_advance", i);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeTransition::AnimationNodeTransition() {
|
|
|
|
for (int i = 0; i < MAX_INPUTS; i++) {
|
2019-01-09 06:44:41 +01:00
|
|
|
inputs[i].name = "state " + itos(i);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////
|
|
|
|
|
|
|
|
String AnimationNodeOutput::get_caption() const {
|
|
|
|
return "Output";
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
double AnimationNodeOutput::process(double p_time, bool p_seek, bool p_seek_root) {
|
2022-06-29 08:35:29 +02:00
|
|
|
return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeOutput::AnimationNodeOutput() {
|
|
|
|
add_input("output");
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
2018-08-20 18:38:18 +02:00
|
|
|
void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position) {
|
2018-06-19 03:10:48 +02:00
|
|
|
ERR_FAIL_COND(nodes.has(p_name));
|
|
|
|
ERR_FAIL_COND(p_node.is_null());
|
|
|
|
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output);
|
2022-02-03 17:03:38 +01:00
|
|
|
ERR_FAIL_COND(String(p_name).contains("/"));
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Node n;
|
|
|
|
n.node = p_node;
|
|
|
|
n.position = p_position;
|
|
|
|
n.connections.resize(n.node->get_input_count());
|
|
|
|
nodes[p_name] = n;
|
2018-06-19 03:10:48 +02:00
|
|
|
|
|
|
|
emit_changed();
|
2021-07-17 23:22:52 +02:00
|
|
|
emit_signal(SNAME("tree_changed"));
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2022-07-28 22:56:41 +02:00
|
|
|
p_node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendTree::_tree_changed), CONNECT_REFERENCE_COUNTED);
|
|
|
|
p_node->connect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_name), CONNECT_REFERENCE_COUNTED);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Ref<AnimationNode> AnimationNodeBlendTree::get_node(const StringName &p_name) const {
|
|
|
|
ERR_FAIL_COND_V(!nodes.has(p_name), Ref<AnimationNode>());
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
return nodes[p_name].node;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
StringName AnimationNodeBlendTree::get_node_name(const Ref<AnimationNode> &p_node) const {
|
2021-08-09 22:13:42 +02:00
|
|
|
for (const KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
if (E.value.node == p_node) {
|
|
|
|
return E.key;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ERR_FAIL_V(StringName());
|
|
|
|
}
|
2018-08-20 18:38:18 +02:00
|
|
|
|
|
|
|
void AnimationNodeBlendTree::set_node_position(const StringName &p_node, const Vector2 &p_position) {
|
|
|
|
ERR_FAIL_COND(!nodes.has(p_node));
|
|
|
|
nodes[p_node].position = p_position;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 AnimationNodeBlendTree::get_node_position(const StringName &p_node) const {
|
|
|
|
ERR_FAIL_COND_V(!nodes.has(p_node), Vector2());
|
|
|
|
return nodes[p_node].position;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlendTree::get_child_nodes(List<ChildNode> *r_child_nodes) {
|
|
|
|
Vector<StringName> ns;
|
|
|
|
|
2021-08-09 22:13:42 +02:00
|
|
|
for (const KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
ns.push_back(E.key);
|
2018-08-20 18:38:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ns.sort_custom<StringName::AlphCompare>();
|
|
|
|
|
|
|
|
for (int i = 0; i < ns.size(); i++) {
|
|
|
|
ChildNode cn;
|
|
|
|
cn.name = ns[i];
|
|
|
|
cn.node = nodes[cn.name].node;
|
|
|
|
r_child_nodes->push_back(cn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
bool AnimationNodeBlendTree::has_node(const StringName &p_name) const {
|
|
|
|
return nodes.has(p_name);
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Vector<StringName> AnimationNodeBlendTree::get_node_connection_array(const StringName &p_name) const {
|
|
|
|
ERR_FAIL_COND_V(!nodes.has(p_name), Vector<StringName>());
|
|
|
|
return nodes[p_name].connections;
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
void AnimationNodeBlendTree::remove_node(const StringName &p_name) {
|
|
|
|
ERR_FAIL_COND(!nodes.has(p_name));
|
|
|
|
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); //can't delete output
|
|
|
|
|
|
|
|
{
|
2018-08-20 18:38:18 +02:00
|
|
|
Ref<AnimationNode> node = nodes[p_name].node;
|
2020-02-21 18:28:45 +01:00
|
|
|
node->disconnect("tree_changed", callable_mp(this, &AnimationNodeBlendTree::_tree_changed));
|
|
|
|
node->disconnect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
nodes.erase(p_name);
|
|
|
|
|
|
|
|
//erase connections to name
|
2021-08-09 22:13:42 +02:00
|
|
|
for (KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
for (int i = 0; i < E.value.connections.size(); i++) {
|
|
|
|
if (E.value.connections[i] == p_name) {
|
|
|
|
E.value.connections.write[i] = StringName();
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
emit_changed();
|
2021-07-17 23:22:52 +02:00
|
|
|
emit_signal(SNAME("tree_changed"));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringName &p_new_name) {
|
|
|
|
ERR_FAIL_COND(!nodes.has(p_name));
|
|
|
|
ERR_FAIL_COND(nodes.has(p_new_name));
|
|
|
|
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output);
|
|
|
|
ERR_FAIL_COND(p_new_name == SceneStringNames::get_singleton()->output);
|
|
|
|
|
2020-02-21 18:28:45 +01:00
|
|
|
nodes[p_name].node->disconnect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed));
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
nodes[p_new_name] = nodes[p_name];
|
|
|
|
nodes.erase(p_name);
|
|
|
|
|
|
|
|
//rename connections
|
2021-08-09 22:13:42 +02:00
|
|
|
for (KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
for (int i = 0; i < E.value.connections.size(); i++) {
|
|
|
|
if (E.value.connections[i] == p_name) {
|
|
|
|
E.value.connections.write[i] = p_new_name;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-20 18:38:18 +02:00
|
|
|
//connection must be done with new name
|
2022-07-28 22:56:41 +02:00
|
|
|
nodes[p_new_name].node->connect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_new_name), CONNECT_REFERENCE_COUNTED);
|
2018-08-20 18:38:18 +02:00
|
|
|
|
2021-07-17 23:22:52 +02:00
|
|
|
emit_signal(SNAME("tree_changed"));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) {
|
|
|
|
ERR_FAIL_COND(!nodes.has(p_output_node));
|
|
|
|
ERR_FAIL_COND(!nodes.has(p_input_node));
|
|
|
|
ERR_FAIL_COND(p_output_node == SceneStringNames::get_singleton()->output);
|
|
|
|
ERR_FAIL_COND(p_input_node == p_output_node);
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Ref<AnimationNode> input = nodes[p_input_node].node;
|
|
|
|
ERR_FAIL_INDEX(p_input_index, nodes[p_input_node].connections.size());
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2021-08-09 22:13:42 +02:00
|
|
|
for (KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
for (int i = 0; i < E.value.connections.size(); i++) {
|
|
|
|
StringName output = E.value.connections[i];
|
2018-06-19 03:10:48 +02:00
|
|
|
ERR_FAIL_COND(output == p_output_node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
nodes[p_input_node].connections.write[p_input_index] = p_output_node;
|
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
emit_changed();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlendTree::disconnect_node(const StringName &p_node, int p_input_index) {
|
|
|
|
ERR_FAIL_COND(!nodes.has(p_node));
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Ref<AnimationNode> input = nodes[p_node].node;
|
|
|
|
ERR_FAIL_INDEX(p_input_index, nodes[p_node].connections.size());
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
nodes[p_node].connections.write[p_input_index] = StringName();
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) const {
|
|
|
|
if (!nodes.has(p_output_node) || p_output_node == SceneStringNames::get_singleton()->output) {
|
|
|
|
return CONNECTION_ERROR_NO_OUTPUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nodes.has(p_input_node)) {
|
|
|
|
return CONNECTION_ERROR_NO_INPUT;
|
|
|
|
}
|
|
|
|
|
2019-06-03 21:52:50 +02:00
|
|
|
if (p_input_node == p_output_node) {
|
2018-06-19 03:10:48 +02:00
|
|
|
return CONNECTION_ERROR_SAME_NODE;
|
|
|
|
}
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Ref<AnimationNode> input = nodes[p_input_node].node;
|
2018-06-19 03:10:48 +02:00
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
if (p_input_index < 0 || p_input_index >= nodes[p_input_node].connections.size()) {
|
2018-06-19 03:10:48 +02:00
|
|
|
return CONNECTION_ERROR_NO_INPUT_INDEX;
|
|
|
|
}
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
if (nodes[p_input_node].connections[p_input_index] != StringName()) {
|
2018-06-19 03:10:48 +02:00
|
|
|
return CONNECTION_ERROR_CONNECTION_EXISTS;
|
|
|
|
}
|
|
|
|
|
2021-08-09 22:13:42 +02:00
|
|
|
for (const KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
for (int i = 0; i < E.value.connections.size(); i++) {
|
|
|
|
const StringName output = E.value.connections[i];
|
2018-06-19 03:10:48 +02:00
|
|
|
if (output == p_output_node) {
|
|
|
|
return CONNECTION_ERROR_CONNECTION_EXISTS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return CONNECTION_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlendTree::get_node_connections(List<NodeConnection> *r_connections) const {
|
2021-08-09 22:13:42 +02:00
|
|
|
for (const KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
for (int i = 0; i < E.value.connections.size(); i++) {
|
|
|
|
const StringName output = E.value.connections[i];
|
2018-06-19 03:10:48 +02:00
|
|
|
if (output != StringName()) {
|
|
|
|
NodeConnection nc;
|
2021-08-09 22:13:42 +02:00
|
|
|
nc.input_node = E.key;
|
2018-06-19 03:10:48 +02:00
|
|
|
nc.input_index = i;
|
|
|
|
nc.output_node = output;
|
|
|
|
r_connections->push_back(nc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeBlendTree::get_caption() const {
|
|
|
|
return "BlendTree";
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:53:48 +02:00
|
|
|
double AnimationNodeBlendTree::process(double p_time, bool p_seek, bool p_seek_root) {
|
2018-08-20 18:38:18 +02:00
|
|
|
Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
|
2022-06-29 08:35:29 +02:00
|
|
|
return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {
|
2021-08-09 22:13:42 +02:00
|
|
|
for (const KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
r_list->push_back(E.key);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlendTree::set_graph_offset(const Vector2 &p_graph_offset) {
|
|
|
|
graph_offset = p_graph_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2 AnimationNodeBlendTree::get_graph_offset() const {
|
|
|
|
return graph_offset;
|
|
|
|
}
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
Ref<AnimationNode> AnimationNodeBlendTree::get_child_by_name(const StringName &p_name) {
|
|
|
|
return get_node(p_name);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) {
|
2022-09-29 11:53:28 +02:00
|
|
|
String prop_name = p_name;
|
|
|
|
if (prop_name.begins_with("nodes/")) {
|
|
|
|
String node_name = prop_name.get_slicec('/', 1);
|
|
|
|
String what = prop_name.get_slicec('/', 2);
|
2018-06-19 03:10:48 +02:00
|
|
|
|
|
|
|
if (what == "node") {
|
|
|
|
Ref<AnimationNode> anode = p_value;
|
|
|
|
if (anode.is_valid()) {
|
|
|
|
add_node(node_name, p_value);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (what == "position") {
|
|
|
|
if (nodes.has(node_name)) {
|
2018-08-20 18:38:18 +02:00
|
|
|
nodes[node_name].position = p_value;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2022-09-29 11:53:28 +02:00
|
|
|
} else if (prop_name == "node_connections") {
|
2018-06-19 03:10:48 +02:00
|
|
|
Array conns = p_value;
|
|
|
|
ERR_FAIL_COND_V(conns.size() % 3 != 0, false);
|
|
|
|
|
|
|
|
for (int i = 0; i < conns.size(); i += 3) {
|
|
|
|
connect_node(conns[i], conns[i + 1], conns[i + 2]);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) const {
|
2022-09-29 11:53:28 +02:00
|
|
|
String prop_name = p_name;
|
|
|
|
if (prop_name.begins_with("nodes/")) {
|
|
|
|
String node_name = prop_name.get_slicec('/', 1);
|
|
|
|
String what = prop_name.get_slicec('/', 2);
|
2018-06-19 03:10:48 +02:00
|
|
|
|
|
|
|
if (what == "node") {
|
|
|
|
if (nodes.has(node_name)) {
|
2018-08-20 18:38:18 +02:00
|
|
|
r_ret = nodes[node_name].node;
|
2018-06-19 03:10:48 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (what == "position") {
|
|
|
|
if (nodes.has(node_name)) {
|
2018-08-20 18:38:18 +02:00
|
|
|
r_ret = nodes[node_name].position;
|
2018-06-19 03:10:48 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2022-09-29 11:53:28 +02:00
|
|
|
} else if (prop_name == "node_connections") {
|
2018-06-19 03:10:48 +02:00
|
|
|
List<NodeConnection> nc;
|
|
|
|
get_node_connections(&nc);
|
|
|
|
Array conns;
|
|
|
|
conns.resize(nc.size() * 3);
|
|
|
|
|
|
|
|
int idx = 0;
|
2021-07-24 15:46:25 +02:00
|
|
|
for (const NodeConnection &E : nc) {
|
2021-07-16 05:45:57 +02:00
|
|
|
conns[idx * 3 + 0] = E.input_node;
|
|
|
|
conns[idx * 3 + 1] = E.input_index;
|
|
|
|
conns[idx * 3 + 2] = E.output_node;
|
2018-06-19 03:10:48 +02:00
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
r_ret = conns;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2020-05-14 14:29:06 +02:00
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const {
|
|
|
|
List<StringName> names;
|
2021-08-09 22:13:42 +02:00
|
|
|
for (const KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
names.push_back(E.key);
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
names.sort_custom<StringName::AlphCompare>();
|
|
|
|
|
2021-07-24 15:46:25 +02:00
|
|
|
for (const StringName &E : names) {
|
2022-09-29 11:53:28 +02:00
|
|
|
String prop_name = E;
|
|
|
|
if (prop_name != "output") {
|
|
|
|
p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NO_EDITOR));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
2022-09-29 11:53:28 +02:00
|
|
|
p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2021-11-03 23:06:17 +01:00
|
|
|
p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2021-02-11 18:18:45 +01:00
|
|
|
void AnimationNodeBlendTree::reset_state() {
|
|
|
|
graph_offset = Vector2();
|
|
|
|
nodes.clear();
|
2021-08-26 18:07:13 +02:00
|
|
|
_initialize_node_tree();
|
2021-02-11 18:18:45 +01:00
|
|
|
emit_changed();
|
2021-07-17 23:22:52 +02:00
|
|
|
emit_signal(SNAME("tree_changed"));
|
2021-02-11 18:18:45 +01:00
|
|
|
}
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
void AnimationNodeBlendTree::_tree_changed() {
|
2021-07-17 23:22:52 +02:00
|
|
|
emit_signal(SNAME("tree_changed"));
|
2018-08-20 18:38:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlendTree::_node_changed(const StringName &p_node) {
|
|
|
|
ERR_FAIL_COND(!nodes.has(p_node));
|
|
|
|
nodes[p_node].connections.resize(nodes[p_node].node->get_input_count());
|
2022-09-01 16:00:55 +02:00
|
|
|
emit_signal(SNAME("node_changed"), p_node);
|
2018-08-20 18:38:18 +02:00
|
|
|
}
|
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
void AnimationNodeBlendTree::_bind_methods() {
|
2018-08-20 18:38:18 +02:00
|
|
|
ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeBlendTree::add_node, DEFVAL(Vector2()));
|
2018-06-19 03:10:48 +02:00
|
|
|
ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeBlendTree::get_node);
|
|
|
|
ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeBlendTree::remove_node);
|
|
|
|
ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeBlendTree::rename_node);
|
|
|
|
ClassDB::bind_method(D_METHOD("has_node", "name"), &AnimationNodeBlendTree::has_node);
|
|
|
|
ClassDB::bind_method(D_METHOD("connect_node", "input_node", "input_index", "output_node"), &AnimationNodeBlendTree::connect_node);
|
|
|
|
ClassDB::bind_method(D_METHOD("disconnect_node", "input_node", "input_index"), &AnimationNodeBlendTree::disconnect_node);
|
|
|
|
|
2018-08-20 18:38:18 +02:00
|
|
|
ClassDB::bind_method(D_METHOD("set_node_position", "name", "position"), &AnimationNodeBlendTree::set_node_position);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_node_position", "name"), &AnimationNodeBlendTree::get_node_position);
|
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &AnimationNodeBlendTree::set_graph_offset);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeBlendTree::get_graph_offset);
|
|
|
|
|
2021-11-03 23:06:17 +01:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset");
|
2018-06-19 03:10:48 +02:00
|
|
|
|
|
|
|
BIND_CONSTANT(CONNECTION_OK);
|
|
|
|
BIND_CONSTANT(CONNECTION_ERROR_NO_INPUT);
|
|
|
|
BIND_CONSTANT(CONNECTION_ERROR_NO_INPUT_INDEX);
|
|
|
|
BIND_CONSTANT(CONNECTION_ERROR_NO_OUTPUT);
|
|
|
|
BIND_CONSTANT(CONNECTION_ERROR_SAME_NODE);
|
|
|
|
BIND_CONSTANT(CONNECTION_ERROR_CONNECTION_EXISTS);
|
2022-09-01 16:00:55 +02:00
|
|
|
|
|
|
|
ADD_SIGNAL(MethodInfo("node_changed", PropertyInfo(Variant::STRING_NAME, "node_name")));
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2021-08-26 18:07:13 +02:00
|
|
|
void AnimationNodeBlendTree::_initialize_node_tree() {
|
2018-06-19 03:10:48 +02:00
|
|
|
Ref<AnimationNodeOutput> output;
|
2021-06-18 00:03:09 +02:00
|
|
|
output.instantiate();
|
2018-08-20 18:38:18 +02:00
|
|
|
Node n;
|
|
|
|
n.node = output;
|
|
|
|
n.position = Vector2(300, 150);
|
|
|
|
n.connections.resize(1);
|
|
|
|
nodes["output"] = n;
|
2018-06-19 03:10:48 +02:00
|
|
|
}
|
|
|
|
|
2021-08-26 18:07:13 +02:00
|
|
|
AnimationNodeBlendTree::AnimationNodeBlendTree() {
|
|
|
|
_initialize_node_tree();
|
|
|
|
}
|
|
|
|
|
2018-06-19 03:10:48 +02:00
|
|
|
AnimationNodeBlendTree::~AnimationNodeBlendTree() {
|
|
|
|
}
|