From e3918692a33476ef14aa2e321f4cf11a0148f2d0 Mon Sep 17 00:00:00 2001 From: Relintai Date: Fri, 12 Aug 2022 01:34:45 +0200 Subject: [PATCH] Backported from Godot 4: Fixed animation insertion in SkeletonEditor - TokageItLab https://github.com/godotengine/godot/commit/653e2a550c5e7abe7d400f3a8e17737e1f020211 --- doc/classes/Animation.xml | 1 + editor/animation_track_editor.cpp | 122 +++----- editor/animation_track_editor.h | 6 +- editor/animation_track_editor_plugins.cpp | 4 +- editor/icons/icon_new_key.svg | 1 + editor/inspector_dock.cpp | 14 +- modules/gltf/gltf_document.cpp | 2 +- .../skeleton_editor_plugin.cpp | 292 ++++++++++++------ .../skeleton_editor/skeleton_editor_plugin.h | 33 +- scene/resources/animation.cpp | 6 +- scene/resources/animation.h | 3 +- 11 files changed, 276 insertions(+), 208 deletions(-) create mode 100644 editor/icons/icon_new_key.svg diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index d294bbbb9..c2c385f2e 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -205,6 +205,7 @@ + Returns the index of the specified track. If the track is not found, return -1. diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index d93cf729b..728ceeadd 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -3494,7 +3494,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) { for (List::Element *E = insert_data.front(); E; E = E->next()) { //prevent insertion of multiple tracks - if (E->get().path == p_id.path) { + if (E->get().path == p_id.path && E->get().type == p_id.type) { return; //already inserted a track for this on this frame } } @@ -3623,7 +3623,11 @@ void AnimationTrackEditor::_insert_delay(bool p_create_reset, bool p_create_bezi insert_queue = false; } -void AnimationTrackEditor::insert_transform_key(Spatial *p_node, const String &p_sub, const Transform &p_xform) { +void AnimationTrackEditor::insert_transform_key(Spatial *p_node, const String &p_sub, const Animation::TrackType p_type, const Variant p_value) { + ERR_FAIL_COND(!root); + ERR_FAIL_COND_MSG( + (p_type != Animation::TYPE_POSITION_3D && p_type != Animation::TYPE_ROTATION_3D && p_type != Animation::TYPE_SCALE_3D), + "Track type must be Position/Rotation/Scale 3D."); if (!keying) { return; } @@ -3631,7 +3635,6 @@ void AnimationTrackEditor::insert_transform_key(Spatial *p_node, const String &p return; } - ERR_FAIL_COND(!root); //let's build a node path String path = root->get_path_to(p_node); if (p_sub != "") { @@ -3640,24 +3643,18 @@ void AnimationTrackEditor::insert_transform_key(Spatial *p_node, const String &p NodePath np = path; - int position_idx = -1; - int rotation_idx = -1; - int scale_idx = -1; + int track_idx = -1; for (int i = 0; i < animation->get_track_count(); i++) { if (animation->track_get_path(i) != np) { continue; } - if (animation->track_get_type(i) == Animation::TYPE_POSITION_3D) { - position_idx = i; - } - if (animation->track_get_type(i) == Animation::TYPE_ROTATION_3D) { - rotation_idx = i; - } - if (animation->track_get_type(i) == Animation::TYPE_SCALE_3D) { - scale_idx = i; + if (animation->track_get_type(i) != p_type) { + continue; } + + track_idx = i; } InsertData id; @@ -3667,28 +3664,39 @@ void AnimationTrackEditor::insert_transform_key(Spatial *p_node, const String &p id.query = vformat(TTR("node '%s'"), p_node->get_name()); id.advance = false; - //dialog insert - - { - id.track_idx = position_idx; - id.value = p_xform.origin; - id.type = Animation::TYPE_POSITION_3D; - _query_insert(id); - } - { - id.track_idx = rotation_idx; - id.value = p_xform.basis.get_rotation_quat(); - id.type = Animation::TYPE_ROTATION_3D; - _query_insert(id); - } - { - id.track_idx = scale_idx; - id.value = p_xform.basis.get_scale(); - id.type = Animation::TYPE_SCALE_3D; - _query_insert(id); - } + id.track_idx = track_idx; + id.value = p_value; + id.type = p_type; + _query_insert(id); } +bool AnimationTrackEditor::has_track(Spatial *p_node, const String &p_sub, const Animation::TrackType p_type) { + ERR_FAIL_COND_V(!root, false); + + if (!keying) { + return false; + } + + if (!animation.is_valid()) { + return false; + } + + //let's build a node path + String path = root->get_path_to(p_node); + if (p_sub != "") { + path += ":" + p_sub; + } + + int track_id = animation->find_track(path, p_type); + + if (track_id >= 0) { + return true; + } + + return false; +} + + void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant &p_value) { String path = p_path; @@ -6385,49 +6393,3 @@ AnimationTrackEditor::~AnimationTrackEditor() { } } -bool AnimationTrackEditor::has_transform_key(Spatial *p_node, const String &p_sub) { - if (!keying) - return false; - if (!animation.is_valid()) - return false; - if (!root) - return false; - - //let's build a node path - String path = root->get_path_to(p_node); - if (p_sub != "") - path += ":" + p_sub; - - if (animation->find_track(path) >= 0) { - return true; - } - return false; -} - -bool AnimationTrackEditor::has_transform_track(Spatial *p_node, const String &p_sub) { - if (!keying) { - return false; - } - if (!animation.is_valid()) { - return false; - } - if (!root) { - return false; - } - - //let's build a node path - String path = root->get_path_to(p_node); - if (p_sub != "") { - path += ":" + p_sub; - } - int track_id = animation->find_track(path); - if (track_id >= 0) { - //TODO - //if (animation->track_get_type(track_id) == Animation::TYPE_TRANSFORM) { - // return true; - //} - return true; - } - return false; -} - diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 8857e992f..5f354bc3b 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -563,7 +563,8 @@ public: void set_anim_pos(float p_pos); void insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists = false); void insert_value_key(const String &p_property, const Variant &p_value, bool p_advance); - void insert_transform_key(Spatial *p_node, const String &p_sub, const Transform &p_xform); + void insert_transform_key(Spatial *p_node, const String &p_sub, const Animation::TrackType p_type, const Variant p_value); + bool has_track(Spatial *p_node, const String &p_sub, const Animation::TrackType p_type); void show_select_node_warning(bool p_show); @@ -585,9 +586,6 @@ public: AnimationTrackEditor(); ~AnimationTrackEditor(); - - bool has_transform_key(Spatial *p_node, const String &p_sub); - bool has_transform_track(Spatial *p_node, const String &p_sub); }; #endif // ANIMATION_TRACK_EDITOR_H diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index 3cb5e4b18..c0a7bd32d 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -419,7 +419,7 @@ Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_se // Go through other track to find if animation is set String animation_path = get_animation()->track_get_path(get_track()); animation_path = animation_path.replace(":frame", ":animation"); - int animation_track = get_animation()->find_track(animation_path); + int animation_track = get_animation()->find_track(animation_path, get_animation()->track_get_type(get_track())); float track_time = get_animation()->track_get_key_time(get_track(), p_index); int animaiton_index = get_animation()->track_find_key(animation_track, track_time); animation = get_animation()->track_get_key_value(animation_track, animaiton_index); @@ -509,7 +509,7 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in // Go through other track to find if animation is set String animation_path = get_animation()->track_get_path(get_track()); animation_path = animation_path.replace(":frame", ":animation"); - int animation_track = get_animation()->find_track(animation_path); + int animation_track = get_animation()->find_track(animation_path, get_animation()->track_get_type(get_track())); float track_time = get_animation()->track_get_key_time(get_track(), p_index); int animaiton_index = get_animation()->track_find_key(animation_track, track_time); animation = get_animation()->track_get_key_value(animation_track, animaiton_index); diff --git a/editor/icons/icon_new_key.svg b/editor/icons/icon_new_key.svg new file mode 100644 index 000000000..fc8507e6c --- /dev/null +++ b/editor/icons/icon_new_key.svg @@ -0,0 +1 @@ + diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index ac815c636..fd5a3584e 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -30,10 +30,6 @@ #include "inspector_dock.h" -#include "editor/editor_node.h" -#include "editor/editor_settings.h" -#include "editor/plugins/animation_player_editor_plugin.h" -#include "scene/3d/spatial.h" #include "core/class_db.h" #include "core/error_macros.h" #include "core/io/resource_loader.h" @@ -51,7 +47,11 @@ #include "editor/editor_data.h" #include "editor/editor_file_dialog.h" #include "editor/editor_inspector.h" +#include "editor/editor_node.h" #include "editor/editor_path.h" +#include "editor/editor_settings.h" +#include "editor/plugins/animation_player_editor_plugin.h" +#include "scene/3d/spatial.h" #include "scene/gui/button.h" #include "scene/gui/control.h" #include "scene/gui/dialogs.h" @@ -352,10 +352,14 @@ void InspectorDock::_property_keyed(const String &p_keyed, const Variant &p_valu void InspectorDock::_transform_keyed(Object *sp, const String &p_sub, const Transform &p_key) { Spatial *s = Object::cast_to(sp); + if (!s) { return; } - AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_transform_key(s, p_sub, p_key); + + AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_transform_key(s, p_sub, Animation::TYPE_POSITION_3D, p_key.origin); + AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_transform_key(s, p_sub, Animation::TYPE_ROTATION_3D, p_key.basis.get_rotation_quat()); + AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_transform_key(s, p_sub, Animation::TYPE_SCALE_3D, p_key.basis.get_scale()); } void InspectorDock::_warning_pressed() { diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index ea1492e98..3bcf4806d 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -6450,7 +6450,7 @@ void GLTFDocument::_convert_animation(Ref state, AnimationPlayer *ap, for (int32_t shape_i = 0; shape_i < mesh->get_blend_shape_count(); shape_i++) { String shape_name = mesh->get_blend_shape_name(shape_i); NodePath shape_path = String(path) + ":blend_shapes/" + shape_name; - int32_t shape_track_i = animation->find_track(shape_path); + int32_t shape_track_i = animation->find_track(shape_path, Animation::TYPE_VALUE); if (shape_track_i == -1) { GLTFAnimation::Channel weight; weight.interpolation = GLTFAnimation::INTERP_LINEAR; diff --git a/modules/skeleton_editor/skeleton_editor_plugin.cpp b/modules/skeleton_editor/skeleton_editor_plugin.cpp index afe3ee3ac..8e82a8ed6 100644 --- a/modules/skeleton_editor/skeleton_editor_plugin.cpp +++ b/modules/skeleton_editor/skeleton_editor_plugin.cpp @@ -31,6 +31,7 @@ #include "skeleton_editor_plugin.h" #include "core/io/resource_saver.h" +#include "core/os/keyboard.h" #include "editor/animation_track_editor.h" #include "editor/editor_file_dialog.h" #include "editor/editor_inspector.h" @@ -94,6 +95,7 @@ void BoneTransformEditor::create_editors() { enabled_checkbox = memnew(EditorPropertyCheck()); enabled_checkbox->set_label("Pose Enabled"); + enabled_checkbox->set_selectable(false); enabled_checkbox->connect("property_changed", this, "_value_changed"); section->get_vbox()->add_child(enabled_checkbox); @@ -101,23 +103,27 @@ void BoneTransformEditor::create_editors() { position_property = memnew(EditorPropertyVector3()); position_property->setup(-10000, 10000, 0.001f, true); position_property->set_label("Position"); + position_property->set_selectable(false); position_property->connect("property_changed", this, "_value_changed"); + position_property->connect("property_keyed", this, "_property_keyed"); section->get_vbox()->add_child(position_property); // Rotation property rotation_property = memnew(EditorPropertyQuat()); rotation_property->setup(-10000, 10000, 0.001f, true); rotation_property->set_label("Rotation"); + rotation_property->set_selectable(false); rotation_property->connect("property_changed", this, "_value_changed"); + rotation_property->connect("property_keyed", this, "_property_keyed"); section->get_vbox()->add_child(rotation_property); // Scale property scale_property = memnew(EditorPropertyVector3()); scale_property->setup(-10000, 10000, 0.001f, true); scale_property->set_label("Scale"); - scale_property->set_use_folding(true); - scale_property->set_read_only(false); + scale_property->set_selectable(false); scale_property->connect("property_changed", this, "_value_changed_vector3"); + scale_property->connect("property_keyed", this, "_property_keyed"); section->get_vbox()->add_child(scale_property); // Transform/Matrix section @@ -129,6 +135,7 @@ void BoneTransformEditor::create_editors() { rest_matrix = memnew(EditorPropertyTransform()); rest_matrix->setup(-10000, 10000, 0.001f, true); rest_matrix->set_label("Transform"); + rest_matrix->set_selectable(false); rest_section->get_vbox()->add_child(rest_matrix); } @@ -155,18 +162,24 @@ void BoneTransformEditor::_value_changed(const String &p_path, const Variant &p_ void BoneTransformEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_value_changed"), &BoneTransformEditor::_value_changed); + ClassDB::bind_method(D_METHOD("_property_keyed"), &BoneTransformEditor::_property_keyed); //ClassDB::bind_method(D_METHOD("update_joint_tree"), &BoneTransformEditor::update_joint_tree); } BoneTransformEditor::BoneTransformEditor(Skeleton *p_skeleton) { skeleton = p_skeleton; enabled_checkbox = nullptr; - keyable = false; toggle_enabled = false; updating = false; undo_redo = EditorNode::get_undo_redo(); } +void BoneTransformEditor::set_keyable(const bool p_keyable) { + position_property->set_keying(p_keyable); + rotation_property->set_keying(p_keyable); + scale_property->set_keying(p_keyable); +} + void BoneTransformEditor::set_target(const String &p_prop) { enabled_checkbox->set_object_and_property(skeleton, p_prop + "enabled"); enabled_checkbox->update_property(); @@ -184,6 +197,23 @@ void BoneTransformEditor::set_target(const String &p_prop) { rest_matrix->update_property(); } +void BoneTransformEditor::_property_keyed(const String &p_path, bool p_advance) { + AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor(); + Vector split = p_path.split("/"); + if (split.size() == 3 && split[0] == "bones") { + int bone_idx = split[1].to_int(); + if (split[2] == "position") { + te->insert_transform_key(skeleton, skeleton->get_bone_name(bone_idx), Animation::TYPE_POSITION_3D, skeleton->get(p_path)); + } + if (split[2] == "rotation") { + te->insert_transform_key(skeleton, skeleton->get_bone_name(bone_idx), Animation::TYPE_ROTATION_3D, skeleton->get(p_path)); + } + if (split[2] == "scale") { + te->insert_transform_key(skeleton, skeleton->get_bone_name(bone_idx), Animation::TYPE_SCALE_3D, skeleton->get(p_path)); + } + } +} + void BoneTransformEditor::_update_properties() { /* if (!skeleton) { @@ -233,12 +263,17 @@ SkeletonEditor *SkeletonEditor::singleton = nullptr; void SkeletonEditor::set_keyable(const bool p_keyable) { keyable = p_keyable; - skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_INSERT_KEYS, !p_keyable); - skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_INSERT_KEYS_EXISTED, !p_keyable); + + if (p_keyable) { + animation_hb->show(); + } else { + animation_hb->hide(); + } }; -void SkeletonEditor::set_rest_options_enabled(const bool p_rest_options_enabled) { - rest_options->get_popup()->set_item_disabled(REST_OPTION_POSE_TO_REST, !p_rest_options_enabled); +void SkeletonEditor::set_bone_options_enabled(const bool p_bone_options_enabled) { + skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_INIT_SELECTED_POSES, !p_bone_options_enabled); + skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_SELECTED_POSES_TO_RESTS, !p_bone_options_enabled); }; void SkeletonEditor::_on_click_skeleton_option(int p_skeleton_option) { @@ -247,22 +282,26 @@ void SkeletonEditor::_on_click_skeleton_option(int p_skeleton_option) { } switch (p_skeleton_option) { + case SKELETON_OPTION_INIT_ALL_POSES: { + init_pose(true); + break; + } + case SKELETON_OPTION_INIT_SELECTED_POSES: { + init_pose(false); + break; + } + case SKELETON_OPTION_ALL_POSES_TO_RESTS: { + pose_to_rest(true); + break; + } + case SKELETON_OPTION_SELECTED_POSES_TO_RESTS: { + pose_to_rest(false); + break; + } case SKELETON_OPTION_CREATE_PHYSICAL_SKELETON: { create_physical_skeleton(); break; } - case SKELETON_OPTION_INIT_POSE: { - init_pose(); - break; - } - case SKELETON_OPTION_INSERT_KEYS: { - insert_keys(true); - break; - } - case SKELETON_OPTION_INSERT_KEYS_EXISTED: { - insert_keys(false); - break; - } case SKELETON_OPTION_ADD_BONE: { add_bone(); } break; @@ -275,43 +314,55 @@ void SkeletonEditor::_on_click_skeleton_option(int p_skeleton_option) { } } -void SkeletonEditor::_on_click_rest_option(int p_rest_option) { +void SkeletonEditor::init_pose(const bool p_all_bones) { if (!skeleton) { return; } - switch (p_rest_option) { - case REST_OPTION_POSE_TO_REST: { - pose_to_rest(); - break; - } - } -} - -void SkeletonEditor::init_pose() { const int bone_len = skeleton->get_bone_count(); if (!bone_len) { return; } UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS); - for (int i = 0; i < bone_len; i++) { - Transform rest = skeleton->get_bone_rest(i); - ur->add_do_method(skeleton, "set_bone_pose_position", i, rest.origin); - ur->add_do_method(skeleton, "set_bone_pose_rotation", i, rest.basis.get_rotation_quat()); - ur->add_do_method(skeleton, "set_bone_pose_scale", i, rest.basis.get_scale()); - ur->add_undo_method(skeleton, "set_bone_pose_position", i, skeleton->get_bone_pose_position(i)); - ur->add_undo_method(skeleton, "set_bone_pose_rotation", i, skeleton->get_bone_pose_rotation(i)); - ur->add_undo_method(skeleton, "set_bone_pose_scale", i, skeleton->get_bone_pose_scale(i)); + + if (p_all_bones) { + for (int i = 0; i < bone_len; i++) { + Transform rest = skeleton->get_bone_rest(i); + ur->add_do_method(skeleton, "set_bone_pose_position", i, rest.origin); + ur->add_do_method(skeleton, "set_bone_pose_rotation", i, rest.basis.get_rotation_quat()); + ur->add_do_method(skeleton, "set_bone_pose_scale", i, rest.basis.get_scale()); + ur->add_undo_method(skeleton, "set_bone_pose_position", i, skeleton->get_bone_pose_position(i)); + ur->add_undo_method(skeleton, "set_bone_pose_rotation", i, skeleton->get_bone_pose_rotation(i)); + ur->add_undo_method(skeleton, "set_bone_pose_scale", i, skeleton->get_bone_pose_scale(i)); + } + } else { + // Todo: Do method with multiple bone selection. + if (selected_bone == -1) { + ur->commit_action(); + return; + } + Transform rest = skeleton->get_bone_rest(selected_bone); + ur->add_do_method(skeleton, "set_bone_pose_position", selected_bone, rest.origin); + ur->add_do_method(skeleton, "set_bone_pose_rotation", selected_bone, rest.basis.get_rotation_quat()); + ur->add_do_method(skeleton, "set_bone_pose_scale", selected_bone, rest.basis.get_scale()); + ur->add_undo_method(skeleton, "set_bone_pose_position", selected_bone, skeleton->get_bone_pose_position(selected_bone)); + ur->add_undo_method(skeleton, "set_bone_pose_rotation", selected_bone, skeleton->get_bone_pose_rotation(selected_bone)); + ur->add_undo_method(skeleton, "set_bone_pose_scale", selected_bone, skeleton->get_bone_pose_scale(selected_bone)); } + ur->commit_action(); } -void SkeletonEditor::insert_keys(bool p_all_bones) { +void SkeletonEditor::insert_keys(const bool p_all_bones) { if (!skeleton) { return; } + bool pos_enabled = key_loc_button->is_pressed(); + bool rot_enabled = key_rot_button->is_pressed(); + bool scl_enabled = key_scale_button->is_pressed(); + int bone_len = skeleton->get_bone_count(); Node *root = EditorNode::get_singleton()->get_tree()->get_root(); String path = root->get_path_to(skeleton); @@ -324,50 +375,50 @@ void SkeletonEditor::insert_keys(bool p_all_bones) { continue; } - if (!p_all_bones && !te->has_transform_track(skeleton, name)) { - continue; + if (pos_enabled && (p_all_bones || te->has_track(skeleton, name, Animation::TYPE_POSITION_3D))) { + te->insert_transform_key(skeleton, name, Animation::TYPE_POSITION_3D, skeleton->get_bone_pose_position(i)); + } + if (rot_enabled && (p_all_bones || te->has_track(skeleton, name, Animation::TYPE_ROTATION_3D))) { + te->insert_transform_key(skeleton, name, Animation::TYPE_ROTATION_3D, skeleton->get_bone_pose_rotation(i)); + } + if (scl_enabled && (p_all_bones || te->has_track(skeleton, name, Animation::TYPE_SCALE_3D))) { + te->insert_transform_key(skeleton, name, Animation::TYPE_SCALE_3D, skeleton->get_bone_pose_scale(i)); } - - // Need to normalize the basis before you key it - Transform tform = skeleton->get_bone_pose(i); - tform.orthonormalize(); - te->insert_transform_key(skeleton, name, tform); } + + //te->commit_insert_queue(); } -void SkeletonEditor::pose_to_rest() { +void SkeletonEditor::pose_to_rest(const bool p_all_bones) { if (!skeleton) { return; } - // Todo: Do method with multiple bone selection. - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - - ur->create_action(TTR("Set Bone Rest"), UndoRedo::MERGE_ENDS); - ur->add_do_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_pose(selected_bone)); - ur->add_undo_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_rest(selected_bone)); - - ur->commit_action(); -} -/* -void SkeletonEditor::pose_to_rest() { const int bone_len = skeleton->get_bone_count(); if (!bone_len) { return; } + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS); - for (int i = 0; i < bone_len; i++) { - ur->add_do_method(skeleton, "set_bone_pose", i, Transform()); - ur->add_undo_method(skeleton, "set_bone_pose", i, skeleton->get_bone_pose(i)); - ur->add_do_method(skeleton, "set_bone_custom_pose", i, Transform()); - ur->add_undo_method(skeleton, "set_bone_custom_pose", i, skeleton->get_bone_custom_pose(i)); - ur->add_do_method(skeleton, "set_bone_rest", i, skeleton->get_bone_rest(i) * skeleton->get_bone_custom_pose(i) * skeleton->get_bone_pose(i)); - ur->add_undo_method(skeleton, "set_bone_rest", i, skeleton->get_bone_rest(i)); + + ur->create_action(TTR("Set Bone Rest"), UndoRedo::MERGE_ENDS); + + if (p_all_bones) { + for (int i = 0; i < bone_len; i++) { + ur->add_do_method(skeleton, "set_bone_rest", i, skeleton->get_bone_pose(i)); + ur->add_undo_method(skeleton, "set_bone_rest", i, skeleton->get_bone_rest(i)); + } + } else { + // Todo: Do method with multiple bone selection. + if (selected_bone == -1) { + ur->commit_action(); + return; + } + ur->add_do_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_pose(selected_bone)); + ur->add_undo_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_rest(selected_bone)); } ur->commit_action(); } -*/ void SkeletonEditor::create_physical_skeleton() { UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); @@ -559,6 +610,7 @@ void SkeletonEditor::_joint_tree_selection_changed() { const String bone_path = "bones/" + itos(b_idx) + "/"; pose_editor->set_target(bone_path); + pose_editor->set_keyable(keyable); selected_bone = b_idx; } @@ -566,7 +618,7 @@ void SkeletonEditor::_joint_tree_selection_changed() { pose_editor->set_visible(selected); - set_rest_options_enabled(selected); + set_bone_options_enabled(selected); _update_properties(); _update_gizmo_visible(); } @@ -690,45 +742,85 @@ void SkeletonEditor::create_editors() { skeleton_options->set_text(TTR("Skeleton")); skeleton_options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Skeleton", "EditorIcons")); - skeleton_options->get_popup()->add_item(TTR("Init pose"), SKELETON_OPTION_INIT_POSE); - skeleton_options->get_popup()->add_item(TTR("Insert key of all bone poses"), SKELETON_OPTION_INSERT_KEYS); - skeleton_options->get_popup()->add_item(TTR("Insert key of bone poses already exist track"), SKELETON_OPTION_INSERT_KEYS_EXISTED); - skeleton_options->get_popup()->add_item(TTR("Create physical skeleton"), SKELETON_OPTION_CREATE_PHYSICAL_SKELETON); - skeleton_options->get_popup()->add_item(TTR("Add bone"), SKELETON_OPTION_ADD_BONE); - skeleton_options->get_popup()->add_item(TTR("Rename bone"), SKELETON_OPTION_RENAME_BONE); - skeleton_options->get_popup()->add_item(TTR("Remove bone"), SKELETON_OPTION_REMOVE_BONE); + PopupMenu *p = skeleton_options->get_popup(); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/init_all_poses", TTR("Init all Poses")), SKELETON_OPTION_INIT_ALL_POSES); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/init_selected_poses", TTR("Init selected Poses")), SKELETON_OPTION_INIT_SELECTED_POSES); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/all_poses_to_rests", TTR("Apply all poses to rests")), SKELETON_OPTION_ALL_POSES_TO_RESTS); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/selected_poses_to_rests", TTR("Apply selected poses to rests")), SKELETON_OPTION_SELECTED_POSES_TO_RESTS); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/create_physical_skeleton", TTR("Create physical skeleton")), SKELETON_OPTION_CREATE_PHYSICAL_SKELETON); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/add_bone", TTR("Add bone")), SKELETON_OPTION_ADD_BONE); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/rename_bone", TTR("Rename bone")), SKELETON_OPTION_RENAME_BONE); + p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/remove_bone", TTR("Remove bone")), SKELETON_OPTION_REMOVE_BONE); + skeleton_options->get_popup()->connect("id_pressed", this, "_on_click_skeleton_option"); - - // Create Rest Option in Top Menu Bar. - rest_options = memnew(MenuButton); - ne->add_control_to_menu_panel(rest_options); - - rest_options->set_text(TTR("Edit Rest")); - rest_options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("BoneAttachment", "EditorIcons")); - - rest_options->get_popup()->add_item(TTR("Apply current pose to rest"), REST_OPTION_POSE_TO_REST); - rest_options->get_popup()->connect("id_pressed", this, "_on_click_rest_option"); - set_rest_options_enabled(false); + set_bone_options_enabled(false); Vector button_binds; button_binds.resize(1); edit_mode_button = memnew(Button); ne->add_control_to_menu_panel(edit_mode_button); - edit_mode_button->set_tooltip(TTR("Edit Mode\nShow buttons on joints.")); - edit_mode_button->set_toggle_mode(true); edit_mode_button->set_flat(true); + edit_mode_button->set_toggle_mode(true); + edit_mode_button->set_focus_mode(FOCUS_NONE); + edit_mode_button->set_tooltip(TTR("Edit Mode\nShow buttons on joints.")); edit_mode_button->connect("toggled", this, "edit_mode_toggled"); edit_mode = false; - set_keyable(te->has_keying()); - if (skeleton) { skeleton->add_child(handles_mesh_instance); handles_mesh_instance->set_skeleton_path(NodePath("")); } + // Keying buttons. + animation_hb = memnew(HBoxContainer); + ne->add_control_to_menu_panel(animation_hb); + animation_hb->add_child(memnew(VSeparator)); + animation_hb->hide(); + + key_loc_button = memnew(Button); + key_loc_button->set_flat(true); + key_loc_button->set_toggle_mode(true); + key_loc_button->set_pressed(false); + key_loc_button->set_focus_mode(FOCUS_NONE); + key_loc_button->set_tooltip(TTR("Translation mask for inserting keys.")); + animation_hb->add_child(key_loc_button); + + key_rot_button = memnew(Button); + key_rot_button->set_flat(true); + key_rot_button->set_toggle_mode(true); + key_rot_button->set_pressed(true); + key_rot_button->set_focus_mode(FOCUS_NONE); + key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys.")); + animation_hb->add_child(key_rot_button); + + key_scale_button = memnew(Button); + key_scale_button->set_flat(true); + key_scale_button->set_toggle_mode(true); + key_scale_button->set_pressed(false); + key_scale_button->set_focus_mode(FOCUS_NONE); + key_scale_button->set_tooltip(TTR("Scale mask for inserting keys.")); + animation_hb->add_child(key_scale_button); + + key_insert_button = memnew(Button); + key_insert_button->set_flat(true); + key_insert_button->set_focus_mode(FOCUS_NONE); + key_insert_button->connect("pressed", this, "insert_keys", varray(false)); + key_insert_button->set_tooltip(TTR("Insert key of bone poses already exist track.")); + key_insert_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_to_existing_tracks", TTR("Insert Key (Existing Tracks)"), KEY_INSERT)); + animation_hb->add_child(key_insert_button); + + key_insert_all_button = memnew(Button); + key_insert_all_button->set_flat(true); + key_insert_all_button->set_focus_mode(FOCUS_NONE); + key_insert_all_button->connect("pressed", this, "insert_keys", varray(true)); + key_insert_all_button->set_tooltip(TTR("Insert key of all bone poses.")); + key_insert_all_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_of_all_bones", TTR("Insert Key (All Bones)"), KEY_MASK_CMD + KEY_INSERT)); + animation_hb->add_child(key_insert_all_button); + + // Bone tree. + const Color section_color = get_color("prop_subsection", "Editor"); EditorInspectorSection *bones_section = memnew(EditorInspectorSection); @@ -756,12 +848,20 @@ void SkeletonEditor::create_editors() { pose_editor->set_label(TTR("Bone Transform")); pose_editor->set_visible(false); add_child(pose_editor); + + set_keyable(te->has_keying()); } void SkeletonEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { edit_mode_button->set_icon(get_icon("ToolBoneSelect", "EditorIcons")); + key_loc_button->set_icon(get_icon("KeyPosition", "EditorIcons")); + key_rot_button->set_icon(get_icon("KeyRotation", "EditorIcons")); + key_scale_button->set_icon(get_icon("KeyScale", "EditorIcons")); + key_insert_button->set_icon(get_icon("Key", "EditorIcons")); + key_insert_all_button->set_icon(get_icon("NewKey", "EditorIcons")); + get_tree()->connect("node_removed", this, "_node_removed", Vector(), Object::CONNECT_ONESHOT); break; } break; @@ -787,7 +887,6 @@ void SkeletonEditor::_node_removed(Node *p_node) { if (skeleton && p_node == skeleton) { skeleton = nullptr; skeleton_options->hide(); - rest_options->hide(); } _update_properties(); @@ -799,7 +898,7 @@ void SkeletonEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_joint_tree_rmb_select"), &SkeletonEditor::_joint_tree_rmb_select); ClassDB::bind_method(D_METHOD("_update_properties"), &SkeletonEditor::_update_properties); ClassDB::bind_method(D_METHOD("_on_click_skeleton_option"), &SkeletonEditor::_on_click_skeleton_option); - ClassDB::bind_method(D_METHOD("_on_click_rest_option"), &SkeletonEditor::_on_click_rest_option); + ClassDB::bind_method(D_METHOD("insert_keys"), &SkeletonEditor::insert_keys); ClassDB::bind_method(D_METHOD("edit_mode_toggled"), &SkeletonEditor::edit_mode_toggled); ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &SkeletonEditor::get_drag_data_fw); @@ -831,7 +930,6 @@ SkeletonEditor::SkeletonEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNo pose_editor = nullptr; skeleton_options = nullptr; - rest_options = nullptr; edit_mode = false; @@ -937,6 +1035,11 @@ SkeletonEditor::~SkeletonEditor() { SpatialEditor *ne = SpatialEditor::get_singleton(); + if (animation_hb) { + ne->remove_control_from_menu_panel(animation_hb); + memdelete(animation_hb); + } + if (separator) { ne->remove_control_from_menu_panel(separator); memdelete(separator); @@ -947,11 +1050,6 @@ SkeletonEditor::~SkeletonEditor() { memdelete(skeleton_options); } - if (rest_options) { - ne->remove_control_from_menu_panel(rest_options); - memdelete(rest_options); - } - if (edit_mode_button) { ne->remove_control_from_menu_panel(edit_mode_button); memdelete(edit_mode_button); diff --git a/modules/skeleton_editor/skeleton_editor_plugin.h b/modules/skeleton_editor/skeleton_editor_plugin.h index 6d4203665..cedc0918b 100644 --- a/modules/skeleton_editor/skeleton_editor_plugin.h +++ b/modules/skeleton_editor/skeleton_editor_plugin.h @@ -79,7 +79,6 @@ class BoneTransformEditor : public VBoxContainer { UndoRedo *undo_redo; - bool keyable; bool toggle_enabled; bool updating; @@ -89,6 +88,8 @@ class BoneTransformEditor : public VBoxContainer { void _value_changed(const String &p_path, const Variant &p_value, const String &p_name = "", bool changing = false); + void _property_keyed(const String &p_path, bool p_advance); + protected: void _notification(int p_what); static void _bind_methods(); @@ -99,6 +100,7 @@ public: // Which transform target to modify void set_target(const String &p_prop); void set_label(const String &p_label) { label = p_label; } + void set_keyable(const bool p_keyable); void _update_properties(); }; @@ -109,19 +111,16 @@ class SkeletonEditor : public VBoxContainer { friend class SkeletonEditorPlugin; enum SkeletonOption { - SKELETON_OPTION_INIT_POSE, - SKELETON_OPTION_INSERT_KEYS, - SKELETON_OPTION_INSERT_KEYS_EXISTED, + SKELETON_OPTION_INIT_ALL_POSES, + SKELETON_OPTION_INIT_SELECTED_POSES, + SKELETON_OPTION_ALL_POSES_TO_RESTS, + SKELETON_OPTION_SELECTED_POSES_TO_RESTS, SKELETON_OPTION_CREATE_PHYSICAL_SKELETON, SKELETON_OPTION_ADD_BONE, SKELETON_OPTION_REMOVE_BONE, SKELETON_OPTION_RENAME_BONE }; - enum RestOption { - REST_OPTION_POSE_TO_REST - }; - struct BoneInfo { PhysicalBone *physical_bone; Transform relative_rest; // Relative to skeleton node @@ -142,11 +141,17 @@ class SkeletonEditor : public VBoxContainer { VSeparator *separator; MenuButton *skeleton_options; - MenuButton *rest_options; Button *edit_mode_button; bool edit_mode; + HBoxContainer *animation_hb; + Button *key_loc_button; + Button *key_rot_button; + Button *key_scale_button; + Button *key_insert_button; + Button *key_insert_all_button; + EditorFileDialog *file_dialog; bool keyable; @@ -154,7 +159,6 @@ class SkeletonEditor : public VBoxContainer { static SkeletonEditor *singleton; void _on_click_skeleton_option(int p_skeleton_option); - void _on_click_rest_option(int p_rest_option); void _file_selected(const String &p_file); TreeItem *_find(TreeItem *p_node, const NodePath &p_path); void edit_mode_toggled(const bool pressed); @@ -166,9 +170,10 @@ class SkeletonEditor : public VBoxContainer { void create_editors(); - void init_pose(); - void insert_keys(bool p_all_bones); - void pose_to_rest(); + void init_pose(const bool p_all_bones); + void pose_to_rest(const bool p_all_bones); + + void insert_keys(const bool p_all_bones); void create_physical_skeleton(); PhysicalBone *create_physical_bone(int bone_id, int bone_child_id, const Vector &bones_infos); @@ -178,7 +183,7 @@ class SkeletonEditor : public VBoxContainer { void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); void set_keyable(const bool p_keyable); - void set_rest_options_enabled(const bool p_rest_options_enabled); + void set_bone_options_enabled(const bool p_bone_options_enabled); MeshInstance *handles_mesh_instance; Ref handles_mesh; diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 05701b0d1..b006bebc0 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -799,9 +799,9 @@ NodePath Animation::track_get_path(int p_track) const { return tracks[p_track]->path; } -int Animation::find_track(const NodePath &p_path) const { +int Animation::find_track(const NodePath &p_path, const TrackType p_type) const { for (int i = 0; i < tracks.size(); i++) { - if (tracks[i]->path == p_path) { + if (tracks[i]->path == p_path && tracks[i]->type == p_type) { return i; } }; @@ -3076,7 +3076,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_get_type", "track_idx"), &Animation::track_get_type); ClassDB::bind_method(D_METHOD("track_get_path", "track_idx"), &Animation::track_get_path); ClassDB::bind_method(D_METHOD("track_set_path", "track_idx", "path"), &Animation::track_set_path); - ClassDB::bind_method(D_METHOD("find_track", "path"), &Animation::find_track); + ClassDB::bind_method(D_METHOD("find_track", "path", "type"), &Animation::find_track); ClassDB::bind_method(D_METHOD("track_move_up", "track_idx"), &Animation::track_move_up); ClassDB::bind_method(D_METHOD("track_move_down", "track_idx"), &Animation::track_move_down); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 891960845..ace3731ca 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -280,8 +280,7 @@ public: void track_set_path(int p_track, const NodePath &p_path); NodePath track_get_path(int p_track) const; - int find_track(const NodePath &p_path) const; - // transform + int find_track(const NodePath &p_path, const TrackType p_type) const; void track_move_up(int p_track); void track_move_down(int p_track);