From 8ded8830e0d45e2fa22d5037f8ca4379e037fdd8 Mon Sep 17 00:00:00 2001 From: Valentin Zagura Date: Fri, 30 Aug 2019 22:05:35 +0100 Subject: [PATCH] Bezier Editor - add "Apply Function on Selected Keys" Added Apply Function on Selected Key(s) feature so you can now scale, move keys and more easily create effects (like Bounce, Overshoot, etc) Functions can have parameters "time" and "value", "time" is the time of the key, "value" is the current value of the key. --- editor/animation_bezier_editor.cpp | 103 +++++++++++++++++++++++++++++ editor/animation_bezier_editor.h | 8 ++- 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 14ea18f885d2..94937ccab13e 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -30,6 +30,7 @@ #include "animation_bezier_editor.h" +#include "core/math/expression.h" #include "editor/editor_node.h" float AnimationBezierTrackEdit::_bezier_h_to_pixel(float p_h) { @@ -673,6 +674,9 @@ void AnimationBezierTrackEdit::_gui_input(const Ref &p_event) { menu->add_separator(); menu->add_icon_item(get_icon("Duplicate", "EditorIcons"), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE); menu->add_separator(); + //menu->add_icon_item(get_icon("Path", "EditorIcons"), TTR("Apply Function on Selected Key(s)"), MENU_KEY_APPLY_FUNCTION); + menu->add_item(TTR("Apply Function on Selected Key(s)"), MENU_KEY_APPLY_FUNCTION); + menu->add_separator(); menu->add_icon_item(get_icon("Remove", "EditorIcons"), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE); } @@ -1079,6 +1083,12 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) { case MENU_KEY_DELETE: { delete_selection(); } break; + case MENU_KEY_APPLY_FUNCTION: { + apply_function_dialog->popup_centered(Size2(200, 100) * EDSCALE); + } break; + case EDIT_FUNCTION_CONFIRM: { + apply_function_on_selection(); + } break; } } @@ -1140,6 +1150,87 @@ void AnimationBezierTrackEdit::duplicate_selection() { update(); } +void AnimationBezierTrackEdit::apply_function_on_selection() { + + String function_text = apply_function_value->get_line_edit()->get_text(); + + Ref expr; + expr.instance(); + + Vector params; + params.push_back("time"); + params.push_back("value"); + + Error err = expr->parse(function_text, params); + if (err != OK) { + return; + } + + if (selection.size() == 0) + return; + + undo_redo->create_action(TTR("Anim Apply Function")); + + List to_restore; + // 1-remove the keys + for (Set::Element *E = selection.back(); E; E = E->prev()) { + + undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, E->get()); + } + + // 2-move the keys (re insert them) + for (Set::Element *E = selection.back(); E; E = E->prev()) { + + float t = editor->snap_time(animation->track_get_key_time(track, E->get())); + + Array key = animation->track_get_key_value(track, E->get()); + float v = key[0]; + + Array a; + a.push_back(t); + a.push_back(v); + + Variant res = expr->execute(a, NULL, false); + if (res.get_type() == Variant::REAL || res.get_type() == Variant::INT) { + v = float(res); + } + + key[0] = v; + undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, t, key, 1); + } + + // 3-(undo) remove inserted keys + for (Set::Element *E = selection.back(); E; E = E->prev()) { + + float newpos = editor->snap_time(animation->track_get_key_time(track, E->get())); + + undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, newpos); + } + + // 4-(undo) reinsert keys + for (Set::Element *E = selection.back(); E; E = E->prev()) { + + float oldpos = animation->track_get_key_time(track, E->get()); + undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, oldpos, animation->track_get_key_value(track, E->get()), 1); + } + + undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); + + // 5-reselect + + for (Set::Element *E = selection.back(); E; E = E->prev()) { + + float oldpos = animation->track_get_key_time(track, E->get()); + float newpos = editor->snap_time(oldpos + moving_selection_offset.x); + + undo_redo->add_do_method(this, "_select_at_anim", animation, track, newpos); + undo_redo->add_undo_method(this, "_select_at_anim", animation, track, oldpos); + } + + undo_redo->commit_action(); +} + void AnimationBezierTrackEdit::delete_selection() { if (selection.size()) { undo_redo->create_action(TTR("Anim Delete Keys")); @@ -1221,5 +1312,17 @@ AnimationBezierTrackEdit::AnimationBezierTrackEdit() { add_child(menu); menu->connect("id_pressed", this, "_menu_selected"); + apply_function_dialog = memnew(ConfirmationDialog); + VBoxContainer *vbc = memnew(VBoxContainer); + apply_function_dialog->add_child(vbc); + + apply_function_value = memnew(SpinBox); + apply_function_value->set_min(-99999); + apply_function_value->set_max(99999); + apply_function_value->set_step(0.001); + vbc->add_margin_child(TTR("Function (time,value):"), apply_function_value); + apply_function_dialog->connect("confirmed", this, "_menu_selected", varray(EDIT_FUNCTION_CONFIRM)); + add_child(apply_function_dialog); + //set_mouse_filter(MOUSE_FILTER_PASS); //scroll has to work too for selection } diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h index 49aab48719fb..75936062d238 100644 --- a/editor/animation_bezier_editor.h +++ b/editor/animation_bezier_editor.h @@ -46,7 +46,9 @@ class AnimationBezierTrackEdit : public Control { enum { MENU_KEY_INSERT, MENU_KEY_DUPLICATE, - MENU_KEY_DELETE + MENU_KEY_DELETE, + MENU_KEY_APPLY_FUNCTION, + EDIT_FUNCTION_CONFIRM }; HandleMode handle_mode; @@ -76,6 +78,9 @@ class AnimationBezierTrackEdit : public Control { PopupMenu *menu; + ConfirmationDialog *apply_function_dialog; + SpinBox *apply_function_value; + void _zoom_changed(); void _gui_input(const Ref &p_event); @@ -164,6 +169,7 @@ class AnimationBezierTrackEdit : public Control { void duplicate_selection(); void delete_selection(); + void apply_function_on_selection(); AnimationBezierTrackEdit(); };