Path: blob/master/scene/animation/animation_mixer.cpp
21212 views
/**************************************************************************/1/* animation_mixer.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "animation_mixer.h"31#include "animation_mixer.compat.inc"3233#include "core/config/engine.h"34#include "core/config/project_settings.h"35#include "core/string/string_name.h"36#include "scene/2d/audio_stream_player_2d.h"37#include "scene/animation/animation_player.h"38#include "scene/audio/audio_stream_player.h"39#include "scene/resources/animation.h"40#include "servers/audio/audio_server.h"41#include "servers/audio/audio_stream.h"4243#ifndef _3D_DISABLED44#include "scene/3d/audio_stream_player_3d.h"45#include "scene/3d/mesh_instance_3d.h"46#include "scene/3d/node_3d.h"47#include "scene/3d/skeleton_3d.h"48#endif // _3D_DISABLED4950#ifdef TOOLS_ENABLED51#include "editor/editor_undo_redo_manager.h"52#endif // TOOLS_ENABLED5354bool AnimationMixer::_set(const StringName &p_name, const Variant &p_value) {55String name = p_name;5657#ifndef DISABLE_DEPRECATED58if (name.begins_with("anims/")) {59// Backwards compatibility with 3.x, add them to "default" library.60String which = name.get_slicec('/', 1);6162Ref<Animation> anim = p_value;63Ref<AnimationLibrary> al;64if (!has_animation_library(StringName())) {65al.instantiate();66add_animation_library(StringName(), al);67} else {68al = get_animation_library(StringName());69}70al->add_animation(which, anim);71} else if (name == "libraries") {72Dictionary d = p_value;73while (animation_libraries.size()) {74remove_animation_library(animation_libraries[0].name);75}76for (const KeyValue<Variant, Variant> &kv : d) {77Ref<AnimationLibrary> lib = kv.value;78add_animation_library(kv.key, lib);79}80emit_signal(SNAME("animation_libraries_updated"));81} else if (name.begins_with("libraries/")) {82String which = name.get_slicec('/', 1);83if (has_animation_library(which)) {84remove_animation_library(which);85}86add_animation_library(which, p_value);87emit_signal(SNAME("animation_libraries_updated"));88} else {89return false;90}91#else92if (name.begins_with("libraries/")) {93String which = name.get_slicec('/', 1);94if (has_animation_library(which)) {95remove_animation_library(which);96}97add_animation_library(which, p_value);98emit_signal(SNAME("animation_libraries_updated"));99} else {100return false;101}102#endif // DISABLE_DEPRECATED103104return true;105}106107bool AnimationMixer::_get(const StringName &p_name, Variant &r_ret) const {108String name = p_name;109110if (name.begins_with("libraries/")) {111String which = name.get_slicec('/', 1);112if (has_animation_library(which)) {113r_ret = get_animation_library(which);114} else {115return false;116}117} else {118return false;119}120121return true;122}123124uint32_t AnimationMixer::_get_libraries_property_usage() const {125return PROPERTY_USAGE_STORAGE;126}127128void AnimationMixer::_get_property_list(List<PropertyInfo> *p_list) const {129for (uint32_t i = 0; i < animation_libraries.size(); i++) {130const String path = vformat("libraries/%s", animation_libraries[i].name);131p_list->push_back(PropertyInfo(Variant::OBJECT, path, PROPERTY_HINT_RESOURCE_TYPE, AnimationLibrary::get_class_static(), _get_libraries_property_usage()));132}133}134135void AnimationMixer::_validate_property(PropertyInfo &p_property) const {136#ifdef TOOLS_ENABLED // `editing` is surrounded by TOOLS_ENABLED so this should also be.137if (Engine::get_singleton()->is_editor_hint() && editing && (p_property.name == "active" || p_property.name == "deterministic" || p_property.name == "root_motion_track")) {138p_property.usage |= PROPERTY_USAGE_READ_ONLY;139}140#endif // TOOLS_ENABLED141if (root_motion_track.is_empty() && p_property.name == "root_motion_local") {142p_property.usage = PROPERTY_USAGE_NONE;143}144}145146/* -------------------------------------------- */147/* -- Data lists ------------------------------ */148/* -------------------------------------------- */149150void AnimationMixer::_animation_set_cache_update() {151// Relatively fast function to update all animations.152animation_set_update_pass++;153bool clear_cache_needed = false;154155// Update changed and add otherwise.156for (const AnimationLibraryData &lib : animation_libraries) {157for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) {158StringName key = lib.name == StringName() ? K.key : StringName(String(lib.name) + "/" + String(K.key));159if (!animation_set.has(key)) {160AnimationData ad;161ad.animation = K.value;162ad.animation_library = lib.name;163ad.name = key;164ad.last_update = animation_set_update_pass;165animation_set.insert(ad.name, ad);166cache_valid = false; // No need to delete the cache, but it must be updated to add track caches.167} else {168AnimationData &ad = animation_set[key];169if (ad.last_update != animation_set_update_pass) {170// Was not updated, update. If the animation is duplicated, the second one will be ignored.171if (ad.animation != K.value || ad.animation_library != lib.name) {172// Animation changed, update and clear caches.173clear_cache_needed = true;174ad.animation = K.value;175ad.animation_library = lib.name;176}177178ad.last_update = animation_set_update_pass;179}180}181}182}183184// Check removed.185List<StringName> to_erase;186for (const KeyValue<StringName, AnimationData> &E : animation_set) {187if (E.value.last_update != animation_set_update_pass) {188// Was not updated, must be erased.189to_erase.push_back(E.key);190clear_cache_needed = true;191}192}193194while (to_erase.size()) {195animation_set.erase(to_erase.front()->get());196to_erase.pop_front();197}198199if (clear_cache_needed) {200// If something was modified or removed, caches need to be cleared.201_clear_caches();202}203204emit_signal(SNAME("animation_list_changed"));205}206207void AnimationMixer::_animation_added(const StringName &p_name, const StringName &p_library) {208_animation_set_cache_update();209}210211void AnimationMixer::_animation_removed(const StringName &p_name, const StringName &p_library) {212StringName name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));213214if (!animation_set.has(name)) {215return; // No need to update because not the one from the library being used.216}217218_animation_set_cache_update();219220_remove_animation(name);221}222223void AnimationMixer::_animation_renamed(const StringName &p_name, const StringName &p_to_name, const StringName &p_library) {224StringName from_name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));225StringName to_name = p_library == StringName() ? p_to_name : StringName(String(p_library) + "/" + String(p_to_name));226227if (!animation_set.has(from_name)) {228return; // No need to update because not the one from the library being used.229}230_animation_set_cache_update();231232_rename_animation(from_name, to_name);233}234235void AnimationMixer::_animation_changed(const StringName &p_name) {236_clear_caches();237}238239void AnimationMixer::_set_active(bool p_active) {240//241}242243void AnimationMixer::_remove_animation(const StringName &p_name) {244//245}246247void AnimationMixer::_rename_animation(const StringName &p_from_name, const StringName &p_to_name) {248//249}250251TypedArray<StringName> AnimationMixer::_get_animation_library_list() const {252TypedArray<StringName> ret;253for (const AnimationLibraryData &lib : animation_libraries) {254ret.push_back(lib.name);255}256return ret;257}258259void AnimationMixer::get_animation_library_list(List<StringName> *p_libraries) const {260for (const AnimationLibraryData &lib : animation_libraries) {261p_libraries->push_back(lib.name);262}263}264265Ref<AnimationLibrary> AnimationMixer::get_animation_library(const StringName &p_name) const {266for (const AnimationLibraryData &lib : animation_libraries) {267if (lib.name == p_name) {268return lib.library;269}270}271ERR_FAIL_V(Ref<AnimationLibrary>());272}273274bool AnimationMixer::has_animation_library(const StringName &p_name) const {275for (const AnimationLibraryData &lib : animation_libraries) {276if (lib.name == p_name) {277return true;278}279}280281return false;282}283284StringName AnimationMixer::find_animation_library(const Ref<Animation> &p_animation) const {285for (const KeyValue<StringName, AnimationData> &E : animation_set) {286if (E.value.animation == p_animation) {287return E.value.animation_library;288}289}290return StringName();291}292293Error AnimationMixer::add_animation_library(const StringName &p_name, const Ref<AnimationLibrary> &p_animation_library) {294ERR_FAIL_COND_V(p_animation_library.is_null(), ERR_INVALID_PARAMETER);295#ifdef DEBUG_ENABLED296ERR_FAIL_COND_V_MSG(String(p_name).contains_char('/') || String(p_name).contains_char(':') || String(p_name).contains_char(',') || String(p_name).contains_char('['), ERR_INVALID_PARAMETER, "Invalid animation name: " + String(p_name) + ".");297#endif298299int insert_pos = 0;300301for (const AnimationLibraryData &lib : animation_libraries) {302ERR_FAIL_COND_V_MSG(lib.name == p_name, ERR_ALREADY_EXISTS, "Can't add animation library twice with name: " + String(p_name));303ERR_FAIL_COND_V_MSG(lib.library == p_animation_library, ERR_ALREADY_EXISTS, "Can't add animation library twice (adding as '" + p_name.operator String() + "', exists as '" + lib.name.operator String() + "'.");304305if (lib.name.operator String() >= p_name.operator String()) {306break;307}308309insert_pos++;310}311312AnimationLibraryData ald;313ald.name = p_name;314ald.library = p_animation_library;315316animation_libraries.insert(insert_pos, ald);317318ald.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added).bind(p_name));319ald.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed).bind(p_name));320ald.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed).bind(p_name));321ald.library->connect(SceneStringName(animation_changed), callable_mp(this, &AnimationMixer::_animation_changed));322323_animation_set_cache_update();324325notify_property_list_changed();326327return OK;328}329330void AnimationMixer::remove_animation_library(const StringName &p_name) {331int at_pos = -1;332333for (uint32_t i = 0; i < animation_libraries.size(); i++) {334if (animation_libraries[i].name == p_name) {335at_pos = i;336break;337}338}339340ERR_FAIL_COND(at_pos == -1);341342animation_libraries[at_pos].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added));343animation_libraries[at_pos].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed));344animation_libraries[at_pos].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed));345animation_libraries[at_pos].library->disconnect(SceneStringName(animation_changed), callable_mp(this, &AnimationMixer::_animation_changed));346347animation_libraries.remove_at(at_pos);348_animation_set_cache_update();349350notify_property_list_changed();351}352353void AnimationMixer::rename_animation_library(const StringName &p_name, const StringName &p_new_name) {354if (p_name == p_new_name) {355return;356}357#ifdef DEBUG_ENABLED358ERR_FAIL_COND_MSG(String(p_new_name).contains_char('/') || String(p_new_name).contains_char(':') || String(p_new_name).contains_char(',') || String(p_new_name).contains_char('['), "Invalid animation library name: " + String(p_new_name) + ".");359#endif360361bool found = false;362for (AnimationLibraryData &lib : animation_libraries) {363ERR_FAIL_COND_MSG(lib.name == p_new_name, "Can't rename animation library to another existing name: " + String(p_new_name) + ".");364if (lib.name == p_name) {365found = true;366lib.name = p_new_name;367// rename connections368lib.library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added));369lib.library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed));370lib.library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed));371372lib.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added).bind(p_new_name));373lib.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed).bind(p_new_name));374lib.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed).bind(p_new_name));375376for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) {377StringName old_name = p_name == StringName() ? K.key : StringName(String(p_name) + "/" + String(K.key));378StringName new_name = p_new_name == StringName() ? K.key : StringName(String(p_new_name) + "/" + String(K.key));379_rename_animation(old_name, new_name);380}381}382}383384ERR_FAIL_COND(!found);385386animation_libraries.sort(); // Must keep alphabetical order.387388_animation_set_cache_update(); // Update cache.389390notify_property_list_changed();391}392393void AnimationMixer::get_animation_list(List<StringName> *p_animations) const {394List<String> anims;395for (const KeyValue<StringName, AnimationData> &E : animation_set) {396anims.push_back(E.key);397}398anims.sort();399for (const String &E : anims) {400p_animations->push_back(E);401}402}403404Ref<Animation> AnimationMixer::get_animation(const StringName &p_name) const {405ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref<Animation>(), vformat("Animation not found: \"%s\".", p_name));406const AnimationData &anim_data = animation_set[p_name];407return anim_data.animation;408}409410bool AnimationMixer::has_animation(const StringName &p_name) const {411return animation_set.has(p_name);412}413414StringName AnimationMixer::find_animation(const Ref<Animation> &p_animation) const {415for (const KeyValue<StringName, AnimationData> &E : animation_set) {416if (E.value.animation == p_animation) {417return E.key;418}419}420return StringName();421}422423/* -------------------------------------------- */424/* -- General settings for animation ---------- */425/* -------------------------------------------- */426427void AnimationMixer::_set_process(bool p_process, bool p_force) {428if (processing == p_process && !p_force) {429return;430}431432switch (callback_mode_process) {433case ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS:434#ifdef TOOLS_ENABLED435set_physics_process_internal(p_process && active && !editing);436#else437set_physics_process_internal(p_process && active);438#endif // TOOLS_ENABLED439break;440case ANIMATION_CALLBACK_MODE_PROCESS_IDLE:441#ifdef TOOLS_ENABLED442set_process_internal(p_process && active && !editing);443#else444set_process_internal(p_process && active);445#endif // TOOLS_ENABLED446break;447case ANIMATION_CALLBACK_MODE_PROCESS_MANUAL:448break;449}450451processing = p_process;452}453454void AnimationMixer::set_active(bool p_active) {455if (active == p_active) {456return;457}458459active = p_active;460_set_active(active);461_set_process(processing, true);462463if (!active && is_inside_tree()) {464_clear_caches();465}466}467468bool AnimationMixer::is_active() const {469return active;470}471472void AnimationMixer::set_root_node(const NodePath &p_path) {473root_node = p_path;474_clear_caches();475}476477NodePath AnimationMixer::get_root_node() const {478return root_node;479}480481void AnimationMixer::set_deterministic(bool p_deterministic) {482deterministic = p_deterministic;483_clear_caches();484}485486bool AnimationMixer::is_deterministic() const {487return deterministic;488}489490void AnimationMixer::set_callback_mode_process(AnimationCallbackModeProcess p_mode) {491if (callback_mode_process == p_mode) {492return;493}494495bool was_active = is_active();496if (was_active) {497set_active(false);498}499500callback_mode_process = p_mode;501502if (was_active) {503set_active(true);504}505}506507AnimationMixer::AnimationCallbackModeProcess AnimationMixer::get_callback_mode_process() const {508return callback_mode_process;509}510511void AnimationMixer::set_callback_mode_method(AnimationCallbackModeMethod p_mode) {512callback_mode_method = p_mode;513emit_signal(SNAME("mixer_updated"));514}515516AnimationMixer::AnimationCallbackModeMethod AnimationMixer::get_callback_mode_method() const {517return callback_mode_method;518}519520void AnimationMixer::set_callback_mode_discrete(AnimationCallbackModeDiscrete p_mode) {521callback_mode_discrete = p_mode;522_clear_caches();523emit_signal(SNAME("mixer_updated"));524}525526AnimationMixer::AnimationCallbackModeDiscrete AnimationMixer::get_callback_mode_discrete() const {527return callback_mode_discrete;528}529530void AnimationMixer::set_audio_max_polyphony(int p_audio_max_polyphony) {531ERR_FAIL_COND(p_audio_max_polyphony < 0 || p_audio_max_polyphony > 128);532audio_max_polyphony = p_audio_max_polyphony;533}534535int AnimationMixer::get_audio_max_polyphony() const {536return audio_max_polyphony;537}538539#ifdef TOOLS_ENABLED540void AnimationMixer::set_editing(bool p_editing) {541if (editing == p_editing) {542return;543}544545editing = p_editing;546_set_process(processing, true);547548if (editing && is_inside_tree()) {549_clear_caches();550}551552notify_property_list_changed(); // To make active readonly.553}554555bool AnimationMixer::is_editing() const {556return editing;557}558559void AnimationMixer::set_dummy(bool p_dummy) {560dummy = p_dummy;561}562563bool AnimationMixer::is_dummy() const {564return dummy;565}566#endif // TOOLS_ENABLED567568/* -------------------------------------------- */569/* -- Caches for blending --------------------- */570/* -------------------------------------------- */571572void AnimationMixer::_clear_caches() {573_init_root_motion_cache();574_clear_audio_streams();575_clear_playing_caches();576for (KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {577memdelete(K.value);578}579track_cache.clear();580animation_track_num_to_track_cache.clear();581cache_valid = false;582capture_cache.clear();583584emit_signal(SNAME("caches_cleared"));585}586587void AnimationMixer::_clear_audio_streams() {588for (int i = 0; i < playing_audio_stream_players.size(); i++) {589playing_audio_stream_players[i]->call(SNAME("stop"));590playing_audio_stream_players[i]->call(SNAME("set_stream"), Ref<AudioStream>());591}592playing_audio_stream_players.clear();593}594595void AnimationMixer::_clear_playing_caches() {596for (const TrackCache *E : playing_caches) {597Object *t_obj = ObjectDB::get_instance(E->object_id);598if (t_obj) {599t_obj->call(SNAME("stop"), true);600}601}602playing_caches.clear();603}604605void AnimationMixer::_init_root_motion_cache() {606root_motion_cache.loc = Vector3(0, 0, 0);607root_motion_cache.rot = Quaternion(0, 0, 0, 1);608root_motion_cache.scale = Vector3(1, 1, 1);609root_motion_position = Vector3(0, 0, 0);610root_motion_rotation = Quaternion(0, 0, 0, 1);611root_motion_scale = Vector3(0, 0, 0);612root_motion_position_accumulator = Vector3(0, 0, 0);613root_motion_rotation_accumulator = Quaternion(0, 0, 0, 1);614root_motion_scale_accumulator = Vector3(1, 1, 1);615}616617void AnimationMixer::_create_track_num_to_track_cache_for_animation(Ref<Animation> &p_animation) {618if (animation_track_num_to_track_cache.has(p_animation)) {619// In AnimationMixer::_update_caches, it retrieves all animations via AnimationMixer::get_animation_list620// Since multiple AnimationLibraries can share the same Animation, it is possible that the cache is already created.621return;622}623LocalVector<TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache.insert_new(p_animation, LocalVector<TrackCache *>())->value;624const LocalVector<Animation::Track *> &tracks = p_animation->get_tracks();625626track_num_to_track_cache.resize(tracks.size());627for (uint32_t i = 0; i < tracks.size(); i++) {628TrackCache **track_ptr = track_cache.getptr(tracks[i]->thash);629if (track_ptr == nullptr) {630track_num_to_track_cache[i] = nullptr;631} else {632track_num_to_track_cache[i] = *track_ptr;633}634}635}636637bool AnimationMixer::_update_caches() {638setup_pass++;639640root_motion_cache.loc = Vector3(0, 0, 0);641root_motion_cache.rot = Quaternion(0, 0, 0, 1);642root_motion_cache.scale = Vector3(1, 1, 1);643644List<StringName> sname_list;645get_animation_list(&sname_list);646647bool check_path = GLOBAL_GET_CACHED(bool, "animation/warnings/check_invalid_track_paths");648bool check_angle_interpolation = GLOBAL_GET_CACHED(bool, "animation/warnings/check_angle_interpolation_type_conflicting");649650Node *parent = get_node_or_null(root_node);651if (!parent) {652WARN_PRINT_ONCE(vformat("'%s' is an invalid root_node path, caches will not be built, please check the root_node assignment on: %s", root_node, get_path()));653cache_valid = false;654return false;655}656657#ifdef TOOLS_ENABLED658String mixer_name = "AnimationMixer";659const Node *owner = get_owner();660if (owner) {661const String scene_path = owner->get_scene_file_path();662if (!scene_path.is_empty()) {663mixer_name += vformat(" (at: %s)", scene_path.get_file());664}665}666#else667const String mixer_name = "AnimationMixer";668#endif669670Ref<Animation> reset_anim;671bool has_reset_anim = has_animation(SceneStringName(RESET));672if (has_reset_anim) {673reset_anim = get_animation(SceneStringName(RESET));674}675for (const StringName &E : sname_list) {676Ref<Animation> anim = get_animation(E);677for (int i = 0; i < anim->get_track_count(); i++) {678if (!anim->track_is_enabled(i)) {679continue;680}681NodePath path = anim->track_get_path(i);682Animation::TypeHash thash = anim->track_get_type_hash(i);683Animation::TrackType track_src_type = anim->track_get_type(i);684Animation::TrackType track_cache_type = Animation::get_cache_type(track_src_type);685686TrackCache *track = nullptr;687if (track_cache.has(thash)) {688track = track_cache.get(thash);689}690691// If not valid, delete track.692if (track && (track->type != track_cache_type || ObjectDB::get_instance(track->object_id) == nullptr)) {693playing_caches.erase(track);694memdelete(track);695track_cache.erase(thash);696track = nullptr;697}698699if (!track) {700Ref<Resource> resource;701Vector<StringName> leftover_path;702703Node *child = parent->get_node_and_resource(path, resource, leftover_path);704if (!child) {705if (check_path) {706WARN_PRINT_ED(mixer_name + ": '" + String(E) + "', couldn't resolve track: '" + String(path) + "'. This warning can be disabled in Project Settings.");707}708continue;709}710711switch (track_src_type) {712case Animation::TYPE_BEZIER:713case Animation::TYPE_VALUE: {714// If a value track without a key is cached first, the initial value cannot be determined.715// It is a corner case, but which may cause problems with blending.716ERR_CONTINUE_MSG(anim->track_get_key_count(i) == 0, mixer_name + ": '" + String(E) + "', Value Track: '" + String(path) + "' must have at least one key to cache for blending.");717718TrackCacheValue *track_value = memnew(TrackCacheValue);719720if (resource.is_valid()) {721track_value->object_id = resource->get_instance_id();722} else {723track_value->object_id = child->get_instance_id();724}725726track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;727728track_value->subpath = leftover_path;729730track = track_value;731732bool is_value = track_src_type == Animation::TYPE_VALUE;733734track_value->init_value = is_value ? anim->track_get_key_value(i, 0) : (anim->track_get_key_value(i, 0).operator Array())[0];735track_value->init_value.zero();736737track_value->is_init = false;738739// Can't interpolate them, need to convert.740track_value->is_variant_interpolatable = Animation::is_variant_interpolatable(track_value->init_value);741742// If there is a Reset Animation, it takes precedence by overwriting.743if (has_reset_anim) {744int rt = reset_anim->find_track(path, track_src_type);745if (rt >= 0 && reset_anim->track_is_enabled(rt) && reset_anim->track_get_key_count(rt) > 0) {746if (is_value) {747track_value->init_value = reset_anim->track_get_key_value(rt, 0);748} else {749track_value->init_value = (reset_anim->track_get_key_value(rt, 0).operator Array())[0];750}751}752}753754if (is_value && callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {755if (child) {756PropertyInfo prop_info;757ClassDB::get_property_info(child->get_class_name(), path.get_concatenated_subnames(), &prop_info);758if (prop_info.hint == PROPERTY_HINT_ONESHOT) {759WARN_PRINT_ED(vformat("%s: '%s', Value Track: '%s' is oneshot property, but will be continuously updated. Consider setting a value other than ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS to AnimationMixer.callback_mode_dominant.", mixer_name, String(E), String(path)));760}761}762}763} break;764case Animation::TYPE_POSITION_3D:765case Animation::TYPE_ROTATION_3D:766case Animation::TYPE_SCALE_3D: {767#ifndef _3D_DISABLED768Node3D *node_3d = Object::cast_to<Node3D>(child);769770if (!node_3d) {771ERR_PRINT(mixer_name + ": '" + String(E) + "', transform track does not point to Node3D: '" + String(path) + "'.");772continue;773}774775TrackCacheTransform *track_xform = memnew(TrackCacheTransform);776track_xform->type = Animation::TYPE_POSITION_3D;777778track_xform->bone_idx = -1;779780bool has_rest = false;781Skeleton3D *sk = Object::cast_to<Skeleton3D>(node_3d);782if (sk && path.get_subname_count() == 1) {783track_xform->skeleton_id = sk->get_instance_id();784int bone_idx = sk->find_bone(path.get_subname(0));785if (bone_idx != -1) {786has_rest = true;787track_xform->bone_idx = bone_idx;788Transform3D rest = sk->get_bone_rest(bone_idx);789track_xform->init_loc = rest.origin;790track_xform->init_rot = rest.basis.get_rotation_quaternion();791track_xform->init_scale = rest.basis.get_scale();792}793}794795track_xform->object_id = node_3d->get_instance_id();796797track = track_xform;798799switch (track_src_type) {800case Animation::TYPE_POSITION_3D: {801track_xform->loc_used = true;802} break;803case Animation::TYPE_ROTATION_3D: {804track_xform->rot_used = true;805} break;806case Animation::TYPE_SCALE_3D: {807track_xform->scale_used = true;808} break;809default: {810}811}812813// For non Skeleton3D bone animation.814if (has_reset_anim && !has_rest) {815int rt = reset_anim->find_track(path, track_src_type);816if (rt >= 0 && reset_anim->track_is_enabled(rt) && reset_anim->track_get_key_count(rt) > 0) {817switch (track_src_type) {818case Animation::TYPE_POSITION_3D: {819track_xform->init_loc = reset_anim->track_get_key_value(rt, 0);820} break;821case Animation::TYPE_ROTATION_3D: {822track_xform->init_rot = reset_anim->track_get_key_value(rt, 0);823} break;824case Animation::TYPE_SCALE_3D: {825track_xform->init_scale = reset_anim->track_get_key_value(rt, 0);826} break;827default: {828}829}830}831}832#endif // _3D_DISABLED833} break;834case Animation::TYPE_BLEND_SHAPE: {835#ifndef _3D_DISABLED836if (path.get_subname_count() != 1) {837ERR_PRINT(mixer_name + ": '" + String(E) + "', blend shape track does not contain a blend shape subname: '" + String(path) + "'.");838continue;839}840MeshInstance3D *mesh_3d = Object::cast_to<MeshInstance3D>(child);841842if (!mesh_3d) {843ERR_PRINT(mixer_name + ": '" + String(E) + "', blend shape track does not point to MeshInstance3D: '" + String(path) + "'.");844continue;845}846847StringName blend_shape_name = path.get_subname(0);848int blend_shape_idx = mesh_3d->find_blend_shape_by_name(blend_shape_name);849if (blend_shape_idx == -1) {850ERR_PRINT(mixer_name + ": '" + String(E) + "', blend shape track points to a non-existing name: '" + String(blend_shape_name) + "'.");851continue;852}853854TrackCacheBlendShape *track_bshape = memnew(TrackCacheBlendShape);855856track_bshape->shape_index = blend_shape_idx;857track_bshape->object_id = mesh_3d->get_instance_id();858track = track_bshape;859860if (has_reset_anim) {861int rt = reset_anim->find_track(path, track_src_type);862if (rt >= 0 && reset_anim->track_is_enabled(rt) && reset_anim->track_get_key_count(rt) > 0) {863track_bshape->init_value = reset_anim->track_get_key_value(rt, 0);864}865}866#endif867} break;868case Animation::TYPE_METHOD: {869TrackCacheMethod *track_method = memnew(TrackCacheMethod);870871if (resource.is_valid()) {872track_method->object_id = resource->get_instance_id();873} else {874track_method->object_id = child->get_instance_id();875}876877track = track_method;878879} break;880case Animation::TYPE_AUDIO: {881TrackCacheAudio *track_audio = memnew(TrackCacheAudio);882883track_audio->object_id = child->get_instance_id();884track_audio->audio_stream.instantiate();885track_audio->audio_stream->set_polyphony(audio_max_polyphony);886track_audio->playback_type = (AudioServer::PlaybackType)(int)(child->call(SNAME("get_playback_type")));887track_audio->bus = (StringName)(child->call(SNAME("get_bus")));888889track = track_audio;890891} break;892case Animation::TYPE_ANIMATION: {893TrackCacheAnimation *track_animation = memnew(TrackCacheAnimation);894895track_animation->object_id = child->get_instance_id();896897track = track_animation;898899} break;900default: {901ERR_PRINT("Animation corrupted (invalid track type).");902continue;903}904}905track->path = path;906track_cache[thash] = track;907} else if (track_cache_type == Animation::TYPE_POSITION_3D) {908TrackCacheTransform *track_xform = static_cast<TrackCacheTransform *>(track);909if (track->setup_pass != setup_pass) {910track_xform->loc_used = false;911track_xform->rot_used = false;912track_xform->scale_used = false;913}914switch (track_src_type) {915case Animation::TYPE_POSITION_3D: {916track_xform->loc_used = true;917} break;918case Animation::TYPE_ROTATION_3D: {919track_xform->rot_used = true;920} break;921case Animation::TYPE_SCALE_3D: {922track_xform->scale_used = true;923} break;924default: {925}926}927} else if (track_cache_type == Animation::TYPE_VALUE) {928TrackCacheValue *track_value = static_cast<TrackCacheValue *>(track);929// If it has at least one angle interpolation, it also uses angle interpolation for blending.930bool was_using_angle = track_value->is_using_angle;931if (track_src_type == Animation::TYPE_VALUE) {932if (track_value->init_value.is_string() && anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE) {933WARN_PRINT_ONCE_ED(mixer_name + ": '" + String(E) + "', Value Track: '" + String(path) + "' blends String types. This is an experimental algorithm.");934}935track_value->is_using_angle = 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;936}937if (check_angle_interpolation && (was_using_angle != track_value->is_using_angle)) {938WARN_PRINT_ED(mixer_name + ": '" + String(E) + "', Value Track: '" + String(path) + "' has different interpolation types for rotation between some animations which may be blended together. Blending prioritizes angle interpolation, so the blending result uses the shortest path referenced to the initial (RESET animation) value.");939}940}941942track->setup_pass = setup_pass;943}944}945946List<Animation::TypeHash> to_delete;947948for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {949if (K.value->setup_pass != setup_pass) {950to_delete.push_back(K.key);951}952}953954while (to_delete.front()) {955Animation::TypeHash thash = to_delete.front()->get();956memdelete(track_cache[thash]);957track_cache.erase(thash);958to_delete.pop_front();959}960961track_map.clear();962963int idx = 0;964for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {965track_map[K.value->path] = idx;966idx++;967}968969for (KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {970K.value->blend_idx = track_map[K.value->path];971}972973animation_track_num_to_track_cache.clear();974for (const StringName &E : sname_list) {975Ref<Animation> anim = get_animation(E);976_create_track_num_to_track_cache_for_animation(anim);977}978979track_count = idx;980981cache_valid = true;982983return true;984}985986/* -------------------------------------------- */987/* -- Blending processor ---------------------- */988/* -------------------------------------------- */989990void AnimationMixer::_process_animation(double p_delta, bool p_update_only) {991_blend_init();992if (cache_valid && _blend_pre_process(p_delta, track_count, track_map)) {993_blend_capture(p_delta);994_blend_calc_total_weight();995_blend_process(p_delta, p_update_only);996clear_animation_instances();997_blend_apply();998_blend_post_process();999emit_signal(SNAME("mixer_applied"));1000} else {1001clear_animation_instances();1002}1003}10041005Variant 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) {1006#ifndef _3D_DISABLED1007switch (p_anim->track_get_type(p_track)) {1008case Animation::TYPE_POSITION_3D: {1009if (p_object_sub_idx >= 0) {1010Skeleton3D *skel = ObjectDB::get_instance<Skeleton3D>(p_object_id);1011if (skel) {1012return Vector3(p_value) * skel->get_motion_scale();1013}1014}1015return p_value;1016} break;1017default: {1018} break;1019}1020#endif // _3D_DISABLED1021return p_value;1022}10231024Variant 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) {1025if (is_GDVIRTUAL_CALL_post_process_key_value) {1026Variant res;1027if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, p_object_id, p_object_sub_idx, res)) {1028return res;1029}1030is_GDVIRTUAL_CALL_post_process_key_value = false;1031}1032return _post_process_key_value(p_anim, p_track, p_value, p_object_id, p_object_sub_idx);1033}10341035void AnimationMixer::_blend_init() {1036// Check all tracks, see if they need modification.1037root_motion_position = Vector3(0, 0, 0);1038root_motion_rotation = Quaternion(0, 0, 0, 1);1039root_motion_scale = Vector3(0, 0, 0);1040root_motion_position_accumulator = Vector3(0, 0, 0);1041root_motion_rotation_accumulator = Quaternion(0, 0, 0, 1);1042root_motion_scale_accumulator = Vector3(1, 1, 1);10431044if (!cache_valid) {1045if (!_update_caches()) {1046return;1047}1048}10491050// Init all value/transform/blend/bezier tracks that track_cache has.1051for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {1052TrackCache *track = K.value;10531054track->total_weight = 0.0;10551056switch (track->type) {1057case Animation::TYPE_POSITION_3D: {1058TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1059if (track->root_motion) {1060root_motion_cache.loc = Vector3(0, 0, 0);1061root_motion_cache.rot = Quaternion(0, 0, 0, 1);1062root_motion_cache.scale = Vector3(1, 1, 1);1063}1064t->loc = t->init_loc;1065t->rot = t->init_rot;1066t->scale = t->init_scale;1067} break;1068case Animation::TYPE_BLEND_SHAPE: {1069TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);1070t->value = t->init_value;1071} break;1072case Animation::TYPE_VALUE: {1073TrackCacheValue *t = static_cast<TrackCacheValue *>(track);1074t->value = Animation::cast_to_blendwise(t->init_value);1075t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0;1076t->use_continuous = false;1077t->use_discrete = false;1078} break;1079case Animation::TYPE_AUDIO: {1080TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);1081for (KeyValue<ObjectID, PlayingAudioTrackInfo> &L : t->playing_streams) {1082PlayingAudioTrackInfo &track_info = L.value;1083track_info.volume = 0.0;1084}1085} break;1086default: {1087} break;1088}1089}1090}10911092bool AnimationMixer::_blend_pre_process(double p_delta, int p_track_count, const AHashMap<NodePath, int> &p_track_map) {1093return true;1094}10951096void AnimationMixer::_blend_post_process() {1097//1098}10991100void AnimationMixer::_blend_capture(double p_delta) {1101blend_capture(p_delta);1102}11031104void AnimationMixer::blend_capture(double p_delta) {1105if (capture_cache.animation.is_null()) {1106return;1107}11081109capture_cache.remain -= p_delta * capture_cache.step;1110if (Animation::is_less_or_equal_approx(capture_cache.remain, 0)) {1111if (capture_cache.animation.is_valid()) {1112animation_track_num_to_track_cache.erase(capture_cache.animation);1113}1114capture_cache.clear();1115return;1116}11171118real_t weight = Tween::run_equation(capture_cache.trans_type, capture_cache.ease_type, capture_cache.remain, 0.0, 1.0, 1.0);11191120// Blend with other animations.1121real_t inv = 1.0 - weight;1122for (AnimationInstance &ai : animation_instances) {1123ai.playback_info.weight *= inv;1124}11251126// Build capture animation instance.1127AnimationData ad;1128ad.animation = capture_cache.animation;11291130PlaybackInfo pi;1131pi.weight = weight;11321133AnimationInstance ai;1134ai.animation_data = ad;1135ai.playback_info = pi;11361137animation_instances.push_back(ai);1138}11391140void AnimationMixer::_blend_calc_total_weight() {1141for (const AnimationInstance &ai : animation_instances) {1142Ref<Animation> a = ai.animation_data.animation;1143real_t weight = ai.playback_info.weight;1144const real_t *track_weights_ptr = ai.playback_info.track_weights.ptr();1145int track_weights_count = ai.playback_info.track_weights.size();1146ERR_CONTINUE_EDMSG(!animation_track_num_to_track_cache.has(a), "No animation in cache.");1147LocalVector<TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache[a];1148thread_local HashSet<Animation::TypeHash, HashHasher> processed_hashes;1149processed_hashes.clear();1150const LocalVector<Animation::Track *> &tracks = a->get_tracks();1151Animation::Track *const *tracks_ptr = tracks.ptr();1152int count = tracks.size();1153for (int i = 0; i < count; i++) {1154Animation::Track *animation_track = tracks_ptr[i];1155if (!animation_track->enabled) {1156continue;1157}1158Animation::TypeHash thash = animation_track->thash;1159TrackCache *track = track_num_to_track_cache[i];1160if (track == nullptr || processed_hashes.has(thash)) {1161// No path, but avoid error spamming.1162// Or, there is the case different track type with same path; These can be distinguished by hash. So don't add the weight doubly.1163continue;1164}1165int blend_idx = track->blend_idx;1166ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);1167real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;1168track->total_weight += blend;1169processed_hashes.insert(thash);1170}1171}1172}11731174void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {1175// Apply value/transform/blend/bezier blends to track caches and execute method/audio/animation tracks.1176#ifdef TOOLS_ENABLED1177bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint();1178#endif // TOOLS_ENABLED1179for (const AnimationInstance &ai : animation_instances) {1180Ref<Animation> a = ai.animation_data.animation;1181double time = ai.playback_info.time;1182double delta = ai.playback_info.delta;1183double start = ai.playback_info.start;1184double end = ai.playback_info.end;1185bool seeked = ai.playback_info.seeked;1186Animation::LoopedFlag looped_flag = ai.playback_info.looped_flag;1187bool is_external_seeking = ai.playback_info.is_external_seeking;1188real_t weight = ai.playback_info.weight;1189const real_t *track_weights_ptr = ai.playback_info.track_weights.ptr();1190int track_weights_count = ai.playback_info.track_weights.size();1191bool backward = std::signbit(delta); // This flag is used by the root motion calculates or detecting the end of audio stream.1192bool seeked_backward = std::signbit(p_delta);1193#ifndef _3D_DISABLED1194bool calc_root = !seeked || is_external_seeking;1195#endif // _3D_DISABLED1196ERR_CONTINUE_EDMSG(!animation_track_num_to_track_cache.has(a), "No animation in cache.");1197LocalVector<TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache[a];1198const LocalVector<Animation::Track *> &tracks = a->get_tracks();1199Animation::Track *const *tracks_ptr = tracks.ptr();1200real_t a_length = a->get_length();1201int count = tracks.size();1202for (int i = 0; i < count; i++) {1203const Animation::Track *animation_track = tracks_ptr[i];1204if (!animation_track->enabled) {1205continue;1206}1207TrackCache *track = track_num_to_track_cache[i];1208if (track == nullptr) {1209continue; // No path, but avoid error spamming.1210}1211int blend_idx = track->blend_idx;1212ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);1213real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;1214if (!deterministic) {1215// If non-deterministic, do normalization.1216// It would be better to make this if statement outside the for loop, but come here since too much code...1217if (Math::is_zero_approx(track->total_weight)) {1218continue;1219}1220blend = blend / track->total_weight;1221}1222Animation::TrackType ttype = animation_track->type;1223track->root_motion = root_motion_track == animation_track->path;1224switch (ttype) {1225case Animation::TYPE_POSITION_3D: {1226#ifndef _3D_DISABLED1227if (Math::is_zero_approx(blend)) {1228continue; // Nothing to blend.1229}1230TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1231if (track->root_motion && calc_root) {1232int rot_track = -1;1233if (root_motion_local) {1234rot_track = a->find_track(a->track_get_path(i), Animation::TYPE_ROTATION_3D);1235}1236double prev_time = time - delta;1237if (!backward) {1238if (Animation::is_less_approx(prev_time, start)) {1239switch (a->get_loop_mode()) {1240case Animation::LOOP_NONE: {1241prev_time = start;1242} break;1243case Animation::LOOP_LINEAR: {1244prev_time = Math::fposmod(prev_time - start, end - start) + start;1245} break;1246case Animation::LOOP_PINGPONG: {1247prev_time = Math::pingpong(prev_time - start, end - start) + start;1248} break;1249default:1250break;1251}1252}1253} else {1254if (Animation::is_greater_approx(prev_time, end)) {1255switch (a->get_loop_mode()) {1256case Animation::LOOP_NONE: {1257prev_time = end;1258} break;1259case Animation::LOOP_LINEAR: {1260prev_time = Math::fposmod(prev_time - start, end - start) + start;1261} break;1262case Animation::LOOP_PINGPONG: {1263prev_time = Math::pingpong(prev_time - start, end - start) + start;1264} break;1265default:1266break;1267}1268}1269}1270if (rot_track >= 0) {1271Vector3 loc[2];1272Quaternion rot;1273if (!backward) {1274if (Animation::is_greater_approx(prev_time, time)) {1275Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1276if (err != OK) {1277continue;1278}1279loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1280a->try_position_track_interpolate(i, end, &loc[1]);1281loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);12821283a->try_rotation_track_interpolate(rot_track, end, &rot);1284rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);12851286root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;1287prev_time = start;1288}1289} else {1290if (Animation::is_less_approx(prev_time, time)) {1291Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1292if (err != OK) {1293continue;1294}1295loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1296a->try_position_track_interpolate(i, start, &loc[1]);1297loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);12981299a->try_rotation_track_interpolate(rot_track, start, &rot);1300rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);13011302root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;1303prev_time = end;1304}1305}1306Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1307if (err != OK) {1308continue;1309}1310loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1311a->try_position_track_interpolate(i, time, &loc[1]);1312loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);13131314a->try_rotation_track_interpolate(rot_track, time, &rot);1315rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);13161317root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;1318prev_time = !backward ? start : end;1319} else {1320Vector3 loc[2];1321if (!backward) {1322if (Animation::is_greater_approx(prev_time, time)) {1323Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1324if (err != OK) {1325continue;1326}1327loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1328a->try_position_track_interpolate(i, end, &loc[1]);1329loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);1330root_motion_cache.loc += (loc[1] - loc[0]) * blend;1331prev_time = start;1332}1333} else {1334if (Animation::is_less_approx(prev_time, time)) {1335Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1336if (err != OK) {1337continue;1338}1339loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1340a->try_position_track_interpolate(i, start, &loc[1]);1341loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);1342root_motion_cache.loc += (loc[1] - loc[0]) * blend;1343prev_time = end;1344}1345}1346Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1347if (err != OK) {1348continue;1349}1350loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1351a->try_position_track_interpolate(i, time, &loc[1]);1352loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);1353root_motion_cache.loc += (loc[1] - loc[0]) * blend;1354prev_time = !backward ? start : end;1355}1356}1357{1358Vector3 loc;1359Error err = a->try_position_track_interpolate(i, time, &loc);1360if (err != OK) {1361continue;1362}1363loc = post_process_key_value(a, i, loc, t->object_id, t->bone_idx);1364t->loc += (loc - t->init_loc) * blend;1365}1366#endif // _3D_DISABLED1367} break;1368case Animation::TYPE_ROTATION_3D: {1369#ifndef _3D_DISABLED1370if (Math::is_zero_approx(blend)) {1371continue; // Nothing to blend.1372}1373TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1374if (track->root_motion && calc_root) {1375double prev_time = time - delta;1376if (!backward) {1377if (Animation::is_less_approx(prev_time, start)) {1378switch (a->get_loop_mode()) {1379case Animation::LOOP_NONE: {1380prev_time = start;1381} break;1382case Animation::LOOP_LINEAR: {1383prev_time = Math::fposmod(prev_time - start, end - start) + start;1384} break;1385case Animation::LOOP_PINGPONG: {1386prev_time = Math::pingpong(prev_time - start, end - start) + start;1387} break;1388default:1389break;1390}1391}1392} else {1393if (Animation::is_greater_approx(prev_time, end)) {1394switch (a->get_loop_mode()) {1395case Animation::LOOP_NONE: {1396prev_time = end;1397} break;1398case Animation::LOOP_LINEAR: {1399prev_time = Math::fposmod(prev_time - start, end - start) + start;1400} break;1401case Animation::LOOP_PINGPONG: {1402prev_time = Math::pingpong(prev_time - start, end - start) + start;1403} break;1404default:1405break;1406}1407}1408}1409Quaternion rot[2];1410if (!backward) {1411if (Animation::is_greater_approx(prev_time, time)) {1412Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);1413if (err != OK) {1414continue;1415}1416rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);1417a->try_rotation_track_interpolate(i, end, &rot[1]);1418rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);1419root_motion_cache.rot = Animation::interpolate_via_rest(root_motion_cache.rot, rot[1], blend, rot[0]);1420prev_time = start;1421}1422} else {1423if (Animation::is_less_approx(prev_time, time)) {1424Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);1425if (err != OK) {1426continue;1427}1428rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);1429a->try_rotation_track_interpolate(i, start, &rot[1]);1430rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);1431root_motion_cache.rot = Animation::interpolate_via_rest(root_motion_cache.rot, rot[1], blend, rot[0]);1432prev_time = end;1433}1434}1435Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);1436if (err != OK) {1437continue;1438}1439rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);1440a->try_rotation_track_interpolate(i, time, &rot[1]);1441rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);1442root_motion_cache.rot = Animation::interpolate_via_rest(root_motion_cache.rot, rot[1], blend, rot[0]);1443prev_time = !backward ? start : end;1444}1445{1446Quaternion rot;1447Error err = a->try_rotation_track_interpolate(i, time, &rot);1448if (err != OK) {1449continue;1450}1451rot = post_process_key_value(a, i, rot, t->object_id, t->bone_idx);1452t->rot = Animation::interpolate_via_rest(t->rot, rot, blend, t->init_rot);1453}1454#endif // _3D_DISABLED1455} break;1456case Animation::TYPE_SCALE_3D: {1457#ifndef _3D_DISABLED1458if (Math::is_zero_approx(blend)) {1459continue; // Nothing to blend.1460}1461TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1462if (track->root_motion && calc_root) {1463double prev_time = time - delta;1464if (!backward) {1465if (Animation::is_less_approx(prev_time, start)) {1466switch (a->get_loop_mode()) {1467case Animation::LOOP_NONE: {1468prev_time = start;1469} break;1470case Animation::LOOP_LINEAR: {1471prev_time = Math::fposmod(prev_time - start, end - start) + start;1472} break;1473case Animation::LOOP_PINGPONG: {1474prev_time = Math::pingpong(prev_time - start, end - start) + start;1475} break;1476default:1477break;1478}1479}1480} else {1481if (Animation::is_greater_approx(prev_time, end)) {1482switch (a->get_loop_mode()) {1483case Animation::LOOP_NONE: {1484prev_time = end;1485} break;1486case Animation::LOOP_LINEAR: {1487prev_time = Math::fposmod(prev_time - start, end - start) + start;1488} break;1489case Animation::LOOP_PINGPONG: {1490prev_time = Math::pingpong(prev_time - start, end - start) + start;1491} break;1492default:1493break;1494}1495}1496}1497Vector3 scale[2];1498if (!backward) {1499if (Animation::is_greater_approx(prev_time, time)) {1500Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);1501if (err != OK) {1502continue;1503}1504scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);1505a->try_scale_track_interpolate(i, end, &scale[1]);1506scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);1507root_motion_cache.scale += (scale[1] - scale[0]) * blend;1508prev_time = start;1509}1510} else {1511if (Animation::is_less_approx(prev_time, time)) {1512Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);1513if (err != OK) {1514continue;1515}1516scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);1517a->try_scale_track_interpolate(i, start, &scale[1]);1518scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);1519root_motion_cache.scale += (scale[1] - scale[0]) * blend;1520prev_time = end;1521}1522}1523Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);1524if (err != OK) {1525continue;1526}1527scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);1528a->try_scale_track_interpolate(i, time, &scale[1]);1529scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);1530root_motion_cache.scale += (scale[1] - scale[0]) * blend;1531prev_time = !backward ? start : end;1532}1533{1534Vector3 scale;1535Error err = a->try_scale_track_interpolate(i, time, &scale);1536if (err != OK) {1537continue;1538}1539scale = post_process_key_value(a, i, scale, t->object_id, t->bone_idx);1540t->scale += (scale - t->init_scale) * blend;1541}1542#endif // _3D_DISABLED1543} break;1544case Animation::TYPE_BLEND_SHAPE: {1545#ifndef _3D_DISABLED1546if (Math::is_zero_approx(blend)) {1547continue; // Nothing to blend.1548}1549TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);1550float value;1551Error err = a->try_blend_shape_track_interpolate(i, time, &value);1552//ERR_CONTINUE(err!=OK); //used for testing, should be removed1553if (err != OK) {1554continue;1555}1556value = post_process_key_value(a, i, value, t->object_id, t->shape_index);1557t->value += (value - t->init_value) * blend;1558#endif // _3D_DISABLED1559} break;1560case Animation::TYPE_BEZIER:1561case Animation::TYPE_VALUE: {1562if (Math::is_zero_approx(blend)) {1563continue; // Nothing to blend.1564}1565TrackCacheValue *t = static_cast<TrackCacheValue *>(track);1566bool is_value = ttype == Animation::TYPE_VALUE;1567bool is_discrete = is_value && a->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE;1568bool force_continuous = callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS;1569if (!is_discrete || force_continuous) {1570t->use_continuous = true;15711572Variant value;1573if (t->is_variant_interpolatable) {1574value = is_value ? a->value_track_interpolate(i, time, is_discrete && force_continuous ? backward : false) : Variant(a->bezier_track_interpolate(i, time));1575value = post_process_key_value(a, i, value, t->object_id);1576if (value == Variant()) {1577continue;1578}1579} else {1580// Discrete track sets the value in the current _blend_process() function,1581// but Force Continuous track does not set the value here because the value must be set in the _blend_apply() function later.1582int idx = a->track_find_key(i, time, Animation::FIND_MODE_NEAREST, false, backward);1583if (idx < 0) {1584continue;1585}1586value = a->track_get_key_value(i, idx);1587value = post_process_key_value(a, i, value, t->object_id);1588if (value == Variant()) {1589continue;1590}1591t->value = value;1592continue;1593}15941595// Special case for angle interpolation.1596if (t->is_using_angle) {1597// For blending consistency, it prevents rotation of more than 180 degrees from init_value.1598// This is the same with Quaternion blending.1599t->value = Animation::interpolate_via_rest((double)t->value, (double)value, blend, (double)t->init_value);1600} else {1601value = Animation::cast_to_blendwise(value);1602if (t->init_value.is_array()) {1603t->element_size = MAX(t->element_size.operator int(), (value.operator Array()).size());1604} else if (t->init_value.is_string()) {1605real_t length = Animation::subtract_variant((real_t)(value.operator Array()).size(), (real_t)(t->init_value.operator String()).length());1606t->element_size = Animation::blend_variant(t->element_size, length, blend);1607}1608value = Animation::subtract_variant(value, Animation::cast_to_blendwise(t->init_value));1609t->value = Animation::blend_variant(t->value, value, blend);1610}1611} else {1612if (seeked) {1613int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, false, seeked_backward);1614if (idx < 0) {1615continue;1616}1617t->use_discrete = true;1618Variant value = a->track_get_key_value(i, idx);1619value = post_process_key_value(a, i, value, t->object_id);1620Object *t_obj = ObjectDB::get_instance(t->object_id);1621if (t_obj) {1622t_obj->set_indexed(t->subpath, value);1623}1624} else {1625List<int> indices;1626a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);1627for (int &F : indices) {1628t->use_discrete = true;1629Variant value = a->track_get_key_value(i, F);1630value = post_process_key_value(a, i, value, t->object_id);1631Object *t_obj = ObjectDB::get_instance(t->object_id);1632if (t_obj) {1633t_obj->set_indexed(t->subpath, value);1634}1635}1636}1637}1638} break;1639case Animation::TYPE_METHOD: {1640#ifdef TOOLS_ENABLED1641if (!can_call) {1642continue;1643}1644#endif // TOOLS_ENABLED1645if (p_update_only || Math::is_zero_approx(blend)) {1646continue;1647}1648TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track);1649if (seeked) {1650int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, true);1651if (idx < 0) {1652continue;1653}1654StringName method = a->method_track_get_name(i, idx);1655Vector<Variant> params = a->method_track_get_params(i, idx);1656_call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);1657} else {1658List<int> indices;1659a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);1660for (int &F : indices) {1661StringName method = a->method_track_get_name(i, F);1662Vector<Variant> params = a->method_track_get_params(i, F);1663_call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);1664}1665}1666} break;1667case Animation::TYPE_AUDIO: {1668// 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.1669TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);1670Object *t_obj = ObjectDB::get_instance(t->object_id);1671Node *asp = t_obj ? Object::cast_to<Node>(t_obj) : nullptr;1672if (!t_obj || !asp) {1673t->playing_streams.clear();1674continue;1675}1676ObjectID oid = a->get_instance_id();1677if (!t->playing_streams.has(oid)) {1678t->playing_streams[oid] = PlayingAudioTrackInfo();1679}16801681PlayingAudioTrackInfo &track_info = t->playing_streams[oid];1682track_info.length = a_length;1683track_info.time = time;1684track_info.volume += blend;1685track_info.loop = a->get_loop_mode() != Animation::LOOP_NONE;1686track_info.backward = backward;1687track_info.use_blend = a->audio_track_is_use_blend(i);1688AHashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;16891690// Main process to fire key is started from here.1691if (p_update_only) {1692continue;1693}1694// Find stream.1695int idx = -1;1696if (seeked) {1697// Audio key may be playbacked from the middle, should use FIND_MODE_NEAREST.1698// Then, check the current playing stream to prevent to playback doubly.1699idx = a->track_find_key(i, time, Animation::FIND_MODE_NEAREST, true);1700// Discard previous stream when seeking.1701if (map.has(idx)) {1702t->audio_stream_playback->stop_stream(map[idx].index);1703map.erase(idx);1704}1705} else {1706List<int> to_play;1707a->track_get_key_indices_in_range(i, time, delta, &to_play, looped_flag);1708if (to_play.size()) {1709idx = to_play.back()->get();1710}1711}1712if (idx < 0) {1713continue;1714}17151716// Play stream.1717Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);1718if (stream.is_valid()) {1719double start_ofs = a->audio_track_get_key_start_offset(i, idx);1720double end_ofs = a->audio_track_get_key_end_offset(i, idx);1721double len = stream->get_length();1722if (seeked) {1723start_ofs += time - a->track_get_key_time(i, idx);1724}17251726if (t_obj->call(SNAME("get_stream")) != t->audio_stream) {1727t_obj->call(SNAME("set_stream"), t->audio_stream);1728t->audio_stream_playback.unref();1729if (!playing_audio_stream_players.has(asp)) {1730playing_audio_stream_players.push_back(asp);1731}1732}1733if (!t_obj->call(SNAME("is_playing"))) {1734t_obj->call(SNAME("play"));1735}1736if (!t_obj->call(SNAME("has_stream_playback"))) {1737t->audio_stream_playback.unref();1738continue;1739}1740if (t->audio_stream_playback.is_null()) {1741t->audio_stream_playback = t_obj->call(SNAME("get_stream_playback"));1742}17431744if (t_obj->call(SNAME("get_is_sample"))) {1745if (t->audio_stream_playback->get_sample_playback().is_valid()) {1746AudioServer::get_singleton()->stop_sample_playback(t->audio_stream_playback->get_sample_playback());1747}1748Ref<AudioSamplePlayback> sample_playback;1749sample_playback.instantiate();1750sample_playback->stream = stream;1751t->audio_stream_playback->set_sample_playback(sample_playback);1752AudioServer::get_singleton()->start_sample_playback(sample_playback);1753continue;1754}17551756PlayingAudioStreamInfo pasi;1757pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs, 0, 1.0, t->playback_type, t->bus);1758pasi.start = time;1759if (len && Animation::is_greater_approx(end_ofs, 0)) { // Force an end at a time.1760pasi.len = len - start_ofs - end_ofs;1761} else {1762pasi.len = 0;1763}1764map[idx] = pasi;1765}1766} break;1767case Animation::TYPE_ANIMATION: {1768if (Math::is_zero_approx(blend)) {1769continue;1770}1771TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track);1772Object *t_obj = ObjectDB::get_instance(t->object_id);1773if (!t_obj) {1774continue;1775}1776AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t_obj);1777if (!player2) {1778continue;1779}1780// TODO: Make it possible to embed section info in animation track keys.1781if (seeked) {1782// Seek.1783int idx = a->track_find_key(i, time, Animation::FIND_MODE_NEAREST, true);1784if (idx < 0) {1785continue;1786}1787double pos = a->track_get_key_time(i, idx);1788StringName anim_name = a->animation_track_get_key_animation(i, idx);1789if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) {1790continue;1791}1792Ref<Animation> anim = player2->get_animation(anim_name);1793double at_anim_pos = start;1794switch (anim->get_loop_mode()) {1795case Animation::LOOP_NONE: {1796if (!is_external_seeking && ((!backward && Animation::is_greater_or_equal_approx(time, pos + end)) || (backward && Animation::is_less_or_equal_approx(time, pos + start)))) {1797continue; // Do nothing if current time is outside of length when started.1798}1799at_anim_pos = MIN(end, time - pos); // Seek to end.1800} break;1801case Animation::LOOP_LINEAR: {1802at_anim_pos = Math::fposmod(time - pos - start, end - start) + start; // Seek to loop.1803} break;1804case Animation::LOOP_PINGPONG: {1805at_anim_pos = Math::pingpong(time - pos - start, end - start) + start;1806} break;1807default:1808break;1809}1810if (player2->is_playing() || !is_external_seeking) {1811player2->seek(at_anim_pos, false, p_update_only);1812player2->play(anim_name);1813t->playing = true;1814playing_caches.insert(t);1815} else {1816player2->set_assigned_animation(anim_name);1817player2->seek(at_anim_pos, true, p_update_only);1818}1819} else {1820// Find stuff to play.1821List<int> to_play;1822a->track_get_key_indices_in_range(i, time, delta, &to_play, looped_flag);1823if (to_play.size()) {1824int idx = to_play.back()->get();1825StringName anim_name = a->animation_track_get_key_animation(i, idx);1826if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) {1827if (playing_caches.has(t)) {1828playing_caches.erase(t);1829player2->stop();1830t->playing = false;1831}1832} else {1833player2->play(anim_name);1834t->playing = true;1835playing_caches.insert(t);1836}1837}1838}1839} break;1840}1841}1842}1843is_GDVIRTUAL_CALL_post_process_key_value = true;1844}18451846void AnimationMixer::_blend_apply() {1847// Finally, set the tracks.1848for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {1849TrackCache *track = K.value;1850bool is_zero_amount = Math::is_zero_approx(track->total_weight);1851if (!deterministic && is_zero_amount) {1852continue;1853}1854switch (track->type) {1855case Animation::TYPE_POSITION_3D: {1856#ifndef _3D_DISABLED1857TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);18581859if (t->root_motion) {1860root_motion_position = root_motion_cache.loc;1861root_motion_rotation = root_motion_cache.rot;1862root_motion_scale = root_motion_cache.scale - Vector3(1, 1, 1);1863root_motion_position_accumulator = t->loc;1864root_motion_rotation_accumulator = t->rot;1865root_motion_scale_accumulator = t->scale;1866} else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) {1867Skeleton3D *t_skeleton = ObjectDB::get_instance<Skeleton3D>(t->skeleton_id);1868if (!t_skeleton) {1869return;1870}1871if (t->loc_used) {1872t_skeleton->set_bone_pose_position(t->bone_idx, t->loc);1873}1874if (t->rot_used) {1875t_skeleton->set_bone_pose_rotation(t->bone_idx, t->rot);1876}1877if (t->scale_used) {1878t_skeleton->set_bone_pose_scale(t->bone_idx, t->scale);1879}18801881} else if (!t->skeleton_id.is_valid()) {1882Node3D *t_node_3d = ObjectDB::get_instance<Node3D>(t->object_id);1883if (!t_node_3d) {1884return;1885}1886if (t->loc_used) {1887t_node_3d->set_position(t->loc);1888}1889if (t->rot_used) {1890t_node_3d->set_rotation(t->rot.get_euler());1891}1892if (t->scale_used) {1893t_node_3d->set_scale(t->scale);1894}1895}1896#endif // _3D_DISABLED1897} break;1898case Animation::TYPE_BLEND_SHAPE: {1899#ifndef _3D_DISABLED1900TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);19011902MeshInstance3D *t_mesh_3d = ObjectDB::get_instance<MeshInstance3D>(t->object_id);1903if (t_mesh_3d) {1904t_mesh_3d->set_blend_shape_value(t->shape_index, t->value);1905}1906#endif // _3D_DISABLED1907} break;1908case Animation::TYPE_VALUE: {1909TrackCacheValue *t = static_cast<TrackCacheValue *>(track);19101911if (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {1912t->is_init = false; // Always update in Force Continuous.1913} else if (!t->use_continuous && (t->use_discrete || !deterministic)) {1914t->is_init = true; // If there is no continuous value and only disctere value is applied or just started, don't RESET.1915}19161917if ((t->is_init && (is_zero_amount || !t->use_continuous)) ||1918(callback_mode_discrete != ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS &&1919!is_zero_amount &&1920callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT &&1921t->use_discrete)) {1922break; // Don't overwrite the value set by UPDATE_DISCRETE.1923}19241925if (callback_mode_discrete != ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {1926t->is_init = !t->use_continuous; // If there is no Continuous in non-Force Continuous type, it means RESET.1927}19281929// Trim unused elements if init array/string is not blended.1930if (t->value.is_array()) {1931int actual_blended_size = (int)Math::round(Math::abs(t->element_size.operator real_t()));1932if (actual_blended_size < (t->value.operator Array()).size()) {1933real_t abs_weight = Math::abs(track->total_weight);1934if (abs_weight >= 1.0) {1935(t->value.operator Array()).resize(actual_blended_size);1936} else if (t->init_value.is_string()) {1937(t->value.operator Array()).resize(Animation::interpolate_variant((t->init_value.operator String()).length(), actual_blended_size, abs_weight));1938}1939}1940}19411942Object *t_obj = ObjectDB::get_instance(t->object_id);1943if (t_obj) {1944t_obj->set_indexed(t->subpath, Animation::cast_from_blendwise(t->value, t->init_value.get_type()));1945}19461947} break;1948case Animation::TYPE_AUDIO: {1949TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);19501951// Audio ending process.1952LocalVector<ObjectID> erase_maps;1953for (KeyValue<ObjectID, PlayingAudioTrackInfo> &L : t->playing_streams) {1954PlayingAudioTrackInfo &track_info = L.value;1955float db = Math::linear_to_db(track_info.use_blend ? track_info.volume : 1.0);1956LocalVector<int> erase_streams;1957AHashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;1958for (const KeyValue<int, PlayingAudioStreamInfo> &M : map) {1959PlayingAudioStreamInfo pasi = M.value;19601961bool stop = false;1962if (!t->audio_stream_playback->is_stream_playing(pasi.index)) {1963stop = true;1964}1965if (!track_info.loop) {1966if (!track_info.backward) {1967if (Animation::is_less_approx(track_info.time, pasi.start)) {1968stop = true;1969}1970} else if (track_info.backward) {1971if (Animation::is_greater_approx(track_info.time, pasi.start)) {1972stop = true;1973}1974}1975}1976if (Animation::is_greater_approx(pasi.len, 0)) {1977double len = 0.0;1978if (!track_info.backward) {1979len = Animation::is_greater_approx(pasi.start, track_info.time) ? (track_info.length - pasi.start) + track_info.time : track_info.time - pasi.start;1980} else {1981len = Animation::is_less_approx(pasi.start, track_info.time) ? (track_info.length - track_info.time) + pasi.start : pasi.start - track_info.time;1982}1983if (Animation::is_greater_approx(len, pasi.len)) {1984stop = true;1985}1986}1987if (stop) {1988// Time to stop.1989t->audio_stream_playback->stop_stream(pasi.index);1990erase_streams.push_back(M.key);1991} else {1992t->audio_stream_playback->set_stream_volume(pasi.index, db);1993}1994}1995for (uint32_t erase_idx = 0; erase_idx < erase_streams.size(); erase_idx++) {1996map.erase(erase_streams[erase_idx]);1997}1998if (map.is_empty()) {1999erase_maps.push_back(L.key);2000}2001}2002for (uint32_t erase_idx = 0; erase_idx < erase_maps.size(); erase_idx++) {2003t->playing_streams.erase(erase_maps[erase_idx]);2004}2005} break;2006default: {2007} // The rest don't matter.2008}2009}2010}20112012void AnimationMixer::_call_object(ObjectID p_object_id, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) {2013// Separate function to use alloca() more efficiently2014const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * p_params.size());2015const Variant *args = p_params.ptr();2016uint32_t argcount = p_params.size();2017for (uint32_t i = 0; i < argcount; i++) {2018argptrs[i] = &args[i];2019}2020Object *t_obj = ObjectDB::get_instance(p_object_id);2021if (!t_obj) {2022return;2023}2024if (p_deferred) {2025Callable(t_obj, p_method).call_deferredp(argptrs, argcount);2026} else {2027Callable::CallError ce;2028t_obj->callp(p_method, argptrs, argcount, ce);2029}2030}20312032void AnimationMixer::make_animation_instance(const StringName &p_name, const PlaybackInfo p_playback_info) {2033ERR_FAIL_COND(!has_animation(p_name));20342035AnimationData ad;2036ad.name = p_name;2037ad.animation = get_animation(p_name);2038ad.animation_library = find_animation_library(ad.animation);20392040AnimationInstance ai;2041ai.animation_data = ad;2042ai.playback_info = p_playback_info;20432044animation_instances.push_back(ai);2045}20462047void AnimationMixer::clear_animation_instances() {2048animation_instances.clear();2049}20502051void AnimationMixer::advance(double p_time) {2052_process_animation(p_time);2053}20542055void AnimationMixer::clear_caches() {2056_clear_caches();2057}20582059/* -------------------------------------------- */2060/* -- Root motion ----------------------------- */2061/* -------------------------------------------- */20622063void AnimationMixer::set_root_motion_track(const NodePath &p_track) {2064root_motion_track = p_track;2065notify_property_list_changed();2066}20672068NodePath AnimationMixer::get_root_motion_track() const {2069return root_motion_track;2070}20712072void AnimationMixer::set_root_motion_local(bool p_enabled) {2073root_motion_local = p_enabled;2074}20752076bool AnimationMixer::is_root_motion_local() const {2077return root_motion_local;2078}20792080Vector3 AnimationMixer::get_root_motion_position() const {2081return root_motion_position;2082}20832084Quaternion AnimationMixer::get_root_motion_rotation() const {2085return root_motion_rotation;2086}20872088Vector3 AnimationMixer::get_root_motion_scale() const {2089return root_motion_scale;2090}20912092Vector3 AnimationMixer::get_root_motion_position_accumulator() const {2093return root_motion_position_accumulator;2094}20952096Quaternion AnimationMixer::get_root_motion_rotation_accumulator() const {2097return root_motion_rotation_accumulator;2098}20992100Vector3 AnimationMixer::get_root_motion_scale_accumulator() const {2101return root_motion_scale_accumulator;2102}21032104/* -------------------------------------------- */2105/* -- Reset on save --------------------------- */2106/* -------------------------------------------- */21072108void AnimationMixer::set_reset_on_save_enabled(bool p_enabled) {2109reset_on_save = p_enabled;2110}21112112bool AnimationMixer::is_reset_on_save_enabled() const {2113return reset_on_save;2114}21152116bool AnimationMixer::can_apply_reset() const {2117return has_animation(SceneStringName(RESET));2118}21192120void AnimationMixer::_build_backup_track_cache() {2121for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {2122TrackCache *track = K.value;2123track->total_weight = 1.0;2124switch (track->type) {2125case Animation::TYPE_POSITION_3D: {2126#ifndef _3D_DISABLED2127TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);2128if (t->root_motion) {2129// Do nothing.2130} else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) {2131Skeleton3D *t_skeleton = ObjectDB::get_instance<Skeleton3D>(t->skeleton_id);2132if (!t_skeleton) {2133return;2134}2135if (t->loc_used) {2136t->loc = t_skeleton->get_bone_pose_position(t->bone_idx);2137}2138if (t->rot_used) {2139t->rot = t_skeleton->get_bone_pose_rotation(t->bone_idx);2140}2141if (t->scale_used) {2142t->scale = t_skeleton->get_bone_pose_scale(t->bone_idx);2143}2144} else if (!t->skeleton_id.is_valid()) {2145Node3D *t_node_3d = ObjectDB::get_instance<Node3D>(t->object_id);2146if (!t_node_3d) {2147return;2148}2149if (t->loc_used) {2150t->loc = t_node_3d->get_position();2151}2152if (t->rot_used) {2153t->rot = t_node_3d->get_quaternion();2154}2155if (t->scale_used) {2156t->scale = t_node_3d->get_scale();2157}2158}2159#endif // _3D_DISABLED2160} break;2161case Animation::TYPE_BLEND_SHAPE: {2162#ifndef _3D_DISABLED2163TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);2164MeshInstance3D *t_mesh_3d = ObjectDB::get_instance<MeshInstance3D>(t->object_id);2165if (t_mesh_3d) {2166t->value = t_mesh_3d->get_blend_shape_value(t->shape_index);2167}2168#endif // _3D_DISABLED2169} break;2170case Animation::TYPE_VALUE: {2171TrackCacheValue *t = static_cast<TrackCacheValue *>(track);2172Object *t_obj = ObjectDB::get_instance(t->object_id);2173if (t_obj) {2174t->value = Animation::cast_to_blendwise(t_obj->get_indexed(t->subpath));2175}2176t->use_continuous = true;2177t->use_discrete = false;2178if (t->init_value.is_array()) {2179t->element_size = MAX(t->element_size.operator int(), (t->value.operator Array()).size());2180} else if (t->init_value.is_string()) {2181t->element_size = (real_t)(t->value.operator Array()).size();2182}2183} break;2184case Animation::TYPE_AUDIO: {2185TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);2186Object *t_obj = ObjectDB::get_instance(t->object_id);2187if (t_obj) {2188Node *asp = Object::cast_to<Node>(t_obj);2189if (asp) {2190asp->call(SNAME("set_stream"), Ref<AudioStream>());2191}2192}2193} break;2194default: {2195} // The rest don't matter.2196}2197}2198}21992200Ref<AnimatedValuesBackup> AnimationMixer::make_backup() {2201Ref<AnimatedValuesBackup> backup;2202backup.instantiate();22032204Ref<Animation> reset_anim = animation_set[SceneStringName(RESET)].animation;2205ERR_FAIL_COND_V(reset_anim.is_null(), Ref<AnimatedValuesBackup>());22062207_blend_init();2208PlaybackInfo pi;2209pi.time = 0;2210pi.delta = 0;2211pi.start = 0;2212pi.end = reset_anim->get_length();2213pi.seeked = true;2214pi.weight = 1.0;2215make_animation_instance(SceneStringName(RESET), pi);2216_build_backup_track_cache();22172218backup->set_data(AHashMap<Animation::TypeHash, TrackCache *, HashHasher>(track_cache));2219clear_animation_instances();22202221return backup;2222}22232224void AnimationMixer::reset() {2225ERR_FAIL_COND(!can_apply_reset());22262227Ref<Animation> reset_anim = animation_set[SceneStringName(RESET)].animation;2228ERR_FAIL_COND(reset_anim.is_null());22292230Node *root_node_object = get_node_or_null(root_node);2231ERR_FAIL_NULL(root_node_object);22322233AnimationPlayer *aux_player = memnew(AnimationPlayer);2234root_node_object->add_child(aux_player);2235Ref<AnimationLibrary> al;2236al.instantiate();2237al->add_animation(SceneStringName(RESET), reset_anim);2238aux_player->set_reset_on_save_enabled(false);2239aux_player->set_root_node(aux_player->get_path_to(root_node_object));2240aux_player->add_animation_library("", al);2241aux_player->set_assigned_animation(SceneStringName(RESET));2242aux_player->seek(0.0f, true);2243aux_player->queue_free();2244}22452246void AnimationMixer::restore(const Ref<AnimatedValuesBackup> &p_backup) {2247ERR_FAIL_COND(p_backup.is_null());2248track_cache = p_backup->get_data();2249_blend_apply();2250track_cache = AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher>();2251cache_valid = false;2252}22532254#ifdef TOOLS_ENABLED2255Ref<AnimatedValuesBackup> AnimationMixer::apply_reset(bool p_user_initiated) {2256if (!p_user_initiated && dummy) {2257return Ref<AnimatedValuesBackup>();2258}2259ERR_FAIL_COND_V(!can_apply_reset(), Ref<AnimatedValuesBackup>());22602261Ref<Animation> reset_anim = animation_set[SceneStringName(RESET)].animation;2262ERR_FAIL_COND_V(reset_anim.is_null(), Ref<AnimatedValuesBackup>());22632264Ref<AnimatedValuesBackup> backup_current = make_backup();2265if (p_user_initiated) {2266EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();2267ur->create_action(TTR("Animation Apply Reset"));2268ur->add_do_method(this, "_reset");2269ur->add_undo_method(this, "_restore", backup_current);2270ur->commit_action();2271} else {2272reset();2273}22742275return backup_current;2276}2277#endif // TOOLS_ENABLED22782279/* -------------------------------------------- */2280/* -- Capture feature ------------------------- */2281/* -------------------------------------------- */22822283void AnimationMixer::capture(const StringName &p_name, double p_duration, Tween::TransitionType p_trans_type, Tween::EaseType p_ease_type) {2284ERR_FAIL_COND(!active);2285ERR_FAIL_COND(!has_animation(p_name));2286ERR_FAIL_COND(p_duration <= 0);2287Ref<Animation> reference_animation = get_animation(p_name);22882289if (!cache_valid) {2290_update_caches(); // Need to retrieve object id.2291}22922293capture_cache.remain = 1.0;2294capture_cache.step = 1.0 / p_duration;2295capture_cache.trans_type = p_trans_type;2296capture_cache.ease_type = p_ease_type;2297if (capture_cache.animation.is_valid()) {2298animation_track_num_to_track_cache.erase(capture_cache.animation);2299}2300capture_cache.animation.instantiate();23012302bool is_valid = false;2303for (int i = 0; i < reference_animation->get_track_count(); i++) {2304if (!reference_animation->track_is_enabled(i)) {2305continue;2306}2307if (reference_animation->track_get_type(i) == Animation::TYPE_VALUE && reference_animation->value_track_get_update_mode(i) == Animation::UPDATE_CAPTURE) {2308TrackCacheValue *t = static_cast<TrackCacheValue *>(track_cache[reference_animation->track_get_type_hash(i)]);2309Object *t_obj = ObjectDB::get_instance(t->object_id);2310if (t_obj) {2311Variant value = t_obj->get_indexed(t->subpath);2312int inserted_idx = capture_cache.animation->add_track(Animation::TYPE_VALUE);2313capture_cache.animation->track_set_path(inserted_idx, reference_animation->track_get_path(i));2314capture_cache.animation->track_insert_key(inserted_idx, 0, value);2315capture_cache.animation->value_track_set_update_mode(inserted_idx, Animation::UPDATE_CONTINUOUS);2316capture_cache.animation->track_set_interpolation_type(inserted_idx, Animation::INTERPOLATION_LINEAR);2317is_valid = true;2318}2319}2320}2321if (!is_valid) {2322capture_cache.clear();2323} else {2324_create_track_num_to_track_cache_for_animation(capture_cache.animation);2325}2326}23272328/* -------------------------------------------- */2329/* -- General functions ----------------------- */2330/* -------------------------------------------- */23312332void AnimationMixer::_node_removed(Node *p_node) {2333_clear_caches();2334}23352336void AnimationMixer::_notification(int p_what) {2337switch (p_what) {2338case NOTIFICATION_ENTER_TREE: {2339if (!processing) {2340set_physics_process_internal(false);2341set_process_internal(false);2342}2343_clear_caches();2344} break;23452346case NOTIFICATION_INTERNAL_PROCESS: {2347if (active && callback_mode_process == ANIMATION_CALLBACK_MODE_PROCESS_IDLE) {2348_process_animation(get_process_delta_time());2349}2350} break;23512352case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {2353if (active && callback_mode_process == ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS) {2354_process_animation(get_physics_process_delta_time());2355}2356} break;23572358case NOTIFICATION_EXIT_TREE: {2359_clear_caches();2360} break;2361}2362}23632364#ifdef TOOLS_ENABLED2365void AnimationMixer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {2366const String pf = p_function;2367if (p_idx == 0) {2368if (pf == "get_animation" || pf == "has_animation") {2369List<StringName> al;2370get_animation_list(&al);2371for (const StringName &name : al) {2372r_options->push_back(String(name).quote());2373}2374} else if (pf == "get_animation_library" || pf == "has_animation_library" || pf == "remove_animation_library" || pf == "rename_animation_library") {2375List<StringName> al;2376get_animation_library_list(&al);2377for (const StringName &name : al) {2378r_options->push_back(String(name).quote());2379}2380}2381}2382Node::get_argument_options(p_function, p_idx, r_options);2383}2384#endif23852386void AnimationMixer::_bind_methods() {2387/* ---- Data lists ---- */2388ClassDB::bind_method(D_METHOD("add_animation_library", "name", "library"), &AnimationMixer::add_animation_library);2389ClassDB::bind_method(D_METHOD("remove_animation_library", "name"), &AnimationMixer::remove_animation_library);2390ClassDB::bind_method(D_METHOD("rename_animation_library", "name", "newname"), &AnimationMixer::rename_animation_library);2391ClassDB::bind_method(D_METHOD("has_animation_library", "name"), &AnimationMixer::has_animation_library);2392ClassDB::bind_method(D_METHOD("get_animation_library", "name"), &AnimationMixer::get_animation_library);2393ClassDB::bind_method(D_METHOD("get_animation_library_list"), &AnimationMixer::_get_animation_library_list);23942395ClassDB::bind_method(D_METHOD("has_animation", "name"), &AnimationMixer::has_animation);2396ClassDB::bind_method(D_METHOD("get_animation", "name"), &AnimationMixer::get_animation);2397ClassDB::bind_method(D_METHOD("get_animation_list"), &AnimationMixer::_get_animation_list);23982399/* ---- General settings for animation ---- */2400ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationMixer::set_active);2401ClassDB::bind_method(D_METHOD("is_active"), &AnimationMixer::is_active);24022403ClassDB::bind_method(D_METHOD("set_deterministic", "deterministic"), &AnimationMixer::set_deterministic);2404ClassDB::bind_method(D_METHOD("is_deterministic"), &AnimationMixer::is_deterministic);24052406ClassDB::bind_method(D_METHOD("set_root_node", "path"), &AnimationMixer::set_root_node);2407ClassDB::bind_method(D_METHOD("get_root_node"), &AnimationMixer::get_root_node);24082409ClassDB::bind_method(D_METHOD("set_callback_mode_process", "mode"), &AnimationMixer::set_callback_mode_process);2410ClassDB::bind_method(D_METHOD("get_callback_mode_process"), &AnimationMixer::get_callback_mode_process);24112412ClassDB::bind_method(D_METHOD("set_callback_mode_method", "mode"), &AnimationMixer::set_callback_mode_method);2413ClassDB::bind_method(D_METHOD("get_callback_mode_method"), &AnimationMixer::get_callback_mode_method);24142415ClassDB::bind_method(D_METHOD("set_callback_mode_discrete", "mode"), &AnimationMixer::set_callback_mode_discrete);2416ClassDB::bind_method(D_METHOD("get_callback_mode_discrete"), &AnimationMixer::get_callback_mode_discrete);24172418/* ---- Audio ---- */2419ClassDB::bind_method(D_METHOD("set_audio_max_polyphony", "max_polyphony"), &AnimationMixer::set_audio_max_polyphony);2420ClassDB::bind_method(D_METHOD("get_audio_max_polyphony"), &AnimationMixer::get_audio_max_polyphony);24212422/* ---- Root motion accumulator for Skeleton3D ---- */2423ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationMixer::set_root_motion_track);2424ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationMixer::get_root_motion_track);2425ClassDB::bind_method(D_METHOD("set_root_motion_local", "enabled"), &AnimationMixer::set_root_motion_local);2426ClassDB::bind_method(D_METHOD("is_root_motion_local"), &AnimationMixer::is_root_motion_local);24272428ClassDB::bind_method(D_METHOD("get_root_motion_position"), &AnimationMixer::get_root_motion_position);2429ClassDB::bind_method(D_METHOD("get_root_motion_rotation"), &AnimationMixer::get_root_motion_rotation);2430ClassDB::bind_method(D_METHOD("get_root_motion_scale"), &AnimationMixer::get_root_motion_scale);2431ClassDB::bind_method(D_METHOD("get_root_motion_position_accumulator"), &AnimationMixer::get_root_motion_position_accumulator);2432ClassDB::bind_method(D_METHOD("get_root_motion_rotation_accumulator"), &AnimationMixer::get_root_motion_rotation_accumulator);2433ClassDB::bind_method(D_METHOD("get_root_motion_scale_accumulator"), &AnimationMixer::get_root_motion_scale_accumulator);24342435/* ---- Blending processor ---- */2436ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationMixer::clear_caches);2437ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationMixer::advance);2438GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object_id", "object_sub_idx");24392440/* ---- Capture feature ---- */2441ClassDB::bind_method(D_METHOD("capture", "name", "duration", "trans_type", "ease_type"), &AnimationMixer::capture, DEFVAL(Tween::TRANS_LINEAR), DEFVAL(Tween::EASE_IN));24422443/* ---- Reset on save ---- */2444ClassDB::bind_method(D_METHOD("set_reset_on_save_enabled", "enabled"), &AnimationMixer::set_reset_on_save_enabled);2445ClassDB::bind_method(D_METHOD("is_reset_on_save_enabled"), &AnimationMixer::is_reset_on_save_enabled);24462447ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");2448ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deterministic"), "set_deterministic", "is_deterministic");2449ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset_on_save", PROPERTY_HINT_NONE, ""), "set_reset_on_save_enabled", "is_reset_on_save_enabled");2450ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root_node", "get_root_node");24512452ADD_GROUP("Root Motion", "root_motion_");2453ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track");2454ADD_PROPERTY(PropertyInfo(Variant::BOOL, "root_motion_local"), "set_root_motion_local", "is_root_motion_local");24552456ADD_GROUP("Audio", "audio_");2457ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_max_polyphony", PROPERTY_HINT_RANGE, "1,127,1"), "set_audio_max_polyphony", "get_audio_max_polyphony");24582459ADD_GROUP("Callback Mode", "callback_mode_");2460ADD_PROPERTY(PropertyInfo(Variant::INT, "callback_mode_process", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_callback_mode_process", "get_callback_mode_process");2461ADD_PROPERTY(PropertyInfo(Variant::INT, "callback_mode_method", PROPERTY_HINT_ENUM, "Deferred,Immediate"), "set_callback_mode_method", "get_callback_mode_method");2462ADD_PROPERTY(PropertyInfo(Variant::INT, "callback_mode_discrete", PROPERTY_HINT_ENUM, "Dominant,Recessive,Force Continuous"), "set_callback_mode_discrete", "get_callback_mode_discrete");24632464BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS);2465BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_PROCESS_IDLE);2466BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_PROCESS_MANUAL);24672468BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);2469BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_METHOD_IMMEDIATE);24702471BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT);2472BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE);2473BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS);24742475ADD_SIGNAL(MethodInfo(SNAME("animation_list_changed")));2476ADD_SIGNAL(MethodInfo(SNAME("animation_libraries_updated")));2477ADD_SIGNAL(MethodInfo(SNAME("animation_finished"), PropertyInfo(Variant::STRING_NAME, "anim_name")));2478ADD_SIGNAL(MethodInfo(SNAME("animation_started"), PropertyInfo(Variant::STRING_NAME, "anim_name")));2479ADD_SIGNAL(MethodInfo(SNAME("caches_cleared")));2480ADD_SIGNAL(MethodInfo(SNAME("mixer_applied")));2481ADD_SIGNAL(MethodInfo(SNAME("mixer_updated"))); // For updating dummy player.24822483ClassDB::bind_method(D_METHOD("_reset"), &AnimationMixer::reset);2484ClassDB::bind_method(D_METHOD("_restore", "backup"), &AnimationMixer::restore);2485}24862487AnimationMixer::AnimationMixer() {2488root_node = SceneStringName(path_pp);2489}24902491AnimationMixer::~AnimationMixer() {2492}24932494void AnimatedValuesBackup::set_data(const AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> p_data) {2495clear_data();24962497for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : p_data) {2498AnimationMixer::TrackCache *track = get_cache_copy(E.value);2499if (!track) {2500continue; // Some types of tracks do not get a copy and must be ignored.2501}25022503data.insert(E.key, track);2504}2505}25062507AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> AnimatedValuesBackup::get_data() const {2508AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> ret;2509for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : data) {2510AnimationMixer::TrackCache *track = get_cache_copy(E.value);2511ERR_CONTINUE(!track); // Backup shouldn't contain tracks that cannot be copied, this is a mistake.25122513ret.insert(E.key, track);2514}2515return ret;2516}25172518void AnimatedValuesBackup::clear_data() {2519for (KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &K : data) {2520memdelete(K.value);2521}2522data.clear();2523}25242525AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer::TrackCache *p_cache) const {2526switch (p_cache->type) {2527case Animation::TYPE_BEZIER:2528case Animation::TYPE_VALUE: {2529AnimationMixer::TrackCacheValue *src = static_cast<AnimationMixer::TrackCacheValue *>(p_cache);2530AnimationMixer::TrackCacheValue *tc = memnew(AnimationMixer::TrackCacheValue(*src));2531return tc;2532}25332534case Animation::TYPE_POSITION_3D:2535case Animation::TYPE_ROTATION_3D:2536case Animation::TYPE_SCALE_3D: {2537AnimationMixer::TrackCacheTransform *src = static_cast<AnimationMixer::TrackCacheTransform *>(p_cache);2538AnimationMixer::TrackCacheTransform *tc = memnew(AnimationMixer::TrackCacheTransform(*src));2539return tc;2540}25412542case Animation::TYPE_BLEND_SHAPE: {2543AnimationMixer::TrackCacheBlendShape *src = static_cast<AnimationMixer::TrackCacheBlendShape *>(p_cache);2544AnimationMixer::TrackCacheBlendShape *tc = memnew(AnimationMixer::TrackCacheBlendShape(*src));2545return tc;2546}25472548case Animation::TYPE_AUDIO: {2549AnimationMixer::TrackCacheAudio *src = static_cast<AnimationMixer::TrackCacheAudio *>(p_cache);2550AnimationMixer::TrackCacheAudio *tc = memnew(AnimationMixer::TrackCacheAudio(*src));2551return tc;2552}25532554case Animation::TYPE_METHOD:2555case Animation::TYPE_ANIMATION: {2556// Nothing to do here.2557} break;2558}2559return nullptr;2560}256125622563