You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-10 13:00:37 +00:00
Add option to auto tangent new bezier points in animation editor
Co-authored-by: Mikael Hermansson <mikael@hermansson.io>
This commit is contained in:
committed by
Mikael Hermansson
parent
e45cc68092
commit
5934804335
@@ -37,6 +37,7 @@
|
||||
#include "editor/gui/editor_spin_slider.h"
|
||||
#include "editor/plugins/animation_player_editor_plugin.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "scene/gui/option_button.h"
|
||||
#include "scene/gui/view_panner.h"
|
||||
#include "scene/resources/text_line.h"
|
||||
|
||||
@@ -97,8 +98,6 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
|
||||
}
|
||||
}
|
||||
|
||||
out_handle += Vector2(offset, height);
|
||||
|
||||
float offset_n = animation->track_get_key_time(p_track, i_n);
|
||||
float height_n = animation->bezier_track_get_key_value(p_track, i_n);
|
||||
Vector2 in_handle = animation->bezier_track_get_key_in_handle(p_track, i_n);
|
||||
@@ -116,6 +115,37 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
|
||||
}
|
||||
}
|
||||
|
||||
if (moving_inserted_key && moving_selection_from_track == p_track) {
|
||||
if (moving_selection_from_key == i) {
|
||||
Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(p_track, i);
|
||||
if (handle_mode != Animation::HANDLE_MODE_FREE) {
|
||||
float offset_p = offset;
|
||||
float height_p = height;
|
||||
if (E->prev()) {
|
||||
int i_p = E->prev()->get();
|
||||
offset_p = animation->track_get_key_time(p_track, i_p);
|
||||
height_p = animation->bezier_track_get_key_value(p_track, i_p);
|
||||
}
|
||||
|
||||
animation->bezier_track_calculate_handles(offset, offset_p, height_p, offset_n, height_n, handle_mode, Animation::HANDLE_SET_MODE_AUTO, nullptr, &out_handle);
|
||||
}
|
||||
} else if (moving_selection_from_key == i_n) {
|
||||
Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(p_track, i_n);
|
||||
if (handle_mode != Animation::HANDLE_MODE_FREE) {
|
||||
float offset_nn = offset_n;
|
||||
float height_nn = height_n;
|
||||
if (E->next()->next()) {
|
||||
int i_nn = E->next()->next()->get();
|
||||
offset_nn = animation->track_get_key_time(p_track, i_nn);
|
||||
height_nn = animation->bezier_track_get_key_value(p_track, i_nn);
|
||||
}
|
||||
|
||||
animation->bezier_track_calculate_handles(offset_n, offset, height, offset_nn, height_nn, handle_mode, Animation::HANDLE_SET_MODE_AUTO, &in_handle, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out_handle += Vector2(offset, height);
|
||||
in_handle += Vector2(offset_n, height_n);
|
||||
|
||||
Vector2 start(offset, height);
|
||||
@@ -570,18 +600,53 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
||||
}
|
||||
|
||||
Vector2 in_vec = animation->bezier_track_get_key_in_handle(i, j);
|
||||
Vector2 out_vec = animation->bezier_track_get_key_out_handle(i, j);
|
||||
|
||||
if ((moving_handle == 1 || moving_handle == -1) && moving_handle_track == i && moving_handle_key == j) {
|
||||
in_vec = moving_handle_left;
|
||||
}
|
||||
Vector2 pos_in(((offset + in_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + in_vec.y));
|
||||
|
||||
Vector2 out_vec = animation->bezier_track_get_key_out_handle(i, j);
|
||||
|
||||
if ((moving_handle == 1 || moving_handle == -1) && moving_handle_track == i && moving_handle_key == j) {
|
||||
out_vec = moving_handle_right;
|
||||
}
|
||||
|
||||
if (moving_inserted_key && moving_selection_from_key == j) {
|
||||
Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(i, j);
|
||||
if (handle_mode != Animation::HANDLE_MODE_FREE) {
|
||||
int key_prev = 0;
|
||||
int key_next = moving_selection_from_key;
|
||||
for (int k = 0; k < key_count; k++) {
|
||||
if (k == moving_selection_from_key) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (animation->track_get_key_time(i, k) < offset) {
|
||||
key_prev = k;
|
||||
} else {
|
||||
key_next = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float prev_time = offset;
|
||||
float prev_value = value;
|
||||
if (key_prev != moving_selection_from_key) {
|
||||
prev_time = animation->track_get_key_time(i, key_prev);
|
||||
prev_value = animation->bezier_track_get_key_value(i, key_prev);
|
||||
}
|
||||
|
||||
float next_time = offset;
|
||||
float next_value = value;
|
||||
if (key_next != moving_selection_from_key) {
|
||||
next_time = animation->track_get_key_time(i, key_next);
|
||||
next_value = animation->bezier_track_get_key_value(i, key_next);
|
||||
}
|
||||
|
||||
animation->bezier_track_calculate_handles(offset, prev_time, prev_value, next_time, next_value, handle_mode, Animation::HANDLE_SET_MODE_AUTO, &in_vec, &out_vec);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 pos_in(((offset + in_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + in_vec.y));
|
||||
Vector2 pos_out(((offset + out_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + out_vec.y));
|
||||
|
||||
if (i == selected_track || is_selected) {
|
||||
@@ -1402,6 +1467,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Add Bezier Point"));
|
||||
undo_redo->add_do_method(animation.ptr(), "bezier_track_insert_key", selected_track, time, new_point[0], Vector2(new_point[1], new_point[2]), Vector2(new_point[3], new_point[4]));
|
||||
undo_redo->add_do_method(editor, "_bezier_track_set_key_handle_mode_at_time", animation.ptr(), selected_track, time, (Animation::HandleMode)editor->bezier_key_mode->get_selected_id(), Animation::HANDLE_SET_MODE_AUTO);
|
||||
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
|
||||
undo_redo->commit_action();
|
||||
|
||||
@@ -1412,6 +1478,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
||||
_select_at_anim(animation, selected_track, animation->track_get_key_time(selected_track, index), true);
|
||||
|
||||
moving_selection_attempt = true;
|
||||
moving_inserted_key = true;
|
||||
moving_selection = false;
|
||||
moving_selection_mouse_begin = mb->get_position();
|
||||
moving_selection_from_key = index;
|
||||
@@ -1539,6 +1606,14 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
||||
real_t h = key[0];
|
||||
h += moving_selection_offset.y;
|
||||
key[0] = h;
|
||||
|
||||
Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second);
|
||||
Animation::HandleSetMode handle_set_mode = Animation::HANDLE_SET_MODE_NONE;
|
||||
if (moving_inserted_key) {
|
||||
handle_mode = (Animation::HandleMode)editor->bezier_key_mode->get_selected_id();
|
||||
handle_set_mode = Animation::HANDLE_SET_MODE_AUTO;
|
||||
}
|
||||
|
||||
undo_redo->add_do_method(
|
||||
this,
|
||||
"_bezier_track_insert_key_at_anim",
|
||||
@@ -1548,7 +1623,8 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
||||
key[0],
|
||||
Vector2(key[1], key[2]),
|
||||
Vector2(key[3], key[4]),
|
||||
animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second));
|
||||
handle_mode,
|
||||
handle_set_mode);
|
||||
}
|
||||
|
||||
// 4 - (undo) Remove inserted keys.
|
||||
@@ -1621,6 +1697,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
||||
|
||||
moving_selection = false;
|
||||
moving_selection_attempt = false;
|
||||
moving_inserted_key = false;
|
||||
moving_selection_mouse_begin = Point2();
|
||||
queue_redraw();
|
||||
}
|
||||
@@ -2058,9 +2135,11 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
|
||||
}
|
||||
float h = (get_size().height / 2.0 - menu_insert_key.y) * timeline_v_zoom + timeline_v_scroll;
|
||||
Array new_point = animation->make_default_bezier_key(h);
|
||||
Animation::HandleMode handle_mode = (Animation::HandleMode)editor->bezier_key_mode->get_selected_id();
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Add Bezier Point"));
|
||||
undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
|
||||
undo_redo->add_do_method(editor, "_bezier_track_set_key_handle_mode_at_time", animation.ptr(), selected_track, time, handle_mode, Animation::HANDLE_SET_MODE_AUTO);
|
||||
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
|
||||
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
|
||||
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||
@@ -2343,9 +2422,9 @@ void AnimationBezierTrackEdit::delete_selection() {
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationBezierTrackEdit::_bezier_track_insert_key_at_anim(const Ref<Animation> &p_anim, int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode) {
|
||||
void AnimationBezierTrackEdit::_bezier_track_insert_key_at_anim(const Ref<Animation> &p_anim, int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode, Animation::HandleSetMode p_handle_set_mode) {
|
||||
int idx = p_anim->bezier_track_insert_key(p_track, p_time, p_value, p_in_handle, p_out_handle);
|
||||
p_anim->bezier_track_set_key_handle_mode(p_track, idx, p_handle_mode);
|
||||
p_anim->bezier_track_set_key_handle_mode(p_track, idx, p_handle_mode, p_handle_set_mode);
|
||||
}
|
||||
|
||||
void AnimationBezierTrackEdit::_bind_methods() {
|
||||
@@ -2354,7 +2433,7 @@ void AnimationBezierTrackEdit::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationBezierTrackEdit::_select_at_anim);
|
||||
ClassDB::bind_method(D_METHOD("_update_hidden_tracks_after"), &AnimationBezierTrackEdit::_update_hidden_tracks_after);
|
||||
ClassDB::bind_method(D_METHOD("_update_locked_tracks_after"), &AnimationBezierTrackEdit::_update_locked_tracks_after);
|
||||
ClassDB::bind_method(D_METHOD("_bezier_track_insert_key_at_anim"), &AnimationBezierTrackEdit::_bezier_track_insert_key_at_anim);
|
||||
ClassDB::bind_method(D_METHOD("_bezier_track_insert_key_at_anim"), &AnimationBezierTrackEdit::_bezier_track_insert_key_at_anim, DEFVAL(Animation::HANDLE_SET_MODE_NONE));
|
||||
|
||||
ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single"), PropertyInfo(Variant::INT, "track")));
|
||||
ADD_SIGNAL(MethodInfo("deselect_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::INT, "track")));
|
||||
|
||||
@@ -108,6 +108,7 @@ class AnimationBezierTrackEdit : public Control {
|
||||
typedef Pair<int, int> IntPair;
|
||||
|
||||
bool moving_selection_attempt = false;
|
||||
bool moving_inserted_key = false;
|
||||
Point2 moving_selection_mouse_begin;
|
||||
IntPair select_single_attempt;
|
||||
bool moving_selection = false;
|
||||
@@ -230,7 +231,7 @@ public:
|
||||
void paste_keys(real_t p_ofs, bool p_ofs_valid);
|
||||
void delete_selection();
|
||||
|
||||
void _bezier_track_insert_key_at_anim(const Ref<Animation> &p_anim, int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode);
|
||||
void _bezier_track_insert_key_at_anim(const Ref<Animation> &p_anim, int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode, Animation::HandleSetMode p_handle_set_mode = Animation::HANDLE_SET_MODE_NONE);
|
||||
|
||||
AnimationBezierTrackEdit();
|
||||
};
|
||||
|
||||
@@ -4880,6 +4880,9 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
|
||||
}
|
||||
|
||||
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_id.track_idx, time, value);
|
||||
if (!created && p_id.type == Animation::TYPE_BEZIER) {
|
||||
undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode_at_time", animation.ptr(), p_id.track_idx, time, (Animation::HandleMode)bezier_key_mode->get_selected_id(), Animation::HANDLE_SET_MODE_AUTO);
|
||||
}
|
||||
|
||||
if (created) {
|
||||
// Just remove the track.
|
||||
@@ -6316,12 +6319,17 @@ void AnimationTrackEditor::_bezier_edit(int p_for_track) {
|
||||
}
|
||||
|
||||
void AnimationTrackEditor::_bezier_track_set_key_handle_mode(Animation *p_anim, int p_track, int p_index, Animation::HandleMode p_mode, Animation::HandleSetMode p_set_mode) {
|
||||
if (!p_anim) {
|
||||
return;
|
||||
}
|
||||
ERR_FAIL_NULL(p_anim);
|
||||
p_anim->bezier_track_set_key_handle_mode(p_track, p_index, p_mode, p_set_mode);
|
||||
}
|
||||
|
||||
void AnimationTrackEditor::_bezier_track_set_key_handle_mode_at_time(Animation *p_anim, int p_track, float p_time, Animation::HandleMode p_mode, Animation::HandleSetMode p_set_mode) {
|
||||
ERR_FAIL_NULL(p_anim);
|
||||
int index = p_anim->track_find_key(p_track, p_time, Animation::FIND_MODE_APPROX);
|
||||
ERR_FAIL_COND(index < 0);
|
||||
_bezier_track_set_key_handle_mode(p_anim, p_track, index, p_mode, p_set_mode);
|
||||
}
|
||||
|
||||
void AnimationTrackEditor::_anim_duplicate_keys(float p_ofs, bool p_ofs_valid, int p_track) {
|
||||
if (selection.size() && animation.is_valid()) {
|
||||
int top_track = 0x7FFFFFFF;
|
||||
@@ -7699,6 +7707,7 @@ void AnimationTrackEditor::_bind_methods() {
|
||||
ClassDB::bind_method("_clear_selection", &AnimationTrackEditor::_clear_selection);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_bezier_track_set_key_handle_mode", "animation", "track_idx", "key_idx", "key_handle_mode", "key_handle_set_mode"), &AnimationTrackEditor::_bezier_track_set_key_handle_mode, DEFVAL(Animation::HANDLE_SET_MODE_NONE));
|
||||
ClassDB::bind_method(D_METHOD("_bezier_track_set_key_handle_mode_at_time", "animation", "track_idx", "time", "key_handle_mode", "key_handle_set_mode"), &AnimationTrackEditor::_bezier_track_set_key_handle_mode_at_time, DEFVAL(Animation::HANDLE_SET_MODE_NONE));
|
||||
|
||||
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "timeline_only"), PropertyInfo(Variant::BOOL, "update_position_only")));
|
||||
ADD_SIGNAL(MethodInfo("keying_changed"));
|
||||
@@ -7870,6 +7879,21 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
||||
spacer->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
bottom_hf->add_child(spacer);
|
||||
|
||||
Label *bezier_key_default_label = memnew(Label);
|
||||
bezier_key_default_label->set_text(TTR("Bezier Default Mode:"));
|
||||
bottom_hf->add_child(bezier_key_default_label);
|
||||
|
||||
bezier_key_mode = memnew(OptionButton);
|
||||
bezier_key_mode->add_item(TTR("Free"));
|
||||
bezier_key_mode->add_item(TTR("Linear"));
|
||||
bezier_key_mode->add_item(TTR("Balanced"));
|
||||
bezier_key_mode->add_item(TTR("Mirrored"));
|
||||
bezier_key_mode->set_tooltip_text(TTR("Set the default behavior of new bezier keys."));
|
||||
bezier_key_mode->select(2);
|
||||
|
||||
bottom_hf->add_child(bezier_key_mode);
|
||||
bottom_hf->add_child(memnew(VSeparator));
|
||||
|
||||
bezier_edit_icon = memnew(Button);
|
||||
bezier_edit_icon->set_flat(true);
|
||||
bezier_edit_icon->set_disabled(true);
|
||||
|
||||
@@ -618,6 +618,7 @@ class AnimationTrackEditor : public VBoxContainer {
|
||||
OptionButton *snap_mode = nullptr;
|
||||
Button *auto_fit = nullptr;
|
||||
Button *auto_fit_bezier = nullptr;
|
||||
OptionButton *bezier_key_mode = nullptr;
|
||||
|
||||
Button *imported_anim_warning = nullptr;
|
||||
void _show_imported_anim_warning();
|
||||
@@ -767,6 +768,7 @@ class AnimationTrackEditor : public VBoxContainer {
|
||||
void _cancel_bezier_edit();
|
||||
void _bezier_edit(int p_for_track);
|
||||
void _bezier_track_set_key_handle_mode(Animation *p_anim, int p_track, int p_index, Animation::HandleMode p_mode, Animation::HandleSetMode p_set_mode = Animation::HANDLE_SET_MODE_NONE);
|
||||
void _bezier_track_set_key_handle_mode_at_time(Animation *p_anim, int p_track, float p_time, Animation::HandleMode p_mode, Animation::HandleSetMode p_set_mode = Animation::HANDLE_SET_MODE_NONE);
|
||||
|
||||
////////////// edit menu stuff
|
||||
|
||||
|
||||
@@ -3492,79 +3492,10 @@ void Animation::bezier_track_set_key_handle_mode(int p_track, int p_index, Handl
|
||||
|
||||
bt->values.write[p_index].value.handle_mode = p_mode;
|
||||
|
||||
switch (p_mode) {
|
||||
case HANDLE_MODE_LINEAR: {
|
||||
bt->values.write[p_index].value.in_handle = Vector2(0, 0);
|
||||
bt->values.write[p_index].value.out_handle = Vector2(0, 0);
|
||||
} break;
|
||||
case HANDLE_MODE_BALANCED:
|
||||
case HANDLE_MODE_MIRRORED: {
|
||||
int prev_key = MAX(0, p_index - 1);
|
||||
int next_key = MIN(bt->values.size() - 1, p_index + 1);
|
||||
if (prev_key == next_key) {
|
||||
break; // Exists only one key.
|
||||
}
|
||||
real_t in_handle_x = 0;
|
||||
real_t in_handle_y = 0;
|
||||
real_t out_handle_x = 0;
|
||||
real_t out_handle_y = 0;
|
||||
if (p_mode == HANDLE_MODE_BALANCED) {
|
||||
// Note:
|
||||
// If p_set_mode == HANDLE_SET_MODE_NONE, I don't know if it should change the Tangent implicitly.
|
||||
// At the least, we need to avoid corrupting the handles when loading animation from the resource.
|
||||
// However, changes made by the Inspector do not go through the BezierEditor,
|
||||
// so if you change from Free to Balanced or Mirrored in Inspector, there is no guarantee that
|
||||
// it is Balanced or Mirrored until there is a handle operation.
|
||||
if (p_set_mode == HANDLE_SET_MODE_RESET) {
|
||||
real_t handle_length = 1.0 / 3.0;
|
||||
in_handle_x = (bt->values[prev_key].time - bt->values[p_index].time) * handle_length;
|
||||
in_handle_y = 0;
|
||||
out_handle_x = (bt->values[next_key].time - bt->values[p_index].time) * handle_length;
|
||||
out_handle_y = 0;
|
||||
bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
|
||||
bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
|
||||
} else if (p_set_mode == HANDLE_SET_MODE_AUTO) {
|
||||
real_t handle_length = 1.0 / 6.0;
|
||||
real_t tangent = (bt->values[next_key].value.value - bt->values[prev_key].value.value) / (bt->values[next_key].time - bt->values[prev_key].time);
|
||||
in_handle_x = (bt->values[prev_key].time - bt->values[p_index].time) * handle_length;
|
||||
in_handle_y = in_handle_x * tangent;
|
||||
out_handle_x = (bt->values[next_key].time - bt->values[p_index].time) * handle_length;
|
||||
out_handle_y = out_handle_x * tangent;
|
||||
bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
|
||||
bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
|
||||
}
|
||||
} else {
|
||||
real_t handle_length = 1.0 / 4.0;
|
||||
real_t prev_interval = Math::abs(bt->values[p_index].time - bt->values[prev_key].time);
|
||||
real_t next_interval = Math::abs(bt->values[p_index].time - bt->values[next_key].time);
|
||||
real_t min_time = 0;
|
||||
if (Math::is_zero_approx(prev_interval)) {
|
||||
min_time = next_interval;
|
||||
} else if (Math::is_zero_approx(next_interval)) {
|
||||
min_time = prev_interval;
|
||||
} else {
|
||||
min_time = MIN(prev_interval, next_interval);
|
||||
}
|
||||
if (p_set_mode == HANDLE_SET_MODE_RESET) {
|
||||
in_handle_x = -min_time * handle_length;
|
||||
in_handle_y = 0;
|
||||
out_handle_x = min_time * handle_length;
|
||||
out_handle_y = 0;
|
||||
bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
|
||||
bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
|
||||
} else if (p_set_mode == HANDLE_SET_MODE_AUTO) {
|
||||
real_t tangent = (bt->values[next_key].value.value - bt->values[prev_key].value.value) / min_time;
|
||||
in_handle_x = -min_time * handle_length;
|
||||
in_handle_y = in_handle_x * tangent;
|
||||
out_handle_x = min_time * handle_length;
|
||||
out_handle_y = out_handle_x * tangent;
|
||||
bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
|
||||
bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
} break;
|
||||
if (p_mode != HANDLE_MODE_FREE && p_set_mode != HANDLE_SET_MODE_NONE) {
|
||||
Vector2 &in_handle = bt->values.write[p_index].value.in_handle;
|
||||
Vector2 &out_handle = bt->values.write[p_index].value.out_handle;
|
||||
bezier_track_calculate_handles(p_track, p_index, p_mode, p_set_mode, &in_handle, &out_handle);
|
||||
}
|
||||
|
||||
emit_changed();
|
||||
@@ -3581,6 +3512,92 @@ Animation::HandleMode Animation::bezier_track_get_key_handle_mode(int p_track, i
|
||||
|
||||
return bt->values[p_index].value.handle_mode;
|
||||
}
|
||||
|
||||
bool Animation::bezier_track_calculate_handles(int p_track, int p_index, HandleMode p_mode, HandleSetMode p_set_mode, Vector2 *r_in_handle, Vector2 *r_out_handle) {
|
||||
ERR_FAIL_INDEX_V(p_track, tracks.size(), false);
|
||||
Track *t = tracks[p_track];
|
||||
ERR_FAIL_COND_V(t->type != TYPE_BEZIER, false);
|
||||
|
||||
BezierTrack *bt = static_cast<BezierTrack *>(t);
|
||||
ERR_FAIL_INDEX_V(p_index, bt->values.size(), false);
|
||||
|
||||
int prev_key = MAX(0, p_index - 1);
|
||||
int next_key = MIN(bt->values.size() - 1, p_index + 1);
|
||||
if (prev_key == next_key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float time = bt->values[p_index].time;
|
||||
float prev_time = bt->values[prev_key].time;
|
||||
float prev_value = bt->values[prev_key].value.value;
|
||||
float next_time = bt->values[next_key].time;
|
||||
float next_value = bt->values[next_key].value.value;
|
||||
|
||||
return bezier_track_calculate_handles(time, prev_time, prev_value, next_time, next_value, p_mode, p_set_mode, r_in_handle, r_out_handle);
|
||||
}
|
||||
|
||||
bool Animation::bezier_track_calculate_handles(float p_time, float p_prev_time, float p_prev_value, float p_next_time, float p_next_value, HandleMode p_mode, HandleSetMode p_set_mode, Vector2 *r_in_handle, Vector2 *r_out_handle) {
|
||||
ERR_FAIL_COND_V(p_mode == HANDLE_MODE_FREE, false);
|
||||
ERR_FAIL_COND_V(p_set_mode == HANDLE_SET_MODE_NONE, false);
|
||||
|
||||
Vector2 in_handle;
|
||||
Vector2 out_handle;
|
||||
|
||||
if (p_mode == HANDLE_MODE_LINEAR) {
|
||||
in_handle = Vector2(0, 0);
|
||||
out_handle = Vector2(0, 0);
|
||||
} else if (p_mode == HANDLE_MODE_BALANCED) {
|
||||
if (p_set_mode == HANDLE_SET_MODE_RESET) {
|
||||
real_t handle_length = 1.0 / 3.0;
|
||||
in_handle.x = (p_prev_time - p_time) * handle_length;
|
||||
in_handle.y = 0;
|
||||
out_handle.x = (p_next_time - p_time) * handle_length;
|
||||
out_handle.y = 0;
|
||||
} else if (p_set_mode == HANDLE_SET_MODE_AUTO) {
|
||||
real_t handle_length = 1.0 / 6.0;
|
||||
real_t tangent = (p_next_value - p_prev_value) / (p_next_time - p_prev_time);
|
||||
in_handle.x = (p_prev_time - p_time) * handle_length;
|
||||
in_handle.y = in_handle.x * tangent;
|
||||
out_handle.x = (p_next_time - p_time) * handle_length;
|
||||
out_handle.y = out_handle.x * tangent;
|
||||
}
|
||||
} else if (p_mode == HANDLE_MODE_MIRRORED) {
|
||||
real_t handle_length = 1.0 / 4.0;
|
||||
real_t prev_interval = Math::abs(p_time - p_prev_time);
|
||||
real_t next_interval = Math::abs(p_time - p_next_time);
|
||||
real_t min_time = 0;
|
||||
if (Math::is_zero_approx(prev_interval)) {
|
||||
min_time = next_interval;
|
||||
} else if (Math::is_zero_approx(next_interval)) {
|
||||
min_time = prev_interval;
|
||||
} else {
|
||||
min_time = MIN(prev_interval, next_interval);
|
||||
}
|
||||
if (p_set_mode == HANDLE_SET_MODE_RESET) {
|
||||
in_handle.x = -min_time * handle_length;
|
||||
in_handle.y = 0;
|
||||
out_handle.x = min_time * handle_length;
|
||||
out_handle.y = 0;
|
||||
} else if (p_set_mode == HANDLE_SET_MODE_AUTO) {
|
||||
real_t tangent = (p_next_value - p_prev_value) / min_time;
|
||||
in_handle.x = -min_time * handle_length;
|
||||
in_handle.y = in_handle.x * tangent;
|
||||
out_handle.x = min_time * handle_length;
|
||||
out_handle.y = out_handle.x * tangent;
|
||||
}
|
||||
}
|
||||
|
||||
if (r_in_handle != nullptr) {
|
||||
*r_in_handle = in_handle;
|
||||
}
|
||||
|
||||
if (r_out_handle != nullptr) {
|
||||
*r_out_handle = out_handle;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
|
||||
|
||||
@@ -481,6 +481,8 @@ public:
|
||||
#ifdef TOOLS_ENABLED
|
||||
void bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, HandleSetMode p_set_mode = HANDLE_SET_MODE_NONE);
|
||||
HandleMode bezier_track_get_key_handle_mode(int p_track, int p_index) const;
|
||||
bool bezier_track_calculate_handles(int p_track, int p_index, HandleMode p_mode, HandleSetMode p_set_mode, Vector2 *r_in_handle, Vector2 *r_out_handle);
|
||||
bool bezier_track_calculate_handles(float p_time, float p_prev_time, float p_prev_value, float p_next_time, float p_next_value, HandleMode p_mode, HandleSetMode p_set_mode, Vector2 *r_in_handle, Vector2 *r_out_handle);
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
real_t bezier_track_interpolate(int p_track, double p_time) const;
|
||||
|
||||
Reference in New Issue
Block a user