2018-08-29 20:38:13 +00:00
|
|
|
/*************************************************************************/
|
|
|
|
/* animation_blend_tree.cpp */
|
|
|
|
/*************************************************************************/
|
|
|
|
/* This file is part of: */
|
|
|
|
/* GODOT ENGINE */
|
|
|
|
/* https://godotengine.org */
|
|
|
|
/*************************************************************************/
|
2022-01-03 20:27:34 +00:00
|
|
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
|
|
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
2018-08-29 20:38:13 +00: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 01:10:48 +00:00
|
|
|
#include "animation_blend_tree.h"
|
2020-01-21 20:32:27 +00:00
|
|
|
|
2021-10-15 13:25:00 +00:00
|
|
|
#include "scene/resources/animation.h"
|
2018-06-19 01:10:48 +00: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-01 23:20:12 +00:00
|
|
|
Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = nullptr;
|
2018-08-20 16:38:18 +00:00
|
|
|
|
2018-11-08 19:51:45 +00:00
|
|
|
void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) const {
|
2021-07-01 01:24:34 +00:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
2018-11-08 19:51:45 +00:00
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const {
|
2018-08-20 16:38:18 +00:00
|
|
|
if (property.name == "animation" && get_editable_animation_list) {
|
|
|
|
Vector<String> names = get_editable_animation_list();
|
|
|
|
String anims;
|
|
|
|
for (int i = 0; i < names.size(); i++) {
|
|
|
|
if (i > 0) {
|
|
|
|
anims += ",";
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
2018-08-20 16:38:18 +00:00
|
|
|
anims += String(names[i]);
|
|
|
|
}
|
2021-12-09 09:42:46 +00:00
|
|
|
if (!anims.is_empty()) {
|
2018-08-20 16:38:18 +00:00
|
|
|
property.hint = PROPERTY_HINT_ENUM;
|
|
|
|
property.hint_string = anims;
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_seek_root) {
|
2018-08-20 16:38:18 +00:00
|
|
|
AnimationPlayer *ap = state->player;
|
2018-06-19 01:10:48 +00:00
|
|
|
ERR_FAIL_COND_V(!ap, 0);
|
|
|
|
|
2021-05-21 06:42:37 +00:00
|
|
|
double time = get_parameter(this->time);
|
2018-11-08 19:51:45 +00:00
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
if (!ap->has_animation(animation)) {
|
|
|
|
AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent);
|
|
|
|
if (tree) {
|
2018-06-21 18:45:44 +00:00
|
|
|
String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
|
2018-06-19 01:10:48 +00:00
|
|
|
make_invalid(vformat(RTR("On BlendTree node '%s', animation not found: '%s'"), name, animation));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
make_invalid(vformat(RTR("Animation not found: '%s'"), animation));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
Ref<Animation> anim = ap->get_animation(animation);
|
2021-10-15 13:25:00 +00:00
|
|
|
double anim_size = (double)anim->get_length();
|
|
|
|
double step = 0.0;
|
|
|
|
double prev_time = time;
|
|
|
|
int pingponged = 0;
|
|
|
|
bool current_backward = signbit(p_time);
|
2018-11-08 19:51:45 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
if (p_seek) {
|
2021-10-15 13:25:00 +00:00
|
|
|
step = p_time - time;
|
2018-06-19 01:10:48 +00:00
|
|
|
time = p_time;
|
|
|
|
} else {
|
2021-10-15 13:25:00 +00:00
|
|
|
p_time *= backward ? -1.0 : 1.0;
|
|
|
|
if (!(time == anim_size && !current_backward) && !(time == 0 && current_backward)) {
|
|
|
|
time = time + p_time;
|
|
|
|
step = p_time;
|
|
|
|
}
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
if (anim->get_loop_mode() == Animation::LOOP_PINGPONG) {
|
|
|
|
if (!Math::is_zero_approx(anim_size)) {
|
2021-10-15 13:25:00 +00:00
|
|
|
if ((int)Math::floor(abs(time - prev_time) / anim_size) % 2 == 0) {
|
|
|
|
if (prev_time > 0 && time <= 0) {
|
|
|
|
backward = !backward;
|
|
|
|
pingponged = -1;
|
|
|
|
}
|
|
|
|
if (prev_time < anim_size && time >= anim_size) {
|
|
|
|
backward = !backward;
|
|
|
|
pingponged = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
time = Math::pingpong(time, anim_size);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
2021-10-15 13:25:00 +00:00
|
|
|
} else {
|
2022-05-04 18:53:48 +00:00
|
|
|
if (anim->get_loop_mode() == Animation::LOOP_LINEAR) {
|
|
|
|
if (!Math::is_zero_approx(anim_size)) {
|
2021-10-15 13:25:00 +00:00
|
|
|
time = Math::fposmod(time, anim_size);
|
|
|
|
}
|
|
|
|
} else if (time < 0) {
|
2022-05-04 18:53:48 +00:00
|
|
|
step += time;
|
2021-10-15 13:25:00 +00:00
|
|
|
time = 0;
|
|
|
|
} else if (time > anim_size) {
|
2022-05-04 18:53:48 +00:00
|
|
|
step += anim_size - time;
|
2021-10-15 13:25:00 +00:00
|
|
|
time = anim_size;
|
|
|
|
}
|
|
|
|
backward = false;
|
2021-04-24 20:47:03 +00:00
|
|
|
}
|
2021-10-11 22:27:50 +00:00
|
|
|
|
2021-10-15 13:25:00 +00:00
|
|
|
if (play_mode == PLAY_MODE_FORWARD) {
|
2022-05-04 18:53:48 +00:00
|
|
|
blend_animation(animation, time, step, p_seek, p_seek_root, 1.0, pingponged);
|
2021-10-15 13:25:00 +00:00
|
|
|
} else {
|
2022-05-04 18:53:48 +00:00
|
|
|
blend_animation(animation, anim_size - time, -step, p_seek, p_seek_root, 1.0, pingponged);
|
2021-10-15 13:25:00 +00:00
|
|
|
}
|
2018-11-08 19:51:45 +00:00
|
|
|
set_parameter(this->time, time);
|
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
return anim_size - time;
|
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeAnimation::get_caption() const {
|
|
|
|
return "Animation";
|
|
|
|
}
|
|
|
|
|
2021-10-15 13:25:00 +00: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 01:10:48 +00: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 13:25:00 +00: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 21:58:05 +00:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation");
|
2021-10-15 13:25:00 +00: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 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeAnimation::AnimationNodeAnimation() {
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
|
|
|
|
r_list->push_back(PropertyInfo(Variant::BOOL, active));
|
2021-07-01 01:24:34 +00: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 16:38:18 +00:00
|
|
|
}
|
2019-01-25 21:15:29 +00:00
|
|
|
|
2018-08-20 16:38:18 +00: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 21:15:29 +00:00
|
|
|
} else if (p_parameter == time_to_restart) {
|
|
|
|
return -1;
|
2018-08-20 16:38:18 +00:00
|
|
|
} else {
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
void AnimationNodeOneShot::set_fadein_time(float p_time) {
|
|
|
|
fade_in = p_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeOneShot::set_fadeout_time(float p_time) {
|
|
|
|
fade_out = p_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
float AnimationNodeOneShot::get_fadein_time() const {
|
|
|
|
return fade_in;
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
float AnimationNodeOneShot::get_fadeout_time() const {
|
|
|
|
return fade_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeOneShot::set_autorestart(bool p_active) {
|
|
|
|
autorestart = p_active;
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
void AnimationNodeOneShot::set_autorestart_delay(float p_time) {
|
|
|
|
autorestart_delay = p_time;
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
void AnimationNodeOneShot::set_autorestart_random_delay(float p_time) {
|
|
|
|
autorestart_random_delay = p_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeOneShot::has_autorestart() const {
|
|
|
|
return autorestart;
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
float AnimationNodeOneShot::get_autorestart_delay() const {
|
|
|
|
return autorestart_delay;
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
float AnimationNodeOneShot::get_autorestart_random_delay() const {
|
|
|
|
return autorestart_random_delay;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeOneShot::set_mix_mode(MixMode p_mix) {
|
|
|
|
mix = p_mix;
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00: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 18:53:48 +00:00
|
|
|
double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_root) {
|
2018-08-20 16:38:18 +00:00
|
|
|
bool active = get_parameter(this->active);
|
|
|
|
bool prev_active = get_parameter(this->prev_active);
|
2021-05-21 06:42:37 +00:00
|
|
|
double time = get_parameter(this->time);
|
|
|
|
double remaining = get_parameter(this->remaining);
|
|
|
|
double time_to_restart = get_parameter(this->time_to_restart);
|
2018-08-20 16:38:18 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
if (!active) {
|
|
|
|
//make it as if this node doesn't exist, pass input 0 by.
|
2018-08-20 16:38:18 +00:00
|
|
|
if (prev_active) {
|
|
|
|
set_parameter(this->prev_active, false);
|
|
|
|
}
|
2019-01-25 21:15:29 +00:00
|
|
|
if (time_to_restart >= 0.0 && !p_seek) {
|
|
|
|
time_to_restart -= p_time;
|
|
|
|
if (time_to_restart < 0) {
|
|
|
|
//restart
|
|
|
|
set_parameter(this->active, true);
|
|
|
|
active = true;
|
|
|
|
}
|
|
|
|
set_parameter(this->time_to_restart, time_to_restart);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!active) {
|
2022-05-04 18:53:48 +00:00
|
|
|
return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, !sync);
|
2019-01-25 21:15:29 +00:00
|
|
|
}
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool os_seek = p_seek;
|
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (p_seek) {
|
2018-06-19 01:10:48 +00:00
|
|
|
time = p_time;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2018-08-20 16:38:18 +00:00
|
|
|
bool do_start = !prev_active;
|
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
if (do_start) {
|
|
|
|
time = 0;
|
|
|
|
os_seek = true;
|
2018-08-20 16:38:18 +00:00
|
|
|
set_parameter(this->prev_active, true);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
float blend;
|
|
|
|
|
|
|
|
if (time < fade_in) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (fade_in > 0) {
|
2018-06-19 01:10:48 +00:00
|
|
|
blend = time / fade_in;
|
2020-05-14 14:41:43 +00:00
|
|
|
} else {
|
2021-09-12 17:06:57 +00:00
|
|
|
blend = 0;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2021-09-12 17:06:57 +00:00
|
|
|
} else if (!do_start && remaining <= fade_out) {
|
|
|
|
if (fade_out > 0) {
|
2018-06-19 01:10:48 +00:00
|
|
|
blend = (remaining / fade_out);
|
2020-05-14 14:41:43 +00:00
|
|
|
} else {
|
2021-09-12 17:06:57 +00:00
|
|
|
blend = 0;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
|
|
|
} else {
|
2018-06-19 01:10:48 +00:00
|
|
|
blend = 1.0;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2018-06-19 01:10:48 +00:00
|
|
|
|
2021-09-12 17:06:57 +00:00
|
|
|
double main_rem;
|
2018-06-19 01:10:48 +00:00
|
|
|
if (mix == MIX_MODE_ADD) {
|
2022-05-04 18:53:48 +00:00
|
|
|
main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, !sync);
|
2018-06-19 01:10:48 +00:00
|
|
|
} else {
|
2022-05-04 18:53:48 +00:00
|
|
|
main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_BLEND, !sync);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
double os_rem = blend_input(1, os_seek ? time : p_time, os_seek, p_seek_root, blend, FILTER_PASS, false);
|
2018-06-19 01:10:48 +00:00
|
|
|
|
|
|
|
if (do_start) {
|
|
|
|
remaining = os_rem;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!p_seek) {
|
|
|
|
time += p_time;
|
|
|
|
remaining = os_rem;
|
2018-08-20 16:38:18 +00:00
|
|
|
if (remaining <= 0) {
|
|
|
|
set_parameter(this->active, false);
|
|
|
|
set_parameter(this->prev_active, false);
|
2019-01-25 21:15:29 +00:00
|
|
|
if (autorestart) {
|
|
|
|
float restart_sec = autorestart_delay + Math::randf() * autorestart_random_delay;
|
|
|
|
set_parameter(this->time_to_restart, restart_sec);
|
|
|
|
}
|
2018-08-20 16:38:18 +00:00
|
|
|
}
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
set_parameter(this->time, time);
|
|
|
|
set_parameter(this->remaining, remaining);
|
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
return MAX(main_rem, remaining);
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
void AnimationNodeOneShot::set_use_sync(bool p_sync) {
|
|
|
|
sync = p_sync;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeOneShot::is_using_sync() const {
|
|
|
|
return sync;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeOneShot::set_use_sync);
|
|
|
|
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeOneShot::is_using_sync);
|
|
|
|
|
2020-04-16 21:21:11 +00:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_mode", PROPERTY_HINT_ENUM, "Blend,Add"), "set_mix_mode", "get_mix_mode");
|
|
|
|
|
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 18:20:53 +00:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadein_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_fadein_time", "get_fadein_time");
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadeout_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_fadeout_time", "get_fadeout_time");
|
2018-06-19 01:10:48 +00:00
|
|
|
|
2022-03-18 04:53:34 +00:00
|
|
|
ADD_GROUP("Auto Restart", "autorestart_");
|
2018-06-19 01:10:48 +00:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autorestart"), "set_autorestart", "has_autorestart");
|
|
|
|
|
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 18:20:53 +00:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_autorestart_delay", "get_autorestart_delay");
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_autorestart_random_delay", "get_autorestart_random_delay");
|
2018-06-19 01:10:48 +00:00
|
|
|
|
|
|
|
ADD_GROUP("", "");
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
|
|
|
|
|
2019-10-02 07:57:12 +00:00
|
|
|
BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
|
|
|
|
BIND_ENUM_CONSTANT(MIX_MODE_ADD);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeOneShot::AnimationNodeOneShot() {
|
|
|
|
add_input("in");
|
|
|
|
add_input("shot");
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
|
|
|
2018-08-20 16:38:18 +00: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 18:20:53 +00:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, add_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
Variant AnimationNodeAdd2::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 0;
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 23:50:25 +00:00
|
|
|
String AnimationNodeAdd2::get_caption() const {
|
|
|
|
return "Add2";
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-27 23:50:25 +00:00
|
|
|
void AnimationNodeAdd2::set_use_sync(bool p_sync) {
|
2018-06-19 01:10:48 +00:00
|
|
|
sync = p_sync;
|
|
|
|
}
|
|
|
|
|
2018-06-27 23:50:25 +00:00
|
|
|
bool AnimationNodeAdd2::is_using_sync() const {
|
2018-06-19 01:10:48 +00:00
|
|
|
return sync;
|
|
|
|
}
|
|
|
|
|
2018-06-27 23:50:25 +00:00
|
|
|
bool AnimationNodeAdd2::has_filter() const {
|
2018-06-19 01:10:48 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
double AnimationNodeAdd2::process(double p_time, bool p_seek, bool p_seek_root) {
|
2021-05-21 06:42:37 +00:00
|
|
|
double amount = get_parameter(add_amount);
|
2022-05-04 18:53:48 +00: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 01:10:48 +00:00
|
|
|
|
|
|
|
return rem0;
|
|
|
|
}
|
|
|
|
|
2018-06-27 23:50:25 +00:00
|
|
|
void AnimationNodeAdd2::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd2::set_use_sync);
|
|
|
|
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd2::is_using_sync);
|
2018-06-19 01:10:48 +00:00
|
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
|
|
|
|
}
|
|
|
|
|
2018-06-27 23:50:25 +00:00
|
|
|
AnimationNodeAdd2::AnimationNodeAdd2() {
|
2018-06-19 01:10:48 +00:00
|
|
|
add_input("in");
|
|
|
|
add_input("add");
|
|
|
|
}
|
|
|
|
|
2018-06-27 23:50:25 +00:00
|
|
|
////////////////////////////////////////////////
|
|
|
|
|
2018-08-20 16:38:18 +00: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 18:20:53 +00:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, add_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
|
2018-06-27 23:50:25 +00:00
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
Variant AnimationNodeAdd3::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 0;
|
2018-06-27 23:50:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeAdd3::get_caption() const {
|
|
|
|
return "Add3";
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-27 23:50:25 +00:00
|
|
|
void AnimationNodeAdd3::set_use_sync(bool p_sync) {
|
|
|
|
sync = p_sync;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeAdd3::is_using_sync() const {
|
|
|
|
return sync;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeAdd3::has_filter() const {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
double AnimationNodeAdd3::process(double p_time, bool p_seek, bool p_seek_root) {
|
2021-05-21 06:42:37 +00:00
|
|
|
double amount = get_parameter(add_amount);
|
2022-05-04 18:53:48 +00: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-27 23:50:25 +00:00
|
|
|
|
|
|
|
return rem0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeAdd3::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd3::set_use_sync);
|
|
|
|
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd3::is_using_sync);
|
|
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeAdd3::AnimationNodeAdd3() {
|
|
|
|
add_input("-add");
|
|
|
|
add_input("in");
|
|
|
|
add_input("+add");
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
/////////////////////////////////////////////
|
|
|
|
|
2018-08-20 16:38:18 +00: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 18:20:53 +00:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 0; //for blend amount
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
2018-08-20 16:38:18 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
String AnimationNodeBlend2::get_caption() const {
|
|
|
|
return "Blend2";
|
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_seek_root) {
|
2021-05-21 06:42:37 +00:00
|
|
|
double amount = get_parameter(blend_amount);
|
2018-08-20 16:38:18 +00:00
|
|
|
|
2022-05-04 18:53:48 +00: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 01:10:48 +00:00
|
|
|
|
|
|
|
return amount > 0.5 ? rem1 : rem0; //hacky but good enough
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlend2::set_use_sync(bool p_sync) {
|
|
|
|
sync = p_sync;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeBlend2::is_using_sync() const {
|
|
|
|
return sync;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeBlend2::has_filter() const {
|
|
|
|
return true;
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
void AnimationNodeBlend2::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend2::set_use_sync);
|
|
|
|
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend2::is_using_sync);
|
|
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
AnimationNodeBlend2::AnimationNodeBlend2() {
|
|
|
|
add_input("in");
|
|
|
|
add_input("blend");
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////
|
|
|
|
|
2018-08-20 16:38:18 +00: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 18:20:53 +00:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 0; //for blend amount
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeBlend3::get_caption() const {
|
|
|
|
return "Blend3";
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlend3::set_use_sync(bool p_sync) {
|
|
|
|
sync = p_sync;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeBlend3::is_using_sync() const {
|
|
|
|
return sync;
|
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_seek_root) {
|
2021-05-21 06:42:37 +00:00
|
|
|
double amount = get_parameter(blend_amount);
|
2022-05-04 18:53:48 +00: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 01:10:48 +00:00
|
|
|
|
|
|
|
return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); //hacky but good enough
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlend3::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend3::set_use_sync);
|
|
|
|
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend3::is_using_sync);
|
|
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
AnimationNodeBlend3::AnimationNodeBlend3() {
|
|
|
|
add_input("-blend");
|
|
|
|
add_input("in");
|
|
|
|
add_input("+blend");
|
|
|
|
sync = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////
|
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const {
|
2021-10-15 13:25:00 +00:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_lesser,or_greater"));
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 1.0; //initial timescale
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeTimeScale::get_caption() const {
|
|
|
|
return "TimeScale";
|
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
double AnimationNodeTimeScale::process(double p_time, bool p_seek, bool p_seek_root) {
|
2021-05-21 06:42:37 +00:00
|
|
|
double scale = get_parameter(this->scale);
|
2018-06-19 01:10:48 +00:00
|
|
|
if (p_seek) {
|
2022-05-04 18:53:48 +00:00
|
|
|
return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, false);
|
2018-06-19 01:10:48 +00:00
|
|
|
} else {
|
2022-05-04 18:53:48 +00:00
|
|
|
return blend_input(0, p_time * scale, false, p_seek_root, 1.0, FILTER_IGNORE, false);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTimeScale::_bind_methods() {
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
AnimationNodeTimeScale::AnimationNodeTimeScale() {
|
|
|
|
add_input("in");
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////
|
|
|
|
|
2018-08-20 16:38:18 +00: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 18:20:53 +00:00
|
|
|
r_list->push_back(PropertyInfo(Variant::FLOAT, seek_pos, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater"));
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const {
|
|
|
|
return 1.0; //initial timescale
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeTimeSeek::get_caption() const {
|
|
|
|
return "Seek";
|
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_seek_root) {
|
2021-05-21 06:42:37 +00:00
|
|
|
double seek_pos = get_parameter(this->seek_pos);
|
2018-06-19 01:10:48 +00:00
|
|
|
if (p_seek) {
|
2022-05-04 18:53:48 +00:00
|
|
|
return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, false);
|
2018-06-19 01:10:48 +00:00
|
|
|
} else if (seek_pos >= 0) {
|
2022-05-04 18:53:48 +00:00
|
|
|
double ret = blend_input(0, seek_pos, true, true, 1.0, FILTER_IGNORE, false);
|
2018-08-20 16:38:18 +00:00
|
|
|
set_parameter(this->seek_pos, -1.0); //reset
|
2018-06-19 01:10:48 +00:00
|
|
|
return ret;
|
|
|
|
} else {
|
2022-05-04 18:53:48 +00:00
|
|
|
return blend_input(0, p_time, false, p_seek_root, 1.0, FILTER_IGNORE, false);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTimeSeek::_bind_methods() {
|
|
|
|
}
|
2018-08-20 16:38:18 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
AnimationNodeTimeSeek::AnimationNodeTimeSeek() {
|
|
|
|
add_input("in");
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
|
|
|
2018-08-20 16:38:18 +00: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 01:24:34 +00: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 16:38:18 +00:00
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-08-20 16:38:18 +00: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 01:10:48 +00: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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTransition::set_cross_fade_time(float p_fade) {
|
|
|
|
xfade = p_fade;
|
|
|
|
}
|
|
|
|
|
|
|
|
float AnimationNodeTransition::get_cross_fade_time() const {
|
|
|
|
return xfade;
|
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_root) {
|
2018-08-20 16:38:18 +00:00
|
|
|
int current = get_parameter(this->current);
|
|
|
|
int prev = get_parameter(this->prev);
|
|
|
|
int prev_current = get_parameter(this->prev_current);
|
|
|
|
|
2021-05-21 06:42:37 +00:00
|
|
|
double time = get_parameter(this->time);
|
|
|
|
double prev_xfading = get_parameter(this->prev_xfading);
|
2018-08-20 16:38:18 +00:00
|
|
|
|
|
|
|
bool switched = current != prev_current;
|
|
|
|
|
|
|
|
if (switched) {
|
|
|
|
set_parameter(this->prev_current, current);
|
|
|
|
set_parameter(this->prev, prev_current);
|
|
|
|
|
|
|
|
prev = prev_current;
|
|
|
|
prev_xfading = xfade;
|
|
|
|
time = 0;
|
|
|
|
switched = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (current < 0 || current >= enabled_inputs || prev >= enabled_inputs) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-01-27 02:52:39 +00:00
|
|
|
double rem = 0.0;
|
2018-08-20 16:38:18 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
if (prev < 0) { // process current animation, check for transition
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, false);
|
2018-06-19 01:10:48 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (p_seek) {
|
2018-06-19 01:10:48 +00:00
|
|
|
time = p_time;
|
2020-05-14 14:41:43 +00:00
|
|
|
} else {
|
2018-06-19 01:10:48 +00:00
|
|
|
time += p_time;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2018-06-19 01:10:48 +00:00
|
|
|
|
|
|
|
if (inputs[current].auto_advance && rem <= xfade) {
|
2018-08-20 16:38:18 +00:00
|
|
|
set_parameter(this->current, (current + 1) % enabled_inputs);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else { // cross-fading from prev to current
|
|
|
|
|
2021-09-10 17:25:47 +00:00
|
|
|
float blend = xfade == 0 ? 0 : (prev_xfading / xfade);
|
2018-06-19 01:10:48 +00:00
|
|
|
|
|
|
|
if (!p_seek && switched) { //just switched, seek to start of current
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
rem = blend_input(current, 0, true, p_seek_root, 1.0 - blend, FILTER_IGNORE, false);
|
2018-06-19 01:10:48 +00:00
|
|
|
} else {
|
2022-05-04 18:53:48 +00:00
|
|
|
rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_IGNORE, false);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (p_seek) { // don't seek prev animation
|
2022-05-04 18:53:48 +00:00
|
|
|
blend_input(prev, 0, false, p_seek_root, blend, FILTER_IGNORE, false);
|
2018-06-19 01:10:48 +00:00
|
|
|
time = p_time;
|
|
|
|
} else {
|
2022-05-04 18:53:48 +00:00
|
|
|
blend_input(prev, p_time, false, p_seek_root, blend, FILTER_IGNORE, false);
|
2018-06-19 01:10:48 +00:00
|
|
|
time += p_time;
|
|
|
|
prev_xfading -= p_time;
|
|
|
|
if (prev_xfading < 0) {
|
2018-08-20 16:38:18 +00:00
|
|
|
set_parameter(this->prev, -1);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-20 16:38:18 +00:00
|
|
|
|
|
|
|
set_parameter(this->time, time);
|
|
|
|
set_parameter(this->prev_xfading, prev_xfading);
|
|
|
|
|
|
|
|
return rem;
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeTransition::_validate_property(PropertyInfo &property) const {
|
|
|
|
if (property.name.begins_with("input_")) {
|
|
|
|
String n = property.name.get_slicec('/', 0).get_slicec('_', 1);
|
|
|
|
if (n != "count") {
|
|
|
|
int idx = n.to_int();
|
|
|
|
if (idx >= enabled_inputs) {
|
2021-07-01 01:24:34 +00:00
|
|
|
property.usage = PROPERTY_USAGE_NONE;
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-21 18:45:44 +00:00
|
|
|
|
|
|
|
AnimationNode::_validate_property(property);
|
2018-06-19 01:10:48 +00: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);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time);
|
|
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
|
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 18:20:53 +00:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01"), "set_cross_fade_time", "get_cross_fade_time");
|
2018-06-19 01:10:48 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < MAX_INPUTS; i++) {
|
2020-01-23 10:14:14 +00: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 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeTransition::AnimationNodeTransition() {
|
|
|
|
for (int i = 0; i < MAX_INPUTS; i++) {
|
2019-01-09 05:44:41 +00:00
|
|
|
inputs[i].name = "state " + itos(i);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////
|
|
|
|
|
|
|
|
String AnimationNodeOutput::get_caption() const {
|
|
|
|
return "Output";
|
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
double AnimationNodeOutput::process(double p_time, bool p_seek, bool p_seek_root) {
|
|
|
|
return blend_input(0, p_time, p_seek, p_seek_root, 1.0);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AnimationNodeOutput::AnimationNodeOutput() {
|
|
|
|
add_input("output");
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
2018-08-20 16:38:18 +00:00
|
|
|
void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position) {
|
2018-06-19 01:10:48 +00: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 16:03:38 +00:00
|
|
|
ERR_FAIL_COND(String(p_name).contains("/"));
|
2018-06-19 01:10:48 +00:00
|
|
|
|
2018-08-20 16:38:18 +00: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 01:10:48 +00:00
|
|
|
|
|
|
|
emit_changed();
|
2021-07-17 21:22:52 +00:00
|
|
|
emit_signal(SNAME("tree_changed"));
|
2018-08-20 16:38:18 +00:00
|
|
|
|
2020-02-21 17:28:45 +00:00
|
|
|
p_node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendTree::_tree_changed), varray(), CONNECT_REFERENCE_COUNTED);
|
|
|
|
p_node->connect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed), varray(p_name), CONNECT_REFERENCE_COUNTED);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ref<AnimationNode> AnimationNodeBlendTree::get_node(const StringName &p_name) const {
|
|
|
|
ERR_FAIL_COND_V(!nodes.has(p_name), Ref<AnimationNode>());
|
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
return nodes[p_name].node;
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StringName AnimationNodeBlendTree::get_node_name(const Ref<AnimationNode> &p_node) const {
|
2021-08-09 20:13:42 +00:00
|
|
|
for (const KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
if (E.value.node == p_node) {
|
|
|
|
return E.key;
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ERR_FAIL_V(StringName());
|
|
|
|
}
|
2018-08-20 16:38:18 +00: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 20:13:42 +00:00
|
|
|
for (const KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
ns.push_back(E.key);
|
2018-08-20 16:38:18 +00: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 01:10:48 +00:00
|
|
|
bool AnimationNodeBlendTree::has_node(const StringName &p_name) const {
|
|
|
|
return nodes.has(p_name);
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-08-20 16:38:18 +00: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 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00: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 16:38:18 +00:00
|
|
|
Ref<AnimationNode> node = nodes[p_name].node;
|
2020-02-21 17:28:45 +00:00
|
|
|
node->disconnect("tree_changed", callable_mp(this, &AnimationNodeBlendTree::_tree_changed));
|
|
|
|
node->disconnect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed));
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nodes.erase(p_name);
|
|
|
|
|
|
|
|
//erase connections to name
|
2021-08-09 20:13:42 +00: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 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
emit_changed();
|
2021-07-17 21:22:52 +00:00
|
|
|
emit_signal(SNAME("tree_changed"));
|
2018-06-19 01:10:48 +00: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 17:28:45 +00:00
|
|
|
nodes[p_name].node->disconnect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed));
|
2018-08-20 16:38:18 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
nodes[p_new_name] = nodes[p_name];
|
|
|
|
nodes.erase(p_name);
|
|
|
|
|
|
|
|
//rename connections
|
2021-08-09 20:13:42 +00: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 01:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-20 16:38:18 +00:00
|
|
|
//connection must be done with new name
|
2020-02-21 17:28:45 +00:00
|
|
|
nodes[p_new_name].node->connect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed), varray(p_new_name), CONNECT_REFERENCE_COUNTED);
|
2018-08-20 16:38:18 +00:00
|
|
|
|
2021-07-17 21:22:52 +00:00
|
|
|
emit_signal(SNAME("tree_changed"));
|
2018-06-19 01:10:48 +00: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 16:38:18 +00:00
|
|
|
Ref<AnimationNode> input = nodes[p_input_node].node;
|
|
|
|
ERR_FAIL_INDEX(p_input_index, nodes[p_input_node].connections.size());
|
2018-06-19 01:10:48 +00:00
|
|
|
|
2021-08-09 20:13:42 +00: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 01:10:48 +00:00
|
|
|
ERR_FAIL_COND(output == p_output_node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
nodes[p_input_node].connections.write[p_input_index] = p_output_node;
|
|
|
|
|
2018-06-19 01:10:48 +00: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 16:38:18 +00:00
|
|
|
Ref<AnimationNode> input = nodes[p_node].node;
|
|
|
|
ERR_FAIL_INDEX(p_input_index, nodes[p_node].connections.size());
|
2018-06-19 01:10:48 +00:00
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
nodes[p_node].connections.write[p_input_index] = StringName();
|
2018-06-19 01:10:48 +00: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 19:52:50 +00:00
|
|
|
if (p_input_node == p_output_node) {
|
2018-06-19 01:10:48 +00:00
|
|
|
return CONNECTION_ERROR_SAME_NODE;
|
|
|
|
}
|
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
Ref<AnimationNode> input = nodes[p_input_node].node;
|
2018-06-19 01:10:48 +00:00
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
if (p_input_index < 0 || p_input_index >= nodes[p_input_node].connections.size()) {
|
2018-06-19 01:10:48 +00:00
|
|
|
return CONNECTION_ERROR_NO_INPUT_INDEX;
|
|
|
|
}
|
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
if (nodes[p_input_node].connections[p_input_index] != StringName()) {
|
2018-06-19 01:10:48 +00:00
|
|
|
return CONNECTION_ERROR_CONNECTION_EXISTS;
|
|
|
|
}
|
|
|
|
|
2021-08-09 20:13:42 +00: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 01:10:48 +00: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 20:13:42 +00: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 01:10:48 +00:00
|
|
|
if (output != StringName()) {
|
|
|
|
NodeConnection nc;
|
2021-08-09 20:13:42 +00:00
|
|
|
nc.input_node = E.key;
|
2018-06-19 01:10:48 +00:00
|
|
|
nc.input_index = i;
|
|
|
|
nc.output_node = output;
|
|
|
|
r_connections->push_back(nc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String AnimationNodeBlendTree::get_caption() const {
|
|
|
|
return "BlendTree";
|
|
|
|
}
|
|
|
|
|
2022-05-04 18:53:48 +00:00
|
|
|
double AnimationNodeBlendTree::process(double p_time, bool p_seek, bool p_seek_root) {
|
2018-08-20 16:38:18 +00:00
|
|
|
Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
|
2022-05-04 18:53:48 +00:00
|
|
|
return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_seek_root, 1.0);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {
|
2021-08-09 20:13:42 +00:00
|
|
|
for (const KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
r_list->push_back(E.key);
|
2018-06-19 01:10:48 +00: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 16:38:18 +00:00
|
|
|
Ref<AnimationNode> AnimationNodeBlendTree::get_child_by_name(const StringName &p_name) {
|
|
|
|
return get_node(p_name);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) {
|
|
|
|
String name = p_name;
|
|
|
|
if (name.begins_with("nodes/")) {
|
|
|
|
String node_name = name.get_slicec('/', 1);
|
|
|
|
String what = name.get_slicec('/', 2);
|
|
|
|
|
|
|
|
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 16:38:18 +00:00
|
|
|
nodes[node_name].position = p_value;
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else if (name == "node_connections") {
|
|
|
|
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 {
|
|
|
|
String name = p_name;
|
|
|
|
if (name.begins_with("nodes/")) {
|
|
|
|
String node_name = name.get_slicec('/', 1);
|
|
|
|
String what = name.get_slicec('/', 2);
|
|
|
|
|
|
|
|
if (what == "node") {
|
|
|
|
if (nodes.has(node_name)) {
|
2018-08-20 16:38:18 +00:00
|
|
|
r_ret = nodes[node_name].node;
|
2018-06-19 01:10:48 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (what == "position") {
|
|
|
|
if (nodes.has(node_name)) {
|
2018-08-20 16:38:18 +00:00
|
|
|
r_ret = nodes[node_name].position;
|
2018-06-19 01:10:48 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (name == "node_connections") {
|
|
|
|
List<NodeConnection> nc;
|
|
|
|
get_node_connections(&nc);
|
|
|
|
Array conns;
|
|
|
|
conns.resize(nc.size() * 3);
|
|
|
|
|
|
|
|
int idx = 0;
|
2021-07-24 13:46:25 +00:00
|
|
|
for (const NodeConnection &E : nc) {
|
2021-07-16 03:45:57 +00: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 01:10:48 +00:00
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
r_ret = conns;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const {
|
|
|
|
List<StringName> names;
|
2021-08-09 20:13:42 +00:00
|
|
|
for (const KeyValue<StringName, Node> &E : nodes) {
|
|
|
|
names.push_back(E.key);
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
names.sort_custom<StringName::AlphCompare>();
|
|
|
|
|
2021-07-24 13:46:25 +00:00
|
|
|
for (const StringName &E : names) {
|
2021-07-16 03:45:57 +00:00
|
|
|
String name = E;
|
2018-06-19 01:10:48 +00:00
|
|
|
if (name != "output") {
|
2021-11-03 22:06:17 +00:00
|
|
|
p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NO_EDITOR));
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
2021-11-03 22:06:17 +00:00
|
|
|
p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2021-11-03 22:06:17 +00:00
|
|
|
p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2021-02-11 17:18:45 +00:00
|
|
|
void AnimationNodeBlendTree::reset_state() {
|
|
|
|
graph_offset = Vector2();
|
|
|
|
nodes.clear();
|
2021-08-26 16:07:13 +00:00
|
|
|
_initialize_node_tree();
|
2021-02-11 17:18:45 +00:00
|
|
|
emit_changed();
|
2021-07-17 21:22:52 +00:00
|
|
|
emit_signal(SNAME("tree_changed"));
|
2021-02-11 17:18:45 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 16:38:18 +00:00
|
|
|
void AnimationNodeBlendTree::_tree_changed() {
|
2021-07-17 21:22:52 +00:00
|
|
|
emit_signal(SNAME("tree_changed"));
|
2018-08-20 16:38:18 +00: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());
|
|
|
|
}
|
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
void AnimationNodeBlendTree::_bind_methods() {
|
2018-08-20 16:38:18 +00:00
|
|
|
ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeBlendTree::add_node, DEFVAL(Vector2()));
|
2018-06-19 01:10:48 +00: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 16:38:18 +00: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 01:10:48 +00: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 22:06:17 +00:00
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset");
|
2018-06-19 01:10:48 +00: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);
|
|
|
|
}
|
|
|
|
|
2021-08-26 16:07:13 +00:00
|
|
|
void AnimationNodeBlendTree::_initialize_node_tree() {
|
2018-06-19 01:10:48 +00:00
|
|
|
Ref<AnimationNodeOutput> output;
|
2021-06-17 22:03:09 +00:00
|
|
|
output.instantiate();
|
2018-08-20 16:38:18 +00:00
|
|
|
Node n;
|
|
|
|
n.node = output;
|
|
|
|
n.position = Vector2(300, 150);
|
|
|
|
n.connections.resize(1);
|
|
|
|
nodes["output"] = n;
|
2018-06-19 01:10:48 +00:00
|
|
|
}
|
|
|
|
|
2021-08-26 16:07:13 +00:00
|
|
|
AnimationNodeBlendTree::AnimationNodeBlendTree() {
|
|
|
|
_initialize_node_tree();
|
|
|
|
}
|
|
|
|
|
2018-06-19 01:10:48 +00:00
|
|
|
AnimationNodeBlendTree::~AnimationNodeBlendTree() {
|
|
|
|
}
|