diff options
Diffstat (limited to 'scene/animation/animation_player.cpp')
-rw-r--r-- | scene/animation/animation_player.cpp | 131 |
1 files changed, 109 insertions, 22 deletions
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 80b7748078..96a59380fa 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; @@ -228,7 +239,11 @@ void AnimationPlayer::_notification(int p_what) { } } -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 +257,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 +266,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 +305,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 +327,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 +351,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->(); @@ -396,7 +407,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 +445,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() + "'."); @@ -545,7 +556,14 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, f } else { - next_pos = Math::fposmod(next_pos, len); + 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; + } } cd.pos = next_pos; @@ -615,7 +633,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"); @@ -1198,6 +1216,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); @@ -1259,7 +1341,12 @@ void AnimationPlayer::_bind_methods() { ADD_GROUP("Playback Options", "playback_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_animation_process_mode", "get_animation_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_default_blend_time", "get_default_blend_time"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root", "get_root"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "autoplay"), "set_autoplay", "get_autoplay"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_animation"), "set_current_animation", "get_current_animation"); ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name"))); |