ソースを参照

Implement backup/restore for animated values

Pedro J. Estébanez 8 年 前
コミット
ff03a0bc7b
2 ファイル変更92 行追加7 行削除
  1. 70 6
      scene/animation/animation_player.cpp
  2. 22 1
      scene/animation/animation_player.h

+ 70 - 6
scene/animation/animation_player.cpp

@@ -228,7 +228,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);
 	Node *parent = get_node(root);
 
 
@@ -336,11 +340,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) {
 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());
 	ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count());
 
 
 	Animation *a = p_anim->animation.operator->();
 	Animation *a = p_anim->animation.operator->();
@@ -1205,6 +1205,70 @@ void AnimationPlayer::get_argument_options(const StringName &p_function, int p_i
 	Node::get_argument_options(p_function, p_idx, r_options);
 	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() {
 void AnimationPlayer::_bind_methods() {
 
 
 	ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationPlayer::_node_removed);
 	ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationPlayer::_node_removed);

+ 22 - 1
scene/animation/animation_player.h

@@ -38,6 +38,21 @@
 	@author Juan Linietsky <[email protected]>
 	@author Juan Linietsky <[email protected]>
 */
 */
 
 
+#ifdef TOOLS_ENABLED
+// To save/restore animated values
+class AnimatedValuesBackup {
+	struct Entry {
+		Object *object;
+		Vector<StringName> subpath; // Unused if bone
+		int bone_idx; // -1 if not a bone
+		Variant value;
+	};
+	Vector<Entry> entries;
+
+	friend class AnimationPlayer;
+};
+#endif
+
 class AnimationPlayer : public Node {
 class AnimationPlayer : public Node {
 	GDCLASS(AnimationPlayer, Node);
 	GDCLASS(AnimationPlayer, Node);
 	OBJ_CATEGORY("Animation Nodes");
 	OBJ_CATEGORY("Animation Nodes");
@@ -198,7 +213,7 @@ private:
 
 
 	void _animation_process_animation(AnimationData *p_anim, float p_time, float p_delta, float p_interp, bool p_allow_discrete = true);
 	void _animation_process_animation(AnimationData *p_anim, float p_time, float p_delta, float p_interp, bool p_allow_discrete = true);
 
 
-	void _generate_node_caches(AnimationData *p_anim);
+	void _ensure_node_caches(AnimationData *p_anim);
 	void _animation_process_data(PlaybackData &cd, float p_delta, float p_blend);
 	void _animation_process_data(PlaybackData &cd, float p_delta, float p_blend);
 	void _animation_process2(float p_delta);
 	void _animation_process2(float p_delta);
 	void _animation_update_transforms();
 	void _animation_update_transforms();
@@ -291,6 +306,12 @@ public:
 
 
 	void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
 	void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
 
 
+#ifdef TOOLS_ENABLED
+	// These may be interesting for games, but are too dangerous for general use
+	AnimatedValuesBackup backup_animated_values();
+	void restore_animated_values(const AnimatedValuesBackup &p_backup);
+#endif
+
 	AnimationPlayer();
 	AnimationPlayer();
 	~AnimationPlayer();
 	~AnimationPlayer();
 };
 };