Optimize Animation Resource, Library, Mixer, Player
Co-Authored-By: Silc Lizard (Tokage) Renew <tokage.it.lab@gmail.com>
This commit is contained in:
parent
220b0b2f74
commit
73d041dd98
30 changed files with 394 additions and 401 deletions
|
|
@ -84,10 +84,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
|
||||
menu->add_submenu_node_item(TTR("Add Animation"), animations_menu);
|
||||
|
||||
List<StringName> names;
|
||||
tree->get_animation_list(&names);
|
||||
|
||||
for (const StringName &E : names) {
|
||||
for (const StringName &E : tree->get_sorted_animation_list()) {
|
||||
animations_menu->add_icon_item(get_editor_theme_icon(SNAME("Animation")), E);
|
||||
animations_to_add.push_back(E);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,9 +128,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
|
||||
menu->add_submenu_node_item(TTR("Add Animation"), animations_menu);
|
||||
|
||||
List<StringName> names;
|
||||
tree->get_animation_list(&names);
|
||||
for (const StringName &E : names) {
|
||||
for (const StringName &E : tree->get_sorted_animation_list()) {
|
||||
animations_menu->add_icon_item(get_editor_theme_icon(SNAME("Animation")), E);
|
||||
animations_to_add.push_back(E);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,10 +275,7 @@ void AnimationNodeBlendTreeEditor::update_graph() {
|
|||
|
||||
ProgressBar *pb = memnew(ProgressBar);
|
||||
|
||||
List<StringName> anims;
|
||||
tree->get_animation_list(&anims);
|
||||
|
||||
for (const StringName &F : anims) {
|
||||
for (const StringName &F : tree->get_sorted_animation_list()) {
|
||||
mb->get_popup()->add_item(F);
|
||||
options.push_back(F);
|
||||
}
|
||||
|
|
@ -801,10 +798,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
|
|||
HashSet<String> paths;
|
||||
HashMap<String, RBSet<String>> types;
|
||||
{
|
||||
List<StringName> animation_list;
|
||||
tree->get_animation_list(&animation_list);
|
||||
|
||||
for (const StringName &E : animation_list) {
|
||||
for (const StringName &E : tree->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = tree->get_animation(E);
|
||||
for (int i = 0; i < anim->get_track_count(); i++) {
|
||||
String track_path = String(anim->track_get_path(i));
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
|
|||
} break;
|
||||
case FILE_MENU_MAKE_LIBRARY_UNIQUE: {
|
||||
StringName lib_name = file_dialog_library;
|
||||
List<StringName> animation_list;
|
||||
LocalVector<StringName> animation_list;
|
||||
|
||||
Ref<AnimationLibrary> ald = memnew(AnimationLibrary);
|
||||
al->get_animation_list(&animation_list);
|
||||
|
|
@ -377,7 +377,7 @@ void AnimationLibraryEditor::_load_files(const PackedStringArray &p_paths) {
|
|||
continue;
|
||||
}
|
||||
|
||||
List<StringName> libs;
|
||||
LocalVector<StringName> libs;
|
||||
mixer->get_animation_library_list(&libs);
|
||||
bool is_already_added = false;
|
||||
for (const StringName &K : libs) {
|
||||
|
|
@ -423,7 +423,7 @@ void AnimationLibraryEditor::_load_files(const PackedStringArray &p_paths) {
|
|||
continue;
|
||||
}
|
||||
|
||||
List<StringName> anims;
|
||||
LocalVector<StringName> anims;
|
||||
al->get_animation_list(&anims);
|
||||
bool is_already_added = false;
|
||||
for (const StringName &K : anims) {
|
||||
|
|
@ -686,7 +686,7 @@ void AnimationLibraryEditor::update_tree() {
|
|||
Color ss_color = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor));
|
||||
|
||||
TreeItem *root = tree->create_item();
|
||||
List<StringName> libs;
|
||||
LocalVector<StringName> libs;
|
||||
const Vector<String> collapsed_libs = _load_mixer_libs_folding();
|
||||
|
||||
mixer->get_animation_library_list(&libs);
|
||||
|
|
@ -743,7 +743,7 @@ void AnimationLibraryEditor::update_tree() {
|
|||
|
||||
libitem->set_custom_bg_color(0, ss_color);
|
||||
|
||||
List<StringName> animations;
|
||||
LocalVector<StringName> animations;
|
||||
al->get_animation_list(&animations);
|
||||
for (const StringName &L : animations) {
|
||||
TreeItem *anitem = tree->create_item(libitem);
|
||||
|
|
@ -888,7 +888,7 @@ String AnimationLibraryEditor::_get_mixer_signature() const {
|
|||
String signature = String();
|
||||
|
||||
// Get all libraries sorted for consistency
|
||||
List<StringName> libs;
|
||||
LocalVector<StringName> libs;
|
||||
mixer->get_animation_library_list(&libs);
|
||||
libs.sort_custom<StringName::AlphCompare>();
|
||||
|
||||
|
|
@ -897,7 +897,7 @@ String AnimationLibraryEditor::_get_mixer_signature() const {
|
|||
signature += "::" + String(lib_name);
|
||||
Ref<AnimationLibrary> lib = mixer->get_animation_library(lib_name);
|
||||
if (lib.is_valid()) {
|
||||
List<StringName> anims;
|
||||
LocalVector<StringName> anims;
|
||||
lib->get_animation_list(&anims);
|
||||
anims.sort_custom<StringName::AlphCompare>();
|
||||
for (const StringName &anim_name : anims) {
|
||||
|
|
|
|||
|
|
@ -829,10 +829,8 @@ void AnimationPlayerEditor::_update_animation_blend() {
|
|||
|
||||
blend_editor.tree->clear();
|
||||
|
||||
String current = animation->get_item_text(animation->get_selected());
|
||||
StringName current = animation->get_item_text(animation->get_selected());
|
||||
|
||||
List<StringName> anims;
|
||||
player->get_animation_list(&anims);
|
||||
TreeItem *root = blend_editor.tree->create_item();
|
||||
updating_blends = true;
|
||||
|
||||
|
|
@ -841,7 +839,7 @@ void AnimationPlayerEditor::_update_animation_blend() {
|
|||
blend_editor.next->clear();
|
||||
blend_editor.next->add_item("", i);
|
||||
|
||||
for (const StringName &to : anims) {
|
||||
for (const StringName &to : player->get_sorted_animation_list()) {
|
||||
TreeItem *blend = blend_editor.tree->create_item(root);
|
||||
blend->set_editable(0, false);
|
||||
blend->set_editable(1, true);
|
||||
|
|
@ -1038,7 +1036,7 @@ void AnimationPlayerEditor::_update_player() {
|
|||
return;
|
||||
}
|
||||
|
||||
List<StringName> libraries;
|
||||
LocalVector<StringName> libraries;
|
||||
player->get_animation_library_list(&libraries);
|
||||
|
||||
int active_idx = -1;
|
||||
|
|
@ -1063,7 +1061,7 @@ void AnimationPlayerEditor::_update_player() {
|
|||
}
|
||||
}
|
||||
|
||||
List<StringName> animlist;
|
||||
LocalVector<StringName> animlist;
|
||||
anim_library->get_animation_list(&animlist);
|
||||
|
||||
for (const StringName &E : animlist) {
|
||||
|
|
@ -1169,7 +1167,7 @@ void AnimationPlayerEditor::_update_name_dialog_library_dropdown() {
|
|||
}
|
||||
}
|
||||
|
||||
List<StringName> libraries;
|
||||
LocalVector<StringName> libraries;
|
||||
player->get_animation_library_list(&libraries);
|
||||
library->clear();
|
||||
|
||||
|
|
@ -1511,7 +1509,7 @@ void AnimationPlayerEditor::_current_animation_changed(const StringName &p_name)
|
|||
}
|
||||
|
||||
// Determine the read-only status of the animation's library and the libraries as a whole.
|
||||
List<StringName> libraries;
|
||||
LocalVector<StringName> libraries;
|
||||
player->get_animation_library_list(&libraries);
|
||||
|
||||
bool current_animation_library_is_readonly = false;
|
||||
|
|
@ -1523,7 +1521,7 @@ void AnimationPlayerEditor::_current_animation_changed(const StringName &p_name)
|
|||
all_animation_libraries_are_readonly = false;
|
||||
}
|
||||
|
||||
List<StringName> animlist;
|
||||
LocalVector<StringName> animlist;
|
||||
anim_library->get_animation_list(&animlist);
|
||||
bool animation_found = false;
|
||||
for (const StringName &E : animlist) {
|
||||
|
|
@ -2464,13 +2462,13 @@ void AnimationPlayerEditorPlugin::_update_dummy_player(AnimationMixer *p_mixer)
|
|||
memdelete(default_node);
|
||||
|
||||
// Library list is dynamically added to property list, should be copied explicitly.
|
||||
List<StringName> existing_libs;
|
||||
LocalVector<StringName> existing_libs;
|
||||
dummy_player->get_animation_library_list(&existing_libs);
|
||||
for (const StringName &K : existing_libs) {
|
||||
dummy_player->remove_animation_library(K);
|
||||
}
|
||||
|
||||
List<StringName> libraries;
|
||||
LocalVector<StringName> libraries;
|
||||
p_mixer->get_animation_library_list(&libraries);
|
||||
for (const StringName &K : libraries) {
|
||||
dummy_player->add_animation_library(K, p_mixer->get_animation_library(K));
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include "scene/gui/line_edit.h"
|
||||
#include "scene/gui/option_button.h"
|
||||
#include "scene/gui/panel_container.h"
|
||||
#include "scene/gui/rich_text_label.h"
|
||||
#include "scene/gui/separator.h"
|
||||
#include "scene/main/viewport.h"
|
||||
#include "scene/main/window.h"
|
||||
|
|
@ -823,8 +824,7 @@ void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) {
|
|||
animations_menu->clear();
|
||||
animations_to_add.clear();
|
||||
|
||||
List<StringName> animation_names;
|
||||
tree->get_animation_list(&animation_names);
|
||||
LocalVector<StringName> animation_names = tree->get_sorted_animation_list();
|
||||
menu->add_submenu_node_item(TTR("Add Animation"), animations_menu);
|
||||
if (animation_names.is_empty()) {
|
||||
menu->set_item_disabled(menu->get_item_idx_from_text(TTR("Add Animation")), true);
|
||||
|
|
|
|||
|
|
@ -649,9 +649,7 @@ void AnimationTrackKeyEdit::_get_property_list(List<PropertyInfo> *p_list) const
|
|||
if (root_path) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(root_path->get_node_or_null(animation->track_get_path(track)));
|
||||
if (ap) {
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &E : anims) {
|
||||
for (const StringName &E : ap->get_sorted_animation_list()) {
|
||||
if (!animations.is_empty()) {
|
||||
animations += ",";
|
||||
}
|
||||
|
|
@ -1255,9 +1253,7 @@ void AnimationMultiTrackKeyEdit::_get_property_list(List<PropertyInfo> *p_list)
|
|||
if (root_path) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(root_path->get_node_or_null(animation->track_get_path(first_track)));
|
||||
if (ap) {
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &anim : anims) {
|
||||
for (const StringName &anim : ap->get_sorted_animation_list()) {
|
||||
if (!animations.is_empty()) {
|
||||
animations += ",";
|
||||
}
|
||||
|
|
@ -4290,10 +4286,8 @@ void AnimationTrackEditor::_animation_track_remove_request(int p_track, Ref<Anim
|
|||
if (reset->track_get_path(i) == p_from_animation->track_get_path(p_track)) {
|
||||
// Check if the reset track isn't used by other animations.
|
||||
bool used = false;
|
||||
List<StringName> animation_list;
|
||||
player->get_animation_list(&animation_list);
|
||||
|
||||
for (const StringName &anim_name : animation_list) {
|
||||
for (const StringName &anim_name : player->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = player->get_animation(anim_name);
|
||||
if (anim == p_from_animation || anim == reset) {
|
||||
continue;
|
||||
|
|
@ -7716,9 +7710,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
|
|||
} break;
|
||||
case EDIT_CLEAN_UP_ANIMATION_CONFIRM: {
|
||||
if (cleanup_all->is_pressed()) {
|
||||
List<StringName> names;
|
||||
AnimationPlayerEditor::get_singleton()->get_player()->get_animation_list(&names);
|
||||
for (const StringName &E : names) {
|
||||
for (const StringName &E : AnimationPlayerEditor::get_singleton()->get_player()->get_sorted_animation_list()) {
|
||||
_cleanup_animation(AnimationPlayerEditor::get_singleton()->get_player()->get_animation(E));
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -238,26 +238,19 @@ bool AnimationTreeEditor::can_edit(const Ref<AnimationNode> &p_node) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
Vector<String> AnimationTreeEditor::get_animation_list() {
|
||||
LocalVector<StringName> AnimationTreeEditor::get_animation_list() {
|
||||
// This can be called off the main thread due to resource preview generation. Quit early in that case.
|
||||
if (!singleton->tree || !Thread::is_main_thread() || !singleton->is_visible()) {
|
||||
// When tree is empty, singleton not in the main thread.
|
||||
return Vector<String>();
|
||||
return LocalVector<StringName>();
|
||||
}
|
||||
|
||||
AnimationTree *tree = singleton->tree;
|
||||
if (!tree) {
|
||||
return Vector<String>();
|
||||
return LocalVector<StringName>();
|
||||
}
|
||||
|
||||
List<StringName> anims;
|
||||
tree->get_animation_list(&anims);
|
||||
Vector<String> ret;
|
||||
for (const StringName &E : anims) {
|
||||
ret.push_back(E);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return tree->get_sorted_animation_list();
|
||||
}
|
||||
|
||||
AnimationTreeEditor::AnimationTreeEditor() {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class AnimationTreeEditor : public EditorDock {
|
|||
void _path_button_pressed(int p_path);
|
||||
void _animation_list_changed();
|
||||
|
||||
static Vector<String> get_animation_list();
|
||||
static LocalVector<StringName> get_animation_list();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
|
|
|||
|
|
@ -1977,10 +1977,7 @@ bool SceneTreeDock::_has_tracks_to_delete(Node *p_node, List<Node *> &p_to_delet
|
|||
if (ap) {
|
||||
Node *root = ap->get_node(ap->get_root_node());
|
||||
if (root && !p_to_delete.find(root)) {
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
|
||||
for (const StringName &E : anims) {
|
||||
for (const StringName &E : ap->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = ap->get_animation(E);
|
||||
if (anim.is_null()) {
|
||||
continue;
|
||||
|
|
@ -2242,15 +2239,13 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
|
|||
}
|
||||
|
||||
if (!points_to_other_animation_player) {
|
||||
List<StringName> anims;
|
||||
mixer->get_animation_list(&anims);
|
||||
Node *root = mixer->get_node(mixer->get_root_node());
|
||||
|
||||
if (root) {
|
||||
HashMap<Node *, NodePath>::Iterator found_root_path = p_renames->find(root);
|
||||
NodePath new_root_path = found_root_path ? found_root_path->value : root->get_path();
|
||||
if (!new_root_path.is_empty()) { // No renaming if root node is deleted.
|
||||
for (const StringName &E : anims) {
|
||||
for (const StringName &E : mixer->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = mixer->get_animation(E);
|
||||
if (!r_rem_anims->has(anim)) {
|
||||
r_rem_anims->insert(anim, HashSet<int>());
|
||||
|
|
|
|||
|
|
@ -95,9 +95,7 @@ void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p
|
|||
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
|
||||
while (nodes.size()) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
for (const StringName &name : ap->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int len = anim->get_track_count();
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
|
@ -208,9 +206,7 @@ void PostImportPluginSkeletonRenamer::internal_process(InternalImportCategory p_
|
|||
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
|
||||
while (nodes.size()) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
for (const StringName &name : ap->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int track_len = anim->get_track_count();
|
||||
for (int i = 0; i < track_len; i++) {
|
||||
|
|
|
|||
|
|
@ -167,9 +167,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
|
||||
while (nodes.size()) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
for (const StringName &name : ap->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int track_len = anim->get_track_count();
|
||||
for (int i = 0; i < track_len; i++) {
|
||||
|
|
@ -235,9 +233,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
|
||||
while (nodes.size()) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
for (const StringName &name : ap->get_sorted_animation_list()) {
|
||||
if (String(name).contains_char('/')) {
|
||||
continue; // Avoid animation library which may be created by importer dynamically.
|
||||
}
|
||||
|
|
@ -407,9 +403,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
|
||||
while (nodes.size()) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
for (const StringName &name : ap->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int track_len = anim->get_track_count();
|
||||
for (int i = 0; i < track_len; i++) {
|
||||
|
|
@ -579,9 +573,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
String general_skeleton_pathname = UNIQUE_NODE_PREFIX + profile_skeleton->get_name();
|
||||
while (nodes.size()) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
for (const StringName &name : ap->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int track_len = anim->get_track_count();
|
||||
for (int i = 0; i < track_len; i++) {
|
||||
|
|
@ -715,9 +707,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
while (nodes.size()) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
ERR_CONTINUE(!ap);
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
for (const StringName &name : ap->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int track_len = anim->get_track_count();
|
||||
for (int i = 0; i < track_len; i++) {
|
||||
|
|
@ -846,9 +836,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
|||
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
|
||||
while (nodes.size()) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
for (const StringName &name : ap->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int track_len = anim->get_track_count();
|
||||
for (int i = 0; i < track_len; i++) {
|
||||
|
|
|
|||
|
|
@ -69,13 +69,11 @@ void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCate
|
|||
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
|
||||
while (nodes.size()) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
|
||||
Ref<AnimationLibrary> unmapped_al;
|
||||
unmapped_al.instantiate();
|
||||
|
||||
for (const StringName &name : anims) {
|
||||
for (const StringName &name : ap->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int track_len = anim->get_track_count();
|
||||
Vector<int> remove_indices;
|
||||
|
|
|
|||
|
|
@ -616,7 +616,7 @@ void _populate_scalable_nodes_collection(Node *p_node, ScalableNodeCollection &p
|
|||
}
|
||||
AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_node);
|
||||
if (animation_player) {
|
||||
List<StringName> animation_list;
|
||||
LocalVector<StringName> animation_list;
|
||||
animation_player->get_animation_list(&animation_list);
|
||||
|
||||
for (const StringName &E : animation_list) {
|
||||
|
|
@ -702,7 +702,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R
|
|||
|
||||
bool nodes_were_renamed = r_node_renames.size() != 0;
|
||||
|
||||
List<StringName> anims;
|
||||
LocalVector<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &E : anims) {
|
||||
Ref<Animation> anim = ap->get_animation(E);
|
||||
|
|
@ -1079,7 +1079,7 @@ Node *ResourceImporterScene::_pre_fix_animations(Node *p_node, Node *p_root, con
|
|||
|
||||
if (Object::cast_to<AnimationPlayer>(p_node)) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
|
||||
List<StringName> anims;
|
||||
LocalVector<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
|
||||
AnimationImportTracks import_tracks_mode[TRACK_CHANNEL_MAX] = {
|
||||
|
|
@ -1127,7 +1127,7 @@ Node *ResourceImporterScene::_post_fix_animations(Node *p_node, Node *p_root, co
|
|||
|
||||
if (Object::cast_to<AnimationPlayer>(p_node)) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
|
||||
List<StringName> anims;
|
||||
LocalVector<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
|
||||
if (p_remove_immutable_tracks) {
|
||||
|
|
@ -1504,10 +1504,10 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
|||
for (int node_i = 0; node_i < children.size(); node_i++) {
|
||||
AnimationPlayer *anim_player = cast_to<AnimationPlayer>(children[node_i]);
|
||||
ERR_CONTINUE(anim_player == nullptr);
|
||||
List<StringName> anim_list;
|
||||
LocalVector<StringName> anim_list;
|
||||
anim_player->get_animation_list(&anim_list);
|
||||
if (anim_list.size() == 1) {
|
||||
selected_animation_name = anim_list.front()->get();
|
||||
selected_animation_name = anim_list[0];
|
||||
}
|
||||
rest_animation = anim_player->get_animation(selected_animation_name);
|
||||
if (rest_animation.is_valid()) {
|
||||
|
|
@ -1520,10 +1520,10 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
|||
if (rest_animation.is_null()) {
|
||||
Ref<AnimationLibrary> library(external_object);
|
||||
if (library.is_valid()) {
|
||||
List<StringName> anim_list;
|
||||
LocalVector<StringName> anim_list;
|
||||
library->get_animation_list(&anim_list);
|
||||
if (anim_list.size() == 1) {
|
||||
selected_animation_name = String(anim_list.front()->get());
|
||||
selected_animation_name = String(anim_list[0]);
|
||||
}
|
||||
rest_animation = library->get_animation(selected_animation_name);
|
||||
}
|
||||
|
|
@ -1873,7 +1873,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
|||
}
|
||||
|
||||
if (post_importer_plugins.size()) {
|
||||
List<StringName> anims;
|
||||
LocalVector<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
if (p_animation_data.has(name)) {
|
||||
|
|
@ -2098,7 +2098,7 @@ void ResourceImporterScene::_create_slices(AnimationPlayer *ap, Ref<Animation> a
|
|||
}
|
||||
|
||||
void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error) {
|
||||
List<StringName> anim_names;
|
||||
LocalVector<StringName> anim_names;
|
||||
anim->get_animation_list(&anim_names);
|
||||
for (const StringName &E : anim_names) {
|
||||
Ref<Animation> a = anim->get_animation(E);
|
||||
|
|
@ -2107,7 +2107,7 @@ void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_
|
|||
}
|
||||
|
||||
void ResourceImporterScene::_compress_animations(AnimationPlayer *anim, int p_page_size_kb) {
|
||||
List<StringName> anim_names;
|
||||
LocalVector<StringName> anim_names;
|
||||
anim->get_animation_list(&anim_names);
|
||||
for (const StringName &E : anim_names) {
|
||||
Ref<Animation> a = anim->get_animation(E);
|
||||
|
|
@ -2384,10 +2384,10 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor
|
|||
Ref<AnimationLibrary> library(res);
|
||||
String selected_animation_name = p_options["rest_pose/selected_animation"];
|
||||
if (library.is_valid()) {
|
||||
List<StringName> anim_list;
|
||||
LocalVector<StringName> anim_list;
|
||||
library->get_animation_list(&anim_list);
|
||||
if (anim_list.size() == 1) {
|
||||
selected_animation_name = String(anim_list.front()->get());
|
||||
selected_animation_name = String(anim_list[0]);
|
||||
}
|
||||
if (library->has_animation(selected_animation_name)) {
|
||||
anim = library->get_animation(selected_animation_name);
|
||||
|
|
@ -2818,7 +2818,7 @@ void ResourceImporterScene::_copy_meta(Object *p_src_object, Object *p_dst_objec
|
|||
}
|
||||
|
||||
void ResourceImporterScene::_optimize_track_usage(AnimationPlayer *p_player, AnimationImportTracks *p_track_actions) {
|
||||
List<StringName> anims;
|
||||
LocalVector<StringName> anims;
|
||||
p_player->get_animation_list(&anims);
|
||||
Node *parent = p_player->get_parent();
|
||||
ERR_FAIL_NULL(parent);
|
||||
|
|
@ -3333,10 +3333,10 @@ Error ResourceImporterScene::import(ResourceUID::ID p_source_id, const String &p
|
|||
for (int i = 0; i < scene->get_child_count(); i++) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(scene->get_child(i));
|
||||
if (ap) {
|
||||
List<StringName> libs;
|
||||
LocalVector<StringName> libs;
|
||||
ap->get_animation_library_list(&libs);
|
||||
if (libs.size()) {
|
||||
library = ap->get_animation_library(libs.front()->get());
|
||||
library = ap->get_animation_library(libs[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,10 +142,10 @@ class SceneImportSettingsData : public Object {
|
|||
hint_string = anim->get_name();
|
||||
}
|
||||
if (library.is_valid()) {
|
||||
List<StringName> anim_names;
|
||||
LocalVector<StringName> anim_names;
|
||||
library->get_animation_list(&anim_names);
|
||||
if (anim_names.size() == 1) {
|
||||
(*settings)["rest_pose/selected_animation"] = String(anim_names.front()->get());
|
||||
(*settings)["rest_pose/selected_animation"] = String(anim_names[0]);
|
||||
}
|
||||
for (StringName anim_name : anim_names) {
|
||||
hint_string += "," + anim_name; // Include preceding, as a catch-all.
|
||||
|
|
@ -465,9 +465,7 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite
|
|||
AnimationPlayer *anim_node = Object::cast_to<AnimationPlayer>(p_node);
|
||||
if (anim_node) {
|
||||
Vector<String> animation_list;
|
||||
List<StringName> animations;
|
||||
anim_node->get_animation_list(&animations);
|
||||
for (const StringName &E : animations) {
|
||||
for (const StringName &E : anim_node->get_sorted_animation_list()) {
|
||||
_fill_animation(scene_tree, anim_node->get_animation(E), E, item);
|
||||
animation_list.append(E);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,10 +67,7 @@ void EditorPropertyRootMotion::_node_assign() {
|
|||
|
||||
HashSet<String> paths;
|
||||
{
|
||||
List<StringName> animations;
|
||||
mixer->get_animation_list(&animations);
|
||||
|
||||
for (const StringName &E : animations) {
|
||||
for (const StringName &E : mixer->get_sorted_animation_list()) {
|
||||
Ref<Animation> anim = mixer->get_animation(E);
|
||||
for (int i = 0; i < anim->get_track_count(); i++) {
|
||||
String pathname = anim->track_get_path(i).get_concatenated_names();
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ void EditorFolding::_fill_folds(const Node *p_root, const Node *p_node, Array &p
|
|||
|
||||
const AnimationMixer *anim_mixer = Object::cast_to<AnimationMixer>(p_node);
|
||||
if (anim_mixer) {
|
||||
List<StringName> anim_names;
|
||||
LocalVector<StringName> anim_names;
|
||||
anim_mixer->get_animation_list(&anim_names);
|
||||
for (const StringName &anim_name : anim_names) {
|
||||
Ref<Animation> anim = anim_mixer->get_animation(anim_name);
|
||||
|
|
|
|||
6
misc/extension_api_validation/4.6-stable/GH-116394.txt
Normal file
6
misc/extension_api_validation/4.6-stable/GH-116394.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
GH-116394
|
||||
---------
|
||||
Validate extension JSON: Error: Field 'classes/Animation/methods/get_length/return_value': meta changed value in new API, from "float" to "double".
|
||||
Validate extension JSON: Error: Field 'classes/Animation/methods/set_length/arguments/0': meta changed value in new API, from "float" to "double".
|
||||
|
||||
Return type and parameter changed from real_t to double to match internals. No compatibility methods registered because GDExtension FFI already uses double.
|
||||
|
|
@ -3519,9 +3519,7 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> p_state) {
|
|||
}
|
||||
for (int32_t player_i = 0; player_i < p_state->animation_players.size(); player_i++) {
|
||||
AnimationPlayer *animation_player = p_state->animation_players[player_i];
|
||||
List<StringName> animations;
|
||||
animation_player->get_animation_list(&animations);
|
||||
for (const StringName &animation_name : animations) {
|
||||
for (const StringName &animation_name : animation_player->get_sorted_animation_list()) {
|
||||
_convert_animation(p_state, animation_player, animation_name);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ StringName AnimationNodeAnimation::get_animation() const {
|
|||
return animation;
|
||||
}
|
||||
|
||||
Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = nullptr;
|
||||
LocalVector<StringName> (*AnimationNodeAnimation::get_editable_animation_list)() = nullptr;
|
||||
|
||||
void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
AnimationNode::get_parameter_list(r_list);
|
||||
|
|
@ -82,9 +82,9 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::get_node_time_info() const {
|
|||
|
||||
void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const {
|
||||
if (Engine::get_singleton()->is_editor_hint() && p_property.name == "animation" && get_editable_animation_list) {
|
||||
Vector<String> names = get_editable_animation_list();
|
||||
LocalVector<StringName> names = get_editable_animation_list();
|
||||
String anims;
|
||||
for (int i = 0; i < names.size(); i++) {
|
||||
for (uint32_t i = 0; i < names.size(); i++) {
|
||||
if (i > 0) {
|
||||
anims += ",";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public:
|
|||
|
||||
virtual NodeTimeInfo get_node_time_info() const override; // Wrapper of get_parameter().
|
||||
|
||||
static Vector<String> (*get_editable_animation_list)();
|
||||
static LocalVector<StringName> (*get_editable_animation_list)();
|
||||
|
||||
virtual String get_caption() const override;
|
||||
virtual NodeTimeInfo process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override;
|
||||
|
|
|
|||
|
|
@ -160,33 +160,32 @@ void AnimationMixer::_animation_set_cache_update() {
|
|||
for (const AnimationLibraryData &lib : animation_libraries) {
|
||||
for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) {
|
||||
StringName key = lib.name == StringName() ? K.key : StringName(String(lib.name) + "/" + String(K.key));
|
||||
if (!animation_set.has(key)) {
|
||||
AnimationData ad;
|
||||
ad.animation = K.value;
|
||||
ad.animation_library = lib.name;
|
||||
ad.name = key;
|
||||
ad.last_update = animation_set_update_pass;
|
||||
animation_set.insert(ad.name, ad);
|
||||
cache_valid = false; // No need to delete the cache, but it must be updated to add track caches.
|
||||
|
||||
AnimationData *ad = animation_set.getptr(key);
|
||||
|
||||
if (!ad) {
|
||||
ad = &animation_set.insert(key, AnimationData())->value; // 2) Hash key and lookup again.
|
||||
ad->animation = K.value;
|
||||
ad->animation_library = lib.name;
|
||||
ad->name = key;
|
||||
ad->last_update = animation_set_update_pass;
|
||||
cache_valid = false;
|
||||
} else {
|
||||
AnimationData &ad = animation_set[key];
|
||||
if (ad.last_update != animation_set_update_pass) {
|
||||
// Was not updated, update. If the animation is duplicated, the second one will be ignored.
|
||||
if (ad.animation != K.value || ad.animation_library != lib.name) {
|
||||
// Animation changed, update and clear caches.
|
||||
if (ad->last_update != animation_set_update_pass) {
|
||||
if (ad->animation != K.value || ad->animation_library != lib.name) {
|
||||
clear_cache_needed = true;
|
||||
ad.animation = K.value;
|
||||
ad.animation_library = lib.name;
|
||||
ad->animation = K.value;
|
||||
ad->animation_library = lib.name;
|
||||
}
|
||||
|
||||
ad.last_update = animation_set_update_pass;
|
||||
ad->last_update = animation_set_update_pass;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check removed.
|
||||
List<StringName> to_erase;
|
||||
LocalVector<StringName> to_erase;
|
||||
for (const KeyValue<StringName, AnimationData> &E : animation_set) {
|
||||
if (E.value.last_update != animation_set_update_pass) {
|
||||
// Was not updated, must be erased.
|
||||
|
|
@ -195,9 +194,8 @@ void AnimationMixer::_animation_set_cache_update() {
|
|||
}
|
||||
}
|
||||
|
||||
while (to_erase.size()) {
|
||||
animation_set.erase(to_erase.front()->get());
|
||||
to_erase.pop_front();
|
||||
for (const StringName &E : to_erase) {
|
||||
animation_set.erase(E);
|
||||
}
|
||||
|
||||
if (clear_cache_needed) {
|
||||
|
|
@ -213,7 +211,7 @@ void AnimationMixer::_animation_added(const StringName &p_name, const StringName
|
|||
}
|
||||
|
||||
void AnimationMixer::_animation_removed(const StringName &p_name, const StringName &p_library) {
|
||||
StringName name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));
|
||||
const StringName name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));
|
||||
|
||||
if (!animation_set.has(name)) {
|
||||
return; // No need to update because not the one from the library being used.
|
||||
|
|
@ -225,8 +223,8 @@ void AnimationMixer::_animation_removed(const StringName &p_name, const StringNa
|
|||
}
|
||||
|
||||
void AnimationMixer::_animation_renamed(const StringName &p_name, const StringName &p_to_name, const StringName &p_library) {
|
||||
StringName from_name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));
|
||||
StringName to_name = p_library == StringName() ? p_to_name : StringName(String(p_library) + "/" + String(p_to_name));
|
||||
const StringName from_name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));
|
||||
const StringName to_name = p_library == StringName() ? p_to_name : StringName(String(p_library) + "/" + String(p_to_name));
|
||||
|
||||
if (!animation_set.has(from_name)) {
|
||||
return; // No need to update because not the one from the library being used.
|
||||
|
|
@ -260,7 +258,7 @@ TypedArray<StringName> AnimationMixer::_get_animation_library_list() const {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void AnimationMixer::get_animation_library_list(List<StringName> *p_libraries) const {
|
||||
void AnimationMixer::get_animation_library_list(LocalVector<StringName> *p_libraries) const {
|
||||
for (const AnimationLibraryData &lib : animation_libraries) {
|
||||
p_libraries->push_back(lib.name);
|
||||
}
|
||||
|
|
@ -285,13 +283,14 @@ bool AnimationMixer::has_animation_library(const StringName &p_name) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
StringName AnimationMixer::find_animation_library(const Ref<Animation> &p_animation) const {
|
||||
const StringName &AnimationMixer::find_animation_library(const Ref<Animation> &p_animation) const {
|
||||
for (const KeyValue<StringName, AnimationData> &E : animation_set) {
|
||||
if (E.value.animation == p_animation) {
|
||||
return E.value.animation_library;
|
||||
}
|
||||
}
|
||||
return StringName();
|
||||
const static StringName empty = StringName();
|
||||
return empty;
|
||||
}
|
||||
|
||||
Error AnimationMixer::add_animation_library(const StringName &p_name, const Ref<AnimationLibrary> &p_animation_library) {
|
||||
|
|
@ -394,21 +393,33 @@ void AnimationMixer::rename_animation_library(const StringName &p_name, const St
|
|||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
void AnimationMixer::get_animation_list(List<StringName> *p_animations) const {
|
||||
List<String> anims;
|
||||
LocalVector<StringName> AnimationMixer::get_sorted_animation_list() const {
|
||||
LocalVector<StringName> animations;
|
||||
get_animation_list(&animations);
|
||||
animations.sort_custom<StringName::AlphCompare>();
|
||||
return animations;
|
||||
}
|
||||
|
||||
void AnimationMixer::get_animation_list(LocalVector<StringName> *p_animations) const {
|
||||
p_animations->reserve(p_animations->size() + animation_set.size());
|
||||
for (const KeyValue<StringName, AnimationData> &E : animation_set) {
|
||||
anims.push_back(E.key);
|
||||
}
|
||||
anims.sort();
|
||||
for (const String &E : anims) {
|
||||
p_animations->push_back(E);
|
||||
p_animations->push_back(E.key);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Animation> AnimationMixer::get_animation(const StringName &p_name) const {
|
||||
ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref<Animation>(), vformat("Animation not found: \"%s\".", p_name));
|
||||
const AnimationData &anim_data = animation_set[p_name];
|
||||
return anim_data.animation;
|
||||
const Ref<Animation> &AnimationMixer::get_animation(const StringName &p_name) const {
|
||||
const Ref<Animation> &animation = get_animation_or_null(p_name);
|
||||
ERR_FAIL_COND_V_MSG(animation.is_null(), animation, vformat("Animation not found: \"%s\".", p_name));
|
||||
return animation;
|
||||
}
|
||||
|
||||
const Ref<Animation> &AnimationMixer::get_animation_or_null(const StringName &p_name) const {
|
||||
const AnimationData *ad = animation_set.getptr(p_name);
|
||||
if (!ad) {
|
||||
const static Ref<Animation> empty = Ref<Animation>();
|
||||
return empty;
|
||||
}
|
||||
return ad->animation;
|
||||
}
|
||||
|
||||
bool AnimationMixer::has_animation(const StringName &p_name) const {
|
||||
|
|
@ -618,7 +629,7 @@ void AnimationMixer::_init_root_motion_cache() {
|
|||
root_motion_scale_accumulator = Vector3(1, 1, 1);
|
||||
}
|
||||
|
||||
void AnimationMixer::_create_track_num_to_track_cache_for_animation(Ref<Animation> &p_animation) {
|
||||
void AnimationMixer::_create_track_num_to_track_cache_for_animation(const Ref<Animation> &p_animation) {
|
||||
if (animation_track_num_to_track_cache.has(p_animation)) {
|
||||
// In AnimationMixer::_update_caches, it retrieves all animations via AnimationMixer::get_animation_list
|
||||
// Since multiple AnimationLibraries can share the same Animation, it is possible that the cache is already created.
|
||||
|
|
@ -640,12 +651,15 @@ void AnimationMixer::_create_track_num_to_track_cache_for_animation(Ref<Animatio
|
|||
|
||||
bool AnimationMixer::_update_caches() {
|
||||
setup_pass++;
|
||||
if (unlikely(setup_pass == 0)) {
|
||||
setup_pass = 1;
|
||||
}
|
||||
|
||||
root_motion_cache.loc = Vector3(0, 0, 0);
|
||||
root_motion_cache.rot = Quaternion(0, 0, 0, 1);
|
||||
root_motion_cache.scale = Vector3(1, 1, 1);
|
||||
|
||||
List<StringName> sname_list;
|
||||
LocalVector<StringName> sname_list;
|
||||
get_animation_list(&sname_list);
|
||||
|
||||
bool check_path = GLOBAL_GET_CACHED(bool, "animation/warnings/check_invalid_track_paths");
|
||||
|
|
@ -677,19 +691,21 @@ bool AnimationMixer::_update_caches() {
|
|||
reset_anim = get_animation(SceneStringName(RESET));
|
||||
}
|
||||
for (const StringName &E : sname_list) {
|
||||
Ref<Animation> anim = get_animation(E);
|
||||
const Ref<Animation> &anim = get_animation(E);
|
||||
for (int i = 0; i < anim->get_track_count(); i++) {
|
||||
if (!anim->track_is_enabled(i)) {
|
||||
continue;
|
||||
}
|
||||
NodePath path = anim->track_get_path(i);
|
||||
(void)path.hash(); // Make sure the cache is valid for faster comparison.
|
||||
|
||||
Animation::TypeHash thash = anim->track_get_type_hash(i);
|
||||
Animation::TrackType track_src_type = anim->track_get_type(i);
|
||||
Animation::TrackType track_cache_type = Animation::get_cache_type(track_src_type);
|
||||
|
||||
TrackCache *track = nullptr;
|
||||
if (track_cache.has(thash)) {
|
||||
track = track_cache.get(thash);
|
||||
if (TrackCache **p = track_cache.getptr(thash)) {
|
||||
track = *p;
|
||||
}
|
||||
|
||||
// If not valid, delete track.
|
||||
|
|
@ -947,7 +963,7 @@ bool AnimationMixer::_update_caches() {
|
|||
}
|
||||
}
|
||||
|
||||
List<Animation::TypeHash> to_delete;
|
||||
LocalVector<Animation::TypeHash> to_delete;
|
||||
|
||||
for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
|
||||
if (K.value->setup_pass != setup_pass) {
|
||||
|
|
@ -955,11 +971,9 @@ bool AnimationMixer::_update_caches() {
|
|||
}
|
||||
}
|
||||
|
||||
while (to_delete.front()) {
|
||||
Animation::TypeHash thash = to_delete.front()->get();
|
||||
for (const Animation::TypeHash &thash : to_delete) {
|
||||
memdelete(track_cache[thash]);
|
||||
track_cache.erase(thash);
|
||||
to_delete.pop_front();
|
||||
}
|
||||
|
||||
track_map.clear();
|
||||
|
|
@ -976,7 +990,7 @@ bool AnimationMixer::_update_caches() {
|
|||
|
||||
animation_track_num_to_track_cache.clear();
|
||||
for (const StringName &E : sname_list) {
|
||||
Ref<Animation> anim = get_animation(E);
|
||||
const Ref<Animation> &anim = get_animation(E);
|
||||
_create_track_num_to_track_cache_for_animation(anim);
|
||||
}
|
||||
|
||||
|
|
@ -1143,14 +1157,29 @@ void AnimationMixer::blend_capture(double p_delta) {
|
|||
|
||||
void AnimationMixer::_blend_calc_total_weight() {
|
||||
for (const AnimationInstance &ai : animation_instances) {
|
||||
Ref<Animation> a = ai.animation_data.animation;
|
||||
const Ref<Animation> &a = ai.animation_data.animation;
|
||||
real_t weight = ai.playback_info.weight;
|
||||
const real_t *track_weights_ptr = ai.playback_info.track_weights.ptr();
|
||||
int track_weights_count = ai.playback_info.track_weights.size();
|
||||
ERR_CONTINUE_EDMSG(!animation_track_num_to_track_cache.has(a), "No animation in cache.");
|
||||
LocalVector<TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache[a];
|
||||
thread_local HashSet<Animation::TypeHash, HashHasher> processed_hashes;
|
||||
processed_hashes.clear();
|
||||
if (Math::is_zero_approx(weight)) {
|
||||
continue;
|
||||
}
|
||||
Span<real_t> track_weights = ai.playback_info.track_weights;
|
||||
|
||||
LocalVector<TrackCache *> *t_cache = animation_track_num_to_track_cache.getptr(a);
|
||||
ERR_CONTINUE_EDMSG(!t_cache, "No animation in cache.");
|
||||
LocalVector<TrackCache *> &track_num_to_track_cache = *t_cache;
|
||||
|
||||
uint64_t pass_id = ++animation_instance_weight_pass_counter;
|
||||
// Handle wrap (slower but rare).
|
||||
if (unlikely(pass_id == 0)) {
|
||||
for (KeyValue<Animation::TypeHash, TrackCache *> &kv : track_cache) {
|
||||
if (kv.value) {
|
||||
kv.value->animation_instance_weight_applied_at = 0;
|
||||
}
|
||||
}
|
||||
animation_instance_weight_pass_counter = 1;
|
||||
pass_id = 1;
|
||||
}
|
||||
|
||||
const LocalVector<Animation::Track *> &tracks = a->get_tracks();
|
||||
Animation::Track *const *tracks_ptr = tracks.ptr();
|
||||
int count = tracks.size();
|
||||
|
|
@ -1159,18 +1188,30 @@ void AnimationMixer::_blend_calc_total_weight() {
|
|||
if (!animation_track->enabled) {
|
||||
continue;
|
||||
}
|
||||
Animation::TypeHash thash = animation_track->thash;
|
||||
TrackCache *track = track_num_to_track_cache[i];
|
||||
if (track == nullptr || processed_hashes.has(thash)) {
|
||||
if (track == nullptr) {
|
||||
// No path, but avoid error spamming.
|
||||
// Or, there is the case different track type with same path; These can be distinguished by hash. So don't add the weight doubly.
|
||||
continue;
|
||||
}
|
||||
|
||||
// In some cases (e.g. TrackCacheTransform),
|
||||
// multiple Animation::Tracks (e.g. TYPE_POSITION_3D, TYPE_ROTATION_3D and TYPE_SCALE_3D)
|
||||
// can point to the same TrackCache instance.
|
||||
// So we need to make sure that the weight is added only once per AnimationInstance.
|
||||
if (track->animation_instance_weight_applied_at == pass_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int blend_idx = track->blend_idx;
|
||||
ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);
|
||||
real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;
|
||||
real_t blend;
|
||||
if (!track_weights.is_empty() && blend_idx < static_cast<int>(track_weights.size())) {
|
||||
blend = track_weights[blend_idx] * weight;
|
||||
} else {
|
||||
blend = weight;
|
||||
}
|
||||
track->total_weight += blend;
|
||||
processed_hashes.insert(thash);
|
||||
track->animation_instance_weight_applied_at = pass_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1181,7 +1222,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|||
bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint();
|
||||
#endif // TOOLS_ENABLED
|
||||
for (const AnimationInstance &ai : animation_instances) {
|
||||
Ref<Animation> a = ai.animation_data.animation;
|
||||
const Ref<Animation> &a = ai.animation_data.animation;
|
||||
double time = ai.playback_info.time;
|
||||
double delta = ai.playback_info.delta;
|
||||
double start = ai.playback_info.start;
|
||||
|
|
@ -1190,18 +1231,18 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|||
Animation::LoopedFlag looped_flag = ai.playback_info.looped_flag;
|
||||
bool is_external_seeking = ai.playback_info.is_external_seeking;
|
||||
real_t weight = ai.playback_info.weight;
|
||||
const real_t *track_weights_ptr = ai.playback_info.track_weights.ptr();
|
||||
int track_weights_count = ai.playback_info.track_weights.size();
|
||||
bool backward = std::signbit(delta); // This flag is used by the root motion calculates or detecting the end of audio stream.
|
||||
bool seeked_backward = std::signbit(p_delta);
|
||||
#ifndef _3D_DISABLED
|
||||
bool calc_root = !seeked || is_external_seeking;
|
||||
#endif // _3D_DISABLED
|
||||
ERR_CONTINUE_EDMSG(!animation_track_num_to_track_cache.has(a), "No animation in cache.");
|
||||
LocalVector<TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache[a];
|
||||
LocalVector<TrackCache *> *t_cache = animation_track_num_to_track_cache.getptr(a);
|
||||
ERR_CONTINUE_EDMSG(!t_cache, "No animation in cache.");
|
||||
LocalVector<TrackCache *> &track_num_to_track_cache = *t_cache;
|
||||
|
||||
const LocalVector<Animation::Track *> &tracks = a->get_tracks();
|
||||
Animation::Track *const *tracks_ptr = tracks.ptr();
|
||||
real_t a_length = a->get_length();
|
||||
double a_length = a->get_length();
|
||||
int count = tracks.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
const Animation::Track *animation_track = tracks_ptr[i];
|
||||
|
|
@ -1214,7 +1255,14 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|||
}
|
||||
int blend_idx = track->blend_idx;
|
||||
ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);
|
||||
real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;
|
||||
real_t blend;
|
||||
Span<real_t> track_weights = ai.playback_info.track_weights;
|
||||
if (!track_weights.is_empty() && blend_idx < static_cast<int>(track_weights.size())) {
|
||||
blend = track_weights[blend_idx] * weight;
|
||||
} else {
|
||||
blend = weight;
|
||||
}
|
||||
|
||||
if (!deterministic) {
|
||||
// If non-deterministic, do normalization.
|
||||
// It would be better to make this if statement outside the for loop, but come here since too much code...
|
||||
|
|
@ -1626,7 +1674,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|||
t_obj->set_indexed(t->subpath, value);
|
||||
}
|
||||
} else {
|
||||
List<int> indices;
|
||||
LocalVector<int> indices;
|
||||
a->track_get_key_indices_in_range(i, time, delta, start, end, &indices, looped_flag);
|
||||
for (int &F : indices) {
|
||||
t->use_discrete = true;
|
||||
|
|
@ -1659,7 +1707,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|||
Vector<Variant> params = a->method_track_get_params(i, idx);
|
||||
_call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED);
|
||||
} else {
|
||||
List<int> indices;
|
||||
LocalVector<int> indices;
|
||||
a->track_get_key_indices_in_range(i, time, delta, start, end, &indices, looped_flag);
|
||||
for (int &F : indices) {
|
||||
StringName method = a->method_track_get_name(i, F);
|
||||
|
|
@ -1707,10 +1755,10 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|||
map.erase(idx);
|
||||
}
|
||||
} else {
|
||||
List<int> to_play;
|
||||
LocalVector<int> to_play;
|
||||
a->track_get_key_indices_in_range(i, time, delta, start, end, &to_play, looped_flag);
|
||||
if (to_play.size()) {
|
||||
idx = to_play.back()->get();
|
||||
idx = to_play[to_play.size() - 1];
|
||||
}
|
||||
}
|
||||
if (idx < 0) {
|
||||
|
|
@ -1790,10 +1838,10 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|||
}
|
||||
double pos = a->track_get_key_time(i, idx);
|
||||
StringName anim_name = a->animation_track_get_key_animation(i, idx);
|
||||
if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) {
|
||||
const Ref<Animation> &anim = player2->get_animation_or_null(anim_name);
|
||||
if (anim_name == SNAME("[stop]") || anim.is_null()) {
|
||||
continue;
|
||||
}
|
||||
Ref<Animation> anim = player2->get_animation(anim_name);
|
||||
double at_anim_pos = start;
|
||||
switch (anim->get_loop_mode()) {
|
||||
case Animation::LOOP_NONE: {
|
||||
|
|
@ -1822,12 +1870,12 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
|
|||
}
|
||||
} else {
|
||||
// Find stuff to play.
|
||||
List<int> to_play;
|
||||
LocalVector<int> to_play;
|
||||
a->track_get_key_indices_in_range(i, time, delta, start, end, &to_play, looped_flag);
|
||||
if (to_play.size()) {
|
||||
int idx = to_play.back()->get();
|
||||
int idx = to_play[to_play.size() - 1];
|
||||
StringName anim_name = a->animation_track_get_key_animation(i, idx);
|
||||
if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) {
|
||||
if (anim_name == SNAME("[stop]") || !player2->has_animation(anim_name)) {
|
||||
if (playing_caches.has(t)) {
|
||||
playing_caches.erase(t);
|
||||
player2->stop();
|
||||
|
|
@ -2033,19 +2081,19 @@ void AnimationMixer::_call_object(ObjectID p_object_id, const StringName &p_meth
|
|||
}
|
||||
}
|
||||
|
||||
void AnimationMixer::make_animation_instance(const StringName &p_name, const PlaybackInfo p_playback_info) {
|
||||
ERR_FAIL_COND(!has_animation(p_name));
|
||||
|
||||
void AnimationMixer::make_animation_instance(const StringName &p_name, const PlaybackInfo &p_playback_info) {
|
||||
const Ref<Animation> &animation = get_animation_or_null(p_name);
|
||||
ERR_FAIL_COND(animation.is_null());
|
||||
AnimationData ad;
|
||||
ad.name = p_name;
|
||||
ad.animation = get_animation(p_name);
|
||||
ad.animation_library = find_animation_library(ad.animation);
|
||||
|
||||
AnimationInstance ai;
|
||||
ai.animation_data = ad;
|
||||
ai.animation_data = std::move(ad);
|
||||
ai.playback_info = p_playback_info;
|
||||
|
||||
animation_instances.push_back(ai);
|
||||
animation_instances.push_back(std::move(ai));
|
||||
}
|
||||
|
||||
void AnimationMixer::clear_animation_instances() {
|
||||
|
|
@ -2286,9 +2334,9 @@ Ref<AnimatedValuesBackup> AnimationMixer::apply_reset(bool p_user_initiated) {
|
|||
|
||||
void AnimationMixer::capture(const StringName &p_name, double p_duration, Tween::TransitionType p_trans_type, Tween::EaseType p_ease_type) {
|
||||
ERR_FAIL_COND(!active);
|
||||
ERR_FAIL_COND(!has_animation(p_name));
|
||||
const Ref<Animation> &reference_animation = get_animation_or_null(p_name);
|
||||
ERR_FAIL_COND(reference_animation.is_null());
|
||||
ERR_FAIL_COND(p_duration <= 0);
|
||||
Ref<Animation> reference_animation = get_animation(p_name);
|
||||
|
||||
if (!cache_valid) {
|
||||
_update_caches(); // Need to retrieve object id.
|
||||
|
|
@ -2370,13 +2418,11 @@ void AnimationMixer::get_argument_options(const StringName &p_function, int p_id
|
|||
const String pf = p_function;
|
||||
if (p_idx == 0) {
|
||||
if (pf == "get_animation" || pf == "has_animation") {
|
||||
List<StringName> al;
|
||||
get_animation_list(&al);
|
||||
for (const StringName &name : al) {
|
||||
for (const StringName &name : get_sorted_animation_list()) {
|
||||
r_options->push_back(String(name).quote());
|
||||
}
|
||||
} else if (pf == "get_animation_library" || pf == "has_animation_library" || pf == "remove_animation_library" || pf == "rename_animation_library") {
|
||||
List<StringName> al;
|
||||
LocalVector<StringName> al;
|
||||
get_animation_library_list(&al);
|
||||
for (const StringName &name : al) {
|
||||
r_options->push_back(String(name).quote());
|
||||
|
|
@ -2495,7 +2541,7 @@ AnimationMixer::AnimationMixer() {
|
|||
AnimationMixer::~AnimationMixer() {
|
||||
}
|
||||
|
||||
void AnimatedValuesBackup::set_data(const AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> p_data) {
|
||||
void AnimatedValuesBackup::set_data(const AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> &p_data) {
|
||||
clear_data();
|
||||
|
||||
for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : p_data) {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ public:
|
|||
};
|
||||
|
||||
struct AnimationData {
|
||||
String name;
|
||||
StringName name;
|
||||
Ref<Animation> animation;
|
||||
StringName animation_library;
|
||||
uint64_t last_update = 0;
|
||||
|
|
@ -91,7 +91,10 @@ public:
|
|||
bool is_external_seeking = false;
|
||||
Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
|
||||
real_t weight = 0.0;
|
||||
// HACK: For now this will still have to be a copy, since we don't have AnimationNodeInstance yet...
|
||||
Vector<real_t> track_weights;
|
||||
// TODO: When rebasing https://github.com/godotengine/godot/pull/113444, update this to use LocalVector instead.
|
||||
// LocalVector<real_t> *track_weights = nullptr;
|
||||
};
|
||||
|
||||
struct AnimationInstance {
|
||||
|
|
@ -105,13 +108,13 @@ protected:
|
|||
AHashMap<StringName, AnimationData> animation_set; // HashMap<Library name + Animation name, AnimationData>
|
||||
|
||||
TypedArray<StringName> _get_animation_library_list() const;
|
||||
// TODO: This needs to be a TypedArray<StringName> see this PR for rationale https://github.com/godotengine/godot/pull/110767/
|
||||
Vector<String> _get_animation_list() const {
|
||||
List<StringName> animations;
|
||||
get_animation_list(&animations);
|
||||
Vector<String> ret;
|
||||
while (animations.size()) {
|
||||
ret.push_back(animations.front()->get());
|
||||
animations.pop_front();
|
||||
LocalVector<StringName> animations = get_sorted_animation_list();
|
||||
ret.resize(animations.size());
|
||||
for (uint32_t i = 0; i < animations.size(); ++i) {
|
||||
ret.write[i] = animations[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -141,7 +144,6 @@ protected:
|
|||
/* ---- Caches for blending ---- */
|
||||
bool cache_valid = false;
|
||||
uint64_t setup_pass = 1;
|
||||
uint64_t process_pass = 1;
|
||||
|
||||
struct TrackCache {
|
||||
bool root_motion = false;
|
||||
|
|
@ -151,6 +153,7 @@ protected:
|
|||
int blend_idx = -1;
|
||||
ObjectID object_id;
|
||||
real_t total_weight = 0.0;
|
||||
uint64_t animation_instance_weight_applied_at = 0;
|
||||
|
||||
TrackCache() = default;
|
||||
TrackCache(const TrackCache &p_other) :
|
||||
|
|
@ -158,7 +161,8 @@ protected:
|
|||
setup_pass(p_other.setup_pass),
|
||||
type(p_other.type),
|
||||
object_id(p_other.object_id),
|
||||
total_weight(p_other.total_weight) {}
|
||||
total_weight(p_other.total_weight),
|
||||
animation_instance_weight_applied_at(p_other.animation_instance_weight_applied_at) {}
|
||||
|
||||
virtual ~TrackCache() {}
|
||||
};
|
||||
|
|
@ -315,13 +319,14 @@ protected:
|
|||
void _clear_playing_caches();
|
||||
void _init_root_motion_cache();
|
||||
bool _update_caches();
|
||||
void _create_track_num_to_track_cache_for_animation(Ref<Animation> &p_animation);
|
||||
void _create_track_num_to_track_cache_for_animation(const Ref<Animation> &p_animation);
|
||||
|
||||
/* ---- Audio ---- */
|
||||
AudioServer::PlaybackType playback_type;
|
||||
|
||||
/* ---- Blending processor ---- */
|
||||
LocalVector<AnimationInstance> animation_instances;
|
||||
uint64_t animation_instance_weight_pass_counter = 0;
|
||||
AHashMap<NodePath, int> track_map;
|
||||
int track_count = 0;
|
||||
bool deterministic = false;
|
||||
|
|
@ -399,16 +404,18 @@ protected:
|
|||
|
||||
public:
|
||||
/* ---- Data lists ---- */
|
||||
void get_animation_library_list(List<StringName> *p_animations) const;
|
||||
void get_animation_library_list(LocalVector<StringName> *p_animations) const;
|
||||
Ref<AnimationLibrary> get_animation_library(const StringName &p_name) const;
|
||||
bool has_animation_library(const StringName &p_name) const;
|
||||
StringName find_animation_library(const Ref<Animation> &p_animation) const;
|
||||
const StringName &find_animation_library(const Ref<Animation> &p_animation) const;
|
||||
Error add_animation_library(const StringName &p_name, const Ref<AnimationLibrary> &p_animation_library);
|
||||
void remove_animation_library(const StringName &p_name);
|
||||
void rename_animation_library(const StringName &p_name, const StringName &p_new_name);
|
||||
|
||||
void get_animation_list(List<StringName> *p_animations) const;
|
||||
Ref<Animation> get_animation(const StringName &p_name) const;
|
||||
LocalVector<StringName> get_sorted_animation_list() const;
|
||||
void get_animation_list(LocalVector<StringName> *p_animations) const;
|
||||
const Ref<Animation> &get_animation(const StringName &p_name) const;
|
||||
const Ref<Animation> &get_animation_or_null(const StringName &p_name) const;
|
||||
bool has_animation(const StringName &p_name) const;
|
||||
StringName find_animation(const Ref<Animation> &p_animation) const;
|
||||
|
||||
|
|
@ -451,7 +458,7 @@ public:
|
|||
Vector3 get_root_motion_scale_accumulator() const;
|
||||
|
||||
/* ---- Blending processor ---- */
|
||||
void make_animation_instance(const StringName &p_name, const PlaybackInfo p_playback_info);
|
||||
void make_animation_instance(const StringName &p_name, const PlaybackInfo &p_playback_info);
|
||||
void clear_animation_instances();
|
||||
virtual void advance(double p_time);
|
||||
virtual void clear_caches(); // Must be called by hand if an animation was modified after added.
|
||||
|
|
@ -488,7 +495,7 @@ class AnimatedValuesBackup : public RefCounted {
|
|||
AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> data;
|
||||
|
||||
public:
|
||||
void set_data(const AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> p_data);
|
||||
void set_data(const AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> &p_data);
|
||||
AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> get_data() const;
|
||||
void clear_data();
|
||||
|
||||
|
|
|
|||
|
|
@ -287,20 +287,20 @@ void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) {
|
|||
}
|
||||
return;
|
||||
}
|
||||
List<List<Blend>::Element *> to_erase;
|
||||
for (List<Blend>::Element *E = c.blend.front(); E; E = E->next()) {
|
||||
Blend &b = E->get();
|
||||
LocalVector<int> to_erase;
|
||||
for (uint32_t i = 0; i < c.blend.size(); i++) {
|
||||
Blend &b = c.blend[i];
|
||||
b.blend_left = MAX(0, b.blend_left - Math::abs(speed_scale * p_delta) / b.blend_time);
|
||||
if (Animation::is_less_or_equal_approx(b.blend_left, 0)) {
|
||||
to_erase.push_back(E);
|
||||
to_erase.push_back(i);
|
||||
b.blend_left = CMP_EPSILON; // May want to play last frame.
|
||||
}
|
||||
// Note: There may be issues if an animation event triggers an animation change while this blend is active,
|
||||
// so it is best to use "deferred" calls instead of "immediate" for animation events that can trigger new animations.
|
||||
_process_playback_data(b.data, p_delta, b.blend_left, false, false, false);
|
||||
}
|
||||
for (List<Blend>::Element *&E : to_erase) {
|
||||
c.blend.erase(E);
|
||||
for (int i = to_erase.size() - 1; i >= 0; i--) {
|
||||
c.blend.remove_at(to_erase[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -351,9 +351,9 @@ void AnimationPlayer::_blend_post_process() {
|
|||
return;
|
||||
}
|
||||
}
|
||||
String old = playback.assigned;
|
||||
const StringName old = playback.assigned;
|
||||
play(playback_queue.front()->get());
|
||||
String new_name = playback.assigned;
|
||||
const StringName &new_name = playback.assigned;
|
||||
playback_queue.pop_front();
|
||||
if (end_notify) {
|
||||
emit_signal(SceneStringName(animation_changed), old, new_name);
|
||||
|
|
@ -432,9 +432,10 @@ void AnimationPlayer::play_section_with_markers(const StringName &p_name, const
|
|||
name = playback.assigned;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_MSG(!animation_set.has(name), vformat("Animation not found: %s.", name));
|
||||
AnimationData *ad = animation_set.getptr(name);
|
||||
ERR_FAIL_NULL_MSG(ad, vformat("Animation not found: %s.", name));
|
||||
|
||||
Ref<Animation> animation = animation_set[name].animation;
|
||||
const Ref<Animation> &animation = ad->animation;
|
||||
|
||||
ERR_FAIL_COND_MSG(p_start_marker == p_end_marker && p_start_marker, vformat("Start marker and end marker cannot be the same marker: %s.", p_start_marker));
|
||||
ERR_FAIL_COND_MSG(p_start_marker && !animation->has_marker(p_start_marker), vformat("Marker %s not found in animation: %s.", p_start_marker, name));
|
||||
|
|
@ -480,12 +481,12 @@ void AnimationPlayer::play_section(const StringName &p_name, double p_start_time
|
|||
} else if (blend_times.has(bk)) {
|
||||
blend_time = blend_times[bk];
|
||||
} else {
|
||||
bk.from = "*";
|
||||
bk.from = SNAME("*");
|
||||
if (blend_times.has(bk)) {
|
||||
blend_time = blend_times[bk];
|
||||
} else {
|
||||
bk.from = c.current.animation_name;
|
||||
bk.to = "*";
|
||||
bk.to = SNAME("*");
|
||||
|
||||
if (blend_times.has(bk)) {
|
||||
blend_time = blend_times[bk];
|
||||
|
|
@ -682,10 +683,11 @@ void AnimationPlayer::seek_internal(double p_time, bool p_update, bool p_update_
|
|||
playback.current.pos = p_time;
|
||||
if (!playback.current.is_enabled) {
|
||||
if (!playback.assigned.is_empty()) {
|
||||
ERR_FAIL_COND_MSG(!animation_set.has(playback.assigned), vformat("Animation not found: %s.", playback.assigned));
|
||||
AnimationData *ad = animation_set.getptr(playback.assigned);
|
||||
ERR_FAIL_NULL_MSG(ad, vformat("Animation not found: %s.", playback.assigned));
|
||||
playback.current.is_enabled = true;
|
||||
playback.current.animation_name = playback.assigned;
|
||||
playback.current.animation_length = animation_set[playback.assigned].animation->get_length();
|
||||
playback.current.animation_length = ad->animation->get_length();
|
||||
}
|
||||
if (!playback.current.is_enabled) {
|
||||
return; // There is no animation.
|
||||
|
|
@ -826,10 +828,11 @@ void AnimationPlayer::animation_set_next(const StringName &p_animation, const St
|
|||
}
|
||||
|
||||
StringName AnimationPlayer::animation_get_next(const StringName &p_animation) const {
|
||||
if (!animation_next_set.has(p_animation)) {
|
||||
const StringName *next = animation_next_set.getptr(p_animation);
|
||||
if (!next) {
|
||||
return StringName();
|
||||
}
|
||||
return animation_next_set[p_animation];
|
||||
return *next;
|
||||
}
|
||||
|
||||
void AnimationPlayer::set_default_blend_time(double p_default) {
|
||||
|
|
@ -860,8 +863,8 @@ double AnimationPlayer::get_blend_time(const StringName &p_animation1, const Str
|
|||
bk.from = p_animation1;
|
||||
bk.to = p_animation2;
|
||||
|
||||
if (blend_times.has(bk)) {
|
||||
return blend_times[bk];
|
||||
if (const double *blend_time = blend_times.getptr(bk)) {
|
||||
return *blend_time;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -904,9 +907,7 @@ Tween::EaseType AnimationPlayer::get_auto_capture_ease_type() const {
|
|||
void AnimationPlayer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
|
||||
const String pf = p_function;
|
||||
if (p_idx == 0 && (pf == "play" || pf == "play_backwards" || pf == "has_animation" || pf == "queue")) {
|
||||
List<StringName> al;
|
||||
get_animation_list(&al);
|
||||
for (const StringName &name : al) {
|
||||
for (const StringName &name : get_sorted_animation_list()) {
|
||||
r_options->push_back(String(name).quote());
|
||||
}
|
||||
}
|
||||
|
|
@ -917,7 +918,7 @@ void AnimationPlayer::get_argument_options(const StringName &p_function, int p_i
|
|||
void AnimationPlayer::_animation_removed(const StringName &p_name, const StringName &p_library) {
|
||||
AnimationMixer::_animation_removed(p_name, p_library);
|
||||
|
||||
StringName name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));
|
||||
const StringName &name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));
|
||||
|
||||
if (!animation_set.has(name)) {
|
||||
return; // No need to update because not the one from the library being used.
|
||||
|
|
@ -926,17 +927,16 @@ void AnimationPlayer::_animation_removed(const StringName &p_name, const StringN
|
|||
_animation_set_cache_update();
|
||||
|
||||
// Erase blends if needed
|
||||
List<BlendKey> to_erase;
|
||||
LocalVector<BlendKey> to_erase;
|
||||
for (const KeyValue<BlendKey, double> &E : blend_times) {
|
||||
BlendKey bk = E.key;
|
||||
const BlendKey &bk = E.key;
|
||||
if (bk.from == name || bk.to == name) {
|
||||
to_erase.push_back(bk);
|
||||
}
|
||||
}
|
||||
|
||||
while (to_erase.size()) {
|
||||
blend_times.erase(to_erase.front()->get());
|
||||
to_erase.pop_front();
|
||||
for (const BlendKey &bk : to_erase) {
|
||||
blend_times.erase(bk);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -944,7 +944,7 @@ void AnimationPlayer::_rename_animation(const StringName &p_from_name, const Str
|
|||
AnimationMixer::_rename_animation(p_from_name, p_to_name);
|
||||
|
||||
// Rename autoplay or blends if needed.
|
||||
List<BlendKey> to_erase;
|
||||
LocalVector<BlendKey> to_erase;
|
||||
HashMap<BlendKey, double, BlendKey> to_insert;
|
||||
for (const KeyValue<BlendKey, double> &E : blend_times) {
|
||||
BlendKey bk = E.key;
|
||||
|
|
@ -965,9 +965,8 @@ void AnimationPlayer::_rename_animation(const StringName &p_from_name, const Str
|
|||
}
|
||||
}
|
||||
|
||||
while (to_erase.size()) {
|
||||
blend_times.erase(to_erase.front()->get());
|
||||
to_erase.pop_front();
|
||||
for (const BlendKey &bk : to_erase) {
|
||||
blend_times.erase(bk);
|
||||
}
|
||||
|
||||
while (to_insert.size()) {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ private:
|
|||
bool seeked = false;
|
||||
bool internal_seeked = false;
|
||||
bool started = false;
|
||||
List<Blend> blend;
|
||||
LocalVector<Blend> blend;
|
||||
} playback;
|
||||
|
||||
struct BlendKey {
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
|
|||
|
||||
void AnimationNode::blend_animation(const StringName &p_animation, AnimationMixer::PlaybackInfo p_playback_info) {
|
||||
ERR_FAIL_NULL(process_state);
|
||||
// HACK: See PlaybackInfo.track_weights for more info
|
||||
p_playback_info.track_weights = Vector<real_t>(node_state.track_weights);
|
||||
process_state->tree->make_animation_instance(p_animation, p_playback_info);
|
||||
}
|
||||
|
|
@ -890,7 +891,7 @@ void AnimationTree::_setup_animation_player() {
|
|||
while (animation_libraries.size()) {
|
||||
remove_animation_library(animation_libraries[0].name);
|
||||
}
|
||||
List<StringName> list;
|
||||
LocalVector<StringName> list;
|
||||
player->get_animation_library_list(&list);
|
||||
for (const StringName &E : list) {
|
||||
Ref<AnimationLibrary> lib = player->get_animation_library(E);
|
||||
|
|
|
|||
|
|
@ -1091,7 +1091,7 @@ void Animation::track_set_interpolation_loop_wrap(int p_track, bool p_enable) {
|
|||
}
|
||||
|
||||
bool Animation::track_get_interpolation_loop_wrap(int p_track) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_track, tracks.size(), INTERPOLATION_NEAREST);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_track, tracks.size(), false);
|
||||
return tracks[p_track]->loop_wrap;
|
||||
}
|
||||
|
||||
|
|
@ -1295,8 +1295,8 @@ Error Animation::try_rotation_track_interpolate(int p_track, double p_time, Quat
|
|||
Quaternion Animation::rotation_track_interpolate(int p_track, double p_time, bool p_backward) const {
|
||||
Quaternion ret = Quaternion(0, 0, 0, 1);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_track, tracks.size(), ret);
|
||||
bool err = try_rotation_track_interpolate(p_track, p_time, &ret, p_backward);
|
||||
ERR_FAIL_COND_V_MSG(err, ret, "3D Rotation Track: '" + String(tracks[p_track]->path) + "' is unavailable.");
|
||||
Error err = try_rotation_track_interpolate(p_track, p_time, &ret, p_backward);
|
||||
ERR_FAIL_COND_V_MSG(err != OK, ret, "3D Rotation Track: '" + String(tracks[p_track]->path) + "' is unavailable.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -2766,7 +2766,7 @@ Animation::UpdateMode Animation::value_track_get_update_mode(int p_track) const
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void Animation::_track_get_key_indices_in_range(const LocalVector<T> &p_array, double from_time, double to_time, List<int> *p_indices, bool p_is_backward) const {
|
||||
void Animation::_track_get_key_indices_in_range(const LocalVector<T> &p_array, double from_time, double to_time, LocalVector<int> *r_indices, bool p_is_backward) const {
|
||||
int len = p_array.size();
|
||||
if (len == 0) {
|
||||
return;
|
||||
|
|
@ -2804,22 +2804,22 @@ void Animation::_track_get_key_indices_in_range(const LocalVector<T> &p_array, d
|
|||
}
|
||||
|
||||
if (from == to) {
|
||||
p_indices->push_back(from);
|
||||
r_indices->push_back(from);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!p_is_backward) {
|
||||
for (int i = from; i <= to; i++) {
|
||||
p_indices->push_back(i);
|
||||
r_indices->push_back(i);
|
||||
}
|
||||
} else {
|
||||
for (int i = to; i >= from; i--) {
|
||||
p_indices->push_back(i);
|
||||
r_indices->push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::track_get_key_indices_in_range(int p_track, double p_time, double p_delta, double p_start, double p_end, List<int> *p_indices, Animation::LoopedFlag p_looped_flag) const {
|
||||
void Animation::track_get_key_indices_in_range(int p_track, double p_time, double p_delta, double p_start, double p_end, LocalVector<int> *r_indices, Animation::LoopedFlag p_looped_flag) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_track, tracks.size());
|
||||
|
||||
if (p_delta == 0) {
|
||||
|
|
@ -2878,111 +2878,111 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
|
|||
case TYPE_POSITION_3D: {
|
||||
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
|
||||
if (tt->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, length, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, p_start, to_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, length, r_indices);
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, p_start, to_time, r_indices);
|
||||
} else {
|
||||
if (!is_backward) {
|
||||
_track_get_key_indices_in_range(tt->positions, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(tt->positions, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(tt->positions, from_time, anim_end, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(tt->positions, anim_start, to_time, r_indices, is_backward);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(tt->positions, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(tt->positions, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(tt->positions, anim_start, to_time, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(tt->positions, from_time, anim_end, r_indices, is_backward);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case TYPE_ROTATION_3D: {
|
||||
const RotationTrack *rt = static_cast<const RotationTrack *>(t);
|
||||
if (rt->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, end, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, start, to_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, end, r_indices);
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, start, to_time, r_indices);
|
||||
} else {
|
||||
if (!is_backward) {
|
||||
_track_get_key_indices_in_range(rt->rotations, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(rt->rotations, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(rt->rotations, from_time, anim_end, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(rt->rotations, anim_start, to_time, r_indices, is_backward);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(rt->rotations, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(rt->rotations, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(rt->rotations, anim_start, to_time, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(rt->rotations, from_time, anim_end, r_indices, is_backward);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case TYPE_SCALE_3D: {
|
||||
const ScaleTrack *st = static_cast<const ScaleTrack *>(t);
|
||||
if (st->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, end, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, start, to_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, end, r_indices);
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, start, to_time, r_indices);
|
||||
} else {
|
||||
if (!is_backward) {
|
||||
_track_get_key_indices_in_range(st->scales, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(st->scales, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(st->scales, from_time, anim_end, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(st->scales, anim_start, to_time, r_indices, is_backward);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(st->scales, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(st->scales, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(st->scales, anim_start, to_time, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(st->scales, from_time, anim_end, r_indices, is_backward);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case TYPE_BLEND_SHAPE: {
|
||||
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
|
||||
if (bst->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, end, p_indices);
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, start, to_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, end, r_indices);
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, start, to_time, r_indices);
|
||||
} else {
|
||||
if (!is_backward) {
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, from_time, anim_end, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, anim_start, to_time, r_indices, is_backward);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, anim_start, to_time, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, from_time, anim_end, r_indices, is_backward);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case TYPE_VALUE: {
|
||||
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
|
||||
if (!is_backward) {
|
||||
_track_get_key_indices_in_range(vt->values, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(vt->values, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(vt->values, from_time, anim_end, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(vt->values, anim_start, to_time, r_indices, is_backward);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(vt->values, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(vt->values, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(vt->values, anim_start, to_time, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(vt->values, from_time, anim_end, r_indices, is_backward);
|
||||
}
|
||||
} break;
|
||||
case TYPE_METHOD: {
|
||||
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
|
||||
if (!is_backward) {
|
||||
_track_get_key_indices_in_range(mt->methods, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(mt->methods, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(mt->methods, from_time, anim_end, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(mt->methods, anim_start, to_time, r_indices, is_backward);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(mt->methods, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(mt->methods, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(mt->methods, anim_start, to_time, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(mt->methods, from_time, anim_end, r_indices, is_backward);
|
||||
}
|
||||
} break;
|
||||
case TYPE_BEZIER: {
|
||||
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
|
||||
if (!is_backward) {
|
||||
_track_get_key_indices_in_range(bz->values, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bz->values, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bz->values, from_time, anim_end, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bz->values, anim_start, to_time, r_indices, is_backward);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(bz->values, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bz->values, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bz->values, anim_start, to_time, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bz->values, from_time, anim_end, r_indices, is_backward);
|
||||
}
|
||||
} break;
|
||||
case TYPE_AUDIO: {
|
||||
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
|
||||
if (!is_backward) {
|
||||
_track_get_key_indices_in_range(ad->values, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(ad->values, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(ad->values, from_time, anim_end, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(ad->values, anim_start, to_time, r_indices, is_backward);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(ad->values, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(ad->values, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(ad->values, anim_start, to_time, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(ad->values, from_time, anim_end, r_indices, is_backward);
|
||||
}
|
||||
} break;
|
||||
case TYPE_ANIMATION: {
|
||||
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
|
||||
if (!is_backward) {
|
||||
_track_get_key_indices_in_range(an->values, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(an->values, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(an->values, from_time, anim_end, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(an->values, anim_start, to_time, r_indices, is_backward);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(an->values, anim_start, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(an->values, from_time, anim_end, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(an->values, anim_start, to_time, r_indices, is_backward);
|
||||
_track_get_key_indices_in_range(an->values, from_time, anim_end, r_indices, is_backward);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
|
@ -2994,12 +2994,12 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
|
|||
if (!is_backward && Math::is_equal_approx(from_time, start)) {
|
||||
int edge = track_find_key(p_track, start, FIND_MODE_EXACT);
|
||||
if (edge >= 0) {
|
||||
p_indices->push_back(edge);
|
||||
r_indices->push_back(edge);
|
||||
}
|
||||
} else if (is_backward && Math::is_equal_approx(to_time, end)) {
|
||||
int edge = track_find_key(p_track, end, FIND_MODE_EXACT);
|
||||
if (edge >= 0) {
|
||||
p_indices->push_back(edge);
|
||||
r_indices->push_back(edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3018,67 +3018,67 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
|
|||
case TYPE_POSITION_3D: {
|
||||
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
|
||||
if (tt->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, start, from_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, start, to_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, start, from_time, r_indices);
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, start, to_time, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(tt->positions, start, from_time, p_indices, true);
|
||||
_track_get_key_indices_in_range(tt->positions, start, to_time, p_indices, false);
|
||||
_track_get_key_indices_in_range(tt->positions, start, from_time, r_indices, true);
|
||||
_track_get_key_indices_in_range(tt->positions, start, to_time, r_indices, false);
|
||||
}
|
||||
} break;
|
||||
case TYPE_ROTATION_3D: {
|
||||
const RotationTrack *rt = static_cast<const RotationTrack *>(t);
|
||||
if (rt->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, start, from_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, start, to_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, start, from_time, r_indices);
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, start, to_time, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(rt->rotations, start, from_time, p_indices, true);
|
||||
_track_get_key_indices_in_range(rt->rotations, start, to_time, p_indices, false);
|
||||
_track_get_key_indices_in_range(rt->rotations, start, from_time, r_indices, true);
|
||||
_track_get_key_indices_in_range(rt->rotations, start, to_time, r_indices, false);
|
||||
}
|
||||
} break;
|
||||
case TYPE_SCALE_3D: {
|
||||
const ScaleTrack *st = static_cast<const ScaleTrack *>(t);
|
||||
if (st->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, start, from_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, start, to_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, start, from_time, r_indices);
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, start, to_time, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(st->scales, start, from_time, p_indices, true);
|
||||
_track_get_key_indices_in_range(st->scales, start, to_time, p_indices, false);
|
||||
_track_get_key_indices_in_range(st->scales, start, from_time, r_indices, true);
|
||||
_track_get_key_indices_in_range(st->scales, start, to_time, r_indices, false);
|
||||
}
|
||||
} break;
|
||||
case TYPE_BLEND_SHAPE: {
|
||||
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
|
||||
if (bst->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, start, from_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, start, to_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, start, from_time, r_indices);
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, start, to_time, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, start, from_time, p_indices, true);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, start, to_time, p_indices, false);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, start, from_time, r_indices, true);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, start, to_time, r_indices, false);
|
||||
}
|
||||
} break;
|
||||
case TYPE_VALUE: {
|
||||
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
|
||||
_track_get_key_indices_in_range(vt->values, start, from_time, p_indices, true);
|
||||
_track_get_key_indices_in_range(vt->values, start, to_time, p_indices, false);
|
||||
_track_get_key_indices_in_range(vt->values, start, from_time, r_indices, true);
|
||||
_track_get_key_indices_in_range(vt->values, start, to_time, r_indices, false);
|
||||
} break;
|
||||
case TYPE_METHOD: {
|
||||
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
|
||||
_track_get_key_indices_in_range(mt->methods, start, from_time, p_indices, true);
|
||||
_track_get_key_indices_in_range(mt->methods, start, to_time, p_indices, false);
|
||||
_track_get_key_indices_in_range(mt->methods, start, from_time, r_indices, true);
|
||||
_track_get_key_indices_in_range(mt->methods, start, to_time, r_indices, false);
|
||||
} break;
|
||||
case TYPE_BEZIER: {
|
||||
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
|
||||
_track_get_key_indices_in_range(bz->values, start, from_time, p_indices, true);
|
||||
_track_get_key_indices_in_range(bz->values, start, to_time, p_indices, false);
|
||||
_track_get_key_indices_in_range(bz->values, start, from_time, r_indices, true);
|
||||
_track_get_key_indices_in_range(bz->values, start, to_time, r_indices, false);
|
||||
} break;
|
||||
case TYPE_AUDIO: {
|
||||
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
|
||||
_track_get_key_indices_in_range(ad->values, start, from_time, p_indices, true);
|
||||
_track_get_key_indices_in_range(ad->values, start, to_time, p_indices, false);
|
||||
_track_get_key_indices_in_range(ad->values, start, from_time, r_indices, true);
|
||||
_track_get_key_indices_in_range(ad->values, start, to_time, r_indices, false);
|
||||
} break;
|
||||
case TYPE_ANIMATION: {
|
||||
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
|
||||
_track_get_key_indices_in_range(an->values, start, from_time, p_indices, true);
|
||||
_track_get_key_indices_in_range(an->values, start, to_time, p_indices, false);
|
||||
_track_get_key_indices_in_range(an->values, start, from_time, r_indices, true);
|
||||
_track_get_key_indices_in_range(an->values, start, to_time, r_indices, false);
|
||||
} break;
|
||||
}
|
||||
return;
|
||||
|
|
@ -3089,67 +3089,67 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
|
|||
case TYPE_POSITION_3D: {
|
||||
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
|
||||
if (tt->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, end, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, to_time, end, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, end, r_indices);
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, to_time, end, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(tt->positions, from_time, end, p_indices, false);
|
||||
_track_get_key_indices_in_range(tt->positions, to_time, end, p_indices, true);
|
||||
_track_get_key_indices_in_range(tt->positions, from_time, end, r_indices, false);
|
||||
_track_get_key_indices_in_range(tt->positions, to_time, end, r_indices, true);
|
||||
}
|
||||
} break;
|
||||
case TYPE_ROTATION_3D: {
|
||||
const RotationTrack *rt = static_cast<const RotationTrack *>(t);
|
||||
if (rt->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, end, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, to_time, end, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, end, r_indices);
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, to_time, end, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(rt->rotations, from_time, end, p_indices, false);
|
||||
_track_get_key_indices_in_range(rt->rotations, to_time, end, p_indices, true);
|
||||
_track_get_key_indices_in_range(rt->rotations, from_time, end, r_indices, false);
|
||||
_track_get_key_indices_in_range(rt->rotations, to_time, end, r_indices, true);
|
||||
}
|
||||
} break;
|
||||
case TYPE_SCALE_3D: {
|
||||
const ScaleTrack *st = static_cast<const ScaleTrack *>(t);
|
||||
if (st->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, end, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, to_time, end, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, end, r_indices);
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, to_time, end, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(st->scales, from_time, end, p_indices, false);
|
||||
_track_get_key_indices_in_range(st->scales, to_time, end, p_indices, true);
|
||||
_track_get_key_indices_in_range(st->scales, from_time, end, r_indices, false);
|
||||
_track_get_key_indices_in_range(st->scales, to_time, end, r_indices, true);
|
||||
}
|
||||
} break;
|
||||
case TYPE_BLEND_SHAPE: {
|
||||
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
|
||||
if (bst->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, end, p_indices);
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, end, p_indices);
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, end, r_indices);
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, end, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, from_time, end, p_indices, false);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, to_time, end, p_indices, true);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, from_time, end, r_indices, false);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, to_time, end, r_indices, true);
|
||||
}
|
||||
} break;
|
||||
case TYPE_VALUE: {
|
||||
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
|
||||
_track_get_key_indices_in_range(vt->values, from_time, end, p_indices, false);
|
||||
_track_get_key_indices_in_range(vt->values, to_time, end, p_indices, true);
|
||||
_track_get_key_indices_in_range(vt->values, from_time, end, r_indices, false);
|
||||
_track_get_key_indices_in_range(vt->values, to_time, end, r_indices, true);
|
||||
} break;
|
||||
case TYPE_METHOD: {
|
||||
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
|
||||
_track_get_key_indices_in_range(mt->methods, from_time, end, p_indices, false);
|
||||
_track_get_key_indices_in_range(mt->methods, to_time, end, p_indices, true);
|
||||
_track_get_key_indices_in_range(mt->methods, from_time, end, r_indices, false);
|
||||
_track_get_key_indices_in_range(mt->methods, to_time, end, r_indices, true);
|
||||
} break;
|
||||
case TYPE_BEZIER: {
|
||||
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
|
||||
_track_get_key_indices_in_range(bz->values, from_time, end, p_indices, false);
|
||||
_track_get_key_indices_in_range(bz->values, to_time, end, p_indices, true);
|
||||
_track_get_key_indices_in_range(bz->values, from_time, end, r_indices, false);
|
||||
_track_get_key_indices_in_range(bz->values, to_time, end, r_indices, true);
|
||||
} break;
|
||||
case TYPE_AUDIO: {
|
||||
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
|
||||
_track_get_key_indices_in_range(ad->values, from_time, end, p_indices, false);
|
||||
_track_get_key_indices_in_range(ad->values, to_time, end, p_indices, true);
|
||||
_track_get_key_indices_in_range(ad->values, from_time, end, r_indices, false);
|
||||
_track_get_key_indices_in_range(ad->values, to_time, end, r_indices, true);
|
||||
} break;
|
||||
case TYPE_ANIMATION: {
|
||||
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
|
||||
_track_get_key_indices_in_range(an->values, from_time, end, p_indices, false);
|
||||
_track_get_key_indices_in_range(an->values, to_time, end, p_indices, true);
|
||||
_track_get_key_indices_in_range(an->values, from_time, end, r_indices, false);
|
||||
_track_get_key_indices_in_range(an->values, to_time, end, r_indices, true);
|
||||
} break;
|
||||
}
|
||||
return;
|
||||
|
|
@ -3167,54 +3167,54 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
|
|||
case TYPE_POSITION_3D: {
|
||||
const PositionTrack *tt = static_cast<const PositionTrack *>(t);
|
||||
if (tt->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, to_time - from_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, to_time - from_time, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(tt->positions, from_time, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(tt->positions, from_time, to_time, r_indices, is_backward);
|
||||
}
|
||||
} break;
|
||||
case TYPE_ROTATION_3D: {
|
||||
const RotationTrack *rt = static_cast<const RotationTrack *>(t);
|
||||
if (rt->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, to_time - from_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, to_time - from_time, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(rt->rotations, from_time, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(rt->rotations, from_time, to_time, r_indices, is_backward);
|
||||
}
|
||||
} break;
|
||||
case TYPE_SCALE_3D: {
|
||||
const ScaleTrack *st = static_cast<const ScaleTrack *>(t);
|
||||
if (st->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, to_time - from_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, to_time - from_time, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(st->scales, from_time, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(st->scales, from_time, to_time, r_indices, is_backward);
|
||||
}
|
||||
} break;
|
||||
case TYPE_BLEND_SHAPE: {
|
||||
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
|
||||
if (bst->compressed_track >= 0) {
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, to_time - from_time, p_indices);
|
||||
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, to_time - from_time, r_indices);
|
||||
} else {
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, from_time, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bst->blend_shapes, from_time, to_time, r_indices, is_backward);
|
||||
}
|
||||
} break;
|
||||
case TYPE_VALUE: {
|
||||
const ValueTrack *vt = static_cast<const ValueTrack *>(t);
|
||||
_track_get_key_indices_in_range(vt->values, from_time, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(vt->values, from_time, to_time, r_indices, is_backward);
|
||||
} break;
|
||||
case TYPE_METHOD: {
|
||||
const MethodTrack *mt = static_cast<const MethodTrack *>(t);
|
||||
_track_get_key_indices_in_range(mt->methods, from_time, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(mt->methods, from_time, to_time, r_indices, is_backward);
|
||||
} break;
|
||||
case TYPE_BEZIER: {
|
||||
const BezierTrack *bz = static_cast<const BezierTrack *>(t);
|
||||
_track_get_key_indices_in_range(bz->values, from_time, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(bz->values, from_time, to_time, r_indices, is_backward);
|
||||
} break;
|
||||
case TYPE_AUDIO: {
|
||||
const AudioTrack *ad = static_cast<const AudioTrack *>(t);
|
||||
_track_get_key_indices_in_range(ad->values, from_time, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(ad->values, from_time, to_time, r_indices, is_backward);
|
||||
} break;
|
||||
case TYPE_ANIMATION: {
|
||||
const AnimationTrack *an = static_cast<const AnimationTrack *>(t);
|
||||
_track_get_key_indices_in_range(an->values, from_time, to_time, p_indices, is_backward);
|
||||
_track_get_key_indices_in_range(an->values, from_time, to_time, r_indices, is_backward);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
|
@ -3853,7 +3853,7 @@ StringName Animation::animation_track_get_key_animation(int p_track, int p_key)
|
|||
return at->values[p_key].value;
|
||||
}
|
||||
|
||||
void Animation::set_length(real_t p_length) {
|
||||
void Animation::set_length(double p_length) {
|
||||
if (p_length < ANIM_MIN_LENGTH) {
|
||||
p_length = ANIM_MIN_LENGTH;
|
||||
}
|
||||
|
|
@ -3861,19 +3861,11 @@ void Animation::set_length(real_t p_length) {
|
|||
emit_changed();
|
||||
}
|
||||
|
||||
real_t Animation::get_length() const {
|
||||
return length;
|
||||
}
|
||||
|
||||
void Animation::set_loop_mode(Animation::LoopMode p_loop_mode) {
|
||||
loop_mode = p_loop_mode;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
Animation::LoopMode Animation::get_loop_mode() const {
|
||||
return loop_mode;
|
||||
}
|
||||
|
||||
void Animation::track_set_imported(int p_track, bool p_imported) {
|
||||
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_track, tracks.size());
|
||||
tracks[p_track]->imported = p_imported;
|
||||
|
|
@ -5495,7 +5487,7 @@ bool Animation::_fetch_compressed(uint32_t p_compressed_track, double p_time, Ve
|
|||
}
|
||||
|
||||
template <uint32_t COMPONENTS>
|
||||
void Animation::_get_compressed_key_indices_in_range(uint32_t p_compressed_track, double p_time, double p_delta, List<int> *r_indices) const {
|
||||
void Animation::_get_compressed_key_indices_in_range(uint32_t p_compressed_track, double p_time, double p_delta, LocalVector<int> *r_indices) const {
|
||||
ERR_FAIL_COND(!compression.enabled);
|
||||
ERR_FAIL_UNSIGNED_INDEX(p_compressed_track, compression.bounds.size());
|
||||
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ private:
|
|||
_FORCE_INLINE_ T _interpolate(const LocalVector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward = false) const;
|
||||
|
||||
template <typename T>
|
||||
_FORCE_INLINE_ void _track_get_key_indices_in_range(const LocalVector<T> &p_array, double from_time, double to_time, List<int> *p_indices, bool p_is_backward) const;
|
||||
_FORCE_INLINE_ void _track_get_key_indices_in_range(const LocalVector<T> &p_array, double from_time, double to_time, LocalVector<int> *r_indices, bool p_is_backward) const;
|
||||
|
||||
double length = 1.0;
|
||||
real_t step = DEFAULT_STEP;
|
||||
|
|
@ -368,7 +368,7 @@ private:
|
|||
bool _fetch_compressed_by_index(uint32_t p_compressed_track, int p_index, Vector3i &r_value, double &r_time) const;
|
||||
int _get_compressed_key_count(uint32_t p_compressed_track) const;
|
||||
template <uint32_t COMPONENTS>
|
||||
void _get_compressed_key_indices_in_range(uint32_t p_compressed_track, double p_time, double p_delta, List<int> *r_indices) const;
|
||||
void _get_compressed_key_indices_in_range(uint32_t p_compressed_track, double p_time, double p_delta, LocalVector<int> *r_indices) const;
|
||||
_FORCE_INLINE_ Quaternion _uncompress_quaternion(const Vector3i &p_value) const;
|
||||
_FORCE_INLINE_ Vector3 _uncompress_pos_scale(uint32_t p_compressed_track, const Vector3i &p_value) const;
|
||||
_FORCE_INLINE_ float _uncompress_blend_shape(const Vector3i &p_value) const;
|
||||
|
|
@ -516,7 +516,7 @@ public:
|
|||
|
||||
void copy_track(int p_track, Ref<Animation> p_to_animation);
|
||||
|
||||
void track_get_key_indices_in_range(int p_track, double p_time, double p_delta, double p_start, double p_end, List<int> *p_indices, Animation::LoopedFlag p_looped_flag = Animation::LOOPED_FLAG_NONE) const;
|
||||
void track_get_key_indices_in_range(int p_track, double p_time, double p_delta, double p_start, double p_end, LocalVector<int> *r_indices, Animation::LoopedFlag p_looped_flag = Animation::LOOPED_FLAG_NONE) const;
|
||||
|
||||
void add_marker(const StringName &p_name, double p_time);
|
||||
void remove_marker(const StringName &p_name);
|
||||
|
|
@ -529,11 +529,11 @@ public:
|
|||
Color get_marker_color(const StringName &p_name) const;
|
||||
void set_marker_color(const StringName &p_name, const Color &p_color);
|
||||
|
||||
void set_length(real_t p_length);
|
||||
real_t get_length() const;
|
||||
void set_length(double p_length);
|
||||
_FORCE_INLINE_ double get_length() const { return length; }
|
||||
|
||||
void set_loop_mode(LoopMode p_loop_mode);
|
||||
LoopMode get_loop_mode() const;
|
||||
_FORCE_INLINE_ LoopMode get_loop_mode() const { return loop_mode; }
|
||||
|
||||
void set_step(real_t p_step);
|
||||
real_t get_step() const;
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ Ref<Animation> AnimationLibrary::get_animation(const StringName &p_name) const {
|
|||
|
||||
TypedArray<StringName> AnimationLibrary::_get_animation_list() const {
|
||||
TypedArray<StringName> ret;
|
||||
List<StringName> names;
|
||||
LocalVector<StringName> names;
|
||||
get_animation_list(&names);
|
||||
for (const StringName &K : names) {
|
||||
ret.push_back(K);
|
||||
|
|
@ -108,8 +108,8 @@ void AnimationLibrary::_animation_changed(const StringName &p_name) {
|
|||
emit_signal(SceneStringName(animation_changed), p_name);
|
||||
}
|
||||
|
||||
void AnimationLibrary::get_animation_list(List<StringName> *p_animations) const {
|
||||
List<StringName> anims;
|
||||
void AnimationLibrary::get_animation_list(LocalVector<StringName> *p_animations) const {
|
||||
LocalVector<StringName> anims;
|
||||
|
||||
for (const KeyValue<StringName, Ref<Animation>> &E : animations) {
|
||||
anims.push_back(E.key);
|
||||
|
|
@ -148,7 +148,7 @@ Dictionary AnimationLibrary::_get_data() const {
|
|||
void AnimationLibrary::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
|
||||
const String pf = p_function;
|
||||
if (p_idx == 0 && (pf == "get_animation" || pf == "has_animation" || pf == "rename_animation" || pf == "remove_animation")) {
|
||||
List<StringName> names;
|
||||
LocalVector<StringName> names;
|
||||
get_animation_list(&names);
|
||||
for (const StringName &E : names) {
|
||||
r_options->push_back(E.operator String().quote());
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public:
|
|||
void rename_animation(const StringName &p_name, const StringName &p_new_name);
|
||||
bool has_animation(const StringName &p_name) const;
|
||||
Ref<Animation> get_animation(const StringName &p_name) const;
|
||||
void get_animation_list(List<StringName> *p_animations) const;
|
||||
void get_animation_list(LocalVector<StringName> *p_animations) const;
|
||||
int get_animation_list_size() const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue