2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* animation_player.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2019-01-01 12:53:14 +01:00
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 02:10:30 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "animation_player.h"
2016-03-09 00:00:52 +01:00
2018-09-11 18:13:45 +02:00
# include "core/engine.h"
# include "core/message_queue.h"
2014-02-10 02:10:30 +01:00
# include "scene/scene_string_names.h"
2018-06-07 17:46:14 +02:00
# include "servers/audio/audio_stream.h"
2017-10-30 19:43:19 +01:00
# ifdef TOOLS_ENABLED
void AnimatedValuesBackup : : update_skeletons ( ) {
for ( int i = 0 ; i < entries . size ( ) ; i + + ) {
if ( entries [ i ] . bone_idx ! = - 1 ) {
Object : : cast_to < Skeleton > ( entries [ i ] . object ) - > notification ( Skeleton : : NOTIFICATION_UPDATE_SKELETON ) ;
}
}
}
# endif
2017-03-05 16:44:50 +01:00
bool AnimationPlayer : : _set ( const StringName & p_name , const Variant & p_value ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
String name = p_name ;
2014-02-10 02:10:30 +01:00
2018-01-11 23:35:12 +01:00
if ( name . begins_with ( " playback/play " ) ) { // bw compatibility
2014-02-10 02:10:30 +01:00
2018-01-11 23:35:12 +01:00
set_current_animation ( p_value ) ;
2014-02-10 02:10:30 +01:00
} else if ( name . begins_with ( " anims/ " ) ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
String which = name . get_slicec ( ' / ' , 1 ) ;
add_animation ( which , p_value ) ;
2018-01-11 23:35:12 +01:00
2014-02-10 02:10:30 +01:00
} else if ( name . begins_with ( " next/ " ) ) {
2017-03-05 16:44:50 +01:00
String which = name . get_slicec ( ' / ' , 1 ) ;
animation_set_next ( which , p_value ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
} else if ( p_name = = SceneStringNames : : get_singleton ( ) - > blend_times ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
Array array = p_value ;
2014-02-10 02:10:30 +01:00
int len = array . size ( ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( len % 3 , false ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < len / 3 ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
StringName from = array [ i * 3 + 0 ] ;
StringName to = array [ i * 3 + 1 ] ;
float time = array [ i * 3 + 2 ] ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
set_blend_time ( from , to , time ) ;
2014-02-10 02:10:30 +01:00
}
} else
return false ;
return true ;
}
2017-03-05 16:44:50 +01:00
bool AnimationPlayer : : _get ( const StringName & p_name , Variant & r_ret ) const {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
String name = p_name ;
2014-02-10 02:10:30 +01:00
2018-01-11 23:35:12 +01:00
if ( name = = " playback/play " ) { // bw compatibility
2016-03-09 00:00:52 +01:00
2018-01-11 23:35:12 +01:00
r_ret = get_current_animation ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name . begins_with ( " anims/ " ) ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
String which = name . get_slicec ( ' / ' , 1 ) ;
r_ret = get_animation ( which ) . get_ref_ptr ( ) ;
2018-01-11 23:35:12 +01:00
2014-02-10 02:10:30 +01:00
} else if ( name . begins_with ( " next/ " ) ) {
2017-03-05 16:44:50 +01:00
String which = name . get_slicec ( ' / ' , 1 ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
r_ret = animation_get_next ( which ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
} else if ( name = = " blend_times " ) {
2016-03-09 00:00:52 +01:00
2017-01-16 18:03:38 +01:00
Vector < BlendKey > keys ;
2017-03-05 16:44:50 +01:00
for ( Map < BlendKey , float > : : Element * E = blend_times . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2017-01-16 18:03:38 +01:00
keys . ordered_insert ( E - > key ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-01-16 18:03:38 +01:00
Array array ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < keys . size ( ) ; i + + ) {
2017-01-16 18:03:38 +01:00
array . push_back ( keys [ i ] . from ) ;
array . push_back ( keys [ i ] . to ) ;
array . push_back ( blend_times [ keys [ i ] ] ) ;
}
2017-03-05 16:44:50 +01:00
r_ret = array ;
2014-02-10 02:10:30 +01:00
} else
return false ;
return true ;
}
2018-01-11 23:35:12 +01:00
void AnimationPlayer : : _validate_property ( PropertyInfo & property ) const {
if ( property . name = = " current_animation " ) {
List < String > names ;
for ( Map < StringName , AnimationData > : : Element * E = animation_set . front ( ) ; E ; E = E - > next ( ) ) {
names . push_back ( E - > key ( ) ) ;
}
names . sort ( ) ;
names . push_front ( " [stop] " ) ;
String hint ;
for ( List < String > : : Element * E = names . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2018-01-11 23:35:12 +01:00
if ( E ! = names . front ( ) )
hint + = " , " ;
hint + = E - > get ( ) ;
}
property . hint_string = hint ;
}
}
void AnimationPlayer : : _get_property_list ( List < PropertyInfo > * p_list ) const {
2014-02-10 02:10:30 +01:00
2016-02-01 04:19:45 +01:00
List < PropertyInfo > anim_names ;
2017-03-05 16:44:50 +01:00
for ( Map < StringName , AnimationData > : : Element * E = animation_set . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2018-01-11 23:35:12 +01:00
anim_names . push_back ( PropertyInfo ( Variant : : OBJECT , " anims/ " + String ( E - > key ( ) ) , PROPERTY_HINT_RESOURCE_TYPE , " Animation " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE ) ) ;
2017-03-05 16:44:50 +01:00
if ( E - > get ( ) . next ! = StringName ( ) )
2018-01-11 23:35:12 +01:00
anim_names . push_back ( PropertyInfo ( Variant : : STRING , " next/ " + String ( E - > key ( ) ) , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
2014-02-10 02:10:30 +01:00
}
2016-02-01 04:19:45 +01:00
anim_names . sort ( ) ;
2017-03-05 16:44:50 +01:00
for ( List < PropertyInfo > : : Element * E = anim_names . front ( ) ; E ; E = E - > next ( ) ) {
2016-02-01 04:19:45 +01:00
p_list - > push_back ( E - > get ( ) ) ;
}
2014-02-10 02:10:30 +01:00
2018-01-11 23:35:12 +01:00
p_list - > push_back ( PropertyInfo ( Variant : : ARRAY , " blend_times " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
2014-02-10 02:10:30 +01:00
}
2014-10-03 05:10:51 +02:00
void AnimationPlayer : : advance ( float p_time ) {
2017-03-05 16:44:50 +01:00
_animation_process ( p_time ) ;
2014-10-03 05:10:51 +02:00
}
2014-02-10 02:10:30 +01:00
void AnimationPlayer : : _notification ( int p_what ) {
2017-03-05 16:44:50 +01:00
switch ( p_what ) {
2016-03-09 00:00:52 +01:00
2014-11-06 01:20:42 +01:00
case NOTIFICATION_ENTER_TREE : {
2014-02-10 02:10:30 +01:00
if ( ! processing ) {
//make sure that a previous process state was not saved
//only process if "processing" is set
2018-04-11 09:28:14 +02:00
set_physics_process_internal ( false ) ;
set_process_internal ( false ) ;
2014-02-10 02:10:30 +01:00
}
//_set_process(false);
clear_caches ( ) ;
} break ;
case NOTIFICATION_READY : {
2017-08-19 01:02:56 +02:00
if ( ! Engine : : get_singleton ( ) - > is_editor_hint ( ) & & animation_set . has ( autoplay ) ) {
2014-02-10 02:10:30 +01:00
play ( autoplay ) ;
2017-05-29 13:56:35 +02:00
_animation_process ( 0 ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
2017-01-10 22:02:19 +01:00
case NOTIFICATION_INTERNAL_PROCESS : {
2017-09-30 16:19:07 +02:00
if ( animation_process_mode = = ANIMATION_PROCESS_PHYSICS )
2014-02-10 02:10:30 +01:00
break ;
if ( processing )
2017-03-05 16:44:50 +01:00
_animation_process ( get_process_delta_time ( ) ) ;
2014-02-10 02:10:30 +01:00
} break ;
2017-09-30 16:19:07 +02:00
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS : {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( animation_process_mode = = ANIMATION_PROCESS_IDLE )
2014-02-10 02:10:30 +01:00
break ;
if ( processing )
2017-09-30 16:19:07 +02:00
_animation_process ( get_physics_process_delta_time ( ) ) ;
2014-02-10 02:10:30 +01:00
} break ;
2014-11-06 01:20:42 +01:00
case NOTIFICATION_EXIT_TREE : {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
clear_caches ( ) ;
} break ;
}
}
2017-11-01 21:32:39 +01:00
void AnimationPlayer : : _ensure_node_caches ( AnimationData * p_anim ) {
// Already cached?
if ( p_anim - > node_cache . size ( ) = = p_anim - > animation - > get_track_count ( ) )
return ;
2014-02-10 02:10:30 +01:00
Node * parent = get_node ( root ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! parent ) ;
2017-03-05 16:44:50 +01:00
Animation * a = p_anim - > animation . operator - > ( ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
p_anim - > node_cache . resize ( a - > get_track_count ( ) ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < a - > get_track_count ( ) ; i + + ) {
2016-03-09 00:00:52 +01:00
2018-07-25 03:11:03 +02:00
p_anim - > node_cache . write [ i ] = NULL ;
2014-02-10 02:10:30 +01:00
RES resource ;
2017-05-30 22:20:15 +02:00
Vector < StringName > leftover_path ;
Node * child = parent - > get_node_and_resource ( a - > track_get_path ( i ) , resource , leftover_path ) ;
2014-02-13 22:03:28 +01:00
if ( ! child ) {
2017-03-05 16:44:50 +01:00
ERR_EXPLAIN ( " On Animation: ' " + p_anim - > name + " ', couldn't resolve track: ' " + String ( a - > track_get_path ( i ) ) + " ' " ) ;
2014-02-13 22:03:28 +01:00
}
2014-02-10 02:10:30 +01:00
ERR_CONTINUE ( ! child ) ; // couldn't find the child node
2017-08-07 12:17:31 +02:00
uint32_t id = resource . is_valid ( ) ? resource - > get_instance_id ( ) : child - > get_instance_id ( ) ;
2017-03-05 16:44:50 +01:00
int bone_idx = - 1 ;
2014-02-10 02:10:30 +01:00
2017-05-30 22:20:15 +02:00
if ( a - > track_get_path ( i ) . get_subname_count ( ) = = 1 & & Object : : cast_to < Skeleton > ( child ) ) {
2014-02-10 02:10:30 +01:00
2017-10-03 18:49:32 +02:00
Skeleton * sk = Object : : cast_to < Skeleton > ( child ) ;
bone_idx = sk - > find_bone ( a - > track_get_path ( i ) . get_subname ( 0 ) ) ;
if ( bone_idx = = - 1 | | sk - > is_bone_ignore_animation ( bone_idx ) ) {
2014-02-10 02:10:30 +01:00
continue ;
}
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
{
2018-01-12 12:28:39 +01:00
if ( ! child - > is_connected ( " tree_exiting " , this , " _node_removed " ) )
child - > connect ( " tree_exiting " , this , " _node_removed " , make_binds ( child ) , CONNECT_ONESHOT ) ;
2014-02-10 02:10:30 +01:00
}
TrackNodeCacheKey key ;
2017-03-05 16:44:50 +01:00
key . id = id ;
key . bone_idx = bone_idx ;
2016-03-09 00:00:52 +01:00
2018-09-09 00:32:57 +02:00
if ( ! node_cache_map . has ( key ) )
2017-03-05 16:44:50 +01:00
node_cache_map [ key ] = TrackNodeCache ( ) ;
2014-02-10 02:10:30 +01:00
2018-09-09 00:32:57 +02:00
p_anim - > node_cache . write [ i ] = & node_cache_map [ key ] ;
p_anim - > node_cache [ i ] - > path = a - > track_get_path ( i ) ;
p_anim - > node_cache [ i ] - > node = child ;
p_anim - > node_cache [ i ] - > resource = resource ;
p_anim - > node_cache [ i ] - > node_2d = Object : : cast_to < Node2D > ( child ) ;
if ( a - > track_get_type ( i ) = = Animation : : TYPE_TRANSFORM ) {
// special cases and caches for transform tracks
// cache spatial
p_anim - > node_cache [ i ] - > spatial = Object : : cast_to < Spatial > ( child ) ;
// cache skeleton
p_anim - > node_cache [ i ] - > skeleton = Object : : cast_to < Skeleton > ( child ) ;
if ( p_anim - > node_cache [ i ] - > skeleton ) {
if ( a - > track_get_path ( i ) . get_subname_count ( ) = = 1 ) {
StringName bone_name = a - > track_get_path ( i ) . get_subname ( 0 ) ;
p_anim - > node_cache [ i ] - > bone_idx = p_anim - > node_cache [ i ] - > skeleton - > find_bone ( bone_name ) ;
if ( p_anim - > node_cache [ i ] - > bone_idx < 0 ) {
// broken track (nonexistent bone)
2017-03-05 16:44:50 +01:00
p_anim - > node_cache [ i ] - > skeleton = NULL ;
2018-09-09 00:32:57 +02:00
p_anim - > node_cache [ i ] - > spatial = NULL ;
printf ( " bone is %ls \n " , String ( bone_name ) . c_str ( ) ) ;
ERR_CONTINUE ( p_anim - > node_cache [ i ] - > bone_idx < 0 ) ;
2014-02-10 02:10:30 +01:00
}
2018-09-09 00:32:57 +02:00
} else {
// no property, just use spatialnode
p_anim - > node_cache [ i ] - > skeleton = NULL ;
2014-02-10 02:10:30 +01:00
}
}
}
2017-03-05 16:44:50 +01:00
if ( a - > track_get_type ( i ) = = Animation : : TYPE_VALUE ) {
2014-02-10 02:10:30 +01:00
2017-05-30 22:20:15 +02:00
if ( ! p_anim - > node_cache [ i ] - > property_anim . has ( a - > track_get_path ( i ) . get_concatenated_subnames ( ) ) ) {
2014-02-10 02:10:30 +01:00
TrackNodeCache : : PropertyAnim pa ;
2017-05-30 22:20:15 +02:00
pa . subpath = leftover_path ;
2017-03-05 16:44:50 +01:00
pa . object = resource . is_valid ( ) ? ( Object * ) resource . ptr ( ) : ( Object * ) child ;
pa . special = SP_NONE ;
pa . owner = p_anim - > node_cache [ i ] ;
2014-02-10 02:10:30 +01:00
if ( false & & p_anim - > node_cache [ i ] - > node_2d ) {
2017-05-30 22:20:15 +02:00
if ( leftover_path . size ( ) = = 1 & & leftover_path [ 0 ] = = SceneStringNames : : get_singleton ( ) - > transform_pos )
2017-03-05 16:44:50 +01:00
pa . special = SP_NODE2D_POS ;
2017-05-30 22:20:15 +02:00
else if ( leftover_path . size ( ) = = 1 & & leftover_path [ 0 ] = = SceneStringNames : : get_singleton ( ) - > transform_rot )
2017-03-05 16:44:50 +01:00
pa . special = SP_NODE2D_ROT ;
2017-05-30 22:20:15 +02:00
else if ( leftover_path . size ( ) = = 1 & & leftover_path [ 0 ] = = SceneStringNames : : get_singleton ( ) - > transform_scale )
2017-03-05 16:44:50 +01:00
pa . special = SP_NODE2D_SCALE ;
2014-02-10 02:10:30 +01:00
}
2017-05-30 22:20:15 +02:00
p_anim - > node_cache [ i ] - > property_anim [ a - > track_get_path ( i ) . get_concatenated_subnames ( ) ] = pa ;
2014-02-10 02:10:30 +01:00
}
}
2018-06-07 17:46:14 +02:00
if ( a - > track_get_type ( i ) = = Animation : : TYPE_BEZIER & & leftover_path . size ( ) ) {
if ( ! p_anim - > node_cache [ i ] - > bezier_anim . has ( a - > track_get_path ( i ) . get_concatenated_subnames ( ) ) ) {
TrackNodeCache : : BezierAnim ba ;
2018-06-18 14:59:13 +02:00
ba . bezier_property = leftover_path ;
2018-06-07 17:46:14 +02:00
ba . object = resource . is_valid ( ) ? ( Object * ) resource . ptr ( ) : ( Object * ) child ;
ba . owner = p_anim - > node_cache [ i ] ;
p_anim - > node_cache [ i ] - > bezier_anim [ a - > track_get_path ( i ) . get_concatenated_subnames ( ) ] = ba ;
}
}
2014-02-10 02:10:30 +01:00
}
}
2018-06-07 17:46:14 +02:00
void AnimationPlayer : : _animation_process_animation ( AnimationData * p_anim , float p_time , float p_delta , float p_interp , bool p_is_current , bool p_seeked , bool p_started ) {
2014-02-10 02:10:30 +01:00
2017-11-01 21:32:39 +01:00
_ensure_node_caches ( p_anim ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_anim - > node_cache . size ( ) ! = p_anim - > animation - > get_track_count ( ) ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Animation * a = p_anim - > animation . operator - > ( ) ;
2017-08-19 01:02:56 +02:00
bool can_call = is_inside_tree ( ) & & ! Engine : : get_singleton ( ) - > is_editor_hint ( ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < a - > get_track_count ( ) ; i + + ) {
2016-03-09 00:00:52 +01:00
2019-02-01 16:15:39 +01:00
// If an animation changes this animation (or it animates itself)
// we need to recreate our animation cache
if ( p_anim - > node_cache . size ( ) ! = a - > get_track_count ( ) ) {
_ensure_node_caches ( p_anim ) ;
}
2017-03-05 16:44:50 +01:00
TrackNodeCache * nc = p_anim - > node_cache [ i ] ;
2016-03-09 00:00:52 +01:00
2019-02-01 16:15:39 +01:00
if ( ! nc )
continue ; // no node cache for this track, skip it
2016-03-09 00:00:52 +01:00
2017-11-28 16:46:37 +01:00
if ( ! a - > track_is_enabled ( i ) )
continue ; // do nothing if the track is disabled
2017-03-05 16:44:50 +01:00
if ( a - > track_get_key_count ( i ) = = 0 )
2014-02-10 02:10:30 +01:00
continue ; // do nothing if track is empty
2017-03-05 16:44:50 +01:00
switch ( a - > track_get_type ( i ) ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
case Animation : : TYPE_TRANSFORM : {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( ! nc - > spatial )
continue ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
Vector3 loc ;
Quat rot ;
Vector3 scale ;
2017-03-05 16:44:50 +01:00
Error err = a - > transform_track_interpolate ( i , p_time , & loc , & rot , & scale ) ;
2014-12-02 18:02:41 +01:00
//ERR_CONTINUE(err!=OK); //used for testing, should be removed
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( err ! = OK )
2014-02-10 02:10:30 +01:00
continue ;
2017-03-05 16:44:50 +01:00
if ( nc - > accum_pass ! = accum_pass ) {
ERR_CONTINUE ( cache_update_size > = NODE_CACHE_UPDATE_MAX ) ;
cache_update [ cache_update_size + + ] = nc ;
nc - > accum_pass = accum_pass ;
nc - > loc_accum = loc ;
nc - > rot_accum = rot ;
nc - > scale_accum = scale ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
nc - > loc_accum = nc - > loc_accum . linear_interpolate ( loc , p_interp ) ;
nc - > rot_accum = nc - > rot_accum . slerp ( rot , p_interp ) ;
nc - > scale_accum = nc - > scale_accum . linear_interpolate ( scale , p_interp ) ;
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
} break ;
case Animation : : TYPE_VALUE : {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( ! nc - > node )
continue ;
//StringName property=a->track_get_path(i).get_property();
2017-05-30 22:20:15 +02:00
Map < StringName , TrackNodeCache : : PropertyAnim > : : Element * E = nc - > property_anim . find ( a - > track_get_path ( i ) . get_concatenated_subnames ( ) ) ;
2014-02-10 02:10:30 +01:00
ERR_CONTINUE ( ! E ) ; //should it continue, or create a new one?
TrackNodeCache : : PropertyAnim * pa = & E - > get ( ) ;
2018-06-07 17:46:14 +02:00
Animation : : UpdateMode update_mode = a - > value_track_get_update_mode ( i ) ;
if ( update_mode = = Animation : : UPDATE_CAPTURE ) {
if ( p_started ) {
pa - > capture = pa - > object - > get_indexed ( pa - > subpath ) ;
}
2018-06-29 14:13:20 +02:00
int key_count = a - > track_get_key_count ( i ) ;
if ( key_count = = 0 )
2018-06-07 17:46:14 +02:00
continue ; //eeh not worth it
float first_key_time = a - > track_get_key_time ( i , 0 ) ;
2018-06-29 14:13:20 +02:00
float transition = 1.0 ;
int first_key = 0 ;
if ( first_key_time = = 0.0 ) {
//ignore, use for transition
if ( key_count = = 1 )
2018-09-13 03:38:39 +02:00
continue ; //with one key we can't do anything
2018-06-29 14:13:20 +02:00
transition = a - > track_get_key_transition ( i , 0 ) ;
first_key_time = a - > track_get_key_time ( i , 1 ) ;
first_key = 1 ;
}
2018-06-07 17:46:14 +02:00
if ( p_time < first_key_time ) {
2018-06-29 14:13:20 +02:00
float c = Math : : ease ( p_time / first_key_time , transition ) ;
Variant first_value = a - > track_get_key_value ( i , first_key ) ;
2018-06-07 17:46:14 +02:00
Variant interp_value ;
Variant : : interpolate ( pa - > capture , first_value , c , interp_value ) ;
if ( pa - > accum_pass ! = accum_pass ) {
ERR_CONTINUE ( cache_update_prop_size > = NODE_CACHE_UPDATE_MAX ) ;
cache_update_prop [ cache_update_prop_size + + ] = pa ;
pa - > value_accum = interp_value ;
pa - > accum_pass = accum_pass ;
} else {
Variant : : interpolate ( pa - > value_accum , interp_value , p_interp , pa - > value_accum ) ;
}
continue ; //handled
}
}
if ( update_mode = = Animation : : UPDATE_CONTINUOUS | | update_mode = = Animation : : UPDATE_CAPTURE | | ( p_delta = = 0 & & update_mode = = Animation : : UPDATE_DISCRETE ) ) { //delta == 0 means seek
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Variant value = a - > value_track_interpolate ( i , p_time ) ;
2017-10-15 01:28:08 +02:00
if ( value = = Variant ( ) )
continue ;
2016-06-19 06:43:02 +02:00
//thanks to trigger mode, this should be solved now..
2017-01-14 12:26:56 +01:00
/*
if ( p_delta = = 0 & & value . get_type ( ) = = Variant : : STRING )
continue ; // doing this with strings is messy, should find another way
*/
2017-03-05 16:44:50 +01:00
if ( pa - > accum_pass ! = accum_pass ) {
ERR_CONTINUE ( cache_update_prop_size > = NODE_CACHE_UPDATE_MAX ) ;
cache_update_prop [ cache_update_prop_size + + ] = pa ;
pa - > value_accum = value ;
pa - > accum_pass = accum_pass ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
Variant : : interpolate ( pa - > value_accum , value , p_interp , pa - > value_accum ) ;
2014-02-10 02:10:30 +01:00
}
2018-06-07 17:46:14 +02:00
} else if ( p_is_current & & p_delta ! = 0 ) {
2014-02-10 02:10:30 +01:00
List < int > indices ;
2017-03-05 16:44:50 +01:00
a - > value_track_get_key_indices ( i , p_time , p_delta , & indices ) ;
2016-06-19 06:43:02 +02:00
2017-03-05 16:44:50 +01:00
for ( List < int > : : Element * F = indices . front ( ) ; F ; F = F - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Variant value = a - > track_get_key_value ( i , F - > get ( ) ) ;
switch ( pa - > special ) {
2014-02-10 02:10:30 +01:00
2015-12-05 18:18:22 +01:00
case SP_NONE : {
bool valid ;
2017-05-30 22:20:15 +02:00
pa - > object - > set_indexed ( pa - > subpath , value , & valid ) ; //you are not speshul
2015-12-05 18:18:22 +01:00
# ifdef DEBUG_ENABLED
if ( ! valid ) {
2017-10-05 01:51:19 +02:00
ERR_PRINTS ( " Failed setting track value ' " + String ( pa - > owner - > path ) + " '. Check if property exists or the type of key is valid. Animation ' " + a - > get_name ( ) + " ' at node ' " + get_path ( ) + " '. " ) ;
2015-12-05 18:18:22 +01:00
}
# endif
} break ;
case SP_NODE2D_POS : {
# ifdef DEBUG_ENABLED
2017-03-05 16:44:50 +01:00
if ( value . get_type ( ) ! = Variant : : VECTOR2 ) {
2017-10-05 01:51:19 +02:00
ERR_PRINTS ( " Position key at time " + rtos ( p_time ) + " in Animation Track ' " + String ( pa - > owner - > path ) + " ' not of type Vector2(). Animation ' " + a - > get_name ( ) + " ' at node ' " + get_path ( ) + " '. " ) ;
2015-12-05 18:18:22 +01:00
}
# endif
2017-03-05 16:44:50 +01:00
static_cast < Node2D * > ( pa - > object ) - > set_position ( value ) ;
2015-12-05 18:18:22 +01:00
} break ;
case SP_NODE2D_ROT : {
# ifdef DEBUG_ENABLED
if ( value . is_num ( ) ) {
2017-10-05 01:51:19 +02:00
ERR_PRINTS ( " Rotation key at time " + rtos ( p_time ) + " in Animation Track ' " + String ( pa - > owner - > path ) + " ' not numerical. Animation ' " + a - > get_name ( ) + " ' at node ' " + get_path ( ) + " '. " ) ;
2015-12-05 18:18:22 +01:00
}
# endif
2017-03-05 16:44:50 +01:00
static_cast < Node2D * > ( pa - > object ) - > set_rotation ( Math : : deg2rad ( ( double ) value ) ) ;
2015-12-05 18:18:22 +01:00
} break ;
case SP_NODE2D_SCALE : {
# ifdef DEBUG_ENABLED
2017-03-05 16:44:50 +01:00
if ( value . get_type ( ) ! = Variant : : VECTOR2 ) {
2017-10-05 01:51:19 +02:00
ERR_PRINTS ( " Scale key at time " + rtos ( p_time ) + " in Animation Track ' " + String ( pa - > owner - > path ) + " ' not of type Vector2(). " + a - > get_name ( ) + " ' at node ' " + get_path ( ) + " '. " ) ;
2015-12-05 18:18:22 +01:00
}
# endif
2017-03-05 16:44:50 +01:00
static_cast < Node2D * > ( pa - > object ) - > set_scale ( value ) ;
2015-12-05 18:18:22 +01:00
} break ;
2014-02-10 02:10:30 +01:00
}
}
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
} break ;
case Animation : : TYPE_METHOD : {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( ! nc - > node )
continue ;
2018-06-07 17:46:14 +02:00
if ( p_delta = = 0 ) {
2014-02-10 02:10:30 +01:00
continue ;
2018-06-07 17:46:14 +02:00
}
if ( ! p_is_current )
2014-02-10 02:10:30 +01:00
break ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
List < int > indices ;
2017-03-05 16:44:50 +01:00
a - > method_track_get_key_indices ( i , p_time , p_delta , & indices ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
for ( List < int > : : Element * E = indices . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
StringName method = a - > method_track_get_name ( i , E - > get ( ) ) ;
Vector < Variant > params = a - > method_track_get_params ( i , E - > get ( ) ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
int s = params . size ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_CONTINUE ( s > VARIANT_ARG_MAX ) ;
2018-07-19 03:26:01 +02:00
# ifdef DEBUG_ENABLED
if ( ! nc - > node - > has_method ( method ) ) {
ERR_PRINTS ( " Invalid method call ' " + method + " '. ' " + a - > get_name ( ) + " ' at node ' " + get_path ( ) + " '. " ) ;
}
# endif
2014-02-10 02:10:30 +01:00
if ( can_call ) {
MessageQueue : : get_singleton ( ) - > push_call (
2017-03-05 16:44:50 +01:00
nc - > node ,
method ,
s > = 1 ? params [ 0 ] : Variant ( ) ,
s > = 2 ? params [ 1 ] : Variant ( ) ,
s > = 3 ? params [ 2 ] : Variant ( ) ,
s > = 4 ? params [ 3 ] : Variant ( ) ,
s > = 5 ? params [ 4 ] : Variant ( ) ) ;
2014-02-10 02:10:30 +01:00
}
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
} break ;
2018-06-07 17:46:14 +02:00
case Animation : : TYPE_BEZIER : {
if ( ! nc - > node )
continue ;
Map < StringName , TrackNodeCache : : BezierAnim > : : Element * E = nc - > bezier_anim . find ( a - > track_get_path ( i ) . get_concatenated_subnames ( ) ) ;
ERR_CONTINUE ( ! E ) ; //should it continue, or create a new one?
TrackNodeCache : : BezierAnim * ba = & E - > get ( ) ;
float bezier = a - > bezier_track_interpolate ( i , p_time ) ;
if ( ba - > accum_pass ! = accum_pass ) {
ERR_CONTINUE ( cache_update_bezier_size > = NODE_CACHE_UPDATE_MAX ) ;
cache_update_bezier [ cache_update_bezier_size + + ] = ba ;
ba - > bezier_accum = bezier ;
ba - > accum_pass = accum_pass ;
} else {
ba - > bezier_accum = Math : : lerp ( ba - > bezier_accum , bezier , p_interp ) ;
}
} break ;
case Animation : : TYPE_AUDIO : {
if ( ! nc - > node )
continue ;
if ( p_delta = = 0 ) {
continue ;
}
if ( p_seeked ) {
//find whathever should be playing
int idx = a - > track_find_key ( i , p_time ) ;
if ( idx < 0 )
continue ;
Ref < AudioStream > stream = a - > audio_track_get_key_stream ( i , idx ) ;
if ( ! stream . is_valid ( ) ) {
nc - > node - > call ( " stop " ) ;
nc - > audio_playing = false ;
playing_caches . erase ( nc ) ;
} else {
float start_ofs = a - > audio_track_get_key_start_offset ( i , idx ) ;
start_ofs + = p_time - a - > track_get_key_time ( i , idx ) ;
float end_ofs = a - > audio_track_get_key_end_offset ( i , idx ) ;
float len = stream - > get_length ( ) ;
if ( start_ofs > len - end_ofs ) {
nc - > node - > call ( " stop " ) ;
nc - > audio_playing = false ;
playing_caches . erase ( nc ) ;
continue ;
}
nc - > node - > call ( " set_stream " , stream ) ;
nc - > node - > call ( " play " , start_ofs ) ;
nc - > audio_playing = true ;
playing_caches . insert ( nc ) ;
if ( len & & end_ofs > 0 ) { //force a end at a time
nc - > audio_len = len - start_ofs - end_ofs ;
} else {
nc - > audio_len = 0 ;
}
nc - > audio_start = p_time ;
}
} else {
//find stuff to play
List < int > to_play ;
a - > track_get_key_indices_in_range ( i , p_time , p_delta , & to_play ) ;
if ( to_play . size ( ) ) {
int idx = to_play . back ( ) - > get ( ) ;
Ref < AudioStream > stream = a - > audio_track_get_key_stream ( i , idx ) ;
if ( ! stream . is_valid ( ) ) {
nc - > node - > call ( " stop " ) ;
nc - > audio_playing = false ;
playing_caches . erase ( nc ) ;
} else {
float start_ofs = a - > audio_track_get_key_start_offset ( i , idx ) ;
float end_ofs = a - > audio_track_get_key_end_offset ( i , idx ) ;
float len = stream - > get_length ( ) ;
nc - > node - > call ( " set_stream " , stream ) ;
nc - > node - > call ( " play " , start_ofs ) ;
nc - > audio_playing = true ;
playing_caches . insert ( nc ) ;
if ( len & & end_ofs > 0 ) { //force a end at a time
nc - > audio_len = len - start_ofs - end_ofs ;
} else {
nc - > audio_len = 0 ;
}
nc - > audio_start = p_time ;
}
} else if ( nc - > audio_playing ) {
2018-07-01 22:44:15 +02:00
bool loop = a - > has_loop ( ) ;
bool stop = false ;
if ( ! loop & & p_time < nc - > audio_start ) {
stop = true ;
} else if ( nc - > audio_len > 0 ) {
float len = nc - > audio_start > p_time ? ( a - > get_length ( ) - nc - > audio_start ) + p_time : p_time - nc - > audio_start ;
if ( len > nc - > audio_len ) {
stop = true ;
}
}
if ( stop ) {
2018-06-07 17:46:14 +02:00
//time to stop
nc - > node - > call ( " stop " ) ;
nc - > audio_playing = false ;
playing_caches . erase ( nc ) ;
}
}
}
} break ;
case Animation : : TYPE_ANIMATION : {
AnimationPlayer * player = Object : : cast_to < AnimationPlayer > ( nc - > node ) ;
if ( ! player )
continue ;
if ( p_delta = = 0 | | p_seeked ) {
//seek
int idx = a - > track_find_key ( i , p_time ) ;
if ( idx < 0 )
continue ;
float pos = a - > track_get_key_time ( i , idx ) ;
StringName anim_name = a - > animation_track_get_key_animation ( i , idx ) ;
if ( String ( anim_name ) = = " [stop] " | | ! player - > has_animation ( anim_name ) )
continue ;
Ref < Animation > anim = player - > get_animation ( anim_name ) ;
float at_anim_pos ;
if ( anim - > has_loop ( ) ) {
at_anim_pos = Math : : fposmod ( p_time - pos , anim - > get_length ( ) ) ; //seek to loop
} else {
at_anim_pos = MAX ( anim - > get_length ( ) , p_time - pos ) ; //seek to end
}
if ( player - > is_playing ( ) | | p_seeked ) {
player - > play ( anim_name ) ;
player - > seek ( at_anim_pos ) ;
nc - > animation_playing = true ;
playing_caches . insert ( nc ) ;
} else {
player - > set_assigned_animation ( anim_name ) ;
player - > seek ( at_anim_pos , true ) ;
}
} else {
//find stuff to play
List < int > to_play ;
a - > track_get_key_indices_in_range ( i , p_time , p_delta , & to_play ) ;
if ( to_play . size ( ) ) {
int idx = to_play . back ( ) - > get ( ) ;
StringName anim_name = a - > animation_track_get_key_animation ( i , idx ) ;
if ( String ( anim_name ) = = " [stop] " | | ! player - > has_animation ( anim_name ) ) {
if ( playing_caches . has ( nc ) ) {
playing_caches . erase ( nc ) ;
player - > stop ( ) ;
nc - > animation_playing = false ;
}
} else {
player - > play ( anim_name ) ;
nc - > animation_playing = true ;
playing_caches . insert ( nc ) ;
}
}
}
} break ;
2014-02-10 02:10:30 +01:00
}
}
}
2018-06-07 17:46:14 +02:00
void AnimationPlayer : : _animation_process_data ( PlaybackData & cd , float p_delta , float p_blend , bool p_seeked , bool p_started ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
float delta = p_delta * speed_scale * cd . speed_scale ;
float next_pos = cd . pos + delta ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
float len = cd . from - > animation - > get_length ( ) ;
bool loop = cd . from - > animation - > has_loop ( ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( ! loop ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( next_pos < 0 )
next_pos = 0 ;
else if ( next_pos > len )
next_pos = len ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
// fix delta
2017-03-05 16:44:50 +01:00
delta = next_pos - cd . pos ;
2014-02-10 02:10:30 +01:00
if ( & cd = = & playback . current ) {
2018-05-14 04:26:45 +02:00
bool backwards = delta < 0 ;
2017-10-14 22:21:20 +02:00
if ( ! backwards & & cd . pos < = len & & next_pos = = len /*&& playback.blend.empty()*/ ) {
2014-02-10 02:10:30 +01:00
//playback finished
2017-12-28 21:48:09 +01:00
end_reached = true ;
end_notify = cd . pos < len ; // Notify only if not already at the end
2014-02-10 02:10:30 +01:00
}
2017-10-14 22:21:20 +02:00
if ( backwards & & cd . pos > = 0 & & next_pos = = 0 /*&& playback.blend.empty()*/ ) {
2014-02-10 02:10:30 +01:00
//playback finished
2017-12-28 21:48:09 +01:00
end_reached = true ;
end_notify = cd . pos > 0 ; // Notify only if not already at the beginning
2014-02-10 02:10:30 +01:00
}
}
2016-06-26 21:19:58 +02:00
} else {
2016-03-09 00:00:52 +01:00
2017-11-13 12:46:30 +01:00
float looped_next_pos = Math : : fposmod ( next_pos , len ) ;
if ( looped_next_pos = = 0 & & next_pos ! = 0 ) {
// Loop multiples of the length to it, rather than 0
// so state at time=length is previewable in the editor
next_pos = len ;
} else {
next_pos = looped_next_pos ;
}
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
cd . pos = next_pos ;
2014-02-10 02:10:30 +01:00
2018-06-07 17:46:14 +02:00
_animation_process_animation ( cd . from , cd . pos , delta , p_blend , & cd = = & playback . current , p_seeked , p_started ) ;
2014-02-10 02:10:30 +01:00
}
2018-06-07 17:46:14 +02:00
void AnimationPlayer : : _animation_process2 ( float p_delta , bool p_started ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Playback & c = playback ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
accum_pass + + ;
2016-03-09 00:00:52 +01:00
2018-06-07 17:46:14 +02:00
_animation_process_data ( c . current , p_delta , 1.0f , c . seeked & & p_delta ! = 0 , p_started ) ;
if ( p_delta ! = 0 ) {
c . seeked = false ;
}
2014-02-10 02:10:30 +01:00
2016-09-12 04:33:40 +02:00
List < Blend > : : Element * prev = NULL ;
2017-03-05 16:44:50 +01:00
for ( List < Blend > : : Element * E = c . blend . back ( ) ; E ; E = prev ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
Blend & b = E - > get ( ) ;
float blend = b . blend_left / b . blend_time ;
2018-06-07 17:46:14 +02:00
_animation_process_data ( b . data , p_delta , blend , false , false ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
b . blend_left - = Math : : absf ( speed_scale * p_delta ) ;
2016-03-09 00:00:52 +01:00
2016-09-12 04:33:40 +02:00
prev = E - > prev ( ) ;
2017-03-05 16:44:50 +01:00
if ( b . blend_left < 0 ) {
2014-02-10 02:10:30 +01:00
2016-09-12 04:33:40 +02:00
c . blend . erase ( E ) ;
2014-02-10 02:10:30 +01:00
}
}
}
void AnimationPlayer : : _animation_update_transforms ( ) {
2017-10-03 18:49:32 +02:00
{
Transform t ;
for ( int i = 0 ; i < cache_update_size ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-10-03 18:49:32 +02:00
TrackNodeCache * nc = cache_update [ i ] ;
2014-02-10 02:10:30 +01:00
2017-10-03 18:49:32 +02:00
ERR_CONTINUE ( nc - > accum_pass ! = accum_pass ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
t . origin = nc - > loc_accum ;
2018-04-14 21:53:25 +02:00
t . basis . set_quat_scale ( nc - > rot_accum , nc - > scale_accum ) ;
2017-03-05 16:44:50 +01:00
if ( nc - > skeleton & & nc - > bone_idx > = 0 ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
nc - > skeleton - > set_bone_pose ( nc - > bone_idx , t ) ;
2014-02-10 02:10:30 +01:00
} else if ( nc - > spatial ) {
nc - > spatial - > set_transform ( t ) ;
}
}
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
cache_update_size = 0 ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < cache_update_prop_size ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
TrackNodeCache : : PropertyAnim * pa = cache_update_prop [ i ] ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_CONTINUE ( pa - > accum_pass ! = accum_pass ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
switch ( pa - > special ) {
2015-12-05 18:18:22 +01:00
case SP_NONE : {
bool valid ;
2017-05-30 22:20:15 +02:00
pa - > object - > set_indexed ( pa - > subpath , pa - > value_accum , & valid ) ; //you are not speshul
2015-12-05 18:18:22 +01:00
# ifdef DEBUG_ENABLED
if ( ! valid ) {
2017-10-05 01:51:19 +02:00
ERR_PRINTS ( " Failed setting key at time " + rtos ( playback . current . pos ) + " in Animation ' " + get_current_animation ( ) + " ' at Node ' " + get_path ( ) + " ', Track ' " + String ( pa - > owner - > path ) + " '. Check if property exists or the type of key is right for the property " ) ;
2015-12-05 18:18:22 +01:00
}
# endif
} break ;
case SP_NODE2D_POS : {
# ifdef DEBUG_ENABLED
2017-03-05 16:44:50 +01:00
if ( pa - > value_accum . get_type ( ) ! = Variant : : VECTOR2 ) {
2017-10-05 01:51:19 +02:00
ERR_PRINTS ( " Position key at time " + rtos ( playback . current . pos ) + " in Animation ' " + get_current_animation ( ) + " ' at Node ' " + get_path ( ) + " ', Track ' " + String ( pa - > owner - > path ) + " ' not of type Vector2() " ) ;
2015-12-05 18:18:22 +01:00
}
# endif
2017-03-05 16:44:50 +01:00
static_cast < Node2D * > ( pa - > object ) - > set_position ( pa - > value_accum ) ;
2015-12-05 18:18:22 +01:00
} break ;
case SP_NODE2D_ROT : {
# ifdef DEBUG_ENABLED
if ( pa - > value_accum . is_num ( ) ) {
2017-10-05 01:51:19 +02:00
ERR_PRINTS ( " Rotation key at time " + rtos ( playback . current . pos ) + " in Animation ' " + get_current_animation ( ) + " ' at Node ' " + get_path ( ) + " ', Track ' " + String ( pa - > owner - > path ) + " ' not numerical " ) ;
2015-12-05 18:18:22 +01:00
}
# endif
2017-03-05 16:44:50 +01:00
static_cast < Node2D * > ( pa - > object ) - > set_rotation ( Math : : deg2rad ( ( double ) pa - > value_accum ) ) ;
2015-12-05 18:18:22 +01:00
} break ;
case SP_NODE2D_SCALE : {
# ifdef DEBUG_ENABLED
2017-03-05 16:44:50 +01:00
if ( pa - > value_accum . get_type ( ) ! = Variant : : VECTOR2 ) {
2017-10-05 01:51:19 +02:00
ERR_PRINTS ( " Scale key at time " + rtos ( playback . current . pos ) + " in Animation ' " + get_current_animation ( ) + " ' at Node ' " + get_path ( ) + " ', Track ' " + String ( pa - > owner - > path ) + " ' not of type Vector2() " ) ;
2015-12-05 18:18:22 +01:00
}
# endif
2017-03-05 16:44:50 +01:00
static_cast < Node2D * > ( pa - > object ) - > set_scale ( pa - > value_accum ) ;
2015-12-05 18:18:22 +01:00
} break ;
2014-02-10 02:10:30 +01:00
}
}
2017-03-05 16:44:50 +01:00
cache_update_prop_size = 0 ;
2018-06-07 17:46:14 +02:00
for ( int i = 0 ; i < cache_update_bezier_size ; i + + ) {
TrackNodeCache : : BezierAnim * ba = cache_update_bezier [ i ] ;
ERR_CONTINUE ( ba - > accum_pass ! = accum_pass ) ;
ba - > object - > set_indexed ( ba - > bezier_property , ba - > bezier_accum ) ;
}
cache_update_bezier_size = 0 ;
2014-02-10 02:10:30 +01:00
}
void AnimationPlayer : : _animation_process ( float p_delta ) {
if ( playback . current . from ) {
2017-12-28 21:48:09 +01:00
end_reached = false ;
2017-03-05 16:44:50 +01:00
end_notify = false ;
2018-06-07 17:46:14 +02:00
_animation_process2 ( p_delta , playback . started ) ;
if ( playback . started ) {
playback . started = false ;
}
2014-02-10 02:10:30 +01:00
_animation_update_transforms ( ) ;
2017-12-28 21:48:09 +01:00
if ( end_reached ) {
2014-02-10 02:10:30 +01:00
if ( queued . size ( ) ) {
String old = playback . assigned ;
play ( queued . front ( ) - > get ( ) ) ;
String new_name = playback . assigned ;
queued . pop_front ( ) ;
2017-12-28 21:48:09 +01:00
if ( end_notify )
emit_signal ( SceneStringNames : : get_singleton ( ) - > animation_changed , old , new_name ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
//stop();
2014-02-10 02:10:30 +01:00
playing = false ;
_set_process ( false ) ;
2017-12-28 21:48:09 +01:00
if ( end_notify )
emit_signal ( SceneStringNames : : get_singleton ( ) - > animation_finished , playback . assigned ) ;
2014-02-10 02:10:30 +01:00
}
2017-12-28 21:48:09 +01:00
end_reached = false ;
2014-02-10 02:10:30 +01:00
}
} else {
_set_process ( false ) ;
}
}
2017-03-05 16:44:50 +01:00
Error AnimationPlayer : : add_animation ( const StringName & p_name , const Ref < Animation > & p_animation ) {
2014-02-10 02:10:30 +01:00
2015-06-29 05:29:49 +02:00
# ifdef DEBUG_ENABLED
2017-03-05 16:44:50 +01:00
ERR_EXPLAIN ( " Invalid animation name: " + String ( p_name ) ) ;
ERR_FAIL_COND_V ( String ( p_name ) . find ( " / " ) ! = - 1 | | String ( p_name ) . find ( " : " ) ! = - 1 | | String ( p_name ) . find ( " , " ) ! = - 1 | | String ( p_name ) . find ( " [ " ) ! = - 1 , ERR_INVALID_PARAMETER ) ;
2015-06-29 05:29:49 +02:00
# endif
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( p_animation . is_null ( ) , ERR_INVALID_PARAMETER ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( animation_set . has ( p_name ) ) {
_unref_anim ( animation_set [ p_name ] . animation ) ;
2017-03-05 16:44:50 +01:00
animation_set [ p_name ] . animation = p_animation ;
2014-02-10 02:10:30 +01:00
clear_caches ( ) ;
} else {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
AnimationData ad ;
2017-03-05 16:44:50 +01:00
ad . animation = p_animation ;
ad . name = p_name ;
animation_set [ p_name ] = ad ;
2016-03-09 00:00:52 +01:00
}
2014-02-10 02:10:30 +01:00
_ref_anim ( p_animation ) ;
_change_notify ( ) ;
return OK ;
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : remove_animation ( const StringName & p_name ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( ! animation_set . has ( p_name ) ) ;
2016-03-09 00:00:52 +01:00
2017-12-14 00:07:39 +01:00
stop ( ) ;
2014-02-10 02:10:30 +01:00
_unref_anim ( animation_set [ p_name ] . animation ) ;
2016-03-09 00:00:52 +01:00
animation_set . erase ( p_name ) ;
2014-02-10 02:10:30 +01:00
clear_caches ( ) ;
_change_notify ( ) ;
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : _ref_anim ( const Ref < Animation > & p_anim ) {
2014-02-10 02:10:30 +01:00
2019-02-14 14:19:03 +01:00
Ref < Animation > ( p_anim ) - > connect ( SceneStringNames : : get_singleton ( ) - > tracks_changed , this , " _animation_changed " , varray ( ) , CONNECT_REFERENCE_COUNTED ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : _unref_anim ( const Ref < Animation > & p_anim ) {
2014-02-10 02:10:30 +01:00
2019-02-14 14:19:03 +01:00
Ref < Animation > ( p_anim ) - > disconnect ( SceneStringNames : : get_singleton ( ) - > tracks_changed , this , " _animation_changed " ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : rename_animation ( const StringName & p_name , const StringName & p_new_name ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( ! animation_set . has ( p_name ) ) ;
ERR_FAIL_COND ( String ( p_new_name ) . find ( " / " ) ! = - 1 | | String ( p_new_name ) . find ( " : " ) ! = - 1 ) ;
ERR_FAIL_COND ( animation_set . has ( p_new_name ) ) ;
2014-02-10 02:10:30 +01:00
2017-12-14 00:07:39 +01:00
stop ( ) ;
2014-02-10 02:10:30 +01:00
AnimationData ad = animation_set [ p_name ] ;
2017-03-05 16:44:50 +01:00
ad . name = p_new_name ;
2014-02-10 02:10:30 +01:00
animation_set . erase ( p_name ) ;
2017-03-05 16:44:50 +01:00
animation_set [ p_new_name ] = ad ;
2014-02-10 02:10:30 +01:00
List < BlendKey > to_erase ;
2017-03-05 16:44:50 +01:00
Map < BlendKey , float > to_insert ;
for ( Map < BlendKey , float > : : Element * E = blend_times . front ( ) ; E ; E = E - > next ( ) ) {
BlendKey bk = E - > key ( ) ;
BlendKey new_bk = bk ;
bool erase = false ;
if ( bk . from = = p_name ) {
new_bk . from = p_new_name ;
erase = true ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
if ( bk . to = = p_name ) {
new_bk . to = p_new_name ;
erase = true ;
2014-02-10 02:10:30 +01:00
}
if ( erase ) {
to_erase . push_back ( bk ) ;
2017-03-05 16:44:50 +01:00
to_insert [ new_bk ] = E - > get ( ) ;
2014-02-10 02:10:30 +01:00
}
}
2017-03-05 16:44:50 +01:00
while ( to_erase . size ( ) ) {
2014-02-10 02:10:30 +01:00
blend_times . erase ( to_erase . front ( ) - > get ( ) ) ;
2017-01-14 18:03:38 +01:00
to_erase . pop_front ( ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
while ( to_insert . size ( ) ) {
blend_times [ to_insert . front ( ) - > key ( ) ] = to_insert . front ( ) - > get ( ) ;
2014-02-10 02:10:30 +01:00
to_insert . erase ( to_insert . front ( ) ) ;
}
2017-03-05 16:44:50 +01:00
if ( autoplay = = p_name )
autoplay = p_new_name ;
2014-02-10 02:10:30 +01:00
clear_caches ( ) ;
_change_notify ( ) ;
}
2017-03-05 16:44:50 +01:00
bool AnimationPlayer : : has_animation ( const StringName & p_name ) const {
2014-02-10 02:10:30 +01:00
return animation_set . has ( p_name ) ;
}
2017-03-05 16:44:50 +01:00
Ref < Animation > AnimationPlayer : : get_animation ( const StringName & p_name ) const {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! animation_set . has ( p_name ) , Ref < Animation > ( ) ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
const AnimationData & data = animation_set [ p_name ] ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return data . animation ;
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : get_animation_list ( List < StringName > * p_animations ) const {
2014-02-10 02:10:30 +01:00
List < String > anims ;
2017-03-05 16:44:50 +01:00
for ( Map < StringName , AnimationData > : : Element * E = animation_set . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
anims . push_back ( E - > key ( ) ) ;
}
anims . sort ( ) ;
2017-03-05 16:44:50 +01:00
for ( List < String > : : Element * E = anims . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
p_animations - > push_back ( E - > get ( ) ) ;
}
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : set_blend_time ( const StringName & p_animation1 , const StringName & p_animation2 , float p_time ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_time < 0 ) ;
2014-02-10 02:10:30 +01:00
BlendKey bk ;
2017-03-05 16:44:50 +01:00
bk . from = p_animation1 ;
bk . to = p_animation2 ;
if ( p_time = = 0 )
2014-02-10 02:10:30 +01:00
blend_times . erase ( bk ) ;
else
2017-03-05 16:44:50 +01:00
blend_times [ bk ] = p_time ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
float AnimationPlayer : : get_blend_time ( const StringName & p_animation1 , const StringName & p_animation2 ) const {
2014-02-10 02:10:30 +01:00
BlendKey bk ;
2017-03-05 16:44:50 +01:00
bk . from = p_animation1 ;
bk . to = p_animation2 ;
2014-02-10 02:10:30 +01:00
if ( blend_times . has ( bk ) )
return blend_times [ bk ] ;
else
return 0 ;
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : queue ( const StringName & p_name ) {
2014-02-10 02:10:30 +01:00
if ( ! is_playing ( ) )
play ( p_name ) ;
else
queued . push_back ( p_name ) ;
}
2018-11-28 01:43:34 +01:00
PoolVector < String > AnimationPlayer : : get_queue ( ) {
PoolVector < String > ret ;
for ( List < StringName > : : Element * E = queued . front ( ) ; E ; E = E - > next ( ) ) {
ret . push_back ( E - > get ( ) ) ;
}
return ret ;
}
2014-02-10 02:10:30 +01:00
void AnimationPlayer : : clear_queue ( ) {
queued . clear ( ) ;
2018-06-07 17:46:14 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : play_backwards ( const StringName & p_name , float p_custom_blend ) {
2015-09-10 05:10:54 +02:00
2017-03-05 16:44:50 +01:00
play ( p_name , p_custom_blend , - 1 , true ) ;
2015-09-10 05:10:54 +02:00
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : play ( const StringName & p_name , float p_custom_blend , float p_custom_scale , bool p_from_end ) {
2014-02-10 02:10:30 +01:00
//printf("animation is %ls\n", String(p_name).c_str());
//ERR_FAIL_COND(!is_inside_scene());
2017-03-05 16:44:50 +01:00
StringName name = p_name ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( String ( name ) = = " " )
name = playback . assigned ;
2014-02-10 02:10:30 +01:00
if ( ! animation_set . has ( name ) ) {
2017-03-05 16:44:50 +01:00
ERR_EXPLAIN ( " Animation not found: " + name ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL ( ) ;
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
Playback & c = playback ;
2014-02-10 02:10:30 +01:00
if ( c . current . from ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
float blend_time = 0 ;
2014-02-10 02:10:30 +01:00
// find if it can blend
BlendKey bk ;
2017-03-05 16:44:50 +01:00
bk . from = c . current . from - > name ;
bk . to = name ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( p_custom_blend > = 0 ) {
blend_time = p_custom_blend ;
2014-02-10 02:10:30 +01:00
} else if ( blend_times . has ( bk ) ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
blend_time = blend_times [ bk ] ;
2014-02-10 02:10:30 +01:00
} else {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
bk . from = " * " ;
2014-02-10 02:10:30 +01:00
if ( blend_times . has ( bk ) ) {
2017-03-05 16:44:50 +01:00
blend_time = blend_times [ bk ] ;
2014-02-10 02:10:30 +01:00
} else {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
bk . from = c . current . from - > name ;
bk . to = " * " ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( blend_times . has ( bk ) ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
blend_time = blend_times [ bk ] ;
2014-02-10 02:10:30 +01:00
}
}
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( p_custom_blend < 0 & & blend_time = = 0 & & default_blend_time )
blend_time = default_blend_time ;
if ( blend_time > 0 ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
Blend b ;
2017-03-05 16:44:50 +01:00
b . data = c . current ;
b . blend_time = b . blend_left = blend_time ;
2016-03-09 00:00:52 +01:00
c . blend . push_back ( b ) ;
2014-02-10 02:10:30 +01:00
}
}
2016-03-09 00:00:52 +01:00
2018-06-07 17:46:14 +02:00
_stop_playing_caches ( ) ;
2017-03-05 16:44:50 +01:00
c . current . from = & animation_set [ name ] ;
2019-02-13 18:40:22 +01:00
if ( c . assigned ! = name ) { // reset
c . current . pos = p_from_end ? c . current . from - > animation - > get_length ( ) : 0 ;
2019-02-20 19:58:53 +01:00
} else {
if ( p_from_end & & c . current . pos = = 0 ) {
// Animation reset BUT played backwards, set position to the end
c . current . pos = c . current . from - > animation - > get_length ( ) ;
} else if ( ! p_from_end & & c . current . pos = = c . current . from - > animation - > get_length ( ) ) {
// Animation resumed but already ended, set position to the beggining
c . current . pos = 0 ;
}
2019-02-13 18:40:22 +01:00
}
2017-03-05 16:44:50 +01:00
c . current . speed_scale = p_custom_scale ;
2019-02-13 18:40:22 +01:00
c . assigned = name ;
2018-06-07 17:46:14 +02:00
c . seeked = false ;
c . started = true ;
2014-02-10 02:10:30 +01:00
2017-12-28 21:48:09 +01:00
if ( ! end_reached )
2014-08-14 15:31:38 +02:00
queued . clear ( ) ;
2014-02-10 02:10:30 +01:00
_set_process ( true ) ; // always process when starting an animation
playing = true ;
2016-05-21 15:29:25 +02:00
2016-04-14 17:19:20 +02:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > animation_started , c . assigned ) ;
2014-02-10 02:10:30 +01:00
2017-08-19 01:02:56 +02:00
if ( is_inside_tree ( ) & & Engine : : get_singleton ( ) - > is_editor_hint ( ) )
2014-02-10 02:10:30 +01:00
return ; // no next in this case
2017-03-05 16:44:50 +01:00
StringName next = animation_get_next ( p_name ) ;
if ( next ! = StringName ( ) & & animation_set . has ( next ) ) {
2014-02-10 02:10:30 +01:00
queue ( next ) ;
}
}
bool AnimationPlayer : : is_playing ( ) const {
2017-03-05 16:44:50 +01:00
return playing ;
/*
2014-02-10 02:10:30 +01:00
if ( playback . current . from = = NULL )
return false ;
float len = playback . current . from - > animation - > get_length ( ) ;
float pos = playback . current . pos ;
bool loop = playback . current . from - > animation - > has_loop ( ) ;
if ( ! loop & & pos > = len ) {
return false ;
} ;
return true ;
2018-01-11 23:35:12 +01:00
*/
2014-02-10 02:10:30 +01:00
}
2018-01-14 11:28:57 +01:00
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : set_current_animation ( const String & p_anim ) {
2014-02-10 02:10:30 +01:00
2018-01-11 23:35:12 +01:00
if ( p_anim = = " [stop] " | | p_anim = = " " ) {
stop ( ) ;
} else if ( ! is_playing ( ) | | playback . assigned ! = p_anim ) {
2014-02-10 02:10:30 +01:00
play ( p_anim ) ;
} else {
2018-01-11 23:35:12 +01:00
// Same animation, do not replay from start
2014-02-10 02:10:30 +01:00
}
}
String AnimationPlayer : : get_current_animation ( ) const {
2018-01-11 23:35:12 +01:00
return ( is_playing ( ) ? playback . assigned : " " ) ;
2014-02-10 02:10:30 +01:00
}
2018-01-14 11:28:57 +01:00
void AnimationPlayer : : set_assigned_animation ( const String & p_anim ) {
if ( is_playing ( ) ) {
play ( p_anim ) ;
} else {
ERR_FAIL_COND ( ! animation_set . has ( p_anim ) ) ;
playback . current . pos = 0 ;
playback . current . from = & animation_set [ p_anim ] ;
playback . assigned = p_anim ;
}
}
String AnimationPlayer : : get_assigned_animation ( ) const {
return playback . assigned ;
}
2015-05-25 06:46:45 +02:00
void AnimationPlayer : : stop ( bool p_reset ) {
2016-03-09 00:00:52 +01:00
2018-06-07 17:46:14 +02:00
_stop_playing_caches ( ) ;
2017-03-05 16:44:50 +01:00
Playback & c = playback ;
2014-02-10 02:10:30 +01:00
c . blend . clear ( ) ;
2015-05-25 06:46:45 +02:00
if ( p_reset ) {
2017-03-05 16:44:50 +01:00
c . current . from = NULL ;
2018-03-09 18:42:24 +01:00
c . current . speed_scale = 1 ;
2019-02-13 18:40:22 +01:00
c . current . pos = 0 ;
2015-05-25 06:46:45 +02:00
}
2014-02-10 02:10:30 +01:00
_set_process ( false ) ;
queued . clear ( ) ;
2015-05-25 06:46:45 +02:00
playing = false ;
2014-02-10 02:10:30 +01:00
}
2017-01-13 23:36:04 +01:00
void AnimationPlayer : : set_speed_scale ( float p_speed ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
speed_scale = p_speed ;
2014-02-10 02:10:30 +01:00
}
2017-01-13 23:36:04 +01:00
float AnimationPlayer : : get_speed_scale ( ) const {
2014-02-10 02:10:30 +01:00
return speed_scale ;
}
2018-03-01 19:52:00 +01:00
float AnimationPlayer : : get_playing_speed ( ) const {
if ( ! playing ) {
return 0 ;
}
return speed_scale * playback . current . speed_scale ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : seek ( float p_time , bool p_update ) {
2014-02-10 02:10:30 +01:00
if ( ! playback . current . from ) {
2018-01-11 23:35:12 +01:00
if ( playback . assigned ) {
ERR_FAIL_COND ( ! animation_set . has ( playback . assigned ) ) ;
playback . current . from = & animation_set [ playback . assigned ] ;
}
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! playback . current . from ) ;
}
2017-03-05 16:44:50 +01:00
playback . current . pos = p_time ;
2018-06-07 17:46:14 +02:00
playback . seeked = true ;
2014-02-10 02:10:30 +01:00
if ( p_update ) {
_animation_process ( 0 ) ;
}
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : seek_delta ( float p_time , float p_delta ) {
2014-02-10 02:10:30 +01:00
if ( ! playback . current . from ) {
2018-01-11 23:35:12 +01:00
if ( playback . assigned ) {
ERR_FAIL_COND ( ! animation_set . has ( playback . assigned ) ) ;
playback . current . from = & animation_set [ playback . assigned ] ;
}
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! playback . current . from ) ;
}
2017-03-05 16:44:50 +01:00
playback . current . pos = p_time - p_delta ;
if ( speed_scale ! = 0.0 )
p_delta / = speed_scale ;
2014-02-10 02:10:30 +01:00
_animation_process ( p_delta ) ;
//playback.current.pos=p_time;
}
bool AnimationPlayer : : is_valid ( ) const {
return ( playback . current . from ) ;
}
2017-09-10 15:37:49 +02:00
float AnimationPlayer : : get_current_animation_position ( ) const {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! playback . current . from , 0 ) ;
2014-02-10 02:10:30 +01:00
return playback . current . pos ;
}
float AnimationPlayer : : get_current_animation_length ( ) const {
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! playback . current . from , 0 ) ;
2014-02-10 02:10:30 +01:00
return playback . current . from - > animation - > get_length ( ) ;
}
void AnimationPlayer : : _animation_changed ( ) {
clear_caches ( ) ;
2018-06-19 03:10:48 +02:00
emit_signal ( " caches_cleared " ) ;
2018-11-19 17:14:37 +01:00
if ( is_playing ( ) ) {
playback . seeked = true ; //need to restart stuff, like audio
}
2014-02-10 02:10:30 +01:00
}
2018-06-07 17:46:14 +02:00
void AnimationPlayer : : _stop_playing_caches ( ) {
for ( Set < TrackNodeCache * > : : Element * E = playing_caches . front ( ) ; E ; E = E - > next ( ) ) {
if ( E - > get ( ) - > node & & E - > get ( ) - > audio_playing ) {
E - > get ( ) - > node - > call ( " stop " ) ;
}
if ( E - > get ( ) - > node & & E - > get ( ) - > animation_playing ) {
AnimationPlayer * player = Object : : cast_to < AnimationPlayer > ( E - > get ( ) - > node ) ;
if ( ! player )
continue ;
player - > stop ( ) ;
}
}
playing_caches . clear ( ) ;
}
2014-02-10 02:10:30 +01:00
void AnimationPlayer : : _node_removed ( Node * p_node ) {
clear_caches ( ) ; // nodes contained here ar being removed, clear the caches
}
void AnimationPlayer : : clear_caches ( ) {
2018-06-07 17:46:14 +02:00
_stop_playing_caches ( ) ;
2014-02-10 02:10:30 +01:00
node_cache_map . clear ( ) ;
2017-03-05 16:44:50 +01:00
for ( Map < StringName , AnimationData > : : Element * E = animation_set . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
E - > get ( ) . node_cache . clear ( ) ;
}
2017-03-05 16:44:50 +01:00
cache_update_size = 0 ;
cache_update_prop_size = 0 ;
2018-06-07 17:46:14 +02:00
cache_update_bezier_size = 0 ;
2014-02-10 02:10:30 +01:00
}
void AnimationPlayer : : set_active ( bool p_active ) {
2017-03-05 16:44:50 +01:00
if ( active = = p_active )
2014-02-10 02:10:30 +01:00
return ;
2017-03-05 16:44:50 +01:00
active = p_active ;
_set_process ( processing , true ) ;
2014-02-10 02:10:30 +01:00
}
bool AnimationPlayer : : is_active ( ) const {
return active ;
}
2017-03-05 16:44:50 +01:00
StringName AnimationPlayer : : find_animation ( const Ref < Animation > & p_animation ) const {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( Map < StringName , AnimationData > : : Element * E = animation_set . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( E - > get ( ) . animation = = p_animation )
2014-02-10 02:10:30 +01:00
return E - > key ( ) ;
}
return " " ;
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : set_autoplay ( const String & p_name ) {
2018-10-05 00:09:53 +02:00
if ( is_inside_tree ( ) & & ! Engine : : get_singleton ( ) - > is_editor_hint ( ) )
WARN_PRINT ( " Setting autoplay after the node has been added to the scene has no effect. " ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
autoplay = p_name ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
String AnimationPlayer : : get_autoplay ( ) const {
2014-02-10 02:10:30 +01:00
return autoplay ;
}
void AnimationPlayer : : set_animation_process_mode ( AnimationProcessMode p_mode ) {
2017-03-05 16:44:50 +01:00
if ( animation_process_mode = = p_mode )
2014-02-10 02:10:30 +01:00
return ;
bool pr = processing ;
if ( pr )
_set_process ( false ) ;
2017-03-05 16:44:50 +01:00
animation_process_mode = p_mode ;
2014-02-10 02:10:30 +01:00
if ( pr )
_set_process ( true ) ;
}
2017-03-05 16:44:50 +01:00
AnimationPlayer : : AnimationProcessMode AnimationPlayer : : get_animation_process_mode ( ) const {
2014-02-10 02:10:30 +01:00
return animation_process_mode ;
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : _set_process ( bool p_process , bool p_force ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( processing = = p_process & & ! p_force )
2014-02-10 02:10:30 +01:00
return ;
2017-03-05 16:44:50 +01:00
switch ( animation_process_mode ) {
2014-02-10 02:10:30 +01:00
2017-09-30 16:19:07 +02:00
case ANIMATION_PROCESS_PHYSICS : set_physics_process_internal ( p_process & & active ) ; break ;
2017-01-10 22:02:19 +01:00
case ANIMATION_PROCESS_IDLE : set_process_internal ( p_process & & active ) ; break ;
2018-09-26 13:13:56 +02:00
case ANIMATION_PROCESS_MANUAL : break ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
processing = p_process ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : animation_set_next ( const StringName & p_animation , const StringName & p_next ) {
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! animation_set . has ( p_animation ) ) ;
2017-03-05 16:44:50 +01:00
animation_set [ p_animation ] . next = p_next ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
StringName AnimationPlayer : : animation_get_next ( const StringName & p_animation ) const {
2014-02-10 02:10:30 +01:00
if ( ! animation_set . has ( p_animation ) )
return StringName ( ) ;
return animation_set [ p_animation ] . next ;
}
void AnimationPlayer : : set_default_blend_time ( float p_default ) {
2017-03-05 16:44:50 +01:00
default_blend_time = p_default ;
2014-02-10 02:10:30 +01:00
}
float AnimationPlayer : : get_default_blend_time ( ) const {
2017-03-05 16:44:50 +01:00
return default_blend_time ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : set_root ( const NodePath & p_root ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
root = p_root ;
2014-02-10 02:10:30 +01:00
clear_caches ( ) ;
}
NodePath AnimationPlayer : : get_root ( ) const {
return root ;
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
2014-12-17 02:31:57 +01:00
String pf = p_function ;
2018-05-07 17:28:55 +02:00
if ( p_function = = " play " | | p_function = = " play_backwards " | | p_function = = " remove_animation " | | p_function = = " has_animation " | | p_function = = " queue " ) {
2014-12-17 02:31:57 +01:00
List < StringName > al ;
get_animation_list ( & al ) ;
2017-03-05 16:44:50 +01:00
for ( List < StringName > : : Element * E = al . front ( ) ; E ; E = E - > next ( ) ) {
2014-12-17 02:31:57 +01:00
2017-03-05 16:44:50 +01:00
r_options - > push_back ( " \" " + String ( E - > get ( ) ) + " \" " ) ;
2014-12-17 02:31:57 +01:00
}
}
2017-03-05 16:44:50 +01:00
Node : : get_argument_options ( p_function , p_idx , r_options ) ;
2014-12-17 02:31:57 +01:00
}
2014-02-10 02:10:30 +01:00
2017-11-01 21:32:39 +01:00
# ifdef TOOLS_ENABLED
AnimatedValuesBackup AnimationPlayer : : backup_animated_values ( ) {
if ( ! playback . current . from )
return AnimatedValuesBackup ( ) ;
_ensure_node_caches ( playback . current . from ) ;
AnimatedValuesBackup backup ;
for ( int i = 0 ; i < playback . current . from - > node_cache . size ( ) ; i + + ) {
TrackNodeCache * nc = playback . current . from - > node_cache [ i ] ;
if ( ! nc )
continue ;
if ( nc - > skeleton ) {
if ( nc - > bone_idx = = - 1 )
continue ;
AnimatedValuesBackup : : Entry entry ;
entry . object = nc - > skeleton ;
entry . bone_idx = nc - > bone_idx ;
entry . value = nc - > skeleton - > get_bone_pose ( nc - > bone_idx ) ;
backup . entries . push_back ( entry ) ;
} else {
if ( nc - > spatial ) {
AnimatedValuesBackup : : Entry entry ;
entry . object = nc - > spatial ;
entry . subpath . push_back ( " transform " ) ;
entry . value = nc - > spatial - > get_transform ( ) ;
entry . bone_idx = - 1 ;
backup . entries . push_back ( entry ) ;
} else {
for ( Map < StringName , TrackNodeCache : : PropertyAnim > : : Element * E = nc - > property_anim . front ( ) ; E ; E = E - > next ( ) ) {
AnimatedValuesBackup : : Entry entry ;
entry . object = E - > value ( ) . object ;
entry . subpath = E - > value ( ) . subpath ;
bool valid ;
entry . value = E - > value ( ) . object - > get_indexed ( E - > value ( ) . subpath , & valid ) ;
entry . bone_idx = - 1 ;
if ( valid )
backup . entries . push_back ( entry ) ;
}
}
}
}
return backup ;
}
void AnimationPlayer : : restore_animated_values ( const AnimatedValuesBackup & p_backup ) {
for ( int i = 0 ; i < p_backup . entries . size ( ) ; i + + ) {
const AnimatedValuesBackup : : Entry * entry = & p_backup . entries [ i ] ;
if ( entry - > bone_idx = = - 1 ) {
entry - > object - > set_indexed ( entry - > subpath , entry - > value ) ;
} else {
Object : : cast_to < Skeleton > ( entry - > object ) - > set_bone_pose ( entry - > bone_idx , entry - > value ) ;
}
}
}
# endif
2014-02-10 02:10:30 +01:00
void AnimationPlayer : : _bind_methods ( ) {
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " _node_removed " ) , & AnimationPlayer : : _node_removed ) ;
ClassDB : : bind_method ( D_METHOD ( " _animation_changed " ) , & AnimationPlayer : : _animation_changed ) ;
2014-02-10 02:10:30 +01:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_animation " , " name " , " animation " ) , & AnimationPlayer : : add_animation ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " remove_animation " , " name " ) , & AnimationPlayer : : remove_animation ) ;
ClassDB : : bind_method ( D_METHOD ( " rename_animation " , " name " , " newname " ) , & AnimationPlayer : : rename_animation ) ;
ClassDB : : bind_method ( D_METHOD ( " has_animation " , " name " ) , & AnimationPlayer : : has_animation ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_animation " , " name " ) , & AnimationPlayer : : get_animation ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_animation_list " ) , & AnimationPlayer : : _get_animation_list ) ;
2016-03-09 00:00:52 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " animation_set_next " , " anim_from " , " anim_to " ) , & AnimationPlayer : : animation_set_next ) ;
ClassDB : : bind_method ( D_METHOD ( " animation_get_next " , " anim_from " ) , & AnimationPlayer : : animation_get_next ) ;
2016-05-07 18:27:52 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_blend_time " , " anim_from " , " anim_to " , " sec " ) , & AnimationPlayer : : set_blend_time ) ;
ClassDB : : bind_method ( D_METHOD ( " get_blend_time " , " anim_from " , " anim_to " ) , & AnimationPlayer : : get_blend_time ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_default_blend_time " , " sec " ) , & AnimationPlayer : : set_default_blend_time ) ;
ClassDB : : bind_method ( D_METHOD ( " get_default_blend_time " ) , & AnimationPlayer : : get_default_blend_time ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " play " , " name " , " custom_blend " , " custom_speed " , " from_end " ) , & AnimationPlayer : : play , DEFVAL ( " " ) , DEFVAL ( - 1 ) , DEFVAL ( 1.0 ) , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " play_backwards " , " name " , " custom_blend " ) , & AnimationPlayer : : play_backwards , DEFVAL ( " " ) , DEFVAL ( - 1 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " stop " , " reset " ) , & AnimationPlayer : : stop , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " is_playing " ) , & AnimationPlayer : : is_playing ) ;
2017-12-14 00:07:39 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_current_animation " , " anim " ) , & AnimationPlayer : : set_current_animation ) ;
ClassDB : : bind_method ( D_METHOD ( " get_current_animation " ) , & AnimationPlayer : : get_current_animation ) ;
2018-01-14 11:28:57 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_assigned_animation " , " anim " ) , & AnimationPlayer : : set_assigned_animation ) ;
ClassDB : : bind_method ( D_METHOD ( " get_assigned_animation " ) , & AnimationPlayer : : get_assigned_animation ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " queue " , " name " ) , & AnimationPlayer : : queue ) ;
2018-11-28 01:43:34 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_queue " ) , & AnimationPlayer : : get_queue ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear_queue " ) , & AnimationPlayer : : clear_queue ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_active " , " active " ) , & AnimationPlayer : : set_active ) ;
ClassDB : : bind_method ( D_METHOD ( " is_active " ) , & AnimationPlayer : : is_active ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_speed_scale " , " speed " ) , & AnimationPlayer : : set_speed_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " get_speed_scale " ) , & AnimationPlayer : : get_speed_scale ) ;
2018-03-01 19:52:00 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_playing_speed " ) , & AnimationPlayer : : get_playing_speed ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_autoplay " , " name " ) , & AnimationPlayer : : set_autoplay ) ;
ClassDB : : bind_method ( D_METHOD ( " get_autoplay " ) , & AnimationPlayer : : get_autoplay ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_root " , " path " ) , & AnimationPlayer : : set_root ) ;
ClassDB : : bind_method ( D_METHOD ( " get_root " ) , & AnimationPlayer : : get_root ) ;
2014-02-10 02:10:30 +01:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " find_animation " , " animation " ) , & AnimationPlayer : : find_animation ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear_caches " ) , & AnimationPlayer : : clear_caches ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_animation_process_mode " , " mode " ) , & AnimationPlayer : : set_animation_process_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_animation_process_mode " ) , & AnimationPlayer : : get_animation_process_mode ) ;
2014-02-10 02:10:30 +01:00
2017-12-07 18:19:21 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_current_animation_position " ) , & AnimationPlayer : : get_current_animation_position ) ;
ClassDB : : bind_method ( D_METHOD ( " get_current_animation_length " ) , & AnimationPlayer : : get_current_animation_length ) ;
2017-12-14 00:07:39 +01:00
ClassDB : : bind_method ( D_METHOD ( " seek " , " seconds " , " update " ) , & AnimationPlayer : : seek , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " advance " , " delta " ) , & AnimationPlayer : : advance ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : NODE_PATH , " root_node " ) , " set_root " , " get_root " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " current_animation " , PROPERTY_HINT_ENUM , " " , PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ANIMATE_AS_TRIGGER ) , " set_current_animation " , " get_current_animation " ) ;
2018-01-14 11:28:57 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " assigned_animation " , PROPERTY_HINT_NONE , " " , 0 ) , " set_assigned_animation " , " get_assigned_animation " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " autoplay " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR ) , " set_autoplay " , " get_autoplay " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : REAL , " current_animation_length " , PROPERTY_HINT_NONE , " " , 0 ) , " " , " get_current_animation_length " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : REAL , " current_animation_position " , PROPERTY_HINT_NONE , " " , 0 ) , " " , " get_current_animation_position " ) ;
2017-08-07 03:51:56 +02:00
ADD_GROUP ( " Playback Options " , " playback_ " ) ;
2018-08-02 09:22:24 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " playback_process_mode " , PROPERTY_HINT_ENUM , " Physics,Idle,Manual " ) , " set_animation_process_mode " , " get_animation_process_mode " ) ;
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : REAL , " playback_default_blend_time " , PROPERTY_HINT_RANGE , " 0,4096,0.01 " ) , " set_default_blend_time " , " get_default_blend_time " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " playback_active " , PROPERTY_HINT_NONE , " " , 0 ) , " set_active " , " is_active " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : REAL , " playback_speed " , PROPERTY_HINT_RANGE , " -64,64,0.01 " ) , " set_speed_scale " , " get_speed_scale " ) ;
2014-02-10 02:10:30 +01:00
2018-01-12 15:45:29 +01:00
ADD_SIGNAL ( MethodInfo ( " animation_finished " , PropertyInfo ( Variant : : STRING , " anim_name " ) ) ) ;
2017-03-05 16:44:50 +01:00
ADD_SIGNAL ( MethodInfo ( " animation_changed " , PropertyInfo ( Variant : : STRING , " old_name " ) , PropertyInfo ( Variant : : STRING , " new_name " ) ) ) ;
2018-01-12 15:45:29 +01:00
ADD_SIGNAL ( MethodInfo ( " animation_started " , PropertyInfo ( Variant : : STRING , " anim_name " ) ) ) ;
2018-06-19 03:10:48 +02:00
ADD_SIGNAL ( MethodInfo ( " caches_cleared " ) ) ;
2014-02-10 02:10:30 +01:00
2017-09-30 16:19:07 +02:00
BIND_ENUM_CONSTANT ( ANIMATION_PROCESS_PHYSICS ) ;
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( ANIMATION_PROCESS_IDLE ) ;
2018-08-02 09:22:24 +02:00
BIND_ENUM_CONSTANT ( ANIMATION_PROCESS_MANUAL ) ;
2014-02-10 02:10:30 +01:00
}
AnimationPlayer : : AnimationPlayer ( ) {
2017-03-05 16:44:50 +01:00
accum_pass = 1 ;
cache_update_size = 0 ;
cache_update_prop_size = 0 ;
2018-06-07 17:46:14 +02:00
cache_update_bezier_size = 0 ;
2017-03-05 16:44:50 +01:00
speed_scale = 1 ;
2017-12-28 21:48:09 +01:00
end_reached = false ;
2017-03-05 16:44:50 +01:00
end_notify = false ;
animation_process_mode = ANIMATION_PROCESS_IDLE ;
processing = false ;
default_blend_time = 0 ;
root = SceneStringNames : : get_singleton ( ) - > path_pp ;
2014-02-10 02:10:30 +01:00
playing = false ;
2017-03-05 16:44:50 +01:00
active = true ;
2018-06-07 17:46:14 +02:00
playback . seeked = false ;
playback . started = false ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
AnimationPlayer : : ~ AnimationPlayer ( ) {
2014-02-10 02:10:30 +01:00
}