diff options
author | RĂ©mi Verschelde <remi@verschelde.fr> | 2020-12-20 16:35:53 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-20 16:35:53 +0100 |
commit | bc2ac0bbd685a01569ba6dde4c68adc1ccf37bb8 (patch) | |
tree | 09fe174ea963c2745f8b268454acb5a39dab7de9 /editor | |
parent | e9d12f9e4ea30a6c3f2cf179f104a153d668c2a3 (diff) | |
parent | b7367ac426659e02facc7c828e57aa687cce957c (diff) |
Merge pull request #43115 from RandomShaper/reset_track
Add animation reset track feature
Diffstat (limited to 'editor')
-rw-r--r-- | editor/animation_track_editor.cpp | 186 | ||||
-rw-r--r-- | editor/animation_track_editor.h | 19 | ||||
-rw-r--r-- | editor/editor_node.cpp | 18 | ||||
-rw-r--r-- | editor/editor_settings.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/animation_player_editor_plugin.cpp | 33 | ||||
-rw-r--r-- | editor/plugins/animation_player_editor_plugin.h | 2 |
6 files changed, 206 insertions, 54 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 492a9f2a2f..ec411c6415 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -37,6 +37,7 @@ #include "editor/plugins/animation_player_editor_plugin.h" #include "editor_node.h" #include "editor_scale.h" +#include "scene/animation/animation_player.h" #include "scene/main/window.h" #include "servers/audio/audio_stream.h" @@ -3299,6 +3300,19 @@ void AnimationTrackEditor::set_anim_pos(float p_pos) { bezier_edit->set_play_position(p_pos); } +static bool track_type_is_resettable(Animation::TrackType p_type) { + switch (p_type) { + case Animation::TYPE_VALUE: + [[fallthrough]]; + case Animation::TYPE_BEZIER: + [[fallthrough]]; + case Animation::TYPE_TRANSFORM: + return true; + default: + return false; + } +} + void AnimationTrackEditor::_query_insert(const InsertData &p_id) { if (insert_frame != Engine::get_singleton()->get_frames_drawn()) { //clear insert list for the frame if frame changed @@ -3319,40 +3333,58 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) { insert_data.push_back(p_id); + bool reset_allowed = true; + AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player(); + if (player->has_animation("RESET") && player->get_animation("RESET") == animation) { + // Avoid messing with the reset animation itself + reset_allowed = false; + } else { + bool some_resettable = false; + for (int i = 0; i < insert_data.size(); i++) { + if (track_type_is_resettable(insert_data[i].type)) { + some_resettable = true; + break; + } + } + if (!some_resettable) { + reset_allowed = false; + } + } + if (p_id.track_idx == -1) { - if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) { - //potential new key, does not exist - int num_tracks = 0; - bool all_bezier = true; - for (int i = 0; i < insert_data.size(); i++) { - if (insert_data[i].type != Animation::TYPE_VALUE && insert_data[i].type != Animation::TYPE_BEZIER) { - all_bezier = false; - } + int num_tracks = 0; + bool all_bezier = true; + for (int i = 0; i < insert_data.size(); i++) { + if (insert_data[i].type != Animation::TYPE_VALUE && insert_data[i].type != Animation::TYPE_BEZIER) { + all_bezier = false; + } - if (insert_data[i].track_idx == -1) { - ++num_tracks; - } + if (insert_data[i].track_idx == -1) { + ++num_tracks; + } - if (insert_data[i].type != Animation::TYPE_VALUE) { - continue; - } + if (insert_data[i].type != Animation::TYPE_VALUE) { + continue; + } - switch (insert_data[i].value.get_type()) { - case Variant::INT: - case Variant::FLOAT: - case Variant::VECTOR2: - case Variant::VECTOR3: - case Variant::QUAT: - case Variant::PLANE: - case Variant::COLOR: { - // Valid. - } break; - default: { - all_bezier = false; - } + switch (insert_data[i].value.get_type()) { + case Variant::INT: + case Variant::FLOAT: + case Variant::VECTOR2: + case Variant::VECTOR3: + case Variant::QUAT: + case Variant::PLANE: + case Variant::COLOR: { + // Valid. + } break; + default: { + all_bezier = false; } } + } + if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) { + //potential new key, does not exist if (num_tracks == 1) { insert_confirm_text->set_text(vformat(TTR("Create new track for %s and insert key?"), p_id.query)); } else { @@ -3360,23 +3392,26 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) { } insert_confirm_bezier->set_visible(all_bezier); + insert_confirm_reset->set_visible(reset_allowed); + insert_confirm->get_ok_button()->set_text(TTR("Create")); insert_confirm->popup_centered(); insert_query = true; } else { - call_deferred("_insert_delay"); + call_deferred("_insert_delay", reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), all_bezier && EDITOR_GET("editors/animation/default_create_bezier_tracks")); insert_queue = true; } } else { if (!insert_query && !insert_queue) { - call_deferred("_insert_delay"); + // Create Beziers wouldn't make sense in this case, where no tracks are being created + call_deferred("_insert_delay", reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), false); insert_queue = true; } } } -void AnimationTrackEditor::_insert_delay() { +void AnimationTrackEditor::_insert_delay(bool p_create_reset, bool p_create_beziers) { if (insert_query) { //discard since it's entered into query mode insert_queue = false; @@ -3385,13 +3420,18 @@ void AnimationTrackEditor::_insert_delay() { undo_redo->create_action(TTR("Anim Insert")); - int last_track = animation->get_track_count(); + Ref<Animation> reset_anim; + if (p_create_reset) { + reset_anim = _create_and_get_reset_animation(); + } + + TrackIndices next_tracks(animation.ptr(), reset_anim.ptr()); bool advance = false; while (insert_data.size()) { if (insert_data.front()->get().advance) { advance = true; } - last_track = _confirm_insert(insert_data.front()->get(), last_track); + next_tracks = _confirm_insert(insert_data.front()->get(), next_tracks, p_create_reset, p_create_beziers); insert_data.pop_front(); } @@ -3682,12 +3722,34 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari } } +Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() { + AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player(); + if (player->has_animation("RESET")) { + return player->get_animation("RESET"); + } else { + Ref<Animation> reset_anim; + reset_anim.instance(); + reset_anim->set_length(ANIM_MIN_LENGTH); + undo_redo->add_do_method(player, "add_animation", "RESET", reset_anim); + undo_redo->add_do_method(AnimationPlayerEditor::singleton, "_animation_player_changed", player); + undo_redo->add_undo_method(player, "remove_animation", "RESET"); + undo_redo->add_undo_method(AnimationPlayerEditor::singleton, "_animation_player_changed", player); + return reset_anim; + } +} + void AnimationTrackEditor::_confirm_insert_list() { undo_redo->create_action(TTR("Anim Create & Insert")); - int last_track = animation->get_track_count(); + bool create_reset = insert_confirm_reset->is_visible() && insert_confirm_reset->is_pressed(); + Ref<Animation> reset_anim; + if (create_reset) { + reset_anim = _create_and_get_reset_animation(); + } + + TrackIndices next_tracks(animation.ptr(), reset_anim.ptr()); while (insert_data.size()) { - last_track = _confirm_insert(insert_data.front()->get(), last_track, insert_confirm_bezier->is_pressed()); + next_tracks = _confirm_insert(insert_data.front()->get(), next_tracks, create_reset, insert_confirm_bezier->is_pressed()); insert_data.pop_front(); } @@ -3807,11 +3869,7 @@ static Vector<String> _get_bezier_subindices_for_type(Variant::Type p_type, bool return subindices; } -int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, bool p_create_beziers) { - if (p_last_track == -1) { - p_last_track = animation->get_track_count(); - } - +AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertData p_id, TrackIndices p_next_tracks, bool p_create_reset, bool p_create_beziers) { bool created = false; if (p_id.track_idx < 0) { if (p_create_beziers) { @@ -3823,10 +3881,10 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo id.type = Animation::TYPE_BEZIER; id.value = p_id.value.get(subindices[i].substr(1, subindices[i].length())); id.path = String(p_id.path) + subindices[i]; - _confirm_insert(id, p_last_track + i); + p_next_tracks = _confirm_insert(id, p_next_tracks, p_create_reset, false); } - return p_last_track + subindices.size(); + return p_next_tracks; } } created = true; @@ -3863,7 +3921,7 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo } } - p_id.track_idx = p_last_track; + p_id.track_idx = p_next_tracks.normal; undo_redo->add_do_method(animation.ptr(), "add_track", p_id.type); undo_redo->add_do_method(animation.ptr(), "track_set_path", p_id.track_idx, p_id.path); @@ -3915,7 +3973,7 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo // Just remove the track. undo_redo->add_undo_method(this, "_clear_selection", false); undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count()); - p_last_track++; + p_next_tracks.normal++; } else { undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_id.track_idx, time); int existing = animation->track_find_key(p_id.track_idx, time, true); @@ -3926,9 +3984,27 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo } } + if (p_create_reset && track_type_is_resettable(p_id.type)) { + bool create_reset_track = true; + Animation *reset_anim = AnimationPlayerEditor::singleton->get_player()->get_animation("RESET").ptr(); + for (int i = 0; i < reset_anim->get_track_count(); i++) { + if (reset_anim->track_get_path(i) == p_id.path) { + create_reset_track = false; + break; + } + } + if (create_reset_track) { + undo_redo->add_do_method(reset_anim, "add_track", p_id.type); + undo_redo->add_do_method(reset_anim, "track_set_path", p_next_tracks.reset, p_id.path); + undo_redo->add_do_method(reset_anim, "track_insert_key", p_next_tracks.reset, 0.0f, value); + undo_redo->add_undo_method(reset_anim, "remove_track", reset_anim->get_track_count()); + p_next_tracks.reset++; + } + } + undo_redo->commit_action(); - return p_last_track; + return p_next_tracks; } void AnimationTrackEditor::show_select_node_warning(bool p_show) { @@ -4224,6 +4300,7 @@ void AnimationTrackEditor::_notification(int p_what) { selected_filter->set_icon(get_theme_icon("AnimationFilter", "EditorIcons")); imported_anim_warning->set_icon(get_theme_icon("NodeWarning", "EditorIcons")); main_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_theme_icon("Reload", "EditorIcons")); } if (p_what == NOTIFICATION_READY) { @@ -5056,6 +5133,11 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) { } } +void AnimationTrackEditor::_edit_menu_about_to_popup() { + AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player(); + edit->get_popup()->set_item_disabled(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), !player->can_apply_reset()); +} + void AnimationTrackEditor::_edit_menu_pressed(int p_option) { last_menu_track_opt = p_option; switch (p_option) { @@ -5378,6 +5460,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { emit_signal("timeline_changed", pos, true); } break; + case EDIT_APPLY_RESET: { + AnimationPlayerEditor::singleton->get_player()->apply_reset(true); + + } break; case EDIT_OPTIMIZE_ANIMATION: { optimize_dialog->popup_centered(Size2(250, 180) * EDSCALE); @@ -5710,10 +5796,13 @@ AnimationTrackEditor::AnimationTrackEditor() { edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Go to Next Step"), KEY_MASK_CMD | KEY_RIGHT), EDIT_GOTO_NEXT_STEP); edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Go to Previous Step"), KEY_MASK_CMD | KEY_LEFT), EDIT_GOTO_PREV_STEP); edit->get_popup()->add_separator(); + edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/apply_reset", TTR("Apply Reset")), EDIT_APPLY_RESET); + edit->get_popup()->add_separator(); edit->get_popup()->add_item(TTR("Optimize Animation"), EDIT_OPTIMIZE_ANIMATION); edit->get_popup()->add_item(TTR("Clean-Up Animation"), EDIT_CLEAN_UP_ANIMATION); edit->get_popup()->connect("id_pressed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed)); + edit->get_popup()->connect("about_to_popup", callable_mp(this, &AnimationTrackEditor::_edit_menu_about_to_popup)); pick_track = memnew(SceneTreeDialog); add_child(pick_track); @@ -5739,9 +5828,16 @@ AnimationTrackEditor::AnimationTrackEditor() { insert_confirm->add_child(icvb); insert_confirm_text = memnew(Label); icvb->add_child(insert_confirm_text); + HBoxContainer *ichb = memnew(HBoxContainer); + icvb->add_child(ichb); insert_confirm_bezier = memnew(CheckBox); insert_confirm_bezier->set_text(TTR("Use Bezier Curves")); - icvb->add_child(insert_confirm_bezier); + insert_confirm_bezier->set_pressed(EDITOR_GET("editors/animation/default_create_bezier_tracks")); + ichb->add_child(insert_confirm_bezier); + insert_confirm_reset = memnew(CheckBox); + insert_confirm_reset->set_text(TTR("Create RESET Track(s)", "")); + insert_confirm_reset->set_pressed(EDITOR_GET("editors/animation/default_create_reset_tracks")); + ichb->add_child(insert_confirm_reset); keying = false; moving_selection = false; key_edit = nullptr; diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 3cb31fe21e..7006959187 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -47,6 +47,8 @@ #include "scene/resources/animation.h" #include "scene_tree_editor.h" +class AnimationPlayer; + class AnimationTimelineEdit : public Range { GDCLASS(AnimationTimelineEdit, Range); @@ -285,6 +287,7 @@ class AnimationTrackEditor : public VBoxContainer { EDIT_DELETE_SELECTION, EDIT_GOTO_NEXT_STEP, EDIT_GOTO_PREV_STEP, + EDIT_APPLY_RESET, EDIT_OPTIMIZE_ANIMATION, EDIT_OPTIMIZE_ANIMATION_CONFIRM, EDIT_CLEAN_UP_ANIMATION, @@ -361,6 +364,7 @@ class AnimationTrackEditor : public VBoxContainer { Label *insert_confirm_text; CheckBox *insert_confirm_bezier; + CheckBox *insert_confirm_reset; ConfirmationDialog *insert_confirm; bool insert_queue; bool inserting; @@ -369,9 +373,19 @@ class AnimationTrackEditor : public VBoxContainer { uint64_t insert_frame; void _query_insert(const InsertData &p_id); + Ref<Animation> _create_and_get_reset_animation(); void _confirm_insert_list(); - int _confirm_insert(InsertData p_id, int p_last_track, bool p_create_beziers = false); - void _insert_delay(); + struct TrackIndices { + int normal; + int reset; + + TrackIndices(const Animation *p_anim = nullptr, const Animation *p_reset_anim = nullptr) { + normal = p_anim ? p_anim->get_track_count() : 0; + reset = p_reset_anim ? p_reset_anim->get_track_count() : 0; + } + }; + TrackIndices _confirm_insert(InsertData p_id, TrackIndices p_next_tracks, bool p_create_reset, bool p_create_beziers); + void _insert_delay(bool p_create_reset, bool p_create_beziers); void _root_removed(Node *p_root); @@ -447,6 +461,7 @@ class AnimationTrackEditor : public VBoxContainer { void _select_all_tracks_for_copy(); + void _edit_menu_about_to_popup(); void _edit_menu_pressed(int p_option); int last_menu_track_opt; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index dfe5d64784..a8dc14427d 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1419,6 +1419,17 @@ int EditorNode::_save_external_resources() { return saved; } +static void _reset_animation_players(Node *p_node, List<Ref<AnimatedValuesBackup>> *r_anim_backups) { + for (int i = 0; i < p_node->get_child_count(); i++) { + AnimationPlayer *player = Object::cast_to<AnimationPlayer>(p_node->get_child(i)); + if (player && player->is_reset_on_save_enabled() && player->can_apply_reset()) { + Ref<AnimatedValuesBackup> old_values = player->apply_reset(); + r_anim_backups->push_back(old_values); + } + _reset_animation_players(p_node->get_child(i), r_anim_backups); + } +} + void EditorNode::_save_scene(String p_file, int idx) { Node *scene = editor_data.get_edited_scene_root(idx); @@ -1433,6 +1444,8 @@ void EditorNode::_save_scene(String p_file, int idx) { } editor_data.apply_changes_in_editors(); + List<Ref<AnimatedValuesBackup>> anim_backups; + _reset_animation_players(scene, &anim_backups); _save_default_environment(); _set_scene_metadata(p_file, idx); @@ -1480,6 +1493,11 @@ void EditorNode::_save_scene(String p_file, int idx) { _save_external_resources(); editor_data.save_editor_external_data(); + + for (List<Ref<AnimatedValuesBackup>>::Element *E = anim_backups.front(); E; E = E->next()) { + E->get()->restore(); + } + if (err == OK) { scene->set_filename(ProjectSettings::get_singleton()->localize_path(p_file)); if (idx < 0 || idx == editor_data.get_edited_scene()) { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index e88f27c857..73a191d317 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -628,6 +628,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Animation _initial_set("editors/animation/autorename_animation_tracks", true); _initial_set("editors/animation/confirm_insert_track", true); + _initial_set("editors/animation/default_create_bezier_tracks", false); + _initial_set("editors/animation/default_create_reset_tracks", true); _initial_set("editors/animation/onion_layers_past_color", Color(1, 0, 0)); _initial_set("editors/animation/onion_layers_future_color", Color(0, 1, 0)); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 7e376eee57..4b97dacbc1 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -116,6 +116,19 @@ void AnimationPlayerEditor::_notification(int p_what) { play_bw_from->set_icon(get_theme_icon("PlayBackwards", "EditorIcons")); autoplay_icon = get_theme_icon("AutoPlay", "EditorIcons"); + reset_icon = get_theme_icon("Reload", "EditorIcons"); + { + Ref<Image> autoplay_img = autoplay_icon->get_data(); + Ref<Image> reset_img = reset_icon->get_data(); + Ref<Image> autoplay_reset_img; + Size2 icon_size = Size2(autoplay_img->get_width(), autoplay_img->get_height()); + autoplay_reset_img.instance(); + autoplay_reset_img->create(icon_size.x * 2, icon_size.y, false, autoplay_img->get_format()); + autoplay_reset_img->blit_rect(autoplay_img, Rect2(Point2(), icon_size), Point2()); + autoplay_reset_img->blit_rect(reset_img, Rect2(Point2(), icon_size), Point2(icon_size.x, 0)); + autoplay_reset_icon.instance(); + autoplay_reset_icon->create_from_image(autoplay_reset_img); + } stop->set_icon(get_theme_icon("Stop", "EditorIcons")); onion_toggle->set_icon(get_theme_icon("Onion", "EditorIcons")); @@ -817,11 +830,17 @@ void AnimationPlayerEditor::_update_player() { int active_idx = -1; for (List<StringName>::Element *E = animlist.front(); E; E = E->next()) { - if (player->get_autoplay() == E->get()) { - animation->add_icon_item(autoplay_icon, E->get()); - } else { - animation->add_item(E->get()); + Ref<Texture2D> icon; + if (E->get() == player->get_autoplay()) { + if (E->get() == "RESET") { + icon = autoplay_reset_icon; + } else { + icon = autoplay_icon; + } + } else if (E->get() == "RESET") { + icon = reset_icon; } + animation->add_icon_item(icon, E->get()); if (player->get_assigned_animation() == E->get()) { active_idx = animation->get_item_count() - 1; @@ -1375,7 +1394,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { } // Backup current animation state. - AnimatedValuesBackup values_backup = player->backup_animated_values(); + Ref<AnimatedValuesBackup> values_backup = player->backup_animated_values(); float cpos = player->get_current_animation_position(); // Render every past/future step with the capture shader. @@ -1405,7 +1424,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { if (valid) { player->seek(pos, true); get_tree()->flush_transform_notifications(); // Needed for transforms of Node3Ds. - values_backup.update_skeletons(); // Needed for Skeletons (2D & 3D). + values_backup->update_skeletons(); // Needed for Skeletons (2D & 3D). RS::get_singleton()->viewport_set_active(onion.captures[cidx], true); RS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]); @@ -1425,7 +1444,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { // (Seeking with update=true wouldn't do the trick because the current value of the properties // may not match their value for the current point in the animation). player->seek(cpos, false); - player->restore_animated_values(values_backup); + values_backup->restore(); // Restore state of main editors. if (Node3DEditor::get_singleton()->is_visible()) { diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 17e554ee0d..ab3feb115f 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -105,6 +105,8 @@ class AnimationPlayerEditor : public VBoxContainer { Label *name_title; UndoRedo *undo_redo; Ref<Texture2D> autoplay_icon; + Ref<Texture2D> reset_icon; + Ref<ImageTexture> autoplay_reset_icon; bool last_active; float timeline_position; |