Add FPS compatible option in second mode of animation editor snapping

This commit is contained in:
Silc Lizard (Tokage) Renew 2024-11-10 14:15:24 +09:00
parent e65a23762b
commit 64d04c375c
4 changed files with 66 additions and 10 deletions

View File

@ -63,7 +63,6 @@
constexpr double FPS_DECIMAL = 1.0; constexpr double FPS_DECIMAL = 1.0;
constexpr double SECOND_DECIMAL = 0.0001; constexpr double SECOND_DECIMAL = 0.0001;
constexpr double FPS_STEP_FRACTION = 0.0625;
void AnimationTrackKeyEdit::_bind_methods() { void AnimationTrackKeyEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj); ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj);
@ -3776,6 +3775,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re
step->set_read_only(false); step->set_read_only(false);
snap_keys->set_disabled(false); snap_keys->set_disabled(false);
snap_timeline->set_disabled(false); snap_timeline->set_disabled(false);
fps_compat->set_disabled(false);
snap_mode->set_disabled(false); snap_mode->set_disabled(false);
auto_fit->set_disabled(false); auto_fit->set_disabled(false);
auto_fit_bezier->set_disabled(false); auto_fit_bezier->set_disabled(false);
@ -3798,6 +3798,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re
step->set_read_only(true); step->set_read_only(true);
snap_keys->set_disabled(true); snap_keys->set_disabled(true);
snap_timeline->set_disabled(true); snap_timeline->set_disabled(true);
fps_compat->set_disabled(true);
snap_mode->set_disabled(true); snap_mode->set_disabled(true);
bezier_edit_icon->set_disabled(true); bezier_edit_icon->set_disabled(true);
auto_fit->set_disabled(true); auto_fit->set_disabled(true);
@ -5029,7 +5030,12 @@ void AnimationTrackEditor::_snap_mode_changed(int p_mode) {
} }
marker_edit->set_use_fps(use_fps); marker_edit->set_use_fps(use_fps);
// To ensure that the conversion results are consistent between serialization and load, the value is snapped with 0.0625 to be a rational number when FPS mode is used. // To ensure that the conversion results are consistent between serialization and load, the value is snapped with 0.0625 to be a rational number when FPS mode is used.
step->set_step(use_fps ? FPS_STEP_FRACTION : SECOND_DECIMAL); step->set_step(use_fps ? FPS_DECIMAL : SECOND_DECIMAL);
if (use_fps) {
fps_compat->hide();
} else {
fps_compat->show();
}
_update_step_spinbox(); _update_step_spinbox();
} }
@ -5045,7 +5051,6 @@ void AnimationTrackEditor::_update_step_spinbox() {
} else { } else {
step->set_value(1.0 / animation->get_step()); step->set_value(1.0 / animation->get_step());
} }
} else { } else {
step->set_value(animation->get_step()); step->set_value(animation->get_step());
} }
@ -5054,6 +5059,20 @@ void AnimationTrackEditor::_update_step_spinbox() {
_update_snap_unit(); _update_snap_unit();
} }
void AnimationTrackEditor::_update_fps_compat_mode(bool p_enabled) {
_update_snap_unit();
}
void AnimationTrackEditor::_update_nearest_fps_label() {
bool is_fps_invalid = nearest_fps == 0;
if (is_fps_invalid) {
nearest_fps_label->hide();
} else {
nearest_fps_label->show();
nearest_fps_label->set_text("Nearest FPS: " + itos(nearest_fps));
}
}
void AnimationTrackEditor::_animation_update() { void AnimationTrackEditor::_animation_update() {
timeline->queue_redraw(); timeline->queue_redraw();
timeline->update_values(); timeline->update_values();
@ -5115,6 +5134,7 @@ void AnimationTrackEditor::_notification(int p_what) {
bezier_edit_icon->set_button_icon(get_editor_theme_icon(SNAME("EditBezier"))); bezier_edit_icon->set_button_icon(get_editor_theme_icon(SNAME("EditBezier")));
snap_timeline->set_button_icon(get_editor_theme_icon(SNAME("SnapTimeline"))); snap_timeline->set_button_icon(get_editor_theme_icon(SNAME("SnapTimeline")));
snap_keys->set_button_icon(get_editor_theme_icon(SNAME("SnapKeys"))); snap_keys->set_button_icon(get_editor_theme_icon(SNAME("SnapKeys")));
fps_compat->set_button_icon(get_editor_theme_icon(SNAME("FPS")));
view_group->set_button_icon(get_editor_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup"))); view_group->set_button_icon(get_editor_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup")));
selected_filter->set_button_icon(get_editor_theme_icon(SNAME("AnimationFilter"))); selected_filter->set_button_icon(get_editor_theme_icon(SNAME("AnimationFilter")));
imported_anim_warning->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning"))); imported_anim_warning->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
@ -5160,9 +5180,8 @@ void AnimationTrackEditor::_update_step(double p_new_step) {
double step_value = p_new_step; double step_value = p_new_step;
if (timeline->is_using_fps()) { if (timeline->is_using_fps()) {
if (step_value != 0.0) { if (step_value != 0.0) {
// step_value must also be less than or equal to 1000 to ensure that no error accumulates due to interactions with retrieving values from inner range. // A step_value should be less than or equal to 1000 to ensure that no error accumulates due to interactions with retrieving values from inner range.
step_value = 1.0 / MIN(1000.0, p_new_step); step_value = 1.0 / MIN(1000.0, p_new_step);
;
} }
timeline->queue_redraw(); timeline->queue_redraw();
} }
@ -7314,19 +7333,30 @@ void AnimationTrackEditor::_selection_changed() {
} }
void AnimationTrackEditor::_update_snap_unit() { void AnimationTrackEditor::_update_snap_unit() {
nearest_fps = 0;
if (step->get_value() <= 0) { if (step->get_value() <= 0) {
snap_unit = 0; snap_unit = 0;
_update_nearest_fps_label();
return; // Avoid zero div. return; // Avoid zero div.
} }
if (timeline->is_using_fps()) { if (timeline->is_using_fps()) {
_clear_selection(true); // Needs to recreate a spinbox of the KeyEdit.
snap_unit = 1.0 / step->get_value(); snap_unit = 1.0 / step->get_value();
} else { } else {
double integer; if (fps_compat->is_pressed()) {
double fraction = Math::modf(step->get_value(), &integer); snap_unit = CLAMP(step->get_value(), 0.0, 1.0);
fraction = 1.0 / Math::round(1.0 / fraction); if (!Math::is_zero_approx(snap_unit)) {
snap_unit = integer + fraction; real_t fps = Math::round(1.0 / snap_unit);
nearest_fps = int(fps);
snap_unit = 1.0 / fps;
}
} else {
snap_unit = step->get_value();
}
} }
_update_nearest_fps_label();
} }
float AnimationTrackEditor::snap_time(float p_value, bool p_relative) { float AnimationTrackEditor::snap_time(float p_value, bool p_relative) {
@ -7347,6 +7377,10 @@ float AnimationTrackEditor::snap_time(float p_value, bool p_relative) {
return p_value; return p_value;
} }
float AnimationTrackEditor::get_snap_unit() {
return snap_unit;
}
void AnimationTrackEditor::_show_imported_anim_warning() { void AnimationTrackEditor::_show_imported_anim_warning() {
// It looks terrible on a single line but the TTR extractor doesn't support line breaks yet. // It looks terrible on a single line but the TTR extractor doesn't support line breaks yet.
EditorNode::get_singleton()->show_warning( EditorNode::get_singleton()->show_warning(
@ -7600,6 +7634,18 @@ AnimationTrackEditor::AnimationTrackEditor() {
snap_keys->set_pressed(true); snap_keys->set_pressed(true);
snap_keys->set_tooltip_text(TTR("Apply snapping to selected key(s).")); snap_keys->set_tooltip_text(TTR("Apply snapping to selected key(s)."));
fps_compat = memnew(Button);
fps_compat->set_flat(true);
bottom_hb->add_child(fps_compat);
fps_compat->set_disabled(true);
fps_compat->set_toggle_mode(true);
fps_compat->set_pressed(true);
fps_compat->set_tooltip_text(TTR("Apply snapping to the nearest integer FPS."));
fps_compat->connect(SceneStringName(toggled), callable_mp(this, &AnimationTrackEditor::_update_fps_compat_mode));
nearest_fps_label = memnew(Label);
bottom_hb->add_child(nearest_fps_label);
step = memnew(EditorSpinSlider); step = memnew(EditorSpinSlider);
step->set_min(0); step->set_min(0);
step->set_max(1000000); step->set_max(1000000);

View File

@ -600,6 +600,8 @@ class AnimationTrackEditor : public VBoxContainer {
AnimationMarkerEdit *marker_edit = nullptr; AnimationMarkerEdit *marker_edit = nullptr;
HSlider *zoom = nullptr; HSlider *zoom = nullptr;
EditorSpinSlider *step = nullptr; EditorSpinSlider *step = nullptr;
Button *fps_compat = nullptr;
Label *nearest_fps_label = nullptr;
TextureRect *zoom_icon = nullptr; TextureRect *zoom_icon = nullptr;
Button *snap_keys = nullptr; Button *snap_keys = nullptr;
Button *snap_timeline = nullptr; Button *snap_timeline = nullptr;
@ -637,6 +639,8 @@ class AnimationTrackEditor : public VBoxContainer {
void _track_grab_focus(int p_track); void _track_grab_focus(int p_track);
void _update_scroll(double); void _update_scroll(double);
void _update_nearest_fps_label();
void _update_fps_compat_mode(bool p_enabled);
void _update_step(double p_new_step); void _update_step(double p_new_step);
void _update_length(double p_new_len); void _update_length(double p_new_len);
void _dropped_track(int p_from_track, int p_to_track); void _dropped_track(int p_from_track, int p_to_track);
@ -853,6 +857,8 @@ class AnimationTrackEditor : public VBoxContainer {
void _pick_track_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates); void _pick_track_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates);
double snap_unit; double snap_unit;
bool fps_compatible = true;
int nearest_fps = 0;
void _update_snap_unit(); void _update_snap_unit();
protected: protected:
@ -935,6 +941,7 @@ public:
bool can_add_reset_key() const; bool can_add_reset_key() const;
float get_moving_selection_offset() const; float get_moving_selection_offset() const;
float snap_time(float p_value, bool p_relative = false); float snap_time(float p_value, bool p_relative = false);
float get_snap_unit();
bool is_grouping_tracks(); bool is_grouping_tracks();
PackedStringArray get_selected_section() const; PackedStringArray get_selected_section() const;
bool is_marker_selected(const StringName &p_marker) const; bool is_marker_selected(const StringName &p_marker) const;

1
editor/icons/FPS.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M7.25 4h-2v8h2v-2c1.656 0 3-1.344 3-3 0-1.657-1.344-3-3-3zm0 4v-2c.553 0 1 .448 1 1s-.447 1-1 1zM.25 7v5h2v-2h2v-2h-2v-1c0-.553.447-1 1-1h1v-2h-1c-1.656 0-3 1.344-3 3zM13.25 7c-.276 0-.5-.224-.5-.5s.224-.5.5-.5h2v-2h-2c-1.381 0-2.5 1.119-2.5 2.5s1.119 2.5 2.5 2.5c.276 0 .5.224.5.5s-.224.5-.5.5h-2v2h2c1.381 0 2.5-1.119 2.5-2.5s-1.119-2.5-2.5-2.5z"/></svg>

After

Width:  |  Height:  |  Size: 443 B

View File

@ -580,8 +580,10 @@ float AnimationPlayerEditor::_get_editor_step() const {
const Ref<Animation> anim = player->get_animation(current); const Ref<Animation> anim = player->get_animation(current);
ERR_FAIL_COND_V(anim.is_null(), 0.0); ERR_FAIL_COND_V(anim.is_null(), 0.0);
float step = track_editor->get_snap_unit();
// Use more precise snapping when holding Shift // Use more precise snapping when holding Shift
return Input::get_singleton()->is_key_pressed(Key::SHIFT) ? anim->get_step() * 0.25 : anim->get_step(); return Input::get_singleton()->is_key_pressed(Key::SHIFT) ? step * 0.25 : step;
} }
void AnimationPlayerEditor::_animation_name_edited() { void AnimationPlayerEditor::_animation_name_edited() {