Path: blob/master/scene/animation/animation_mixer.cpp
9896 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_stream.h"41#include "servers/audio_server.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.begins_with("libraries")) {72#else73if (name.begins_with("libraries")) {74#endif // DISABLE_DEPRECATED75Dictionary d = p_value;76while (animation_libraries.size()) {77remove_animation_library(animation_libraries[0].name);78}79for (const KeyValue<Variant, Variant> &kv : d) {80Ref<AnimationLibrary> lib = kv.value;81add_animation_library(kv.key, lib);82}83emit_signal(SNAME("animation_libraries_updated"));8485} else {86return false;87}8889return true;90}9192bool AnimationMixer::_get(const StringName &p_name, Variant &r_ret) const {93String name = p_name;9495if (name.begins_with("libraries")) {96Dictionary d;97for (const AnimationLibraryData &lib : animation_libraries) {98d[lib.name] = lib.library;99}100r_ret = d;101} else {102return false;103}104105return true;106}107108void AnimationMixer::_get_property_list(List<PropertyInfo> *p_list) const {109p_list->push_back(PropertyInfo(Variant::DICTIONARY, PNAME("libraries"), PROPERTY_HINT_DICTIONARY_TYPE, "StringName;AnimationLibrary"));110}111112void AnimationMixer::_validate_property(PropertyInfo &p_property) const {113#ifdef TOOLS_ENABLED // `editing` is surrounded by TOOLS_ENABLED so this should also be.114if (Engine::get_singleton()->is_editor_hint() && editing && (p_property.name == "active" || p_property.name == "deterministic" || p_property.name == "root_motion_track")) {115p_property.usage |= PROPERTY_USAGE_READ_ONLY;116}117#endif // TOOLS_ENABLED118if (root_motion_track.is_empty() && p_property.name == "root_motion_local") {119p_property.usage = PROPERTY_USAGE_NONE;120}121}122123/* -------------------------------------------- */124/* -- Data lists ------------------------------ */125/* -------------------------------------------- */126127void AnimationMixer::_animation_set_cache_update() {128// Relatively fast function to update all animations.129animation_set_update_pass++;130bool clear_cache_needed = false;131132// Update changed and add otherwise.133for (const AnimationLibraryData &lib : animation_libraries) {134for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) {135StringName key = lib.name == StringName() ? K.key : StringName(String(lib.name) + "/" + String(K.key));136if (!animation_set.has(key)) {137AnimationData ad;138ad.animation = K.value;139ad.animation_library = lib.name;140ad.name = key;141ad.last_update = animation_set_update_pass;142animation_set.insert(ad.name, ad);143cache_valid = false; // No need to delete the cache, but it must be updated to add track caches.144} else {145AnimationData &ad = animation_set[key];146if (ad.last_update != animation_set_update_pass) {147// Was not updated, update. If the animation is duplicated, the second one will be ignored.148if (ad.animation != K.value || ad.animation_library != lib.name) {149// Animation changed, update and clear caches.150clear_cache_needed = true;151ad.animation = K.value;152ad.animation_library = lib.name;153}154155ad.last_update = animation_set_update_pass;156}157}158}159}160161// Check removed.162List<StringName> to_erase;163for (const KeyValue<StringName, AnimationData> &E : animation_set) {164if (E.value.last_update != animation_set_update_pass) {165// Was not updated, must be erased.166to_erase.push_back(E.key);167clear_cache_needed = true;168}169}170171while (to_erase.size()) {172animation_set.erase(to_erase.front()->get());173to_erase.pop_front();174}175176if (clear_cache_needed) {177// If something was modified or removed, caches need to be cleared.178_clear_caches();179}180181emit_signal(SNAME("animation_list_changed"));182}183184void AnimationMixer::_animation_added(const StringName &p_name, const StringName &p_library) {185_animation_set_cache_update();186}187188void AnimationMixer::_animation_removed(const StringName &p_name, const StringName &p_library) {189StringName name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));190191if (!animation_set.has(name)) {192return; // No need to update because not the one from the library being used.193}194195_animation_set_cache_update();196197_remove_animation(name);198}199200void AnimationMixer::_animation_renamed(const StringName &p_name, const StringName &p_to_name, const StringName &p_library) {201StringName from_name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));202StringName to_name = p_library == StringName() ? p_to_name : StringName(String(p_library) + "/" + String(p_to_name));203204if (!animation_set.has(from_name)) {205return; // No need to update because not the one from the library being used.206}207_animation_set_cache_update();208209_rename_animation(from_name, to_name);210}211212void AnimationMixer::_animation_changed(const StringName &p_name) {213_clear_caches();214}215216void AnimationMixer::_set_active(bool p_active) {217//218}219220void AnimationMixer::_remove_animation(const StringName &p_name) {221//222}223224void AnimationMixer::_rename_animation(const StringName &p_from_name, const StringName &p_to_name) {225//226}227228TypedArray<StringName> AnimationMixer::_get_animation_library_list() const {229TypedArray<StringName> ret;230for (const AnimationLibraryData &lib : animation_libraries) {231ret.push_back(lib.name);232}233return ret;234}235236void AnimationMixer::get_animation_library_list(List<StringName> *p_libraries) const {237for (const AnimationLibraryData &lib : animation_libraries) {238p_libraries->push_back(lib.name);239}240}241242Ref<AnimationLibrary> AnimationMixer::get_animation_library(const StringName &p_name) const {243for (const AnimationLibraryData &lib : animation_libraries) {244if (lib.name == p_name) {245return lib.library;246}247}248ERR_FAIL_V(Ref<AnimationLibrary>());249}250251bool AnimationMixer::has_animation_library(const StringName &p_name) const {252for (const AnimationLibraryData &lib : animation_libraries) {253if (lib.name == p_name) {254return true;255}256}257258return false;259}260261StringName AnimationMixer::get_animation_library_name(const Ref<AnimationLibrary> &p_animation_library) const {262ERR_FAIL_COND_V(p_animation_library.is_null(), StringName());263for (const AnimationLibraryData &lib : animation_libraries) {264if (lib.library == p_animation_library) {265return lib.name;266}267}268return StringName();269}270271StringName AnimationMixer::find_animation_library(const Ref<Animation> &p_animation) const {272for (const KeyValue<StringName, AnimationData> &E : animation_set) {273if (E.value.animation == p_animation) {274return E.value.animation_library;275}276}277return StringName();278}279280Error AnimationMixer::add_animation_library(const StringName &p_name, const Ref<AnimationLibrary> &p_animation_library) {281ERR_FAIL_COND_V(p_animation_library.is_null(), ERR_INVALID_PARAMETER);282#ifdef DEBUG_ENABLED283ERR_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) + ".");284#endif285286int insert_pos = 0;287288for (const AnimationLibraryData &lib : animation_libraries) {289ERR_FAIL_COND_V_MSG(lib.name == p_name, ERR_ALREADY_EXISTS, "Can't add animation library twice with name: " + String(p_name));290ERR_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() + "'.");291292if (lib.name.operator String() >= p_name.operator String()) {293break;294}295296insert_pos++;297}298299AnimationLibraryData ald;300ald.name = p_name;301ald.library = p_animation_library;302303animation_libraries.insert(insert_pos, ald);304305ald.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added).bind(p_name));306ald.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed).bind(p_name));307ald.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed).bind(p_name));308ald.library->connect(SceneStringName(animation_changed), callable_mp(this, &AnimationMixer::_animation_changed));309310_animation_set_cache_update();311312notify_property_list_changed();313314return OK;315}316317void AnimationMixer::remove_animation_library(const StringName &p_name) {318int at_pos = -1;319320for (uint32_t i = 0; i < animation_libraries.size(); i++) {321if (animation_libraries[i].name == p_name) {322at_pos = i;323break;324}325}326327ERR_FAIL_COND(at_pos == -1);328329animation_libraries[at_pos].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added));330animation_libraries[at_pos].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed));331animation_libraries[at_pos].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed));332animation_libraries[at_pos].library->disconnect(SceneStringName(animation_changed), callable_mp(this, &AnimationMixer::_animation_changed));333334animation_libraries.remove_at(at_pos);335_animation_set_cache_update();336337notify_property_list_changed();338}339340void AnimationMixer::rename_animation_library(const StringName &p_name, const StringName &p_new_name) {341if (p_name == p_new_name) {342return;343}344#ifdef DEBUG_ENABLED345ERR_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) + ".");346#endif347348bool found = false;349for (AnimationLibraryData &lib : animation_libraries) {350ERR_FAIL_COND_MSG(lib.name == p_new_name, "Can't rename animation library to another existing name: " + String(p_new_name) + ".");351if (lib.name == p_name) {352found = true;353lib.name = p_new_name;354// rename connections355lib.library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added));356lib.library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed));357lib.library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed));358359lib.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added).bind(p_new_name));360lib.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed).bind(p_new_name));361lib.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed).bind(p_new_name));362363for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) {364StringName old_name = p_name == StringName() ? K.key : StringName(String(p_name) + "/" + String(K.key));365StringName new_name = p_new_name == StringName() ? K.key : StringName(String(p_new_name) + "/" + String(K.key));366_rename_animation(old_name, new_name);367}368}369}370371ERR_FAIL_COND(!found);372373animation_libraries.sort(); // Must keep alphabetical order.374375_animation_set_cache_update(); // Update cache.376377notify_property_list_changed();378}379380void AnimationMixer::get_animation_list(List<StringName> *p_animations) const {381List<String> anims;382for (const KeyValue<StringName, AnimationData> &E : animation_set) {383anims.push_back(E.key);384}385anims.sort();386for (const String &E : anims) {387p_animations->push_back(E);388}389}390391Ref<Animation> AnimationMixer::get_animation(const StringName &p_name) const {392ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref<Animation>(), vformat("Animation not found: \"%s\".", p_name));393const AnimationData &anim_data = animation_set[p_name];394return anim_data.animation;395}396397bool AnimationMixer::has_animation(const StringName &p_name) const {398return animation_set.has(p_name);399}400401StringName AnimationMixer::find_animation(const Ref<Animation> &p_animation) const {402for (const KeyValue<StringName, AnimationData> &E : animation_set) {403if (E.value.animation == p_animation) {404return E.key;405}406}407return StringName();408}409410/* -------------------------------------------- */411/* -- General settings for animation ---------- */412/* -------------------------------------------- */413414void AnimationMixer::_set_process(bool p_process, bool p_force) {415if (processing == p_process && !p_force) {416return;417}418419switch (callback_mode_process) {420case ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS:421#ifdef TOOLS_ENABLED422set_physics_process_internal(p_process && active && !editing);423#else424set_physics_process_internal(p_process && active);425#endif // TOOLS_ENABLED426break;427case ANIMATION_CALLBACK_MODE_PROCESS_IDLE:428#ifdef TOOLS_ENABLED429set_process_internal(p_process && active && !editing);430#else431set_process_internal(p_process && active);432#endif // TOOLS_ENABLED433break;434case ANIMATION_CALLBACK_MODE_PROCESS_MANUAL:435break;436}437438processing = p_process;439}440441void AnimationMixer::set_active(bool p_active) {442if (active == p_active) {443return;444}445446active = p_active;447_set_active(active);448_set_process(processing, true);449450if (!active && is_inside_tree()) {451_clear_caches();452}453}454455bool AnimationMixer::is_active() const {456return active;457}458459void AnimationMixer::set_root_node(const NodePath &p_path) {460root_node = p_path;461_clear_caches();462}463464NodePath AnimationMixer::get_root_node() const {465return root_node;466}467468void AnimationMixer::set_deterministic(bool p_deterministic) {469deterministic = p_deterministic;470_clear_caches();471}472473bool AnimationMixer::is_deterministic() const {474return deterministic;475}476477void AnimationMixer::set_callback_mode_process(AnimationCallbackModeProcess p_mode) {478if (callback_mode_process == p_mode) {479return;480}481482bool was_active = is_active();483if (was_active) {484set_active(false);485}486487callback_mode_process = p_mode;488489if (was_active) {490set_active(true);491}492}493494AnimationMixer::AnimationCallbackModeProcess AnimationMixer::get_callback_mode_process() const {495return callback_mode_process;496}497498void AnimationMixer::set_callback_mode_method(AnimationCallbackModeMethod p_mode) {499callback_mode_method = p_mode;500emit_signal(SNAME("mixer_updated"));501}502503AnimationMixer::AnimationCallbackModeMethod AnimationMixer::get_callback_mode_method() const {504return callback_mode_method;505}506507void AnimationMixer::set_callback_mode_discrete(AnimationCallbackModeDiscrete p_mode) {508callback_mode_discrete = p_mode;509_clear_caches();510emit_signal(SNAME("mixer_updated"));511}512513AnimationMixer::AnimationCallbackModeDiscrete AnimationMixer::get_callback_mode_discrete() const {514return callback_mode_discrete;515}516517void AnimationMixer::set_audio_max_polyphony(int p_audio_max_polyphony) {518ERR_FAIL_COND(p_audio_max_polyphony < 0 || p_audio_max_polyphony > 128);519audio_max_polyphony = p_audio_max_polyphony;520}521522int AnimationMixer::get_audio_max_polyphony() const {523return audio_max_polyphony;524}525526#ifdef TOOLS_ENABLED527void AnimationMixer::set_editing(bool p_editing) {528if (editing == p_editing) {529return;530}531532editing = p_editing;533_set_process(processing, true);534535if (editing && is_inside_tree()) {536_clear_caches();537}538539notify_property_list_changed(); // To make active readonly.540}541542bool AnimationMixer::is_editing() const {543return editing;544}545546void AnimationMixer::set_dummy(bool p_dummy) {547dummy = p_dummy;548}549550bool AnimationMixer::is_dummy() const {551return dummy;552}553#endif // TOOLS_ENABLED554555/* -------------------------------------------- */556/* -- Caches for blending --------------------- */557/* -------------------------------------------- */558559void AnimationMixer::_clear_caches() {560_init_root_motion_cache();561_clear_audio_streams();562_clear_playing_caches();563for (KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {564memdelete(K.value);565}566track_cache.clear();567animation_track_num_to_track_cache.clear();568cache_valid = false;569capture_cache.clear();570571emit_signal(SNAME("caches_cleared"));572}573574void AnimationMixer::_clear_audio_streams() {575for (int i = 0; i < playing_audio_stream_players.size(); i++) {576playing_audio_stream_players[i]->call(SNAME("stop"));577playing_audio_stream_players[i]->call(SNAME("set_stream"), Ref<AudioStream>());578}579playing_audio_stream_players.clear();580}581582void AnimationMixer::_clear_playing_caches() {583for (const TrackCache *E : playing_caches) {584Object *t_obj = ObjectDB::get_instance(E->object_id);585if (t_obj) {586t_obj->call(SNAME("stop"), true);587}588}589playing_caches.clear();590}591592void AnimationMixer::_init_root_motion_cache() {593root_motion_cache.loc = Vector3(0, 0, 0);594root_motion_cache.rot = Quaternion(0, 0, 0, 1);595root_motion_cache.scale = Vector3(1, 1, 1);596root_motion_position = Vector3(0, 0, 0);597root_motion_rotation = Quaternion(0, 0, 0, 1);598root_motion_scale = Vector3(0, 0, 0);599root_motion_position_accumulator = Vector3(0, 0, 0);600root_motion_rotation_accumulator = Quaternion(0, 0, 0, 1);601root_motion_scale_accumulator = Vector3(1, 1, 1);602}603604void AnimationMixer::_create_track_num_to_track_cache_for_animation(Ref<Animation> &p_animation) {605if (animation_track_num_to_track_cache.has(p_animation)) {606// In AnimationMixer::_update_caches, it retrieves all animations via AnimationMixer::get_animation_list607// Since multiple AnimationLibraries can share the same Animation, it is possible that the cache is already created.608return;609}610LocalVector<TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache.insert_new(p_animation, LocalVector<TrackCache *>())->value;611const Vector<Animation::Track *> &tracks = p_animation->get_tracks();612613track_num_to_track_cache.resize(tracks.size());614for (int i = 0; i < tracks.size(); i++) {615TrackCache **track_ptr = track_cache.getptr(tracks[i]->thash);616if (track_ptr == nullptr) {617track_num_to_track_cache[i] = nullptr;618} else {619track_num_to_track_cache[i] = *track_ptr;620}621}622}623624bool AnimationMixer::_update_caches() {625setup_pass++;626627root_motion_cache.loc = Vector3(0, 0, 0);628root_motion_cache.rot = Quaternion(0, 0, 0, 1);629root_motion_cache.scale = Vector3(1, 1, 1);630631List<StringName> sname_list;632get_animation_list(&sname_list);633634bool check_path = GLOBAL_GET_CACHED(bool, "animation/warnings/check_invalid_track_paths");635bool check_angle_interpolation = GLOBAL_GET_CACHED(bool, "animation/warnings/check_angle_interpolation_type_conflicting");636637Node *parent = get_node_or_null(root_node);638if (!parent) {639cache_valid = false;640return false;641}642643#ifdef TOOLS_ENABLED644String mixer_name = "AnimationMixer";645const Node *owner = get_owner();646if (owner) {647const String scene_path = owner->get_scene_file_path();648if (!scene_path.is_empty()) {649mixer_name += vformat(" (at: %s)", scene_path.get_file());650}651}652#else653const String mixer_name = "AnimationMixer";654#endif655656Ref<Animation> reset_anim;657bool has_reset_anim = has_animation(SceneStringName(RESET));658if (has_reset_anim) {659reset_anim = get_animation(SceneStringName(RESET));660}661for (const StringName &E : sname_list) {662Ref<Animation> anim = get_animation(E);663for (int i = 0; i < anim->get_track_count(); i++) {664NodePath path = anim->track_get_path(i);665Animation::TypeHash thash = anim->track_get_type_hash(i);666Animation::TrackType track_src_type = anim->track_get_type(i);667Animation::TrackType track_cache_type = Animation::get_cache_type(track_src_type);668669TrackCache *track = nullptr;670if (track_cache.has(thash)) {671track = track_cache.get(thash);672}673674// If not valid, delete track.675if (track && (track->type != track_cache_type || ObjectDB::get_instance(track->object_id) == nullptr)) {676playing_caches.erase(track);677memdelete(track);678track_cache.erase(thash);679track = nullptr;680}681682if (!track) {683Ref<Resource> resource;684Vector<StringName> leftover_path;685686Node *child = parent->get_node_and_resource(path, resource, leftover_path);687if (!child) {688if (check_path) {689WARN_PRINT_ED(mixer_name + ": '" + String(E) + "', couldn't resolve track: '" + String(path) + "'. This warning can be disabled in Project Settings.");690}691continue;692}693694switch (track_src_type) {695case Animation::TYPE_BEZIER:696case Animation::TYPE_VALUE: {697// If a value track without a key is cached first, the initial value cannot be determined.698// It is a corner case, but which may cause problems with blending.699ERR_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.");700701TrackCacheValue *track_value = memnew(TrackCacheValue);702703if (resource.is_valid()) {704track_value->object_id = resource->get_instance_id();705} else {706track_value->object_id = child->get_instance_id();707}708709track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;710711track_value->subpath = leftover_path;712713track = track_value;714715bool is_value = track_src_type == Animation::TYPE_VALUE;716717track_value->init_value = is_value ? anim->track_get_key_value(i, 0) : (anim->track_get_key_value(i, 0).operator Array())[0];718track_value->init_value.zero();719720track_value->is_init = false;721722// Can't interpolate them, need to convert.723track_value->is_variant_interpolatable = Animation::is_variant_interpolatable(track_value->init_value);724725// If there is a Reset Animation, it takes precedence by overwriting.726if (has_reset_anim) {727int rt = reset_anim->find_track(path, track_src_type);728if (rt >= 0) {729if (is_value) {730if (reset_anim->track_get_key_count(rt) > 0) {731track_value->init_value = reset_anim->track_get_key_value(rt, 0);732}733} else {734if (reset_anim->track_get_key_count(rt) > 0) {735track_value->init_value = (reset_anim->track_get_key_value(rt, 0).operator Array())[0];736}737}738}739}740741if (is_value && callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {742if (child) {743PropertyInfo prop_info;744ClassDB::get_property_info(child->get_class_name(), path.get_concatenated_subnames(), &prop_info);745if (prop_info.hint == PROPERTY_HINT_ONESHOT) {746WARN_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)));747}748}749}750} break;751case Animation::TYPE_POSITION_3D:752case Animation::TYPE_ROTATION_3D:753case Animation::TYPE_SCALE_3D: {754#ifndef _3D_DISABLED755Node3D *node_3d = Object::cast_to<Node3D>(child);756757if (!node_3d) {758ERR_PRINT(mixer_name + ": '" + String(E) + "', transform track does not point to Node3D: '" + String(path) + "'.");759continue;760}761762TrackCacheTransform *track_xform = memnew(TrackCacheTransform);763track_xform->type = Animation::TYPE_POSITION_3D;764765track_xform->bone_idx = -1;766767bool has_rest = false;768Skeleton3D *sk = Object::cast_to<Skeleton3D>(node_3d);769if (sk && path.get_subname_count() == 1) {770track_xform->skeleton_id = sk->get_instance_id();771int bone_idx = sk->find_bone(path.get_subname(0));772if (bone_idx != -1) {773has_rest = true;774track_xform->bone_idx = bone_idx;775Transform3D rest = sk->get_bone_rest(bone_idx);776track_xform->init_loc = rest.origin;777track_xform->init_rot = rest.basis.get_rotation_quaternion();778track_xform->init_scale = rest.basis.get_scale();779}780}781782track_xform->object_id = node_3d->get_instance_id();783784track = track_xform;785786switch (track_src_type) {787case Animation::TYPE_POSITION_3D: {788track_xform->loc_used = true;789} break;790case Animation::TYPE_ROTATION_3D: {791track_xform->rot_used = true;792} break;793case Animation::TYPE_SCALE_3D: {794track_xform->scale_used = true;795} break;796default: {797}798}799800// For non Skeleton3D bone animation.801if (has_reset_anim && !has_rest) {802int rt = reset_anim->find_track(path, track_src_type);803if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {804switch (track_src_type) {805case Animation::TYPE_POSITION_3D: {806track_xform->init_loc = reset_anim->track_get_key_value(rt, 0);807} break;808case Animation::TYPE_ROTATION_3D: {809track_xform->init_rot = reset_anim->track_get_key_value(rt, 0);810} break;811case Animation::TYPE_SCALE_3D: {812track_xform->init_scale = reset_anim->track_get_key_value(rt, 0);813} break;814default: {815}816}817}818}819#endif // _3D_DISABLED820} break;821case Animation::TYPE_BLEND_SHAPE: {822#ifndef _3D_DISABLED823if (path.get_subname_count() != 1) {824ERR_PRINT(mixer_name + ": '" + String(E) + "', blend shape track does not contain a blend shape subname: '" + String(path) + "'.");825continue;826}827MeshInstance3D *mesh_3d = Object::cast_to<MeshInstance3D>(child);828829if (!mesh_3d) {830ERR_PRINT(mixer_name + ": '" + String(E) + "', blend shape track does not point to MeshInstance3D: '" + String(path) + "'.");831continue;832}833834StringName blend_shape_name = path.get_subname(0);835int blend_shape_idx = mesh_3d->find_blend_shape_by_name(blend_shape_name);836if (blend_shape_idx == -1) {837ERR_PRINT(mixer_name + ": '" + String(E) + "', blend shape track points to a non-existing name: '" + String(blend_shape_name) + "'.");838continue;839}840841TrackCacheBlendShape *track_bshape = memnew(TrackCacheBlendShape);842843track_bshape->shape_index = blend_shape_idx;844track_bshape->object_id = mesh_3d->get_instance_id();845track = track_bshape;846847if (has_reset_anim) {848int rt = reset_anim->find_track(path, track_src_type);849if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {850track_bshape->init_value = reset_anim->track_get_key_value(rt, 0);851}852}853#endif854} break;855case Animation::TYPE_METHOD: {856TrackCacheMethod *track_method = memnew(TrackCacheMethod);857858if (resource.is_valid()) {859track_method->object_id = resource->get_instance_id();860} else {861track_method->object_id = child->get_instance_id();862}863864track = track_method;865866} break;867case Animation::TYPE_AUDIO: {868TrackCacheAudio *track_audio = memnew(TrackCacheAudio);869870track_audio->object_id = child->get_instance_id();871track_audio->audio_stream.instantiate();872track_audio->audio_stream->set_polyphony(audio_max_polyphony);873track_audio->playback_type = (AudioServer::PlaybackType)(int)(child->call(SNAME("get_playback_type")));874track_audio->bus = (StringName)(child->call(SNAME("get_bus")));875876track = track_audio;877878} break;879case Animation::TYPE_ANIMATION: {880TrackCacheAnimation *track_animation = memnew(TrackCacheAnimation);881882track_animation->object_id = child->get_instance_id();883884track = track_animation;885886} break;887default: {888ERR_PRINT("Animation corrupted (invalid track type).");889continue;890}891}892track->path = path;893track_cache[thash] = track;894} else if (track_cache_type == Animation::TYPE_POSITION_3D) {895TrackCacheTransform *track_xform = static_cast<TrackCacheTransform *>(track);896if (track->setup_pass != setup_pass) {897track_xform->loc_used = false;898track_xform->rot_used = false;899track_xform->scale_used = false;900}901switch (track_src_type) {902case Animation::TYPE_POSITION_3D: {903track_xform->loc_used = true;904} break;905case Animation::TYPE_ROTATION_3D: {906track_xform->rot_used = true;907} break;908case Animation::TYPE_SCALE_3D: {909track_xform->scale_used = true;910} break;911default: {912}913}914} else if (track_cache_type == Animation::TYPE_VALUE) {915TrackCacheValue *track_value = static_cast<TrackCacheValue *>(track);916// If it has at least one angle interpolation, it also uses angle interpolation for blending.917bool was_using_angle = track_value->is_using_angle;918if (track_src_type == Animation::TYPE_VALUE) {919if (track_value->init_value.is_string() && anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE) {920WARN_PRINT_ONCE_ED(mixer_name + ": '" + String(E) + "', Value Track: '" + String(path) + "' blends String types. This is an experimental algorithm.");921}922track_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;923}924if (check_angle_interpolation && (was_using_angle != track_value->is_using_angle)) {925WARN_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.");926}927}928929track->setup_pass = setup_pass;930}931}932933List<Animation::TypeHash> to_delete;934935for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {936if (K.value->setup_pass != setup_pass) {937to_delete.push_back(K.key);938}939}940941while (to_delete.front()) {942Animation::TypeHash thash = to_delete.front()->get();943memdelete(track_cache[thash]);944track_cache.erase(thash);945to_delete.pop_front();946}947948track_map.clear();949950int idx = 0;951for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {952track_map[K.value->path] = idx;953idx++;954}955956for (KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {957K.value->blend_idx = track_map[K.value->path];958}959960animation_track_num_to_track_cache.clear();961for (const StringName &E : sname_list) {962Ref<Animation> anim = get_animation(E);963_create_track_num_to_track_cache_for_animation(anim);964}965966track_count = idx;967968cache_valid = true;969970return true;971}972973/* -------------------------------------------- */974/* -- Blending processor ---------------------- */975/* -------------------------------------------- */976977void AnimationMixer::_process_animation(double p_delta, bool p_update_only) {978_blend_init();979if (_blend_pre_process(p_delta, track_count, track_map)) {980_blend_capture(p_delta);981_blend_calc_total_weight();982_blend_process(p_delta, p_update_only);983_blend_apply();984_blend_post_process();985emit_signal(SNAME("mixer_applied"));986};987clear_animation_instances();988}989990Variant 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) {991#ifndef _3D_DISABLED992switch (p_anim->track_get_type(p_track)) {993case Animation::TYPE_POSITION_3D: {994if (p_object_sub_idx >= 0) {995Skeleton3D *skel = ObjectDB::get_instance<Skeleton3D>(p_object_id);996if (skel) {997return Vector3(p_value) * skel->get_motion_scale();998}999}1000return p_value;1001} break;1002default: {1003} break;1004}1005#endif // _3D_DISABLED1006return p_value;1007}10081009Variant 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) {1010if (is_GDVIRTUAL_CALL_post_process_key_value) {1011Variant res;1012if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, p_object_id, p_object_sub_idx, res)) {1013return res;1014}1015is_GDVIRTUAL_CALL_post_process_key_value = false;1016}1017return _post_process_key_value(p_anim, p_track, p_value, p_object_id, p_object_sub_idx);1018}10191020void AnimationMixer::_blend_init() {1021// Check all tracks, see if they need modification.1022root_motion_position = Vector3(0, 0, 0);1023root_motion_rotation = Quaternion(0, 0, 0, 1);1024root_motion_scale = Vector3(0, 0, 0);1025root_motion_position_accumulator = Vector3(0, 0, 0);1026root_motion_rotation_accumulator = Quaternion(0, 0, 0, 1);1027root_motion_scale_accumulator = Vector3(1, 1, 1);10281029if (!cache_valid) {1030if (!_update_caches()) {1031return;1032}1033}10341035// Init all value/transform/blend/bezier tracks that track_cache has.1036for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {1037TrackCache *track = K.value;10381039track->total_weight = 0.0;10401041switch (track->type) {1042case Animation::TYPE_POSITION_3D: {1043TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1044if (track->root_motion) {1045root_motion_cache.loc = Vector3(0, 0, 0);1046root_motion_cache.rot = Quaternion(0, 0, 0, 1);1047root_motion_cache.scale = Vector3(1, 1, 1);1048}1049t->loc = t->init_loc;1050t->rot = t->init_rot;1051t->scale = t->init_scale;1052} break;1053case Animation::TYPE_BLEND_SHAPE: {1054TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);1055t->value = t->init_value;1056} break;1057case Animation::TYPE_VALUE: {1058TrackCacheValue *t = static_cast<TrackCacheValue *>(track);1059t->value = Animation::cast_to_blendwise(t->init_value);1060t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0;1061t->use_continuous = false;1062t->use_discrete = false;1063} break;1064case Animation::TYPE_AUDIO: {1065TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);1066for (KeyValue<ObjectID, PlayingAudioTrackInfo> &L : t->playing_streams) {1067PlayingAudioTrackInfo &track_info = L.value;1068track_info.volume = 0.0;1069}1070} break;1071default: {1072} break;1073}1074}1075}10761077bool AnimationMixer::_blend_pre_process(double p_delta, int p_track_count, const AHashMap<NodePath, int> &p_track_map) {1078return true;1079}10801081void AnimationMixer::_blend_post_process() {1082//1083}10841085void AnimationMixer::_blend_capture(double p_delta) {1086blend_capture(p_delta);1087}10881089void AnimationMixer::blend_capture(double p_delta) {1090if (capture_cache.animation.is_null()) {1091return;1092}10931094capture_cache.remain -= p_delta * capture_cache.step;1095if (Animation::is_less_or_equal_approx(capture_cache.remain, 0)) {1096if (capture_cache.animation.is_valid()) {1097animation_track_num_to_track_cache.erase(capture_cache.animation);1098}1099capture_cache.clear();1100return;1101}11021103real_t weight = Tween::run_equation(capture_cache.trans_type, capture_cache.ease_type, capture_cache.remain, 0.0, 1.0, 1.0);11041105// Blend with other animations.1106real_t inv = 1.0 - weight;1107for (AnimationInstance &ai : animation_instances) {1108ai.playback_info.weight *= inv;1109}11101111// Build capture animation instance.1112AnimationData ad;1113ad.animation = capture_cache.animation;11141115PlaybackInfo pi;1116pi.weight = weight;11171118AnimationInstance ai;1119ai.animation_data = ad;1120ai.playback_info = pi;11211122animation_instances.push_back(ai);1123}11241125void AnimationMixer::_blend_calc_total_weight() {1126for (const AnimationInstance &ai : animation_instances) {1127Ref<Animation> a = ai.animation_data.animation;1128real_t weight = ai.playback_info.weight;1129const real_t *track_weights_ptr = ai.playback_info.track_weights.ptr();1130int track_weights_count = ai.playback_info.track_weights.size();1131ERR_CONTINUE_EDMSG(!animation_track_num_to_track_cache.has(a), "No animation in cache.");1132LocalVector<TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache[a];1133thread_local HashSet<Animation::TypeHash, HashHasher> processed_hashes;1134processed_hashes.clear();1135const Vector<Animation::Track *> tracks = a->get_tracks();1136Animation::Track *const *tracks_ptr = tracks.ptr();1137int count = tracks.size();1138for (int i = 0; i < count; i++) {1139Animation::Track *animation_track = tracks_ptr[i];1140if (!animation_track->enabled) {1141continue;1142}1143Animation::TypeHash thash = animation_track->thash;1144TrackCache *track = track_num_to_track_cache[i];1145if (track == nullptr || processed_hashes.has(thash)) {1146// No path, but avoid error spamming.1147// Or, there is the case different track type with same path; These can be distinguished by hash. So don't add the weight doubly.1148continue;1149}1150int blend_idx = track->blend_idx;1151ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);1152real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;1153track->total_weight += blend;1154processed_hashes.insert(thash);1155}1156}1157}11581159void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {1160// Apply value/transform/blend/bezier blends to track caches and execute method/audio/animation tracks.1161#ifdef TOOLS_ENABLED1162bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint();1163#endif // TOOLS_ENABLED1164for (const AnimationInstance &ai : animation_instances) {1165Ref<Animation> a = ai.animation_data.animation;1166double time = ai.playback_info.time;1167double delta = ai.playback_info.delta;1168double start = ai.playback_info.start;1169double end = ai.playback_info.end;1170bool seeked = ai.playback_info.seeked;1171Animation::LoopedFlag looped_flag = ai.playback_info.looped_flag;1172bool is_external_seeking = ai.playback_info.is_external_seeking;1173real_t weight = ai.playback_info.weight;1174const real_t *track_weights_ptr = ai.playback_info.track_weights.ptr();1175int track_weights_count = ai.playback_info.track_weights.size();1176bool backward = std::signbit(delta); // This flag is used by the root motion calculates or detecting the end of audio stream.1177bool seeked_backward = std::signbit(p_delta);1178#ifndef _3D_DISABLED1179bool calc_root = !seeked || is_external_seeking;1180#endif // _3D_DISABLED1181ERR_CONTINUE_EDMSG(!animation_track_num_to_track_cache.has(a), "No animation in cache.");1182LocalVector<TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache[a];1183const Vector<Animation::Track *> tracks = a->get_tracks();1184Animation::Track *const *tracks_ptr = tracks.ptr();1185real_t a_length = a->get_length();1186int count = tracks.size();1187for (int i = 0; i < count; i++) {1188const Animation::Track *animation_track = tracks_ptr[i];1189if (!animation_track->enabled) {1190continue;1191}1192TrackCache *track = track_num_to_track_cache[i];1193if (track == nullptr) {1194continue; // No path, but avoid error spamming.1195}1196int blend_idx = track->blend_idx;1197ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);1198real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;1199if (!deterministic) {1200// If non-deterministic, do normalization.1201// It would be better to make this if statement outside the for loop, but come here since too much code...1202if (Math::is_zero_approx(track->total_weight)) {1203continue;1204}1205blend = blend / track->total_weight;1206}1207Animation::TrackType ttype = animation_track->type;1208track->root_motion = root_motion_track == animation_track->path;1209switch (ttype) {1210case Animation::TYPE_POSITION_3D: {1211#ifndef _3D_DISABLED1212if (Math::is_zero_approx(blend)) {1213continue; // Nothing to blend.1214}1215TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1216if (track->root_motion && calc_root) {1217int rot_track = -1;1218if (root_motion_local) {1219rot_track = a->find_track(a->track_get_path(i), Animation::TYPE_ROTATION_3D);1220}1221double prev_time = time - delta;1222if (!backward) {1223if (Animation::is_less_approx(prev_time, start)) {1224switch (a->get_loop_mode()) {1225case Animation::LOOP_NONE: {1226prev_time = start;1227} break;1228case Animation::LOOP_LINEAR: {1229prev_time = Math::fposmod(prev_time - start, end - start) + start;1230} break;1231case Animation::LOOP_PINGPONG: {1232prev_time = Math::pingpong(prev_time - start, end - start) + start;1233} break;1234default:1235break;1236}1237}1238} else {1239if (Animation::is_greater_approx(prev_time, end)) {1240switch (a->get_loop_mode()) {1241case Animation::LOOP_NONE: {1242prev_time = end;1243} break;1244case Animation::LOOP_LINEAR: {1245prev_time = Math::fposmod(prev_time - start, end - start) + start;1246} break;1247case Animation::LOOP_PINGPONG: {1248prev_time = Math::pingpong(prev_time - start, end - start) + start;1249} break;1250default:1251break;1252}1253}1254}1255if (rot_track >= 0) {1256Vector3 loc[2];1257Quaternion rot;1258if (!backward) {1259if (Animation::is_greater_approx(prev_time, time)) {1260Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1261if (err != OK) {1262continue;1263}1264loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1265a->try_position_track_interpolate(i, end, &loc[1]);1266loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);12671268a->try_rotation_track_interpolate(rot_track, end, &rot);1269rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);12701271root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;1272prev_time = start;1273}1274} else {1275if (Animation::is_less_approx(prev_time, time)) {1276Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1277if (err != OK) {1278continue;1279}1280loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1281a->try_position_track_interpolate(i, start, &loc[1]);1282loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);12831284a->try_rotation_track_interpolate(rot_track, start, &rot);1285rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);12861287root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;1288prev_time = end;1289}1290}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, time, &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, time, &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 = !backward ? start : end;1304} else {1305Vector3 loc[2];1306if (!backward) {1307if (Animation::is_greater_approx(prev_time, time)) {1308Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1309if (err != OK) {1310continue;1311}1312loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1313a->try_position_track_interpolate(i, end, &loc[1]);1314loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);1315root_motion_cache.loc += (loc[1] - loc[0]) * blend;1316prev_time = start;1317}1318} else {1319if (Animation::is_less_approx(prev_time, time)) {1320Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1321if (err != OK) {1322continue;1323}1324loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1325a->try_position_track_interpolate(i, start, &loc[1]);1326loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);1327root_motion_cache.loc += (loc[1] - loc[0]) * blend;1328prev_time = end;1329}1330}1331Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1332if (err != OK) {1333continue;1334}1335loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1336a->try_position_track_interpolate(i, time, &loc[1]);1337loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);1338root_motion_cache.loc += (loc[1] - loc[0]) * blend;1339prev_time = !backward ? start : end;1340}1341}1342{1343Vector3 loc;1344Error err = a->try_position_track_interpolate(i, time, &loc);1345if (err != OK) {1346continue;1347}1348loc = post_process_key_value(a, i, loc, t->object_id, t->bone_idx);1349t->loc += (loc - t->init_loc) * blend;1350}1351#endif // _3D_DISABLED1352} break;1353case Animation::TYPE_ROTATION_3D: {1354#ifndef _3D_DISABLED1355if (Math::is_zero_approx(blend)) {1356continue; // Nothing to blend.1357}1358TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1359if (track->root_motion && calc_root) {1360double prev_time = time - delta;1361if (!backward) {1362if (Animation::is_less_approx(prev_time, start)) {1363switch (a->get_loop_mode()) {1364case Animation::LOOP_NONE: {1365prev_time = start;1366} break;1367case Animation::LOOP_LINEAR: {1368prev_time = Math::fposmod(prev_time - start, end - start) + start;1369} break;1370case Animation::LOOP_PINGPONG: {1371prev_time = Math::pingpong(prev_time - start, end - start) + start;1372} break;1373default:1374break;1375}1376}1377} else {1378if (Animation::is_greater_approx(prev_time, end)) {1379switch (a->get_loop_mode()) {1380case Animation::LOOP_NONE: {1381prev_time = end;1382} break;1383case Animation::LOOP_LINEAR: {1384prev_time = Math::fposmod(prev_time - start, end - start) + start;1385} break;1386case Animation::LOOP_PINGPONG: {1387prev_time = Math::pingpong(prev_time - start, end - start) + start;1388} break;1389default:1390break;1391}1392}1393}1394Quaternion rot[2];1395if (!backward) {1396if (Animation::is_greater_approx(prev_time, time)) {1397Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);1398if (err != OK) {1399continue;1400}1401rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);1402a->try_rotation_track_interpolate(i, end, &rot[1]);1403rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);1404root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();1405prev_time = start;1406}1407} else {1408if (Animation::is_less_approx(prev_time, time)) {1409Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);1410if (err != OK) {1411continue;1412}1413rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);1414a->try_rotation_track_interpolate(i, start, &rot[1]);1415rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);1416root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();1417prev_time = end;1418}1419}1420Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);1421if (err != OK) {1422continue;1423}1424rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);1425a->try_rotation_track_interpolate(i, time, &rot[1]);1426rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);1427root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();1428prev_time = !backward ? start : end;1429}1430{1431Quaternion rot;1432Error err = a->try_rotation_track_interpolate(i, time, &rot);1433if (err != OK) {1434continue;1435}1436rot = post_process_key_value(a, i, rot, t->object_id, t->bone_idx);1437t->rot = (t->rot * Quaternion().slerp(t->init_rot.inverse() * rot, blend)).normalized();1438}1439#endif // _3D_DISABLED1440} break;1441case Animation::TYPE_SCALE_3D: {1442#ifndef _3D_DISABLED1443if (Math::is_zero_approx(blend)) {1444continue; // Nothing to blend.1445}1446TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1447if (track->root_motion && calc_root) {1448double prev_time = time - delta;1449if (!backward) {1450if (Animation::is_less_approx(prev_time, start)) {1451switch (a->get_loop_mode()) {1452case Animation::LOOP_NONE: {1453prev_time = start;1454} break;1455case Animation::LOOP_LINEAR: {1456prev_time = Math::fposmod(prev_time - start, end - start) + start;1457} break;1458case Animation::LOOP_PINGPONG: {1459prev_time = Math::pingpong(prev_time - start, end - start) + start;1460} break;1461default:1462break;1463}1464}1465} else {1466if (Animation::is_greater_approx(prev_time, end)) {1467switch (a->get_loop_mode()) {1468case Animation::LOOP_NONE: {1469prev_time = end;1470} break;1471case Animation::LOOP_LINEAR: {1472prev_time = Math::fposmod(prev_time - start, end - start) + start;1473} break;1474case Animation::LOOP_PINGPONG: {1475prev_time = Math::pingpong(prev_time - start, end - start) + start;1476} break;1477default:1478break;1479}1480}1481}1482Vector3 scale[2];1483if (!backward) {1484if (Animation::is_greater_approx(prev_time, time)) {1485Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);1486if (err != OK) {1487continue;1488}1489scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);1490a->try_scale_track_interpolate(i, end, &scale[1]);1491scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);1492root_motion_cache.scale += (scale[1] - scale[0]) * blend;1493prev_time = start;1494}1495} else {1496if (Animation::is_less_approx(prev_time, time)) {1497Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);1498if (err != OK) {1499continue;1500}1501scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);1502a->try_scale_track_interpolate(i, start, &scale[1]);1503scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);1504root_motion_cache.scale += (scale[1] - scale[0]) * blend;1505prev_time = end;1506}1507}1508Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);1509if (err != OK) {1510continue;1511}1512scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);1513a->try_scale_track_interpolate(i, time, &scale[1]);1514scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);1515root_motion_cache.scale += (scale[1] - scale[0]) * blend;1516prev_time = !backward ? start : end;1517}1518{1519Vector3 scale;1520Error err = a->try_scale_track_interpolate(i, time, &scale);1521if (err != OK) {1522continue;1523}1524scale = post_process_key_value(a, i, scale, t->object_id, t->bone_idx);1525t->scale += (scale - t->init_scale) * blend;1526}1527#endif // _3D_DISABLED1528} break;1529case Animation::TYPE_BLEND_SHAPE: {1530#ifndef _3D_DISABLED1531if (Math::is_zero_approx(blend)) {1532continue; // Nothing to blend.1533}1534TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);1535float value;1536Error err = a->try_blend_shape_track_interpolate(i, time, &value);1537//ERR_CONTINUE(err!=OK); //used for testing, should be removed1538if (err != OK) {1539continue;1540}1541value = post_process_key_value(a, i, value, t->object_id, t->shape_index);1542t->value += (value - t->init_value) * blend;1543#endif // _3D_DISABLED1544} break;1545case Animation::TYPE_BEZIER:1546case Animation::TYPE_VALUE: {1547if (Math::is_zero_approx(blend)) {1548continue; // Nothing to blend.1549}1550TrackCacheValue *t = static_cast<TrackCacheValue *>(track);1551bool is_value = ttype == Animation::TYPE_VALUE;1552bool is_discrete = is_value && a->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE;1553bool force_continuous = callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS;1554if (!is_discrete || force_continuous) {1555t->use_continuous = true;15561557Variant value;1558if (t->is_variant_interpolatable) {1559value = is_value ? a->value_track_interpolate(i, time, is_discrete && force_continuous ? backward : false) : Variant(a->bezier_track_interpolate(i, time));1560value = post_process_key_value(a, i, value, t->object_id);1561if (value == Variant()) {1562continue;1563}1564} else {1565// Discrete track sets the value in the current _blend_process() function,1566// but Force Continuous track does not set the value here because the value must be set in the _blend_apply() function later.1567int idx = a->track_find_key(i, time, Animation::FIND_MODE_NEAREST, false, backward);1568if (idx < 0) {1569continue;1570}1571value = a->track_get_key_value(i, idx);1572value = post_process_key_value(a, i, value, t->object_id);1573if (value == Variant()) {1574continue;1575}1576t->value = value;1577continue;1578}15791580// Special case for angle interpolation.1581if (t->is_using_angle) {1582// For blending consistency, it prevents rotation of more than 180 degrees from init_value.1583// This is the same as for Quaternion blends.1584float rot_a = t->value;1585float rot_b = value;1586float rot_init = t->init_value;1587rot_a = Math::fposmod(rot_a, (float)Math::TAU);1588rot_b = Math::fposmod(rot_b, (float)Math::TAU);1589rot_init = Math::fposmod(rot_init, (float)Math::TAU);1590if (rot_init < Math::PI) {1591rot_a = rot_a > rot_init + Math::PI ? rot_a - Math::TAU : rot_a;1592rot_b = rot_b > rot_init + Math::PI ? rot_b - Math::TAU : rot_b;1593} else {1594rot_a = rot_a < rot_init - Math::PI ? rot_a + Math::TAU : rot_a;1595rot_b = rot_b < rot_init - Math::PI ? rot_b + Math::TAU : rot_b;1596}1597t->value = Math::fposmod(rot_a + (rot_b - rot_init) * (float)blend, (float)Math::TAU);1598} else {1599value = Animation::cast_to_blendwise(value);1600if (t->init_value.is_array()) {1601t->element_size = MAX(t->element_size.operator int(), (value.operator Array()).size());1602} else if (t->init_value.is_string()) {1603real_t length = Animation::subtract_variant((real_t)(value.operator Array()).size(), (real_t)(t->init_value.operator String()).length());1604t->element_size = Animation::blend_variant(t->element_size, length, blend);1605}1606value = Animation::subtract_variant(value, Animation::cast_to_blendwise(t->init_value));1607t->value = Animation::blend_variant(t->value, value, blend);1608}1609} else {1610if (seeked) {1611int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, false, seeked_backward);1612if (idx < 0) {1613continue;1614}1615t->use_discrete = true;1616Variant value = a->track_get_key_value(i, idx);1617value = post_process_key_value(a, i, value, t->object_id);1618Object *t_obj = ObjectDB::get_instance(t->object_id);1619if (t_obj) {1620t_obj->set_indexed(t->subpath, value);1621}1622} else {1623List<int> indices;1624a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);1625for (int &F : indices) {1626t->use_discrete = true;1627Variant value = a->track_get_key_value(i, F);1628value = post_process_key_value(a, i, value, t->object_id);1629Object *t_obj = ObjectDB::get_instance(t->object_id);1630if (t_obj) {1631t_obj->set_indexed(t->subpath, value);1632}1633}1634}1635}1636} break;1637case Animation::TYPE_METHOD: {1638#ifdef TOOLS_ENABLED1639if (!can_call) {1640continue;1641}1642#endif // TOOLS_ENABLED1643if (p_update_only || Math::is_zero_approx(blend)) {1644continue;1645}1646TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track);1647if (seeked) {1648int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, true);1649if (idx < 0) {1650continue;1651}1652StringName method = a->method_track_get_name(i, idx);1653Vector<Variant> params = a->method_track_get_params(i, idx);1654_call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);1655} else {1656List<int> indices;1657a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);1658for (int &F : indices) {1659StringName method = a->method_track_get_name(i, F);1660Vector<Variant> params = a->method_track_get_params(i, F);1661_call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);1662}1663}1664} break;1665case Animation::TYPE_AUDIO: {1666// 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.1667TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);1668Object *t_obj = ObjectDB::get_instance(t->object_id);1669Node *asp = t_obj ? Object::cast_to<Node>(t_obj) : nullptr;1670if (!t_obj || !asp) {1671t->playing_streams.clear();1672continue;1673}1674ObjectID oid = a->get_instance_id();1675if (!t->playing_streams.has(oid)) {1676t->playing_streams[oid] = PlayingAudioTrackInfo();1677}16781679PlayingAudioTrackInfo &track_info = t->playing_streams[oid];1680track_info.length = a_length;1681track_info.time = time;1682track_info.volume += blend;1683track_info.loop = a->get_loop_mode() != Animation::LOOP_NONE;1684track_info.backward = backward;1685track_info.use_blend = a->audio_track_is_use_blend(i);1686AHashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;16871688// Main process to fire key is started from here.1689if (p_update_only) {1690continue;1691}1692// Find stream.1693int idx = -1;1694if (seeked) {1695// Audio key may be playbacked from the middle, should use FIND_MODE_NEAREST.1696// Then, check the current playing stream to prevent to playback doubly.1697idx = a->track_find_key(i, time, Animation::FIND_MODE_NEAREST, true);1698// Discard previous stream when seeking.1699if (map.has(idx)) {1700t->audio_stream_playback->stop_stream(map[idx].index);1701map.erase(idx);1702}1703} else {1704List<int> to_play;1705a->track_get_key_indices_in_range(i, time, delta, &to_play, looped_flag);1706if (to_play.size()) {1707idx = to_play.back()->get();1708}1709}1710if (idx < 0) {1711continue;1712}17131714// Play stream.1715Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);1716if (stream.is_valid()) {1717double start_ofs = a->audio_track_get_key_start_offset(i, idx);1718double end_ofs = a->audio_track_get_key_end_offset(i, idx);1719double len = stream->get_length();1720if (seeked) {1721start_ofs += time - a->track_get_key_time(i, idx);1722}17231724if (t_obj->call(SNAME("get_stream")) != t->audio_stream) {1725t_obj->call(SNAME("set_stream"), t->audio_stream);1726t->audio_stream_playback.unref();1727if (!playing_audio_stream_players.has(asp)) {1728playing_audio_stream_players.push_back(asp);1729}1730}1731if (!t_obj->call(SNAME("is_playing"))) {1732t_obj->call(SNAME("play"));1733}1734if (!t_obj->call(SNAME("has_stream_playback"))) {1735t->audio_stream_playback.unref();1736continue;1737}1738if (t->audio_stream_playback.is_null()) {1739t->audio_stream_playback = t_obj->call(SNAME("get_stream_playback"));1740}17411742if (t_obj->call(SNAME("get_is_sample"))) {1743if (t->audio_stream_playback->get_sample_playback().is_valid()) {1744AudioServer::get_singleton()->stop_sample_playback(t->audio_stream_playback->get_sample_playback());1745}1746Ref<AudioSamplePlayback> sample_playback;1747sample_playback.instantiate();1748sample_playback->stream = stream;1749t->audio_stream_playback->set_sample_playback(sample_playback);1750AudioServer::get_singleton()->start_sample_playback(sample_playback);1751continue;1752}17531754PlayingAudioStreamInfo pasi;1755pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs, 0, 1.0, t->playback_type, t->bus);1756pasi.start = time;1757if (len && Animation::is_greater_approx(end_ofs, 0)) { // Force an end at a time.1758pasi.len = len - start_ofs - end_ofs;1759} else {1760pasi.len = 0;1761}1762map[idx] = pasi;1763}1764} break;1765case Animation::TYPE_ANIMATION: {1766if (Math::is_zero_approx(blend)) {1767continue;1768}1769TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track);1770Object *t_obj = ObjectDB::get_instance(t->object_id);1771if (!t_obj) {1772continue;1773}1774AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t_obj);1775if (!player2) {1776continue;1777}1778// TODO: Make it possible to embed section info in animation track keys.1779if (seeked) {1780// Seek.1781int idx = a->track_find_key(i, time, Animation::FIND_MODE_NEAREST, true);1782if (idx < 0) {1783continue;1784}1785double pos = a->track_get_key_time(i, idx);1786StringName anim_name = a->animation_track_get_key_animation(i, idx);1787if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) {1788continue;1789}1790Ref<Animation> anim = player2->get_animation(anim_name);1791double at_anim_pos = start;1792switch (anim->get_loop_mode()) {1793case Animation::LOOP_NONE: {1794if (!is_external_seeking && ((!backward && Animation::is_greater_or_equal_approx(time, pos + end)) || (backward && Animation::is_less_or_equal_approx(time, pos + start)))) {1795continue; // Do nothing if current time is outside of length when started.1796}1797at_anim_pos = MIN(end, time - pos); // Seek to end.1798} break;1799case Animation::LOOP_LINEAR: {1800at_anim_pos = Math::fposmod(time - pos - start, end - start) + start; // Seek to loop.1801} break;1802case Animation::LOOP_PINGPONG: {1803at_anim_pos = Math::pingpong(time - pos - start, end - start) + start;1804} break;1805default:1806break;1807}1808if (player2->is_playing() || !is_external_seeking) {1809player2->seek(at_anim_pos, false, p_update_only);1810player2->play(anim_name);1811t->playing = true;1812playing_caches.insert(t);1813} else {1814player2->set_assigned_animation(anim_name);1815player2->seek(at_anim_pos, true, p_update_only);1816}1817} else {1818// Find stuff to play.1819List<int> to_play;1820a->track_get_key_indices_in_range(i, time, delta, &to_play, looped_flag);1821if (to_play.size()) {1822int idx = to_play.back()->get();1823StringName anim_name = a->animation_track_get_key_animation(i, idx);1824if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) {1825if (playing_caches.has(t)) {1826playing_caches.erase(t);1827player2->stop();1828t->playing = false;1829}1830} else {1831player2->play(anim_name);1832t->playing = true;1833playing_caches.insert(t);1834}1835}1836}1837} break;1838}1839}1840}1841is_GDVIRTUAL_CALL_post_process_key_value = true;1842}18431844void AnimationMixer::_blend_apply() {1845// Finally, set the tracks.1846for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {1847TrackCache *track = K.value;1848bool is_zero_amount = Math::is_zero_approx(track->total_weight);1849if (!deterministic && is_zero_amount) {1850continue;1851}1852switch (track->type) {1853case Animation::TYPE_POSITION_3D: {1854#ifndef _3D_DISABLED1855TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);18561857if (t->root_motion) {1858root_motion_position = root_motion_cache.loc;1859root_motion_rotation = root_motion_cache.rot;1860root_motion_scale = root_motion_cache.scale - Vector3(1, 1, 1);1861root_motion_position_accumulator = t->loc;1862root_motion_rotation_accumulator = t->rot;1863root_motion_scale_accumulator = t->scale;1864} else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) {1865Skeleton3D *t_skeleton = ObjectDB::get_instance<Skeleton3D>(t->skeleton_id);1866if (!t_skeleton) {1867return;1868}1869if (t->loc_used) {1870t_skeleton->set_bone_pose_position(t->bone_idx, t->loc);1871}1872if (t->rot_used) {1873t_skeleton->set_bone_pose_rotation(t->bone_idx, t->rot);1874}1875if (t->scale_used) {1876t_skeleton->set_bone_pose_scale(t->bone_idx, t->scale);1877}18781879} else if (!t->skeleton_id.is_valid()) {1880Node3D *t_node_3d = ObjectDB::get_instance<Node3D>(t->object_id);1881if (!t_node_3d) {1882return;1883}1884if (t->loc_used) {1885t_node_3d->set_position(t->loc);1886}1887if (t->rot_used) {1888t_node_3d->set_rotation(t->rot.get_euler());1889}1890if (t->scale_used) {1891t_node_3d->set_scale(t->scale);1892}1893}1894#endif // _3D_DISABLED1895} break;1896case Animation::TYPE_BLEND_SHAPE: {1897#ifndef _3D_DISABLED1898TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);18991900MeshInstance3D *t_mesh_3d = ObjectDB::get_instance<MeshInstance3D>(t->object_id);1901if (t_mesh_3d) {1902t_mesh_3d->set_blend_shape_value(t->shape_index, t->value);1903}1904#endif // _3D_DISABLED1905} break;1906case Animation::TYPE_VALUE: {1907TrackCacheValue *t = static_cast<TrackCacheValue *>(track);19081909if (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {1910t->is_init = false; // Always update in Force Continuous.1911} else if (!t->use_continuous && (t->use_discrete || !deterministic)) {1912t->is_init = true; // If there is no continuous value and only disctere value is applied or just started, don't RESET.1913}19141915if ((t->is_init && (is_zero_amount || !t->use_continuous)) ||1916(callback_mode_discrete != ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS &&1917!is_zero_amount &&1918callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT &&1919t->use_discrete)) {1920break; // Don't overwrite the value set by UPDATE_DISCRETE.1921}19221923if (callback_mode_discrete != ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {1924t->is_init = !t->use_continuous; // If there is no Continuous in non-Force Continuous type, it means RESET.1925}19261927// Trim unused elements if init array/string is not blended.1928if (t->value.is_array()) {1929int actual_blended_size = (int)Math::round(Math::abs(t->element_size.operator real_t()));1930if (actual_blended_size < (t->value.operator Array()).size()) {1931real_t abs_weight = Math::abs(track->total_weight);1932if (abs_weight >= 1.0) {1933(t->value.operator Array()).resize(actual_blended_size);1934} else if (t->init_value.is_string()) {1935(t->value.operator Array()).resize(Animation::interpolate_variant((t->init_value.operator String()).length(), actual_blended_size, abs_weight));1936}1937}1938}19391940Object *t_obj = ObjectDB::get_instance(t->object_id);1941if (t_obj) {1942t_obj->set_indexed(t->subpath, Animation::cast_from_blendwise(t->value, t->init_value.get_type()));1943}19441945} break;1946case Animation::TYPE_AUDIO: {1947TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);19481949// Audio ending process.1950LocalVector<ObjectID> erase_maps;1951for (KeyValue<ObjectID, PlayingAudioTrackInfo> &L : t->playing_streams) {1952PlayingAudioTrackInfo &track_info = L.value;1953float db = Math::linear_to_db(track_info.use_blend ? track_info.volume : 1.0);1954LocalVector<int> erase_streams;1955AHashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;1956for (const KeyValue<int, PlayingAudioStreamInfo> &M : map) {1957PlayingAudioStreamInfo pasi = M.value;19581959bool stop = false;1960if (!t->audio_stream_playback->is_stream_playing(pasi.index)) {1961stop = true;1962}1963if (!track_info.loop) {1964if (!track_info.backward) {1965if (Animation::is_less_approx(track_info.time, pasi.start)) {1966stop = true;1967}1968} else if (track_info.backward) {1969if (Animation::is_greater_approx(track_info.time, pasi.start)) {1970stop = true;1971}1972}1973}1974if (Animation::is_greater_approx(pasi.len, 0)) {1975double len = 0.0;1976if (!track_info.backward) {1977len = Animation::is_greater_approx(pasi.start, track_info.time) ? (track_info.length - pasi.start) + track_info.time : track_info.time - pasi.start;1978} else {1979len = Animation::is_less_approx(pasi.start, track_info.time) ? (track_info.length - track_info.time) + pasi.start : pasi.start - track_info.time;1980}1981if (Animation::is_greater_approx(len, pasi.len)) {1982stop = true;1983}1984}1985if (stop) {1986// Time to stop.1987t->audio_stream_playback->stop_stream(pasi.index);1988erase_streams.push_back(M.key);1989} else {1990t->audio_stream_playback->set_stream_volume(pasi.index, db);1991}1992}1993for (uint32_t erase_idx = 0; erase_idx < erase_streams.size(); erase_idx++) {1994map.erase(erase_streams[erase_idx]);1995}1996if (map.is_empty()) {1997erase_maps.push_back(L.key);1998}1999}2000for (uint32_t erase_idx = 0; erase_idx < erase_maps.size(); erase_idx++) {2001t->playing_streams.erase(erase_maps[erase_idx]);2002}2003} break;2004default: {2005} // The rest don't matter.2006}2007}2008}20092010void AnimationMixer::_call_object(ObjectID p_object_id, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) {2011// Separate function to use alloca() more efficiently2012const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * p_params.size());2013const Variant *args = p_params.ptr();2014uint32_t argcount = p_params.size();2015for (uint32_t i = 0; i < argcount; i++) {2016argptrs[i] = &args[i];2017}2018Object *t_obj = ObjectDB::get_instance(p_object_id);2019if (!t_obj) {2020return;2021}2022if (p_deferred) {2023Callable(t_obj, p_method).call_deferredp(argptrs, argcount);2024} else {2025Callable::CallError ce;2026t_obj->callp(p_method, argptrs, argcount, ce);2027}2028}20292030void AnimationMixer::make_animation_instance(const StringName &p_name, const PlaybackInfo p_playback_info) {2031ERR_FAIL_COND(!has_animation(p_name));20322033AnimationData ad;2034ad.name = p_name;2035ad.animation = get_animation(p_name);2036ad.animation_library = find_animation_library(ad.animation);20372038AnimationInstance ai;2039ai.animation_data = ad;2040ai.playback_info = p_playback_info;20412042animation_instances.push_back(ai);2043}20442045void AnimationMixer::clear_animation_instances() {2046animation_instances.clear();2047}20482049void AnimationMixer::advance(double p_time) {2050_process_animation(p_time);2051}20522053void AnimationMixer::clear_caches() {2054_clear_caches();2055}20562057/* -------------------------------------------- */2058/* -- Root motion ----------------------------- */2059/* -------------------------------------------- */20602061void AnimationMixer::set_root_motion_track(const NodePath &p_track) {2062root_motion_track = p_track;2063notify_property_list_changed();2064}20652066NodePath AnimationMixer::get_root_motion_track() const {2067return root_motion_track;2068}20692070void AnimationMixer::set_root_motion_local(bool p_enabled) {2071root_motion_local = p_enabled;2072}20732074bool AnimationMixer::is_root_motion_local() const {2075return root_motion_local;2076}20772078Vector3 AnimationMixer::get_root_motion_position() const {2079return root_motion_position;2080}20812082Quaternion AnimationMixer::get_root_motion_rotation() const {2083return root_motion_rotation;2084}20852086Vector3 AnimationMixer::get_root_motion_scale() const {2087return root_motion_scale;2088}20892090Vector3 AnimationMixer::get_root_motion_position_accumulator() const {2091return root_motion_position_accumulator;2092}20932094Quaternion AnimationMixer::get_root_motion_rotation_accumulator() const {2095return root_motion_rotation_accumulator;2096}20972098Vector3 AnimationMixer::get_root_motion_scale_accumulator() const {2099return root_motion_scale_accumulator;2100}21012102/* -------------------------------------------- */2103/* -- Reset on save --------------------------- */2104/* -------------------------------------------- */21052106void AnimationMixer::set_reset_on_save_enabled(bool p_enabled) {2107reset_on_save = p_enabled;2108}21092110bool AnimationMixer::is_reset_on_save_enabled() const {2111return reset_on_save;2112}21132114bool AnimationMixer::can_apply_reset() const {2115return has_animation(SceneStringName(RESET));2116}21172118void AnimationMixer::_build_backup_track_cache() {2119for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {2120TrackCache *track = K.value;2121track->total_weight = 1.0;2122switch (track->type) {2123case Animation::TYPE_POSITION_3D: {2124#ifndef _3D_DISABLED2125TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);2126if (t->root_motion) {2127// Do nothing.2128} else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) {2129Skeleton3D *t_skeleton = ObjectDB::get_instance<Skeleton3D>(t->skeleton_id);2130if (!t_skeleton) {2131return;2132}2133if (t->loc_used) {2134t->loc = t_skeleton->get_bone_pose_position(t->bone_idx);2135}2136if (t->rot_used) {2137t->rot = t_skeleton->get_bone_pose_rotation(t->bone_idx);2138}2139if (t->scale_used) {2140t->scale = t_skeleton->get_bone_pose_scale(t->bone_idx);2141}2142} else if (!t->skeleton_id.is_valid()) {2143Node3D *t_node_3d = ObjectDB::get_instance<Node3D>(t->object_id);2144if (!t_node_3d) {2145return;2146}2147if (t->loc_used) {2148t->loc = t_node_3d->get_position();2149}2150if (t->rot_used) {2151t->rot = t_node_3d->get_quaternion();2152}2153if (t->scale_used) {2154t->scale = t_node_3d->get_scale();2155}2156}2157#endif // _3D_DISABLED2158} break;2159case Animation::TYPE_BLEND_SHAPE: {2160#ifndef _3D_DISABLED2161TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);2162MeshInstance3D *t_mesh_3d = ObjectDB::get_instance<MeshInstance3D>(t->object_id);2163if (t_mesh_3d) {2164t->value = t_mesh_3d->get_blend_shape_value(t->shape_index);2165}2166#endif // _3D_DISABLED2167} break;2168case Animation::TYPE_VALUE: {2169TrackCacheValue *t = static_cast<TrackCacheValue *>(track);2170Object *t_obj = ObjectDB::get_instance(t->object_id);2171if (t_obj) {2172t->value = Animation::cast_to_blendwise(t_obj->get_indexed(t->subpath));2173}2174t->use_continuous = true;2175t->use_discrete = false;2176if (t->init_value.is_array()) {2177t->element_size = MAX(t->element_size.operator int(), (t->value.operator Array()).size());2178} else if (t->init_value.is_string()) {2179t->element_size = (real_t)(t->value.operator Array()).size();2180}2181} break;2182case Animation::TYPE_AUDIO: {2183TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);2184Object *t_obj = ObjectDB::get_instance(t->object_id);2185if (t_obj) {2186Node *asp = Object::cast_to<Node>(t_obj);2187if (asp) {2188asp->call(SNAME("set_stream"), Ref<AudioStream>());2189}2190}2191} break;2192default: {2193} // The rest don't matter.2194}2195}2196}21972198Ref<AnimatedValuesBackup> AnimationMixer::make_backup() {2199Ref<AnimatedValuesBackup> backup;2200backup.instantiate();22012202Ref<Animation> reset_anim = animation_set[SceneStringName(RESET)].animation;2203ERR_FAIL_COND_V(reset_anim.is_null(), Ref<AnimatedValuesBackup>());22042205_blend_init();2206PlaybackInfo pi;2207pi.time = 0;2208pi.delta = 0;2209pi.start = 0;2210pi.end = reset_anim->get_length();2211pi.seeked = true;2212pi.weight = 1.0;2213make_animation_instance(SceneStringName(RESET), pi);2214_build_backup_track_cache();22152216backup->set_data(track_cache);2217clear_animation_instances();22182219return backup;2220}22212222void AnimationMixer::reset() {2223ERR_FAIL_COND(!can_apply_reset());22242225Ref<Animation> reset_anim = animation_set[SceneStringName(RESET)].animation;2226ERR_FAIL_COND(reset_anim.is_null());22272228Node *root_node_object = get_node_or_null(root_node);2229ERR_FAIL_NULL(root_node_object);22302231AnimationPlayer *aux_player = memnew(AnimationPlayer);2232root_node_object->add_child(aux_player);2233Ref<AnimationLibrary> al;2234al.instantiate();2235al->add_animation(SceneStringName(RESET), reset_anim);2236aux_player->set_reset_on_save_enabled(false);2237aux_player->set_root_node(aux_player->get_path_to(root_node_object));2238aux_player->add_animation_library("", al);2239aux_player->set_assigned_animation(SceneStringName(RESET));2240aux_player->seek(0.0f, true);2241aux_player->queue_free();2242}22432244void AnimationMixer::restore(const Ref<AnimatedValuesBackup> &p_backup) {2245ERR_FAIL_COND(p_backup.is_null());2246track_cache = p_backup->get_data();2247_blend_apply();2248track_cache = AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher>();2249cache_valid = false;2250}22512252#ifdef TOOLS_ENABLED2253Ref<AnimatedValuesBackup> AnimationMixer::apply_reset(bool p_user_initiated) {2254if (!p_user_initiated && dummy) {2255return Ref<AnimatedValuesBackup>();2256}2257ERR_FAIL_COND_V(!can_apply_reset(), Ref<AnimatedValuesBackup>());22582259Ref<Animation> reset_anim = animation_set[SceneStringName(RESET)].animation;2260ERR_FAIL_COND_V(reset_anim.is_null(), Ref<AnimatedValuesBackup>());22612262Ref<AnimatedValuesBackup> backup_current = make_backup();2263if (p_user_initiated) {2264EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();2265ur->create_action(TTR("Animation Apply Reset"));2266ur->add_do_method(this, "_reset");2267ur->add_undo_method(this, "_restore", backup_current);2268ur->commit_action();2269} else {2270reset();2271}22722273return backup_current;2274}2275#endif // TOOLS_ENABLED22762277/* -------------------------------------------- */2278/* -- Capture feature ------------------------- */2279/* -------------------------------------------- */22802281void AnimationMixer::capture(const StringName &p_name, double p_duration, Tween::TransitionType p_trans_type, Tween::EaseType p_ease_type) {2282ERR_FAIL_COND(!active);2283ERR_FAIL_COND(!has_animation(p_name));2284ERR_FAIL_COND(p_duration <= 0);2285Ref<Animation> reference_animation = get_animation(p_name);22862287if (!cache_valid) {2288_update_caches(); // Need to retrieve object id.2289}22902291capture_cache.remain = 1.0;2292capture_cache.step = 1.0 / p_duration;2293capture_cache.trans_type = p_trans_type;2294capture_cache.ease_type = p_ease_type;2295if (capture_cache.animation.is_valid()) {2296animation_track_num_to_track_cache.erase(capture_cache.animation);2297}2298capture_cache.animation.instantiate();22992300bool is_valid = false;2301for (int i = 0; i < reference_animation->get_track_count(); i++) {2302if (!reference_animation->track_is_enabled(i)) {2303continue;2304}2305if (reference_animation->track_get_type(i) == Animation::TYPE_VALUE && reference_animation->value_track_get_update_mode(i) == Animation::UPDATE_CAPTURE) {2306TrackCacheValue *t = static_cast<TrackCacheValue *>(track_cache[reference_animation->track_get_type_hash(i)]);2307Object *t_obj = ObjectDB::get_instance(t->object_id);2308if (t_obj) {2309Variant value = t_obj->get_indexed(t->subpath);2310int inserted_idx = capture_cache.animation->add_track(Animation::TYPE_VALUE);2311capture_cache.animation->track_set_path(inserted_idx, reference_animation->track_get_path(i));2312capture_cache.animation->track_insert_key(inserted_idx, 0, value);2313capture_cache.animation->value_track_set_update_mode(inserted_idx, Animation::UPDATE_CONTINUOUS);2314capture_cache.animation->track_set_interpolation_type(inserted_idx, Animation::INTERPOLATION_LINEAR);2315is_valid = true;2316}2317}2318}2319if (!is_valid) {2320capture_cache.clear();2321} else {2322_create_track_num_to_track_cache_for_animation(capture_cache.animation);2323}2324}23252326/* -------------------------------------------- */2327/* -- General functions ----------------------- */2328/* -------------------------------------------- */23292330void AnimationMixer::_node_removed(Node *p_node) {2331_clear_caches();2332}23332334void AnimationMixer::_notification(int p_what) {2335switch (p_what) {2336case NOTIFICATION_ENTER_TREE: {2337if (!processing) {2338set_physics_process_internal(false);2339set_process_internal(false);2340}2341_clear_caches();2342} break;23432344case NOTIFICATION_INTERNAL_PROCESS: {2345if (active && callback_mode_process == ANIMATION_CALLBACK_MODE_PROCESS_IDLE) {2346_process_animation(get_process_delta_time());2347}2348} break;23492350case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {2351if (active && callback_mode_process == ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS) {2352_process_animation(get_physics_process_delta_time());2353}2354} break;23552356case NOTIFICATION_EXIT_TREE: {2357_clear_caches();2358} break;2359}2360}23612362#ifdef TOOLS_ENABLED2363void AnimationMixer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {2364const String pf = p_function;2365if (p_idx == 0) {2366if (pf == "get_animation" || pf == "has_animation") {2367List<StringName> al;2368get_animation_list(&al);2369for (const StringName &name : al) {2370r_options->push_back(String(name).quote());2371}2372} else if (pf == "get_animation_library" || pf == "has_animation_library" || pf == "remove_animation_library" || pf == "rename_animation_library") {2373List<StringName> al;2374get_animation_library_list(&al);2375for (const StringName &name : al) {2376r_options->push_back(String(name).quote());2377}2378}2379}2380Node::get_argument_options(p_function, p_idx, r_options);2381}2382#endif23832384void AnimationMixer::_bind_methods() {2385/* ---- Data lists ---- */2386ClassDB::bind_method(D_METHOD("add_animation_library", "name", "library"), &AnimationMixer::add_animation_library);2387ClassDB::bind_method(D_METHOD("remove_animation_library", "name"), &AnimationMixer::remove_animation_library);2388ClassDB::bind_method(D_METHOD("rename_animation_library", "name", "newname"), &AnimationMixer::rename_animation_library);2389ClassDB::bind_method(D_METHOD("has_animation_library", "name"), &AnimationMixer::has_animation_library);2390ClassDB::bind_method(D_METHOD("get_animation_library", "name"), &AnimationMixer::get_animation_library);2391ClassDB::bind_method(D_METHOD("get_animation_library_list"), &AnimationMixer::_get_animation_library_list);23922393ClassDB::bind_method(D_METHOD("has_animation", "name"), &AnimationMixer::has_animation);2394ClassDB::bind_method(D_METHOD("get_animation", "name"), &AnimationMixer::get_animation);2395ClassDB::bind_method(D_METHOD("get_animation_list"), &AnimationMixer::_get_animation_list);23962397/* ---- General settings for animation ---- */2398ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationMixer::set_active);2399ClassDB::bind_method(D_METHOD("is_active"), &AnimationMixer::is_active);24002401ClassDB::bind_method(D_METHOD("set_deterministic", "deterministic"), &AnimationMixer::set_deterministic);2402ClassDB::bind_method(D_METHOD("is_deterministic"), &AnimationMixer::is_deterministic);24032404ClassDB::bind_method(D_METHOD("set_root_node", "path"), &AnimationMixer::set_root_node);2405ClassDB::bind_method(D_METHOD("get_root_node"), &AnimationMixer::get_root_node);24062407ClassDB::bind_method(D_METHOD("set_callback_mode_process", "mode"), &AnimationMixer::set_callback_mode_process);2408ClassDB::bind_method(D_METHOD("get_callback_mode_process"), &AnimationMixer::get_callback_mode_process);24092410ClassDB::bind_method(D_METHOD("set_callback_mode_method", "mode"), &AnimationMixer::set_callback_mode_method);2411ClassDB::bind_method(D_METHOD("get_callback_mode_method"), &AnimationMixer::get_callback_mode_method);24122413ClassDB::bind_method(D_METHOD("set_callback_mode_discrete", "mode"), &AnimationMixer::set_callback_mode_discrete);2414ClassDB::bind_method(D_METHOD("get_callback_mode_discrete"), &AnimationMixer::get_callback_mode_discrete);24152416/* ---- Audio ---- */2417ClassDB::bind_method(D_METHOD("set_audio_max_polyphony", "max_polyphony"), &AnimationMixer::set_audio_max_polyphony);2418ClassDB::bind_method(D_METHOD("get_audio_max_polyphony"), &AnimationMixer::get_audio_max_polyphony);24192420/* ---- Root motion accumulator for Skeleton3D ---- */2421ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationMixer::set_root_motion_track);2422ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationMixer::get_root_motion_track);2423ClassDB::bind_method(D_METHOD("set_root_motion_local", "enabled"), &AnimationMixer::set_root_motion_local);2424ClassDB::bind_method(D_METHOD("is_root_motion_local"), &AnimationMixer::is_root_motion_local);24252426ClassDB::bind_method(D_METHOD("get_root_motion_position"), &AnimationMixer::get_root_motion_position);2427ClassDB::bind_method(D_METHOD("get_root_motion_rotation"), &AnimationMixer::get_root_motion_rotation);2428ClassDB::bind_method(D_METHOD("get_root_motion_scale"), &AnimationMixer::get_root_motion_scale);2429ClassDB::bind_method(D_METHOD("get_root_motion_position_accumulator"), &AnimationMixer::get_root_motion_position_accumulator);2430ClassDB::bind_method(D_METHOD("get_root_motion_rotation_accumulator"), &AnimationMixer::get_root_motion_rotation_accumulator);2431ClassDB::bind_method(D_METHOD("get_root_motion_scale_accumulator"), &AnimationMixer::get_root_motion_scale_accumulator);24322433/* ---- Blending processor ---- */2434ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationMixer::clear_caches);2435ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationMixer::advance);2436GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object_id", "object_sub_idx");24372438/* ---- Capture feature ---- */2439ClassDB::bind_method(D_METHOD("capture", "name", "duration", "trans_type", "ease_type"), &AnimationMixer::capture, DEFVAL(Tween::TRANS_LINEAR), DEFVAL(Tween::EASE_IN));24402441/* ---- Reset on save ---- */2442ClassDB::bind_method(D_METHOD("set_reset_on_save_enabled", "enabled"), &AnimationMixer::set_reset_on_save_enabled);2443ClassDB::bind_method(D_METHOD("is_reset_on_save_enabled"), &AnimationMixer::is_reset_on_save_enabled);24442445ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");2446ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deterministic"), "set_deterministic", "is_deterministic");2447ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset_on_save", PROPERTY_HINT_NONE, ""), "set_reset_on_save_enabled", "is_reset_on_save_enabled");2448ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root_node", "get_root_node");24492450ADD_GROUP("Root Motion", "root_motion_");2451ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track");2452ADD_PROPERTY(PropertyInfo(Variant::BOOL, "root_motion_local"), "set_root_motion_local", "is_root_motion_local");24532454ADD_GROUP("Audio", "audio_");2455ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_max_polyphony", PROPERTY_HINT_RANGE, "1,127,1"), "set_audio_max_polyphony", "get_audio_max_polyphony");24562457ADD_GROUP("Callback Mode", "callback_mode_");2458ADD_PROPERTY(PropertyInfo(Variant::INT, "callback_mode_process", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_callback_mode_process", "get_callback_mode_process");2459ADD_PROPERTY(PropertyInfo(Variant::INT, "callback_mode_method", PROPERTY_HINT_ENUM, "Deferred,Immediate"), "set_callback_mode_method", "get_callback_mode_method");2460ADD_PROPERTY(PropertyInfo(Variant::INT, "callback_mode_discrete", PROPERTY_HINT_ENUM, "Dominant,Recessive,Force Continuous"), "set_callback_mode_discrete", "get_callback_mode_discrete");24612462BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS);2463BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_PROCESS_IDLE);2464BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_PROCESS_MANUAL);24652466BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);2467BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_METHOD_IMMEDIATE);24682469BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT);2470BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE);2471BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS);24722473ADD_SIGNAL(MethodInfo(SNAME("animation_list_changed")));2474ADD_SIGNAL(MethodInfo(SNAME("animation_libraries_updated")));2475ADD_SIGNAL(MethodInfo(SNAME("animation_finished"), PropertyInfo(Variant::STRING_NAME, "anim_name")));2476ADD_SIGNAL(MethodInfo(SNAME("animation_started"), PropertyInfo(Variant::STRING_NAME, "anim_name")));2477ADD_SIGNAL(MethodInfo(SNAME("caches_cleared")));2478ADD_SIGNAL(MethodInfo(SNAME("mixer_applied")));2479ADD_SIGNAL(MethodInfo(SNAME("mixer_updated"))); // For updating dummy player.24802481ClassDB::bind_method(D_METHOD("_reset"), &AnimationMixer::reset);2482ClassDB::bind_method(D_METHOD("_restore", "backup"), &AnimationMixer::restore);2483}24842485AnimationMixer::AnimationMixer() {2486root_node = SceneStringName(path_pp);2487}24882489AnimationMixer::~AnimationMixer() {2490}24912492void AnimatedValuesBackup::set_data(const AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> p_data) {2493clear_data();24942495for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : p_data) {2496AnimationMixer::TrackCache *track = get_cache_copy(E.value);2497if (!track) {2498continue; // Some types of tracks do not get a copy and must be ignored.2499}25002501data.insert(E.key, track);2502}2503}25042505AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> AnimatedValuesBackup::get_data() const {2506HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> ret;2507for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : data) {2508AnimationMixer::TrackCache *track = get_cache_copy(E.value);2509ERR_CONTINUE(!track); // Backup shouldn't contain tracks that cannot be copied, this is a mistake.25102511ret.insert(E.key, track);2512}2513return ret;2514}25152516void AnimatedValuesBackup::clear_data() {2517for (KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &K : data) {2518memdelete(K.value);2519}2520data.clear();2521}25222523AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer::TrackCache *p_cache) const {2524switch (p_cache->type) {2525case Animation::TYPE_BEZIER:2526case Animation::TYPE_VALUE: {2527AnimationMixer::TrackCacheValue *src = static_cast<AnimationMixer::TrackCacheValue *>(p_cache);2528AnimationMixer::TrackCacheValue *tc = memnew(AnimationMixer::TrackCacheValue(*src));2529return tc;2530}25312532case Animation::TYPE_POSITION_3D:2533case Animation::TYPE_ROTATION_3D:2534case Animation::TYPE_SCALE_3D: {2535AnimationMixer::TrackCacheTransform *src = static_cast<AnimationMixer::TrackCacheTransform *>(p_cache);2536AnimationMixer::TrackCacheTransform *tc = memnew(AnimationMixer::TrackCacheTransform(*src));2537return tc;2538}25392540case Animation::TYPE_BLEND_SHAPE: {2541AnimationMixer::TrackCacheBlendShape *src = static_cast<AnimationMixer::TrackCacheBlendShape *>(p_cache);2542AnimationMixer::TrackCacheBlendShape *tc = memnew(AnimationMixer::TrackCacheBlendShape(*src));2543return tc;2544}25452546case Animation::TYPE_AUDIO: {2547AnimationMixer::TrackCacheAudio *src = static_cast<AnimationMixer::TrackCacheAudio *>(p_cache);2548AnimationMixer::TrackCacheAudio *tc = memnew(AnimationMixer::TrackCacheAudio(*src));2549return tc;2550}25512552case Animation::TYPE_METHOD:2553case Animation::TYPE_ANIMATION: {2554// Nothing to do here.2555} break;2556}2557return nullptr;2558}255925602561