Path: blob/master/scene/animation/animation_tree.cpp
10277 views
/**************************************************************************/1/* animation_tree.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_tree.h"31#include "animation_tree.compat.inc"3233#include "animation_blend_tree.h"34#include "scene/animation/animation_player.h"3536void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {37Array parameters;3839if (GDVIRTUAL_CALL(_get_parameter_list, parameters)) {40for (int i = 0; i < parameters.size(); i++) {41Dictionary d = parameters[i];42ERR_CONTINUE(d.is_empty());43r_list->push_back(PropertyInfo::from_dict(d));44}45}4647r_list->push_back(PropertyInfo(Variant::FLOAT, current_length, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_READ_ONLY));48r_list->push_back(PropertyInfo(Variant::FLOAT, current_position, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_READ_ONLY));49r_list->push_back(PropertyInfo(Variant::FLOAT, current_delta, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_READ_ONLY));50}5152Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const {53Variant ret;54if (p_parameter == current_length || p_parameter == current_position || p_parameter == current_delta) {55return 0.0;56}57GDVIRTUAL_CALL(_get_parameter_default_value, p_parameter, ret);58return ret;59}6061bool AnimationNode::is_parameter_read_only(const StringName &p_parameter) const {62bool ret = false;63if (GDVIRTUAL_CALL(_is_parameter_read_only, p_parameter, ret) && ret) {64return true;65}6667if (p_parameter == current_length || p_parameter == current_position || p_parameter == current_delta) {68return true;69}7071return false;72}7374void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {75ERR_FAIL_NULL(process_state);76if (process_state->is_testing) {77return;78}7980const AHashMap<StringName, int>::Iterator it = property_cache.find(p_name);81if (it) {82Pair<Variant, bool> &prop = process_state->tree->property_map.get_by_index(it->value).value;83Variant value = p_value;84if (Animation::validate_type_match(prop.first, value)) {85prop.first = value;86}87return;88}8990ERR_FAIL_COND(!process_state->tree->property_parent_map.has(node_state.base_path));91ERR_FAIL_COND(!process_state->tree->property_parent_map[node_state.base_path].has(p_name));92StringName path = process_state->tree->property_parent_map[node_state.base_path][p_name];93int idx = process_state->tree->property_map.get_index(path);94property_cache.insert_new(p_name, idx);95process_state->tree->property_map.get_by_index(idx).value.first = p_value;96}9798Variant AnimationNode::get_parameter(const StringName &p_name) const {99ERR_FAIL_NULL_V(process_state, Variant());100const AHashMap<StringName, int>::ConstIterator it = property_cache.find(p_name);101if (it) {102return process_state->tree->property_map.get_by_index(it->value).value.first;103}104ERR_FAIL_COND_V(!process_state->tree->property_parent_map.has(node_state.base_path), Variant());105ERR_FAIL_COND_V(!process_state->tree->property_parent_map[node_state.base_path].has(p_name), Variant());106107StringName path = process_state->tree->property_parent_map[node_state.base_path][p_name];108int idx = process_state->tree->property_map.get_index(path);109property_cache.insert_new(p_name, idx);110return process_state->tree->property_map.get_by_index(idx).value.first;111}112113void AnimationNode::set_node_time_info(const NodeTimeInfo &p_node_time_info) {114set_parameter(current_length, p_node_time_info.length);115set_parameter(current_position, p_node_time_info.position);116set_parameter(current_delta, p_node_time_info.delta);117}118119AnimationNode::NodeTimeInfo AnimationNode::get_node_time_info() const {120NodeTimeInfo nti;121nti.length = get_parameter(current_length);122nti.position = get_parameter(current_position);123nti.delta = get_parameter(current_delta);124return nti;125}126127void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {128Dictionary cn;129if (GDVIRTUAL_CALL(_get_child_nodes, cn)) {130for (const KeyValue<Variant, Variant> &kv : cn) {131ChildNode child;132child.name = kv.key;133child.node = kv.value;134r_child_nodes->push_back(child);135}136}137}138139void AnimationNode::blend_animation(const StringName &p_animation, AnimationMixer::PlaybackInfo p_playback_info) {140ERR_FAIL_NULL(process_state);141p_playback_info.track_weights = node_state.track_weights;142process_state->tree->make_animation_instance(p_animation, p_playback_info);143}144145AnimationNode::NodeTimeInfo AnimationNode::_pre_process(ProcessState *p_process_state, AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {146process_state = p_process_state;147NodeTimeInfo nti = process(p_playback_info, p_test_only);148process_state = nullptr;149return nti;150}151152void AnimationNode::make_invalid(const String &p_reason) {153ERR_FAIL_NULL(process_state);154process_state->valid = false;155if (!process_state->invalid_reasons.is_empty()) {156process_state->invalid_reasons += "\n";157}158process_state->invalid_reasons += String::utf8("• ") + p_reason;159}160161AnimationTree *AnimationNode::get_animation_tree() const {162ERR_FAIL_NULL_V(process_state, nullptr);163return process_state->tree;164}165166AnimationNode::NodeTimeInfo AnimationNode::blend_input(int p_input, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only) {167ERR_FAIL_INDEX_V(p_input, (int64_t)inputs.size(), NodeTimeInfo());168169AnimationNodeBlendTree *blend_tree = Object::cast_to<AnimationNodeBlendTree>(node_state.parent);170ERR_FAIL_NULL_V(blend_tree, NodeTimeInfo());171172// Update connections.173StringName current_name = blend_tree->get_node_name(Ref<AnimationNode>(this));174node_state.connections = blend_tree->get_node_connection_array(current_name);175176// Get node which is connected input port.177StringName node_name = node_state.connections[p_input];178if (!blend_tree->has_node(node_name)) {179make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), current_name));180return NodeTimeInfo();181}182183Ref<AnimationNode> node = blend_tree->get_node(node_name);184ERR_FAIL_COND_V(node.is_null(), NodeTimeInfo());185186real_t activity = 0.0;187LocalVector<AnimationTree::Activity> *activity_ptr = process_state->tree->input_activity_map.getptr(node_state.base_path);188NodeTimeInfo nti = _blend_node(node, node_name, nullptr, p_playback_info, p_filter, p_sync, p_test_only, &activity);189190if (activity_ptr && p_input < (int64_t)activity_ptr->size()) {191(*activity_ptr)[p_input].last_pass = process_state->last_pass;192(*activity_ptr)[p_input].activity = activity;193}194return nti;195}196197AnimationNode::NodeTimeInfo AnimationNode::blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only) {198ERR_FAIL_COND_V(p_node.is_null(), NodeTimeInfo());199p_node->node_state.connections.clear();200return _blend_node(p_node, p_subpath, this, p_playback_info, p_filter, p_sync, p_test_only, nullptr);201}202203AnimationNode::NodeTimeInfo AnimationNode::_blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationNode *p_new_parent, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only, real_t *r_activity) {204ERR_FAIL_NULL_V(process_state, NodeTimeInfo());205206int blend_count = node_state.track_weights.size();207208if ((int64_t)p_node->node_state.track_weights.size() != blend_count) {209p_node->node_state.track_weights.resize(blend_count);210}211212real_t *blendw = p_node->node_state.track_weights.ptr();213const real_t *blendr = node_state.track_weights.ptr();214215bool any_valid = false;216217if (has_filter() && is_filter_enabled() && p_filter != FILTER_IGNORE) {218for (int i = 0; i < blend_count; i++) {219blendw[i] = 0.0; // All to zero by default.220}221222for (const KeyValue<NodePath, bool> &E : filter) {223const AHashMap<NodePath, int> &map = *process_state->track_map;224if (!map.has(E.key)) {225continue;226}227int idx = map[E.key];228blendw[idx] = 1.0; // Filtered goes to one.229}230231switch (p_filter) {232case FILTER_IGNORE:233break; // Will not happen anyway.234case FILTER_PASS: {235// Values filtered pass, the rest don't.236for (int i = 0; i < blend_count; i++) {237if (blendw[i] == 0) { // Not filtered, does not pass.238continue;239}240241blendw[i] = blendr[i] * p_playback_info.weight;242if (!Math::is_zero_approx(blendw[i])) {243any_valid = true;244}245}246247} break;248case FILTER_STOP: {249// Values filtered don't pass, the rest are blended.250251for (int i = 0; i < blend_count; i++) {252if (blendw[i] > 0) { // Filtered, does not pass.253continue;254}255256blendw[i] = blendr[i] * p_playback_info.weight;257if (!Math::is_zero_approx(blendw[i])) {258any_valid = true;259}260}261262} break;263case FILTER_BLEND: {264// Filtered values are blended, the rest are passed without blending.265266for (int i = 0; i < blend_count; i++) {267if (blendw[i] == 1.0) {268blendw[i] = blendr[i] * p_playback_info.weight; // Filtered, blend.269} else {270blendw[i] = blendr[i]; // Not filtered, do not blend.271}272273if (!Math::is_zero_approx(blendw[i])) {274any_valid = true;275}276}277278} break;279}280} else {281for (int i = 0; i < blend_count; i++) {282// Regular blend.283blendw[i] = blendr[i] * p_playback_info.weight;284if (!Math::is_zero_approx(blendw[i])) {285any_valid = true;286}287}288}289290if (r_activity) {291*r_activity = 0;292for (int i = 0; i < blend_count; i++) {293*r_activity = MAX(*r_activity, Math::abs(blendw[i]));294}295}296297String new_path;298AnimationNode *new_parent;299300// This is the slowest part of processing, but as strings process in powers of 2, and the paths always exist, it will not result in that many allocations.301if (p_new_parent) {302new_parent = p_new_parent;303new_path = String(node_state.base_path) + String(p_subpath) + "/";304} else {305ERR_FAIL_NULL_V(node_state.parent, NodeTimeInfo());306new_parent = node_state.parent;307new_path = String(new_parent->node_state.base_path) + String(p_subpath) + "/";308}309310// This process, which depends on p_sync is needed to process sync correctly in the case of311// that a synced AnimationNodeSync exists under the un-synced AnimationNodeSync.312p_node->set_node_state_base_path(new_path);313p_node->node_state.parent = new_parent;314if (!p_playback_info.seeked && !p_sync && !any_valid) {315p_playback_info.delta = 0.0;316return p_node->_pre_process(process_state, p_playback_info, p_test_only);317}318return p_node->_pre_process(process_state, p_playback_info, p_test_only);319}320321String AnimationNode::get_caption() const {322String ret = "Node";323GDVIRTUAL_CALL(_get_caption, ret);324return ret;325}326327bool AnimationNode::add_input(const String &p_name) {328// Root nodes can't add inputs.329ERR_FAIL_COND_V(Object::cast_to<AnimationRootNode>(this) != nullptr, false);330Input input;331ERR_FAIL_COND_V(p_name.contains_char('.') || p_name.contains_char('/'), false);332input.name = p_name;333inputs.push_back(input);334emit_changed();335return true;336}337338void AnimationNode::remove_input(int p_index) {339ERR_FAIL_INDEX(p_index, (int64_t)inputs.size());340inputs.remove_at(p_index);341emit_changed();342}343344bool AnimationNode::set_input_name(int p_input, const String &p_name) {345ERR_FAIL_INDEX_V(p_input, (int64_t)inputs.size(), false);346ERR_FAIL_COND_V(p_name.contains_char('.') || p_name.contains_char('/'), false);347inputs[p_input].name = p_name;348emit_changed();349return true;350}351352String AnimationNode::get_input_name(int p_input) const {353ERR_FAIL_INDEX_V(p_input, (int64_t)inputs.size(), String());354return inputs[p_input].name;355}356357int AnimationNode::get_input_count() const {358return inputs.size();359}360361int AnimationNode::find_input(const String &p_name) const {362int idx = -1;363for (int i = 0; i < (int64_t)inputs.size(); i++) {364if (inputs[i].name == p_name) {365idx = i;366break;367}368}369return idx;370}371372AnimationNode::NodeTimeInfo AnimationNode::process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {373process_state->is_testing = p_test_only;374375AnimationMixer::PlaybackInfo pi = p_playback_info;376if (p_playback_info.seeked) {377if (p_playback_info.is_external_seeking) {378pi.delta = get_node_time_info().position - p_playback_info.time;379}380} else {381pi.time = get_node_time_info().position + p_playback_info.delta;382}383384NodeTimeInfo nti = _process(pi, p_test_only);385386if (!p_test_only) {387set_node_time_info(nti);388}389390return nti;391}392393AnimationNode::NodeTimeInfo AnimationNode::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {394double r_ret = 0.0;395GDVIRTUAL_CALL(_process, p_playback_info.time, p_playback_info.seeked, p_playback_info.is_external_seeking, p_test_only, r_ret);396NodeTimeInfo nti;397nti.delta = r_ret;398return nti;399}400401void AnimationNode::set_filter_path(const NodePath &p_path, bool p_enable) {402if (p_enable) {403filter[p_path] = true;404} else {405filter.erase(p_path);406}407}408409void AnimationNode::set_filter_enabled(bool p_enable) {410filter_enabled = p_enable;411}412413bool AnimationNode::is_filter_enabled() const {414return filter_enabled;415}416417void AnimationNode::set_deletable(bool p_closable) {418closable = p_closable;419}420421bool AnimationNode::is_deletable() const {422return closable;423}424425ObjectID AnimationNode::get_processing_animation_tree_instance_id() const {426ERR_FAIL_NULL_V(process_state, ObjectID());427return process_state->tree->get_instance_id();428}429430bool AnimationNode::is_process_testing() const {431ERR_FAIL_NULL_V(process_state, false);432return process_state->is_testing;433}434435bool AnimationNode::is_path_filtered(const NodePath &p_path) const {436return filter.has(p_path);437}438439bool AnimationNode::has_filter() const {440bool ret = false;441GDVIRTUAL_CALL(_has_filter, ret);442return ret;443}444445Array AnimationNode::_get_filters() const {446Array paths;447448for (const KeyValue<NodePath, bool> &E : filter) {449paths.push_back(String(E.key)); // Use strings, so sorting is possible.450}451paths.sort(); // Done so every time the scene is saved, it does not change.452453return paths;454}455456void AnimationNode::_set_filters(const Array &p_filters) {457filter.clear();458for (int i = 0; i < p_filters.size(); i++) {459set_filter_path(p_filters[i], true);460}461}462463void AnimationNode::_validate_property(PropertyInfo &p_property) const {464if (!has_filter() && (p_property.name == "filter_enabled" || p_property.name == "filters")) {465p_property.usage = PROPERTY_USAGE_NONE;466}467}468469Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) const {470Ref<AnimationNode> ret;471GDVIRTUAL_CALL(_get_child_by_name, p_name, ret);472return ret;473}474475Ref<AnimationNode> AnimationNode::find_node_by_path(const String &p_name) const {476Vector<String> split = p_name.split("/");477Ref<AnimationNode> ret = const_cast<AnimationNode *>(this);478for (int i = 0; i < split.size(); i++) {479ret = ret->get_child_by_name(split[i]);480if (ret.is_null()) {481break;482}483}484return ret;485}486487void AnimationNode::blend_animation_ex(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, Animation::LoopedFlag p_looped_flag) {488AnimationMixer::PlaybackInfo info;489info.time = p_time;490info.delta = p_delta;491info.seeked = p_seeked;492info.is_external_seeking = p_is_external_seeking;493info.weight = p_blend;494info.looped_flag = p_looped_flag;495blend_animation(p_animation, info);496}497498double AnimationNode::blend_node_ex(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync, bool p_test_only) {499AnimationMixer::PlaybackInfo info;500info.time = p_time;501info.seeked = p_seek;502info.is_external_seeking = p_is_external_seeking;503info.weight = p_blend;504NodeTimeInfo nti = blend_node(p_node, p_sub_path, info, p_filter, p_sync, p_test_only);505return nti.length - nti.position;506}507508double AnimationNode::blend_input_ex(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync, bool p_test_only) {509AnimationMixer::PlaybackInfo info;510info.time = p_time;511info.seeked = p_seek;512info.is_external_seeking = p_is_external_seeking;513info.weight = p_blend;514NodeTimeInfo nti = blend_input(p_input, info, p_filter, p_sync, p_test_only);515return nti.length - nti.position;516}517518#ifdef TOOLS_ENABLED519void AnimationNode::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {520const String pf = p_function;521if (p_idx == 0) {522if (pf == "find_input") {523for (const AnimationNode::Input &E : inputs) {524r_options->push_back(E.name.quote());525}526} else if (pf == "get_parameter" || pf == "set_parameter") {527bool is_setter = pf == "set_parameter";528List<PropertyInfo> parameters;529get_parameter_list(¶meters);530for (const PropertyInfo &E : parameters) {531if (is_setter && is_parameter_read_only(E.name)) {532continue;533}534r_options->push_back(E.name.quote());535}536} else if (pf == "set_filter_path" || pf == "is_path_filtered") {537for (const KeyValue<NodePath, bool> &E : filter) {538r_options->push_back(String(E.key).quote());539}540}541}542Resource::get_argument_options(p_function, p_idx, r_options);543}544#endif545546void AnimationNode::_bind_methods() {547ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input);548ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input);549ClassDB::bind_method(D_METHOD("set_input_name", "input", "name"), &AnimationNode::set_input_name);550ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name);551ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count);552ClassDB::bind_method(D_METHOD("find_input", "name"), &AnimationNode::find_input);553554ClassDB::bind_method(D_METHOD("set_filter_path", "path", "enable"), &AnimationNode::set_filter_path);555ClassDB::bind_method(D_METHOD("is_path_filtered", "path"), &AnimationNode::is_path_filtered);556557ClassDB::bind_method(D_METHOD("set_filter_enabled", "enable"), &AnimationNode::set_filter_enabled);558ClassDB::bind_method(D_METHOD("is_filter_enabled"), &AnimationNode::is_filter_enabled);559560ClassDB::bind_method(D_METHOD("get_processing_animation_tree_instance_id"), &AnimationNode::get_processing_animation_tree_instance_id);561562ClassDB::bind_method(D_METHOD("is_process_testing"), &AnimationNode::is_process_testing);563564ClassDB::bind_method(D_METHOD("_set_filters", "filters"), &AnimationNode::_set_filters);565ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);566567ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "is_external_seeking", "blend", "looped_flag"), &AnimationNode::blend_animation_ex, DEFVAL(Animation::LOOPED_FLAG_NONE));568ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "is_external_seeking", "blend", "filter", "sync", "test_only"), &AnimationNode::blend_node_ex, DEFVAL(FILTER_IGNORE), DEFVAL(true), DEFVAL(false));569ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "is_external_seeking", "blend", "filter", "sync", "test_only"), &AnimationNode::blend_input_ex, DEFVAL(FILTER_IGNORE), DEFVAL(true), DEFVAL(false));570571ClassDB::bind_method(D_METHOD("set_parameter", "name", "value"), &AnimationNode::set_parameter);572ClassDB::bind_method(D_METHOD("get_parameter", "name"), &AnimationNode::get_parameter);573574ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_filter_enabled", "is_filter_enabled");575ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters");576577GDVIRTUAL_BIND(_get_child_nodes);578GDVIRTUAL_BIND(_get_parameter_list);579GDVIRTUAL_BIND(_get_child_by_name, "name");580GDVIRTUAL_BIND(_get_parameter_default_value, "parameter");581GDVIRTUAL_BIND(_is_parameter_read_only, "parameter");582GDVIRTUAL_BIND(_process, "time", "seek", "is_external_seeking", "test_only");583GDVIRTUAL_BIND(_get_caption);584GDVIRTUAL_BIND(_has_filter);585586ADD_SIGNAL(MethodInfo("tree_changed"));587ADD_SIGNAL(MethodInfo("animation_node_renamed", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name")));588ADD_SIGNAL(MethodInfo("animation_node_removed", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "name")));589590BIND_ENUM_CONSTANT(FILTER_IGNORE);591BIND_ENUM_CONSTANT(FILTER_PASS);592BIND_ENUM_CONSTANT(FILTER_STOP);593BIND_ENUM_CONSTANT(FILTER_BLEND);594}595596AnimationNode::AnimationNode() {597}598599////////////////////600601void AnimationRootNode::_tree_changed() {602emit_signal(SNAME("tree_changed"));603}604605void AnimationRootNode::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) {606emit_signal(SNAME("animation_node_renamed"), p_oid, p_old_name, p_new_name);607}608609void AnimationRootNode::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) {610emit_signal(SNAME("animation_node_removed"), p_oid, p_node);611}612613////////////////////614615void AnimationTree::set_root_animation_node(const Ref<AnimationRootNode> &p_animation_node) {616if (root_animation_node.is_valid()) {617root_animation_node->disconnect(SNAME("tree_changed"), callable_mp(this, &AnimationTree::_tree_changed));618root_animation_node->disconnect(SNAME("animation_node_renamed"), callable_mp(this, &AnimationTree::_animation_node_renamed));619root_animation_node->disconnect(SNAME("animation_node_removed"), callable_mp(this, &AnimationTree::_animation_node_removed));620}621622root_animation_node = p_animation_node;623624if (root_animation_node.is_valid()) {625root_animation_node->connect(SNAME("tree_changed"), callable_mp(this, &AnimationTree::_tree_changed));626root_animation_node->connect(SNAME("animation_node_renamed"), callable_mp(this, &AnimationTree::_animation_node_renamed));627root_animation_node->connect(SNAME("animation_node_removed"), callable_mp(this, &AnimationTree::_animation_node_removed));628}629630properties_dirty = true;631632update_configuration_warnings();633}634635Ref<AnimationRootNode> AnimationTree::get_root_animation_node() const {636return root_animation_node;637}638639bool AnimationTree::_blend_pre_process(double p_delta, int p_track_count, const AHashMap<NodePath, int> &p_track_map) {640_update_properties(); // If properties need updating, update them.641642if (root_animation_node.is_null()) {643return false;644}645646{ // Setup.647process_pass++;648649// Init process state.650process_state = AnimationNode::ProcessState();651process_state.tree = this;652process_state.valid = true;653process_state.invalid_reasons = "";654process_state.last_pass = process_pass;655process_state.track_map = &p_track_map;656657// Init node state for root AnimationNode.658root_animation_node->node_state.track_weights.resize(p_track_count);659real_t *src_blendsw = root_animation_node->node_state.track_weights.ptr();660for (int i = 0; i < p_track_count; i++) {661src_blendsw[i] = 1.0; // By default all go to 1 for the root input.662}663root_animation_node->set_node_state_base_path(SNAME(Animation::PARAMETERS_BASE_PATH.ascii().get_data()));664root_animation_node->node_state.parent = nullptr;665}666667// Process.668{669PlaybackInfo pi;670671if (started) {672// If started, seek.673pi.seeked = true;674pi.delta = p_delta;675root_animation_node->_pre_process(&process_state, pi, false);676started = false;677} else {678pi.seeked = false;679pi.delta = p_delta;680root_animation_node->_pre_process(&process_state, pi, false);681}682}683684if (!process_state.valid) {685return false; // State is not valid, abort process.686}687688return true;689}690691void AnimationTree::_set_active(bool p_active) {692_set_process(p_active);693started = p_active;694}695696void AnimationTree::set_advance_expression_base_node(const NodePath &p_path) {697advance_expression_base_node = p_path;698}699700NodePath AnimationTree::get_advance_expression_base_node() const {701return advance_expression_base_node;702}703704bool AnimationTree::is_state_invalid() const {705return !process_state.valid;706}707708String AnimationTree::get_invalid_state_reason() const {709return process_state.invalid_reasons;710}711712uint64_t AnimationTree::get_last_process_pass() const {713return process_pass;714}715716PackedStringArray AnimationTree::get_configuration_warnings() const {717PackedStringArray warnings = AnimationMixer::get_configuration_warnings();718if (root_animation_node.is_null()) {719warnings.push_back(RTR("No root AnimationNode for the graph is set."));720}721return warnings;722}723724void AnimationTree::_tree_changed() {725if (properties_dirty) {726return;727}728729callable_mp(this, &AnimationTree::_update_properties).call_deferred();730properties_dirty = true;731}732733void AnimationTree::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) {734ERR_FAIL_COND(!property_reference_map.has(p_oid));735String base_path = property_reference_map[p_oid];736String old_base = base_path + p_old_name;737String new_base = base_path + p_new_name;738for (const PropertyInfo &E : properties) {739if (E.name.begins_with(old_base)) {740String new_name = E.name.replace_first(old_base, new_base);741property_map[new_name] = property_map[E.name];742property_map.erase(E.name);743}744}745746// Update tree second.747properties_dirty = true;748_update_properties();749}750751void AnimationTree::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) {752ERR_FAIL_COND(!property_reference_map.has(p_oid));753String base_path = String(property_reference_map[p_oid]) + String(p_node);754for (const PropertyInfo &E : properties) {755if (E.name.begins_with(base_path)) {756property_map.erase(E.name);757}758}759760// Update tree second.761properties_dirty = true;762_update_properties();763}764765void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<AnimationNode> p_node) const {766ERR_FAIL_COND(p_node.is_null());767if (!property_parent_map.has(p_base_path)) {768property_parent_map[p_base_path] = AHashMap<StringName, StringName>();769}770if (!property_reference_map.has(p_node->get_instance_id())) {771property_reference_map[p_node->get_instance_id()] = p_base_path;772}773774if (p_node->get_input_count() && !input_activity_map.has(p_base_path)) {775LocalVector<Activity> activity;776for (int i = 0; i < p_node->get_input_count(); i++) {777Activity a;778a.activity = 0;779a.last_pass = 0;780activity.push_back(a);781}782input_activity_map[p_base_path] = activity;783input_activity_map_get[String(p_base_path).substr(0, String(p_base_path).length() - 1)] = input_activity_map.get_index(p_base_path);784}785786List<PropertyInfo> plist;787p_node->get_parameter_list(&plist);788for (PropertyInfo &pinfo : plist) {789StringName key = pinfo.name;790791if (!property_map.has(p_base_path + key)) {792Pair<Variant, bool> param;793param.first = p_node->get_parameter_default_value(key);794param.second = p_node->is_parameter_read_only(key);795property_map[p_base_path + key] = param;796}797798property_parent_map[p_base_path][key] = p_base_path + key;799800pinfo.name = p_base_path + key;801properties.push_back(pinfo);802}803p_node->make_cache_dirty();804List<AnimationNode::ChildNode> children;805p_node->get_child_nodes(&children);806807for (const AnimationNode::ChildNode &E : children) {808_update_properties_for_node(p_base_path + E.name + "/", E.node);809}810}811812void AnimationTree::_update_properties() const {813if (!properties_dirty) {814return;815}816817properties.clear();818property_reference_map.clear();819property_parent_map.clear();820input_activity_map.clear();821input_activity_map_get.clear();822823if (root_animation_node.is_valid()) {824_update_properties_for_node(Animation::PARAMETERS_BASE_PATH, root_animation_node);825}826827properties_dirty = false;828829const_cast<AnimationTree *>(this)->notify_property_list_changed();830}831832void AnimationTree::_notification(int p_what) {833switch (p_what) {834case NOTIFICATION_ENTER_TREE: {835_setup_animation_player();836if (active) {837_set_process(true);838}839} break;840}841}842843void AnimationTree::set_animation_player(const NodePath &p_path) {844animation_player = p_path;845if (p_path.is_empty()) {846set_root_node(SceneStringName(path_pp));847while (animation_libraries.size()) {848remove_animation_library(animation_libraries[0].name);849}850}851emit_signal(SNAME("animation_player_changed")); // Needs to unpin AnimationPlayerEditor.852_setup_animation_player();853notify_property_list_changed();854}855856NodePath AnimationTree::get_animation_player() const {857return animation_player;858}859860void AnimationTree::_setup_animation_player() {861if (!is_inside_tree()) {862return;863}864865cache_valid = false;866867if (animation_player.is_empty()) {868clear_caches();869return;870}871872// Using AnimationPlayer here is for compatibility. Changing to AnimationMixer needs extra work like error handling.873AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node_or_null(animation_player));874if (player) {875if (!player->is_connected(SNAME("caches_cleared"), callable_mp(this, &AnimationTree::_setup_animation_player))) {876player->connect(SNAME("caches_cleared"), callable_mp(this, &AnimationTree::_setup_animation_player), CONNECT_DEFERRED);877}878if (!player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationTree::_setup_animation_player))) {879player->connect(SNAME("animation_list_changed"), callable_mp(this, &AnimationTree::_setup_animation_player), CONNECT_DEFERRED);880}881Node *root = player->get_node_or_null(player->get_root_node());882if (root) {883set_root_node(get_path_to(root, true));884}885while (animation_libraries.size()) {886remove_animation_library(animation_libraries[0].name);887}888List<StringName> list;889player->get_animation_library_list(&list);890for (const StringName &E : list) {891Ref<AnimationLibrary> lib = player->get_animation_library(E);892if (lib.is_valid()) {893add_animation_library(E, lib);894}895}896}897898clear_caches();899}900901// `libraries` is a dynamic property, so we can't use `_validate_property` to change it.902uint32_t AnimationTree::_get_libraries_property_usage() const {903if (!animation_player.is_empty()) {904return PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY;905}906return PROPERTY_USAGE_DEFAULT;907}908909void AnimationTree::_validate_property(PropertyInfo &p_property) const {910if (!Engine::get_singleton()->is_editor_hint()) {911return;912}913914if (!animation_player.is_empty()) {915if (p_property.name == "root_node") {916p_property.usage |= PROPERTY_USAGE_READ_ONLY;917}918}919}920921bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {922#ifndef DISABLE_DEPRECATED923String name = p_name;924if (name == "process_callback") {925set_callback_mode_process(static_cast<AnimationCallbackModeProcess>((int)p_value));926return true;927}928#endif // DISABLE_DEPRECATED929if (properties_dirty) {930_update_properties();931}932933if (property_map.has(p_name)) {934if (is_inside_tree() && property_map[p_name].second) {935return false; // Prevent to set property by user.936}937Pair<Variant, bool> &prop = property_map[p_name];938Variant value = p_value;939if (Animation::validate_type_match(prop.first, value)) {940prop.first = value;941}942return true;943}944945return false;946}947948bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const {949#ifndef DISABLE_DEPRECATED950if (p_name == "process_callback") {951r_ret = get_callback_mode_process();952return true;953}954#endif // DISABLE_DEPRECATED955if (properties_dirty) {956_update_properties();957}958959if (property_map.has(p_name)) {960r_ret = property_map[p_name].first;961return true;962}963964return false;965}966967void AnimationTree::_get_property_list(List<PropertyInfo> *p_list) const {968if (properties_dirty) {969_update_properties();970}971972for (const PropertyInfo &E : properties) {973p_list->push_back(E);974}975}976977real_t AnimationTree::get_connection_activity(const StringName &p_path, int p_connection) const {978if (!input_activity_map_get.has(p_path)) {979return 0;980}981982int index = input_activity_map_get[p_path];983const LocalVector<Activity> &activity = input_activity_map.get_by_index(index).value;984985if (p_connection < 0 || p_connection >= (int64_t)activity.size() || activity[p_connection].last_pass != process_pass) {986return 0;987}988989return activity[p_connection].activity;990}991992void AnimationTree::_bind_methods() {993ClassDB::bind_method(D_METHOD("set_tree_root", "animation_node"), &AnimationTree::set_root_animation_node);994ClassDB::bind_method(D_METHOD("get_tree_root"), &AnimationTree::get_root_animation_node);995996ClassDB::bind_method(D_METHOD("set_advance_expression_base_node", "path"), &AnimationTree::set_advance_expression_base_node);997ClassDB::bind_method(D_METHOD("get_advance_expression_base_node"), &AnimationTree::get_advance_expression_base_node);998999ClassDB::bind_method(D_METHOD("set_animation_player", "path"), &AnimationTree::set_animation_player);1000ClassDB::bind_method(D_METHOD("get_animation_player"), &AnimationTree::get_animation_player);10011002ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root");1003ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "advance_expression_base_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node"), "set_advance_expression_base_node", "get_advance_expression_base_node");1004ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player");10051006ADD_SIGNAL(MethodInfo(SNAME("animation_player_changed")));1007}10081009AnimationTree::AnimationTree() {1010deterministic = true;1011callback_mode_discrete = ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS;1012}10131014AnimationTree::~AnimationTree() {1015}101610171018