diff options
Diffstat (limited to 'scene/animation/animation_player.cpp')
| -rw-r--r-- | scene/animation/animation_player.cpp | 322 | 
1 files changed, 309 insertions, 13 deletions
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index a0e0137863..eac2c8d0c1 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -33,7 +33,7 @@  #include "engine.h"  #include "message_queue.h"  #include "scene/scene_string_names.h" - +#include "servers/audio/audio_stream.h"  #ifdef TOOLS_ENABLED  void AnimatedValuesBackup::update_skeletons() { @@ -325,10 +325,27 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {  				p_anim->node_cache[i]->property_anim[a->track_get_path(i).get_concatenated_subnames()] = pa;  			}  		} + +		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; +				String path = leftover_path[leftover_path.size() - 1]; +				Vector<String> index = path.split("."); +				for (int j = 0; j < index.size(); j++) { +					ba.bezier_property.push_back(index[j]); +				} +				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; +			} +		}  	}  } -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_is_current, bool p_seeked, bool p_started) {  	_ensure_node_caches(p_anim);  	ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count()); @@ -394,7 +411,51 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float  				TrackNodeCache::PropertyAnim *pa = &E->get(); -				if (a->value_track_get_update_mode(i) == Animation::UPDATE_CONTINUOUS || (p_delta == 0 && a->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE)) { //delta == 0 means seek +				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); +					} + +					int key_count = a->track_get_key_count(i); +					if (key_count == 0) +						continue; //eeh not worth it + +					float first_key_time = a->track_get_key_time(i, 0); +					float transition = 1.0; +					int first_key = 0; + +					if (first_key_time == 0.0) { +						//ignore, use for transition +						if (key_count == 1) +							continue; //with one key we cant do anything +						transition = a->track_get_key_transition(i, 0); +						first_key_time = a->track_get_key_time(i, 1); +						first_key = 1; +					} + +					if (p_time < first_key_time) { +						float c = Math::ease(p_time / first_key_time, transition); +						Variant first_value = a->track_get_key_value(i, first_key); +						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  					Variant value = a->value_track_interpolate(i, p_time); @@ -415,7 +476,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float  						Variant::interpolate(pa->value_accum, value, p_interp, pa->value_accum);  					} -				} else if (p_allow_discrete && p_delta != 0) { +				} else if (p_is_current && p_delta != 0) {  					List<int> indices;  					a->value_track_get_key_indices(i, p_time, p_delta, &indices); @@ -470,9 +531,10 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float  				if (!nc->node)  					continue; -				if (p_delta == 0) +				if (p_delta == 0) {  					continue; -				if (!p_allow_discrete) +				} +				if (!p_is_current)  					break;  				List<int> indices; @@ -500,11 +562,195 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float  				}  			} break; +			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) { + +						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) { +							//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;  		}  	}  } -void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, float p_blend) { +void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, float p_blend, bool p_seeked, bool p_started) {  	float delta = p_delta * speed_scale * cd.speed_scale;  	float next_pos = cd.pos + delta; @@ -553,22 +799,25 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, f  	cd.pos = next_pos; -	_animation_process_animation(cd.from, cd.pos, delta, p_blend, &cd == &playback.current); +	_animation_process_animation(cd.from, cd.pos, delta, p_blend, &cd == &playback.current, p_seeked, p_started);  } -void AnimationPlayer::_animation_process2(float p_delta) { +void AnimationPlayer::_animation_process2(float p_delta, bool p_started) {  	Playback &c = playback;  	accum_pass++; -	_animation_process_data(c.current, p_delta, 1.0f); +	_animation_process_data(c.current, p_delta, 1.0f, c.seeked && p_delta != 0, p_started); +	if (p_delta != 0) { +		c.seeked = false; +	}  	List<Blend>::Element *prev = NULL;  	for (List<Blend>::Element *E = c.blend.back(); E; E = prev) {  		Blend &b = E->get();  		float blend = b.blend_left / b.blend_time; -		_animation_process_data(b.data, p_delta, blend); +		_animation_process_data(b.data, p_delta, blend, false, false);  		b.blend_left -= Math::absf(speed_scale * p_delta); @@ -652,6 +901,16 @@ void AnimationPlayer::_animation_update_transforms() {  	}  	cache_update_prop_size = 0; + +	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;  }  void AnimationPlayer::_animation_process(float p_delta) { @@ -660,7 +919,12 @@ void AnimationPlayer::_animation_process(float p_delta) {  		end_reached = false;  		end_notify = false; -		_animation_process2(p_delta); +		_animation_process2(p_delta, playback.started); + +		if (playback.started) { +			playback.started = false; +		} +  		_animation_update_transforms();  		if (end_reached) {  			if (queued.size()) { @@ -865,7 +1129,7 @@ void AnimationPlayer::queue(const StringName &p_name) {  void AnimationPlayer::clear_queue() {  	queued.clear(); -}; +}  void AnimationPlayer::play_backwards(const StringName &p_name, float p_custom_blend) { @@ -930,10 +1194,14 @@ void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float  		}  	} +	_stop_playing_caches(); +  	c.current.from = &animation_set[name];  	c.current.pos = p_from_end ? c.current.from->animation->get_length() : 0;  	c.current.speed_scale = p_custom_scale;  	c.assigned = p_name; +	c.seeked = false; +	c.started = true;  	if (!end_reached)  		queued.clear(); @@ -1004,6 +1272,7 @@ String AnimationPlayer::get_assigned_animation() const {  void AnimationPlayer::stop(bool p_reset) { +	_stop_playing_caches();  	Playback &c = playback;  	c.blend.clear();  	if (p_reset) { @@ -1042,6 +1311,7 @@ void AnimationPlayer::seek(float p_time, bool p_update) {  	}  	playback.current.pos = p_time; +	playback.seeked = true;  	if (p_update) {  		_animation_process(0);  	} @@ -1084,6 +1354,25 @@ float AnimationPlayer::get_current_animation_length() const {  void AnimationPlayer::_animation_changed() {  	clear_caches(); +	emit_signal("caches_cleared"); +} + +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();  }  void AnimationPlayer::_node_removed(Node *p_node) { @@ -1093,6 +1382,8 @@ void AnimationPlayer::_node_removed(Node *p_node) {  void AnimationPlayer::clear_caches() { +	_stop_playing_caches(); +  	node_cache_map.clear();  	for (Map<StringName, AnimationData>::Element *E = animation_set.front(); E; E = E->next()) { @@ -1102,6 +1393,7 @@ void AnimationPlayer::clear_caches() {  	cache_update_size = 0;  	cache_update_prop_size = 0; +	cache_update_bezier_size = 0;  }  void AnimationPlayer::set_active(bool p_active) { @@ -1358,6 +1650,7 @@ void AnimationPlayer::_bind_methods() {  	ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING, "anim_name")));  	ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name")));  	ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING, "anim_name"))); +	ADD_SIGNAL(MethodInfo("caches_cleared"));  	BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);  	BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE); @@ -1368,6 +1661,7 @@ AnimationPlayer::AnimationPlayer() {  	accum_pass = 1;  	cache_update_size = 0;  	cache_update_prop_size = 0; +	cache_update_bezier_size = 0;  	speed_scale = 1;  	end_reached = false;  	end_notify = false; @@ -1377,6 +1671,8 @@ AnimationPlayer::AnimationPlayer() {  	root = SceneStringNames::get_singleton()->path_pp;  	playing = false;  	active = true; +	playback.seeked = false; +	playback.started = false;  }  AnimationPlayer::~AnimationPlayer() {  |