Skip to content

Commit

Permalink
Merge branch 'animation-autofit' into 4.3-dev-custom
Browse files Browse the repository at this point in the history
  • Loading branch information
Hilderin committed Jan 21, 2024
2 parents 167ef27 + 0e06b1c commit eb38890
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 32 deletions.
121 changes: 90 additions & 31 deletions editor/animation_bezier_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,23 +264,11 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
RBMap<String, Vector<int>> track_indices;
int track_count = animation->get_track_count();
for (int i = 0; i < track_count; ++i) {
if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER) {
if (!_is_track_displayed(i)) {
continue;
}

String base_path = animation->track_get_path(i);
if (is_filtered) {
if (root && root->has_node(base_path)) {
Node *node = root->get_node(base_path);
if (!node) {
continue; // No node, no filter.
}
if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
continue; // Skip track due to not selected.
}
}
}

int end = base_path.find(":");
if (end != -1) {
base_path = base_path.substr(0, end + 1);
Expand Down Expand Up @@ -518,28 +506,11 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
float scale = timeline->get_zoom_scale();

for (int i = 0; i < track_count; ++i) {
if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER || hidden_tracks.has(i)) {
continue;
}

if (hidden_tracks.has(i) || locked_tracks.has(i)) {
if (!_is_track_curves_displayed(i) || locked_tracks.has(i)) {
continue;
}

int key_count = animation->track_get_key_count(i);
String path = animation->track_get_path(i);

if (is_filtered) {
if (root && root->has_node(path)) {
Node *node = root->get_node(path);
if (!node) {
continue; // No node, no filter.
}
if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
continue; // Skip track due to not selected.
}
}
}

for (int j = 0; j < key_count; ++j) {
float offset = animation->track_get_key_time(i, j);
Expand Down Expand Up @@ -646,6 +617,43 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
}
}

// Check if a track is displayed in the bezier editor (track type = bezier and track not filtered).
bool AnimationBezierTrackEdit::_is_track_displayed(int p_track_index) {
if (animation->track_get_type(p_track_index) != Animation::TrackType::TYPE_BEZIER) {
return false;
}

if (is_filtered) {
String path = animation->track_get_path(p_track_index);
if (root && root->has_node(path)) {
Node *node = root->get_node(path);
if (!node) {
return false; // No node, no filter.
}
if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
return false; // Skip track due to not selected.
}
}
}

return true;
}

// Check if the curves for a track are displayed in the editor (not hidden). Includes the check on the track visibility.
bool AnimationBezierTrackEdit::_is_track_curves_displayed(int p_track_index) {
//Is the track is visible in the editor?
if (!_is_track_displayed(p_track_index)) {
return false;
}

//And curves visible?
if (hidden_tracks.has(p_track_index)) {
return false;
}

return true;
}

Ref<Animation> AnimationBezierTrackEdit::get_animation() const {
return animation;
}
Expand Down Expand Up @@ -739,6 +747,57 @@ void AnimationBezierTrackEdit::set_filtered(bool p_filtered) {
queue_redraw();
}

void AnimationBezierTrackEdit::auto_fit_vertically() {
timeline_v_zoom = 0;
timeline_v_scroll = 0;

int track_count = animation->get_track_count();
real_t minimum_value = INFINITY;
real_t maximum_value = -INFINITY;

int nb_track_visible = 0;
for (int i = 0; i < track_count; ++i) {
if (!_is_track_curves_displayed(i) || locked_tracks.has(i)) {
continue;
}

int key_count = animation->track_get_key_count(i);

for (int j = 0; j < key_count; ++j) {
real_t value = animation->bezier_track_get_key_value(i, j);

minimum_value = MIN(value, minimum_value);
maximum_value = MAX(value, maximum_value);

//We also want to includes the handles...
Vector2 in_vec = animation->bezier_track_get_key_in_handle(i, j);
Vector2 out_vec = animation->bezier_track_get_key_out_handle(i, j);

minimum_value = MIN(value + in_vec.y, minimum_value);
maximum_value = MAX(value + in_vec.y, maximum_value);
minimum_value = MIN(value + out_vec.y, minimum_value);
maximum_value = MAX(value + out_vec.y, maximum_value);
}

nb_track_visible++;
}

if (nb_track_visible == 0) {
//No visible track... we will not adjust the vertical zoom
return;
}

if (Math::is_finite(minimum_value) && Math::is_finite(maximum_value)) {
timeline_v_scroll = (maximum_value + minimum_value) / 2.0;
if (maximum_value - minimum_value > CMP_EPSILON) {
timeline_v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9);
} else {
timeline_v_zoom = CMP_EPSILON;
}
queue_redraw();
}
}

