2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* animation_blend_tree.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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-08-29 22:38:13 +02:00
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
}
}
}
2023-02-18 03:02:28 +01:00
double AnimationNodeAnimation : : _process ( double p_time , bool p_seek , bool p_is_external_seeking , bool p_test_only ) {
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 ;
2022-11-29 10:51:45 +01:00
Animation : : LoopedFlag looped_flag = Animation : : LOOPED_FLAG_NONE ;
bool node_backward = play_mode = = PLAY_MODE_BACKWARD ;
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-11-29 10:51:45 +01:00
cur_time = cur_time + p_time ;
step = p_time ;
2018-06-19 03:10:48 +02:00
}
2023-02-18 03:02:28 +01:00
bool is_looping = false ;
2022-05-04 20:53:48 +02:00
if ( anim - > get_loop_mode ( ) = = Animation : : LOOP_PINGPONG ) {
if ( ! Math : : is_zero_approx ( anim_size ) ) {
2022-11-29 10:51:45 +01:00
if ( prev_time > = 0 & & cur_time < 0 ) {
backward = ! backward ;
looped_flag = node_backward ? Animation : : LOOPED_FLAG_END : Animation : : LOOPED_FLAG_START ;
}
if ( prev_time < = anim_size & & cur_time > anim_size ) {
backward = ! backward ;
looped_flag = node_backward ? Animation : : LOOPED_FLAG_START : Animation : : LOOPED_FLAG_END ;
2021-10-15 15:25:00 +02:00
}
2022-09-29 11:53:28 +02:00
cur_time = Math : : pingpong ( cur_time , anim_size ) ;
2018-06-19 03:10:48 +02:00
}
2023-02-18 03:02:28 +01:00
is_looping = true ;
2022-11-21 20:30:55 +01:00
} else if ( anim - > get_loop_mode ( ) = = Animation : : LOOP_LINEAR ) {
if ( ! Math : : is_zero_approx ( anim_size ) ) {
2022-11-29 10:51:45 +01:00
if ( prev_time > = 0 & & cur_time < 0 ) {
looped_flag = node_backward ? Animation : : LOOPED_FLAG_END : Animation : : LOOPED_FLAG_START ;
}
if ( prev_time < = anim_size & & cur_time > anim_size ) {
looped_flag = node_backward ? Animation : : LOOPED_FLAG_START : Animation : : LOOPED_FLAG_END ;
}
2022-11-21 20:30:55 +01:00
cur_time = Math : : fposmod ( cur_time , anim_size ) ;
}
backward = false ;
2023-02-18 03:02:28 +01:00
is_looping = true ;
2021-10-15 15:25:00 +02:00
} else {
2022-11-21 20:30:55 +01:00
if ( cur_time < 0 ) {
2022-09-29 11:53:28 +02:00
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 ;
2022-11-21 20:30:55 +01:00
// If ended, don't progress animation. So set delta to 0.
if ( p_time > 0 ) {
if ( play_mode = = PLAY_MODE_FORWARD ) {
if ( prev_time > = anim_size ) {
step = 0 ;
}
} else {
if ( prev_time < = 0 ) {
step = 0 ;
}
}
}
2022-12-19 01:10:15 +01:00
// Emit start & finish signal. Internally, the detections are the same for backward.
// We should use call_deferred since the track keys are still being prosessed.
if ( state - > tree ) {
// AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection.
if ( p_seek & & ! p_is_external_seeking & & cur_time = = 0 ) {
state - > tree - > call_deferred ( SNAME ( " emit_signal " ) , " animation_started " , animation ) ;
}
// Finished.
if ( prev_time < anim_size & & cur_time > = anim_size ) {
state - > tree - > call_deferred ( SNAME ( " emit_signal " ) , " animation_finished " , animation ) ;
}
}
2021-04-24 22:47:03 +02:00
}
2021-10-12 00:27:50 +02:00
2023-02-18 03:02:28 +01:00
if ( ! p_test_only ) {
if ( play_mode = = PLAY_MODE_FORWARD ) {
blend_animation ( animation , cur_time , step , p_seek , p_is_external_seeking , 1.0 , looped_flag ) ;
} else {
blend_animation ( animation , anim_size - cur_time , - step , p_seek , p_is_external_seeking , 1.0 , looped_flag ) ;
}
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
2023-02-18 03:02:28 +01:00
return is_looping ? HUGE_LENGTH : 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 {
2023-01-12 13:51:03 +01:00
r_list - > push_back ( PropertyInfo ( Variant : : BOOL , active , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY ) ) ;
r_list - > push_back ( PropertyInfo ( Variant : : INT , request , PROPERTY_HINT_ENUM , " ,Fire,Abort " ) ) ;
2021-07-01 03:24:34 +02:00
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 {
2023-01-12 13:51:03 +01:00
if ( p_parameter = = request ) {
return ONE_SHOT_REQUEST_NONE ;
} else if ( p_parameter = = active ) {
2018-08-20 18:38:18 +02:00
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 ;
}
}
2023-01-12 13:51:03 +01:00
bool AnimationNodeOneShot : : is_parameter_read_only ( const StringName & p_parameter ) const {
if ( p_parameter = = active ) {
return true ;
}
return false ;
}
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 ;
}
2023-02-18 03:02:28 +01:00
double AnimationNodeOneShot : : _process ( double p_time , bool p_seek , bool p_is_external_seeking , bool p_test_only ) {
2023-01-12 13:51:03 +01:00
OneShotRequest cur_request = static_cast < OneShotRequest > ( ( int ) get_parameter ( request ) ) ;
2022-09-29 11:53:28 +02:00
bool cur_active = get_parameter ( 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
2023-01-12 13:51:03 +01:00
set_parameter ( request , ONE_SHOT_REQUEST_NONE ) ;
bool do_start = cur_request = = ONE_SHOT_REQUEST_FIRE ;
if ( cur_request = = ONE_SHOT_REQUEST_ABORT ) {
set_parameter ( active , false ) ;
set_parameter ( time_to_restart , - 1 ) ;
2023-02-18 03:02:28 +01:00
return blend_input ( 0 , p_time , p_seek , p_is_external_seeking , 1.0 , FILTER_IGNORE , sync , p_test_only ) ;
2023-01-12 13:51:03 +01:00
} else if ( ! do_start & & ! cur_active ) {
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 ) {
2023-01-12 13:51:03 +01:00
do_start = true ; // Restart.
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
}
2023-01-12 13:51:03 +01:00
if ( ! do_start ) {
2023-02-18 03:02:28 +01:00
return blend_input ( 0 , p_time , p_seek , p_is_external_seeking , 1.0 , FILTER_IGNORE , sync , p_test_only ) ;
2023-01-12 13:51:03 +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
}
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 ;
2023-01-12 13:51:03 +01:00
set_parameter ( request , ONE_SHOT_REQUEST_NONE ) ;
set_parameter ( active , true ) ;
2018-06-19 03:10:48 +02:00
}
2023-02-13 00:12:34 +01:00
real_t blend = 1.0 ;
bool use_blend = sync ;
2022-09-29 11:53:28 +02:00
if ( cur_time < fade_in ) {
2023-02-13 00:12:34 +01:00
if ( fade_in > 0 ) {
use_blend = true ;
2022-09-29 11:53:28 +02:00
blend = cur_time / fade_in ;
2020-05-14 16:41:43 +02:00
} else {
2023-02-10 04:51:22 +01:00
blend = 0 ; // Should not happen.
2020-05-14 16:41:43 +02:00
}
2022-09-29 11:53:28 +02:00
} else if ( ! do_start & & cur_remaining < = fade_out ) {
2023-02-11 20:28:46 +01:00
use_blend = true ;
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
}
}
2018-06-19 03:10:48 +02:00
2023-02-10 04:51:22 +01:00
double main_rem = 0.0 ;
2018-06-19 03:10:48 +02:00
if ( mix = = MIX_MODE_ADD ) {
2023-02-18 03:02:28 +01:00
main_rem = blend_input ( 0 , p_time , p_seek , p_is_external_seeking , 1.0 , FILTER_IGNORE , sync , p_test_only ) ;
2023-02-13 00:12:34 +01:00
} else {
2023-02-18 03:02:28 +01:00
main_rem = blend_input ( 0 , p_time , use_blend & & p_seek , p_is_external_seeking , 1.0 - blend , FILTER_BLEND , sync , p_test_only ) ; // Unlike below, processing this edge is a corner case.
2018-06-19 03:10:48 +02:00
}
2023-02-18 03:02:28 +01:00
double os_rem = blend_input ( 1 , os_seek ? cur_time : p_time , os_seek , p_is_external_seeking , Math : : is_zero_approx ( blend ) ? CMP_EPSILON : blend , FILTER_PASS , true , p_test_only ) ; // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
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 ) ;
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
2023-01-12 13:51:03 +01:00
BIND_ENUM_CONSTANT ( ONE_SHOT_REQUEST_NONE ) ;
BIND_ENUM_CONSTANT ( ONE_SHOT_REQUEST_FIRE ) ;
BIND_ENUM_CONSTANT ( ONE_SHOT_REQUEST_ABORT ) ;
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 ;
}
2023-02-18 03:02:28 +01:00
double AnimationNodeAdd2 : : _process ( double p_time , bool p_seek , bool p_is_external_seeking , bool p_test_only ) {
2021-05-21 08:42:37 +02:00
double amount = get_parameter ( add_amount ) ;
2023-02-18 03:02:28 +01:00
double rem0 = blend_input ( 0 , p_time , p_seek , p_is_external_seeking , 1.0 , FILTER_IGNORE , sync , p_test_only ) ;
blend_input ( 1 , p_time , p_seek , p_is_external_seeking , amount , FILTER_PASS , sync , p_test_only ) ;
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 ;
}
2023-02-18 03:02:28 +01:00
double AnimationNodeAdd3 : : _process ( double p_time , bool p_seek , bool p_is_external_seeking , bool p_test_only ) {
2021-05-21 08:42:37 +02:00
double amount = get_parameter ( add_amount ) ;
2023-02-18 03:02:28 +01:00
blend_input ( 0 , p_time , p_seek , p_is_external_seeking , MAX ( 0 , - amount ) , FILTER_PASS , sync , p_test_only ) ;
double rem0 = blend_input ( 1 , p_time , p_seek , p_is_external_seeking , 1.0 , FILTER_IGNORE , sync , p_test_only ) ;
blend_input ( 2 , p_time , p_seek , p_is_external_seeking , MAX ( 0 , amount ) , FILTER_PASS , sync , p_test_only ) ;
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 {
2023-02-01 12:49:31 +01:00
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 " ;
}
2023-02-18 03:02:28 +01:00
double AnimationNodeBlend2 : : _process ( double p_time , bool p_seek , bool p_is_external_seeking , bool p_test_only ) {
2021-05-21 08:42:37 +02:00
double amount = get_parameter ( blend_amount ) ;
2018-08-20 18:38:18 +02:00
2023-02-18 03:02:28 +01:00
double rem0 = blend_input ( 0 , p_time , p_seek , p_is_external_seeking , 1.0 - amount , FILTER_BLEND , sync , p_test_only ) ;
double rem1 = blend_input ( 1 , p_time , p_seek , p_is_external_seeking , amount , FILTER_PASS , sync , p_test_only ) ;
2018-06-19 03:10:48 +02:00
2023-02-01 12:49:31 +01:00
return amount > 0.5 ? rem1 : rem0 ; // Hacky but good enough.
2018-06-19 03:10:48 +02:00
}
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 {
2023-02-01 12:49:31 +01:00
return 0 ; // For blend amount.
2018-06-19 03:10:48 +02:00
}
String AnimationNodeBlend3 : : get_caption ( ) const {
return " Blend3 " ;
}
2023-02-18 03:02:28 +01:00
double AnimationNodeBlend3 : : _process ( double p_time , bool p_seek , bool p_is_external_seeking , bool p_test_only ) {
2021-05-21 08:42:37 +02:00
double amount = get_parameter ( blend_amount ) ;
2023-02-18 03:02:28 +01:00
double rem0 = blend_input ( 0 , p_time , p_seek , p_is_external_seeking , MAX ( 0 , - amount ) , FILTER_IGNORE , sync , p_test_only ) ;
double rem1 = blend_input ( 1 , p_time , p_seek , p_is_external_seeking , 1.0 - ABS ( amount ) , FILTER_IGNORE , sync , p_test_only ) ;
double rem2 = blend_input ( 2 , p_time , p_seek , p_is_external_seeking , MAX ( 0 , amount ) , FILTER_IGNORE , sync , p_test_only ) ;
2018-06-19 03:10:48 +02:00
2023-02-01 12:49:31 +01:00
return amount > 0.5 ? rem2 : ( amount < - 0.5 ? rem0 : rem1 ) ; // Hacky but good enough.
2018-06-19 03:10:48 +02:00
}
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 {
2023-02-01 12:49:31 +01:00
return 1.0 ; // Initial timescale.
2018-06-19 03:10:48 +02:00
}
String AnimationNodeTimeScale : : get_caption ( ) const {
return " TimeScale " ;
}
2023-02-18 03:02:28 +01:00
double AnimationNodeTimeScale : : _process ( double p_time , bool p_seek , bool p_is_external_seeking , bool p_test_only ) {
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 ) {
2023-02-18 03:02:28 +01:00
return blend_input ( 0 , p_time , true , p_is_external_seeking , 1.0 , FILTER_IGNORE , true , p_test_only ) ;
2018-06-19 03:10:48 +02:00
} else {
2023-02-18 03:02:28 +01:00
return blend_input ( 0 , p_time * cur_scale , false , p_is_external_seeking , 1.0 , FILTER_IGNORE , true , p_test_only ) ;
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 {
2023-02-01 12:49:31 +01:00
r_list - > push_back ( PropertyInfo ( Variant : : FLOAT , seek_pos_request , PROPERTY_HINT_RANGE , " -1,3600,0.01,or_greater " ) ) ; // It will be reset to -1 after seeking the position immediately.
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 {
2023-02-01 12:49:31 +01:00
return - 1.0 ; // Initial seek request.
2018-06-19 03:10:48 +02:00
}
String AnimationNodeTimeSeek : : get_caption ( ) const {
2023-02-01 12:49:31 +01:00
return " TimeSeek " ;
2018-06-19 03:10:48 +02:00
}
2023-02-18 03:02:28 +01:00
double AnimationNodeTimeSeek : : _process ( double p_time , bool p_seek , bool p_is_external_seeking , bool p_test_only ) {
2023-02-01 12:49:31 +01:00
double cur_seek_pos = get_parameter ( seek_pos_request ) ;
2018-06-19 03:10:48 +02:00
if ( p_seek ) {
2023-02-18 03:02:28 +01:00
return blend_input ( 0 , p_time , true , p_is_external_seeking , 1.0 , FILTER_IGNORE , true , p_test_only ) ;
2022-09-29 11:53:28 +02:00
} else if ( cur_seek_pos > = 0 ) {
2023-02-18 03:02:28 +01:00
double ret = blend_input ( 0 , cur_seek_pos , true , true , 1.0 , FILTER_IGNORE , true , p_test_only ) ;
2023-02-01 12:49:31 +01:00
set_parameter ( seek_pos_request , - 1.0 ) ; // Reset.
2018-06-19 03:10:48 +02:00
return ret ;
} else {
2023-02-18 03:02:28 +01:00
return blend_input ( 0 , p_time , false , p_is_external_seeking , 1.0 , FILTER_IGNORE , true , p_test_only ) ;
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 " ) ;
}
/////////////////////////////////////////////////
2023-01-29 15:54:13 +01:00
bool AnimationNodeTransition : : _set ( const StringName & p_path , const Variant & p_value ) {
String path = p_path ;
if ( ! path . begins_with ( " input_ " ) ) {
return false ;
}
int which = path . get_slicec ( ' / ' , 0 ) . get_slicec ( ' _ ' , 1 ) . to_int ( ) ;
String what = path . get_slicec ( ' / ' , 1 ) ;
if ( which = = get_input_count ( ) & & what = = " name " ) {
if ( add_input ( p_value ) ) {
return true ;
}
return false ;
}
ERR_FAIL_INDEX_V ( which , get_input_count ( ) , false ) ;
if ( what = = " name " ) {
set_input_name ( which , p_value ) ;
} else if ( what = = " auto_advance " ) {
set_input_as_auto_advance ( which , p_value ) ;
2023-01-30 16:40:45 +01:00
} else if ( what = = " reset " ) {
set_input_reset ( which , p_value ) ;
2023-01-29 15:54:13 +01:00
} else {
return false ;
}
return true ;
}
bool AnimationNodeTransition : : _get ( const StringName & p_path , Variant & r_ret ) const {
String path = p_path ;
if ( ! path . begins_with ( " input_ " ) ) {
return false ;
}
int which = path . get_slicec ( ' / ' , 0 ) . get_slicec ( ' _ ' , 1 ) . to_int ( ) ;
String what = path . get_slicec ( ' / ' , 1 ) ;
ERR_FAIL_INDEX_V ( which , get_input_count ( ) , false ) ;
if ( what = = " name " ) {
r_ret = get_input_name ( which ) ;
} else if ( what = = " auto_advance " ) {
r_ret = is_input_set_as_auto_advance ( which ) ;
2023-01-30 16:40:45 +01:00
} else if ( what = = " reset " ) {
r_ret = is_input_reset ( which ) ;
2023-01-29 15:54:13 +01:00
} else {
return false ;
}
return true ;
}
2018-08-20 18:38:18 +02:00
void AnimationNodeTransition : : get_parameter_list ( List < PropertyInfo > * r_list ) const {
String anims ;
2023-01-29 15:54:13 +01:00
for ( int i = 0 ; i < get_input_count ( ) ; i + + ) {
2018-08-20 18:38:18 +02:00
if ( i > 0 ) {
anims + = " , " ;
}
anims + = inputs [ i ] . name ;
}
2023-01-12 13:51:03 +01:00
r_list - > push_back ( PropertyInfo ( Variant : : STRING , current_state , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY ) ) ; // For interface.
r_list - > push_back ( PropertyInfo ( Variant : : STRING , transition_request , PROPERTY_HINT_ENUM , anims ) ) ; // For transition request. It will be cleared after setting the value immediately.
r_list - > push_back ( PropertyInfo ( Variant : : INT , current_index , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY ) ) ; // To avoid finding the index every frame, use this internally.
r_list - > push_back ( PropertyInfo ( Variant : : INT , prev_index , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) ) ;
2021-07-01 03:24:34 +02:00
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 ;
2023-02-04 16:29:34 +01:00
} else if ( p_parameter = = prev_index | | p_parameter = = current_index ) {
2018-08-20 18:38:18 +02:00
return - 1 ;
} else {
2023-02-04 16:29:34 +01:00
return String ( ) ;
2018-08-20 18:38:18 +02:00
}
}
2023-01-12 13:51:03 +01:00
bool AnimationNodeTransition : : is_parameter_read_only ( const StringName & p_parameter ) const {
if ( p_parameter = = current_state | | p_parameter = = current_index ) {
return true ;
}
return false ;
}
2018-06-19 03:10:48 +02:00
String AnimationNodeTransition : : get_caption ( ) const {
return " Transition " ;
}
2023-01-29 15:54:13 +01:00
void AnimationNodeTransition : : set_input_count ( int p_inputs ) {
for ( int i = get_input_count ( ) ; i < p_inputs ; i + + ) {
add_input ( " state_ " + itos ( i ) ) ;
2018-06-19 03:10:48 +02:00
}
2023-01-29 15:54:13 +01:00
while ( get_input_count ( ) > p_inputs ) {
2018-06-19 03:10:48 +02:00
remove_input ( get_input_count ( ) - 1 ) ;
}
2023-02-04 16:29:34 +01:00
pending_update = true ;
emit_signal ( SNAME ( " tree_changed " ) ) ; // For updating connect activity map.
2023-01-29 15:54:13 +01:00
notify_property_list_changed ( ) ;
2018-06-19 03:10:48 +02:00
}
2023-01-29 15:54:13 +01:00
bool AnimationNodeTransition : : add_input ( const String & p_name ) {
if ( AnimationNode : : add_input ( p_name ) ) {
2023-01-30 16:40:45 +01:00
input_data . push_back ( InputData ( ) ) ;
2023-01-29 15:54:13 +01:00
return true ;
}
return false ;
2018-06-19 03:10:48 +02:00
}
2023-01-29 15:54:13 +01:00
void AnimationNodeTransition : : remove_input ( int p_index ) {
2023-01-30 16:40:45 +01:00
input_data . remove_at ( p_index ) ;
2023-01-29 15:54:13 +01:00
AnimationNode : : remove_input ( p_index ) ;
2018-06-19 03:10:48 +02:00
}
2023-02-04 16:29:34 +01:00
bool AnimationNodeTransition : : set_input_name ( int p_input , const String & p_name ) {
pending_update = true ;
return AnimationNode : : set_input_name ( p_input , p_name ) ;
}
2018-06-19 03:10:48 +02:00
void AnimationNodeTransition : : set_input_as_auto_advance ( int p_input , bool p_enable ) {
2023-01-29 15:54:13 +01:00
ERR_FAIL_INDEX ( p_input , get_input_count ( ) ) ;
2023-01-30 16:40:45 +01:00
input_data . write [ p_input ] . auto_advance = p_enable ;
2018-06-19 03:10:48 +02:00
}
bool AnimationNodeTransition : : is_input_set_as_auto_advance ( int p_input ) const {
2023-01-29 15:54:13 +01:00
ERR_FAIL_INDEX_V ( p_input , get_input_count ( ) , false ) ;
2023-01-30 16:40:45 +01:00
return input_data [ p_input ] . auto_advance ;
}
void AnimationNodeTransition : : set_input_reset ( int p_input , bool p_enable ) {
ERR_FAIL_INDEX ( p_input , get_input_count ( ) ) ;
input_data . write [ p_input ] . reset = p_enable ;
}
bool AnimationNodeTransition : : is_input_reset ( int p_input ) const {
ERR_FAIL_INDEX_V ( p_input , get_input_count ( ) , true ) ;
return input_data [ p_input ] . reset ;
2023-01-12 13:51:03 +01:00
}
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
}
2023-01-31 13:17:29 +01:00
void AnimationNodeTransition : : set_allow_transition_to_self ( bool p_enable ) {
allow_transition_to_self = p_enable ;
}
bool AnimationNodeTransition : : is_allow_transition_to_self ( ) const {
return allow_transition_to_self ;
}
2023-02-18 03:02:28 +01:00
double AnimationNodeTransition : : _process ( double p_time , bool p_seek , bool p_is_external_seeking , bool p_test_only ) {
2023-01-12 13:51:03 +01:00
String cur_transition_request = get_parameter ( transition_request ) ;
int cur_current_index = get_parameter ( current_index ) ;
int cur_prev_index = get_parameter ( prev_index ) ;
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
2023-01-12 13:51:03 +01:00
bool switched = false ;
bool restart = false ;
2023-02-11 20:12:15 +01:00
bool clear_remaining_fade = false ;
2023-01-12 13:51:03 +01:00
2023-02-04 16:29:34 +01:00
if ( pending_update ) {
if ( cur_current_index < 0 | | cur_current_index > = get_input_count ( ) ) {
set_parameter ( prev_index , - 1 ) ;
if ( get_input_count ( ) > 0 ) {
set_parameter ( current_index , 0 ) ;
set_parameter ( current_state , get_input_name ( 0 ) ) ;
} else {
set_parameter ( current_index , - 1 ) ;
set_parameter ( current_state , StringName ( ) ) ;
}
} else {
set_parameter ( current_state , get_input_name ( cur_current_index ) ) ;
}
pending_update = false ;
}
2023-02-11 20:12:15 +01:00
if ( p_time = = 0 & & p_seek & & ! p_is_external_seeking ) {
clear_remaining_fade = true ; // Reset occurs.
}
2023-01-12 13:51:03 +01:00
if ( ! cur_transition_request . is_empty ( ) ) {
2023-01-29 15:54:13 +01:00
int new_idx = find_input ( cur_transition_request ) ;
2023-01-12 13:51:03 +01:00
if ( new_idx > = 0 ) {
if ( cur_current_index = = new_idx ) {
2023-01-31 13:17:29 +01:00
if ( allow_transition_to_self ) {
// Transition to same state.
restart = input_data [ cur_current_index ] . reset ;
2023-02-11 20:12:15 +01:00
clear_remaining_fade = true ;
2023-01-31 13:17:29 +01:00
}
2023-01-12 13:51:03 +01:00
} else {
switched = true ;
cur_prev_index = cur_current_index ;
set_parameter ( prev_index , cur_current_index ) ;
2023-01-31 13:17:29 +01:00
cur_current_index = new_idx ;
set_parameter ( current_index , cur_current_index ) ;
set_parameter ( current_state , cur_transition_request ) ;
2023-01-12 13:51:03 +01:00
}
} else {
ERR_PRINT ( " No such input: ' " + cur_transition_request + " ' " ) ;
}
cur_transition_request = String ( ) ;
set_parameter ( transition_request , cur_transition_request ) ;
}
2018-08-20 18:38:18 +02:00
2023-02-11 20:12:15 +01:00
if ( clear_remaining_fade ) {
cur_prev_xfading = 0 ;
set_parameter ( prev_xfading , 0 ) ;
cur_prev_index = - 1 ;
set_parameter ( prev_index , - 1 ) ;
}
2023-01-12 13:51:03 +01:00
// Special case for restart.
if ( restart ) {
set_parameter ( time , 0 ) ;
2023-02-18 03:02:28 +01:00
return blend_input ( cur_current_index , 0 , true , p_is_external_seeking , 1.0 , FILTER_IGNORE , true , p_test_only ) ;
2023-01-12 13:51:03 +01:00
}
2018-08-20 18:38:18 +02:00
2023-01-12 13:51:03 +01:00
if ( switched ) {
2022-09-29 11:53:28 +02:00
cur_prev_xfading = xfade_time ;
cur_time = 0 ;
2018-08-20 18:38:18 +02:00
}
2023-01-29 15:54:13 +01:00
if ( cur_current_index < 0 | | cur_current_index > = get_input_count ( ) | | cur_prev_index > = get_input_count ( ) ) {
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-11-15 07:06:10 +01:00
if ( sync ) {
2023-01-29 15:54:13 +01:00
for ( int i = 0 ; i < get_input_count ( ) ; i + + ) {
2023-01-12 13:51:03 +01:00
if ( i ! = cur_current_index & & i ! = cur_prev_index ) {
2023-02-18 03:02:28 +01:00
blend_input ( i , p_time , p_seek , p_is_external_seeking , 0 , FILTER_IGNORE , true , p_test_only ) ;
2022-11-15 07:06:10 +01:00
}
2022-06-29 08:35:29 +02:00
}
}
2023-02-01 12:49:31 +01:00
if ( cur_prev_index < 0 ) { // Process current animation, check for transition.
2018-06-19 03:10:48 +02:00
2023-02-18 03:02:28 +01:00
rem = blend_input ( cur_current_index , p_time , p_seek , p_is_external_seeking , 1.0 , FILTER_IGNORE , true , p_test_only ) ;
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
2023-01-30 16:40:45 +01:00
if ( input_data [ cur_current_index ] . auto_advance & & rem < = xfade_time ) {
2023-01-29 15:54:13 +01:00
set_parameter ( transition_request , get_input_name ( ( cur_current_index + 1 ) % get_input_count ( ) ) ) ;
2018-06-19 03:10:48 +02:00
}
2023-02-01 12:49:31 +01:00
} else { // Cross-fading from prev to current.
2018-06-19 03:10:48 +02:00
2023-02-13 00:12:34 +01:00
real_t blend = 0.0 ;
real_t blend_inv = 1.0 ;
bool use_blend = sync ;
if ( xfade_time > 0 ) {
use_blend = true ;
blend = cur_prev_xfading / xfade_time ;
if ( xfade_curve . is_valid ( ) ) {
blend = xfade_curve - > sample ( blend ) ;
}
blend_inv = 1.0 - blend ;
blend = Math : : is_zero_approx ( blend ) ? CMP_EPSILON : blend ;
blend_inv = Math : : is_zero_approx ( blend_inv ) ? CMP_EPSILON : blend_inv ;
2022-07-28 10:31:23 +02:00
}
2018-06-19 03:10:48 +02:00
2022-11-29 10:51:45 +01:00
// Blend values must be more than CMP_EPSILON to process discrete keys in edge.
2023-02-01 12:49:31 +01:00
if ( input_data [ cur_current_index ] . reset & & ! p_seek & & switched ) { // Just switched, seek to start of current.
2023-02-18 03:02:28 +01:00
rem = blend_input ( cur_current_index , 0 , true , p_is_external_seeking , blend_inv , FILTER_IGNORE , true , p_test_only ) ;
2018-06-19 03:10:48 +02:00
} else {
2023-02-18 03:02:28 +01:00
rem = blend_input ( cur_current_index , p_time , p_seek , p_is_external_seeking , blend_inv , FILTER_IGNORE , true , p_test_only ) ;
2018-06-19 03:10:48 +02:00
}
2023-02-18 03:02:28 +01:00
blend_input ( cur_prev_index , p_time , use_blend & & p_seek , p_is_external_seeking , blend , FILTER_IGNORE , true , p_test_only ) ;
2022-06-29 08:35:29 +02:00
if ( p_seek ) {
2022-09-29 11:53:28 +02:00
cur_time = p_time ;
2018-06-19 03:10:48 +02:00
} else {
2022-09-29 11:53:28 +02:00
cur_time + = p_time ;
cur_prev_xfading - = p_time ;
if ( cur_prev_xfading < 0 ) {
2023-01-12 13:51:03 +01:00
set_parameter ( prev_index , - 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
}
2023-01-29 15:54:13 +01:00
void AnimationNodeTransition : : _get_property_list ( List < PropertyInfo > * p_list ) const {
for ( int i = 0 ; i < get_input_count ( ) ; i + + ) {
p_list - > push_back ( PropertyInfo ( Variant : : STRING , " input_ " + itos ( i ) + " /name " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL ) ) ;
p_list - > push_back ( PropertyInfo ( Variant : : BOOL , " input_ " + itos ( i ) + " /auto_advance " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL ) ) ;
2023-01-30 16:40:45 +01:00
p_list - > push_back ( PropertyInfo ( Variant : : BOOL , " input_ " + itos ( i ) + " /reset " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL ) ) ;
2018-06-19 03:10:48 +02:00
}
}
void AnimationNodeTransition : : _bind_methods ( ) {
2023-01-29 15:54:13 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_input_count " , " input_count " ) , & AnimationNodeTransition : : set_input_count ) ;
2018-06-19 03:10:48 +02:00
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 ) ;
2023-01-30 16:40:45 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_input_reset " , " input " , " enable " ) , & AnimationNodeTransition : : set_input_reset ) ;
ClassDB : : bind_method ( D_METHOD ( " is_input_reset " , " input " ) , & AnimationNodeTransition : : is_input_reset ) ;
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
2023-01-31 13:17:29 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_allow_transition_to_self " , " enable " ) , & AnimationNodeTransition : : set_allow_transition_to_self ) ;
ClassDB : : bind_method ( D_METHOD ( " is_allow_transition_to_self " ) , & AnimationNodeTransition : : is_allow_transition_to_self ) ;
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 " ) ;
2023-01-31 13:17:29 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " allow_transition_to_self " ) , " set_allow_transition_to_self " , " is_allow_transition_to_self " ) ;
2023-01-29 15:54:13 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " input_count " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED , " Inputs,input_ " ) , " set_input_count " , " get_input_count " ) ;
2018-06-19 03:10:48 +02:00
}
AnimationNodeTransition : : AnimationNodeTransition ( ) {
}
/////////////////////
String AnimationNodeOutput : : get_caption ( ) const {
return " Output " ;
}
2023-02-18 03:02:28 +01:00
double AnimationNodeOutput : : _process ( double p_time , bool p_seek , bool p_is_external_seeking , bool p_test_only ) {
return blend_input ( 0 , p_time , p_seek , p_is_external_seeking , 1.0 , FILTER_IGNORE , true , p_test_only ) ;
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 ) ;
2023-02-04 16:29:34 +01:00
p_node - > connect ( " animation_node_renamed " , callable_mp ( this , & AnimationNodeBlendTree : : _animation_node_renamed ) , CONNECT_REFERENCE_COUNTED ) ;
p_node - > connect ( " animation_node_removed " , callable_mp ( this , & AnimationNodeBlendTree : : _animation_node_removed ) , CONNECT_REFERENCE_COUNTED ) ;
2022-07-28 22:56:41 +02:00
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 ) ) ;
2023-02-04 16:29:34 +01:00
node - > disconnect ( " animation_node_renamed " , callable_mp ( this , & AnimationNodeBlendTree : : _animation_node_renamed ) ) ;
node - > disconnect ( " animation_node_removed " , callable_mp ( this , & AnimationNodeBlendTree : : _animation_node_removed ) ) ;
2020-02-21 18:28:45 +01:00
node - > disconnect ( " changed " , callable_mp ( this , & AnimationNodeBlendTree : : _node_changed ) ) ;
2018-06-19 03:10:48 +02:00
}
nodes . erase ( p_name ) ;
2023-02-01 12:49:31 +01:00
// 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
}
}
}
2023-02-04 16:29:34 +01:00
emit_signal ( SNAME ( " animation_node_removed " ) , get_instance_id ( ) , p_name ) ;
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 ) ;
2023-02-01 12:49:31 +01:00
// 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
}
}
}
2023-02-01 12:49:31 +01: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
2023-02-04 16:29:34 +01:00
emit_signal ( SNAME ( " animation_node_renamed " ) , get_instance_id ( ) , p_name , p_new_name ) ;
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 " ;
}
2023-02-18 03:02:28 +01:00
double AnimationNodeBlendTree : : _process ( double p_time , bool p_seek , bool p_is_external_seeking , bool p_test_only ) {
2018-08-20 18:38:18 +02:00
Ref < AnimationNodeOutput > output = nodes [ SceneStringNames : : get_singleton ( ) - > output ] . node ;
2023-02-18 03:02:28 +01:00
return _blend_node ( " output " , nodes [ SceneStringNames : : get_singleton ( ) - > output ] . connections , this , output , p_time , p_seek , p_is_external_seeking , 1.0 , FILTER_IGNORE , true , nullptr , p_test_only ) ;
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 ;
}
2023-02-18 03:02:28 +01:00
Ref < AnimationNode > AnimationNodeBlendTree : : get_child_by_name ( const StringName & p_name ) const {
2018-08-20 18:38:18 +02:00
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
}
2023-02-04 16:29:34 +01:00
void AnimationNodeBlendTree : : _tree_changed ( ) {
AnimationRootNode : : _tree_changed ( ) ;
}
void AnimationNodeBlendTree : : _animation_node_renamed ( const ObjectID & p_oid , const String & p_old_name , const String & p_new_name ) {
AnimationRootNode : : _animation_node_renamed ( p_oid , p_old_name , p_new_name ) ;
}
void AnimationNodeBlendTree : : _animation_node_removed ( const ObjectID & p_oid , const StringName & p_node ) {
AnimationRootNode : : _animation_node_removed ( p_oid , p_node ) ;
}
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 : : _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 ( ) {
}