2018-08-29 22:38:13 +02:00
/**************************************************************************/
/* animation_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-25 23:40:24 +02:00
# include "animation_tree.h"
2023-07-20 17:34:06 +02:00
# include "animation_tree.compat.inc"
2018-09-11 18:13:45 +02:00
2018-06-19 03:10:48 +02:00
# include "animation_blend_tree.h"
2020-11-07 23:33:38 +01:00
# include "core/config/engine.h"
2023-11-07 16:31:32 +01:00
# include "scene/animation/animation_player.h"
2018-06-19 03:10:48 +02:00
2018-08-20 18:38:18 +02:00
void AnimationNode : : get_parameter_list ( List < PropertyInfo > * r_list ) const {
2021-08-22 03:52:44 +02:00
Array parameters ;
if ( GDVIRTUAL_CALL ( _get_parameter_list , parameters ) ) {
2018-11-25 20:56:49 +01:00
for ( int i = 0 ; i < parameters . size ( ) ; i + + ) {
Dictionary d = parameters [ i ] ;
2020-12-15 13:04:21 +01:00
ERR_CONTINUE ( d . is_empty ( ) ) ;
2018-11-25 20:56:49 +01:00
r_list - > push_back ( PropertyInfo : : from_dict ( d ) ) ;
}
}
2024-01-07 22:08:10 +01:00
r_list - > push_back ( PropertyInfo ( Variant : : FLOAT , current_length , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_READ_ONLY ) ) ;
r_list - > push_back ( PropertyInfo ( Variant : : FLOAT , current_position , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_READ_ONLY ) ) ;
r_list - > push_back ( PropertyInfo ( Variant : : FLOAT , current_delta , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_READ_ONLY ) ) ;
2018-08-20 18:38:18 +02:00
}
Variant AnimationNode : : get_parameter_default_value ( const StringName & p_parameter ) const {
2021-08-22 03:52:44 +02:00
Variant ret ;
2022-10-18 18:47:44 +02:00
GDVIRTUAL_CALL ( _get_parameter_default_value , p_parameter , ret ) ;
return ret ;
2018-08-20 18:38:18 +02:00
}
2023-01-12 13:51:03 +01:00
bool AnimationNode : : is_parameter_read_only ( const StringName & p_parameter ) const {
bool ret = false ;
2024-01-07 22:08:10 +01:00
if ( GDVIRTUAL_CALL ( _is_parameter_read_only , p_parameter , ret ) & & ret ) {
return true ;
}
if ( p_parameter = = current_length | | p_parameter = = current_position | | p_parameter = = current_delta ) {
return true ;
}
return false ;
2023-01-12 13:51:03 +01:00
}
2018-08-21 21:28:06 +02:00
void AnimationNode : : set_parameter ( const StringName & p_name , const Variant & p_value ) {
2023-07-20 17:34:06 +02:00
ERR_FAIL_NULL ( process_state ) ;
if ( process_state - > is_testing ) {
2023-02-18 03:02:28 +01:00
return ;
}
2023-07-20 17:34:06 +02:00
ERR_FAIL_COND ( ! process_state - > tree - > property_parent_map . has ( node_state . base_path ) ) ;
ERR_FAIL_COND ( ! process_state - > tree - > property_parent_map [ node_state . base_path ] . has ( p_name ) ) ;
StringName path = process_state - > tree - > property_parent_map [ node_state . base_path ] [ p_name ] ;
2018-08-20 18:38:18 +02:00
2023-07-20 17:34:06 +02:00
process_state - > tree - > property_map [ path ] . first = p_value ;
2018-08-20 18:38:18 +02:00
}
2018-08-21 21:28:06 +02:00
Variant AnimationNode : : get_parameter ( const StringName & p_name ) const {
2023-07-20 17:34:06 +02:00
ERR_FAIL_NULL_V ( process_state , Variant ( ) ) ;
ERR_FAIL_COND_V ( ! process_state - > tree - > property_parent_map . has ( node_state . base_path ) , Variant ( ) ) ;
ERR_FAIL_COND_V ( ! process_state - > tree - > property_parent_map [ node_state . base_path ] . has ( p_name ) , Variant ( ) ) ;
2018-08-20 18:38:18 +02:00
2023-07-20 17:34:06 +02:00
StringName path = process_state - > tree - > property_parent_map [ node_state . base_path ] [ p_name ] ;
return process_state - > tree - > property_map [ path ] . first ;
2018-08-20 18:38:18 +02:00
}
2024-01-07 22:08:10 +01:00
void AnimationNode : : set_node_time_info ( const NodeTimeInfo & p_node_time_info ) {
set_parameter ( current_length , p_node_time_info . length ) ;
set_parameter ( current_position , p_node_time_info . position ) ;
set_parameter ( current_delta , p_node_time_info . delta ) ;
}
AnimationNode : : NodeTimeInfo AnimationNode : : get_node_time_info ( ) const {
NodeTimeInfo nti ;
nti . length = get_parameter ( current_length ) ;
nti . position = get_parameter ( current_position ) ;
nti . delta = get_parameter ( current_delta ) ;
return nti ;
}
2018-08-20 18:38:18 +02:00
void AnimationNode : : get_child_nodes ( List < ChildNode > * r_child_nodes ) {
2021-08-22 03:52:44 +02:00
Dictionary cn ;
if ( GDVIRTUAL_CALL ( _get_child_nodes , cn ) ) {
2018-11-25 20:56:49 +01:00
List < Variant > keys ;
cn . get_key_list ( & keys ) ;
2021-07-24 15:46:25 +02:00
for ( const Variant & E : keys ) {
2018-11-25 20:56:49 +01:00
ChildNode child ;
2021-07-16 05:45:57 +02:00
child . name = E ;
child . node = cn [ E ] ;
2018-11-25 20:56:49 +01:00
r_child_nodes - > push_back ( child ) ;
}
}
2018-08-20 18:38:18 +02:00
}
2023-07-20 17:34:06 +02:00
void AnimationNode : : blend_animation ( const StringName & p_animation , AnimationMixer : : PlaybackInfo p_playback_info ) {
ERR_FAIL_NULL ( process_state ) ;
p_playback_info . track_weights = node_state . track_weights ;
process_state - > tree - > make_animation_instance ( p_animation , p_playback_info ) ;
2018-06-19 03:10:48 +02:00
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNode : : _pre_process ( ProcessState * p_process_state , AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
2023-07-20 17:34:06 +02:00
process_state = p_process_state ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo nti = process ( p_playback_info , p_test_only ) ;
2023-07-20 17:34:06 +02:00
process_state = nullptr ;
2024-01-07 22:08:10 +01:00
return nti ;
2018-06-19 03:10:48 +02:00
}
void AnimationNode : : make_invalid ( const String & p_reason ) {
2023-07-20 17:34:06 +02:00
ERR_FAIL_NULL ( process_state ) ;
process_state - > valid = false ;
if ( ! process_state - > invalid_reasons . is_empty ( ) ) {
process_state - > invalid_reasons + = " \n " ;
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
process_state - > invalid_reasons + = String : : utf8 ( " • " ) + p_reason ;
}
AnimationTree * AnimationNode : : get_animation_tree ( ) const {
ERR_FAIL_NULL_V ( process_state , nullptr ) ;
return process_state - > tree ;
2018-06-19 03:10:48 +02:00
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNode : : blend_input ( int p_input , AnimationMixer : : PlaybackInfo p_playback_info , FilterAction p_filter , bool p_sync , bool p_test_only ) {
ERR_FAIL_INDEX_V ( p_input , inputs . size ( ) , NodeTimeInfo ( ) ) ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
AnimationNodeBlendTree * blend_tree = Object : : cast_to < AnimationNodeBlendTree > ( node_state . parent ) ;
2024-01-07 22:08:10 +01:00
ERR_FAIL_NULL_V ( blend_tree , NodeTimeInfo ( ) ) ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
// Update connections.
StringName current_name = blend_tree - > get_node_name ( Ref < AnimationNode > ( this ) ) ;
node_state . connections = blend_tree - > get_node_connection_array ( current_name ) ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
// Get node which is connected input port.
StringName node_name = node_state . connections [ p_input ] ;
2018-08-20 18:38:18 +02:00
if ( ! blend_tree - > has_node ( node_name ) ) {
2023-07-20 17:34:06 +02:00
make_invalid ( vformat ( RTR ( " Nothing connected to input '%s' of node '%s'. " ) , get_input_name ( p_input ) , current_name ) ) ;
2024-01-07 22:08:10 +01:00
return NodeTimeInfo ( ) ;
2018-06-19 03:10:48 +02:00
}
2018-08-20 18:38:18 +02:00
Ref < AnimationNode > node = blend_tree - > get_node ( node_name ) ;
2024-01-07 22:08:10 +01:00
ERR_FAIL_COND_V ( node . is_null ( ) , NodeTimeInfo ( ) ) ;
2018-06-19 03:10:48 +02:00
2021-08-10 00:15:17 +02:00
real_t activity = 0.0 ;
2023-07-20 17:34:06 +02:00
Vector < AnimationTree : : Activity > * activity_ptr = process_state - > tree - > input_activity_map . getptr ( node_state . base_path ) ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo nti = _blend_node ( node , node_name , nullptr , p_playback_info , p_filter , p_sync , p_test_only , & activity ) ;
2018-08-23 21:44:10 +02:00
2018-08-24 16:50:29 +02:00
if ( activity_ptr & & p_input < activity_ptr - > size ( ) ) {
2023-07-20 17:34:06 +02:00
activity_ptr - > write [ p_input ] . last_pass = process_state - > last_pass ;
2018-08-23 21:44:10 +02:00
activity_ptr - > write [ p_input ] . activity = activity ;
}
2024-01-07 22:08:10 +01:00
return nti ;
2018-06-19 03:10:48 +02:00
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNode : : blend_node ( Ref < AnimationNode > p_node , const StringName & p_subpath , AnimationMixer : : PlaybackInfo p_playback_info , FilterAction p_filter , bool p_sync , bool p_test_only ) {
ERR_FAIL_COND_V ( p_node . is_null ( ) , NodeTimeInfo ( ) ) ;
2023-12-05 16:42:31 +01:00
p_node - > node_state . connections . clear ( ) ;
2023-07-20 17:34:06 +02:00
return _blend_node ( p_node , p_subpath , this , p_playback_info , p_filter , p_sync , p_test_only , nullptr ) ;
2018-06-19 03:10:48 +02:00
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNode : : _blend_node ( Ref < AnimationNode > p_node , const StringName & p_subpath , AnimationNode * p_new_parent , AnimationMixer : : PlaybackInfo p_playback_info , FilterAction p_filter , bool p_sync , bool p_test_only , real_t * r_activity ) {
ERR_FAIL_NULL_V ( process_state , NodeTimeInfo ( ) ) ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
int blend_count = node_state . track_weights . size ( ) ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
if ( p_node - > node_state . track_weights . size ( ) ! = blend_count ) {
p_node - > node_state . track_weights . resize ( blend_count ) ;
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
real_t * blendw = p_node - > node_state . track_weights . ptrw ( ) ;
const real_t * blendr = node_state . track_weights . ptr ( ) ;
2018-06-19 03:10:48 +02:00
bool any_valid = false ;
if ( has_filter ( ) & & is_filter_enabled ( ) & & p_filter ! = FILTER_IGNORE ) {
for ( int i = 0 ; i < blend_count ; i + + ) {
2023-07-20 17:34:06 +02:00
blendw [ i ] = 0.0 ; // All to zero by default.
2018-06-19 03:10:48 +02:00
}
2022-05-08 10:09:19 +02:00
for ( const KeyValue < NodePath , bool > & E : filter ) {
2023-07-20 17:34:06 +02:00
if ( ! process_state - > track_map . has ( E . key ) ) {
2018-06-19 03:10:48 +02:00
continue ;
}
2023-07-20 17:34:06 +02:00
int idx = process_state - > track_map [ E . key ] ;
blendw [ idx ] = 1.0 ; // Filtered goes to one.
2018-06-19 03:10:48 +02:00
}
switch ( p_filter ) {
case FILTER_IGNORE :
2023-07-20 17:34:06 +02:00
break ; // Will not happen anyway.
2018-06-19 03:10:48 +02:00
case FILTER_PASS : {
2023-07-20 17:34:06 +02:00
// Values filtered pass, the rest don't.
2018-06-19 03:10:48 +02:00
for ( int i = 0 ; i < blend_count ; i + + ) {
2023-07-20 17:34:06 +02:00
if ( blendw [ i ] = = 0 ) { // Not filtered, does not pass.
2018-06-19 03:10:48 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
blendw [ i ] = blendr [ i ] * p_playback_info . weight ;
2022-11-23 02:46:01 +01:00
if ( ! Math : : is_zero_approx ( blendw [ i ] ) ) {
2018-06-19 03:10:48 +02:00
any_valid = true ;
}
}
} break ;
case FILTER_STOP : {
2023-07-20 17:34:06 +02:00
// Values filtered don't pass, the rest are blended.
2018-06-19 03:10:48 +02:00
for ( int i = 0 ; i < blend_count ; i + + ) {
2023-07-20 17:34:06 +02:00
if ( blendw [ i ] > 0 ) { // Filtered, does not pass.
2018-06-19 03:10:48 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
blendw [ i ] = blendr [ i ] * p_playback_info . weight ;
2022-11-23 02:46:01 +01:00
if ( ! Math : : is_zero_approx ( blendw [ i ] ) ) {
2018-06-19 03:10:48 +02:00
any_valid = true ;
}
}
} break ;
case FILTER_BLEND : {
2023-07-20 17:34:06 +02:00
// Filtered values are blended, the rest are passed without blending.
2018-06-19 03:10:48 +02:00
for ( int i = 0 ; i < blend_count ; i + + ) {
if ( blendw [ i ] = = 1.0 ) {
2023-07-20 17:34:06 +02:00
blendw [ i ] = blendr [ i ] * p_playback_info . weight ; // Filtered, blend.
2018-06-19 03:10:48 +02:00
} else {
2023-07-20 17:34:06 +02:00
blendw [ i ] = blendr [ i ] ; // Not filtered, do not blend.
2018-06-19 03:10:48 +02:00
}
2022-11-23 02:46:01 +01:00
if ( ! Math : : is_zero_approx ( blendw [ i ] ) ) {
2018-06-19 03:10:48 +02:00
any_valid = true ;
}
}
} break ;
}
} else {
for ( int i = 0 ; i < blend_count ; i + + ) {
2023-07-20 17:34:06 +02:00
// Regular blend.
blendw [ i ] = blendr [ i ] * p_playback_info . weight ;
2022-11-23 02:46:01 +01:00
if ( ! Math : : is_zero_approx ( blendw [ i ] ) ) {
2018-06-19 03:10:48 +02:00
any_valid = true ;
}
}
}
2023-07-20 17:34:06 +02:00
if ( r_activity ) {
* r_activity = 0 ;
2018-06-19 03:10:48 +02:00
for ( int i = 0 ; i < blend_count ; i + + ) {
2023-07-20 17:34:06 +02:00
* r_activity = MAX ( * r_activity , Math : : abs ( blendw [ i ] ) ) ;
2018-06-19 03:10:48 +02:00
}
}
2018-08-20 18:38:18 +02:00
String new_path ;
AnimationNode * new_parent ;
2022-06-10 10:01:07 +02:00
// This is the slowest part of processing, but as strings process in powers of 2, and the paths always exist, it will not result in that many allocations.
2018-08-20 18:38:18 +02:00
if ( p_new_parent ) {
new_parent = p_new_parent ;
2023-07-20 17:34:06 +02:00
new_path = String ( node_state . base_path ) + String ( p_subpath ) + " / " ;
2018-08-20 18:38:18 +02:00
} else {
2024-01-07 22:08:10 +01:00
ERR_FAIL_NULL_V ( node_state . parent , NodeTimeInfo ( ) ) ;
2023-07-20 17:34:06 +02:00
new_parent = node_state . parent ;
new_path = String ( new_parent - > node_state . base_path ) + String ( p_subpath ) + " / " ;
2018-08-20 18:38:18 +02:00
}
2022-03-15 17:35:25 +01:00
2022-11-15 07:06:10 +01:00
// This process, which depends on p_sync is needed to process sync correctly in the case of
// that a synced AnimationNodeSync exists under the un-synced AnimationNodeSync.
2023-07-20 17:34:06 +02:00
p_node - > node_state . base_path = new_path ;
p_node - > node_state . parent = new_parent ;
if ( ! p_playback_info . seeked & & ! p_sync & & ! any_valid ) {
2024-01-07 22:08:10 +01:00
p_playback_info . delta = 0.0 ;
2023-12-05 16:42:31 +01:00
return p_node - > _pre_process ( process_state , p_playback_info , p_test_only ) ;
2022-03-15 17:35:25 +01:00
}
2023-12-05 16:42:31 +01:00
return p_node - > _pre_process ( process_state , p_playback_info , p_test_only ) ;
2018-06-19 03:10:48 +02:00
}
String AnimationNode : : get_caption ( ) const {
2022-10-18 18:47:44 +02:00
String ret = " Node " ;
GDVIRTUAL_CALL ( _get_caption , ret ) ;
return ret ;
2018-06-19 03:10:48 +02:00
}
2023-01-29 15:54:13 +01:00
bool AnimationNode : : add_input ( const String & p_name ) {
2023-07-20 17:34:06 +02:00
// Root nodes can't add inputs.
2023-01-29 15:54:13 +01:00
ERR_FAIL_COND_V ( Object : : cast_to < AnimationRootNode > ( this ) ! = nullptr , false ) ;
2018-06-19 03:10:48 +02:00
Input input ;
2023-01-29 15:54:13 +01:00
ERR_FAIL_COND_V ( p_name . contains ( " . " ) | | p_name . contains ( " / " ) , false ) ;
2018-06-19 03:10:48 +02:00
input . name = p_name ;
inputs . push_back ( input ) ;
emit_changed ( ) ;
2023-01-29 15:54:13 +01:00
return true ;
2018-06-19 03:10:48 +02:00
}
void AnimationNode : : remove_input ( int p_index ) {
ERR_FAIL_INDEX ( p_index , inputs . size ( ) ) ;
2021-07-04 00:17:03 +02:00
inputs . remove_at ( p_index ) ;
2018-06-19 03:10:48 +02:00
emit_changed ( ) ;
}
2023-01-29 15:54:13 +01:00
bool AnimationNode : : set_input_name ( int p_input , const String & p_name ) {
ERR_FAIL_INDEX_V ( p_input , inputs . size ( ) , false ) ;
ERR_FAIL_COND_V ( p_name . contains ( " . " ) | | p_name . contains ( " / " ) , false ) ;
inputs . write [ p_input ] . name = p_name ;
emit_changed ( ) ;
return true ;
}
String AnimationNode : : get_input_name ( int p_input ) const {
ERR_FAIL_INDEX_V ( p_input , inputs . size ( ) , String ( ) ) ;
return inputs [ p_input ] . name ;
}
int AnimationNode : : get_input_count ( ) const {
return inputs . size ( ) ;
}
int AnimationNode : : find_input ( const String & p_name ) const {
int idx = - 1 ;
for ( int i = 0 ; i < inputs . size ( ) ; i + + ) {
if ( inputs [ i ] . name = = p_name ) {
idx = i ;
break ;
}
}
return idx ;
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNode : : process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
2023-07-20 17:34:06 +02:00
process_state - > is_testing = p_test_only ;
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 + p_playback_info . delta ;
}
NodeTimeInfo nti = _process ( pi , p_test_only ) ;
if ( ! p_test_only ) {
set_node_time_info ( nti ) ;
}
return nti ;
2023-02-18 03:02:28 +01:00
}
2024-01-07 22:08:10 +01:00
AnimationNode : : NodeTimeInfo AnimationNode : : _process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only ) {
double r_ret = 0.0 ;
GDVIRTUAL_CALL ( _process , p_playback_info . time , p_playback_info . seeked , p_playback_info . is_external_seeking , p_test_only , r_ret ) ;
NodeTimeInfo nti ;
nti . delta = r_ret ;
return nti ;
2018-06-19 03:10:48 +02:00
}
void AnimationNode : : set_filter_path ( const NodePath & p_path , bool p_enable ) {
if ( p_enable ) {
filter [ p_path ] = true ;
} else {
filter . erase ( p_path ) ;
}
}
void AnimationNode : : set_filter_enabled ( bool p_enable ) {
filter_enabled = p_enable ;
}
bool AnimationNode : : is_filter_enabled ( ) const {
return filter_enabled ;
}
2024-02-07 02:37:26 +01:00
void AnimationNode : : set_deletable ( bool p_closable ) {
2023-08-09 18:31:15 +02:00
closable = p_closable ;
}
2024-02-07 02:37:26 +01:00
bool AnimationNode : : is_deletable ( ) const {
2023-08-09 18:31:15 +02:00
return closable ;
}
2018-06-19 03:10:48 +02:00
bool AnimationNode : : is_path_filtered ( const NodePath & p_path ) const {
return filter . has ( p_path ) ;
}
bool AnimationNode : : has_filter ( ) const {
2022-10-18 18:47:44 +02:00
bool ret = false ;
GDVIRTUAL_CALL ( _has_filter , ret ) ;
return ret ;
2018-06-19 03:10:48 +02:00
}
Array AnimationNode : : _get_filters ( ) const {
Array paths ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < NodePath , bool > & E : filter ) {
2023-07-20 17:34:06 +02:00
paths . push_back ( String ( E . key ) ) ; // Use strings, so sorting is possible.
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
paths . sort ( ) ; // Done so every time the scene is saved, it does not change.
2018-06-19 03:10:48 +02:00
return paths ;
}
2020-05-14 14:29:06 +02:00
2018-06-19 03:10:48 +02:00
void AnimationNode : : _set_filters ( const Array & p_filters ) {
filter . clear ( ) ;
for ( int i = 0 ; i < p_filters . size ( ) ; i + + ) {
set_filter_path ( p_filters [ i ] , true ) ;
}
}
2022-08-12 22:57:11 +02:00
void AnimationNode : : _validate_property ( PropertyInfo & p_property ) const {
if ( ! has_filter ( ) & & ( p_property . name = = " filter_enabled " | | p_property . name = = " filters " ) ) {
p_property . usage = PROPERTY_USAGE_NONE ;
2018-06-19 03:10:48 +02:00
}
}
2023-02-18 03:02:28 +01:00
Ref < AnimationNode > AnimationNode : : get_child_by_name ( const StringName & p_name ) const {
2021-08-22 03:52:44 +02:00
Ref < AnimationNode > ret ;
2022-10-18 18:47:44 +02:00
GDVIRTUAL_CALL ( _get_child_by_name , p_name , ret ) ;
return ret ;
2018-08-20 18:38:18 +02:00
}
2023-02-18 03:02:28 +01:00
Ref < AnimationNode > AnimationNode : : find_node_by_path ( const String & p_name ) const {
Vector < String > split = p_name . split ( " / " ) ;
Ref < AnimationNode > ret = const_cast < AnimationNode * > ( this ) ;
for ( int i = 0 ; i < split . size ( ) ; i + + ) {
ret = ret - > get_child_by_name ( split [ i ] ) ;
if ( ! ret . is_valid ( ) ) {
break ;
}
}
return ret ;
}
2023-07-20 17:34:06 +02:00
void AnimationNode : : blend_animation_ex ( const StringName & p_animation , double p_time , double p_delta , bool p_seeked , bool p_is_external_seeking , real_t p_blend , Animation : : LoopedFlag p_looped_flag ) {
AnimationMixer : : PlaybackInfo info ;
info . time = p_time ;
info . delta = p_delta ;
info . seeked = p_seeked ;
info . is_external_seeking = p_is_external_seeking ;
info . weight = p_blend ;
info . looped_flag = p_looped_flag ;
blend_animation ( p_animation , info ) ;
}
double AnimationNode : : blend_node_ex ( const StringName & p_sub_path , Ref < AnimationNode > p_node , double p_time , bool p_seek , bool p_is_external_seeking , real_t p_blend , FilterAction p_filter , bool p_sync , bool p_test_only ) {
AnimationMixer : : PlaybackInfo info ;
info . time = p_time ;
info . seeked = p_seek ;
info . is_external_seeking = p_is_external_seeking ;
info . weight = p_blend ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo nti = blend_node ( p_node , p_sub_path , info , p_filter , p_sync , p_test_only ) ;
return nti . length - nti . position ;
2023-07-20 17:34:06 +02:00
}
double AnimationNode : : blend_input_ex ( int p_input , double p_time , bool p_seek , bool p_is_external_seeking , real_t p_blend , FilterAction p_filter , bool p_sync , bool p_test_only ) {
AnimationMixer : : PlaybackInfo info ;
info . time = p_time ;
info . seeked = p_seek ;
info . is_external_seeking = p_is_external_seeking ;
info . weight = p_blend ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo nti = blend_input ( p_input , info , p_filter , p_sync , p_test_only ) ;
return nti . length - nti . position ;
2023-07-20 17:34:06 +02:00
}
2024-01-06 17:23:25 +01:00
# ifdef TOOLS_ENABLED
void AnimationNode : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
const String pf = p_function ;
if ( p_idx = = 0 ) {
if ( pf = = " find_input " ) {
for ( const AnimationNode : : Input & E : inputs ) {
r_options - > push_back ( E . name . quote ( ) ) ;
}
} else if ( pf = = " get_parameter " | | pf = = " set_parameter " ) {
bool is_setter = pf = = " set_parameter " ;
List < PropertyInfo > parameters ;
get_parameter_list ( & parameters ) ;
for ( const PropertyInfo & E : parameters ) {
if ( is_setter & & is_parameter_read_only ( E . name ) ) {
continue ;
}
r_options - > push_back ( E . name . quote ( ) ) ;
}
} else if ( pf = = " set_filter_path " | | pf = = " is_path_filtered " ) {
for ( const KeyValue < NodePath , bool > & E : filter ) {
r_options - > push_back ( String ( E . key ) . quote ( ) ) ;
}
}
}
Resource : : get_argument_options ( p_function , p_idx , r_options ) ;
}
# endif
2018-06-19 03:10:48 +02:00
void AnimationNode : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " add_input " , " name " ) , & AnimationNode : : add_input ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_input " , " index " ) , & AnimationNode : : remove_input ) ;
2023-01-29 15:54:13 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_input_name " , " input " , " name " ) , & AnimationNode : : set_input_name ) ;
ClassDB : : bind_method ( D_METHOD ( " get_input_name " , " input " ) , & AnimationNode : : get_input_name ) ;
ClassDB : : bind_method ( D_METHOD ( " get_input_count " ) , & AnimationNode : : get_input_count ) ;
ClassDB : : bind_method ( D_METHOD ( " find_input " , " name " ) , & AnimationNode : : find_input ) ;
2018-06-19 03:10:48 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_filter_path " , " path " , " enable " ) , & AnimationNode : : set_filter_path ) ;
ClassDB : : bind_method ( D_METHOD ( " is_path_filtered " , " path " ) , & AnimationNode : : is_path_filtered ) ;
ClassDB : : bind_method ( D_METHOD ( " set_filter_enabled " , " enable " ) , & AnimationNode : : set_filter_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_filter_enabled " ) , & AnimationNode : : is_filter_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " _set_filters " , " filters " ) , & AnimationNode : : _set_filters ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_filters " ) , & AnimationNode : : _get_filters ) ;
2023-07-20 17:34:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " blend_animation " , " animation " , " time " , " delta " , " seeked " , " is_external_seeking " , " blend " , " looped_flag " ) , & AnimationNode : : blend_animation_ex , DEFVAL ( Animation : : LOOPED_FLAG_NONE ) ) ;
ClassDB : : bind_method ( D_METHOD ( " blend_node " , " name " , " node " , " time " , " seek " , " is_external_seeking " , " blend " , " filter " , " sync " , " test_only " ) , & AnimationNode : : blend_node_ex , DEFVAL ( FILTER_IGNORE ) , DEFVAL ( true ) , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " blend_input " , " input_index " , " time " , " seek " , " is_external_seeking " , " blend " , " filter " , " sync " , " test_only " ) , & AnimationNode : : blend_input_ex , DEFVAL ( FILTER_IGNORE ) , DEFVAL ( true ) , DEFVAL ( false ) ) ;
2018-06-19 03:10:48 +02:00
2018-08-21 21:28:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_parameter " , " name " , " value " ) , & AnimationNode : : set_parameter ) ;
ClassDB : : bind_method ( D_METHOD ( " get_parameter " , " name " ) , & AnimationNode : : get_parameter ) ;
2018-06-27 08:00:08 +02:00
2021-11-03 23:06:17 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " filter_enabled " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR ) , " set_filter_enabled " , " is_filter_enabled " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : ARRAY , " filters " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) , " _set_filters " , " _get_filters " ) ;
2018-06-19 03:10:48 +02:00
2021-08-22 03:52:44 +02:00
GDVIRTUAL_BIND ( _get_child_nodes ) ;
GDVIRTUAL_BIND ( _get_parameter_list ) ;
GDVIRTUAL_BIND ( _get_child_by_name , " name " ) ;
GDVIRTUAL_BIND ( _get_parameter_default_value , " parameter " ) ;
2023-01-12 13:51:03 +01:00
GDVIRTUAL_BIND ( _is_parameter_read_only , " parameter " ) ;
2023-02-18 03:02:28 +01:00
GDVIRTUAL_BIND ( _process , " time " , " seek " , " is_external_seeking " , " test_only " ) ;
2021-08-22 03:52:44 +02:00
GDVIRTUAL_BIND ( _get_caption ) ;
GDVIRTUAL_BIND ( _has_filter ) ;
2018-06-19 03:10:48 +02:00
2018-08-20 18:38:18 +02:00
ADD_SIGNAL ( MethodInfo ( " tree_changed " ) ) ;
2023-02-04 16:29:34 +01:00
ADD_SIGNAL ( MethodInfo ( " animation_node_renamed " , PropertyInfo ( Variant : : INT , " object_id " ) , PropertyInfo ( Variant : : STRING , " old_name " ) , PropertyInfo ( Variant : : STRING , " new_name " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " animation_node_removed " , PropertyInfo ( Variant : : INT , " object_id " ) , PropertyInfo ( Variant : : STRING , " name " ) ) ) ;
2018-08-20 18:38:18 +02:00
2018-06-19 03:10:48 +02:00
BIND_ENUM_CONSTANT ( FILTER_IGNORE ) ;
BIND_ENUM_CONSTANT ( FILTER_PASS ) ;
BIND_ENUM_CONSTANT ( FILTER_STOP ) ;
BIND_ENUM_CONSTANT ( FILTER_BLEND ) ;
}
AnimationNode : : AnimationNode ( ) {
}
////////////////////
2023-02-04 16:29:34 +01:00
void AnimationRootNode : : _tree_changed ( ) {
emit_signal ( SNAME ( " tree_changed " ) ) ;
}
void AnimationRootNode : : _animation_node_renamed ( const ObjectID & p_oid , const String & p_old_name , const String & p_new_name ) {
emit_signal ( SNAME ( " animation_node_renamed " ) , p_oid , p_old_name , p_new_name ) ;
}
void AnimationRootNode : : _animation_node_removed ( const ObjectID & p_oid , const StringName & p_node ) {
emit_signal ( SNAME ( " animation_node_removed " ) , p_oid , p_node ) ;
}
////////////////////
2023-07-20 17:34:06 +02:00
void AnimationTree : : set_root_animation_node ( const Ref < AnimationRootNode > & p_animation_node ) {
if ( root_animation_node . is_valid ( ) ) {
root_animation_node - > disconnect ( SNAME ( " tree_changed " ) , callable_mp ( this , & AnimationTree : : _tree_changed ) ) ;
root_animation_node - > disconnect ( SNAME ( " animation_node_renamed " ) , callable_mp ( this , & AnimationTree : : _animation_node_renamed ) ) ;
root_animation_node - > disconnect ( SNAME ( " animation_node_removed " ) , callable_mp ( this , & AnimationTree : : _animation_node_removed ) ) ;
2018-06-19 03:10:48 +02:00
}
2018-08-20 18:38:18 +02:00
2023-07-20 17:34:06 +02:00
root_animation_node = p_animation_node ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
if ( root_animation_node . is_valid ( ) ) {
root_animation_node - > connect ( SNAME ( " tree_changed " ) , callable_mp ( this , & AnimationTree : : _tree_changed ) ) ;
root_animation_node - > connect ( SNAME ( " animation_node_renamed " ) , callable_mp ( this , & AnimationTree : : _animation_node_renamed ) ) ;
root_animation_node - > connect ( SNAME ( " animation_node_removed " ) , callable_mp ( this , & AnimationTree : : _animation_node_removed ) ) ;
2018-06-19 03:10:48 +02:00
}
2018-08-21 21:28:06 +02:00
properties_dirty = true ;
2018-08-20 18:38:18 +02:00
2020-10-29 11:01:28 +01:00
update_configuration_warnings ( ) ;
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
Ref < AnimationRootNode > AnimationTree : : get_root_animation_node ( ) const {
return root_animation_node ;
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
bool AnimationTree : : _blend_pre_process ( double p_delta , int p_track_count , const HashMap < NodePath , int > & p_track_map ) {
_update_properties ( ) ; // If properties need updating, update them.
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
if ( ! root_animation_node . is_valid ( ) ) {
2018-06-19 03:10:48 +02:00
return false ;
}
2023-07-20 17:34:06 +02:00
{ // Setup.
2018-06-19 03:10:48 +02:00
process_pass + + ;
2023-07-20 17:34:06 +02:00
// Init process state.
process_state = AnimationNode : : ProcessState ( ) ;
process_state . tree = this ;
process_state . valid = true ;
process_state . invalid_reasons = " " ;
process_state . last_pass = process_pass ;
process_state . track_map = p_track_map ;
// Init node state for root AnimationNode.
root_animation_node - > node_state . track_weights . resize ( p_track_count ) ;
real_t * src_blendsw = root_animation_node - > node_state . track_weights . ptrw ( ) ;
for ( int i = 0 ; i < p_track_count ; i + + ) {
src_blendsw [ i ] = 1.0 ; // By default all go to 1 for the root input.
2018-06-19 03:10:48 +02:00
}
2024-05-14 13:28:56 +02:00
root_animation_node - > node_state . base_path = SNAME ( Animation : : PARAMETERS_BASE_PATH . ascii ( ) . get_data ( ) ) ;
2023-07-20 17:34:06 +02:00
root_animation_node - > node_state . parent = nullptr ;
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
// Process.
2018-06-19 03:10:48 +02:00
{
2023-07-20 17:34:06 +02:00
PlaybackInfo pi ;
2018-06-19 03:10:48 +02:00
if ( started ) {
2023-07-20 17:34:06 +02:00
// If started, seek.
pi . seeked = true ;
2024-01-07 22:08:10 +01:00
pi . delta = p_delta ;
2023-12-05 16:42:31 +01:00
root_animation_node - > _pre_process ( & process_state , pi , false ) ;
2018-06-19 03:10:48 +02:00
started = false ;
2023-12-30 17:20:44 +01:00
} else {
pi . seeked = false ;
2024-01-07 22:08:10 +01:00
pi . delta = p_delta ;
2023-12-30 17:20:44 +01:00
root_animation_node - > _pre_process ( & process_state , pi , false ) ;
2018-06-19 03:10:48 +02:00
}
2022-09-01 16:00:55 +02:00
}
2023-07-20 17:34:06 +02:00
if ( ! process_state . valid ) {
return false ; // State is not valid, abort process.
2022-09-01 16:00:55 +02:00
}
2023-07-20 17:34:06 +02:00
return true ;
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
void AnimationTree : : _set_active ( bool p_active ) {
_set_process ( p_active ) ;
started = p_active ;
2018-06-19 03:10:48 +02:00
}
2023-07-20 17:34:06 +02:00
void AnimationTree : : set_advance_expression_base_node ( const NodePath & p_path ) {
advance_expression_base_node = p_path ;
2022-04-20 12:36:54 +02:00
}
NodePath AnimationTree : : get_advance_expression_base_node ( ) const {
return advance_expression_base_node ;
}
2018-06-25 23:40:24 +02:00
bool AnimationTree : : is_state_invalid ( ) const {
2023-07-20 17:34:06 +02:00
return ! process_state . valid ;
2018-06-19 03:10:48 +02:00
}
2020-05-14 14:29:06 +02:00
2018-06-25 23:40:24 +02:00
String AnimationTree : : get_invalid_state_reason ( ) const {
2023-07-20 17:34:06 +02:00
return process_state . invalid_reasons ;
2018-06-19 03:10:48 +02:00
}
2018-06-25 23:40:24 +02:00
uint64_t AnimationTree : : get_last_process_pass ( ) const {
2018-06-19 03:10:48 +02:00
return process_pass ;
}
2024-02-17 19:03:21 +01:00
PackedStringArray AnimationTree : : get_configuration_warnings ( ) const {
PackedStringArray warnings = Node : : get_configuration_warnings ( ) ;
2023-07-20 17:34:06 +02:00
if ( ! root_animation_node . is_valid ( ) ) {
2022-03-28 15:24:14 +02:00
warnings . push_back ( RTR ( " No root AnimationNode for the graph is set. " ) ) ;
2018-06-19 03:10:48 +02:00
}
2020-10-29 11:01:28 +01:00
return warnings ;
2018-06-19 03:10:48 +02:00
}
2018-08-20 18:38:18 +02:00
void AnimationTree : : _tree_changed ( ) {
if ( properties_dirty ) {
return ;
}
2023-12-18 15:46:56 +01:00
callable_mp ( this , & AnimationTree : : _update_properties ) . call_deferred ( ) ;
2018-08-21 21:28:06 +02:00
properties_dirty = true ;
2018-08-20 18:38:18 +02:00
}
2023-02-04 16:29:34 +01:00
void AnimationTree : : _animation_node_renamed ( const ObjectID & p_oid , const String & p_old_name , const String & p_new_name ) {
ERR_FAIL_COND ( ! property_reference_map . has ( p_oid ) ) ;
String base_path = property_reference_map [ p_oid ] ;
String old_base = base_path + p_old_name ;
String new_base = base_path + p_new_name ;
for ( const PropertyInfo & E : properties ) {
if ( E . name . begins_with ( old_base ) ) {
String new_name = E . name . replace_first ( old_base , new_base ) ;
property_map [ new_name ] = property_map [ E . name ] ;
property_map . erase ( E . name ) ;
}
}
2023-07-20 17:34:06 +02:00
// Update tree second.
2023-02-04 16:29:34 +01:00
properties_dirty = true ;
_update_properties ( ) ;
}
void AnimationTree : : _animation_node_removed ( const ObjectID & p_oid , const StringName & p_node ) {
ERR_FAIL_COND ( ! property_reference_map . has ( p_oid ) ) ;
String base_path = String ( property_reference_map [ p_oid ] ) + String ( p_node ) ;
for ( const PropertyInfo & E : properties ) {
if ( E . name . begins_with ( base_path ) ) {
property_map . erase ( E . name ) ;
}
}
2023-07-20 17:34:06 +02:00
// Update tree second.
2023-02-04 16:29:34 +01:00
properties_dirty = true ;
_update_properties ( ) ;
}
2023-07-20 17:34:06 +02:00
void AnimationTree : : _update_properties_for_node ( const String & p_base_path , Ref < AnimationNode > p_node ) {
ERR_FAIL_COND ( p_node . is_null ( ) ) ;
2018-08-20 18:38:18 +02:00
if ( ! property_parent_map . has ( p_base_path ) ) {
2018-08-21 21:28:06 +02:00
property_parent_map [ p_base_path ] = HashMap < StringName , StringName > ( ) ;
2018-08-20 18:38:18 +02:00
}
2023-07-20 17:34:06 +02:00
if ( ! property_reference_map . has ( p_node - > get_instance_id ( ) ) ) {
property_reference_map [ p_node - > get_instance_id ( ) ] = p_base_path ;
2023-02-04 16:29:34 +01:00
}
2018-08-20 18:38:18 +02:00
2023-07-20 17:34:06 +02:00
if ( p_node - > get_input_count ( ) & & ! input_activity_map . has ( p_base_path ) ) {
2018-08-23 21:44:10 +02:00
Vector < Activity > activity ;
2023-07-20 17:34:06 +02:00
for ( int i = 0 ; i < p_node - > get_input_count ( ) ; i + + ) {
2018-08-23 21:44:10 +02:00
Activity a ;
2019-08-27 17:13:08 +02:00
a . activity = 0 ;
2018-08-24 16:50:29 +02:00
a . last_pass = 0 ;
2018-08-23 21:44:10 +02:00
activity . push_back ( a ) ;
}
input_activity_map [ p_base_path ] = activity ;
2018-08-24 16:50:29 +02:00
input_activity_map_get [ String ( p_base_path ) . substr ( 0 , String ( p_base_path ) . length ( ) - 1 ) ] = & input_activity_map [ p_base_path ] ;
2018-08-23 21:44:10 +02:00
}
2018-08-20 18:38:18 +02:00
List < PropertyInfo > plist ;
2023-07-20 17:34:06 +02:00
p_node - > get_parameter_list ( & plist ) ;
2021-07-16 05:45:57 +02:00
for ( PropertyInfo & pinfo : plist ) {
2018-08-20 18:38:18 +02:00
StringName key = pinfo . name ;
2018-08-21 21:28:06 +02:00
if ( ! property_map . has ( p_base_path + key ) ) {
2023-01-12 13:51:03 +01:00
Pair < Variant , bool > param ;
2023-07-20 17:34:06 +02:00
param . first = p_node - > get_parameter_default_value ( key ) ;
param . second = p_node - > is_parameter_read_only ( key ) ;
2023-01-12 13:51:03 +01:00
property_map [ p_base_path + key ] = param ;
2018-08-20 18:38:18 +02:00
}
2018-08-21 21:28:06 +02:00
property_parent_map [ p_base_path ] [ key ] = p_base_path + key ;
2018-08-20 18:38:18 +02:00
pinfo . name = p_base_path + key ;
properties . push_back ( pinfo ) ;
}
List < AnimationNode : : ChildNode > children ;
2023-07-20 17:34:06 +02:00
p_node - > get_child_nodes ( & children ) ;
2018-08-20 18:38:18 +02:00
2021-07-24 15:46:25 +02:00
for ( const AnimationNode : : ChildNode & E : children ) {
2021-07-16 05:45:57 +02:00
_update_properties_for_node ( p_base_path + E . name + " / " , E . node ) ;
2018-08-20 18:38:18 +02:00
}
}
void AnimationTree : : _update_properties ( ) {
if ( ! properties_dirty ) {
return ;
}
properties . clear ( ) ;
2023-02-04 16:29:34 +01:00
property_reference_map . clear ( ) ;
2018-08-20 18:38:18 +02:00
property_parent_map . clear ( ) ;
2018-08-23 21:44:10 +02:00
input_activity_map . clear ( ) ;
input_activity_map_get . clear ( ) ;
2018-08-20 18:38:18 +02:00
2023-07-20 17:34:06 +02:00
if ( root_animation_node . is_valid ( ) ) {
2024-05-14 13:28:56 +02:00
_update_properties_for_node ( Animation : : PARAMETERS_BASE_PATH , root_animation_node ) ;
2018-08-20 18:38:18 +02:00
}
properties_dirty = false ;
2021-02-10 21:18:45 +01:00
notify_property_list_changed ( ) ;
2018-08-20 18:38:18 +02:00
}
2023-07-20 17:34:06 +02:00
void AnimationTree : : _notification ( int p_what ) {
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
_setup_animation_player ( ) ;
if ( active ) {
_set_process ( true ) ;
}
} break ;
}
}
void AnimationTree : : set_animation_player ( const NodePath & p_path ) {
animation_player = p_path ;
if ( p_path . is_empty ( ) ) {
2023-09-04 17:01:33 +02:00
set_root_node ( SceneStringName ( path_pp ) ) ;
2023-07-20 17:34:06 +02:00
while ( animation_libraries . size ( ) ) {
remove_animation_library ( animation_libraries [ 0 ] . name ) ;
}
}
emit_signal ( SNAME ( " animation_player_changed " ) ) ; // Needs to unpin AnimationPlayerEditor.
_setup_animation_player ( ) ;
notify_property_list_changed ( ) ;
}
NodePath AnimationTree : : get_animation_player ( ) const {
return animation_player ;
}
void AnimationTree : : _setup_animation_player ( ) {
if ( ! is_inside_tree ( ) ) {
return ;
}
cache_valid = false ;
if ( animation_player . is_empty ( ) ) {
clear_caches ( ) ;
return ;
}
2023-11-07 16:31:32 +01:00
// Using AnimationPlayer here is for compatibility. Changing to AnimationMixer needs extra work like error handling.
AnimationPlayer * player = Object : : cast_to < AnimationPlayer > ( get_node_or_null ( animation_player ) ) ;
if ( player ) {
if ( ! player - > is_connected ( SNAME ( " caches_cleared " ) , callable_mp ( this , & AnimationTree : : _setup_animation_player ) ) ) {
player - > connect ( SNAME ( " caches_cleared " ) , callable_mp ( this , & AnimationTree : : _setup_animation_player ) , CONNECT_DEFERRED ) ;
2023-07-20 17:34:06 +02:00
}
2023-11-07 16:31:32 +01:00
if ( ! player - > is_connected ( SNAME ( " animation_list_changed " ) , callable_mp ( this , & AnimationTree : : _setup_animation_player ) ) ) {
player - > connect ( SNAME ( " animation_list_changed " ) , callable_mp ( this , & AnimationTree : : _setup_animation_player ) , CONNECT_DEFERRED ) ;
2023-07-20 17:34:06 +02:00
}
2023-11-07 16:31:32 +01:00
Node * root = player - > get_node_or_null ( player - > get_root_node ( ) ) ;
2023-07-20 17:34:06 +02:00
if ( root ) {
set_root_node ( get_path_to ( root , true ) ) ;
}
while ( animation_libraries . size ( ) ) {
remove_animation_library ( animation_libraries [ 0 ] . name ) ;
}
List < StringName > list ;
2023-11-07 16:31:32 +01:00
player - > get_animation_library_list ( & list ) ;
2024-04-15 15:18:34 +02:00
for ( const StringName & E : list ) {
Ref < AnimationLibrary > lib = player - > get_animation_library ( E ) ;
2023-07-20 17:34:06 +02:00
if ( lib . is_valid ( ) ) {
2024-04-15 15:18:34 +02:00
add_animation_library ( E , lib ) ;
2023-07-20 17:34:06 +02:00
}
}
}
clear_caches ( ) ;
}
void AnimationTree : : _validate_property ( PropertyInfo & p_property ) const {
AnimationMixer : : _validate_property ( p_property ) ;
if ( ! animation_player . is_empty ( ) ) {
if ( p_property . name = = " root_node " | | p_property . name . begins_with ( " libraries " ) ) {
p_property . usage | = PROPERTY_USAGE_READ_ONLY ;
}
2023-11-30 20:50:58 +01:00
if ( p_property . name . begins_with ( " libraries " ) ) {
p_property . usage & = ~ PROPERTY_USAGE_STORAGE ;
}
2023-07-20 17:34:06 +02:00
}
}
2018-08-20 18:38:18 +02:00
bool AnimationTree : : _set ( const StringName & p_name , const Variant & p_value ) {
2023-07-20 17:34:06 +02:00
# ifndef DISABLE_DEPRECATED
String name = p_name ;
if ( name = = " process_callback " ) {
set_callback_mode_process ( static_cast < AnimationCallbackModeProcess > ( ( int ) p_value ) ) ;
return true ;
}
# endif // DISABLE_DEPRECATED
2018-08-20 18:38:18 +02:00
if ( properties_dirty ) {
_update_properties ( ) ;
}
if ( property_map . has ( p_name ) ) {
2023-01-12 13:51:03 +01:00
if ( is_inside_tree ( ) & & property_map [ p_name ] . second ) {
return false ; // Prevent to set property by user.
}
property_map [ p_name ] . first = p_value ;
2018-08-20 18:38:18 +02:00
return true ;
}
return false ;
}
bool AnimationTree : : _get ( const StringName & p_name , Variant & r_ret ) const {
2023-07-20 17:34:06 +02:00
# ifndef DISABLE_DEPRECATED
if ( p_name = = " process_callback " ) {
r_ret = get_callback_mode_process ( ) ;
return true ;
}
# endif // DISABLE_DEPRECATED
2018-08-20 18:38:18 +02:00
if ( properties_dirty ) {
2018-08-21 21:28:06 +02:00
const_cast < AnimationTree * > ( this ) - > _update_properties ( ) ;
2018-08-20 18:38:18 +02:00
}
if ( property_map . has ( p_name ) ) {
2023-01-12 13:51:03 +01:00
r_ret = property_map [ p_name ] . first ;
2018-08-20 18:38:18 +02:00
return true ;
}
return false ;
}
2020-05-14 14:29:06 +02:00
2018-08-20 18:38:18 +02:00
void AnimationTree : : _get_property_list ( List < PropertyInfo > * p_list ) const {
if ( properties_dirty ) {
2018-08-21 21:28:06 +02:00
const_cast < AnimationTree * > ( this ) - > _update_properties ( ) ;
2018-08-20 18:38:18 +02:00
}
2021-07-16 05:45:57 +02:00
for ( const PropertyInfo & E : properties ) {
p_list - > push_back ( E ) ;
2018-08-20 18:38:18 +02:00
}
}
2021-08-10 00:15:17 +02:00
real_t AnimationTree : : get_connection_activity ( const StringName & p_path , int p_connection ) const {
2018-08-23 21:44:10 +02:00
if ( ! input_activity_map_get . has ( p_path ) ) {
return 0 ;
}
const Vector < Activity > * activity = input_activity_map_get [ p_path ] ;
2018-08-24 16:50:29 +02:00
if ( ! activity | | p_connection < 0 | | p_connection > = activity - > size ( ) ) {
2018-08-23 21:44:10 +02:00
return 0 ;
}
if ( ( * activity ) [ p_connection ] . last_pass ! = process_pass ) {
return 0 ;
}
return ( * activity ) [ p_connection ] . activity ;
}
2018-06-25 23:40:24 +02:00
void AnimationTree : : _bind_methods ( ) {
2023-07-20 17:34:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_tree_root " , " animation_node " ) , & AnimationTree : : set_root_animation_node ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tree_root " ) , & AnimationTree : : get_root_animation_node ) ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_advance_expression_base_node " , " path " ) , & AnimationTree : : set_advance_expression_base_node ) ;
2022-04-20 12:36:54 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_advance_expression_base_node " ) , & AnimationTree : : get_advance_expression_base_node ) ;
2023-07-20 17:34:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_animation_player " , " path " ) , & AnimationTree : : set_animation_player ) ;
ClassDB : : bind_method ( D_METHOD ( " get_animation_player " ) , & AnimationTree : : get_animation_player ) ;
2018-06-29 14:13:20 +02:00
2018-08-20 18:38:18 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " tree_root " , PROPERTY_HINT_RESOURCE_TYPE , " AnimationRootNode " ) , " set_tree_root " , " get_tree_root " ) ;
2022-04-20 12:36:54 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : NODE_PATH , " advance_expression_base_node " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " Node " ) , " set_advance_expression_base_node " , " get_advance_expression_base_node " ) ;
2023-07-20 17:34:06 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : NODE_PATH , " anim_player " , PROPERTY_HINT_NODE_PATH_VALID_TYPES , " AnimationPlayer " ) , " set_animation_player " , " get_animation_player " ) ;
2022-04-20 12:36:54 +02:00
2023-07-20 17:34:06 +02:00
ADD_SIGNAL ( MethodInfo ( SNAME ( " animation_player_changed " ) ) ) ;
2018-06-19 03:10:48 +02:00
}
2018-06-25 23:40:24 +02:00
AnimationTree : : AnimationTree ( ) {
2023-07-20 17:34:06 +02:00
deterministic = true ;
2023-12-30 07:26:17 +01:00
callback_mode_discrete = ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS ;
2018-06-19 03:10:48 +02:00
}
2018-06-25 23:40:24 +02:00
AnimationTree : : ~ AnimationTree ( ) {
2018-06-19 03:10:48 +02:00
}