|
|
|
@ -29,8 +29,12 @@
|
|
|
|
|
/**************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "animation_mixer.h"
|
|
|
|
|
#include "animation_mixer.compat.inc"
|
|
|
|
|
|
|
|
|
|
#include "core/config/engine.h"
|
|
|
|
|
#include "scene/3d/mesh_instance_3d.h"
|
|
|
|
|
#include "scene/3d/node_3d.h"
|
|
|
|
|
#include "scene/3d/skeleton_3d.h"
|
|
|
|
|
#include "scene/animation/animation_player.h"
|
|
|
|
|
#include "scene/resources/animation.h"
|
|
|
|
|
#include "scene/scene_string_names.h"
|
|
|
|
@ -543,7 +547,7 @@ void AnimationMixer::_clear_caches() {
|
|
|
|
|
_init_root_motion_cache();
|
|
|
|
|
_clear_audio_streams();
|
|
|
|
|
_clear_playing_caches();
|
|
|
|
|
for (KeyValue<NodePath, TrackCache *> &K : track_cache) {
|
|
|
|
|
for (KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
|
|
|
|
|
memdelete(K.value);
|
|
|
|
|
}
|
|
|
|
|
track_cache.clear();
|
|
|
|
@ -562,8 +566,9 @@ void AnimationMixer::_clear_audio_streams() {
|
|
|
|
|
|
|
|
|
|
void AnimationMixer::_clear_playing_caches() {
|
|
|
|
|
for (const TrackCache *E : playing_caches) {
|
|
|
|
|
if (ObjectDB::get_instance(E->object_id)) {
|
|
|
|
|
E->object->call(SNAME("stop"), true);
|
|
|
|
|
Object *t_obj = ObjectDB::get_instance(E->object_id);
|
|
|
|
|
if (t_obj) {
|
|
|
|
|
t_obj->call(SNAME("stop"), true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
playing_caches.clear();
|
|
|
|
@ -606,23 +611,20 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
Ref<Animation> anim = get_animation(E);
|
|
|
|
|
for (int i = 0; i < anim->get_track_count(); i++) {
|
|
|
|
|
NodePath path = anim->track_get_path(i);
|
|
|
|
|
Animation::TrackType track_type = anim->track_get_type(i);
|
|
|
|
|
|
|
|
|
|
Animation::TrackType track_cache_type = track_type;
|
|
|
|
|
if (track_cache_type == Animation::TYPE_POSITION_3D || track_cache_type == Animation::TYPE_ROTATION_3D || track_cache_type == Animation::TYPE_SCALE_3D) {
|
|
|
|
|
track_cache_type = Animation::TYPE_POSITION_3D; // Reference them as position3D tracks, even if they modify rotation or scale.
|
|
|
|
|
}
|
|
|
|
|
Animation::TypeHash thash = anim->track_get_type_hash(i);
|
|
|
|
|
Animation::TrackType track_src_type = anim->track_get_type(i);
|
|
|
|
|
Animation::TrackType track_cache_type = Animation::get_cache_type(track_src_type);
|
|
|
|
|
|
|
|
|
|
TrackCache *track = nullptr;
|
|
|
|
|
if (track_cache.has(path)) {
|
|
|
|
|
track = track_cache.get(path);
|
|
|
|
|
if (track_cache.has(thash)) {
|
|
|
|
|
track = track_cache.get(thash);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If not valid, delete track.
|
|
|
|
|
if (track && (track->type != track_cache_type || ObjectDB::get_instance(track->object_id) == nullptr)) {
|
|
|
|
|
playing_caches.erase(track);
|
|
|
|
|
memdelete(track);
|
|
|
|
|
track_cache.erase(path);
|
|
|
|
|
track_cache.erase(thash);
|
|
|
|
|
track = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -636,7 +638,8 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (track_type) {
|
|
|
|
|
switch (track_src_type) {
|
|
|
|
|
case Animation::TYPE_BEZIER:
|
|
|
|
|
case Animation::TYPE_VALUE: {
|
|
|
|
|
// If a value track without a key is cached first, the initial value cannot be determined.
|
|
|
|
|
// It is a corner case, but which may cause problems with blending.
|
|
|
|
@ -645,16 +648,20 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
TrackCacheValue *track_value = memnew(TrackCacheValue);
|
|
|
|
|
|
|
|
|
|
if (resource.is_valid()) {
|
|
|
|
|
track_value->object = resource.ptr();
|
|
|
|
|
track_value->object_id = resource->get_instance_id();
|
|
|
|
|
} else {
|
|
|
|
|
track_value->object = child;
|
|
|
|
|
track_value->object_id = child->get_instance_id();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
track_value->is_continuous = anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
|
|
|
|
|
track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
|
|
|
|
|
if (track_src_type == Animation::TYPE_VALUE) {
|
|
|
|
|
track_value->is_continuous = anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
|
|
|
|
|
track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
|
|
|
|
|
} else {
|
|
|
|
|
track_value->is_continuous = true;
|
|
|
|
|
track_value->is_using_angle = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
track_value->subpath = leftover_path;
|
|
|
|
|
track_value->object_id = track_value->object->get_instance_id();
|
|
|
|
|
|
|
|
|
|
track = track_value;
|
|
|
|
|
|
|
|
|
@ -663,9 +670,9 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
|
|
|
|
|
// If there is a Reset Animation, it takes precedence by overwriting.
|
|
|
|
|
if (has_reset_anim) {
|
|
|
|
|
int rt = reset_anim->find_track(path, track_type);
|
|
|
|
|
int rt = reset_anim->find_track(path, track_src_type);
|
|
|
|
|
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
|
|
|
|
|
track_value->init_value = reset_anim->track_get_key_value(rt, 0);
|
|
|
|
|
track_value->init_value = track_src_type == Animation::TYPE_VALUE ? reset_anim->track_get_key_value(rt, 0) : (reset_anim->track_get_key_value(rt, 0).operator Array())[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -684,14 +691,12 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
TrackCacheTransform *track_xform = memnew(TrackCacheTransform);
|
|
|
|
|
track_xform->type = Animation::TYPE_POSITION_3D;
|
|
|
|
|
|
|
|
|
|
track_xform->node_3d = node_3d;
|
|
|
|
|
track_xform->skeleton = nullptr;
|
|
|
|
|
track_xform->bone_idx = -1;
|
|
|
|
|
|
|
|
|
|
bool has_rest = false;
|
|
|
|
|
if (path.get_subname_count() == 1 && Object::cast_to<Skeleton3D>(node_3d)) {
|
|
|
|
|
Skeleton3D *sk = Object::cast_to<Skeleton3D>(node_3d);
|
|
|
|
|
track_xform->skeleton = sk;
|
|
|
|
|
Skeleton3D *sk = Object::cast_to<Skeleton3D>(node_3d);
|
|
|
|
|
if (sk && path.get_subname_count() == 1) {
|
|
|
|
|
track_xform->skeleton_id = sk->get_instance_id();
|
|
|
|
|
int bone_idx = sk->find_bone(path.get_subname(0));
|
|
|
|
|
if (bone_idx != -1) {
|
|
|
|
|
has_rest = true;
|
|
|
|
@ -703,12 +708,11 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
track_xform->object = node_3d;
|
|
|
|
|
track_xform->object_id = track_xform->object->get_instance_id();
|
|
|
|
|
track_xform->object_id = node_3d->get_instance_id();
|
|
|
|
|
|
|
|
|
|
track = track_xform;
|
|
|
|
|
|
|
|
|
|
switch (track_type) {
|
|
|
|
|
switch (track_src_type) {
|
|
|
|
|
case Animation::TYPE_POSITION_3D: {
|
|
|
|
|
track_xform->loc_used = true;
|
|
|
|
|
} break;
|
|
|
|
@ -724,9 +728,9 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
|
|
|
|
|
// For non Skeleton3D bone animation.
|
|
|
|
|
if (has_reset_anim && !has_rest) {
|
|
|
|
|
int rt = reset_anim->find_track(path, track_type);
|
|
|
|
|
int rt = reset_anim->find_track(path, track_src_type);
|
|
|
|
|
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
|
|
|
|
|
switch (track_type) {
|
|
|
|
|
switch (track_src_type) {
|
|
|
|
|
case Animation::TYPE_POSITION_3D: {
|
|
|
|
|
track_xform->init_loc = reset_anim->track_get_key_value(rt, 0);
|
|
|
|
|
} break;
|
|
|
|
@ -765,15 +769,12 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
|
|
|
|
|
TrackCacheBlendShape *track_bshape = memnew(TrackCacheBlendShape);
|
|
|
|
|
|
|
|
|
|
track_bshape->mesh_3d = mesh_3d;
|
|
|
|
|
track_bshape->shape_index = blend_shape_idx;
|
|
|
|
|
|
|
|
|
|
track_bshape->object = mesh_3d;
|
|
|
|
|
track_bshape->object_id = mesh_3d->get_instance_id();
|
|
|
|
|
track = track_bshape;
|
|
|
|
|
|
|
|
|
|
if (has_reset_anim) {
|
|
|
|
|
int rt = reset_anim->find_track(path, track_type);
|
|
|
|
|
int rt = reset_anim->find_track(path, track_src_type);
|
|
|
|
|
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
|
|
|
|
|
track_bshape->init_value = reset_anim->track_get_key_value(rt, 0);
|
|
|
|
|
}
|
|
|
|
@ -784,43 +785,18 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
TrackCacheMethod *track_method = memnew(TrackCacheMethod);
|
|
|
|
|
|
|
|
|
|
if (resource.is_valid()) {
|
|
|
|
|
track_method->object = resource.ptr();
|
|
|
|
|
track_method->object_id = resource->get_instance_id();
|
|
|
|
|
} else {
|
|
|
|
|
track_method->object = child;
|
|
|
|
|
track_method->object_id = child->get_instance_id();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
track_method->object_id = track_method->object->get_instance_id();
|
|
|
|
|
|
|
|
|
|
track = track_method;
|
|
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_BEZIER: {
|
|
|
|
|
TrackCacheBezier *track_bezier = memnew(TrackCacheBezier);
|
|
|
|
|
|
|
|
|
|
if (resource.is_valid()) {
|
|
|
|
|
track_bezier->object = resource.ptr();
|
|
|
|
|
} else {
|
|
|
|
|
track_bezier->object = child;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
track_bezier->subpath = leftover_path;
|
|
|
|
|
track_bezier->object_id = track_bezier->object->get_instance_id();
|
|
|
|
|
|
|
|
|
|
track = track_bezier;
|
|
|
|
|
|
|
|
|
|
if (has_reset_anim) {
|
|
|
|
|
int rt = reset_anim->find_track(path, track_type);
|
|
|
|
|
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
|
|
|
|
|
track_bezier->init_value = (reset_anim->track_get_key_value(rt, 0).operator Array())[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_AUDIO: {
|
|
|
|
|
TrackCacheAudio *track_audio = memnew(TrackCacheAudio);
|
|
|
|
|
|
|
|
|
|
track_audio->object = child;
|
|
|
|
|
track_audio->object_id = track_audio->object->get_instance_id();
|
|
|
|
|
track_audio->object_id = child->get_instance_id();
|
|
|
|
|
track_audio->audio_stream.instantiate();
|
|
|
|
|
track_audio->audio_stream->set_polyphony(audio_max_polyphony);
|
|
|
|
|
|
|
|
|
@ -830,8 +806,7 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
case Animation::TYPE_ANIMATION: {
|
|
|
|
|
TrackCacheAnimation *track_animation = memnew(TrackCacheAnimation);
|
|
|
|
|
|
|
|
|
|
track_animation->object = child;
|
|
|
|
|
track_animation->object_id = track_animation->object->get_instance_id();
|
|
|
|
|
track_animation->object_id = child->get_instance_id();
|
|
|
|
|
|
|
|
|
|
track = track_animation;
|
|
|
|
|
|
|
|
|
@ -841,8 +816,8 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
track_cache[path] = track;
|
|
|
|
|
track->path = path;
|
|
|
|
|
track_cache[thash] = track;
|
|
|
|
|
} else if (track_cache_type == Animation::TYPE_POSITION_3D) {
|
|
|
|
|
TrackCacheTransform *track_xform = static_cast<TrackCacheTransform *>(track);
|
|
|
|
|
if (track->setup_pass != setup_pass) {
|
|
|
|
@ -850,7 +825,7 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
track_xform->rot_used = false;
|
|
|
|
|
track_xform->scale_used = false;
|
|
|
|
|
}
|
|
|
|
|
switch (track_type) {
|
|
|
|
|
switch (track_src_type) {
|
|
|
|
|
case Animation::TYPE_POSITION_3D: {
|
|
|
|
|
track_xform->loc_used = true;
|
|
|
|
|
} break;
|
|
|
|
@ -868,8 +843,13 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
TrackCacheValue *track_value = static_cast<TrackCacheValue *>(track);
|
|
|
|
|
bool was_continuous = track_value->is_continuous;
|
|
|
|
|
bool was_using_angle = track_value->is_using_angle;
|
|
|
|
|
track_value->is_continuous |= anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
|
|
|
|
|
track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
|
|
|
|
|
|
|
|
|
|
if (track_src_type == Animation::TYPE_VALUE) {
|
|
|
|
|
track_value->is_continuous |= anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
|
|
|
|
|
track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
|
|
|
|
|
} else {
|
|
|
|
|
track_value->is_continuous |= true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Currently, misc type cannot be blended.
|
|
|
|
|
// In the future, it should have a separate blend weight, just as bool is converted to 0 and 1.
|
|
|
|
@ -898,27 +878,26 @@ bool AnimationMixer::_update_caches() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<NodePath> to_delete;
|
|
|
|
|
List<Animation::TypeHash> to_delete;
|
|
|
|
|
|
|
|
|
|
for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
|
|
|
|
|
TrackCache *tc = track_cache[K.key];
|
|
|
|
|
if (tc->setup_pass != setup_pass) {
|
|
|
|
|
for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
|
|
|
|
|
if (K.value->setup_pass != setup_pass) {
|
|
|
|
|
to_delete.push_back(K.key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (to_delete.front()) {
|
|
|
|
|
NodePath np = to_delete.front()->get();
|
|
|
|
|
memdelete(track_cache[np]);
|
|
|
|
|
track_cache.erase(np);
|
|
|
|
|
Animation::TypeHash thash = to_delete.front()->get();
|
|
|
|
|
memdelete(track_cache[thash]);
|
|
|
|
|
track_cache.erase(thash);
|
|
|
|
|
to_delete.pop_front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
track_map.clear();
|
|
|
|
|
|
|
|
|
|
int idx = 0;
|
|
|
|
|
for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
|
|
|
|
|
track_map[K.key] = idx;
|
|
|
|
|
for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
|
|
|
|
|
track_map[K.value->path] = idx;
|
|
|
|
|
idx++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -944,19 +923,28 @@ void AnimationMixer::_process_animation(double p_delta, bool p_update_only) {
|
|
|
|
|
clear_animation_instances();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Variant AnimationMixer::post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) {
|
|
|
|
|
Variant AnimationMixer::post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) {
|
|
|
|
|
Variant res;
|
|
|
|
|
if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, const_cast<Object *>(p_object), p_object_idx, res)) {
|
|
|
|
|
if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, p_object_id, p_object_sub_idx, res)) {
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
return _post_process_key_value(p_anim, p_track, p_value, p_object, p_object_idx);
|
|
|
|
|
return _post_process_key_value(p_anim, p_track, p_value, p_object_id, p_object_sub_idx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Variant AnimationMixer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) {
|
|
|
|
|
Variant AnimationMixer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) {
|
|
|
|
|
#ifndef _3D_DISABLED
|
|
|
|
|
if (p_object_idx >= 0 && p_anim->track_get_type(p_track) == Animation::TYPE_POSITION_3D) {
|
|
|
|
|
const Skeleton3D *skel = Object::cast_to<Skeleton3D>(p_object);
|
|
|
|
|
return Vector3(p_value) * skel->get_motion_scale();
|
|
|
|
|
switch (p_anim->track_get_type(p_track)) {
|
|
|
|
|
case Animation::TYPE_POSITION_3D: {
|
|
|
|
|
if (p_object_sub_idx >= 0) {
|
|
|
|
|
Skeleton3D *skel = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(p_object_id));
|
|
|
|
|
if (skel) {
|
|
|
|
|
return Vector3(p_value) * skel->get_motion_scale();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return p_value;
|
|
|
|
|
} break;
|
|
|
|
|
default: {
|
|
|
|
|
} break;
|
|
|
|
|
}
|
|
|
|
|
#endif // _3D_DISABLED
|
|
|
|
|
return p_value;
|
|
|
|
@ -978,7 +966,7 @@ void AnimationMixer::_blend_init() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Init all value/transform/blend/bezier tracks that track_cache has.
|
|
|
|
|
for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
|
|
|
|
|
for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
|
|
|
|
|
TrackCache *track = K.value;
|
|
|
|
|
|
|
|
|
|
track->total_weight = 0.0;
|
|
|
|
@ -1004,10 +992,6 @@ void AnimationMixer::_blend_init() {
|
|
|
|
|
t->value = Animation::cast_to_blendwise(t->init_value);
|
|
|
|
|
t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0;
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_BEZIER: {
|
|
|
|
|
TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
|
|
|
|
|
t->value = t->init_value;
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_AUDIO: {
|
|
|
|
|
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
|
|
|
|
|
for (KeyValue<ObjectID, PlayingAudioTrackInfo> &L : t->playing_streams) {
|
|
|
|
@ -1039,12 +1023,12 @@ void AnimationMixer::_blend_calc_total_weight() {
|
|
|
|
|
if (!a->track_is_enabled(i)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
NodePath path = a->track_get_path(i);
|
|
|
|
|
if (!track_cache.has(path)) {
|
|
|
|
|
Animation::TypeHash thash = a->track_get_type_hash(i);
|
|
|
|
|
if (!track_cache.has(thash)) {
|
|
|
|
|
continue; // No path, but avoid error spamming.
|
|
|
|
|
}
|
|
|
|
|
TrackCache *track = track_cache[path];
|
|
|
|
|
int blend_idx = track_map[path];
|
|
|
|
|
TrackCache *track = track_cache[thash];
|
|
|
|
|
int blend_idx = track_map[track->path];
|
|
|
|
|
if (processed_indices.has(blend_idx)) {
|
|
|
|
|
continue; // There is the case different track type with same path... Is there more faster iterating way than has()?
|
|
|
|
|
}
|
|
|
|
@ -1079,13 +1063,13 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (!a->track_is_enabled(i)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
NodePath path = a->track_get_path(i);
|
|
|
|
|
if (!track_cache.has(path)) {
|
|
|
|
|
Animation::TypeHash thash = a->track_get_type_hash(i);
|
|
|
|
|
if (!track_cache.has(thash)) {
|
|
|
|
|
continue; // No path, but avoid error spamming.
|
|
|
|
|
}
|
|
|
|
|
TrackCache *track = track_cache[path];
|
|
|
|
|
ERR_CONTINUE(!track_map.has(path));
|
|
|
|
|
int blend_idx = track_map[path];
|
|
|
|
|
TrackCache *track = track_cache[thash];
|
|
|
|
|
ERR_CONTINUE(!track_map.has(track->path));
|
|
|
|
|
int blend_idx = track_map[track->path];
|
|
|
|
|
ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);
|
|
|
|
|
real_t blend = blend_idx < track_weights.size() ? track_weights[blend_idx] * weight : weight;
|
|
|
|
|
if (!deterministic) {
|
|
|
|
@ -1097,11 +1081,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
blend = blend / track->total_weight;
|
|
|
|
|
}
|
|
|
|
|
Animation::TrackType ttype = a->track_get_type(i);
|
|
|
|
|
if (ttype != Animation::TYPE_POSITION_3D && ttype != Animation::TYPE_ROTATION_3D && ttype != Animation::TYPE_SCALE_3D && track->type != ttype) {
|
|
|
|
|
// Broken animation, but avoid error spamming.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
track->root_motion = root_motion_track == path;
|
|
|
|
|
track->root_motion = root_motion_track == a->track_get_path(i);
|
|
|
|
|
switch (ttype) {
|
|
|
|
|
case Animation::TYPE_POSITION_3D: {
|
|
|
|
|
#ifndef _3D_DISABLED
|
|
|
|
@ -1151,9 +1131,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx);
|
|
|
|
|
loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
|
|
|
|
|
a->try_position_track_interpolate(i, (double)a->get_length(), &loc[1]);
|
|
|
|
|
loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx);
|
|
|
|
|
loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
|
|
|
|
|
root_motion_cache.loc += (loc[1] - loc[0]) * blend;
|
|
|
|
|
prev_time = 0;
|
|
|
|
|
}
|
|
|
|
@ -1163,9 +1143,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx);
|
|
|
|
|
loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
|
|
|
|
|
a->try_position_track_interpolate(i, 0, &loc[1]);
|
|
|
|
|
loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx);
|
|
|
|
|
loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
|
|
|
|
|
root_motion_cache.loc += (loc[1] - loc[0]) * blend;
|
|
|
|
|
prev_time = (double)a->get_length();
|
|
|
|
|
}
|
|
|
|
@ -1174,9 +1154,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx);
|
|
|
|
|
loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
|
|
|
|
|
a->try_position_track_interpolate(i, time, &loc[1]);
|
|
|
|
|
loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx);
|
|
|
|
|
loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
|
|
|
|
|
root_motion_cache.loc += (loc[1] - loc[0]) * blend;
|
|
|
|
|
prev_time = !backward ? 0 : (double)a->get_length();
|
|
|
|
|
}
|
|
|
|
@ -1186,7 +1166,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
loc = post_process_key_value(a, i, loc, t->object, t->bone_idx);
|
|
|
|
|
loc = post_process_key_value(a, i, loc, t->object_id, t->bone_idx);
|
|
|
|
|
t->loc += (loc - t->init_loc) * blend;
|
|
|
|
|
}
|
|
|
|
|
#endif // _3D_DISABLED
|
|
|
|
@ -1239,9 +1219,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx);
|
|
|
|
|
rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
|
|
|
|
|
a->try_rotation_track_interpolate(i, (double)a->get_length(), &rot[1]);
|
|
|
|
|
rot[1] = post_process_key_value(a, i, rot[1], t->object, t->bone_idx);
|
|
|
|
|
rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);
|
|
|
|
|
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
|
|
|
|
|
prev_time = 0;
|
|
|
|
|
}
|
|
|
|
@ -1251,7 +1231,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx);
|
|
|
|
|
rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
|
|
|
|
|
a->try_rotation_track_interpolate(i, 0, &rot[1]);
|
|
|
|
|
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
|
|
|
|
|
prev_time = (double)a->get_length();
|
|
|
|
@ -1261,9 +1241,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx);
|
|
|
|
|
rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
|
|
|
|
|
a->try_rotation_track_interpolate(i, time, &rot[1]);
|
|
|
|
|
rot[1] = post_process_key_value(a, i, rot[1], t->object, t->bone_idx);
|
|
|
|
|
rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);
|
|
|
|
|
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
|
|
|
|
|
prev_time = !backward ? 0 : (double)a->get_length();
|
|
|
|
|
}
|
|
|
|
@ -1273,7 +1253,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
rot = post_process_key_value(a, i, rot, t->object, t->bone_idx);
|
|
|
|
|
rot = post_process_key_value(a, i, rot, t->object_id, t->bone_idx);
|
|
|
|
|
t->rot = (t->rot * Quaternion().slerp(t->init_rot.inverse() * rot, blend)).normalized();
|
|
|
|
|
}
|
|
|
|
|
#endif // _3D_DISABLED
|
|
|
|
@ -1326,10 +1306,10 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx);
|
|
|
|
|
scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);
|
|
|
|
|
a->try_scale_track_interpolate(i, (double)a->get_length(), &scale[1]);
|
|
|
|
|
root_motion_cache.scale += (scale[1] - scale[0]) * blend;
|
|
|
|
|
scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx);
|
|
|
|
|
scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
|
|
|
|
|
prev_time = 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
@ -1338,9 +1318,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx);
|
|
|
|
|
scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);
|
|
|
|
|
a->try_scale_track_interpolate(i, 0, &scale[1]);
|
|
|
|
|
scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx);
|
|
|
|
|
scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
|
|
|
|
|
root_motion_cache.scale += (scale[1] - scale[0]) * blend;
|
|
|
|
|
prev_time = (double)a->get_length();
|
|
|
|
|
}
|
|
|
|
@ -1349,9 +1329,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx);
|
|
|
|
|
scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);
|
|
|
|
|
a->try_scale_track_interpolate(i, time, &scale[1]);
|
|
|
|
|
scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx);
|
|
|
|
|
scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
|
|
|
|
|
root_motion_cache.scale += (scale[1] - scale[0]) * blend;
|
|
|
|
|
prev_time = !backward ? 0 : (double)a->get_length();
|
|
|
|
|
}
|
|
|
|
@ -1361,7 +1341,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
scale = post_process_key_value(a, i, scale, t->object, t->bone_idx);
|
|
|
|
|
scale = post_process_key_value(a, i, scale, t->object_id, t->bone_idx);
|
|
|
|
|
t->scale += (scale - t->init_scale) * blend;
|
|
|
|
|
}
|
|
|
|
|
#endif // _3D_DISABLED
|
|
|
|
@ -1378,18 +1358,19 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (err != OK) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
value = post_process_key_value(a, i, value, t->object, t->shape_index);
|
|
|
|
|
value = post_process_key_value(a, i, value, t->object_id, t->shape_index);
|
|
|
|
|
t->value += (value - t->init_value) * blend;
|
|
|
|
|
#endif // _3D_DISABLED
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_BEZIER:
|
|
|
|
|
case Animation::TYPE_VALUE: {
|
|
|
|
|
if (Math::is_zero_approx(blend)) {
|
|
|
|
|
continue; // Nothing to blend.
|
|
|
|
|
}
|
|
|
|
|
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
|
|
|
|
|
if (t->is_continuous) {
|
|
|
|
|
Variant value = a->value_track_interpolate(i, time);
|
|
|
|
|
value = post_process_key_value(a, i, value, t->object);
|
|
|
|
|
Variant value = ttype == Animation::TYPE_VALUE ? a->value_track_interpolate(i, time) : Variant(a->bezier_track_interpolate(i, time));
|
|
|
|
|
value = post_process_key_value(a, i, value, t->object_id);
|
|
|
|
|
if (value == Variant()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
@ -1429,15 +1410,21 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Variant value = a->track_get_key_value(i, idx);
|
|
|
|
|
value = post_process_key_value(a, i, value, t->object);
|
|
|
|
|
t->object->set_indexed(t->subpath, value);
|
|
|
|
|
value = post_process_key_value(a, i, value, t->object_id);
|
|
|
|
|
Object *t_obj = ObjectDB::get_instance(t->object_id);
|
|
|
|
|
if (t_obj) {
|
|
|
|
|
t_obj->set_indexed(t->subpath, value);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
List<int> indices;
|
|
|
|
|
a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);
|
|
|
|
|
for (int &F : indices) {
|
|
|
|
|
Variant value = a->track_get_key_value(i, F);
|
|
|
|
|
value = post_process_key_value(a, i, value, t->object);
|
|
|
|
|
t->object->set_indexed(t->subpath, value);
|
|
|
|
|
value = post_process_key_value(a, i, value, t->object_id);
|
|
|
|
|
Object *t_obj = ObjectDB::get_instance(t->object_id);
|
|
|
|
|
if (t_obj) {
|
|
|
|
|
t_obj->set_indexed(t->subpath, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1459,31 +1446,23 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
}
|
|
|
|
|
StringName method = a->method_track_get_name(i, idx);
|
|
|
|
|
Vector<Variant> params = a->method_track_get_params(i, idx);
|
|
|
|
|
_call_object(t->object, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);
|
|
|
|
|
_call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);
|
|
|
|
|
} else {
|
|
|
|
|
List<int> indices;
|
|
|
|
|
a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);
|
|
|
|
|
for (int &F : indices) {
|
|
|
|
|
StringName method = a->method_track_get_name(i, F);
|
|
|
|
|
Vector<Variant> params = a->method_track_get_params(i, F);
|
|
|
|
|
_call_object(t->object, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);
|
|
|
|
|
_call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_BEZIER: {
|
|
|
|
|
if (Math::is_zero_approx(blend)) {
|
|
|
|
|
continue; // Nothing to blend.
|
|
|
|
|
}
|
|
|
|
|
TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
|
|
|
|
|
real_t bezier = a->bezier_track_interpolate(i, time);
|
|
|
|
|
bezier = post_process_key_value(a, i, bezier, t->object);
|
|
|
|
|
t->value += (bezier - t->init_value) * blend;
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_AUDIO: {
|
|
|
|
|
// The end of audio should be observed even if the blend value is 0, build up the information and store to the cache for that.
|
|
|
|
|
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
|
|
|
|
|
Node *asp = Object::cast_to<Node>(t->object);
|
|
|
|
|
if (!asp) {
|
|
|
|
|
Object *t_obj = ObjectDB::get_instance(t->object_id);
|
|
|
|
|
Node *asp = t_obj ? Object::cast_to<Node>(t_obj) : nullptr;
|
|
|
|
|
if (!t_obj || !asp) {
|
|
|
|
|
t->playing_streams.clear();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
@ -1533,22 +1512,22 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
if (seeked) {
|
|
|
|
|
start_ofs += time - a->track_get_key_time(i, idx);
|
|
|
|
|
}
|
|
|
|
|
if (t->object->call(SNAME("get_stream")) != t->audio_stream) {
|
|
|
|
|
t->object->call(SNAME("set_stream"), t->audio_stream);
|
|
|
|
|
if (t_obj->call(SNAME("get_stream")) != t->audio_stream) {
|
|
|
|
|
t_obj->call(SNAME("set_stream"), t->audio_stream);
|
|
|
|
|
t->audio_stream_playback.unref();
|
|
|
|
|
if (!playing_audio_stream_players.has(asp)) {
|
|
|
|
|
playing_audio_stream_players.push_back(asp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!t->object->call(SNAME("is_playing"))) {
|
|
|
|
|
t->object->call(SNAME("play"));
|
|
|
|
|
if (!t_obj->call(SNAME("is_playing"))) {
|
|
|
|
|
t_obj->call(SNAME("play"));
|
|
|
|
|
}
|
|
|
|
|
if (!t->object->call(SNAME("has_stream_playback"))) {
|
|
|
|
|
if (!t_obj->call(SNAME("has_stream_playback"))) {
|
|
|
|
|
t->audio_stream_playback.unref();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (t->audio_stream_playback.is_null()) {
|
|
|
|
|
t->audio_stream_playback = t->object->call(SNAME("get_stream_playback"));
|
|
|
|
|
t->audio_stream_playback = t_obj->call(SNAME("get_stream_playback"));
|
|
|
|
|
}
|
|
|
|
|
PlayingAudioStreamInfo pasi;
|
|
|
|
|
pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs);
|
|
|
|
@ -1566,7 +1545,11 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track);
|
|
|
|
|
AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t->object);
|
|
|
|
|
Object *t_obj = ObjectDB::get_instance(t->object_id);
|
|
|
|
|
if (!t_obj) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t_obj);
|
|
|
|
|
if (!player2) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
@ -1633,7 +1616,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|
|
|
|
|
|
|
|
|
void AnimationMixer::_blend_apply() {
|
|
|
|
|
// Finally, set the tracks.
|
|
|
|
|
for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
|
|
|
|
|
for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
|
|
|
|
|
TrackCache *track = K.value;
|
|
|
|
|
if (!deterministic && Math::is_zero_approx(track->total_weight)) {
|
|
|
|
|
continue;
|
|
|
|
@ -1650,26 +1633,34 @@ void AnimationMixer::_blend_apply() {
|
|
|
|
|
root_motion_position_accumulator = t->loc;
|
|
|
|
|
root_motion_rotation_accumulator = t->rot;
|
|
|
|
|
root_motion_scale_accumulator = t->scale;
|
|
|
|
|
} else if (t->skeleton && t->bone_idx >= 0) {
|
|
|
|
|
} else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) {
|
|
|
|
|
Skeleton3D *t_skeleton = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(t->skeleton_id));
|
|
|
|
|
if (!t_skeleton) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (t->loc_used) {
|
|
|
|
|
t->skeleton->set_bone_pose_position(t->bone_idx, t->loc);
|
|
|
|
|
t_skeleton->set_bone_pose_position(t->bone_idx, t->loc);
|
|
|
|
|
}
|
|
|
|
|
if (t->rot_used) {
|
|
|
|
|
t->skeleton->set_bone_pose_rotation(t->bone_idx, t->rot);
|
|
|
|
|
t_skeleton->set_bone_pose_rotation(t->bone_idx, t->rot);
|
|
|
|
|
}
|
|
|
|
|
if (t->scale_used) {
|
|
|
|
|
t->skeleton->set_bone_pose_scale(t->bone_idx, t->scale);
|
|
|
|
|
t_skeleton->set_bone_pose_scale(t->bone_idx, t->scale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (!t->skeleton) {
|
|
|
|
|
} else if (!t->skeleton_id.is_valid()) {
|
|
|
|
|
Node3D *t_node_3d = Object::cast_to<Node3D>(ObjectDB::get_instance(t->object_id));
|
|
|
|
|
if (!t_node_3d) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (t->loc_used) {
|
|
|
|
|
t->node_3d->set_position(t->loc);
|
|
|
|
|
t_node_3d->set_position(t->loc);
|
|
|
|
|
}
|
|
|
|
|
if (t->rot_used) {
|
|
|
|
|
t->node_3d->set_rotation(t->rot.get_euler());
|
|
|
|
|
t_node_3d->set_rotation(t->rot.get_euler());
|
|
|
|
|
}
|
|
|
|
|
if (t->scale_used) {
|
|
|
|
|
t->node_3d->set_scale(t->scale);
|
|
|
|
|
t_node_3d->set_scale(t->scale);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif // _3D_DISABLED
|
|
|
|
@ -1678,8 +1669,9 @@ void AnimationMixer::_blend_apply() {
|
|
|
|
|
#ifndef _3D_DISABLED
|
|
|
|
|
TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);
|
|
|
|
|
|
|
|
|
|
if (t->mesh_3d) {
|
|
|
|
|
t->mesh_3d->set_blend_shape_value(t->shape_index, t->value);
|
|
|
|
|
MeshInstance3D *t_mesh_3d = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(t->object_id));
|
|
|
|
|
if (t_mesh_3d) {
|
|
|
|
|
t_mesh_3d->set_blend_shape_value(t->shape_index, t->value);
|
|
|
|
|
}
|
|
|
|
|
#endif // _3D_DISABLED
|
|
|
|
|
} break;
|
|
|
|
@ -1703,18 +1695,11 @@ void AnimationMixer::_blend_apply() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// t->object isn't safe here, get instance from id (GH-85365).
|
|
|
|
|
Object *obj = ObjectDB::get_instance(t->object_id);
|
|
|
|
|
if (obj) {
|
|
|
|
|
obj->set_indexed(t->subpath, Animation::cast_from_blendwise(t->value, t->init_value.get_type()));
|
|
|
|
|
Object *t_obj = ObjectDB::get_instance(t->object_id);
|
|
|
|
|
if (t_obj) {
|
|
|
|
|
t_obj->set_indexed(t->subpath, Animation::cast_from_blendwise(t->value, t->init_value.get_type()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_BEZIER: {
|
|
|
|
|
TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
|
|
|
|
|
|
|
|
|
|
t->object->set_indexed(t->subpath, t->value);
|
|
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_AUDIO: {
|
|
|
|
|
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
|
|
|
|
@ -1780,7 +1765,7 @@ void AnimationMixer::_blend_apply() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimationMixer::_call_object(Object *p_object, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) {
|
|
|
|
|
void AnimationMixer::_call_object(ObjectID p_object_id, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) {
|
|
|
|
|
// Separate function to use alloca() more efficiently
|
|
|
|
|
const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * p_params.size());
|
|
|
|
|
const Variant *args = p_params.ptr();
|
|
|
|
@ -1788,11 +1773,15 @@ void AnimationMixer::_call_object(Object *p_object, const StringName &p_method,
|
|
|
|
|
for (uint32_t i = 0; i < argcount; i++) {
|
|
|
|
|
argptrs[i] = &args[i];
|
|
|
|
|
}
|
|
|
|
|
Object *t_obj = ObjectDB::get_instance(p_object_id);
|
|
|
|
|
if (!t_obj) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (p_deferred) {
|
|
|
|
|
MessageQueue::get_singleton()->push_callp(p_object, p_method, argptrs, argcount);
|
|
|
|
|
MessageQueue::get_singleton()->push_callp(t_obj, p_method, argptrs, argcount);
|
|
|
|
|
} else {
|
|
|
|
|
Callable::CallError ce;
|
|
|
|
|
p_object->callp(p_method, argptrs, argcount, ce);
|
|
|
|
|
t_obj->callp(p_method, argptrs, argcount, ce);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1872,7 +1861,7 @@ bool AnimationMixer::can_apply_reset() const {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimationMixer::_build_backup_track_cache() {
|
|
|
|
|
for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
|
|
|
|
|
for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
|
|
|
|
|
TrackCache *track = K.value;
|
|
|
|
|
track->total_weight = 1.0;
|
|
|
|
|
switch (track->type) {
|
|
|
|
@ -1881,25 +1870,33 @@ void AnimationMixer::_build_backup_track_cache() {
|
|
|
|
|
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
|
|
|
|
|
if (t->root_motion) {
|
|
|
|
|
// Do nothing.
|
|
|
|
|
} else if (t->skeleton && t->bone_idx >= 0) {
|
|
|
|
|
} else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) {
|
|
|
|
|
Skeleton3D *t_skeleton = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(t->skeleton_id));
|
|
|
|
|
if (!t_skeleton) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (t->loc_used) {
|
|
|
|
|
t->loc = t->skeleton->get_bone_pose_position(t->bone_idx);
|
|
|
|
|
t->loc = t_skeleton->get_bone_pose_position(t->bone_idx);
|
|
|
|
|
}
|
|
|
|
|
if (t->rot_used) {
|
|
|
|
|
t->rot = t->skeleton->get_bone_pose_rotation(t->bone_idx);
|
|
|
|
|
t->rot = t_skeleton->get_bone_pose_rotation(t->bone_idx);
|
|
|
|
|
}
|
|
|
|
|
if (t->scale_used) {
|
|
|
|
|
t->scale = t->skeleton->get_bone_pose_scale(t->bone_idx);
|
|
|
|
|
t->scale = t_skeleton->get_bone_pose_scale(t->bone_idx);
|
|
|
|
|
}
|
|
|
|
|
} else if (!t->skeleton_id.is_valid()) {
|
|
|
|
|
Node3D *t_node_3d = Object::cast_to<Node3D>(ObjectDB::get_instance(t->object_id));
|
|
|
|
|
if (!t_node_3d) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if (!t->skeleton) {
|
|
|
|
|
if (t->loc_used) {
|
|
|
|
|
t->loc = t->node_3d->get_position();
|
|
|
|
|
t->loc = t_node_3d->get_position();
|
|
|
|
|
}
|
|
|
|
|
if (t->rot_used) {
|
|
|
|
|
t->rot = t->node_3d->get_quaternion();
|
|
|
|
|
t->rot = t_node_3d->get_quaternion();
|
|
|
|
|
}
|
|
|
|
|
if (t->scale_used) {
|
|
|
|
|
t->scale = t->node_3d->get_scale();
|
|
|
|
|
t->scale = t_node_3d->get_scale();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif // _3D_DISABLED
|
|
|
|
@ -1907,25 +1904,28 @@ void AnimationMixer::_build_backup_track_cache() {
|
|
|
|
|
case Animation::TYPE_BLEND_SHAPE: {
|
|
|
|
|
#ifndef _3D_DISABLED
|
|
|
|
|
TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);
|
|
|
|
|
if (t->mesh_3d) {
|
|
|
|
|
t->value = t->mesh_3d->get_blend_shape_value(t->shape_index);
|
|
|
|
|
MeshInstance3D *t_mesh_3d = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(t->object_id));
|
|
|
|
|
if (t_mesh_3d) {
|
|
|
|
|
t->value = t_mesh_3d->get_blend_shape_value(t->shape_index);
|
|
|
|
|
}
|
|
|
|
|
#endif // _3D_DISABLED
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_VALUE: {
|
|
|
|
|
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
|
|
|
|
|
t->value = t->object->get_indexed(t->subpath);
|
|
|
|
|
Object *t_obj = ObjectDB::get_instance(t->object_id);
|
|
|
|
|
if (t_obj) {
|
|
|
|
|
t->value = t_obj->get_indexed(t->subpath);
|
|
|
|
|
}
|
|
|
|
|
t->is_continuous = true;
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_BEZIER: {
|
|
|
|
|
TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
|
|
|
|
|
t->value = t->object->get_indexed(t->subpath);
|
|
|
|
|
} break;
|
|
|
|
|
case Animation::TYPE_AUDIO: {
|
|
|
|
|
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
|
|
|
|
|
Node *asp = Object::cast_to<Node>(t->object);
|
|
|
|
|
if (asp) {
|
|
|
|
|
t->object->call(SNAME("set_stream"), Ref<AudioStream>());
|
|
|
|
|
Object *t_obj = ObjectDB::get_instance(t->object_id);
|
|
|
|
|
if (t_obj) {
|
|
|
|
|
Node *asp = Object::cast_to<Node>(t_obj);
|
|
|
|
|
if (asp) {
|
|
|
|
|
asp->call(SNAME("set_stream"), Ref<AudioStream>());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
default: {
|
|
|
|
@ -1982,7 +1982,7 @@ void AnimationMixer::restore(const Ref<AnimatedValuesBackup> &p_backup) {
|
|
|
|
|
ERR_FAIL_COND(p_backup.is_null());
|
|
|
|
|
track_cache = p_backup->get_data();
|
|
|
|
|
_blend_apply();
|
|
|
|
|
track_cache = HashMap<NodePath, AnimationMixer::TrackCache *>();
|
|
|
|
|
track_cache = HashMap<Animation::TypeHash, AnimationMixer::TrackCache *>();
|
|
|
|
|
cache_valid = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2113,7 +2113,7 @@ void AnimationMixer::_bind_methods() {
|
|
|
|
|
/* ---- Blending processor ---- */
|
|
|
|
|
ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationMixer::clear_caches);
|
|
|
|
|
ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationMixer::advance);
|
|
|
|
|
GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object", "object_idx");
|
|
|
|
|
GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object_id", "object_sub_idx");
|
|
|
|
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deterministic"), "set_deterministic", "is_deterministic");
|
|
|
|
@ -2159,10 +2159,10 @@ AnimationMixer::AnimationMixer() {
|
|
|
|
|
AnimationMixer::~AnimationMixer() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimatedValuesBackup::set_data(const HashMap<NodePath, AnimationMixer::TrackCache *> &p_data) {
|
|
|
|
|
void AnimatedValuesBackup::set_data(const HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> p_data) {
|
|
|
|
|
clear_data();
|
|
|
|
|
|
|
|
|
|
for (const KeyValue<NodePath, AnimationMixer::TrackCache *> &E : p_data) {
|
|
|
|
|
for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : p_data) {
|
|
|
|
|
AnimationMixer::TrackCache *track = get_cache_copy(E.value);
|
|
|
|
|
if (!track) {
|
|
|
|
|
continue; // Some types of tracks do not get a copy and must be ignored.
|
|
|
|
@ -2172,9 +2172,9 @@ void AnimatedValuesBackup::set_data(const HashMap<NodePath, AnimationMixer::Trac
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HashMap<NodePath, AnimationMixer::TrackCache *> AnimatedValuesBackup::get_data() const {
|
|
|
|
|
HashMap<NodePath, AnimationMixer::TrackCache *> ret;
|
|
|
|
|
for (const KeyValue<NodePath, AnimationMixer::TrackCache *> &E : data) {
|
|
|
|
|
HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> AnimatedValuesBackup::get_data() const {
|
|
|
|
|
HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> ret;
|
|
|
|
|
for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : data) {
|
|
|
|
|
AnimationMixer::TrackCache *track = get_cache_copy(E.value);
|
|
|
|
|
ERR_CONTINUE(!track); // Backup shouldn't contain tracks that cannot be copied, this is a mistake.
|
|
|
|
|
|
|
|
|
@ -2184,7 +2184,7 @@ HashMap<NodePath, AnimationMixer::TrackCache *> AnimatedValuesBackup::get_data()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimatedValuesBackup::clear_data() {
|
|
|
|
|
for (KeyValue<NodePath, AnimationMixer::TrackCache *> &K : data) {
|
|
|
|
|
for (KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &K : data) {
|
|
|
|
|
memdelete(K.value);
|
|
|
|
|
}
|
|
|
|
|
data.clear();
|
|
|
|
@ -2192,6 +2192,7 @@ void AnimatedValuesBackup::clear_data() {
|
|
|
|
|
|
|
|
|
|
AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer::TrackCache *p_cache) const {
|
|
|
|
|
switch (p_cache->type) {
|
|
|
|
|
case Animation::TYPE_BEZIER:
|
|
|
|
|
case Animation::TYPE_VALUE: {
|
|
|
|
|
AnimationMixer::TrackCacheValue *src = static_cast<AnimationMixer::TrackCacheValue *>(p_cache);
|
|
|
|
|
AnimationMixer::TrackCacheValue *tc = memnew(AnimationMixer::TrackCacheValue(*src));
|
|
|
|
@ -2212,12 +2213,6 @@ AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer:
|
|
|
|
|
return tc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case Animation::TYPE_BEZIER: {
|
|
|
|
|
AnimationMixer::TrackCacheBezier *src = static_cast<AnimationMixer::TrackCacheBezier *>(p_cache);
|
|
|
|
|
AnimationMixer::TrackCacheBezier *tc = memnew(AnimationMixer::TrackCacheBezier(*src));
|
|
|
|
|
return tc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case Animation::TYPE_AUDIO: {
|
|
|
|
|
AnimationMixer::TrackCacheAudio *src = static_cast<AnimationMixer::TrackCacheAudio *>(p_cache);
|
|
|
|
|
AnimationMixer::TrackCacheAudio *tc = memnew(AnimationMixer::TrackCacheAudio(*src));
|
|
|
|
|