summaryrefslogtreecommitdiff
path: root/scene/animation/animation_player.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/animation/animation_player.cpp')
-rw-r--r--scene/animation/animation_player.cpp140
1 files changed, 103 insertions, 37 deletions
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 6be3ff88d9..5e776c5a1a 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -33,6 +33,17 @@
#include "message_queue.h"
#include "scene/scene_string_names.h"
+#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
+
bool AnimationPlayer::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
@@ -222,13 +233,16 @@ void AnimationPlayer::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
- //stop_all();
clear_caches();
} break;
}
}
-void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) {
+void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
+
+ // Already cached?
+ if (p_anim->node_cache.size() == p_anim->animation->get_track_count())
+ return;
Node *parent = get_node(root);
@@ -242,7 +256,8 @@ void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) {
p_anim->node_cache[i] = NULL;
RES resource;
- Node *child = parent->get_node_and_resource(a->track_get_path(i), resource);
+ Vector<StringName> leftover_path;
+ Node *child = parent->get_node_and_resource(a->track_get_path(i), resource, leftover_path);
if (!child) {
ERR_EXPLAIN("On Animation: '" + p_anim->name + "', couldn't resolve track: '" + String(a->track_get_path(i)) + "'");
}
@@ -250,9 +265,9 @@ void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) {
uint32_t id = resource.is_valid() ? resource->get_instance_id() : child->get_instance_id();
int bone_idx = -1;
- if (a->track_get_path(i).get_property() && Object::cast_to<Skeleton>(child)) {
+ if (a->track_get_path(i).get_subname_count() == 1 && Object::cast_to<Skeleton>(child)) {
- bone_idx = Object::cast_to<Skeleton>(child)->find_bone(a->track_get_path(i).get_property());
+ bone_idx = Object::cast_to<Skeleton>(child)->find_bone(a->track_get_path(i).get_subname(0));
if (bone_idx == -1) {
continue;
@@ -289,8 +304,8 @@ void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) {
p_anim->node_cache[i]->skeleton = Object::cast_to<Skeleton>(child);
if (p_anim->node_cache[i]->skeleton) {
- StringName bone_name = a->track_get_path(i).get_property();
- if (bone_name.operator String() != "") {
+ 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) {
@@ -311,24 +326,23 @@ void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) {
if (a->track_get_type(i) == Animation::TYPE_VALUE) {
- StringName property = a->track_get_path(i).get_property();
- if (!p_anim->node_cache[i]->property_anim.has(property)) {
+ if (!p_anim->node_cache[i]->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) {
TrackNodeCache::PropertyAnim pa;
- pa.prop = property;
+ pa.subpath = leftover_path;
pa.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child;
pa.special = SP_NONE;
pa.owner = p_anim->node_cache[i];
if (false && p_anim->node_cache[i]->node_2d) {
- if (pa.prop == SceneStringNames::get_singleton()->transform_pos)
+ if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_pos)
pa.special = SP_NODE2D_POS;
- else if (pa.prop == SceneStringNames::get_singleton()->transform_rot)
+ else if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_rot)
pa.special = SP_NODE2D_ROT;
- else if (pa.prop == SceneStringNames::get_singleton()->transform_scale)
+ else if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_scale)
pa.special = SP_NODE2D_SCALE;
}
- p_anim->node_cache[i]->property_anim[property] = pa;
+ p_anim->node_cache[i]->property_anim[a->track_get_path(i).get_concatenated_subnames()] = pa;
}
}
}
@@ -336,11 +350,7 @@ void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) {
void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float p_time, float p_delta, float p_interp, bool p_allow_discrete) {
- if (p_anim->node_cache.size() != p_anim->animation->get_track_count()) {
- // animation hasn't been "node-cached"
- _generate_node_caches(p_anim);
- }
-
+ _ensure_node_caches(p_anim);
ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count());
Animation *a = p_anim->animation.operator->();
@@ -353,6 +363,9 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
if (!nc) // no node cache for this track, skip it
continue;
+ if (!a->track_is_enabled(i))
+ continue; // do nothing if the track is disabled
+
if (a->track_get_key_count(i) == 0)
continue; // do nothing if track is empty
@@ -396,7 +409,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
//StringName property=a->track_get_path(i).get_property();
- Map<StringName, TrackNodeCache::PropertyAnim>::Element *E = nc->property_anim.find(a->track_get_path(i).get_property());
+ Map<StringName, TrackNodeCache::PropertyAnim>::Element *E = nc->property_anim.find(a->track_get_path(i).get_concatenated_subnames());
ERR_CONTINUE(!E); //should it continue, or create a new one?
TrackNodeCache::PropertyAnim *pa = &E->get();
@@ -434,7 +447,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
case SP_NONE: {
bool valid;
- pa->object->set(pa->prop, value, &valid); //you are not speshul
+ pa->object->set_indexed(pa->subpath, value, &valid); //you are not speshul
#ifdef DEBUG_ENABLED
if (!valid) {
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() + "'.");
@@ -622,7 +635,7 @@ void AnimationPlayer::_animation_update_transforms() {
case SP_NONE: {
bool valid;
- pa->object->set(pa->prop, pa->value_accum, &valid); //you are not speshul
+ pa->object->set_indexed(pa->subpath, pa->value_accum, &valid); //you are not speshul
#ifdef DEBUG_ENABLED
if (!valid) {
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");
@@ -724,7 +737,7 @@ void AnimationPlayer::remove_animation(const StringName &p_name) {
ERR_FAIL_COND(!animation_set.has(p_name));
- stop_all();
+ stop();
_unref_anim(animation_set[p_name].animation);
animation_set.erase(p_name);
@@ -761,9 +774,7 @@ void AnimationPlayer::rename_animation(const StringName &p_name, const StringNam
ERR_FAIL_COND(String(p_new_name).find("/") != -1 || String(p_new_name).find(":") != -1);
ERR_FAIL_COND(animation_set.has(p_new_name));
- //print_line("Rename anim: "+String(p_name)+" name: "+String(p_new_name));
-
- stop_all();
+ stop();
AnimationData ad = animation_set[p_name];
ad.name = p_new_name;
animation_set.erase(p_name);
@@ -1005,13 +1016,6 @@ void AnimationPlayer::stop(bool p_reset) {
playing = false;
}
-void AnimationPlayer::stop_all() {
-
- stop();
-
- _set_process(false); // always process when starting an animation
-}
-
void AnimationPlayer::set_speed_scale(float p_speed) {
speed_scale = p_speed;
@@ -1205,6 +1209,70 @@ void AnimationPlayer::get_argument_options(const StringName &p_function, int p_i
Node::get_argument_options(p_function, p_idx, r_options);
}
+#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
+
void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationPlayer::_node_removed);
@@ -1229,8 +1297,8 @@ void AnimationPlayer::_bind_methods() {
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("stop_all"), &AnimationPlayer::stop_all);
ClassDB::bind_method(D_METHOD("is_playing"), &AnimationPlayer::is_playing);
+
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);
ClassDB::bind_method(D_METHOD("queue", "name"), &AnimationPlayer::queue);
@@ -1248,9 +1316,6 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root", "path"), &AnimationPlayer::set_root);
ClassDB::bind_method(D_METHOD("get_root"), &AnimationPlayer::get_root);
- ClassDB::bind_method(D_METHOD("seek", "seconds", "update"), &AnimationPlayer::seek, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_position"), &AnimationPlayer::get_current_animation_position);
-
ClassDB::bind_method(D_METHOD("find_animation", "animation"), &AnimationPlayer::find_animation);
ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationPlayer::clear_caches);
@@ -1261,6 +1326,7 @@ void AnimationPlayer::_bind_methods() {
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);
+ ClassDB::bind_method(D_METHOD("seek", "seconds", "update"), &AnimationPlayer::seek, DEFVAL(false));
ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationPlayer::advance);
ADD_GROUP("Playback Options", "playback_");