diff options
Diffstat (limited to 'editor/animation_track_editor.cpp')
-rw-r--r-- | editor/animation_track_editor.cpp | 738 |
1 files changed, 441 insertions, 297 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index ff2818f027..7f118532c9 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -165,21 +165,40 @@ public: } switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM3D: { - Dictionary d_old = animation->track_get_key_value(track, key); - Dictionary d_new = d_old.duplicate(); - d_new[p_name] = p_value; - setting = true; - undo_redo->create_action(TTR("Anim Change Transform")); - undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new); - undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old); - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - undo_redo->commit_action(); + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: { + if (name == "position" || name == "rotation" || name == "scale") { + Variant old = animation->track_get_key_value(track, key); + setting = true; + String chan; + switch (animation->track_get_type(track)) { + case Animation::TYPE_POSITION_3D: + chan = "Position3D"; + break; + case Animation::TYPE_ROTATION_3D: + chan = "Rotation3D"; + break; + case Animation::TYPE_SCALE_3D: + chan = "Scale3D"; + break; + default: { + } + } + + undo_redo->create_action(vformat(TTR("Anim Change %s"), chan)); + undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value); + undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old); + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + undo_redo->commit_action(); + + setting = false; + return true; + } - setting = false; - return true; } break; + case Animation::TYPE_BLEND_SHAPE: case Animation::TYPE_VALUE: { if (name == "value") { Variant value = p_value; @@ -412,13 +431,15 @@ public: } switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM3D: { - Dictionary d = animation->track_get_key_value(track, key); - ERR_FAIL_COND_V(!d.has(name), false); - r_ret = d[p_name]; - return true; - + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: { + if (name == "position" || name == "rotation" || name == "scale") { + r_ret = animation->track_get_key_value(track, key); + return true; + } } break; + case Animation::TYPE_BLEND_SHAPE: case Animation::TYPE_VALUE: { if (name == "value") { r_ret = animation->track_get_key_value(track, key); @@ -523,11 +544,17 @@ public: } switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM3D: { - p_list->push_back(PropertyInfo(Variant::VECTOR3, "location")); - p_list->push_back(PropertyInfo(Variant::QUATERNION, "rotation")); + case Animation::TYPE_POSITION_3D: { + p_list->push_back(PropertyInfo(Variant::VECTOR3, "position")); + } break; + case Animation::TYPE_ROTATION_3D: { + p_list->push_back(PropertyInfo(Variant::VECTOR3, "rotation")); + } break; + case Animation::TYPE_SCALE_3D: { p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale")); - + } break; + case Animation::TYPE_BLEND_SHAPE: { + p_list->push_back(PropertyInfo(Variant::FLOAT, "value")); } break; case Animation::TYPE_VALUE: { Variant v = animation->track_get_key_value(track, key); @@ -541,7 +568,7 @@ public: String hint_string; if (v.get_type() == Variant::OBJECT) { - //could actually check the object property if exists..? yes i will! + // Could actually check the object property if exists..? Yes I will! Ref<Resource> res = v; if (res.is_valid()) { hint = PROPERTY_HINT_RESOURCE_TYPE; @@ -700,16 +727,15 @@ public: return; } - for (Map<int, List<float>>::Element *E = key_ofs_map.front(); E; E = E->next()) { + for (const KeyValue<int, List<float>> &E : key_ofs_map) { int key = 0; - for (float &F : E->value()) { - float key_ofs = F; + for (const float &key_ofs : E.value) { if (from != key_ofs) { key++; continue; } - int track = E->key(); + int track = E.key; key_ofs_map[track][key] = to; if (setting) { @@ -726,10 +752,9 @@ public: bool _set(const StringName &p_name, const Variant &p_value) { bool update_obj = false; bool change_notify_deserved = false; - for (Map<int, List<float>>::Element *E = key_ofs_map.front(); E; E = E->next()) { - int track = E->key(); - for (float &F : E->value()) { - float key_ofs = F; + for (const KeyValue<int, List<float>> &E : key_ofs_map) { + int track = E.key; + for (const float &key_ofs : E.value) { int key = animation->track_find_key(track, key_ofs, true); ERR_FAIL_COND_V(key == -1, false); @@ -781,19 +806,34 @@ public: } switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM3D: { - Dictionary d_old = animation->track_get_key_value(track, key); - Dictionary d_new = d_old.duplicate(); - d_new[p_name] = p_value; - + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: { + Variant old = animation->track_get_key_value(track, key); if (!setting) { + String chan; + switch (animation->track_get_type(track)) { + case Animation::TYPE_POSITION_3D: + chan = "Position3D"; + break; + case Animation::TYPE_ROTATION_3D: + chan = "Rotation3D"; + break; + case Animation::TYPE_SCALE_3D: + chan = "Scale3D"; + break; + default: { + } + } + setting = true; - undo_redo->create_action(TTR("Anim Multi Change Transform")); + undo_redo->create_action(vformat(TTR("Anim Multi Change %s"), chan)); } - undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new); - undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old); + undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value); + undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old); update_obj = true; } break; + case Animation::TYPE_BLEND_SHAPE: case Animation::TYPE_VALUE: { if (name == "value") { Variant value = p_value; @@ -984,10 +1024,9 @@ public: } bool _get(const StringName &p_name, Variant &r_ret) const { - for (Map<int, List<float>>::Element *E = key_ofs_map.front(); E; E = E->next()) { - int track = E->key(); - for (float &F : E->value()) { - float key_ofs = F; + for (const KeyValue<int, List<float>> &E : key_ofs_map) { + int track = E.key; + for (const float &key_ofs : E.value) { int key = animation->track_find_key(track, key_ofs, true); ERR_CONTINUE(key == -1); @@ -1012,13 +1051,16 @@ public: } switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM3D: { - Dictionary d = animation->track_get_key_value(track, key); - ERR_FAIL_COND_V(!d.has(name), false); - r_ret = d[p_name]; - return true; + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: { + if (name == "position" || name == "rotation" || name == "scale") { + r_ret = animation->track_get_key_value(track, key); + return true; + } } break; + case Animation::TYPE_BLEND_SHAPE: case Animation::TYPE_VALUE: { if (name == "value") { r_ret = animation->track_get_key_value(track, key); @@ -1119,15 +1161,15 @@ public: bool show_time = true; bool same_track_type = true; bool same_key_type = true; - for (Map<int, List<float>>::Element *E = key_ofs_map.front(); E; E = E->next()) { - int track = E->key(); + for (const KeyValue<int, List<float>> &E : key_ofs_map) { + int track = E.key; ERR_FAIL_INDEX(track, animation->get_track_count()); if (first_track < 0) { first_track = track; } - if (show_time && E->value().size() > 1) { + if (show_time && E.value.size() > 1) { show_time = false; } @@ -1137,7 +1179,7 @@ public: same_key_type = false; } - for (float &F : E->value()) { + for (const float &F : E.value) { int key = animation->track_find_key(track, F, true); ERR_FAIL_COND(key == -1); if (first_key < 0) { @@ -1162,11 +1204,18 @@ public: if (same_track_type) { switch (animation->track_get_type(first_track)) { - case Animation::TYPE_TRANSFORM3D: { - p_list->push_back(PropertyInfo(Variant::VECTOR3, "location")); - p_list->push_back(PropertyInfo(Variant::QUATERNION, "rotation")); + case Animation::TYPE_POSITION_3D: { + p_list->push_back(PropertyInfo(Variant::VECTOR3, "position")); + } break; + case Animation::TYPE_ROTATION_3D: { + p_list->push_back(PropertyInfo(Variant::QUATERNION, "scale")); + } break; + case Animation::TYPE_SCALE_3D: { p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale")); } break; + case Animation::TYPE_BLEND_SHAPE: { + p_list->push_back(PropertyInfo(Variant::FLOAT, "value")); + } break; case Animation::TYPE_VALUE: { if (same_key_type) { Variant v = animation->track_get_key_value(first_track, first_key); @@ -1180,7 +1229,7 @@ public: String hint_string; if (v.get_type() == Variant::OBJECT) { - //could actually check the object property if exists..? yes i will! + // Could actually check the object property if exists..? Yes I will! Ref<Resource> res = v; if (res.is_valid()) { hint = PROPERTY_HINT_RESOURCE_TYPE; @@ -1362,7 +1411,10 @@ void AnimationTimelineEdit::_notification(int p_what) { add_track->get_popup()->clear(); add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyValue"), SNAME("EditorIcons")), TTR("Property Track")); - add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyXform"), SNAME("EditorIcons")), TTR("3D Transform Track")); + add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyXPosition"), SNAME("EditorIcons")), TTR("3D Position Track")); + add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyXRotation"), SNAME("EditorIcons")), TTR("3D Rotation Track")); + add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyXScale"), SNAME("EditorIcons")), TTR("3D Scale Track")); + add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyBlendShape"), SNAME("EditorIcons")), TTR("Blend Shape Track")); add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyCall"), SNAME("EditorIcons")), TTR("Call Method Track")); add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyBezier"), SNAME("EditorIcons")), TTR("Bezier Curve Track")); add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyAudio"), SNAME("EditorIcons")), TTR("Audio Playback Track")); @@ -1391,7 +1443,7 @@ void AnimationTimelineEdit::_notification(int p_what) { float l = animation->get_length(); if (l <= 0) { - l = 0.001; //avoid crashor + l = 0.001; // Avoid crashor. } Ref<Texture2D> hsize_icon = get_theme_icon(SNAME("Hsize"), SNAME("EditorIcons")); @@ -1404,18 +1456,12 @@ void AnimationTimelineEdit::_notification(int p_what) { for (int i = 0; i < animation->get_track_count(); i++) { if (animation->track_get_key_count(i) > 0) { float beg = animation->track_get_key_time(i, 0); - /*if (animation->track_get_type(i) == Animation::TYPE_BEZIER) { - beg += animation->bezier_track_get_key_in_handle(i, 0).x; - }* not worth it since they have no use */ if (beg < time_min) { time_min = beg; } float end = animation->track_get_key_time(i, animation->track_get_key_count(i) - 1); - /*if (animation->track_get_type(i) == Animation::TYPE_BEZIER) { - end += animation->bezier_track_get_key_out_handle(i, animation->track_get_key_count(i) - 1).x; - } not worth it since they have no use */ if (end > time_max) { time_max = end; @@ -1425,8 +1471,6 @@ void AnimationTimelineEdit::_notification(int p_what) { float extra = (zoomw / scale) * 0.5; - //if (time_min < -0.001) - // time_min -= extra; time_max += extra; set_min(time_min); set_max(time_max); @@ -1642,7 +1686,7 @@ void AnimationTimelineEdit::_play_position_draw() { } } -void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) { +void AnimationTimelineEdit::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); const Ref<InputEventMouseButton> mb = p_event; @@ -1754,8 +1798,6 @@ void AnimationTimelineEdit::_track_added(int p_track) { } void AnimationTimelineEdit::_bind_methods() { - ClassDB::bind_method("_gui_input", &AnimationTimelineEdit::_gui_input); - ADD_SIGNAL(MethodInfo("zoom_changed")); ADD_SIGNAL(MethodInfo("name_limit_changed")); ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag"))); @@ -1841,9 +1883,12 @@ void AnimationTrackEdit::_notification(int p_what) { Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label")); Color color = get_theme_color(SNAME("font_color"), SNAME("Label")); - Ref<Texture2D> type_icons[6] = { + Ref<Texture2D> type_icons[9] = { get_theme_icon(SNAME("KeyValue"), SNAME("EditorIcons")), - get_theme_icon(SNAME("KeyXform"), SNAME("EditorIcons")), + get_theme_icon(SNAME("KeyTrackPosition"), SNAME("EditorIcons")), + get_theme_icon(SNAME("KeyTrackRotation"), SNAME("EditorIcons")), + get_theme_icon(SNAME("KeyTrackScale"), SNAME("EditorIcons")), + get_theme_icon(SNAME("KeyTrackBlendShape"), SNAME("EditorIcons")), get_theme_icon(SNAME("KeyCall"), SNAME("EditorIcons")), get_theme_icon(SNAME("KeyBezier"), SNAME("EditorIcons")), get_theme_icon(SNAME("KeyAudio"), SNAME("EditorIcons")), @@ -1858,7 +1903,7 @@ void AnimationTrackEdit::_notification(int p_what) { { Ref<Texture2D> check = animation->track_is_enabled(track) ? get_theme_icon(SNAME("checked"), SNAME("CheckBox")) : get_theme_icon(SNAME("unchecked"), SNAME("CheckBox")); - int ofs = in_group ? check->get_width() : 0; //not the best reference for margin but.. + int ofs = in_group ? check->get_width() : 0; // Not the best reference for margin but.. check_rect = Rect2(Point2(ofs, int(get_size().height - check->get_height()) / 2), check->get_size()); draw_texture(check, check_rect.position); @@ -1976,7 +2021,7 @@ void AnimationTrackEdit::_notification(int p_what) { ofs += hsep; { - //callmode + // Callmode. Animation::UpdateMode update_mode; @@ -1995,7 +2040,7 @@ void AnimationTrackEdit::_notification(int p_what) { if (animation->track_get_type(track) == Animation::TYPE_VALUE) { draw_texture(update_icon, update_mode_rect.position); } - //make it easier to click + // Make it easier to click. update_mode_rect.position.y = 0; update_mode_rect.size.y = get_size().height; @@ -2024,7 +2069,7 @@ void AnimationTrackEdit::_notification(int p_what) { } { - //interp + // Interp. Animation::InterpolationType interp_mode = animation->track_get_interpolation_type(track); @@ -2034,17 +2079,17 @@ void AnimationTrackEdit::_notification(int p_what) { interp_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2; interp_mode_rect.size = icon->get_size(); - if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) { + if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D) { draw_texture(icon, interp_mode_rect.position); } - //make it easier to click + // Make it easier to click. interp_mode_rect.position.y = 0; interp_mode_rect.size.y = get_size().height; ofs += icon->get_width() + hsep; interp_mode_rect.size.x += hsep; - if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) { + if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D) { draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); interp_mode_rect.size.x += down_icon->get_width(); } else { @@ -2057,7 +2102,7 @@ void AnimationTrackEdit::_notification(int p_what) { } { - //loop + // Loop. bool loop_wrap = animation->track_get_interpolation_loop_wrap(track); @@ -2067,7 +2112,7 @@ void AnimationTrackEdit::_notification(int p_what) { loop_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2; loop_mode_rect.size = icon->get_size(); - if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) { + if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D) { draw_texture(icon, loop_mode_rect.position); } @@ -2077,7 +2122,7 @@ void AnimationTrackEdit::_notification(int p_what) { ofs += icon->get_width() + hsep; loop_mode_rect.size.x += hsep; - if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) { + if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D) { draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); loop_mode_rect.size.x += down_icon->get_width(); } else { @@ -2090,7 +2135,7 @@ void AnimationTrackEdit::_notification(int p_what) { } { - //erase + // Erase. Ref<Texture2D> icon = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")); @@ -2137,7 +2182,7 @@ Rect2 AnimationTrackEdit::get_key_rect(int p_index, float p_pixels_sec) { } Rect2 rect = Rect2(-type_icon->get_width() / 2, 0, type_icon->get_width(), get_size().height); - //make it a big easier to click + // Make it a big easier to click. rect.position.x -= rect.size.x * 0.5; rect.size.x *= 2; return rect; @@ -2226,7 +2271,7 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool draw_texture(icon_to_draw, ofs); } -//helper +// Helper. void AnimationTrackEdit::draw_rect_clipped(const Rect2 &p_rect, const Color &p_color, bool p_filled) { int clip_left = timeline->get_name_limit(); int clip_right = get_size().width - timeline->get_buttons_width(); @@ -2251,7 +2296,7 @@ void AnimationTrackEdit::draw_texture_region_clipped(const Ref<Texture2D> &p_tex int clip_left = timeline->get_name_limit(); int clip_right = get_size().width - timeline->get_buttons_width(); - //clip left and right + // Clip left and right. if (clip_left > p_rect.position.x + p_rect.size.x) { return; } @@ -2297,9 +2342,12 @@ void AnimationTrackEdit::set_animation_and_track(const Ref<Animation> &p_animati track = p_track; update(); - Ref<Texture2D> type_icons[6] = { + Ref<Texture2D> type_icons[9] = { get_theme_icon(SNAME("KeyValue"), SNAME("EditorIcons")), - get_theme_icon(SNAME("KeyXform"), SNAME("EditorIcons")), + get_theme_icon(SNAME("KeyXPosition"), SNAME("EditorIcons")), + get_theme_icon(SNAME("KeyXRotation"), SNAME("EditorIcons")), + get_theme_icon(SNAME("KeyXScale"), SNAME("EditorIcons")), + get_theme_icon(SNAME("KeyBlendShape"), SNAME("EditorIcons")), get_theme_icon(SNAME("KeyCall"), SNAME("EditorIcons")), get_theme_icon(SNAME("KeyBezier"), SNAME("EditorIcons")), get_theme_icon(SNAME("KeyAudio"), SNAME("EditorIcons")), @@ -2460,7 +2508,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const { key_distance = distance; } } else { - //first one does it + // First one does it. break; } } @@ -2469,17 +2517,21 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const { if (key_idx != -1) { String text = TTR("Time (s): ") + rtos(animation->track_get_key_time(track, key_idx)) + "\n"; switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM3D: { - Dictionary d = animation->track_get_key_value(track, key_idx); - if (d.has("location")) { - text += "Pos: " + String(d["location"]) + "\n"; - } - if (d.has("rotation")) { - text += "Rot: " + String(d["rotation"]) + "\n"; - } - if (d.has("scale")) { - text += "Scale: " + String(d["scale"]) + "\n"; - } + case Animation::TYPE_POSITION_3D: { + Vector3 t = animation->track_get_key_value(track, key_idx); + text += "Position: " + String(t) + "\n"; + } break; + case Animation::TYPE_ROTATION_3D: { + Quaternion t = animation->track_get_key_value(track, key_idx); + text += "Rotation: " + String(t) + "\n"; + } break; + case Animation::TYPE_SCALE_3D: { + Vector3 t = animation->track_get_key_value(track, key_idx); + text += "Scale: " + String(t) + "\n"; + } break; + case Animation::TYPE_BLEND_SHAPE: { + float t = animation->track_get_key_value(track, key_idx); + text += "Blend Shape: " + itos(t) + "\n"; } break; case Animation::TYPE_VALUE: { const Variant &v = animation->track_get_key_value(track, key_idx); @@ -2551,7 +2603,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const { return Control::get_tooltip(p_pos); } -void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) { +void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (p_event->is_pressed()) { @@ -2965,8 +3017,6 @@ void AnimationTrackEdit::append_to_selection(const Rect2 &p_box, bool p_deselect } void AnimationTrackEdit::_bind_methods() { - ClassDB::bind_method("_gui_input", &AnimationTrackEdit::_gui_input); - ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag"))); ADD_SIGNAL(MethodInfo("remove_request", PropertyInfo(Variant::INT, "track"))); ADD_SIGNAL(MethodInfo("dropped", PropertyInfo(Variant::INT, "from_track"), PropertyInfo(Variant::INT, "to_track"))); @@ -3008,7 +3058,7 @@ AnimationTrackEdit::AnimationTrackEdit() { play_position->set_anchors_and_offsets_preset(PRESET_WIDE); play_position->connect("draw", callable_mp(this, &AnimationTrackEdit::_play_position_draw)); set_focus_mode(FOCUS_CLICK); - set_mouse_filter(MOUSE_FILTER_PASS); //scroll has to work too for selection + set_mouse_filter(MOUSE_FILTER_PASS); // Scroll has to work too for selection. } ////////////////////////////////////// @@ -3336,39 +3386,31 @@ static bool track_type_is_resettable(Animation::TrackType p_type) { switch (p_type) { case Animation::TYPE_VALUE: [[fallthrough]]; + case Animation::TYPE_BLEND_SHAPE: + [[fallthrough]]; case Animation::TYPE_BEZIER: [[fallthrough]]; - case Animation::TYPE_TRANSFORM3D: + case Animation::TYPE_POSITION_3D: + [[fallthrough]]; + case Animation::TYPE_ROTATION_3D: + [[fallthrough]]; + case Animation::TYPE_SCALE_3D: 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 - if (insert_confirm->is_visible()) { - return; //do nothing - } - insert_data.clear(); - insert_query = false; - } - insert_frame = Engine::get_singleton()->get_frames_drawn(); - - for (const InsertData &E : insert_data) { - //prevent insertion of multiple tracks - if (E.path == p_id.path) { - return; //already inserted a track for this on this frame - } - } - - insert_data.push_back(p_id); +void AnimationTrackEditor::make_insert_queue() { + insert_data.clear(); + insert_queue = true; +} +void AnimationTrackEditor::commit_insert_queue() { bool reset_allowed = true; - AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player(); + AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player(); if (player->has_animation("RESET") && player->get_animation("RESET") == animation) { - // Avoid messing with the reset animation itself + // Avoid messing with the reset animation itself. reset_allowed = false; } else { bool some_resettable = false; @@ -3383,74 +3425,82 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) { } } - if (p_id.track_idx == -1) { - 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; - } + // Organize insert data. + int num_tracks = 0; + String last_track_query; + 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].type != Animation::TYPE_VALUE) { - continue; - } + if (insert_data[i].track_idx == -1) { + ++num_tracks; + last_track_query = insert_data[i].query; + } - switch (insert_data[i].value.get_type()) { - case Variant::INT: - case Variant::FLOAT: - case Variant::VECTOR2: - case Variant::VECTOR3: - case Variant::QUATERNION: - case Variant::PLANE: - case Variant::COLOR: { - // Valid. - } break; - default: { - all_bezier = false; - } - } + if (insert_data[i].type != Animation::TYPE_VALUE) { + continue; } - if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) { - //potential new key, does not exist - if (num_tracks == 1) { - // TRANSLATORS: %s will be replaced by a phrase describing the target of track. - insert_confirm_text->set_text(vformat(TTR("Create new track for %s and insert key?"), p_id.query)); - } else { - insert_confirm_text->set_text(vformat(TTR("Create %d new tracks and insert keys?"), num_tracks)); + switch (insert_data[i].value.get_type()) { + case Variant::INT: + case Variant::FLOAT: + case Variant::VECTOR2: + case Variant::VECTOR3: + case Variant::QUATERNION: + case Variant::PLANE: + case Variant::COLOR: { + // Valid. + } break; + default: { + all_bezier = false; } + } + } - 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; + if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true)) && num_tracks > 0) { + // Potentially a new key, does not exist. + if (num_tracks == 1) { + // TRANSLATORS: %s will be replaced by a phrase describing the target of track. + insert_confirm_text->set_text(vformat(TTR("Create new track for %s and insert key?"), last_track_query)); } else { - call_deferred(SNAME("_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; + insert_confirm_text->set_text(vformat(TTR("Create %d new tracks and insert keys?"), num_tracks)); } + 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(); } else { - if (!insert_query && !insert_queue) { - // Create Beziers wouldn't make sense in this case, where no tracks are being created - call_deferred(SNAME("_insert_delay"), reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), false); - insert_queue = true; - } + _insert_track(reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), all_bezier && EDITOR_GET("editors/animation/default_create_bezier_tracks")); } + + insert_queue = false; } -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; - return; +void AnimationTrackEditor::_query_insert(const InsertData &p_id) { + if (!insert_queue) { + insert_data.clear(); + } + + for (const InsertData &E : insert_data) { + // Prevent insertion of multiple tracks. + if (E.path == p_id.path) { + return; // Already inserted a track this frame. + } + } + + insert_data.push_back(p_id); + + // Without queue, commit immediately. + if (!insert_queue) { + commit_insert_queue(); } +} +void AnimationTrackEditor::_insert_track(bool p_create_reset, bool p_create_beziers) { undo_redo->create_action(TTR("Anim Insert")); Ref<Animation> reset_anim; @@ -3485,7 +3535,6 @@ void AnimationTrackEditor::_insert_delay(bool p_create_reset, bool p_create_bezi set_anim_pos(pos); emit_signal(SNAME("timeline_changed"), pos, true); } - insert_queue = false; } void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Transform3D &p_xform) { @@ -3497,7 +3546,7 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_ } ERR_FAIL_COND(!root); - //let's build a node path + // Let's build a node path. String path = root->get_path_to(p_node); if (p_sub != "") { path += ":" + p_sub; @@ -3505,45 +3554,86 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_ NodePath np = path; - int track_idx = -1; + int position_idx = -1; + int rotation_idx = -1; + int scale_idx = -1; for (int i = 0; i < animation->get_track_count(); i++) { - if (animation->track_get_type(i) != Animation::TYPE_TRANSFORM3D) { - continue; - } if (animation->track_get_path(i) != np) { continue; } - track_idx = i; - break; + 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; + } } InsertData id; - Dictionary val; - id.path = np; - id.track_idx = track_idx; - id.value = p_xform; - id.type = Animation::TYPE_TRANSFORM3D; // TRANSLATORS: This describes the target of new animation track, will be inserted into another string. 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_quaternion(); + 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); + } +} + +bool AnimationTrackEditor::has_transform_track(Node3D *p_node, const String &p_sub) { + if (!keying) { + return false; + } + if (!animation.is_valid()) { + return false; + } + if (!root) { + return false; + } - _query_insert(id); + //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) { + if (animation->track_get_type(track_id) == Animation::TYPE_POSITION_3D || animation->track_get_type(track_id) == Animation::TYPE_ROTATION_3D || animation->track_get_type(track_id) == Animation::TYPE_SCALE_3D) { + return true; + } + } + return false; } void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant &p_value) { String path = p_path; - //animation property is a special case, always creates an animation track + // Animation property is a special case, always creates an animation track. for (int i = 0; i < animation->get_track_count(); i++) { String np = animation->track_get_path(i); if (path == np && animation->track_get_type(i) == Animation::TYPE_ANIMATION) { - //exists + // Exists. InsertData id; id.path = path; id.track_idx = i; @@ -3552,7 +3642,7 @@ void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant // TRANSLATORS: This describes the target of new animation track, will be inserted into another string. id.query = TTR("animation"); id.advance = false; - //dialog insert + // Dialog insert. _query_insert(id); return; } @@ -3565,20 +3655,20 @@ void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant id.type = Animation::TYPE_ANIMATION; id.query = TTR("animation"); id.advance = false; - //dialog insert + // Dialog insert. _query_insert(id); } void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists) { ERR_FAIL_COND(!root); - //let's build a node path + // Let's build a node path. Node *node = p_node; String path = root->get_path_to(node); if (Object::cast_to<AnimationPlayer>(node) && p_property == "current_animation") { - if (node == AnimationPlayerEditor::singleton->get_player()) { + if (node == AnimationPlayerEditor::get_singleton()->get_player()) { EditorNode::get_singleton()->show_warning(TTR("AnimationPlayer can't animate itself, only other players.")); return; } @@ -3597,7 +3687,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p NodePath np = path; - //locate track + // Locate track. bool inserted = false; @@ -3615,14 +3705,14 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p // TRANSLATORS: This describes the target of new animation track, will be inserted into another string. id.query = vformat(TTR("property '%s'"), p_property); id.advance = false; - //dialog insert + // Dialog insert. _query_insert(id); inserted = true; } else if (animation->track_get_type(i) == Animation::TYPE_BEZIER) { Variant value; String track_path = animation->track_get_path(i); if (track_path == np) { - value = p_value; //all good + value = p_value; // All good. } else { int sep = track_path.rfind(":"); if (sep != -1) { @@ -3645,7 +3735,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p id.type = Animation::TYPE_BEZIER; id.query = vformat(TTR("property '%s'"), p_property); id.advance = false; - //dialog insert + // Dialog insert. _query_insert(id); inserted = true; } @@ -3661,7 +3751,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p id.type = Animation::TYPE_VALUE; id.query = vformat(TTR("property '%s'"), p_property); id.advance = false; - //dialog insert + // Dialog insert. _query_insert(id); } @@ -3669,7 +3759,7 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari EditorHistory *history = EditorNode::get_singleton()->get_editor_history(); ERR_FAIL_COND(!root); - //let's build a node path + // Let's build a node path. ERR_FAIL_COND(history->get_path_size() == 0); Object *obj = ObjectDB::get_instance(history->get_path_object(0)); ERR_FAIL_COND(!Object::cast_to<Node>(obj)); @@ -3679,7 +3769,7 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari String path = root->get_path_to(node); if (Object::cast_to<AnimationPlayer>(node) && p_property == "current_animation") { - if (node == AnimationPlayerEditor::singleton->get_player()) { + if (node == AnimationPlayerEditor::get_singleton()->get_player()) { EditorNode::get_singleton()->show_warning(TTR("AnimationPlayer can't animate itself, only other players.")); return; } @@ -3697,10 +3787,11 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari NodePath np = path; - //locate track + // Locate track. bool inserted = false; + make_insert_queue(); for (int i = 0; i < animation->get_track_count(); i++) { if (animation->track_get_type(i) == Animation::TYPE_VALUE) { if (animation->track_get_path(i) != np) { @@ -3714,13 +3805,13 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari id.type = Animation::TYPE_VALUE; id.query = vformat(TTR("property '%s'"), p_property); id.advance = p_advance; - //dialog insert + // Dialog insert. _query_insert(id); inserted = true; } else if (animation->track_get_type(i) == Animation::TYPE_BEZIER) { Variant value; if (animation->track_get_path(i) == np) { - value = p_value; //all good + value = p_value; // All good. } else { String tpath = animation->track_get_path(i); int index = tpath.rfind(":"); @@ -3739,11 +3830,12 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari id.type = Animation::TYPE_BEZIER; id.query = vformat(TTR("property '%s'"), p_property); id.advance = p_advance; - //dialog insert + // Dialog insert. _query_insert(id); inserted = true; } } + commit_insert_queue(); if (!inserted) { InsertData id; @@ -3753,13 +3845,13 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari id.type = Animation::TYPE_VALUE; id.query = vformat(TTR("property '%s'"), p_property); id.advance = p_advance; - //dialog insert + // Dialog insert. _query_insert(id); } } Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() { - AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player(); + AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player(); if (player->has_animation("RESET")) { return player->get_animation("RESET"); } else { @@ -3767,9 +3859,9 @@ Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() { reset_anim.instantiate(); 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_do_method(AnimationPlayerEditor::get_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); + undo_redo->add_undo_method(AnimationPlayerEditor::get_singleton(), "_animation_player_changed", player); return reset_anim; } } @@ -3936,7 +4028,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD animation->add_track(p_id.type); animation->track_set_path(animation->get_track_count() - 1, p_id.path); PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np); - animation->remove_track(animation->get_track_count() - 1); //hack + animation->remove_track(animation->get_track_count() - 1); // Hack. if (h.type == Variant::FLOAT || h.type == Variant::VECTOR2 || @@ -3973,18 +4065,14 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD Variant value; switch (p_id.type) { + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: + case Animation::TYPE_BLEND_SHAPE: case Animation::TYPE_VALUE: { value = p_id.value; } break; - case Animation::TYPE_TRANSFORM3D: { - Transform3D tr = p_id.value; - Dictionary d; - d["location"] = tr.origin; - d["scale"] = tr.basis.get_scale(); - d["rotation"] = Quaternion(tr.basis); - value = d; - } break; case Animation::TYPE_BEZIER: { Array array; array.resize(5); @@ -4085,7 +4173,7 @@ void AnimationTrackEditor::_update_tracks() { for (int i = 0; i < animation->get_track_count(); i++) { AnimationTrackEdit *track_edit = nullptr; - //find hint and info for plugin + // Find hint and info for plugin. if (use_filter) { NodePath path = animation->track_get_path(i); @@ -4093,10 +4181,10 @@ void AnimationTrackEditor::_update_tracks() { if (root && root->has_node(path)) { Node *node = root->get_node(path); if (!node) { - continue; // no node, no filter + continue; // No node, no filter. } if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) { - continue; //skip track due to not selected + continue; // Skip track due to not selected. } } } @@ -4158,7 +4246,7 @@ void AnimationTrackEditor::_update_tracks() { } if (track_edit == nullptr) { - //no valid plugin_found + // No valid plugin_found. track_edit = memnew(AnimationTrackEdit); } @@ -4233,11 +4321,11 @@ void AnimationTrackEditor::_update_tracks() { void AnimationTrackEditor::_animation_changed() { if (animation_changing_awaiting_update) { - return; //all will be updated, don't bother with anything + return; // All will be updated, don't bother with anything. } if (key_edit && key_edit->setting) { - //if editing a key, just update the edited track, makes refresh less costly + // If editing a key, just update the edited track, makes refresh less costly. if (key_edit->track < track_edits.size()) { if (animation->track_get_type(key_edit->track) == Animation::TYPE_BEZIER) { bezier_edit->update(); @@ -4291,7 +4379,7 @@ void AnimationTrackEditor::_animation_update() { } if (track_edits.size() == animation->get_track_count()) { - //check tracks are the same + // Check tracks are the same. for (int i = 0; i < track_edits.size(); i++) { if (track_edits[i]->get_path() != animation->track_get_path(i)) { @@ -4400,8 +4488,13 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { ERR_FAIL_COND(!node); NodePath path_to = root->get_path_to(node); - if (adding_track_type == Animation::TYPE_TRANSFORM3D && !node->is_class("Node3D")) { - EditorNode::get_singleton()->show_warning(TTR("Transform3D tracks only apply to 3D-based nodes.")); + if (adding_track_type == Animation::TYPE_BLEND_SHAPE && !node->is_class("MeshInstance3D")) { + EditorNode::get_singleton()->show_warning(TTR("Blend Shape tracks only apply to MeshInstance3D nodes.")); + return; + } + + if ((adding_track_type == Animation::TYPE_POSITION_3D || adding_track_type == Animation::TYPE_ROTATION_3D || adding_track_type == Animation::TYPE_SCALE_3D) && !node->is_class("Node3D")) { + EditorNode::get_singleton()->show_warning(TTR("Position/Rotation/Scale 3D tracks only apply to 3D-based nodes.")); return; } @@ -4411,7 +4504,16 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { prop_selector->set_type_filter(Vector<Variant::Type>()); prop_selector->select_property_from_instance(node); } break; - case Animation::TYPE_TRANSFORM3D: + case Animation::TYPE_BLEND_SHAPE: { + adding_track_path = path_to; + Vector<Variant::Type> filter; + filter.push_back(Variant::FLOAT); + prop_selector->set_type_filter(filter); + prop_selector->select_property_from_instance(node); + } break; + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: case Animation::TYPE_METHOD: { undo_redo->create_action(TTR("Add Track")); undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type); @@ -4453,7 +4555,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { return; } - if (node == AnimationPlayerEditor::singleton->get_player()) { + if (node == AnimationPlayerEditor::get_singleton()->get_player()) { EditorNode::get_singleton()->show_warning(TTR("AnimationPlayer can't animate itself, only other players.")); return; } @@ -4485,12 +4587,12 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) { if (adding_track_type == Animation::TYPE_VALUE) { Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE; { - //hack + // Hack. NodePath np; animation->add_track(Animation::TYPE_VALUE); animation->track_set_path(animation->get_track_count() - 1, full_path); PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np); - animation->remove_track(animation->get_track_count() - 1); //hack + animation->remove_track(animation->get_track_count() - 1); // Hack. if (h.type == Variant::FLOAT || h.type == Variant::VECTOR2 || h.type == Variant::RECT2 || @@ -4518,12 +4620,12 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) { } else { Vector<String> subindices; { - //hack + // Hack. NodePath np; animation->add_track(Animation::TYPE_VALUE); animation->track_set_path(animation->get_track_count() - 1, full_path); PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np); - animation->remove_track(animation->get_track_count() - 1); //hack + animation->remove_track(animation->get_track_count() - 1); // Hack. bool valid; subindices = _get_bezier_subindices_for_type(h.type, &valid); if (!valid) { @@ -4575,12 +4677,32 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { if (snap->is_pressed() && step->get_value() != 0) { p_ofs = snap_time(p_ofs); } - while (animation->track_find_key(p_track, p_ofs, true) != -1) { //make sure insertion point is valid + while (animation->track_find_key(p_track, p_ofs, true) != -1) { // Make sure insertion point is valid. p_ofs += 0.001; } switch (animation->track_get_type(p_track)) { - case Animation::TYPE_TRANSFORM3D: { + case Animation::TYPE_POSITION_3D: { + if (!root->has_node(animation->track_get_path(p_track))) { + EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a key.")); + return; + } + Node3D *base = Object::cast_to<Node3D>(root->get_node(animation->track_get_path(p_track))); + + if (!base) { + EditorNode::get_singleton()->show_warning(TTR("Track is not of type Node3D, can't insert key")); + return; + } + + Vector3 pos = base->get_position(); + + undo_redo->create_action(TTR("Add Position Key")); + undo_redo->add_do_method(animation.ptr(), "position_track_insert_key", p_track, p_ofs, pos); + undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs); + undo_redo->commit_action(); + + } break; + case Animation::TYPE_ROTATION_3D: { if (!root->has_node(animation->track_get_path(p_track))) { EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a key.")); return; @@ -4592,18 +4714,35 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { return; } - Transform3D xf = base->get_transform(); + Quaternion rot = base->get_transform().basis.operator Quaternion(); + + undo_redo->create_action(TTR("Add Rotation Key")); + undo_redo->add_do_method(animation.ptr(), "rotation_track_insert_key", p_track, p_ofs, rot); + undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs); + undo_redo->commit_action(); + + } break; + case Animation::TYPE_SCALE_3D: { + if (!root->has_node(animation->track_get_path(p_track))) { + EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a key.")); + return; + } + Node3D *base = Object::cast_to<Node3D>(root->get_node(animation->track_get_path(p_track))); + + if (!base) { + EditorNode::get_singleton()->show_warning(TTR("Track is not of type Node3D, can't insert key")); + return; + } - Vector3 loc = xf.get_origin(); - Vector3 scale = xf.basis.get_scale_local(); - Quaternion rot = xf.basis; + Vector3 scale = base->get_scale(); - undo_redo->create_action(TTR("Add Transform Track Key")); - undo_redo->add_do_method(animation.ptr(), "transform_track_insert_key", p_track, p_ofs, loc, rot, scale); + undo_redo->create_action(TTR("Add Scale Key")); + undo_redo->add_do_method(animation.ptr(), "scale_track_insert_key", p_track, p_ofs, scale); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs); undo_redo->commit_action(); } break; + case Animation::TYPE_BLEND_SHAPE: case Animation::TYPE_VALUE: { NodePath bp; Variant value; @@ -4770,16 +4909,16 @@ struct _AnimMoveRestore { Variant key; float transition = 0; }; -//used for undo/redo +// Used for undo/redo. void AnimationTrackEditor::_clear_key_edit() { if (key_edit) { - //if key edit is the object being inspected, remove it first + // If key edit is the object being inspected, remove it first. if (EditorNode::get_singleton()->get_inspector()->get_edited_object() == key_edit) { EditorNode::get_singleton()->push_item(nullptr); } - //then actually delete it + // Then actually delete it. memdelete(key_edit); key_edit = nullptr; } @@ -4835,8 +4974,8 @@ void AnimationTrackEditor::_update_key_edit() { Map<int, List<float>> key_ofs_map; Map<int, NodePath> base_map; int first_track = -1; - for (Map<SelectedKey, KeyInfo>::Element *E = selection.front(); E; E = E->next()) { - int track = E->key().track; + for (const KeyValue<SelectedKey, KeyInfo> &E : selection) { + int track = E.key.track; if (first_track < 0) { first_track = track; } @@ -4846,7 +4985,7 @@ void AnimationTrackEditor::_update_key_edit() { base_map[track] = NodePath(); } - key_ofs_map[track].push_back(animation->track_get_key_time(track, E->key().key)); + key_ofs_map[track].push_back(animation->track_get_key_time(track, E.key.key)); } multi_key_edit->key_ofs_map = key_ofs_map; multi_key_edit->base_map = base_map; @@ -4893,11 +5032,11 @@ void AnimationTrackEditor::_move_selection_commit() { List<_AnimMoveRestore> to_restore; float motion = moving_selection_offset; - // 1 - remove the keys + // 1 - remove the keys. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key); } - // 2 - remove overlapped keys + // 2 - Remove overlapped keys. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { float newtime = snap_time(E->get().pos + motion); int idx = animation->track_find_key(E->key().track, newtime, true); @@ -4908,7 +5047,7 @@ void AnimationTrackEditor::_move_selection_commit() { sk.key = idx; sk.track = E->key().track; if (selection.has(sk)) { - continue; //already in selection, don't save + continue; // Already in selection, don't save. } undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newtime); @@ -4922,24 +5061,24 @@ void AnimationTrackEditor::_move_selection_commit() { to_restore.push_back(amr); } - // 3 - move the keys (re insert them) + // 3 - Move the keys (Reinsert them). for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { float newpos = snap_time(E->get().pos + motion); undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key)); } - // 4 - (undo) remove inserted keys + // 4 - (Undo) Remove inserted keys. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { float newpos = snap_time(E->get().pos + motion); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos); } - // 5 - (undo) reinsert keys + // 5 - (Undo) Reinsert keys. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key)); } - // 6 - (undo) reinsert overlapped keys + // 6 - (Undo) Reinsert overlapped keys. for (_AnimMoveRestore &amr : to_restore) { undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, amr.transition); } @@ -4947,7 +5086,7 @@ void AnimationTrackEditor::_move_selection_commit() { undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); - // 7 - reselect + // 7 - Reselect. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { float oldpos = E->get().pos; float newpos = snap_time(oldpos + motion); @@ -5017,18 +5156,18 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) { box_select_rect = Rect2(); } else if (box_selecting) { if (box_selection->is_visible_in_tree()) { - //only if moved + // Only if moved. for (int i = 0; i < track_edits.size(); i++) { Rect2 local_rect = box_select_rect; local_rect.position -= track_edits[i]->get_global_position(); track_edits[i]->append_to_selection(local_rect, mb->is_command_pressed()); } - if (_get_track_selected() == -1 && track_edits.size() > 0) { //minimal hack to make shortcuts work + if (_get_track_selected() == -1 && track_edits.size() > 0) { // Minimal hack to make shortcuts work. track_edits[track_edits.size() - 1]->grab_focus(); } } else { - _clear_selection(); //clear it + _clear_selection(); // Clear it. } box_selection->hide(); @@ -5044,7 +5183,7 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) { if (mm.is_valid() && box_selecting) { if (!(mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT)) { - //no longer + // No longer. box_selection->hide(); box_selecting = false; return; @@ -5084,16 +5223,16 @@ void AnimationTrackEditor::_cancel_bezier_edit() { } void AnimationTrackEditor::_bezier_edit(int p_for_track) { - _clear_selection(); //bezier probably wants to use a separate selection mode + _clear_selection(); // Bezier probably wants to use a separate selection mode. bezier_edit->set_root(root); bezier_edit->set_animation_and_track(animation, p_for_track); scroll->hide(); bezier_edit->show(); - //search everything within the track and curve- edit it + // Search everything within the track and curve - edit it. } void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) { - //duplicait! + // Duplicait! if (selection.size() && animation.is_valid() && (!transpose || (_get_track_selected() >= 0 && _get_track_selected() < animation->get_track_count()))) { int top_track = 0x7FFFFFFF; float top_time = 1e10; @@ -5151,7 +5290,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) { undo_redo->commit_action(); - //reselect duplicated + // Reselect duplicated. Map<SelectedKey, KeyInfo> new_selection; for (const Pair<int, float> &E : new_selection_values) { @@ -5180,7 +5319,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) { } void AnimationTrackEditor::_edit_menu_about_to_popup() { - AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player(); + AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player(); edit->get_popup()->set_item_disabled(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), !player->can_apply_reset()); } @@ -5263,7 +5402,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { text += sn[j]; } - path = NodePath(node->get_path().get_names(), path.get_subnames(), true); //store full path instead for copying + path = NodePath(node->get_path().get_names(), path.get_subnames(), true); // Store full path instead for copying. } else { text = path; int sep = text.find(":"); @@ -5273,8 +5412,17 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } switch (animation->track_get_type(i)) { - case Animation::TYPE_TRANSFORM3D: - text += " (Transform)"; + case Animation::TYPE_POSITION_3D: + text += " (Position)"; + break; + case Animation::TYPE_ROTATION_3D: + text += " (Rotation)"; + break; + case Animation::TYPE_SCALE_3D: + text += " (Scale)"; + break; + case Animation::TYPE_BLEND_SHAPE: + text += " (BlendShape)"; break; case Animation::TYPE_METHOD: text += " (Methods)"; @@ -5390,8 +5538,8 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { float len = -1e20; float pivot = 0; - for (Map<SelectedKey, KeyInfo>::Element *E = selection.front(); E; E = E->next()) { - float t = animation->track_get_key_time(E->key().track, E->key().key); + for (const KeyValue<SelectedKey, KeyInfo> &E : selection) { + float t = animation->track_get_key_time(E.key.track, E.key.key); if (t < from_t) { from_t = t; } @@ -5417,11 +5565,11 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { List<_AnimMoveRestore> to_restore; - // 1-remove the keys + // 1 - Remove the keys. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key); } - // 2- remove overlapped keys + // 2 - Remove overlapped keys. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { float newtime = (E->get().pos - from_t) * s + from_t; int idx = animation->track_find_key(E->key().track, newtime, true); @@ -5432,7 +5580,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { sk.key = idx; sk.track = E->key().track; if (selection.has(sk)) { - continue; //already in selection, don't save + continue; // Already in selection, don't save. } undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newtime); @@ -5447,24 +5595,24 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } #define _NEW_POS(m_ofs) (((s > 0) ? m_ofs : from_t + (len - (m_ofs - from_t))) - pivot) * ABS(s) + from_t - // 3-move the keys (re insert them) + // 3 - Move the keys (re insert them). for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { float newpos = _NEW_POS(E->get().pos); undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key)); } - // 4-(undo) remove inserted keys + // 4 - (Undo) Remove inserted keys. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { float newpos = _NEW_POS(E->get().pos); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos); } - // 5-(undo) reinsert keys + // 5 - (Undo) Reinsert keys. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key)); } - // 6-(undo) reinsert overlapped keys + // 6 - (Undo) Reinsert overlapped keys. for (_AnimMoveRestore &amr : to_restore) { undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, amr.transition); } @@ -5472,7 +5620,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); - // 7-reselect + // 7-reselect. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { float oldpos = E->get().pos; float newpos = _NEW_POS(oldpos); @@ -5524,7 +5672,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { goto_prev_step(false); } break; case EDIT_APPLY_RESET: { - AnimationPlayerEditor::singleton->get_player()->apply_reset(true); + AnimationPlayerEditor::get_singleton()->get_player()->apply_reset(true); } break; case EDIT_OPTIMIZE_ANIMATION: { @@ -5544,9 +5692,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { case EDIT_CLEAN_UP_ANIMATION_CONFIRM: { if (cleanup_all->is_pressed()) { List<StringName> names; - AnimationPlayerEditor::singleton->get_player()->get_animation_list(&names); + AnimationPlayerEditor::get_singleton()->get_player()->get_animation_list(&names); for (const StringName &E : names) { - _cleanup_animation(AnimationPlayerEditor::singleton->get_player()->get_animation(E)); + _cleanup_animation(AnimationPlayerEditor::get_singleton()->get_player()->get_animation(E)); } } else { _cleanup_animation(animation); @@ -5621,7 +5769,7 @@ bool AnimationTrackEditor::is_grouping_tracks() { void AnimationTrackEditor::_selection_changed() { if (selected_filter->is_pressed()) { - _update_tracks(); //needs updatin + _update_tracks(); // Needs updatin. } else { for (int i = 0; i < track_edits.size(); i++) { track_edits[i]->update(); @@ -5690,7 +5838,6 @@ void AnimationTrackEditor::_bind_methods() { ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update); ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus); ClassDB::bind_method("_update_tracks", &AnimationTrackEditor::_update_tracks); - ClassDB::bind_method("_insert_delay", &AnimationTrackEditor::_insert_delay); ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim); ClassDB::bind_method("_select_at_anim", &AnimationTrackEditor::_select_at_anim); @@ -5761,7 +5908,7 @@ void AnimationTrackEditor::_pick_track_filter_input(const Ref<InputEvent> &p_ie) case KEY_DOWN: case KEY_PAGEUP: case KEY_PAGEDOWN: { - pick_track->get_scene_tree()->get_scene_tree()->call("_gui_input", k); + pick_track->get_scene_tree()->get_scene_tree()->gui_input(k); pick_track->get_filter_line_edit()->accept_event(); } break; default: @@ -5776,7 +5923,7 @@ AnimationTrackEditor::AnimationTrackEditor() { undo_redo = EditorNode::get_singleton()->get_undo_redo(); main_panel = memnew(PanelContainer); - main_panel->set_focus_mode(FOCUS_ALL); // allow panel to have focus so that shortcuts work as expected. + main_panel->set_focus_mode(FOCUS_ALL); // Allow panel to have focus so that shortcuts work as expected. add_child(main_panel); main_panel->set_v_size_flags(SIZE_EXPAND_FILL); HBoxContainer *timeline_scroll = memnew(HBoxContainer); @@ -5812,7 +5959,7 @@ AnimationTrackEditor::AnimationTrackEditor() { scroll->set_v_size_flags(SIZE_EXPAND_FILL); VScrollBar *sb = scroll->get_v_scrollbar(); scroll->remove_child(sb); - timeline_scroll->add_child(sb); //move here so timeline and tracks are always aligned + timeline_scroll->add_child(sb); // Move here so timeline and tracks are always aligned. scroll->connect("gui_input", callable_mp(this, &AnimationTrackEditor::_scroll_input)); bezier_edit = memnew(AnimationBezierTrackEdit); @@ -5853,7 +6000,7 @@ AnimationTrackEditor::AnimationTrackEditor() { selected_filter = memnew(Button); selected_filter->set_flat(true); - selected_filter->connect("pressed", callable_mp(this, &AnimationTrackEditor::_view_group_toggle)); //same function works the same + selected_filter->connect("pressed", callable_mp(this, &AnimationTrackEditor::_view_group_toggle)); // Same function works the same. selected_filter->set_toggle_mode(true); selected_filter->set_tooltip(TTR("Only show tracks from nodes selected in tree.")); @@ -5954,9 +6101,6 @@ AnimationTrackEditor::AnimationTrackEditor() { add_child(method_selector); method_selector->connect("selected", callable_mp(this, &AnimationTrackEditor::_add_method_key)); - inserting = false; - insert_query = false; - insert_frame = 0; insert_queue = false; insert_confirm = memnew(ConfirmationDialog); @@ -5989,13 +6133,13 @@ AnimationTrackEditor::AnimationTrackEditor() { box_selection->connect("draw", callable_mp(this, &AnimationTrackEditor::_box_selection_draw)); box_selecting = false; - //default plugins + // Default Plugins. Ref<AnimationTrackEditDefaultPlugin> def_plugin; def_plugin.instantiate(); add_track_edit_plugin(def_plugin); - //dialogs + // Dialogs. optimize_dialog = memnew(ConfirmationDialog); add_child(optimize_dialog); |