Path: blob/master/scene/animation/animation_mixer.cpp
10277 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}107108uint32_t AnimationMixer::_get_libraries_property_usage() const {109return PROPERTY_USAGE_DEFAULT;110}111112void AnimationMixer::_get_property_list(List<PropertyInfo> *p_list) const {113p_list->push_back(PropertyInfo(Variant::DICTIONARY, PNAME("libraries"), PROPERTY_HINT_DICTIONARY_TYPE, "StringName;AnimationLibrary", _get_libraries_property_usage()));114}115116void AnimationMixer::_validate_property(PropertyInfo &p_property) const {117#ifdef TOOLS_ENABLED // `editing` is surrounded by TOOLS_ENABLED so this should also be.118if (Engine::get_singleton()->is_editor_hint() && editing && (p_property.name == "active" || p_property.name == "deterministic" || p_property.name == "root_motion_track")) {119p_property.usage |= PROPERTY_USAGE_READ_ONLY;120}121#endif // TOOLS_ENABLED122if (root_motion_track.is_empty() && p_property.name == "root_motion_local") {123p_property.usage = PROPERTY_USAGE_NONE;124}125}126127/* -------------------------------------------- */128/* -- Data lists ------------------------------ */129/* -------------------------------------------- */130131void AnimationMixer::_animation_set_cache_update() {132// Relatively fast function to update all animations.133animation_set_update_pass++;134bool clear_cache_needed = false;135136// Update changed and add otherwise.137for (const AnimationLibraryData &lib : animation_libraries) {138for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) {139StringName key = lib.name == StringName() ? K.key : StringName(String(lib.name) + "/" + String(K.key));140if (!animation_set.has(key)) {141AnimationData ad;142ad.animation = K.value;143ad.animation_library = lib.name;144ad.name = key;145ad.last_update = animation_set_update_pass;146animation_set.insert(ad.name, ad);147cache_valid = false; // No need to delete the cache, but it must be updated to add track caches.148} else {149AnimationData &ad = animation_set[key];150if (ad.last_update != animation_set_update_pass) {151// Was not updated, update. If the animation is duplicated, the second one will be ignored.152if (ad.animation != K.value || ad.animation_library != lib.name) {153// Animation changed, update and clear caches.154clear_cache_needed = true;155ad.animation = K.value;156ad.animation_library = lib.name;157}158159ad.last_update = animation_set_update_pass;160}161}162}163}164165// Check removed.166List<StringName> to_erase;167for (const KeyValue<StringName, AnimationData> &E : animation_set) {168if (E.value.last_update != animation_set_update_pass) {169// Was not updated, must be erased.170to_erase.push_back(E.key);171clear_cache_needed = true;172}173}174175while (to_erase.size()) {176animation_set.erase(to_erase.front()->get());177to_erase.pop_front();178}179180if (clear_cache_needed) {181// If something was modified or removed, caches need to be cleared.182_clear_caches();183}184185emit_signal(SNAME("animation_list_changed"));186}187188void AnimationMixer::_animation_added(const StringName &p_name, const StringName &p_library) {189_animation_set_cache_update();190}191192void AnimationMixer::_animation_removed(const StringName &p_name, const StringName &p_library) {193StringName name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));194195if (!animation_set.has(name)) {196return; // No need to update because not the one from the library being used.197}198199_animation_set_cache_update();200201_remove_animation(name);202}203204void AnimationMixer::_animation_renamed(const StringName &p_name, const StringName &p_to_name, const StringName &p_library) {205StringName from_name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));206StringName to_name = p_library == StringName() ? p_to_name : StringName(String(p_library) + "/" + String(p_to_name));207208if (!animation_set.has(from_name)) {209return; // No need to update because not the one from the library being used.210}211_animation_set_cache_update();212213_rename_animation(from_name, to_name);214}215216void AnimationMixer::_animation_changed(const StringName &p_name) {217_clear_caches();218}219220void AnimationMixer::_set_active(bool p_active) {221//222}223224void AnimationMixer::_remove_animation(const StringName &p_name) {225//226}227228void AnimationMixer::_rename_animation(const StringName &p_from_name, const StringName &p_to_name) {229//230}231232TypedArray<StringName> AnimationMixer::_get_animation_library_list() const {233TypedArray<StringName> ret;234for (const AnimationLibraryData &lib : animation_libraries) {235ret.push_back(lib.name);236}237return ret;238}239240void AnimationMixer::get_animation_library_list(List<StringName> *p_libraries) const {241for (const AnimationLibraryData &lib : animation_libraries) {242p_libraries->push_back(lib.name);243}244}245246Ref<AnimationLibrary> AnimationMixer::get_animation_library(const StringName &p_name) const {247for (const AnimationLibraryData &lib : animation_libraries) {248if (lib.name == p_name) {249return lib.library;250}251}252ERR_FAIL_V(Ref<AnimationLibrary>());253}254255bool AnimationMixer::has_animation_library(const StringName &p_name) const {256for (const AnimationLibraryData &lib : animation_libraries) {257if (lib.name == p_name) {258return true;259}260}261262return false;263}264265StringName AnimationMixer::get_animation_library_name(const Ref<AnimationLibrary> &p_animation_library) const {266ERR_FAIL_COND_V(p_animation_library.is_null(), StringName());267for (const AnimationLibraryData &lib : animation_libraries) {268if (lib.library == p_animation_library) {269return lib.name;270}271}272return StringName();273}274275StringName AnimationMixer::find_animation_library(const Ref<Animation> &p_animation) const {276for (const KeyValue<StringName, AnimationData> &E : animation_set) {277if (E.value.animation == p_animation) {278return E.value.animation_library;279}280}281return StringName();282}283284Error AnimationMixer::add_animation_library(const StringName &p_name, const Ref<AnimationLibrary> &p_animation_library) {285ERR_FAIL_COND_V(p_animation_library.is_null(), ERR_INVALID_PARAMETER);286#ifdef DEBUG_ENABLED287ERR_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) + ".");288#endif289290int insert_pos = 0;291292for (const AnimationLibraryData &lib : animation_libraries) {293ERR_FAIL_COND_V_MSG(lib.name == p_name, ERR_ALREADY_EXISTS, "Can't add animation library twice with name: " + String(p_name));294ERR_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() + "'.");295296if (lib.name.operator String() >= p_name.operator String()) {297break;298}299300insert_pos++;301}302303AnimationLibraryData ald;304ald.name = p_name;305ald.library = p_animation_library;306307animation_libraries.insert(insert_pos, ald);308309ald.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added).bind(p_name));310ald.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed).bind(p_name));311ald.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed).bind(p_name));312ald.library->connect(SceneStringName(animation_changed), callable_mp(this, &AnimationMixer::_animation_changed));313314_animation_set_cache_update();315316notify_property_list_changed();317318return OK;319}320321void AnimationMixer::remove_animation_library(const StringName &p_name) {322int at_pos = -1;323324for (uint32_t i = 0; i < animation_libraries.size(); i++) {325if (animation_libraries[i].name == p_name) {326at_pos = i;327break;328}329}330331ERR_FAIL_COND(at_pos == -1);332333animation_libraries[at_pos].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added));334animation_libraries[at_pos].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed));335animation_libraries[at_pos].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed));336animation_libraries[at_pos].library->disconnect(SceneStringName(animation_changed), callable_mp(this, &AnimationMixer::_animation_changed));337338animation_libraries.remove_at(at_pos);339_animation_set_cache_update();340341notify_property_list_changed();342}343344void AnimationMixer::rename_animation_library(const StringName &p_name, const StringName &p_new_name) {345if (p_name == p_new_name) {346return;347}348#ifdef DEBUG_ENABLED349ERR_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) + ".");350#endif351352bool found = false;353for (AnimationLibraryData &lib : animation_libraries) {354ERR_FAIL_COND_MSG(lib.name == p_new_name, "Can't rename animation library to another existing name: " + String(p_new_name) + ".");355if (lib.name == p_name) {356found = true;357lib.name = p_new_name;358// rename connections359lib.library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added));360lib.library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed));361lib.library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed));362363lib.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationMixer::_animation_added).bind(p_new_name));364lib.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationMixer::_animation_removed).bind(p_new_name));365lib.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationMixer::_animation_renamed).bind(p_new_name));366367for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) {368StringName old_name = p_name == StringName() ? K.key : StringName(String(p_name) + "/" + String(K.key));369StringName new_name = p_new_name == StringName() ? K.key : StringName(String(p_new_name) + "/" + String(K.key));370_rename_animation(old_name, new_name);371}372}373}374375ERR_FAIL_COND(!found);376377animation_libraries.sort(); // Must keep alphabetical order.378379_animation_set_cache_update(); // Update cache.380381notify_property_list_changed();382}383384void AnimationMixer::get_animation_list(List<StringName> *p_animations) const {385List<String> anims;386for (const KeyValue<StringName, AnimationData> &E : animation_set) {387anims.push_back(E.key);388}389anims.sort();390for (const String &E : anims) {391p_animations->push_back(E);392}393}394395Ref<Animation> AnimationMixer::get_animation(const StringName &p_name) const {396ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref<Animation>(), vformat("Animation not found: \"%s\".", p_name));397const AnimationData &anim_data = animation_set[p_name];398return anim_data.animation;399}400401bool AnimationMixer::has_animation(const StringName &p_name) const {402return animation_set.has(p_name);403}404405StringName AnimationMixer::find_animation(const Ref<Animation> &p_animation) const {406for (const KeyValue<StringName, AnimationData> &E : animation_set) {407if (E.value.animation == p_animation) {408return E.key;409}410}411return StringName();412}413414/* -------------------------------------------- */415/* -- General settings for animation ---------- */416/* -------------------------------------------- */417418void AnimationMixer::_set_process(bool p_process, bool p_force) {419if (processing == p_process && !p_force) {420return;421}422423switch (callback_mode_process) {424case ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS:425#ifdef TOOLS_ENABLED426set_physics_process_internal(p_process && active && !editing);427#else428set_physics_process_internal(p_process && active);429#endif // TOOLS_ENABLED430break;431case ANIMATION_CALLBACK_MODE_PROCESS_IDLE:432#ifdef TOOLS_ENABLED433set_process_internal(p_process && active && !editing);434#else435set_process_internal(p_process && active);436#endif // TOOLS_ENABLED437break;438case ANIMATION_CALLBACK_MODE_PROCESS_MANUAL:439break;440}441442processing = p_process;443}444445void AnimationMixer::set_active(bool p_active) {446if (active == p_active) {447return;448}449450active = p_active;451_set_active(active);452_set_process(processing, true);453454if (!active && is_inside_tree()) {455_clear_caches();456}457}458459bool AnimationMixer::is_active() const {460return active;461}462463void AnimationMixer::set_root_node(const NodePath &p_path) {464root_node = p_path;465_clear_caches();466}467468NodePath AnimationMixer::get_root_node() const {469return root_node;470}471472void AnimationMixer::set_deterministic(bool p_deterministic) {473deterministic = p_deterministic;474_clear_caches();475}476477bool AnimationMixer::is_deterministic() const {478return deterministic;479}480481void AnimationMixer::set_callback_mode_process(AnimationCallbackModeProcess p_mode) {482if (callback_mode_process == p_mode) {483return;484}485486bool was_active = is_active();487if (was_active) {488set_active(false);489}490491callback_mode_process = p_mode;492493if (was_active) {494set_active(true);495}496}497498AnimationMixer::AnimationCallbackModeProcess AnimationMixer::get_callback_mode_process() const {499return callback_mode_process;500}501502void AnimationMixer::set_callback_mode_method(AnimationCallbackModeMethod p_mode) {503callback_mode_method = p_mode;504emit_signal(SNAME("mixer_updated"));505}506507AnimationMixer::AnimationCallbackModeMethod AnimationMixer::get_callback_mode_method() const {508return callback_mode_method;509}510511void AnimationMixer::set_callback_mode_discrete(AnimationCallbackModeDiscrete p_mode) {512callback_mode_discrete = p_mode;513_clear_caches();514emit_signal(SNAME("mixer_updated"));515}516517AnimationMixer::AnimationCallbackModeDiscrete AnimationMixer::get_callback_mode_discrete() const {518return callback_mode_discrete;519}520521void AnimationMixer::set_audio_max_polyphony(int p_audio_max_polyphony) {522ERR_FAIL_COND(p_audio_max_polyphony < 0 || p_audio_max_polyphony > 128);523audio_max_polyphony = p_audio_max_polyphony;524}525526int AnimationMixer::get_audio_max_polyphony() const {527return audio_max_polyphony;528}529530#ifdef TOOLS_ENABLED531void AnimationMixer::set_editing(bool p_editing) {532if (editing == p_editing) {533return;534}535536editing = p_editing;537_set_process(processing, true);538539if (editing && is_inside_tree()) {540_clear_caches();541}542543notify_property_list_changed(); // To make active readonly.544}545546bool AnimationMixer::is_editing() const {547return editing;548}549550void AnimationMixer::set_dummy(bool p_dummy) {551dummy = p_dummy;552}553554bool AnimationMixer::is_dummy() const {555return dummy;556}557#endif // TOOLS_ENABLED558559/* -------------------------------------------- */560/* -- Caches for blending --------------------- */561/* -------------------------------------------- */562563void AnimationMixer::_clear_caches() {564_init_root_motion_cache();565_clear_audio_streams();566_clear_playing_caches();567for (KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {568memdelete(K.value);569}570track_cache.clear();571animation_track_num_to_track_cache.clear();572cache_valid = false;573capture_cache.clear();574575emit_signal(SNAME("caches_cleared"));576}577578void AnimationMixer::_clear_audio_streams() {579for (int i = 0; i < playing_audio_stream_players.size(); i++) {580playing_audio_stream_players[i]->call(SNAME("stop"));581playing_audio_stream_players[i]->call(SNAME("set_stream"), Ref<AudioStream>());582}583playing_audio_stream_players.clear();584}585586void AnimationMixer::_clear_playing_caches() {587for (const TrackCache *E : playing_caches) {588Object *t_obj = ObjectDB::get_instance(E->object_id);589if (t_obj) {590t_obj->call(SNAME("stop"), true);591}592}593playing_caches.clear();594}595596void AnimationMixer::_init_root_motion_cache() {597root_motion_cache.loc = Vector3(0, 0, 0);598root_motion_cache.rot = Quaternion(0, 0, 0, 1);599root_motion_cache.scale = Vector3(1, 1, 1);600root_motion_position = Vector3(0, 0, 0);601root_motion_rotation = Quaternion(0, 0, 0, 1);602root_motion_scale = Vector3(0, 0, 0);603root_motion_position_accumulator = Vector3(0, 0, 0);604root_motion_rotation_accumulator = Quaternion(0, 0, 0, 1);605root_motion_scale_accumulator = Vector3(1, 1, 1);606}607608void AnimationMixer::_create_track_num_to_track_cache_for_animation(Ref<Animation> &p_animation) {609if (animation_track_num_to_track_cache.has(p_animation)) {610// In AnimationMixer::_update_caches, it retrieves all animations via AnimationMixer::get_animation_list611// Since multiple AnimationLibraries can share the same Animation, it is possible that the cache is already created.612return;613}614LocalVector<TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache.insert_new(p_animation, LocalVector<TrackCache *>())->value;615const Vector<Animation::Track *> &tracks = p_animation->get_tracks();616617track_num_to_track_cache.resize(tracks.size());618for (int i = 0; i < tracks.size(); i++) {619TrackCache **track_ptr = track_cache.getptr(tracks[i]->thash);620if (track_ptr == nullptr) {621track_num_to_track_cache[i] = nullptr;622} else {623track_num_to_track_cache[i] = *track_ptr;624}625}626}627628bool AnimationMixer::_update_caches() {629setup_pass++;630631root_motion_cache.loc = Vector3(0, 0, 0);632root_motion_cache.rot = Quaternion(0, 0, 0, 1);633root_motion_cache.scale = Vector3(1, 1, 1);634635List<StringName> sname_list;636get_animation_list(&sname_list);637638bool check_path = GLOBAL_GET_CACHED(bool, "animation/warnings/check_invalid_track_paths");639bool check_angle_interpolation = GLOBAL_GET_CACHED(bool, "animation/warnings/check_angle_interpolation_type_conflicting");640641Node *parent = get_node_or_null(root_node);642if (!parent) {643cache_valid = false;644return false;645}646647#ifdef TOOLS_ENABLED648String mixer_name = "AnimationMixer";649const Node *owner = get_owner();650if (owner) {651const String scene_path = owner->get_scene_file_path();652if (!scene_path.is_empty()) {653mixer_name += vformat(" (at: %s)", scene_path.get_file());654}655}656#else657const String mixer_name = "AnimationMixer";658#endif659660Ref<Animation> reset_anim;661bool has_reset_anim = has_animation(SceneStringName(RESET));662if (has_reset_anim) {663reset_anim = get_animation(SceneStringName(RESET));664}665for (const StringName &E : sname_list) {666Ref<Animation> anim = get_animation(E);667for (int i = 0; i < anim->get_track_count(); i++) {668NodePath path = anim->track_get_path(i);669Animation::TypeHash thash = anim->track_get_type_hash(i);670Animation::TrackType track_src_type = anim->track_get_type(i);671Animation::TrackType track_cache_type = Animation::get_cache_type(track_src_type);672673TrackCache *track = nullptr;674if (track_cache.has(thash)) {675track = track_cache.get(thash);676}677678// If not valid, delete track.679if (track && (track->type != track_cache_type || ObjectDB::get_instance(track->object_id) == nullptr)) {680playing_caches.erase(track);681memdelete(track);682track_cache.erase(thash);683track = nullptr;684}685686if (!track) {687Ref<Resource> resource;688Vector<StringName> leftover_path;689690Node *child = parent->get_node_and_resource(path, resource, leftover_path);691if (!child) {692if (check_path) {693WARN_PRINT_ED(mixer_name + ": '" + String(E) + "', couldn't resolve track: '" + String(path) + "'. This warning can be disabled in Project Settings.");694}695continue;696}697698switch (track_src_type) {699case Animation::TYPE_BEZIER:700case Animation::TYPE_VALUE: {701// If a value track without a key is cached first, the initial value cannot be determined.702// It is a corner case, but which may cause problems with blending.703ERR_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.");704705TrackCacheValue *track_value = memnew(TrackCacheValue);706707if (resource.is_valid()) {708track_value->object_id = resource->get_instance_id();709} else {710track_value->object_id = child->get_instance_id();711}712713track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;714715track_value->subpath = leftover_path;716717track = track_value;718719bool is_value = track_src_type == Animation::TYPE_VALUE;720721track_value->init_value = is_value ? anim->track_get_key_value(i, 0) : (anim->track_get_key_value(i, 0).operator Array())[0];722track_value->init_value.zero();723724track_value->is_init = false;725726// Can't interpolate them, need to convert.727track_value->is_variant_interpolatable = Animation::is_variant_interpolatable(track_value->init_value);728729// If there is a Reset Animation, it takes precedence by overwriting.730if (has_reset_anim) {731int rt = reset_anim->find_track(path, track_src_type);732if (rt >= 0) {733if (is_value) {734if (reset_anim->track_get_key_count(rt) > 0) {735track_value->init_value = reset_anim->track_get_key_value(rt, 0);736}737} else {738if (reset_anim->track_get_key_count(rt) > 0) {739track_value->init_value = (reset_anim->track_get_key_value(rt, 0).operator Array())[0];740}741}742}743}744745if (is_value && callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {746if (child) {747PropertyInfo prop_info;748ClassDB::get_property_info(child->get_class_name(), path.get_concatenated_subnames(), &prop_info);749if (prop_info.hint == PROPERTY_HINT_ONESHOT) {750WARN_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)));751}752}753}754} break;755case Animation::TYPE_POSITION_3D:756case Animation::TYPE_ROTATION_3D:757case Animation::TYPE_SCALE_3D: {758#ifndef _3D_DISABLED759Node3D *node_3d = Object::cast_to<Node3D>(child);760761if (!node_3d) {762ERR_PRINT(mixer_name + ": '" + String(E) + "', transform track does not point to Node3D: '" + String(path) + "'.");763continue;764}765766TrackCacheTransform *track_xform = memnew(TrackCacheTransform);767track_xform->type = Animation::TYPE_POSITION_3D;768769track_xform->bone_idx = -1;770771bool has_rest = false;772Skeleton3D *sk = Object::cast_to<Skeleton3D>(node_3d);773if (sk && path.get_subname_count() == 1) {774track_xform->skeleton_id = sk->get_instance_id();775int bone_idx = sk->find_bone(path.get_subname(0));776if (bone_idx != -1) {777has_rest = true;778track_xform->bone_idx = bone_idx;779Transform3D rest = sk->get_bone_rest(bone_idx);780track_xform->init_loc = rest.origin;781track_xform->init_rot = rest.basis.get_rotation_quaternion();782track_xform->init_scale = rest.basis.get_scale();783}784}785786track_xform->object_id = node_3d->get_instance_id();787788track = track_xform;789790switch (track_src_type) {791case Animation::TYPE_POSITION_3D: {792track_xform->loc_used = true;793} break;794case Animation::TYPE_ROTATION_3D: {795track_xform->rot_used = true;796} break;797case Animation::TYPE_SCALE_3D: {798track_xform->scale_used = true;799} break;800default: {801}802}803804// For non Skeleton3D bone animation.805if (has_reset_anim && !has_rest) {806int rt = reset_anim->find_track(path, track_src_type);807if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {808switch (track_src_type) {809case Animation::TYPE_POSITION_3D: {810track_xform->init_loc = reset_anim->track_get_key_value(rt, 0);811} break;812case Animation::TYPE_ROTATION_3D: {813track_xform->init_rot = reset_anim->track_get_key_value(rt, 0);814} break;815case Animation::TYPE_SCALE_3D: {816track_xform->init_scale = reset_anim->track_get_key_value(rt, 0);817} break;818default: {819}820}821}822}823#endif // _3D_DISABLED824} break;825case Animation::TYPE_BLEND_SHAPE: {826#ifndef _3D_DISABLED827if (path.get_subname_count() != 1) {828ERR_PRINT(mixer_name + ": '" + String(E) + "', blend shape track does not contain a blend shape subname: '" + String(path) + "'.");829continue;830}831MeshInstance3D *mesh_3d = Object::cast_to<MeshInstance3D>(child);832833if (!mesh_3d) {834ERR_PRINT(mixer_name + ": '" + String(E) + "', blend shape track does not point to MeshInstance3D: '" + String(path) + "'.");835continue;836}837838StringName blend_shape_name = path.get_subname(0);839int blend_shape_idx = mesh_3d->find_blend_shape_by_name(blend_shape_name);840if (blend_shape_idx == -1) {841ERR_PRINT(mixer_name + ": '" + String(E) + "', blend shape track points to a non-existing name: '" + String(blend_shape_name) + "'.");842continue;843}844845TrackCacheBlendShape *track_bshape = memnew(TrackCacheBlendShape);846847track_bshape->shape_index = blend_shape_idx;848track_bshape->object_id = mesh_3d->get_instance_id();849track = track_bshape;850851if (has_reset_anim) {852int rt = reset_anim->find_track(path, track_src_type);853if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {854track_bshape->init_value = reset_anim->track_get_key_value(rt, 0);855}856}857#endif858} break;859case Animation::TYPE_METHOD: {860TrackCacheMethod *track_method = memnew(TrackCacheMethod);861862if (resource.is_valid()) {863track_method->object_id = resource->get_instance_id();864} else {865track_method->object_id = child->get_instance_id();866}867868track = track_method;869870} break;871case Animation::TYPE_AUDIO: {872TrackCacheAudio *track_audio = memnew(TrackCacheAudio);873874track_audio->object_id = child->get_instance_id();875track_audio->audio_stream.instantiate();876track_audio->audio_stream->set_polyphony(audio_max_polyphony);877track_audio->playback_type = (AudioServer::PlaybackType)(int)(child->call(SNAME("get_playback_type")));878track_audio->bus = (StringName)(child->call(SNAME("get_bus")));879880track = track_audio;881882} break;883case Animation::TYPE_ANIMATION: {884TrackCacheAnimation *track_animation = memnew(TrackCacheAnimation);885886track_animation->object_id = child->get_instance_id();887888track = track_animation;889890} break;891default: {892ERR_PRINT("Animation corrupted (invalid track type).");893continue;894}895}896track->path = path;897track_cache[thash] = track;898} else if (track_cache_type == Animation::TYPE_POSITION_3D) {899TrackCacheTransform *track_xform = static_cast<TrackCacheTransform *>(track);900if (track->setup_pass != setup_pass) {901track_xform->loc_used = false;902track_xform->rot_used = false;903track_xform->scale_used = false;904}905switch (track_src_type) {906case Animation::TYPE_POSITION_3D: {907track_xform->loc_used = true;908} break;909case Animation::TYPE_ROTATION_3D: {910track_xform->rot_used = true;911} break;912case Animation::TYPE_SCALE_3D: {913track_xform->scale_used = true;914} break;915default: {916}917}918} else if (track_cache_type == Animation::TYPE_VALUE) {919TrackCacheValue *track_value = static_cast<TrackCacheValue *>(track);920// If it has at least one angle interpolation, it also uses angle interpolation for blending.921bool was_using_angle = track_value->is_using_angle;922if (track_src_type == Animation::TYPE_VALUE) {923if (track_value->init_value.is_string() && anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE) {924WARN_PRINT_ONCE_ED(mixer_name + ": '" + String(E) + "', Value Track: '" + String(path) + "' blends String types. This is an experimental algorithm.");925}926track_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;927}928if (check_angle_interpolation && (was_using_angle != track_value->is_using_angle)) {929WARN_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.");930}931}932933track->setup_pass = setup_pass;934}935}936937List<Animation::TypeHash> to_delete;938939for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {940if (K.value->setup_pass != setup_pass) {941to_delete.push_back(K.key);942}943}944945while (to_delete.front()) {946Animation::TypeHash thash = to_delete.front()->get();947memdelete(track_cache[thash]);948track_cache.erase(thash);949to_delete.pop_front();950}951952track_map.clear();953954int idx = 0;955for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {956track_map[K.value->path] = idx;957idx++;958}959960for (KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {961K.value->blend_idx = track_map[K.value->path];962}963964animation_track_num_to_track_cache.clear();965for (const StringName &E : sname_list) {966Ref<Animation> anim = get_animation(E);967_create_track_num_to_track_cache_for_animation(anim);968}969970track_count = idx;971972cache_valid = true;973974return true;975}976977/* -------------------------------------------- */978/* -- Blending processor ---------------------- */979/* -------------------------------------------- */980981void AnimationMixer::_process_animation(double p_delta, bool p_update_only) {982_blend_init();983if (_blend_pre_process(p_delta, track_count, track_map)) {984_blend_capture(p_delta);985_blend_calc_total_weight();986_blend_process(p_delta, p_update_only);987_blend_apply();988_blend_post_process();989emit_signal(SNAME("mixer_applied"));990};991clear_animation_instances();992}993994Variant 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) {995#ifndef _3D_DISABLED996switch (p_anim->track_get_type(p_track)) {997case Animation::TYPE_POSITION_3D: {998if (p_object_sub_idx >= 0) {999Skeleton3D *skel = ObjectDB::get_instance<Skeleton3D>(p_object_id);1000if (skel) {1001return Vector3(p_value) * skel->get_motion_scale();1002}1003}1004return p_value;1005} break;1006default: {1007} break;1008}1009#endif // _3D_DISABLED1010return p_value;1011}10121013Variant 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) {1014if (is_GDVIRTUAL_CALL_post_process_key_value) {1015Variant res;1016if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, p_object_id, p_object_sub_idx, res)) {1017return res;1018}1019is_GDVIRTUAL_CALL_post_process_key_value = false;1020}1021return _post_process_key_value(p_anim, p_track, p_value, p_object_id, p_object_sub_idx);1022}10231024void AnimationMixer::_blend_init() {1025// Check all tracks, see if they need modification.1026root_motion_position = Vector3(0, 0, 0);1027root_motion_rotation = Quaternion(0, 0, 0, 1);1028root_motion_scale = Vector3(0, 0, 0);1029root_motion_position_accumulator = Vector3(0, 0, 0);1030root_motion_rotation_accumulator = Quaternion(0, 0, 0, 1);1031root_motion_scale_accumulator = Vector3(1, 1, 1);10321033if (!cache_valid) {1034if (!_update_caches()) {1035return;1036}1037}10381039// Init all value/transform/blend/bezier tracks that track_cache has.1040for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {1041TrackCache *track = K.value;10421043track->total_weight = 0.0;10441045switch (track->type) {1046case Animation::TYPE_POSITION_3D: {1047TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1048if (track->root_motion) {1049root_motion_cache.loc = Vector3(0, 0, 0);1050root_motion_cache.rot = Quaternion(0, 0, 0, 1);1051root_motion_cache.scale = Vector3(1, 1, 1);1052}1053t->loc = t->init_loc;1054t->rot = t->init_rot;1055t->scale = t->init_scale;1056} break;1057case Animation::TYPE_BLEND_SHAPE: {1058TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);1059t->value = t->init_value;1060} break;1061case Animation::TYPE_VALUE: {1062TrackCacheValue *t = static_cast<TrackCacheValue *>(track);1063t->value = Animation::cast_to_blendwise(t->init_value);1064t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0;1065t->use_continuous = false;1066t->use_discrete = false;1067} break;1068case Animation::TYPE_AUDIO: {1069TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);1070for (KeyValue<ObjectID, PlayingAudioTrackInfo> &L : t->playing_streams) {1071PlayingAudioTrackInfo &track_info = L.value;1072track_info.volume = 0.0;1073}1074} break;1075default: {1076} break;1077}1078}1079}10801081bool AnimationMixer::_blend_pre_process(double p_delta, int p_track_count, const AHashMap<NodePath, int> &p_track_map) {1082return true;1083}10841085void AnimationMixer::_blend_post_process() {1086//1087}10881089void AnimationMixer::_blend_capture(double p_delta) {1090blend_capture(p_delta);1091}10921093void AnimationMixer::blend_capture(double p_delta) {1094if (capture_cache.animation.is_null()) {1095return;1096}10971098capture_cache.remain -= p_delta * capture_cache.step;1099if (Animation::is_less_or_equal_approx(capture_cache.remain, 0)) {1100if (capture_cache.animation.is_valid()) {1101animation_track_num_to_track_cache.erase(capture_cache.animation);1102}1103capture_cache.clear();1104return;1105}11061107real_t weight = Tween::run_equation(capture_cache.trans_type, capture_cache.ease_type, capture_cache.remain, 0.0, 1.0, 1.0);11081109// Blend with other animations.1110real_t inv = 1.0 - weight;1111for (AnimationInstance &ai : animation_instances) {1112ai.playback_info.weight *= inv;1113}11141115// Build capture animation instance.1116AnimationData ad;1117ad.animation = capture_cache.animation;11181119PlaybackInfo pi;1120pi.weight = weight;11211122AnimationInstance ai;1123ai.animation_data = ad;1124ai.playback_info = pi;11251126animation_instances.push_back(ai);1127}11281129void AnimationMixer::_blend_calc_total_weight() {1130for (const AnimationInstance &ai : animation_instances) {1131Ref<Animation> a = ai.animation_data.animation;1132real_t weight = ai.playback_info.weight;1133const real_t *track_weights_ptr = ai.playback_info.track_weights.ptr();1134int track_weights_count = ai.playback_info.track_weights.size();1135ERR_CONTINUE_EDMSG(!animation_track_num_to_track_cache.has(a), "No animation in cache.");1136LocalVector<TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache[a];1137thread_local HashSet<Animation::TypeHash, HashHasher> processed_hashes;1138processed_hashes.clear();1139const Vector<Animation::Track *> tracks = a->get_tracks();1140Animation::Track *const *tracks_ptr = tracks.ptr();1141int count = tracks.size();1142for (int i = 0; i < count; i++) {1143Animation::Track *animation_track = tracks_ptr[i];1144if (!animation_track->enabled) {1145continue;1146}1147Animation::TypeHash thash = animation_track->thash;1148TrackCache *track = track_num_to_track_cache[i];1149if (track == nullptr || processed_hashes.has(thash)) {1150// No path, but avoid error spamming.1151// Or, there is the case different track type with same path; These can be distinguished by hash. So don't add the weight doubly.1152continue;1153}1154int blend_idx = track->blend_idx;1155ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);1156real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;1157track->total_weight += blend;1158processed_hashes.insert(thash);1159}1160}1161}11621163void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {1164// Apply value/transform/blend/bezier blends to track caches and execute method/audio/animation tracks.1165#ifdef TOOLS_ENABLED1166bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint();1167#endif // TOOLS_ENABLED1168for (const AnimationInstance &ai : animation_instances) {1169Ref<Animation> a = ai.animation_data.animation;1170double time = ai.playback_info.time;1171double delta = ai.playback_info.delta;1172double start = ai.playback_info.start;1173double end = ai.playback_info.end;1174bool seeked = ai.playback_info.seeked;1175Animation::LoopedFlag looped_flag = ai.playback_info.looped_flag;1176bool is_external_seeking = ai.playback_info.is_external_seeking;1177real_t weight = ai.playback_info.weight;1178const real_t *track_weights_ptr = ai.playback_info.track_weights.ptr();1179int track_weights_count = ai.playback_info.track_weights.size();1180bool backward = std::signbit(delta); // This flag is used by the root motion calculates or detecting the end of audio stream.1181bool seeked_backward = std::signbit(p_delta);1182#ifndef _3D_DISABLED1183bool calc_root = !seeked || is_external_seeking;1184#endif // _3D_DISABLED1185ERR_CONTINUE_EDMSG(!animation_track_num_to_track_cache.has(a), "No animation in cache.");1186LocalVector<TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache[a];1187const Vector<Animation::Track *> tracks = a->get_tracks();1188Animation::Track *const *tracks_ptr = tracks.ptr();1189real_t a_length = a->get_length();1190int count = tracks.size();1191for (int i = 0; i < count; i++) {1192const Animation::Track *animation_track = tracks_ptr[i];1193if (!animation_track->enabled) {1194continue;1195}1196TrackCache *track = track_num_to_track_cache[i];1197if (track == nullptr) {1198continue; // No path, but avoid error spamming.1199}1200int blend_idx = track->blend_idx;1201ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);1202real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;1203if (!deterministic) {1204// If non-deterministic, do normalization.1205// It would be better to make this if statement outside the for loop, but come here since too much code...1206if (Math::is_zero_approx(track->total_weight)) {1207continue;1208}1209blend = blend / track->total_weight;1210}1211Animation::TrackType ttype = animation_track->type;1212track->root_motion = root_motion_track == animation_track->path;1213switch (ttype) {1214case Animation::TYPE_POSITION_3D: {1215#ifndef _3D_DISABLED1216if (Math::is_zero_approx(blend)) {1217continue; // Nothing to blend.1218}1219TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1220if (track->root_motion && calc_root) {1221int rot_track = -1;1222if (root_motion_local) {1223rot_track = a->find_track(a->track_get_path(i), Animation::TYPE_ROTATION_3D);1224}1225double prev_time = time - delta;1226if (!backward) {1227if (Animation::is_less_approx(prev_time, start)) {1228switch (a->get_loop_mode()) {1229case Animation::LOOP_NONE: {1230prev_time = start;1231} break;1232case Animation::LOOP_LINEAR: {1233prev_time = Math::fposmod(prev_time - start, end - start) + start;1234} break;1235case Animation::LOOP_PINGPONG: {1236prev_time = Math::pingpong(prev_time - start, end - start) + start;1237} break;1238default:1239break;1240}1241}1242} else {1243if (Animation::is_greater_approx(prev_time, end)) {1244switch (a->get_loop_mode()) {1245case Animation::LOOP_NONE: {1246prev_time = end;1247} break;1248case Animation::LOOP_LINEAR: {1249prev_time = Math::fposmod(prev_time - start, end - start) + start;1250} break;1251case Animation::LOOP_PINGPONG: {1252prev_time = Math::pingpong(prev_time - start, end - start) + start;1253} break;1254default:1255break;1256}1257}1258}1259if (rot_track >= 0) {1260Vector3 loc[2];1261Quaternion rot;1262if (!backward) {1263if (Animation::is_greater_approx(prev_time, time)) {1264Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1265if (err != OK) {1266continue;1267}1268loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1269a->try_position_track_interpolate(i, end, &loc[1]);1270loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);12711272a->try_rotation_track_interpolate(rot_track, end, &rot);1273rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);12741275root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;1276prev_time = start;1277}1278} else {1279if (Animation::is_less_approx(prev_time, time)) {1280Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1281if (err != OK) {1282continue;1283}1284loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1285a->try_position_track_interpolate(i, start, &loc[1]);1286loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);12871288a->try_rotation_track_interpolate(rot_track, start, &rot);1289rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);12901291root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;1292prev_time = end;1293}1294}1295Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1296if (err != OK) {1297continue;1298}1299loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1300a->try_position_track_interpolate(i, time, &loc[1]);1301loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);13021303a->try_rotation_track_interpolate(rot_track, time, &rot);1304rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);13051306root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;1307prev_time = !backward ? start : end;1308} else {1309Vector3 loc[2];1310if (!backward) {1311if (Animation::is_greater_approx(prev_time, time)) {1312Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1313if (err != OK) {1314continue;1315}1316loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1317a->try_position_track_interpolate(i, end, &loc[1]);1318loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);1319root_motion_cache.loc += (loc[1] - loc[0]) * blend;1320prev_time = start;1321}1322} else {1323if (Animation::is_less_approx(prev_time, time)) {1324Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1325if (err != OK) {1326continue;1327}1328loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1329a->try_position_track_interpolate(i, start, &loc[1]);1330loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);1331root_motion_cache.loc += (loc[1] - loc[0]) * blend;1332prev_time = end;1333}1334}1335Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);1336if (err != OK) {1337continue;1338}1339loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);1340a->try_position_track_interpolate(i, time, &loc[1]);1341loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);1342root_motion_cache.loc += (loc[1] - loc[0]) * blend;1343prev_time = !backward ? start : end;1344}1345}1346{1347Vector3 loc;1348Error err = a->try_position_track_interpolate(i, time, &loc);1349if (err != OK) {1350continue;1351}1352loc = post_process_key_value(a, i, loc, t->object_id, t->bone_idx);1353t->loc += (loc - t->init_loc) * blend;1354}1355#endif // _3D_DISABLED1356} break;1357case Animation::TYPE_ROTATION_3D: {1358#ifndef _3D_DISABLED1359if (Math::is_zero_approx(blend)) {1360continue; // Nothing to blend.1361}1362TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1363if (track->root_motion && calc_root) {1364double prev_time = time - delta;1365if (!backward) {1366if (Animation::is_less_approx(prev_time, start)) {1367switch (a->get_loop_mode()) {1368case Animation::LOOP_NONE: {1369prev_time = start;1370} break;1371case Animation::LOOP_LINEAR: {1372prev_time = Math::fposmod(prev_time - start, end - start) + start;1373} break;1374case Animation::LOOP_PINGPONG: {1375prev_time = Math::pingpong(prev_time - start, end - start) + start;1376} break;1377default:1378break;1379}1380}1381} else {1382if (Animation::is_greater_approx(prev_time, end)) {1383switch (a->get_loop_mode()) {1384case Animation::LOOP_NONE: {1385prev_time = end;1386} break;1387case Animation::LOOP_LINEAR: {1388prev_time = Math::fposmod(prev_time - start, end - start) + start;1389} break;1390case Animation::LOOP_PINGPONG: {1391prev_time = Math::pingpong(prev_time - start, end - start) + start;1392} break;1393default:1394break;1395}1396}1397}1398Quaternion rot[2];1399if (!backward) {1400if (Animation::is_greater_approx(prev_time, time)) {1401Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);1402if (err != OK) {1403continue;1404}1405rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);1406a->try_rotation_track_interpolate(i, end, &rot[1]);1407rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);1408root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();1409prev_time = start;1410}1411} else {1412if (Animation::is_less_approx(prev_time, time)) {1413Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);1414if (err != OK) {1415continue;1416}1417rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);1418a->try_rotation_track_interpolate(i, start, &rot[1]);1419rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);1420root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();1421prev_time = end;1422}1423}1424Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]);1425if (err != OK) {1426continue;1427}1428rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);1429a->try_rotation_track_interpolate(i, time, &rot[1]);1430rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);1431root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();1432prev_time = !backward ? start : end;1433}1434{1435Quaternion rot;1436Error err = a->try_rotation_track_interpolate(i, time, &rot);1437if (err != OK) {1438continue;1439}1440rot = post_process_key_value(a, i, rot, t->object_id, t->bone_idx);1441t->rot = (t->rot * Quaternion().slerp(t->init_rot.inverse() * rot, blend)).normalized();1442}1443#endif // _3D_DISABLED1444} break;1445case Animation::TYPE_SCALE_3D: {1446#ifndef _3D_DISABLED1447if (Math::is_zero_approx(blend)) {1448continue; // Nothing to blend.1449}1450TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);1451if (track->root_motion && calc_root) {1452double prev_time = time - delta;1453if (!backward) {1454if (Animation::is_less_approx(prev_time, start)) {1455switch (a->get_loop_mode()) {1456case Animation::LOOP_NONE: {1457prev_time = start;1458} break;1459case Animation::LOOP_LINEAR: {1460prev_time = Math::fposmod(prev_time - start, end - start) + start;1461} break;1462case Animation::LOOP_PINGPONG: {1463prev_time = Math::pingpong(prev_time - start, end - start) + start;1464} break;1465default:1466break;1467}1468}1469} else {1470if (Animation::is_greater_approx(prev_time, end)) {1471switch (a->get_loop_mode()) {1472case Animation::LOOP_NONE: {1473prev_time = end;1474} break;1475case Animation::LOOP_LINEAR: {1476prev_time = Math::fposmod(prev_time - start, end - start) + start;1477} break;1478case Animation::LOOP_PINGPONG: {1479prev_time = Math::pingpong(prev_time - start, end - start) + start;1480} break;1481default:1482break;1483}1484}1485}1486Vector3 scale[2];1487if (!backward) {1488if (Animation::is_greater_approx(prev_time, time)) {1489Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);1490if (err != OK) {1491continue;1492}1493scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);1494a->try_scale_track_interpolate(i, end, &scale[1]);1495scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);1496root_motion_cache.scale += (scale[1] - scale[0]) * blend;1497prev_time = start;1498}1499} else {1500if (Animation::is_less_approx(prev_time, time)) {1501Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);1502if (err != OK) {1503continue;1504}1505scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);1506a->try_scale_track_interpolate(i, start, &scale[1]);1507scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);1508root_motion_cache.scale += (scale[1] - scale[0]) * blend;1509prev_time = end;1510}1511}1512Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]);1513if (err != OK) {1514continue;1515}1516scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);1517a->try_scale_track_interpolate(i, time, &scale[1]);1518scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);1519root_motion_cache.scale += (scale[1] - scale[0]) * blend;1520prev_time = !backward ? start : end;1521}1522{1523Vector3 scale;1524Error err = a->try_scale_track_interpolate(i, time, &scale);1525if (err != OK) {1526continue;1527}1528scale = post_process_key_value(a, i, scale, t->object_id, t->bone_idx);1529t->scale += (scale - t->init_scale) * blend;1530}1531#endif // _3D_DISABLED1532} break;1533case Animation::TYPE_BLEND_SHAPE: {1534#ifndef _3D_DISABLED1535if (Math::is_zero_approx(blend)) {1536continue; // Nothing to blend.1537}1538TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);1539float value;1540Error err = a->try_blend_shape_track_interpolate(i, time, &value);1541//ERR_CONTINUE(err!=OK); //used for testing, should be removed1542if (err != OK) {1543continue;1544}1545value = post_process_key_value(a, i, value, t->object_id, t->shape_index);1546t->value += (value - t->init_value) * blend;1547#endif // _3D_DISABLED1548} break;1549case Animation::TYPE_BEZIER:1550case Animation::TYPE_VALUE: {1551if (Math::is_zero_approx(blend)) {1552continue; // Nothing to blend.1553}1554TrackCacheValue *t = static_cast<TrackCacheValue *>(track);1555bool is_value = ttype == Animation::TYPE_VALUE;1556bool is_discrete = is_value && a->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE;1557bool force_continuous = callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS;1558if (!is_discrete || force_continuous) {1559t->use_continuous = true;15601561Variant value;1562if (t->is_variant_interpolatable) {1563value = is_value ? a->value_track_interpolate(i, time, is_discrete && force_continuous ? backward : false) : Variant(a->bezier_track_interpolate(i, time));1564value = post_process_key_value(a, i, value, t->object_id);1565if (value == Variant()) {1566continue;1567}1568} else {1569// Discrete track sets the value in the current _blend_process() function,1570// but Force Continuous track does not set the value here because the value must be set in the _blend_apply() function later.1571int idx = a->track_find_key(i, time, Animation::FIND_MODE_NEAREST, false, backward);1572if (idx < 0) {1573continue;1574}1575value = a->track_get_key_value(i, idx);1576value = post_process_key_value(a, i, value, t->object_id);1577if (value == Variant()) {1578continue;1579}1580t->value = value;1581continue;1582}15831584// Special case for angle interpolation.1585if (t->is_using_angle) {1586// For blending consistency, it prevents rotation of more than 180 degrees from init_value.1587// This is the same as for Quaternion blends.1588float rot_a = t->value;1589float rot_b = value;1590float rot_init = t->init_value;1591rot_a = Math::fposmod(rot_a, (float)Math::TAU);1592rot_b = Math::fposmod(rot_b, (float)Math::TAU);1593rot_init = Math::fposmod(rot_init, (float)Math::TAU);1594if (rot_init < Math::PI) {1595rot_a = rot_a > rot_init + Math::PI ? rot_a - Math::TAU : rot_a;1596rot_b = rot_b > rot_init + Math::PI ? rot_b - Math::TAU : rot_b;1597} else {1598rot_a = rot_a < rot_init - Math::PI ? rot_a + Math::TAU : rot_a;1599rot_b = rot_b < rot_init - Math::PI ? rot_b + Math::TAU : rot_b;1600}1601t->value = Math::fposmod(rot_a + (rot_b - rot_init) * (float)blend, (float)Math::TAU);1602} else {1603value = Animation::cast_to_blendwise(value);1604if (t->init_value.is_array()) {1605t->element_size = MAX(t->element_size.operator int(), (value.operator Array()).size());1606} else if (t->init_value.is_string()) {1607real_t length = Animation::subtract_variant((real_t)(value.operator Array()).size(), (real_t)(t->init_value.operator String()).length());1608t->element_size = Animation::blend_variant(t->element_size, length, blend);1609}1610value = Animation::subtract_variant(value, Animation::cast_to_blendwise(t->init_value));1611t->value = Animation::blend_variant(t->value, value, blend);1612}1613} else {1614if (seeked) {1615int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, false, seeked_backward);1616if (idx < 0) {1617continue;1618}1619t->use_discrete = true;1620Variant value = a->track_get_key_value(i, idx);1621value = post_process_key_value(a, i, value, t->object_id);1622Object *t_obj = ObjectDB::get_instance(t->object_id);1623if (t_obj) {1624t_obj->set_indexed(t->subpath, value);1625}1626} else {1627List<int> indices;1628a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);1629for (int &F : indices) {1630t->use_discrete = true;1631Variant value = a->track_get_key_value(i, F);1632value = post_process_key_value(a, i, value, t->object_id);1633Object *t_obj = ObjectDB::get_instance(t->object_id);1634if (t_obj) {1635t_obj->set_indexed(t->subpath, value);1636}1637}1638}1639}1640} break;1641case Animation::TYPE_METHOD: {1642#ifdef TOOLS_ENABLED1643if (!can_call) {1644continue;1645}1646#endif // TOOLS_ENABLED1647if (p_update_only || Math::is_zero_approx(blend)) {1648continue;1649}1650TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track);1651if (seeked) {1652int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, true);1653if (idx < 0) {1654continue;1655}1656StringName method = a->method_track_get_name(i, idx);1657Vector<Variant> params = a->method_track_get_params(i, idx);1658_call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);1659} else {1660List<int> indices;1661a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);1662for (int &F : indices) {1663StringName method = a->method_track_get_name(i, F);1664Vector<Variant> params = a->method_track_get_params(i, F);1665_call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);1666}1667}1668} break;1669case Animation::TYPE_AUDIO: {1670// 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.1671TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);1672Object *t_obj = ObjectDB::get_instance(t->object_id);1673Node *asp = t_obj ? Object::cast_to<Node>(t_obj) : nullptr;1674if (!t_obj || !asp) {1675t->playing_streams.clear();1676continue;1677}1678ObjectID oid = a->get_instance_id();1679if (!t->playing_streams.has(oid)) {1680t->playing_streams[oid] = PlayingAudioTrackInfo();1681}16821683PlayingAudioTrackInfo &track_info = t->playing_streams[oid];1684track_info.length = a_length;1685track_info.time = time;1686track_info.volume += blend;1687track_info.loop = a->get_loop_mode() != Animation::LOOP_NONE;1688track_info.backward = backward;1689track_info.use_blend = a->audio_track_is_use_blend(i);1690AHashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;16911692// Main process to fire key is started from here.1693if (p_update_only) {1694continue;1695}1696// Find stream.1697int idx = -1;1698if (seeked) {1699// Audio key may be playbacked from the middle, should use FIND_MODE_NEAREST.1700// Then, check the current playing stream to prevent to playback doubly.1701idx = a->track_find_key(i, time, Animation::FIND_MODE_NEAREST, true);1702// Discard previous stream when seeking.1703if (map.has(idx)) {1704t->audio_stream_playback->stop_stream(map[idx].index);1705map.erase(idx);1706}1707} else {1708List<int> to_play;1709a->track_get_key_indices_in_range(i, time, delta, &to_play, looped_flag);1710if (to_play.size()) {1711idx = to_play.back()->get();1712}1713}1714if (idx < 0) {1715continue;1716}17171718// Play stream.1719Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);1720if (stream.is_valid()) {1721double start_ofs = a->audio_track_get_key_start_offset(i, idx);1722double end_ofs = a->audio_track_get_key_end_offset(i, idx);1723double len = stream->get_length();1724if (seeked) {1725start_ofs += time - a->track_get_key_time(i, idx);1726}17271728if (t_obj->call(SNAME("get_stream")) != t->audio_stream) {1729t_obj->call(SNAME("set_stream"), t->audio_stream);1730t->audio_stream_playback.unref();1731if (!playing_audio_stream_players.has(asp)) {1732playing_audio_stream_players.push_back(asp);1733}1734}1735if (!t_obj->call(SNAME("is_playing"))) {1736t_obj->call(SNAME("play"));1737}1738if (!t_obj->call(SNAME("has_stream_playback"))) {1739t->audio_stream_playback.unref();1740continue;1741}1742if (t->audio_stream_playback.is_null()) {1743t->audio_stream_playback = t_obj->call(SNAME("get_stream_playback"));1744}17451746if (t_obj->call(SNAME("get_is_sample"))) {1747if (t->audio_stream_playback->get_sample_playback().is_valid()) {1748AudioServer::get_singleton()->stop_sample_playback(t->audio_stream_playback->get_sample_playback());1749}1750Ref<AudioSamplePlayback> sample_playback;1751sample_playback.instantiate();1752sample_playback->stream = stream;1753t->audio_stream_playback->set_sample_playback(sample_playback);1754AudioServer::get_singleton()->start_sample_playback(sample_playback);1755continue;1756}17571758PlayingAudioStreamInfo pasi;1759pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs, 0, 1.0, t->playback_type, t->bus);1760pasi.start = time;1761if (len && Animation::is_greater_approx(end_ofs, 0)) { // Force an end at a time.1762pasi.len = len - start_ofs - end_ofs;1763} else {1764pasi.len = 0;1765}1766map[idx] = pasi;1767}1768} break;1769case Animation::TYPE_ANIMATION: {1770if (Math::is_zero_approx(blend)) {1771continue;1772}1773TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track);1774Object *t_obj = ObjectDB::get_instance(t->object_id);1775if (!t_obj) {1776continue;1777}1778AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t_obj);1779if (!player2) {1780continue;1781}1782// TODO: Make it possible to embed section info in animation track keys.1783if (seeked) {1784// Seek.1785int idx = a->track_find_key(i, time, Animation::FIND_MODE_NEAREST, true);1786if (idx < 0) {1787continue;1788}1789double pos = a->track_get_key_time(i, idx);1790StringName anim_name = a->animation_track_get_key_animation(i, idx);1791if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) {1792continue;1793}1794Ref<Animation> anim = player2->get_animation(anim_name);1795double at_anim_pos = start;1796switch (anim->get_loop_mode()) {1797case Animation::LOOP_NONE: {1798if (!is_external_seeking && ((!backward && Animation::is_greater_or_equal_approx(time, pos + end)) || (backward && Animation::is_less_or_equal_approx(time, pos + start)))) {1799continue; // Do nothing if current time is outside of length when started.1800}1801at_anim_pos = MIN(end, time - pos); // Seek to end.1802} break;1803case Animation::LOOP_LINEAR: {1804at_anim_pos = Math::fposmod(time - pos - start, end - start) + start; // Seek to loop.1805} break;1806case Animation::LOOP_PINGPONG: {1807at_anim_pos = Math::pingpong(time - pos - start, end - start) + start;1808} break;1809default:1810break;1811}1812if (player2->is_playing() || !is_external_seeking) {1813player2->seek(at_anim_pos, false, p_update_only);1814player2->play(anim_name);1815t->playing = true;1816playing_caches.insert(t);1817} else {1818player2->set_assigned_animation(anim_name);1819player2->seek(at_anim_pos, true, p_update_only);1820}1821} else {1822// Find stuff to play.1823List<int> to_play;1824a->track_get_key_indices_in_range(i, time, delta, &to_play, looped_flag);1825if (to_play.size()) {1826int idx = to_play.back()->get();1827StringName anim_name = a->animation_track_get_key_animation(i, idx);1828if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) {1829if (playing_caches.has(t)) {1830playing_caches.erase(t);1831player2->stop();1832t->playing = false;1833}1834} else {1835player2->play(anim_name);1836t->playing = true;1837playing_caches.insert(t);1838}1839}1840}1841} break;1842}1843}1844}1845is_GDVIRTUAL_CALL_post_process_key_value = true;1846}18471848void AnimationMixer::_blend_apply() {1849// Finally, set the tracks.1850for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {1851TrackCache *track = K.value;1852bool is_zero_amount = Math::is_zero_approx(track->total_weight);1853if (!deterministic && is_zero_amount) {1854continue;1855}1856switch (track->type) {1857case Animation::TYPE_POSITION_3D: {1858#ifndef _3D_DISABLED1859TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);18601861if (t->root_motion) {1862root_motion_position = root_motion_cache.loc;1863root_motion_rotation = root_motion_cache.rot;1864root_motion_scale = root_motion_cache.scale - Vector3(1, 1, 1);1865root_motion_position_accumulator = t->loc;1866root_motion_rotation_accumulator = t->rot;1867root_motion_scale_accumulator = t->scale;1868} else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) {1869Skeleton3D *t_skeleton = ObjectDB::get_instance<Skeleton3D>(t->skeleton_id);1870if (!t_skeleton) {1871return;1872}1873if (t->loc_used) {1874t_skeleton->set_bone_pose_position(t->bone_idx, t->loc);1875}1876if (t->rot_used) {1877t_skeleton->set_bone_pose_rotation(t->bone_idx, t->rot);1878}1879if (t->scale_used) {1880t_skeleton->set_bone_pose_scale(t->bone_idx, t->scale);1881}18821883} else if (!t->skeleton_id.is_valid()) {1884Node3D *t_node_3d = ObjectDB::get_instance<Node3D>(t->object_id);1885if (!t_node_3d) {1886return;1887}1888if (t->loc_used) {1889t_node_3d->set_position(t->loc);1890}1891if (t->rot_used) {1892t_node_3d->set_rotation(t->rot.get_euler());1893}1894if (t->scale_used) {1895t_node_3d->set_scale(t->scale);1896}1897}1898#endif // _3D_DISABLED1899} break;1900case Animation::TYPE_BLEND_SHAPE: {1901#ifndef _3D_DISABLED1902TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);19031904MeshInstance3D *t_mesh_3d = ObjectDB::get_instance<MeshInstance3D>(t->object_id);1905if (t_mesh_3d) {1906t_mesh_3d->set_blend_shape_value(t->shape_index, t->value);1907}1908#endif // _3D_DISABLED1909} break;1910case Animation::TYPE_VALUE: {1911TrackCacheValue *t = static_cast<TrackCacheValue *>(track);19121913if (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {1914t->is_init = false; // Always update in Force Continuous.1915} else if (!t->use_continuous && (t->use_discrete || !deterministic)) {1916t->is_init = true; // If there is no continuous value and only disctere value is applied or just started, don't RESET.1917}19181919if ((t->is_init && (is_zero_amount || !t->use_continuous)) ||1920(callback_mode_discrete != ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS &&1921!is_zero_amount &&1922callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT &&1923t->use_discrete)) {1924break; // Don't overwrite the value set by UPDATE_DISCRETE.1925}19261927if (callback_mode_discrete != ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {1928t->is_init = !t->use_continuous; // If there is no Continuous in non-Force Continuous type, it means RESET.1929}19301931// Trim unused elements if init array/string is not blended.1932if (t->value.is_array()) {1933int actual_blended_size = (int)Math::round(Math::abs(t->element_size.operator real_t()));1934if (actual_blended_size < (t->value.operator Array()).size()) {1935real_t abs_weight = Math::abs(track->total_weight);1936if (abs_weight >= 1.0) {1937(t->value.operator Array()).resize(actual_blended_size);1938} else if (t->init_value.is_string()) {1939(t->value.operator Array()).resize(Animation::interpolate_variant((t->init_value.operator String()).length(), actual_blended_size, abs_weight));1940}1941}1942}19431944Object *t_obj = ObjectDB::get_instance(t->object_id);1945if (t_obj) {1946t_obj->set_indexed(t->subpath, Animation::cast_from_blendwise(t->value, t->init_value.get_type()));1947}19481949} break;1950case Animation::TYPE_AUDIO: {1951TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);19521953// Audio ending process.1954LocalVector<ObjectID> erase_maps;1955for (KeyValue<ObjectID, PlayingAudioTrackInfo> &L : t->playing_streams) {1956PlayingAudioTrackInfo &track_info = L.value;1957float db = Math::linear_to_db(track_info.use_blend ? track_info.volume : 1.0);1958LocalVector<int> erase_streams;1959AHashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;1960for (const KeyValue<int, PlayingAudioStreamInfo> &M : map) {1961PlayingAudioStreamInfo pasi = M.value;19621963bool stop = false;1964if (!t->audio_stream_playback->is_stream_playing(pasi.index)) {1965stop = true;1966}1967if (!track_info.loop) {1968if (!track_info.backward) {1969if (Animation::is_less_approx(track_info.time, pasi.start)) {1970stop = true;1971}1972} else if (track_info.backward) {1973if (Animation::is_greater_approx(track_info.time, pasi.start)) {1974stop = true;1975}1976}1977}1978if (Animation::is_greater_approx(pasi.len, 0)) {1979double len = 0.0;1980if (!track_info.backward) {1981len = Animation::is_greater_approx(pasi.start, track_info.time) ? (track_info.length - pasi.start) + track_info.time : track_info.time - pasi.start;1982} else {1983len = Animation::is_less_approx(pasi.start, track_info.time) ? (track_info.length - track_info.time) + pasi.start : pasi.start - track_info.time;1984}1985if (Animation::is_greater_approx(len, pasi.len)) {1986stop = true;1987}1988}1989if (stop) {1990// Time to stop.1991t->audio_stream_playback->stop_stream(pasi.index);1992erase_streams.push_back(M.key);1993} else {1994t->audio_stream_playback->set_stream_volume(pasi.index, db);1995}1996}1997for (uint32_t erase_idx = 0; erase_idx < erase_streams.size(); erase_idx++) {1998map.erase(erase_streams[erase_idx]);1999}2000if (map.is_empty()) {2001erase_maps.push_back(L.key);2002}2003}2004for (uint32_t erase_idx = 0; erase_idx < erase_maps.size(); erase_idx++) {2005t->playing_streams.erase(erase_maps[erase_idx]);2006}2007} break;2008default: {2009} // The rest don't matter.2010}2011}2012}20132014void AnimationMixer::_call_object(ObjectID p_object_id, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) {2015// Separate function to use alloca() more efficiently2016const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * p_params.size());2017const Variant *args = p_params.ptr();2018uint32_t argcount = p_params.size();2019for (uint32_t i = 0; i < argcount; i++) {2020argptrs[i] = &args[i];2021}2022Object *t_obj = ObjectDB::get_instance(p_object_id);2023if (!t_obj) {2024return;2025}2026if (p_deferred) {2027Callable(t_obj, p_method).call_deferredp(argptrs, argcount);2028} else {2029Callable::CallError ce;2030t_obj->callp(p_method, argptrs, argcount, ce);2031}2032}20332034void AnimationMixer::make_animation_instance(const StringName &p_name, const PlaybackInfo p_playback_info) {2035ERR_FAIL_COND(!has_animation(p_name));20362037AnimationData ad;2038ad.name = p_name;2039ad.animation = get_animation(p_name);2040ad.animation_library = find_animation_library(ad.animation);20412042AnimationInstance ai;2043ai.animation_data = ad;2044ai.playback_info = p_playback_info;20452046animation_instances.push_back(ai);2047}20482049void AnimationMixer::clear_animation_instances() {2050animation_instances.clear();2051}20522053void AnimationMixer::advance(double p_time) {2054_process_animation(p_time);2055}20562057void AnimationMixer::clear_caches() {2058_clear_caches();2059}20602061/* -------------------------------------------- */2062/* -- Root motion ----------------------------- */2063/* -------------------------------------------- */20642065void AnimationMixer::set_root_motion_track(const NodePath &p_track) {2066root_motion_track = p_track;2067notify_property_list_changed();2068}20692070NodePath AnimationMixer::get_root_motion_track() const {2071return root_motion_track;2072}20732074void AnimationMixer::set_root_motion_local(bool p_enabled) {2075root_motion_local = p_enabled;2076}20772078bool AnimationMixer::is_root_motion_local() const {2079return root_motion_local;2080}20812082Vector3 AnimationMixer::get_root_motion_position() const {2083return root_motion_position;2084}20852086Quaternion AnimationMixer::get_root_motion_rotation() const {2087return root_motion_rotation;2088}20892090Vector3 AnimationMixer::get_root_motion_scale() const {2091return root_motion_scale;2092}20932094Vector3 AnimationMixer::get_root_motion_position_accumulator() const {2095return root_motion_position_accumulator;2096}20972098Quaternion AnimationMixer::get_root_motion_rotation_accumulator() const {2099return root_motion_rotation_accumulator;2100}21012102Vector3 AnimationMixer::get_root_motion_scale_accumulator() const {2103return root_motion_scale_accumulator;2104}21052106/* -------------------------------------------- */2107/* -- Reset on save --------------------------- */2108/* -------------------------------------------- */21092110void AnimationMixer::set_reset_on_save_enabled(bool p_enabled) {2111reset_on_save = p_enabled;2112}21132114bool AnimationMixer::is_reset_on_save_enabled() const {2115return reset_on_save;2116}21172118bool AnimationMixer::can_apply_reset() const {2119return has_animation(SceneStringName(RESET));2120}21212122void AnimationMixer::_build_backup_track_cache() {2123for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {2124TrackCache *track = K.value;2125track->total_weight = 1.0;2126switch (track->type) {2127case Animation::TYPE_POSITION_3D: {2128#ifndef _3D_DISABLED2129TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);2130if (t->root_motion) {2131// Do nothing.2132} else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) {2133Skeleton3D *t_skeleton = ObjectDB::get_instance<Skeleton3D>(t->skeleton_id);2134if (!t_skeleton) {2135return;2136}2137if (t->loc_used) {2138t->loc = t_skeleton->get_bone_pose_position(t->bone_idx);2139}2140if (t->rot_used) {2141t->rot = t_skeleton->get_bone_pose_rotation(t->bone_idx);2142}2143if (t->scale_used) {2144t->scale = t_skeleton->get_bone_pose_scale(t->bone_idx);2145}2146} else if (!t->skeleton_id.is_valid()) {2147Node3D *t_node_3d = ObjectDB::get_instance<Node3D>(t->object_id);2148if (!t_node_3d) {2149return;2150}2151if (t->loc_used) {2152t->loc = t_node_3d->get_position();2153}2154if (t->rot_used) {2155t->rot = t_node_3d->get_quaternion();2156}2157if (t->scale_used) {2158t->scale = t_node_3d->get_scale();2159}2160}2161#endif // _3D_DISABLED2162} break;2163case Animation::TYPE_BLEND_SHAPE: {2164#ifndef _3D_DISABLED2165TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);2166MeshInstance3D *t_mesh_3d = ObjectDB::get_instance<MeshInstance3D>(t->object_id);2167if (t_mesh_3d) {2168t->value = t_mesh_3d->get_blend_shape_value(t->shape_index);2169}2170#endif // _3D_DISABLED2171} break;2172case Animation::TYPE_VALUE: {2173TrackCacheValue *t = static_cast<TrackCacheValue *>(track);2174Object *t_obj = ObjectDB::get_instance(t->object_id);2175if (t_obj) {2176t->value = Animation::cast_to_blendwise(t_obj->get_indexed(t->subpath));2177}2178t->use_continuous = true;2179t->use_discrete = false;2180if (t->init_value.is_array()) {2181t->element_size = MAX(t->element_size.operator int(), (t->value.operator Array()).size());2182} else if (t->init_value.is_string()) {2183t->element_size = (real_t)(t->value.operator Array()).size();2184}2185} break;2186case Animation::TYPE_AUDIO: {2187TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);2188Object *t_obj = ObjectDB::get_instance(t->object_id);2189if (t_obj) {2190Node *asp = Object::cast_to<Node>(t_obj);2191if (asp) {2192asp->call(SNAME("set_stream"), Ref<AudioStream>());2193}2194}2195} break;2196default: {2197} // The rest don't matter.2198}2199}2200}22012202Ref<AnimatedValuesBackup> AnimationMixer::make_backup() {2203Ref<AnimatedValuesBackup> backup;2204backup.instantiate();22052206Ref<Animation> reset_anim = animation_set[SceneStringName(RESET)].animation;2207ERR_FAIL_COND_V(reset_anim.is_null(), Ref<AnimatedValuesBackup>());22082209_blend_init();2210PlaybackInfo pi;2211pi.time = 0;2212pi.delta = 0;2213pi.start = 0;2214pi.end = reset_anim->get_length();2215pi.seeked = true;2216pi.weight = 1.0;2217make_animation_instance(SceneStringName(RESET), pi);2218_build_backup_track_cache();22192220backup->set_data(track_cache);2221clear_animation_instances();22222223return backup;2224}22252226void AnimationMixer::reset() {2227ERR_FAIL_COND(!can_apply_reset());22282229Ref<Animation> reset_anim = animation_set[SceneStringName(RESET)].animation;2230ERR_FAIL_COND(reset_anim.is_null());22312232Node *root_node_object = get_node_or_null(root_node);2233ERR_FAIL_NULL(root_node_object);22342235AnimationPlayer *aux_player = memnew(AnimationPlayer);2236root_node_object->add_child(aux_player);2237Ref<AnimationLibrary> al;2238al.instantiate();2239al->add_animation(SceneStringName(RESET), reset_anim);2240aux_player->set_reset_on_save_enabled(false);2241aux_player->set_root_node(aux_player->get_path_to(root_node_object));2242aux_player->add_animation_library("", al);2243aux_player->set_assigned_animation(SceneStringName(RESET));2244aux_player->seek(0.0f, true);2245aux_player->queue_free();2246}22472248void AnimationMixer::restore(const Ref<AnimatedValuesBackup> &p_backup) {2249ERR_FAIL_COND(p_backup.is_null());2250track_cache = p_backup->get_data();2251_blend_apply();2252track_cache = AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher>();2253cache_valid = false;2254}22552256#ifdef TOOLS_ENABLED2257Ref<AnimatedValuesBackup> AnimationMixer::apply_reset(bool p_user_initiated) {2258if (!p_user_initiated && dummy) {2259return Ref<AnimatedValuesBackup>();2260}2261ERR_FAIL_COND_V(!can_apply_reset(), Ref<AnimatedValuesBackup>());22622263Ref<Animation> reset_anim = animation_set[SceneStringName(RESET)].animation;2264ERR_FAIL_COND_V(reset_anim.is_null(), Ref<AnimatedValuesBackup>());22652266Ref<AnimatedValuesBackup> backup_current = make_backup();2267if (p_user_initiated) {2268EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();2269ur->create_action(TTR("Animation Apply Reset"));2270ur->add_do_method(this, "_reset");2271ur->add_undo_method(this, "_restore", backup_current);2272ur->commit_action();2273} else {2274reset();2275}22762277return backup_current;2278}2279#endif // TOOLS_ENABLED22802281/* -------------------------------------------- */2282/* -- Capture feature ------------------------- */2283/* -------------------------------------------- */22842285void AnimationMixer::capture(const StringName &p_name, double p_duration, Tween::TransitionType p_trans_type, Tween::EaseType p_ease_type) {2286ERR_FAIL_COND(!active);2287ERR_FAIL_COND(!has_animation(p_name));2288ERR_FAIL_COND(p_duration <= 0);2289Ref<Animation> reference_animation = get_animation(p_name);22902291if (!cache_valid) {2292_update_caches(); // Need to retrieve object id.2293}22942295capture_cache.remain = 1.0;2296capture_cache.step = 1.0 / p_duration;2297capture_cache.trans_type = p_trans_type;2298capture_cache.ease_type = p_ease_type;2299if (capture_cache.animation.is_valid()) {2300animation_track_num_to_track_cache.erase(capture_cache.animation);2301}2302capture_cache.animation.instantiate();23032304bool is_valid = false;2305for (int i = 0; i < reference_animation->get_track_count(); i++) {2306if (!reference_animation->track_is_enabled(i)) {2307continue;2308}2309if (reference_animation->track_get_type(i) == Animation::TYPE_VALUE && reference_animation->value_track_get_update_mode(i) == Animation::UPDATE_CAPTURE) {2310TrackCacheValue *t = static_cast<TrackCacheValue *>(track_cache[reference_animation->track_get_type_hash(i)]);2311Object *t_obj = ObjectDB::get_instance(t->object_id);2312if (t_obj) {2313Variant value = t_obj->get_indexed(t->subpath);2314int inserted_idx = capture_cache.animation->add_track(Animation::TYPE_VALUE);2315capture_cache.animation->track_set_path(inserted_idx, reference_animation->track_get_path(i));2316capture_cache.animation->track_insert_key(inserted_idx, 0, value);2317capture_cache.animation->value_track_set_update_mode(inserted_idx, Animation::UPDATE_CONTINUOUS);2318capture_cache.animation->track_set_interpolation_type(inserted_idx, Animation::INTERPOLATION_LINEAR);2319is_valid = true;2320}2321}2322}2323if (!is_valid) {2324capture_cache.clear();2325} else {2326_create_track_num_to_track_cache_for_animation(capture_cache.animation);2327}2328}23292330/* -------------------------------------------- */2331/* -- General functions ----------------------- */2332/* -------------------------------------------- */23332334void AnimationMixer::_node_removed(Node *p_node) {2335_clear_caches();2336}23372338void AnimationMixer::_notification(int p_what) {2339switch (p_what) {2340case NOTIFICATION_ENTER_TREE: {2341if (!processing) {2342set_physics_process_internal(false);2343set_process_internal(false);2344}2345_clear_caches();2346} break;23472348case NOTIFICATION_INTERNAL_PROCESS: {2349if (active && callback_mode_process == ANIMATION_CALLBACK_MODE_PROCESS_IDLE) {2350_process_animation(get_process_delta_time());2351}2352} break;23532354case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {2355if (active && callback_mode_process == ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS) {2356_process_animation(get_physics_process_delta_time());2357}2358} break;23592360case NOTIFICATION_EXIT_TREE: {2361_clear_caches();2362} break;2363}2364}23652366#ifdef TOOLS_ENABLED2367void AnimationMixer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {2368const String pf = p_function;2369if (p_idx == 0) {2370if (pf == "get_animation" || pf == "has_animation") {2371List<StringName> al;2372get_animation_list(&al);2373for (const StringName &name : al) {2374r_options->push_back(String(name).quote());2375}2376} else if (pf == "get_animation_library" || pf == "has_animation_library" || pf == "remove_animation_library" || pf == "rename_animation_library") {2377List<StringName> al;2378get_animation_library_list(&al);2379for (const StringName &name : al) {2380r_options->push_back(String(name).quote());2381}2382}2383}2384Node::get_argument_options(p_function, p_idx, r_options);2385}2386#endif23872388void AnimationMixer::_bind_methods() {2389/* ---- Data lists ---- */2390ClassDB::bind_method(D_METHOD("add_animation_library", "name", "library"), &AnimationMixer::add_animation_library);2391ClassDB::bind_method(D_METHOD("remove_animation_library", "name"), &AnimationMixer::remove_animation_library);2392ClassDB::bind_method(D_METHOD("rename_animation_library", "name", "newname"), &AnimationMixer::rename_animation_library);2393ClassDB::bind_method(D_METHOD("has_animation_library", "name"), &AnimationMixer::has_animation_library);2394ClassDB::bind_method(D_METHOD("get_animation_library", "name"), &AnimationMixer::get_animation_library);2395ClassDB::bind_method(D_METHOD("get_animation_library_list"), &AnimationMixer::_get_animation_library_list);23962397ClassDB::bind_method(D_METHOD("has_animation", "name"), &AnimationMixer::has_animation);2398ClassDB::bind_method(D_METHOD("get_animation", "name"), &AnimationMixer::get_animation);2399ClassDB::bind_method(D_METHOD("get_animation_list"), &AnimationMixer::_get_animation_list);24002401/* ---- General settings for animation ---- */2402ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationMixer::set_active);2403ClassDB::bind_method(D_METHOD("is_active"), &AnimationMixer::is_active);24042405ClassDB::bind_method(D_METHOD("set_deterministic", "deterministic"), &AnimationMixer::set_deterministic);2406ClassDB::bind_method(D_METHOD("is_deterministic"), &AnimationMixer::is_deterministic);24072408ClassDB::bind_method(D_METHOD("set_root_node", "path"), &AnimationMixer::set_root_node);2409ClassDB::bind_method(D_METHOD("get_root_node"), &AnimationMixer::get_root_node);24102411ClassDB::bind_method(D_METHOD("set_callback_mode_process", "mode"), &AnimationMixer::set_callback_mode_process);2412ClassDB::bind_method(D_METHOD("get_callback_mode_process"), &AnimationMixer::get_callback_mode_process);24132414ClassDB::bind_method(D_METHOD("set_callback_mode_method", "mode"), &AnimationMixer::set_callback_mode_method);2415ClassDB::bind_method(D_METHOD("get_callback_mode_method"), &AnimationMixer::get_callback_mode_method);24162417ClassDB::bind_method(D_METHOD("set_callback_mode_discrete", "mode"), &AnimationMixer::set_callback_mode_discrete);2418ClassDB::bind_method(D_METHOD("get_callback_mode_discrete"), &AnimationMixer::get_callback_mode_discrete);24192420/* ---- Audio ---- */2421ClassDB::bind_method(D_METHOD("set_audio_max_polyphony", "max_polyphony"), &AnimationMixer::set_audio_max_polyphony);2422ClassDB::bind_method(D_METHOD("get_audio_max_polyphony"), &AnimationMixer::get_audio_max_polyphony);24232424/* ---- Root motion accumulator for Skeleton3D ---- */2425ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationMixer::set_root_motion_track);2426ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationMixer::get_root_motion_track);2427ClassDB::bind_method(D_METHOD("set_root_motion_local", "enabled"), &AnimationMixer::set_root_motion_local);2428ClassDB::bind_method(D_METHOD("is_root_motion_local"), &AnimationMixer::is_root_motion_local);24292430ClassDB::bind_method(D_METHOD("get_root_motion_position"), &AnimationMixer::get_root_motion_position);2431ClassDB::bind_method(D_METHOD("get_root_motion_rotation"), &AnimationMixer::get_root_motion_rotation);2432ClassDB::bind_method(D_METHOD("get_root_motion_scale"), &AnimationMixer::get_root_motion_scale);2433ClassDB::bind_method(D_METHOD("get_root_motion_position_accumulator"), &AnimationMixer::get_root_motion_position_accumulator);2434ClassDB::bind_method(D_METHOD("get_root_motion_rotation_accumulator"), &AnimationMixer::get_root_motion_rotation_accumulator);2435ClassDB::bind_method(D_METHOD("get_root_motion_scale_accumulator"), &AnimationMixer::get_root_motion_scale_accumulator);24362437/* ---- Blending processor ---- */2438ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationMixer::clear_caches);2439ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationMixer::advance);2440GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object_id", "object_sub_idx");24412442/* ---- Capture feature ---- */2443ClassDB::bind_method(D_METHOD("capture", "name", "duration", "trans_type", "ease_type"), &AnimationMixer::capture, DEFVAL(Tween::TRANS_LINEAR), DEFVAL(Tween::EASE_IN));24442445/* ---- Reset on save ---- */2446ClassDB::bind_method(D_METHOD("set_reset_on_save_enabled", "enabled"), &AnimationMixer::set_reset_on_save_enabled);2447ClassDB::bind_method(D_METHOD("is_reset_on_save_enabled"), &AnimationMixer::is_reset_on_save_enabled);24482449ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");2450ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deterministic"), "set_deterministic", "is_deterministic");2451ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset_on_save", PROPERTY_HINT_NONE, ""), "set_reset_on_save_enabled", "is_reset_on_save_enabled");2452ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root_node", "get_root_node");24532454ADD_GROUP("Root Motion", "root_motion_");2455ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track");2456ADD_PROPERTY(PropertyInfo(Variant::BOOL, "root_motion_local"), "set_root_motion_local", "is_root_motion_local");24572458ADD_GROUP("Audio", "audio_");2459ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_max_polyphony", PROPERTY_HINT_RANGE, "1,127,1"), "set_audio_max_polyphony", "get_audio_max_polyphony");24602461ADD_GROUP("Callback Mode", "callback_mode_");2462ADD_PROPERTY(PropertyInfo(Variant::INT, "callback_mode_process", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_callback_mode_process", "get_callback_mode_process");2463ADD_PROPERTY(PropertyInfo(Variant::INT, "callback_mode_method", PROPERTY_HINT_ENUM, "Deferred,Immediate"), "set_callback_mode_method", "get_callback_mode_method");2464ADD_PROPERTY(PropertyInfo(Variant::INT, "callback_mode_discrete", PROPERTY_HINT_ENUM, "Dominant,Recessive,Force Continuous"), "set_callback_mode_discrete", "get_callback_mode_discrete");24652466BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS);2467BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_PROCESS_IDLE);2468BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_PROCESS_MANUAL);24692470BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);2471BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_METHOD_IMMEDIATE);24722473BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT);2474BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE);2475BIND_ENUM_CONSTANT(ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS);24762477ADD_SIGNAL(MethodInfo(SNAME("animation_list_changed")));2478ADD_SIGNAL(MethodInfo(SNAME("animation_libraries_updated")));2479ADD_SIGNAL(MethodInfo(SNAME("animation_finished"), PropertyInfo(Variant::STRING_NAME, "anim_name")));2480ADD_SIGNAL(MethodInfo(SNAME("animation_started"), PropertyInfo(Variant::STRING_NAME, "anim_name")));2481ADD_SIGNAL(MethodInfo(SNAME("caches_cleared")));2482ADD_SIGNAL(MethodInfo(SNAME("mixer_applied")));2483ADD_SIGNAL(MethodInfo(SNAME("mixer_updated"))); // For updating dummy player.24842485ClassDB::bind_method(D_METHOD("_reset"), &AnimationMixer::reset);2486ClassDB::bind_method(D_METHOD("_restore", "backup"), &AnimationMixer::restore);2487}24882489AnimationMixer::AnimationMixer() {2490root_node = SceneStringName(path_pp);2491}24922493AnimationMixer::~AnimationMixer() {2494}24952496void AnimatedValuesBackup::set_data(const AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> p_data) {2497clear_data();24982499for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : p_data) {2500AnimationMixer::TrackCache *track = get_cache_copy(E.value);2501if (!track) {2502continue; // Some types of tracks do not get a copy and must be ignored.2503}25042505data.insert(E.key, track);2506}2507}25082509AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> AnimatedValuesBackup::get_data() const {2510HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> ret;2511for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : data) {2512AnimationMixer::TrackCache *track = get_cache_copy(E.value);2513ERR_CONTINUE(!track); // Backup shouldn't contain tracks that cannot be copied, this is a mistake.25142515ret.insert(E.key, track);2516}2517return ret;2518}25192520void AnimatedValuesBackup::clear_data() {2521for (KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &K : data) {2522memdelete(K.value);2523}2524data.clear();2525}25262527AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer::TrackCache *p_cache) const {2528switch (p_cache->type) {2529case Animation::TYPE_BEZIER:2530case Animation::TYPE_VALUE: {2531AnimationMixer::TrackCacheValue *src = static_cast<AnimationMixer::TrackCacheValue *>(p_cache);2532AnimationMixer::TrackCacheValue *tc = memnew(AnimationMixer::TrackCacheValue(*src));2533return tc;2534}25352536case Animation::TYPE_POSITION_3D:2537case Animation::TYPE_ROTATION_3D:2538case Animation::TYPE_SCALE_3D: {2539AnimationMixer::TrackCacheTransform *src = static_cast<AnimationMixer::TrackCacheTransform *>(p_cache);2540AnimationMixer::TrackCacheTransform *tc = memnew(AnimationMixer::TrackCacheTransform(*src));2541return tc;2542}25432544case Animation::TYPE_BLEND_SHAPE: {2545AnimationMixer::TrackCacheBlendShape *src = static_cast<AnimationMixer::TrackCacheBlendShape *>(p_cache);2546AnimationMixer::TrackCacheBlendShape *tc = memnew(AnimationMixer::TrackCacheBlendShape(*src));2547return tc;2548}25492550case Animation::TYPE_AUDIO: {2551AnimationMixer::TrackCacheAudio *src = static_cast<AnimationMixer::TrackCacheAudio *>(p_cache);2552AnimationMixer::TrackCacheAudio *tc = memnew(AnimationMixer::TrackCacheAudio(*src));2553return tc;2554}25552556case Animation::TYPE_METHOD:2557case Animation::TYPE_ANIMATION: {2558// Nothing to do here.2559} break;2560}2561return nullptr;2562}256325642565