2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* animation_tree.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-08-29 22:38:13 +02:00
2022-07-23 23:41:51 +02:00
# ifndef ANIMATION_TREE_H
# define ANIMATION_TREE_H
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
# include "animation_mixer.h"
2018-06-19 03:10:48 +02:00
# include "scene/resources/animation.h"
2023-07-20 17:34:06 +02:00
# define HUGE_LENGTH 31540000 // 31540000 seconds mean 1 year... is it too long? It must be longer than any Animation length and Transition xfade time to prevent time inversion for AnimationNodeStateMachine.
2023-02-18 03:02:28 +01:00
2018-06-19 03:10:48 +02:00
class AnimationNodeBlendTree ;
2018-12-16 15:43:20 +01:00
class AnimationNodeStartState ;
class AnimationNodeEndState ;
2018-06-25 23:40:24 +02:00
class AnimationTree ;
2018-06-19 03:10:48 +02:00
class AnimationNode : public Resource {
2019-03-19 19:35:57 +01:00
GDCLASS ( AnimationNode , Resource ) ;
2018-06-19 03:10:48 +02:00
public :
2023-07-20 17:34:06 +02:00
friend class AnimationTree ;
2018-06-19 03:10:48 +02:00
enum FilterAction {
FILTER_IGNORE ,
FILTER_PASS ,
FILTER_STOP ,
FILTER_BLEND
} ;
struct Input {
String name ;
} ;
2023-07-20 17:34:06 +02:00
bool closable = false ;
2018-06-19 03:10:48 +02:00
Vector < Input > inputs ;
2023-07-20 17:34:06 +02:00
HashMap < NodePath , bool > filter ;
bool filter_enabled = false ;
2018-06-19 03:10:48 +02:00
2024-01-07 22:08:10 +01:00
// To propagate information from upstream for use in estimation of playback progress.
// These values must be taken from the result of blend_node() or blend_input() and must be essentially read-only.
// For example, if you want to change the position, you need to change the pi.time value of PlaybackInfo passed to blend_input(pi) and get the result.
struct NodeTimeInfo {
// Retain the previous frame values. These are stored into the AnimationTree's Map and exposing them as read-only values.
double length = 0.0 ;
double position = 0.0 ;
double delta = 0.0 ;
// Needs internally to estimate remain time, the previous frame values are not retained.
Animation : : LoopMode loop_mode = Animation : : LOOP_NONE ;
2024-07-28 07:48:38 +02:00
bool will_end = false ; // For breaking loop, it is true when just looped.
2024-01-07 22:08:10 +01:00
bool is_infinity = false ; // For unpredictable state machine's end.
bool is_looping ( ) {
return loop_mode ! = Animation : : LOOP_NONE ;
}
double get_remain ( bool p_break_loop = false ) {
if ( ( is_looping ( ) & & ! p_break_loop ) | | is_infinity ) {
return HUGE_LENGTH ;
}
2024-07-28 07:48:38 +02:00
if ( is_looping ( ) & & p_break_loop & & will_end ) {
2024-01-07 22:08:10 +01:00
return 0 ;
}
2024-07-23 18:00:42 +02:00
double remain = length - position ;
if ( Math : : is_zero_approx ( remain ) ) {
return 0 ;
}
2024-01-07 22:08:10 +01:00
return length - position ;
}
} ;
2023-07-20 17:34:06 +02:00
// Temporary state for blending process which needs to be stored in each AnimationNodes.
struct NodeState {
StringName base_path ;
AnimationNode * parent = nullptr ;
Vector < StringName > connections ;
Vector < real_t > track_weights ;
} node_state ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
// Temporary state for blending process which needs to be started in the AnimationTree, pass through the AnimationNodes, and then return to the AnimationTree.
struct ProcessState {
2021-02-07 22:29:31 +01:00
AnimationTree * tree = nullptr ;
2023-07-20 17:34:06 +02:00
HashMap < NodePath , int > track_map ; // TODO: Is there a better way to manage filter/tracks?
bool is_testing = false ;
bool valid = false ;
2018-06-19 03:10:48 +02:00
String invalid_reasons ;
2021-02-07 22:29:31 +01:00
uint64_t last_pass = 0 ;
2023-07-20 17:34:06 +02:00
} * process_state = nullptr ;
2023-08-09 18:31:15 +02:00
2018-06-19 03:10:48 +02:00
Array _get_filters ( ) const ;
void _set_filters ( const Array & p_filters ) ;
2018-08-20 18:38:18 +02:00
friend class AnimationNodeBlendTree ;
2024-01-07 22:08:10 +01:00
// The time information is passed from upstream to downstream by AnimationMixer::PlaybackInfo::p_playback_info until AnimationNodeAnimation processes it.
// Conversely, AnimationNodeAnimation returns the processed result as NodeTimeInfo from downstream to upstream.
NodeTimeInfo _blend_node ( Ref < AnimationNode > p_node , const StringName & p_subpath , AnimationNode * p_new_parent , AnimationMixer : : PlaybackInfo p_playback_info , FilterAction p_filter = FILTER_IGNORE , bool p_sync = true , bool p_test_only = false , real_t * r_activity = nullptr ) ;
NodeTimeInfo _pre_process ( ProcessState * p_process_state , AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only = false ) ;
2018-06-19 03:10:48 +02:00
protected :
2024-01-07 22:08:10 +01:00
StringName current_length = " current_length " ;
StringName current_position = " current_position " ;
StringName current_delta = " current_delta " ;
virtual NodeTimeInfo process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only = false ) ; // To organize time information. Virtualizing for especially AnimationNodeAnimation needs to take "backward" into account.
virtual NodeTimeInfo _process ( const AnimationMixer : : PlaybackInfo p_playback_info , bool p_test_only = false ) ; // Main process.
2023-07-20 17:34:06 +02:00
void blend_animation ( const StringName & p_animation , AnimationMixer : : PlaybackInfo p_playback_info ) ;
2024-01-07 22:08:10 +01:00
NodeTimeInfo blend_node ( Ref < AnimationNode > p_node , const StringName & p_subpath , AnimationMixer : : PlaybackInfo p_playback_info , FilterAction p_filter = FILTER_IGNORE , bool p_sync = true , bool p_test_only = false ) ;
NodeTimeInfo blend_input ( int p_input , AnimationMixer : : PlaybackInfo p_playback_info , FilterAction p_filter = FILTER_IGNORE , bool p_sync = true , bool p_test_only = false ) ;
2023-02-18 03:02:28 +01:00
2023-07-20 17:34:06 +02:00
// Bind-able methods to expose for compatibility, moreover AnimationMixer::PlaybackInfo is not exposed.
void 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 = Animation : : LOOPED_FLAG_NONE ) ;
double 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 = FILTER_IGNORE , bool p_sync = true , bool p_test_only = false ) ;
double blend_input_ex ( int p_input , double p_time , bool p_seek , bool p_is_external_seeking , real_t p_blend , FilterAction p_filter = FILTER_IGNORE , bool p_sync = true , bool p_test_only = false ) ;
2021-10-15 15:25:00 +02:00
2018-06-19 03:10:48 +02:00
void make_invalid ( const String & p_reason ) ;
2022-04-20 12:36:54 +02:00
AnimationTree * get_animation_tree ( ) const ;
2018-06-19 03:10:48 +02:00
static void _bind_methods ( ) ;
2022-08-12 22:57:11 +02:00
void _validate_property ( PropertyInfo & p_property ) const ;
2018-06-19 03:10:48 +02:00
2021-08-22 03:52:44 +02:00
GDVIRTUAL0RC ( Dictionary , _get_child_nodes )
GDVIRTUAL0RC ( Array , _get_parameter_list )
GDVIRTUAL1RC ( Ref < AnimationNode > , _get_child_by_name , StringName )
GDVIRTUAL1RC ( Variant , _get_parameter_default_value , StringName )
2023-01-12 13:51:03 +01:00
GDVIRTUAL1RC ( bool , _is_parameter_read_only , StringName )
2023-02-18 03:02:28 +01:00
GDVIRTUAL4RC ( double , _process , double , bool , bool , bool )
2021-08-22 03:52:44 +02:00
GDVIRTUAL0RC ( String , _get_caption )
GDVIRTUAL0RC ( bool , _has_filter )
2018-06-19 03:10:48 +02:00
public :
2018-08-20 18:38:18 +02:00
virtual void get_parameter_list ( List < PropertyInfo > * r_list ) const ;
virtual Variant get_parameter_default_value ( const StringName & p_parameter ) const ;
2023-01-12 13:51:03 +01:00
virtual bool is_parameter_read_only ( const StringName & p_parameter ) const ;
2018-08-20 18:38:18 +02:00
void set_parameter ( const StringName & p_name , const Variant & p_value ) ;
Variant get_parameter ( const StringName & p_name ) const ;
2024-01-07 22:08:10 +01:00
void set_node_time_info ( const NodeTimeInfo & p_node_time_info ) ; // Wrapper of set_parameter().
virtual NodeTimeInfo get_node_time_info ( ) const ; // Wrapper of get_parameter().
2018-08-20 18:38:18 +02:00
struct ChildNode {
StringName name ;
Ref < AnimationNode > node ;
} ;
virtual void get_child_nodes ( List < ChildNode > * r_child_nodes ) ;
2018-06-19 03:10:48 +02:00
2018-06-21 20:45:44 +02:00
virtual String get_caption ( ) const ;
2018-06-19 03:10:48 +02:00
2023-01-29 15:54:13 +01:00
virtual bool add_input ( const String & p_name ) ;
virtual void remove_input ( int p_index ) ;
virtual bool set_input_name ( int p_input , const String & p_name ) ;
virtual String get_input_name ( int p_input ) const ;
2018-06-19 03:10:48 +02:00
int get_input_count ( ) const ;
2023-01-29 15:54:13 +01:00
int find_input ( const String & p_name ) const ;
2018-06-19 03:10:48 +02:00
void set_filter_path ( const NodePath & p_path , bool p_enable ) ;
bool is_path_filtered ( const NodePath & p_path ) const ;
void set_filter_enabled ( bool p_enable ) ;
bool is_filter_enabled ( ) const ;
2024-02-07 02:37:26 +01:00
void set_deletable ( bool p_closable ) ;
bool is_deletable ( ) const ;
2023-08-09 18:31:15 +02:00
2018-06-19 03:10:48 +02:00
virtual bool has_filter ( ) const ;
2024-01-06 17:23:25 +01:00
# ifdef TOOLS_ENABLED
virtual void get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const override ;
# endif
2023-02-18 03:02:28 +01:00
virtual Ref < AnimationNode > get_child_by_name ( const StringName & p_name ) const ;
Ref < AnimationNode > find_node_by_path ( const String & p_name ) const ;
2018-06-19 03:10:48 +02:00
AnimationNode ( ) ;
} ;
VARIANT_ENUM_CAST ( AnimationNode : : FilterAction )
2023-07-20 17:34:06 +02:00
// Root node does not allow inputs.
2018-06-21 20:45:44 +02:00
class AnimationRootNode : public AnimationNode {
2019-03-19 19:35:57 +01:00
GDCLASS ( AnimationRootNode , AnimationNode ) ;
2023-02-04 16:29:34 +01:00
protected :
virtual void _tree_changed ( ) ;
virtual void _animation_node_renamed ( const ObjectID & p_oid , const String & p_old_name , const String & p_new_name ) ;
virtual void _animation_node_removed ( const ObjectID & p_oid , const StringName & p_node ) ;
2018-06-21 20:45:44 +02:00
public :
AnimationRootNode ( ) { }
} ;
2018-12-16 15:43:20 +01:00
class AnimationNodeStartState : public AnimationRootNode {
GDCLASS ( AnimationNodeStartState , AnimationRootNode ) ;
} ;
class AnimationNodeEndState : public AnimationRootNode {
GDCLASS ( AnimationNodeEndState , AnimationRootNode ) ;
} ;
2023-07-20 17:34:06 +02:00
class AnimationTree : public AnimationMixer {
GDCLASS ( AnimationTree , AnimationMixer ) ;
2023-05-17 17:22:26 +02:00
2023-07-20 17:34:06 +02:00
# ifndef DISABLE_DEPRECATED
2018-06-19 03:10:48 +02:00
public :
2021-02-18 19:52:29 +01:00
enum AnimationProcessCallback {
2018-06-19 03:10:48 +02:00
ANIMATION_PROCESS_PHYSICS ,
ANIMATION_PROCESS_IDLE ,
2018-08-02 09:22:24 +02:00
ANIMATION_PROCESS_MANUAL ,
2018-06-19 03:10:48 +02:00
} ;
2023-07-20 17:34:06 +02:00
# endif // DISABLE_DEPRECATED
2018-06-19 03:10:48 +02:00
private :
2023-07-20 17:34:06 +02:00
Ref < AnimationRootNode > root_animation_node ;
2022-04-20 12:36:54 +02:00
NodePath advance_expression_base_node = NodePath ( String ( " . " ) ) ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
AnimationNode : : ProcessState process_state ;
2021-02-07 22:29:31 +01:00
uint64_t process_pass = 1 ;
2018-06-19 03:10:48 +02:00
2021-02-07 22:29:31 +01:00
bool started = true ;
2018-06-19 03:10:48 +02:00
2018-08-20 18:38:18 +02:00
friend class AnimationNode ;
2023-07-20 17:34:06 +02:00
2018-08-20 18:38:18 +02:00
List < PropertyInfo > properties ;
2020-03-17 07:33:00 +01:00
HashMap < StringName , HashMap < StringName , StringName > > property_parent_map ;
2023-02-04 16:29:34 +01:00
HashMap < ObjectID , StringName > property_reference_map ;
2023-01-12 13:51:03 +01:00
HashMap < StringName , Pair < Variant , bool > > property_map ; // Property value and read-only flag.
2018-08-20 18:38:18 +02:00
2023-07-20 17:34:06 +02:00
bool properties_dirty = true ;
void _update_properties ( ) ;
void _update_properties_for_node ( const String & p_base_path , Ref < AnimationNode > p_node ) ;
void _tree_changed ( ) ;
void _animation_node_renamed ( const ObjectID & p_oid , const String & p_old_name , const String & p_new_name ) ;
void _animation_node_removed ( const ObjectID & p_oid , const StringName & p_node ) ;
2018-08-23 21:44:10 +02:00
struct Activity {
2021-02-07 22:29:31 +01:00
uint64_t last_pass = 0 ;
2021-08-10 00:15:17 +02:00
real_t activity = 0.0 ;
2018-08-23 21:44:10 +02:00
} ;
2020-03-17 07:33:00 +01:00
HashMap < StringName , Vector < Activity > > input_activity_map ;
2018-08-23 21:44:10 +02:00
HashMap < StringName , Vector < Activity > * > input_activity_map_get ;
2023-07-20 17:34:06 +02:00
NodePath animation_player ;
2018-08-20 18:38:18 +02:00
2023-07-20 17:34:06 +02:00
void _setup_animation_player ( ) ;
void _animation_player_changed ( ) ;
2018-08-24 16:41:04 +02:00
2018-08-20 18:38:18 +02:00
bool _set ( const StringName & p_name , const Variant & p_value ) ;
bool _get ( const StringName & p_name , Variant & r_ret ) const ;
void _get_property_list ( List < PropertyInfo > * p_list ) const ;
2023-07-20 17:34:06 +02:00
virtual void _validate_property ( PropertyInfo & p_property ) const override ;
2018-06-19 03:10:48 +02:00
void _notification ( int p_what ) ;
2023-07-20 17:34:06 +02:00
2018-06-19 03:10:48 +02:00
static void _bind_methods ( ) ;
2023-07-20 17:34:06 +02:00
virtual void _set_active ( bool p_active ) override ;
2022-07-26 11:48:08 +02:00
2023-07-20 17:34:06 +02:00
// Make animation instances.
virtual bool _blend_pre_process ( double p_delta , int p_track_count , const HashMap < NodePath , int > & p_track_map ) override ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
# ifndef DISABLE_DEPRECATED
void _set_process_callback_bind_compat_80813 ( AnimationProcessCallback p_mode ) ;
AnimationProcessCallback _get_process_callback_bind_compat_80813 ( ) const ;
void _set_tree_root_bind_compat_80813 ( const Ref < AnimationNode > & p_root ) ;
Ref < AnimationNode > _get_tree_root_bind_compat_80813 ( ) const ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
static void _bind_compatibility_methods ( ) ;
# endif // DISABLE_DEPRECATED
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
public :
void set_animation_player ( const NodePath & p_path ) ;
2018-06-19 03:10:48 +02:00
NodePath get_animation_player ( ) const ;
2023-07-20 17:34:06 +02:00
void set_root_animation_node ( const Ref < AnimationRootNode > & p_animation_node ) ;
Ref < AnimationRootNode > get_root_animation_node ( ) const ;
2022-04-20 12:36:54 +02:00
2023-07-20 17:34:06 +02:00
void set_advance_expression_base_node ( const NodePath & p_path ) ;
NodePath get_advance_expression_base_node ( ) const ;
2023-01-27 19:25:49 +01:00
2024-02-17 19:03:21 +01:00
PackedStringArray get_configuration_warnings ( ) const override ;
2018-06-19 03:10:48 +02:00
bool is_state_invalid ( ) const ;
String get_invalid_state_reason ( ) const ;
2021-08-10 00:15:17 +02:00
real_t get_connection_activity ( const StringName & p_path , int p_connection ) const ;
2018-08-02 09:22:24 +02:00
2018-06-19 03:10:48 +02:00
uint64_t get_last_process_pass ( ) const ;
2023-07-20 17:34:06 +02:00
2018-06-25 23:40:24 +02:00
AnimationTree ( ) ;
~ AnimationTree ( ) ;
2018-06-19 03:10:48 +02:00
} ;
2023-07-20 17:34:06 +02:00
# ifndef DISABLE_DEPRECATED
VARIANT_ENUM_CAST ( AnimationTree : : AnimationProcessCallback ) ;
# endif // DISABLE_DEPRECATED
2018-06-19 03:10:48 +02:00
2022-07-23 23:41:51 +02:00
# endif // ANIMATION_TREE_H