2018-08-29 22:38:13 +02: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-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
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 {
2024-01-07 22:08:10 +01:00
AnimationNode : : get_parameter_list ( r_list ) ;
}
AnimationNode : : NodeTimeInfo AnimationNodeAnimation : : get_node_time_info ( ) const {
NodeTimeInfo nti ;
if ( ! process_state - > tree - > has_animation ( animation ) ) {
return nti ;
}
if ( use_custom_timeline ) {
nti . length = timeline_length ;
nti . loop_mode = loop_mode ;
} else {
Ref < Animation > anim = process_state - > tree - > get_animation ( animation ) ;
nti . length = ( double ) anim - > get_length ( ) ;
nti . loop_mode = anim - > get_loop_mode ( ) ;
}
nti . position = get_parameter ( current_position ) ;
return nti ;
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
}
}
2024-01-07 22:08:10 +01:00
if ( ! use_custom_timeline ) {
if ( p_property . name = = " timeline_length " | | p_property . name = = " start_offset " | | p_property . name = = " loop_mode " | | p_property . name = = " stretch_time_scale " ) {
p_property . usage = PROPERTY_USAGE_NONE ;
}
}
2018-06-19 03:10:48 +02:00
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeAnimation : : process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
process_state - > is_testing = p_test_only ;
2018-11-08 20:51:45 +01:00
2024-01-07 22:08:10 +01:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
if ( p_playback_info . seeked ) {
pi . delta = get_node_time_info ( ) . position - p_playback_info . time ;
} else {
pi . time = get_node_time_info ( ) . position + ( backward ? - p_playback_info . delta : p_playback_info . delta ) ;
}
NodeTimeInfo nti = _process ( pi , p_test_only ) ;
if ( ! p_test_only ) {
set_node_time_info ( nti ) ;
}
return nti ;
}
AnimationNode : : NodeTimeInfo AnimationNodeAnimation : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
2023-07-20 17:34:06 +02:00
if ( ! process_state - > tree - > has_animation ( animation ) ) {
AnimationNodeBlendTree * tree = Object : : cast_to < AnimationNodeBlendTree > ( node_state . parent ) ;
2018-08-20 18:38:18 +02:00
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 ) ) ;
}
2024-01-07 22:08:10 +01:00
return NodeTimeInfo ( ) ;
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
Ref < Animation > anim = process_state - > tree - > get_animation ( animation ) ;
2021-10-15 15:25:00 +02:00
double anim_size = ( double ) anim - > get_length ( ) ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo cur_nti = get_node_time_info ( ) ;
double cur_len = cur_nti . length ;
double cur_time = p_playback_info . time ;
double cur_delta = p_playback_info . delta ;
Animation : : LoopMode cur_loop_mode = cur_nti . loop_mode ;
double prev_time = cur_nti . position ;
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
2023-07-20 17:34:06 +02:00
bool p_seek = p_playback_info . seeked ;
bool p_is_external_seeking = p_playback_info . is_external_seeking ;
2024-01-07 22:08:10 +01:00
// 1. Progress for AnimationNode.
2024-07-28 07:48:38 +02:00
bool will_end = Animation : : is_greater_or_equal_approx ( cur_time + cur_delta , cur_len ) ;
2024-01-07 22:08:10 +01:00
if ( cur_loop_mode ! = Animation : : LOOP_NONE ) {
if ( cur_loop_mode = = Animation : : LOOP_LINEAR ) {
if ( ! Math : : is_zero_approx ( cur_len ) ) {
cur_time = Math : : fposmod ( cur_time , cur_len ) ;
}
backward = false ;
} else {
if ( ! Math : : is_zero_approx ( cur_len ) ) {
2024-07-23 18:00:42 +02:00
if ( Animation : : is_greater_or_equal_approx ( prev_time , 0 ) & & Animation : : is_less_approx ( cur_time , 0 ) ) {
2024-01-07 22:08:10 +01:00
backward = ! backward ;
2024-07-23 18:00:42 +02:00
} else if ( Animation : : is_less_or_equal_approx ( prev_time , cur_len ) & & Animation : : is_greater_approx ( cur_time , cur_len ) ) {
2024-01-07 22:08:10 +01:00
backward = ! backward ;
}
cur_time = Math : : pingpong ( cur_time , cur_len ) ;
}
}
2018-06-19 03:10:48 +02:00
} else {
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_approx ( cur_time , 0 ) ) {
2024-01-07 22:08:10 +01:00
cur_delta + = cur_time ;
cur_time = 0 ;
2024-07-23 18:00:42 +02:00
} else if ( Animation : : is_greater_approx ( cur_time , cur_len ) ) {
2024-01-07 22:08:10 +01:00
cur_delta + = cur_time - cur_len ;
cur_time = cur_len ;
}
backward = false ;
// If ended, don't progress AnimationNode. So set delta to 0.
if ( ! Math : : is_zero_approx ( cur_delta ) ) {
if ( play_mode = = PLAY_MODE_FORWARD ) {
2024-07-23 18:00:42 +02:00
if ( Animation : : is_greater_or_equal_approx ( prev_time , cur_len ) ) {
2024-01-07 22:08:10 +01:00
cur_delta = 0 ;
}
} else {
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_or_equal_approx ( prev_time , 0 ) ) {
2024-01-07 22:08:10 +01:00
cur_delta = 0 ;
}
}
}
2018-06-19 03:10:48 +02:00
}
2024-01-07 22:08:10 +01:00
// 2. For return, store "AnimationNode" time info here, not "Animation" time info as below.
NodeTimeInfo nti ;
nti . length = cur_len ;
nti . position = cur_time ;
nti . delta = cur_delta ;
nti . loop_mode = cur_loop_mode ;
2024-07-28 07:48:38 +02:00
nti . will_end = will_end ;
2024-01-07 22:08:10 +01:00
// 3. Progress for Animation.
2024-05-11 08:47:21 +02:00
double prev_playback_time = prev_time + start_offset ;
double cur_playback_time = cur_time + start_offset ;
2024-01-07 22:08:10 +01:00
if ( stretch_time_scale ) {
double mlt = anim_size / cur_len ;
2024-07-23 18:00:42 +02:00
prev_playback_time * = mlt ;
2024-01-07 22:08:10 +01:00
cur_playback_time * = mlt ;
cur_delta * = mlt ;
}
if ( cur_loop_mode = = Animation : : LOOP_LINEAR ) {
2022-05-04 20:53:48 +02:00
if ( ! Math : : is_zero_approx ( anim_size ) ) {
2024-01-07 22:08:10 +01:00
prev_playback_time = Math : : fposmod ( prev_playback_time , anim_size ) ;
cur_playback_time = Math : : fposmod ( cur_playback_time , anim_size ) ;
2024-07-23 18:00:42 +02:00
if ( Animation : : is_greater_or_equal_approx ( prev_playback_time , 0 ) & & Animation : : is_less_approx ( cur_playback_time , 0 ) ) {
2022-11-29 10:51:45 +01:00
looped_flag = node_backward ? Animation : : LOOPED_FLAG_END : Animation : : LOOPED_FLAG_START ;
}
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_or_equal_approx ( prev_playback_time , anim_size ) & & Animation : : is_greater_approx ( cur_playback_time , anim_size ) ) {
2022-11-29 10:51:45 +01:00
looped_flag = node_backward ? Animation : : LOOPED_FLAG_START : Animation : : LOOPED_FLAG_END ;
2021-10-15 15:25:00 +02:00
}
2018-06-19 03:10:48 +02:00
}
2024-01-07 22:08:10 +01:00
} else if ( cur_loop_mode = = Animation : : LOOP_PINGPONG ) {
2022-11-21 20:30:55 +01:00
if ( ! Math : : is_zero_approx ( anim_size ) ) {
2024-07-23 18:00:42 +02:00
if ( Animation : : is_greater_or_equal_approx ( Math : : fposmod ( cur_playback_time , anim_size * 2.0 ) , anim_size ) ) {
2024-05-07 10:05:42 +02:00
cur_delta = - cur_delta ; // Needed for retrieving discrete keys correctly.
2024-01-07 22:08:10 +01:00
}
prev_playback_time = Math : : pingpong ( prev_playback_time , anim_size ) ;
cur_playback_time = Math : : pingpong ( cur_playback_time , anim_size ) ;
2024-07-23 18:00:42 +02:00
if ( Animation : : is_greater_or_equal_approx ( prev_playback_time , 0 ) & & Animation : : is_less_approx ( cur_playback_time , 0 ) ) {
2022-11-29 10:51:45 +01:00
looped_flag = node_backward ? Animation : : LOOPED_FLAG_END : Animation : : LOOPED_FLAG_START ;
}
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_or_equal_approx ( prev_playback_time , anim_size ) & & Animation : : is_greater_approx ( cur_playback_time , anim_size ) ) {
2022-11-29 10:51:45 +01:00
looped_flag = node_backward ? Animation : : LOOPED_FLAG_START : Animation : : LOOPED_FLAG_END ;
}
2022-11-21 20:30:55 +01:00
}
2021-10-15 15:25:00 +02:00
} else {
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_approx ( cur_playback_time , 0 ) ) {
2024-01-07 22:08:10 +01:00
cur_playback_time = 0 ;
2024-07-23 18:00:42 +02:00
} else if ( Animation : : is_greater_approx ( cur_playback_time , anim_size ) ) {
2024-01-07 22:08:10 +01:00
cur_playback_time = anim_size ;
2022-11-21 20:30:55 +01:00
}
2022-12-19 01:10:15 +01:00
// Emit start & finish signal. Internally, the detections are the same for backward.
2023-09-18 09:53:39 +02:00
// We should use call_deferred since the track keys are still being processed.
2023-07-20 17:34:06 +02:00
if ( process_state - > tree & & ! p_test_only ) {
2022-12-19 01:10:15 +01:00
// AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection.
2024-07-23 18:00:42 +02:00
if ( p_seek & & ! p_is_external_seeking & & Math : : is_zero_approx ( cur_playback_time ) ) {
2024-05-13 16:56:03 +02:00
process_state - > tree - > call_deferred ( SNAME ( " emit_signal " ) , SceneStringName ( animation_started ) , animation ) ;
2022-12-19 01:10:15 +01:00
}
// Finished.
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_approx ( prev_playback_time , anim_size ) & & Animation : : is_greater_or_equal_approx ( cur_playback_time , anim_size ) ) {
2024-05-13 16:56:03 +02:00
process_state - > tree - > call_deferred ( SNAME ( " emit_signal " ) , SceneStringName ( animation_finished ) , animation ) ;
2022-12-19 01:10:15 +01:00
}
}
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 ) {
2023-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
2023-02-18 03:02:28 +01:00
if ( play_mode = = PLAY_MODE_FORWARD ) {
2024-01-07 22:08:10 +01:00
pi . time = cur_playback_time ;
pi . delta = cur_delta ;
2023-02-18 03:02:28 +01:00
} else {
2024-01-07 22:08:10 +01:00
pi . time = anim_size - cur_playback_time ;
pi . delta = - cur_delta ;
2023-02-18 03:02:28 +01:00
}
2023-07-20 17:34:06 +02:00
pi . weight = 1.0 ;
pi . looped_flag = looped_flag ;
blend_animation ( animation , pi ) ;
2021-10-15 15:25:00 +02:00
}
2018-11-08 20:51:45 +01:00
2024-01-07 22:08:10 +01:00
return nti ;
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 ;
}
2024-01-07 22:08:10 +01:00
void AnimationNodeAnimation : : set_use_custom_timeline ( bool p_use_custom_timeline ) {
use_custom_timeline = p_use_custom_timeline ;
notify_property_list_changed ( ) ;
}
bool AnimationNodeAnimation : : is_using_custom_timeline ( ) const {
return use_custom_timeline ;
}
void AnimationNodeAnimation : : set_timeline_length ( double p_length ) {
timeline_length = p_length ;
}
double AnimationNodeAnimation : : get_timeline_length ( ) const {
return timeline_length ;
}
void AnimationNodeAnimation : : set_stretch_time_scale ( bool p_strech_time_scale ) {
stretch_time_scale = p_strech_time_scale ;
notify_property_list_changed ( ) ;
}
bool AnimationNodeAnimation : : is_stretching_time_scale ( ) const {
return stretch_time_scale ;
}
void AnimationNodeAnimation : : set_start_offset ( double p_offset ) {
start_offset = p_offset ;
}
double AnimationNodeAnimation : : get_start_offset ( ) const {
return start_offset ;
}
void AnimationNodeAnimation : : set_loop_mode ( Animation : : LoopMode p_loop_mode ) {
loop_mode = p_loop_mode ;
}
Animation : : LoopMode AnimationNodeAnimation : : get_loop_mode ( ) const {
return loop_mode ;
}
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 ) ;
2024-01-07 22:08:10 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_use_custom_timeline " , " use_custom_timeline " ) , & AnimationNodeAnimation : : set_use_custom_timeline ) ;
ClassDB : : bind_method ( D_METHOD ( " is_using_custom_timeline " ) , & AnimationNodeAnimation : : is_using_custom_timeline ) ;
ClassDB : : bind_method ( D_METHOD ( " set_timeline_length " , " timeline_length " ) , & AnimationNodeAnimation : : set_timeline_length ) ;
ClassDB : : bind_method ( D_METHOD ( " get_timeline_length " ) , & AnimationNodeAnimation : : get_timeline_length ) ;
ClassDB : : bind_method ( D_METHOD ( " set_stretch_time_scale " , " stretch_time_scale " ) , & AnimationNodeAnimation : : set_stretch_time_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " is_stretching_time_scale " ) , & AnimationNodeAnimation : : is_stretching_time_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " set_start_offset " , " start_offset " ) , & AnimationNodeAnimation : : set_start_offset ) ;
ClassDB : : bind_method ( D_METHOD ( " get_start_offset " ) , & AnimationNodeAnimation : : get_start_offset ) ;
ClassDB : : bind_method ( D_METHOD ( " set_loop_mode " , " loop_mode " ) , & AnimationNodeAnimation : : set_loop_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_loop_mode " ) , & AnimationNodeAnimation : : get_loop_mode ) ;
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 " ) ;
2024-01-07 22:08:10 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " use_custom_timeline " ) , " set_use_custom_timeline " , " is_using_custom_timeline " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " timeline_length " , PROPERTY_HINT_RANGE , " 0.001,60,0.001,or_greater,or_less,hide_slider,suffix:s " ) , " set_timeline_length " , " get_timeline_length " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " stretch_time_scale " ) , " set_stretch_time_scale " , " is_stretching_time_scale " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " start_offset " , PROPERTY_HINT_RANGE , " -60,60,0.001,or_greater,or_less,hide_slider,suffix:s " ) , " set_start_offset " , " get_start_offset " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " loop_mode " , PROPERTY_HINT_ENUM , " None,Linear,Ping-Pong " ) , " set_loop_mode " , " get_loop_mode " ) ;
2021-10-15 15:25:00 +02:00
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 {
2024-01-07 22:08:10 +01:00
AnimationNode : : get_parameter_list ( r_list ) ;
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 ) ) ;
2023-05-13 00:20:35 +02:00
r_list - > push_back ( PropertyInfo ( Variant : : BOOL , internal_active , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY ) ) ;
r_list - > push_back ( PropertyInfo ( Variant : : INT , request , PROPERTY_HINT_ENUM , " ,Fire,Abort,Fade Out " ) ) ;
2024-01-07 22:08:10 +01:00
r_list - > push_back ( PropertyInfo ( Variant : : FLOAT , fade_in_remaining , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) ) ;
2023-05-13 00:20:35 +02:00
r_list - > push_back ( PropertyInfo ( Variant : : FLOAT , fade_out_remaining , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) ) ;
2021-07-01 03:24:34 +02:00
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 {
2024-01-07 22:08:10 +01:00
Variant ret = AnimationNode : : get_parameter_default_value ( p_parameter ) ;
if ( ret ! = Variant ( ) ) {
return ret ;
}
2023-01-12 13:51:03 +01:00
if ( p_parameter = = request ) {
return ONE_SHOT_REQUEST_NONE ;
2023-05-13 00:20:35 +02:00
} else if ( p_parameter = = active | | p_parameter = = internal_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 {
2024-01-07 22:08:10 +01:00
if ( AnimationNode : : is_parameter_read_only ( p_parameter ) ) {
return true ;
}
2023-05-13 00:20:35 +02:00
if ( p_parameter = = active | | p_parameter = = internal_active ) {
2023-01-12 13:51:03 +01:00
return true ;
}
return false ;
}
2023-05-13 00:20:35 +02:00
void AnimationNodeOneShot : : set_fade_in_time ( double p_time ) {
2018-06-19 03:10:48 +02:00
fade_in = p_time ;
}
2023-05-13 00:20:35 +02:00
double AnimationNodeOneShot : : get_fade_in_time ( ) const {
return fade_in ;
2018-06-19 03:10:48 +02:00
}
2023-05-13 00:20:35 +02:00
void AnimationNodeOneShot : : set_fade_out_time ( double p_time ) {
fade_out = p_time ;
2018-06-19 03:10:48 +02:00
}
2020-05-14 14:29:06 +02:00
2023-05-13 00:20:35 +02:00
double AnimationNodeOneShot : : get_fade_out_time ( ) const {
2018-06-19 03:10:48 +02:00
return fade_out ;
}
2023-05-13 00:20:35 +02:00
void AnimationNodeOneShot : : set_fade_in_curve ( const Ref < Curve > & p_curve ) {
fade_in_curve = p_curve ;
2018-06-19 03:10:48 +02:00
}
2020-05-14 14:29:06 +02:00
2023-05-13 00:20:35 +02:00
Ref < Curve > AnimationNodeOneShot : : get_fade_in_curve ( ) const {
return fade_in_curve ;
2018-06-19 03:10:48 +02:00
}
2020-05-14 14:29:06 +02:00
2023-05-13 00:20:35 +02:00
void AnimationNodeOneShot : : set_fade_out_curve ( const Ref < Curve > & p_curve ) {
fade_out_curve = p_curve ;
2018-06-19 03:10:48 +02:00
}
2023-05-13 00:20:35 +02:00
Ref < Curve > AnimationNodeOneShot : : get_fade_out_curve ( ) const {
return fade_out_curve ;
2018-06-19 03:10:48 +02:00
}
2020-05-14 14:29:06 +02:00
2023-05-13 00:20:35 +02:00
void AnimationNodeOneShot : : set_auto_restart_enabled ( bool p_enabled ) {
auto_restart = p_enabled ;
2018-06-19 03:10:48 +02:00
}
2020-05-14 14:29:06 +02:00
2023-05-13 00:20:35 +02:00
void AnimationNodeOneShot : : set_auto_restart_delay ( double p_time ) {
auto_restart_delay = p_time ;
}
void AnimationNodeOneShot : : set_auto_restart_random_delay ( double p_time ) {
auto_restart_random_delay = p_time ;
}
bool AnimationNodeOneShot : : is_auto_restart_enabled ( ) const {
return auto_restart ;
}
double AnimationNodeOneShot : : get_auto_restart_delay ( ) const {
return auto_restart_delay ;
}
double AnimationNodeOneShot : : get_auto_restart_random_delay ( ) const {
return auto_restart_random_delay ;
2018-06-19 03:10:48 +02:00
}
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 ;
}
2024-01-07 22:08:10 +01:00
void AnimationNodeOneShot : : set_break_loop_at_end ( bool p_enable ) {
break_loop_at_end = p_enable ;
}
bool AnimationNodeOneShot : : is_loop_broken_at_end ( ) const {
return break_loop_at_end ;
}
2018-06-19 03:10:48 +02:00
String AnimationNodeOneShot : : get_caption ( ) const {
return " OneShot " ;
}
bool AnimationNodeOneShot : : has_filter ( ) const {
return true ;
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeOneShot : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , 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 ) ;
2023-05-13 00:20:35 +02:00
bool cur_internal_active = get_parameter ( internal_active ) ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo cur_nti = get_node_time_info ( ) ;
2022-09-29 11:53:28 +02:00
double cur_time_to_restart = get_parameter ( time_to_restart ) ;
2024-01-07 22:08:10 +01:00
double cur_fade_in_remaining = get_parameter ( fade_in_remaining ) ;
double cur_fade_out_remaining = get_parameter ( fade_out_remaining ) ;
2018-08-20 18:38:18 +02:00
2023-01-12 13:51:03 +01:00
set_parameter ( request , ONE_SHOT_REQUEST_NONE ) ;
2023-05-13 00:20:35 +02:00
bool is_shooting = true ;
bool clear_remaining_fade = false ;
bool is_fading_out = cur_active = = true & & cur_internal_active = = false ;
2023-07-20 17:34:06 +02:00
double p_time = p_playback_info . time ;
2024-01-07 22:08:10 +01:00
double p_delta = p_playback_info . delta ;
double abs_delta = Math : : abs ( p_delta ) ;
2023-07-20 17:34:06 +02:00
bool p_seek = p_playback_info . seeked ;
bool p_is_external_seeking = p_playback_info . is_external_seeking ;
2024-07-23 18:00:42 +02:00
if ( Math : : is_zero_approx ( p_time ) & & p_seek & & ! p_is_external_seeking ) {
2023-05-13 00:20:35 +02:00
clear_remaining_fade = true ; // Reset occurs.
}
2023-01-12 13:51:03 +01:00
bool do_start = cur_request = = ONE_SHOT_REQUEST_FIRE ;
if ( cur_request = = ONE_SHOT_REQUEST_ABORT ) {
2023-05-13 00:20:35 +02:00
set_parameter ( internal_active , false ) ;
2023-01-12 13:51:03 +01:00
set_parameter ( active , false ) ;
set_parameter ( time_to_restart , - 1 ) ;
2023-05-13 00:20:35 +02:00
is_shooting = false ;
} else if ( cur_request = = ONE_SHOT_REQUEST_FADE_OUT & & ! is_fading_out ) { // If fading, keep current fade.
if ( cur_active ) {
// Request fading.
is_fading_out = true ;
cur_fade_out_remaining = fade_out ;
2024-01-07 22:08:10 +01:00
cur_fade_in_remaining = 0 ;
2023-05-13 00:20:35 +02:00
} else {
// Shot is ended, do nothing.
is_shooting = false ;
}
set_parameter ( internal_active , false ) ;
set_parameter ( time_to_restart , - 1 ) ;
2023-01-12 13:51:03 +01:00
} else if ( ! do_start & & ! cur_active ) {
2024-07-23 18:00:42 +02:00
if ( Animation : : is_greater_or_equal_approx ( cur_time_to_restart , 0 ) & & ! p_seek ) {
2024-01-07 22:08:10 +01:00
cur_time_to_restart - = abs_delta ;
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_approx ( 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-05-13 00:20:35 +02:00
is_shooting = false ;
2023-01-12 13:51:03 +01:00
}
2018-06-19 03:10:48 +02:00
}
bool os_seek = p_seek ;
2023-05-13 00:20:35 +02:00
if ( clear_remaining_fade ) {
os_seek = false ;
cur_fade_out_remaining = 0 ;
set_parameter ( fade_out_remaining , 0 ) ;
if ( is_fading_out ) {
is_fading_out = false ;
set_parameter ( internal_active , false ) ;
set_parameter ( active , false ) ;
}
}
if ( ! is_shooting ) {
2023-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
pi . weight = 1.0 ;
return blend_input ( 0 , pi , FILTER_IGNORE , sync , p_test_only ) ;
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 ) {
os_seek = true ;
2024-01-07 22:08:10 +01:00
if ( ! cur_internal_active ) {
cur_fade_in_remaining = fade_in ; // If already active, don't fade-in again.
}
cur_internal_active = true ;
2023-01-12 13:51:03 +01:00
set_parameter ( request , ONE_SHOT_REQUEST_NONE ) ;
2023-05-13 00:20:35 +02:00
set_parameter ( internal_active , true ) ;
2023-01-12 13:51:03 +01:00
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 ;
2024-01-07 22:08:10 +01:00
2024-07-23 18:00:42 +02:00
if ( Animation : : is_greater_approx ( cur_fade_in_remaining , 0 ) ) {
if ( Animation : : is_greater_approx ( fade_in , 0 ) ) {
2023-02-13 00:12:34 +01:00
use_blend = true ;
2024-01-07 22:08:10 +01:00
blend = ( fade_in - cur_fade_in_remaining ) / fade_in ;
2023-05-13 00:20:35 +02:00
if ( fade_in_curve . is_valid ( ) ) {
blend = fade_in_curve - > sample ( blend ) ;
}
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
}
2023-05-13 00:20:35 +02:00
}
if ( is_fading_out ) {
2023-02-11 20:28:46 +01:00
use_blend = true ;
2024-07-23 18:00:42 +02:00
if ( Animation : : is_greater_approx ( fade_out , 0 ) ) {
2023-05-13 00:20:35 +02:00
blend = cur_fade_out_remaining / fade_out ;
if ( fade_out_curve . is_valid ( ) ) {
blend = 1.0 - fade_out_curve - > sample ( 1.0 - blend ) ;
}
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-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo main_nti ;
2018-06-19 03:10:48 +02:00
if ( mix = = MIX_MODE_ADD ) {
2023-07-20 17:34:06 +02:00
pi . weight = 1.0 ;
2024-01-07 22:08:10 +01:00
main_nti = blend_input ( 0 , pi , FILTER_IGNORE , sync , p_test_only ) ;
2023-02-13 00:12:34 +01:00
} else {
2023-07-20 17:34:06 +02:00
pi . seeked & = use_blend ;
pi . weight = 1.0 - blend ;
2024-01-07 22:08:10 +01:00
main_nti = blend_input ( 0 , pi , FILTER_BLEND , sync , p_test_only ) ; // Unlike below, processing this edge is a corner case.
2023-07-20 17:34:06 +02:00
}
2024-01-07 22:08:10 +01:00
2023-07-20 17:34:06 +02:00
pi = p_playback_info ;
2024-01-07 22:08:10 +01:00
if ( do_start ) {
pi . time = 0 ;
} else if ( os_seek ) {
pi . time = cur_nti . position ;
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
pi . seeked = os_seek ;
pi . weight = Math : : is_zero_approx ( blend ) ? CMP_EPSILON : blend ;
2018-06-19 03:10:48 +02:00
2024-01-07 22:08:10 +01:00
NodeTimeInfo os_nti = blend_input ( 1 , pi , FILTER_PASS , true , p_test_only ) ; // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_or_equal_approx ( cur_fade_in_remaining , 0 ) & & ! do_start & & ! is_fading_out & & Animation : : is_less_or_equal_approx ( os_nti . get_remain ( break_loop_at_end ) , fade_out ) ) {
2024-01-07 22:08:10 +01:00
is_fading_out = true ;
cur_fade_out_remaining = os_nti . get_remain ( break_loop_at_end ) ;
cur_fade_in_remaining = 0 ;
set_parameter ( internal_active , false ) ;
2018-06-19 03:10:48 +02:00
}
2024-01-07 22:08:10 +01:00
if ( ! p_seek ) {
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_or_equal_approx ( os_nti . get_remain ( break_loop_at_end ) , 0 ) | | ( is_fading_out & & Animation : : is_less_or_equal_approx ( cur_fade_out_remaining , 0 ) ) ) {
2023-05-13 00:20:35 +02:00
set_parameter ( internal_active , false ) ;
2022-09-29 11:53:28 +02:00
set_parameter ( active , false ) ;
2023-05-13 00:20:35 +02:00
if ( auto_restart ) {
double restart_sec = auto_restart_delay + Math : : randd ( ) * auto_restart_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
}
2024-01-07 22:08:10 +01:00
double d = Math : : abs ( os_nti . delta ) ;
if ( ! do_start ) {
cur_fade_in_remaining = MAX ( 0 , cur_fade_in_remaining - d ) ; // Don't consider seeked delta by restart.
}
cur_fade_out_remaining = MAX ( 0 , cur_fade_out_remaining - d ) ;
2018-06-19 03:10:48 +02:00
}
2024-01-07 22:08:10 +01:00
set_parameter ( fade_in_remaining , cur_fade_in_remaining ) ;
2023-05-13 00:20:35 +02:00
set_parameter ( fade_out_remaining , cur_fade_out_remaining ) ;
2018-08-20 18:38:18 +02:00
2024-01-07 22:08:10 +01:00
return cur_internal_active ? os_nti : main_nti ;
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 ( ) {
2023-05-13 00:20:35 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_fadein_time " , " time " ) , & AnimationNodeOneShot : : set_fade_in_time ) ;
ClassDB : : bind_method ( D_METHOD ( " get_fadein_time " ) , & AnimationNodeOneShot : : get_fade_in_time ) ;
ClassDB : : bind_method ( D_METHOD ( " set_fadein_curve " , " curve " ) , & AnimationNodeOneShot : : set_fade_in_curve ) ;
ClassDB : : bind_method ( D_METHOD ( " get_fadein_curve " ) , & AnimationNodeOneShot : : get_fade_in_curve ) ;
ClassDB : : bind_method ( D_METHOD ( " set_fadeout_time " , " time " ) , & AnimationNodeOneShot : : set_fade_out_time ) ;
ClassDB : : bind_method ( D_METHOD ( " get_fadeout_time " ) , & AnimationNodeOneShot : : get_fade_out_time ) ;
2018-06-19 03:10:48 +02:00
2023-05-13 00:20:35 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_fadeout_curve " , " curve " ) , & AnimationNodeOneShot : : set_fade_out_curve ) ;
ClassDB : : bind_method ( D_METHOD ( " get_fadeout_curve " ) , & AnimationNodeOneShot : : get_fade_out_curve ) ;
2018-06-19 03:10:48 +02:00
2024-01-07 22:08:10 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_break_loop_at_end " , " enable " ) , & AnimationNodeOneShot : : set_break_loop_at_end ) ;
ClassDB : : bind_method ( D_METHOD ( " is_loop_broken_at_end " ) , & AnimationNodeOneShot : : is_loop_broken_at_end ) ;
2023-05-13 00:20:35 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_autorestart " , " active " ) , & AnimationNodeOneShot : : set_auto_restart_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " has_autorestart " ) , & AnimationNodeOneShot : : is_auto_restart_enabled ) ;
2018-06-19 03:10:48 +02:00
2023-05-13 00:20:35 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_autorestart_delay " , " time " ) , & AnimationNodeOneShot : : set_auto_restart_delay ) ;
ClassDB : : bind_method ( D_METHOD ( " get_autorestart_delay " ) , & AnimationNodeOneShot : : get_auto_restart_delay ) ;
2018-06-19 03:10:48 +02:00
2023-05-13 00:20:35 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_autorestart_random_delay " , " time " ) , & AnimationNodeOneShot : : set_auto_restart_random_delay ) ;
ClassDB : : bind_method ( D_METHOD ( " get_autorestart_random_delay " ) , & AnimationNodeOneShot : : get_auto_restart_random_delay ) ;
2018-06-19 03:10:48 +02:00
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 " ) ;
2023-05-13 00:20:35 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " fadein_curve " , PROPERTY_HINT_RESOURCE_TYPE , " Curve " ) , " set_fadein_curve " , " get_fadein_curve " ) ;
2022-05-20 07:24:41 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " fadeout_time " , PROPERTY_HINT_RANGE , " 0,60,0.01,or_greater,suffix:s " ) , " set_fadeout_time " , " get_fadeout_time " ) ;
2023-05-13 00:20:35 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " fadeout_curve " , PROPERTY_HINT_RESOURCE_TYPE , " Curve " ) , " set_fadeout_curve " , " get_fadeout_curve " ) ;
2024-01-07 22:08:10 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " break_loop_at_end " ) , " set_break_loop_at_end " , " is_loop_broken_at_end " ) ;
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 ) ;
2023-05-13 00:20:35 +02:00
BIND_ENUM_CONSTANT ( ONE_SHOT_REQUEST_FADE_OUT ) ;
2023-01-12 13:51:03 +01:00
2019-10-02 09:57:12 +02:00
BIND_ENUM_CONSTANT ( MIX_MODE_BLEND ) ;
BIND_ENUM_CONSTANT ( MIX_MODE_ADD ) ;
2018-06-19 03:10:48 +02:00
}
AnimationNodeOneShot : : AnimationNodeOneShot ( ) {
add_input ( " in " ) ;
add_input ( " shot " ) ;
}
////////////////////////////////////////////////
2018-08-20 18:38:18 +02:00
void AnimationNodeAdd2 : : get_parameter_list ( List < PropertyInfo > * r_list ) const {
2024-01-07 22:08:10 +01:00
AnimationNode : : get_parameter_list ( r_list ) ;
2023-04-30 16:32:18 +02:00
r_list - > push_back ( PropertyInfo ( Variant : : FLOAT , add_amount , PROPERTY_HINT_RANGE , " 0,1,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 AnimationNodeAdd2 : : get_parameter_default_value ( const StringName & p_parameter ) const {
2024-01-07 22:08:10 +01:00
Variant ret = AnimationNode : : get_parameter_default_value ( p_parameter ) ;
if ( ret ! = Variant ( ) ) {
return ret ;
}
2018-08-20 18:38:18 +02:00
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 ;
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeAdd2 : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
2021-05-21 08:42:37 +02:00
double amount = get_parameter ( add_amount ) ;
2023-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
pi . weight = 1.0 ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo nti = blend_input ( 0 , pi , FILTER_IGNORE , sync , p_test_only ) ;
2023-07-20 17:34:06 +02:00
pi . weight = amount ;
blend_input ( 1 , pi , FILTER_PASS , sync , p_test_only ) ;
2018-06-19 03:10:48 +02:00
2024-01-07 22:08:10 +01:00
return nti ;
2018-06-19 03:10:48 +02:00
}
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 {
2024-01-07 22:08:10 +01:00
AnimationNode : : get_parameter_list ( r_list ) ;
2023-04-30 16:32:18 +02:00
r_list - > push_back ( PropertyInfo ( Variant : : FLOAT , add_amount , PROPERTY_HINT_RANGE , " -1,1,0.01,or_less,or_greater " ) ) ;
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 {
2024-01-07 22:08:10 +01:00
Variant ret = AnimationNode : : get_parameter_default_value ( p_parameter ) ;
if ( ret ! = Variant ( ) ) {
return ret ;
}
2018-08-20 18:38:18 +02:00
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 ;
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeAdd3 : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
2021-05-21 08:42:37 +02:00
double amount = get_parameter ( add_amount ) ;
2023-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
pi . weight = MAX ( 0 , - amount ) ;
blend_input ( 0 , pi , FILTER_PASS , sync , p_test_only ) ;
pi . weight = 1.0 ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo nti = blend_input ( 1 , pi , FILTER_IGNORE , sync , p_test_only ) ;
2023-07-20 17:34:06 +02:00
pi . weight = MAX ( 0 , amount ) ;
blend_input ( 2 , pi , FILTER_PASS , sync , p_test_only ) ;
2018-06-28 01:50:25 +02:00
2024-01-07 22:08:10 +01:00
return nti ;
2018-06-28 01:50:25 +02:00
}
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 {
2024-01-07 22:08:10 +01:00
AnimationNode : : get_parameter_list ( r_list ) ;
2023-04-30 16:32:18 +02:00
r_list - > push_back ( PropertyInfo ( Variant : : FLOAT , blend_amount , PROPERTY_HINT_RANGE , " 0,1,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 AnimationNodeBlend2 : : get_parameter_default_value ( const StringName & p_parameter ) const {
2024-01-07 22:08:10 +01:00
Variant ret = AnimationNode : : get_parameter_default_value ( p_parameter ) ;
if ( ret ! = Variant ( ) ) {
return ret ;
}
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 " ;
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeBlend2 : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , 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-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
pi . weight = 1.0 - amount ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo nti0 = blend_input ( 0 , pi , FILTER_BLEND , sync , p_test_only ) ;
2023-07-20 17:34:06 +02:00
pi . weight = amount ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo nti1 = blend_input ( 1 , pi , FILTER_PASS , sync , p_test_only ) ;
2018-06-19 03:10:48 +02:00
2024-01-07 22:08:10 +01:00
return amount > 0.5 ? nti1 : nti0 ; // 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 {
2024-01-07 22:08:10 +01:00
AnimationNode : : get_parameter_list ( r_list ) ;
2023-04-30 16:32:18 +02:00
r_list - > push_back ( PropertyInfo ( Variant : : FLOAT , blend_amount , PROPERTY_HINT_RANGE , " -1,1,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 AnimationNodeBlend3 : : get_parameter_default_value ( const StringName & p_parameter ) const {
2024-01-07 22:08:10 +01:00
Variant ret = AnimationNode : : get_parameter_default_value ( p_parameter ) ;
if ( ret ! = Variant ( ) ) {
return ret ;
}
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 " ;
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeBlend3 : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
2021-05-21 08:42:37 +02:00
double amount = get_parameter ( blend_amount ) ;
2023-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
pi . weight = MAX ( 0 , - amount ) ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo nti0 = blend_input ( 0 , pi , FILTER_IGNORE , sync , p_test_only ) ;
2023-07-20 17:34:06 +02:00
pi . weight = 1.0 - ABS ( amount ) ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo nti1 = blend_input ( 1 , pi , FILTER_IGNORE , sync , p_test_only ) ;
2023-07-20 17:34:06 +02:00
pi . weight = MAX ( 0 , amount ) ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo nti2 = blend_input ( 2 , pi , FILTER_IGNORE , sync , p_test_only ) ;
2018-06-19 03:10:48 +02:00
2024-01-07 22:08:10 +01:00
return amount > 0.5 ? nti2 : ( amount < - 0.5 ? nti0 : nti1 ) ; // 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 " ) ;
}
2023-04-30 16:32:18 +02:00
////////////////////////////////////////////////
void AnimationNodeSub2 : : get_parameter_list ( List < PropertyInfo > * r_list ) const {
2024-01-07 22:08:10 +01:00
AnimationNode : : get_parameter_list ( r_list ) ;
2023-04-30 16:32:18 +02:00
r_list - > push_back ( PropertyInfo ( Variant : : FLOAT , sub_amount , PROPERTY_HINT_RANGE , " 0,1,0.01,or_less,or_greater " ) ) ;
}
Variant AnimationNodeSub2 : : get_parameter_default_value ( const StringName & p_parameter ) const {
2024-01-07 22:08:10 +01:00
Variant ret = AnimationNode : : get_parameter_default_value ( p_parameter ) ;
if ( ret ! = Variant ( ) ) {
return ret ;
}
2023-04-30 16:32:18 +02:00
return 0 ;
}
String AnimationNodeSub2 : : get_caption ( ) const {
return " Sub2 " ;
}
bool AnimationNodeSub2 : : has_filter ( ) const {
return true ;
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeSub2 : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
2023-04-30 16:32:18 +02:00
double amount = get_parameter ( sub_amount ) ;
2023-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
2023-04-30 16:32:18 +02:00
// Out = Sub.Transform3D^(-1) * In.Transform3D
2023-07-20 17:34:06 +02:00
pi . weight = - amount ;
blend_input ( 1 , pi , FILTER_PASS , sync , p_test_only ) ;
pi . weight = 1.0 ;
return blend_input ( 0 , pi , FILTER_IGNORE , sync , p_test_only ) ;
2023-04-30 16:32:18 +02:00
}
void AnimationNodeSub2 : : _bind_methods ( ) {
}
AnimationNodeSub2 : : AnimationNodeSub2 ( ) {
add_input ( " in " ) ;
add_input ( " sub " ) ;
}
2018-06-19 03:10:48 +02:00
/////////////////////////////////
2018-08-20 18:38:18 +02:00
void AnimationNodeTimeScale : : get_parameter_list ( List < PropertyInfo > * r_list ) const {
2024-01-07 22:08:10 +01:00
AnimationNode : : get_parameter_list ( r_list ) ;
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 {
2024-01-07 22:08:10 +01:00
Variant ret = AnimationNode : : get_parameter_default_value ( p_parameter ) ;
if ( ret ! = Variant ( ) ) {
return ret ;
}
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 " ;
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeTimeScale : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
2022-09-29 11:53:28 +02:00
double cur_scale = get_parameter ( scale ) ;
2023-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
pi . weight = 1.0 ;
if ( ! pi . seeked ) {
2024-01-07 22:08:10 +01:00
pi . delta * = cur_scale ;
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
return blend_input ( 0 , pi , 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 {
2024-01-07 22:08:10 +01:00
AnimationNode : : get_parameter_list ( r_list ) ;
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 {
2024-01-07 22:08:10 +01:00
Variant ret = AnimationNode : : get_parameter_default_value ( p_parameter ) ;
if ( ret ! = Variant ( ) ) {
return ret ;
}
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
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeTimeSeek : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
2023-02-01 12:49:31 +01:00
double cur_seek_pos = get_parameter ( seek_pos_request ) ;
2023-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
pi . weight = 1.0 ;
2024-07-23 18:00:42 +02:00
if ( Animation : : is_greater_or_equal_approx ( cur_seek_pos , 0 ) ) {
2023-07-20 17:34:06 +02:00
pi . time = cur_seek_pos ;
pi . seeked = true ;
pi . is_external_seeking = true ;
2023-02-01 12:49:31 +01:00
set_parameter ( seek_pos_request , - 1.0 ) ; // Reset.
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
return blend_input ( 0 , pi , 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 ) ;
2024-01-07 22:08:10 +01:00
} else if ( what = = " break_loop_at_end " ) {
set_input_break_loop_at_end ( 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 ) ;
2024-01-07 22:08:10 +01:00
} else if ( what = = " break_loop_at_end " ) {
r_ret = is_input_loop_broken_at_end ( 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 {
2024-01-07 22:08:10 +01:00
AnimationNode : : get_parameter_list ( r_list ) ;
2018-08-20 18:38:18 +02:00
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 , 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 {
2024-01-07 22:08:10 +01:00
Variant ret = AnimationNode : : get_parameter_default_value ( p_parameter ) ;
if ( ret ! = Variant ( ) ) {
return ret ;
}
if ( p_parameter = = prev_xfading ) {
2018-08-20 18:38:18 +02:00
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 {
2024-01-07 22:08:10 +01:00
if ( AnimationNode : : is_parameter_read_only ( p_parameter ) ) {
return true ;
}
2023-01-12 13:51:03 +01:00
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 ;
}
2024-01-07 22:08:10 +01:00
void AnimationNodeTransition : : set_input_break_loop_at_end ( int p_input , bool p_enable ) {
ERR_FAIL_INDEX ( p_input , get_input_count ( ) ) ;
input_data . write [ p_input ] . break_loop_at_end = p_enable ;
}
bool AnimationNodeTransition : : is_input_loop_broken_at_end ( int p_input ) const {
ERR_FAIL_INDEX_V ( p_input , get_input_count ( ) , false ) ;
return input_data [ p_input ] . break_loop_at_end ;
}
2023-01-30 16:40:45 +01:00
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 ;
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeTransition : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , 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
2024-01-07 22:08:10 +01:00
NodeTimeInfo cur_nti = get_node_time_info ( ) ;
2022-09-29 11:53:28 +02:00
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-07-20 17:34:06 +02:00
double p_time = p_playback_info . time ;
bool p_seek = p_playback_info . seeked ;
bool p_is_external_seeking = p_playback_info . is_external_seeking ;
2024-07-23 18:00:42 +02:00
if ( Math : : is_zero_approx ( p_time ) & & p_seek & & ! p_is_external_seeking ) {
2023-02-11 20:12:15 +01:00
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-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
2023-01-12 13:51:03 +01:00
// Special case for restart.
if ( restart ) {
2023-07-20 17:34:06 +02:00
pi . time = 0 ;
pi . seeked = true ;
pi . weight = 1.0 ;
return blend_input ( cur_current_index , pi , 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 ;
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 ( ) ) {
2024-01-07 22:08:10 +01:00
return NodeTimeInfo ( ) ;
2018-08-20 18:38:18 +02:00
}
2022-11-15 07:06:10 +01:00
if ( sync ) {
2023-07-20 17:34:06 +02:00
pi . weight = 0 ;
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-07-20 17:34:06 +02:00
blend_input ( i , pi , 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.
2023-07-20 17:34:06 +02:00
pi . weight = 1.0 ;
2024-01-07 22:08:10 +01:00
cur_nti = blend_input ( cur_current_index , pi , FILTER_IGNORE , true , p_test_only ) ;
2024-07-23 18:00:42 +02:00
if ( input_data [ cur_current_index ] . auto_advance & & Animation : : is_less_or_equal_approx ( cur_nti . get_remain ( input_data [ cur_current_index ] . break_loop_at_end ) , 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-07-20 17:34:06 +02:00
pi . weight = blend_inv ;
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-07-20 17:34:06 +02:00
pi . time = 0 ;
pi . seeked = true ;
2018-06-19 03:10:48 +02:00
}
2024-01-07 22:08:10 +01:00
cur_nti = blend_input ( cur_current_index , pi , FILTER_IGNORE , true , p_test_only ) ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
pi = p_playback_info ;
pi . seeked & = use_blend ;
pi . weight = blend ;
blend_input ( cur_prev_index , pi , FILTER_IGNORE , true , p_test_only ) ;
2024-01-07 22:08:10 +01:00
if ( ! p_seek ) {
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_or_equal_approx ( 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
}
2024-01-07 22:08:10 +01:00
cur_prev_xfading - = Math : : abs ( p_playback_info . delta ) ;
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 ( prev_xfading , cur_prev_xfading ) ;
2018-08-20 18:38:18 +02:00
2024-01-07 22:08:10 +01:00
return cur_nti ;
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 ) ) ;
2024-01-07 22:08:10 +01:00
p_list - > push_back ( PropertyInfo ( Variant : : BOOL , " input_ " + itos ( i ) + " /break_loop_at_end " , 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 ) ;
2024-01-07 22:08:10 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_input_break_loop_at_end " , " input " , " enable " ) , & AnimationNodeTransition : : set_input_break_loop_at_end ) ;
ClassDB : : bind_method ( D_METHOD ( " is_input_loop_broken_at_end " , " input " ) , & AnimationNodeTransition : : is_input_loop_broken_at_end ) ;
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 " ;
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeOutput : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
2023-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
pi . weight = 1.0 ;
return blend_input ( 0 , pi , 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 ( ) ) ;
2023-09-04 17:01:33 +02:00
ERR_FAIL_COND ( p_name = = SceneStringName ( 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
2023-07-20 17:34:06 +02:00
p_node - > connect ( SNAME ( " tree_changed " ) , callable_mp ( this , & AnimationNodeBlendTree : : _tree_changed ) , CONNECT_REFERENCE_COUNTED ) ;
p_node - > connect ( SNAME ( " animation_node_renamed " ) , callable_mp ( this , & AnimationNodeBlendTree : : _animation_node_renamed ) , CONNECT_REFERENCE_COUNTED ) ;
p_node - > connect ( SNAME ( " animation_node_removed " ) , callable_mp ( this , & AnimationNodeBlendTree : : _animation_node_removed ) , CONNECT_REFERENCE_COUNTED ) ;
2023-07-03 21:29:37 +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
}
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 ) ) ;
2023-09-04 17:01:33 +02:00
ERR_FAIL_COND ( p_name = = SceneStringName ( output ) ) ; //can't delete output
2018-06-19 03:10:48 +02:00
{
2018-08-20 18:38:18 +02:00
Ref < AnimationNode > node = nodes [ p_name ] . node ;
2023-07-20 17:34:06 +02:00
node - > disconnect ( SNAME ( " tree_changed " ) , callable_mp ( this , & AnimationNodeBlendTree : : _tree_changed ) ) ;
node - > disconnect ( SNAME ( " animation_node_renamed " ) , callable_mp ( this , & AnimationNodeBlendTree : : _animation_node_renamed ) ) ;
node - > disconnect ( SNAME ( " animation_node_removed " ) , callable_mp ( this , & AnimationNodeBlendTree : : _animation_node_removed ) ) ;
2023-07-03 21:29:37 +02: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 ) ) ;
2023-09-04 17:01:33 +02:00
ERR_FAIL_COND ( p_name = = SceneStringName ( output ) ) ;
ERR_FAIL_COND ( p_new_name = = SceneStringName ( output ) ) ;
2018-06-19 03:10:48 +02:00
2023-07-03 21:29:37 +02: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.
2023-07-03 21:29:37 +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 ) ) ;
2023-09-04 17:01:33 +02:00
ERR_FAIL_COND ( p_output_node = = SceneStringName ( output ) ) ;
2018-06-19 03:10:48 +02:00
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 {
2023-09-04 17:01:33 +02:00
if ( ! nodes . has ( p_output_node ) | | p_output_node = = SceneStringName ( output ) ) {
2018-06-19 03:10:48 +02:00
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 " ;
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNodeBlendTree : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
2023-09-04 17:01:33 +02:00
Ref < AnimationNodeOutput > output = nodes [ SceneStringName ( output ) ] . node ;
node_state . connections = nodes [ SceneStringName ( output ) ] . connections ;
2024-01-07 22:08:10 +01:00
ERR_FAIL_COND_V ( output . is_null ( ) , NodeTimeInfo ( ) ) ;
2023-07-20 17:34:06 +02:00
AnimationMixer : : PlaybackInfo pi = p_playback_info ;
pi . weight = 1.0 ;
return _blend_node ( output , " output " , this , pi , FILTER_IGNORE , true , p_test_only , nullptr ) ;
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
}
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
}
2024-01-03 12:10:11 +01:00
# ifdef TOOLS_ENABLED
2024-01-06 16:16:10 +01:00
void AnimationNodeBlendTree : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
2024-01-03 12:10:11 +01:00
const String pf = p_function ;
2024-01-06 16:16:10 +01:00
bool add_node_options = false ;
if ( p_idx = = 0 ) {
add_node_options = ( pf = = " get_node " | | pf = = " has_node " | | pf = = " rename_node " | | pf = = " remove_node " | | pf = = " set_node_position " | | pf = = " get_node_position " | | pf = = " connect_node " | | pf = = " disconnect_node " ) ;
} else if ( p_idx = = 2 ) {
add_node_options = ( pf = = " connect_node " | | pf = = " disconnect_node " ) ;
}
if ( add_node_options ) {
2024-01-03 12:10:11 +01:00
for ( const KeyValue < StringName , Node > & E : nodes ) {
2024-01-06 16:16:10 +01:00
r_options - > push_back ( String ( E . key ) . quote ( ) ) ;
}
}
AnimationRootNode : : get_argument_options ( p_function , p_idx , r_options ) ;
}
2024-01-03 12:10:11 +01:00
# endif
2024-01-06 16:16:10 +01: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
2023-07-20 17:34:06 +02:00
ADD_SIGNAL ( MethodInfo ( SNAME ( " 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 ( ) {
}