void AnimationBezierTrackEdit::_zoom_changed() {
queue_redraw();
play_position->queue_redraw();
Expand Down
3 changes: 3 additions & 0 deletions editor/animation_bezier_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ class AnimationBezierTrackEdit : public Control {
void _menu_selected(int p_index);

void _play_position_draw();
bool _is_track_displayed(int p_track_index);
bool _is_track_curves_displayed(int p_track_index);

Vector2 insert_at_pos;

Expand Down Expand Up @@ -201,6 +203,7 @@ class AnimationBezierTrackEdit : public Control {
void set_editor(AnimationTrackEditor *p_editor);
void set_root(Node *p_root);
void set_filtered(bool p_filtered);
void auto_fit_vertically();

void set_play_position(real_t p_pos);
void update_play_position();
Expand Down
77 changes: 76 additions & 1 deletion editor/animation_track_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1305,7 +1305,11 @@ void AnimationTimelineEdit::_zoom_changed(double) {
}

float AnimationTimelineEdit::get_zoom_scale() const {
float zv = zoom->get_max() - zoom->get_value();
return _get_zoom_scale(zoom->get_value());
}

float AnimationTimelineEdit::_get_zoom_scale(double p_zoom_value) const {
float zv = zoom->get_max() - p_zoom_value;
if (zv < 1) {
zv = 1.0 - zv;
return Math::pow(1.0f + zv, 8.0f) * 100;
Expand Down Expand Up @@ -1632,6 +1636,42 @@ void AnimationTimelineEdit::set_zoom(Range *p_zoom) {
zoom->connect("value_changed", callable_mp(this, &AnimationTimelineEdit::_zoom_changed));
}

void AnimationTimelineEdit::auto_fit() {
if (!animation.is_valid()) {
return;
}

float anim_length = animation->get_length();

int timeline_width_pixels = get_size().width - get_buttons_width() - get_name_limit();

//I want a little buffer at the end... (5% looks nice and we should keep some space for the bezier handles)
timeline_width_pixels *= 0.95;

//The technique is to reuse the _get_zoom_scale function directly to be sure that the auto_fit is always calculated
//the same way as the zoom slider. It's a little bit more calculation then doing the inverse of get_zoom_scale but
//it's really easier to inderstand and should always be accurate.
float new_zoom = zoom->get_max();
while (true) {
double test_zoom_scale = _get_zoom_scale(new_zoom);

if (anim_length * test_zoom_scale <= timeline_width_pixels) {
//It fits...
break;
}

new_zoom -= zoom->get_step();

if (new_zoom <= zoom->get_min()) {
new_zoom = zoom->get_min();
break;
}
}

//Set the zoom value... the signal value_changed will be emitted and the timeline will be refreshed correctly!
zoom->set_value(new_zoom);
}

void AnimationTimelineEdit::set_track_edit(AnimationTrackEdit *p_track_edit) {
track_edit = p_track_edit;
}
Expand Down Expand Up @@ -3400,6 +3440,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re
step->set_read_only(false);
snap->set_disabled(false);
snap_mode->set_disabled(false);
auto_fit->set_disabled(false);
auto_fit_bezier->set_disabled(false);

imported_anim_warning->hide();
for (int i = 0; i < animation->get_track_count(); i++) {
Expand All @@ -3420,6 +3462,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re
snap->set_disabled(true);
snap_mode->set_disabled(true);
bezier_edit_icon->set_disabled(true);
auto_fit->set_disabled(true);
auto_fit_bezier->set_disabled(true);
}
}

Expand Down Expand Up @@ -4708,6 +4752,8 @@ void AnimationTrackEditor::_notification(int p_what) {
inactive_player_warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning")));
main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_editor_theme_icon(SNAME("Reload")));
auto_fit->set_icon(get_editor_theme_icon(SNAME("AnimationAutoFit")));
auto_fit_bezier->set_icon(get_editor_theme_icon(SNAME("AnimationAutoFitBezier")));
} break;

case NOTIFICATION_READY: {
Expand Down Expand Up @@ -5560,6 +5606,8 @@ void AnimationTrackEditor::_cancel_bezier_edit() {
bezier_edit->hide();
scroll->show();
bezier_edit_icon->set_pressed(false);
auto_fit->show();
auto_fit_bezier->hide();
}

void AnimationTrackEditor::_bezier_edit(int p_for_track) {
Expand All @@ -5568,6 +5616,8 @@ void AnimationTrackEditor::_bezier_edit(int p_for_track) {
bezier_edit->set_animation_and_track(animation, p_for_track, read_only);
scroll->hide();
bezier_edit->show();
auto_fit->hide();
auto_fit_bezier->show();
// Search everything within the track and curve - edit it.
}

Expand Down Expand Up @@ -6405,6 +6455,18 @@ bool AnimationTrackEditor::is_grouping_tracks() {
return !view_group->is_pressed();
}

void AnimationTrackEditor::_auto_fit() {
timeline->auto_fit();
}

void AnimationTrackEditor::_auto_fit_bezier() {
timeline->auto_fit();

if (bezier_edit->is_visible()) {
bezier_edit->auto_fit_vertically();
}
}

void AnimationTrackEditor::_selection_changed() {
if (selected_filter->is_pressed()) {
_update_tracks(); // Needs updatin.
Expand Down Expand Up @@ -6720,6 +6782,19 @@ AnimationTrackEditor::AnimationTrackEditor() {
bottom_hb->add_child(zoom);
timeline->set_zoom(zoom);

auto_fit = memnew(Button);
auto_fit->set_flat(true);
auto_fit->connect("pressed", callable_mp(this, &AnimationTrackEditor::_auto_fit));
auto_fit->set_tooltip_text(TTR("Adjust the timeline based on the animation."));
bottom_hb->add_child(auto_fit);

auto_fit_bezier = memnew(Button);
auto_fit_bezier->set_flat(true);
auto_fit_bezier->set_visible(false);
auto_fit_bezier->connect("pressed", callable_mp(this, &AnimationTrackEditor::_auto_fit_bezier));
auto_fit_bezier->set_tooltip_text(TTR("Adjust the timeline and the scale based on the animation and visible tracks."));
bottom_hb->add_child(auto_fit_bezier);

edit = memnew(MenuButton);
edit->set_shortcut_context(this);
edit->set_text(TTR("Edit"));
Expand Down
8 changes: 8 additions & 0 deletions editor/animation_track_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ class AnimationTimelineEdit : public Range {
virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _track_added(int p_track);

float _get_zoom_scale(double p_zoom_value) const;

protected:
static void _bind_methods();
void _notification(int p_what);
Expand All @@ -196,6 +198,7 @@ class AnimationTimelineEdit : public Range {
void set_track_edit(AnimationTrackEdit *p_track_edit);
void set_zoom(Range *p_zoom);
Range *get_zoom() const { return zoom; }
void auto_fit();

void set_play_position(float p_pos);
float get_play_position() const;
Expand Down Expand Up @@ -397,6 +400,8 @@ class AnimationTrackEditor : public VBoxContainer {
Button *snap = nullptr;
Button *bezier_edit_icon = nullptr;
OptionButton *snap_mode = nullptr;
Button *auto_fit = nullptr;
Button *auto_fit_bezier = nullptr;

Button *imported_anim_warning = nullptr;
void _show_imported_anim_warning();
Expand Down Expand Up @@ -576,6 +581,9 @@ class AnimationTrackEditor : public VBoxContainer {
Button *view_group = nullptr;
Button *selected_filter = nullptr;

void _auto_fit();
void _auto_fit_bezier();

void _selection_changed();

ConfirmationDialog *track_copy_dialog = nullptr;
Expand Down
2 changes: 2 additions & 0 deletions editor/icons/AnimationAutoFit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions editor/icons/AnimationAutoFitBezier.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit eb38890

Please sign in to comment.