Make bezier handle type a property of keyframes, update interface
- Replaced unused code related to old close icon with a button - Add bezier handle options to right-click menu - Remove mirror handle mode, only keep balanced - Update animation reference
This commit is contained in:
parent
098e3cf8f7
commit
a5d0a74b65
6 changed files with 261 additions and 84 deletions
|
@ -130,6 +130,14 @@
|
|||
Sets the stream of the key identified by [code]key_idx[/code] to value [code]stream[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
|
||||
</description>
|
||||
</method>
|
||||
<method name="bezier_track_get_key_handle_mode" qualifiers="const">
|
||||
<return type="int" />
|
||||
<argument index="0" name="track_idx" type="int" />
|
||||
<argument index="1" name="key_idx" type="int" />
|
||||
<description>
|
||||
Returns the handle mode of the key identified by [code]index[/code]. See [enum HandleMode] for possible values. The [code]track_idx[/code] must be the index of a Bezier Track.
|
||||
</description>
|
||||
</method>
|
||||
<method name="bezier_track_get_key_in_handle" qualifiers="const">
|
||||
<return type="Vector2" />
|
||||
<argument index="0" name="track_idx" type="int" />
|
||||
|
@ -161,6 +169,7 @@
|
|||
<argument index="2" name="value" type="float" />
|
||||
<argument index="3" name="in_handle" type="Vector2" default="Vector2(0, 0)" />
|
||||
<argument index="4" name="out_handle" type="Vector2" default="Vector2(0, 0)" />
|
||||
<argument index="5" name="handle_mode" type="int" enum="Animation.HandleMode" default="1" />
|
||||
<description>
|
||||
Inserts a Bezier Track key at the given [code]time[/code] in seconds. The [code]track_idx[/code] must be the index of a Bezier Track.
|
||||
[code]in_handle[/code] is the left-side weight of the added Bezier curve point, [code]out_handle[/code] is the right-side one, while [code]value[/code] is the actual value at this point.
|
||||
|
@ -174,11 +183,22 @@
|
|||
Returns the interpolated value at the given [code]time[/code] (in seconds). The [code]track_idx[/code] must be the index of a Bezier Track.
|
||||
</description>
|
||||
</method>
|
||||
<method name="bezier_track_set_key_handle_mode">
|
||||
<return type="void" />
|
||||
<argument index="0" name="track_idx" type="int" />
|
||||
<argument index="1" name="key_idx" type="int" />
|
||||
<argument index="2" name="key_handle_mode" type="int" enum="Animation.HandleMode" />
|
||||
<argument index="3" name="balanced_value_time_ratio" type="float" default="1.0" />
|
||||
<description>
|
||||
Changes the handle mode of the keyframe at the given [code]index[/code]. See [enum HandleMode] for possible values. The [code]track_idx[/code] must be the index of a Bezier Track.
|
||||
</description>
|
||||
</method>
|
||||
<method name="bezier_track_set_key_in_handle">
|
||||
<return type="void" />
|
||||
<argument index="0" name="track_idx" type="int" />
|
||||
<argument index="1" name="key_idx" type="int" />
|
||||
<argument index="2" name="in_handle" type="Vector2" />
|
||||
<argument index="3" name="balanced_value_time_ratio" type="float" default="1.0" />
|
||||
<description>
|
||||
Sets the in handle of the key identified by [code]key_idx[/code] to value [code]in_handle[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
|
||||
</description>
|
||||
|
@ -188,6 +208,7 @@
|
|||
<argument index="0" name="track_idx" type="int" />
|
||||
<argument index="1" name="key_idx" type="int" />
|
||||
<argument index="2" name="out_handle" type="Vector2" />
|
||||
<argument index="3" name="balanced_value_time_ratio" type="float" default="1.0" />
|
||||
<description>
|
||||
Sets the out handle of the key identified by [code]key_idx[/code] to value [code]out_handle[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
|
||||
</description>
|
||||
|
@ -619,5 +640,11 @@
|
|||
<constant name="LOOP_PINGPONG" value="2" enum="LoopMode">
|
||||
Repeats playback and reverse playback at both ends of the animation.
|
||||
</constant>
|
||||
<constant name="HANDLE_MODE_FREE" value="0" enum="HandleMode">
|
||||
Assigning the free handle mode to a Bezier Track's keyframe allows you to edit the keyframe's left and right handles independently from one another.
|
||||
</constant>
|
||||
<constant name="HANDLE_MODE_BALANCED" value="1" enum="HandleMode">
|
||||
Assigning the balanced handle mode to a Bezier Track's keyframe makes it so the two handles of the keyframe always stay aligned when changing either the keyframe's left or right handle.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
|
@ -187,7 +187,7 @@ void AnimationBezierTrackEdit::_draw_line_clipped(const Vector2 &p_from, const V
|
|||
Vector2 from = p_from;
|
||||
Vector2 to = p_to;
|
||||
|
||||
if (from.x == to.x) {
|
||||
if (from.x == to.x && from.y == to.y) {
|
||||
return;
|
||||
}
|
||||
if (to.x < from.x) {
|
||||
|
@ -222,11 +222,6 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
|||
bezier_icon = get_theme_icon(SNAME("KeyBezierPoint"), SNAME("EditorIcons"));
|
||||
bezier_handle_icon = get_theme_icon(SNAME("KeyBezierHandle"), SNAME("EditorIcons"));
|
||||
selected_icon = get_theme_icon(SNAME("KeyBezierSelected"), SNAME("EditorIcons"));
|
||||
if (handle_mode_option->get_item_count() == 0) {
|
||||
handle_mode_option->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Free"), HANDLE_MODE_FREE);
|
||||
handle_mode_option->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Balanced"), HANDLE_MODE_BALANCED);
|
||||
handle_mode_option->add_icon_item(get_theme_icon(SNAME("BezierHandlesMirror"), SNAME("EditorIcons")), TTR("Mirror"), HANDLE_MODE_MIRROR);
|
||||
}
|
||||
}
|
||||
if (p_what == NOTIFICATION_RESIZED) {
|
||||
int right_limit = get_size().width - timeline->get_buttons_width();
|
||||
|
@ -420,9 +415,9 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
|||
|
||||
//draw editor handles
|
||||
{
|
||||
float scale = timeline->get_zoom_scale();
|
||||
edit_points.clear();
|
||||
|
||||
float scale = timeline->get_zoom_scale();
|
||||
for (int i = 0; i < animation->track_get_key_count(track); i++) {
|
||||
float offset = animation->track_get_key_time(track, i);
|
||||
float value = animation->bezier_track_get_key_value(track, i);
|
||||
|
@ -438,7 +433,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
|||
if (moving_handle != 0 && moving_handle_key == i) {
|
||||
in_vec = moving_handle_left;
|
||||
}
|
||||
Vector2 pos_in = Vector2(((offset + in_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + in_vec.y));
|
||||
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(track, i);
|
||||
|
||||
|
@ -446,7 +441,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
|
|||
out_vec = moving_handle_right;
|
||||
}
|
||||
|
||||
Vector2 pos_out = Vector2(((offset + out_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + out_vec.y));
|
||||
Vector2 pos_out(((offset + out_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + out_vec.y));
|
||||
|
||||
_draw_line_clipped(pos, pos_in, accent, limit, right_limit);
|
||||
_draw_line_clipped(pos, pos_out, accent, limit, right_limit);
|
||||
|
@ -581,11 +576,21 @@ void AnimationBezierTrackEdit::_clear_selection() {
|
|||
update();
|
||||
}
|
||||
|
||||
void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode) {
|
||||
undo_redo->create_action(TTR("Update Selected Key Handles"));
|
||||
double ratio = timeline->get_zoom_scale() * v_zoom;
|
||||
for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
|
||||
const int key_index = E->get();
|
||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key_index, animation->bezier_track_get_key_handle_mode(track, key_index), ratio);
|
||||
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key_index, p_mode, ratio);
|
||||
}
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void AnimationBezierTrackEdit::_clear_selection_for_anim(const Ref<Animation> &p_anim) {
|
||||
if (!(animation == p_anim)) {
|
||||
return;
|
||||
}
|
||||
//selection.clear();
|
||||
_clear_selection();
|
||||
}
|
||||
|
||||
|
@ -667,6 +672,9 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE);
|
||||
menu->add_separator();
|
||||
menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE);
|
||||
menu->add_separator();
|
||||
menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Make Handles Free"), MENU_KEY_SET_HANDLE_FREE);
|
||||
menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED);
|
||||
}
|
||||
|
||||
menu->set_as_minsize();
|
||||
|
@ -676,10 +684,6 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
|
||||
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
|
||||
if (close_icon_rect.has_point(mb->get_position())) {
|
||||
emit_signal(SNAME("close_request"));
|
||||
return;
|
||||
}
|
||||
for (const KeyValue<int, Rect2> &E : subtracks) {
|
||||
if (E.value.has_point(mb->get_position())) {
|
||||
set_animation_and_track(animation, E.key);
|
||||
|
@ -746,7 +750,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
//insert new point
|
||||
if (mb->is_command_pressed() && mb->get_position().x >= timeline->get_name_limit() && mb->get_position().x < get_size().width - timeline->get_buttons_width()) {
|
||||
Array new_point;
|
||||
new_point.resize(5);
|
||||
new_point.resize(6);
|
||||
|
||||
float h = (get_size().height / 2 - mb->get_position().y) * v_zoom + v_scroll;
|
||||
|
||||
|
@ -755,6 +759,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
new_point[2] = 0;
|
||||
new_point[3] = 0.25;
|
||||
new_point[4] = 0;
|
||||
new_point[5] = 0;
|
||||
|
||||
float time = ((mb->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
|
||||
while (animation->track_find_key(track, time, true) != -1) {
|
||||
|
@ -986,33 +991,49 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
|||
|
||||
if (moving_handle == -1) {
|
||||
moving_handle_left = moving_handle_value;
|
||||
if (moving_handle_left.x > 0) {
|
||||
moving_handle_left.x = 0;
|
||||
|
||||
if (animation->bezier_track_get_key_handle_mode(track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) {
|
||||
double ratio = timeline->get_zoom_scale() * v_zoom;
|
||||
Transform2D xform;
|
||||
xform.set_scale(Vector2(1.0, 1.0 / ratio));
|
||||
|
||||
Vector2 vec_out = xform.xform(moving_handle_right);
|
||||
Vector2 vec_in = xform.xform(moving_handle_left);
|
||||
|
||||
moving_handle_right = xform.affine_inverse().xform(-vec_in.normalized() * vec_out.length());
|
||||
}
|
||||
|
||||
if (handle_mode_option->get_selected() == HANDLE_MODE_BALANCED) {
|
||||
Vector2 scale = Vector2(timeline->get_zoom_scale(), v_zoom);
|
||||
moving_handle_right = (-(moving_handle_left * scale).normalized() * (moving_handle_right * scale).length()) / scale;
|
||||
|
||||
} else if (handle_mode_option->get_selected() == HANDLE_MODE_MIRROR) {
|
||||
moving_handle_right = -moving_handle_left;
|
||||
}
|
||||
}
|
||||
|
||||
if (moving_handle == 1) {
|
||||
} else if (moving_handle == 1) {
|
||||
moving_handle_right = moving_handle_value;
|
||||
if (moving_handle_right.x < 0) {
|
||||
moving_handle_right.x = 0;
|
||||
}
|
||||
|
||||
if (handle_mode_option->get_selected() == HANDLE_MODE_BALANCED) {
|
||||
Vector2 scale = Vector2(timeline->get_zoom_scale(), v_zoom);
|
||||
moving_handle_left = (-(moving_handle_right * scale).normalized() * (moving_handle_left * scale).length()) / scale;
|
||||
} else if (handle_mode_option->get_selected() == HANDLE_MODE_MIRROR) {
|
||||
moving_handle_left = -moving_handle_right;
|
||||
if (animation->bezier_track_get_key_handle_mode(track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) {
|
||||
double ratio = timeline->get_zoom_scale() * v_zoom;
|
||||
Transform2D xform;
|
||||
xform.set_scale(Vector2(1.0, 1.0 / ratio));
|
||||
|
||||
Vector2 vec_in = xform.xform(moving_handle_left);
|
||||
Vector2 vec_out = xform.xform(moving_handle_right);
|
||||
|
||||
moving_handle_left = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length());
|
||||
}
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
bool is_finishing_key_handle_drag = moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT;
|
||||
if (is_finishing_key_handle_drag) {
|
||||
undo_redo->create_action(TTR("Move Bezier Points"));
|
||||
if (moving_handle == -1) {
|
||||
double ratio = timeline->get_zoom_scale() * v_zoom;
|
||||
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, moving_handle_left, ratio);
|
||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, animation->bezier_track_get_key_in_handle(track, moving_handle_key), ratio);
|
||||
} else if (moving_handle == 1) {
|
||||
double ratio = timeline->get_zoom_scale() * v_zoom;
|
||||
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, moving_handle_right, ratio);
|
||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, animation->bezier_track_get_key_out_handle(track, moving_handle_key), ratio);
|
||||
}
|
||||
undo_redo->commit_action();
|
||||
|
||||
moving_handle = 0;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
@ -1021,7 +1042,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
|
|||
switch (p_index) {
|
||||
case MENU_KEY_INSERT: {
|
||||
Array new_point;
|
||||
new_point.resize(5);
|
||||
new_point.resize(6);
|
||||
|
||||
float h = (get_size().height / 2 - menu_insert_key.y) * v_zoom + v_scroll;
|
||||
|
||||
|
@ -1030,6 +1051,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
|
|||
new_point[2] = 0;
|
||||
new_point[3] = 0.25;
|
||||
new_point[4] = 0;
|
||||
new_point[5] = Animation::HANDLE_MODE_BALANCED;
|
||||
|
||||
float time = ((menu_insert_key.x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
|
||||
while (animation->track_find_key(track, time, true) != -1) {
|
||||
|
@ -1048,6 +1070,12 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
|
|||
case MENU_KEY_DELETE: {
|
||||
delete_selection();
|
||||
} break;
|
||||
case MENU_KEY_SET_HANDLE_FREE: {
|
||||
_change_selected_keys_handle_mode(Animation::HANDLE_MODE_FREE);
|
||||
} break;
|
||||
case MENU_KEY_SET_HANDLE_BALANCED: {
|
||||
_change_selected_keys_handle_mode(Animation::HANDLE_MODE_BALANCED);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1118,6 +1146,7 @@ void AnimationBezierTrackEdit::delete_selection() {
|
|||
undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
|
||||
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
|
||||
undo_redo->commit_action();
|
||||
|
||||
//selection.clear();
|
||||
}
|
||||
}
|
||||
|
@ -1150,8 +1179,6 @@ AnimationBezierTrackEdit::AnimationBezierTrackEdit() {
|
|||
set_focus_mode(FOCUS_CLICK);
|
||||
|
||||
set_clip_contents(true);
|
||||
handle_mode = HANDLE_MODE_FREE;
|
||||
handle_mode_option = memnew(OptionButton);
|
||||
|
||||
close_button = memnew(Button);
|
||||
close_button->connect("pressed", Callable(this, SNAME("emit_signal")), varray(SNAME("close_request")));
|
||||
|
@ -1160,7 +1187,6 @@ AnimationBezierTrackEdit::AnimationBezierTrackEdit() {
|
|||
right_column = memnew(VBoxContainer);
|
||||
right_column->add_child(close_button);
|
||||
right_column->add_spacer();
|
||||
right_column->add_child(handle_mode_option);
|
||||
add_child(right_column);
|
||||
|
||||
menu = memnew(PopupMenu);
|
||||
|
|
|
@ -36,21 +36,14 @@
|
|||
class AnimationBezierTrackEdit : public Control {
|
||||
GDCLASS(AnimationBezierTrackEdit, Control);
|
||||
|
||||
enum HandleMode {
|
||||
HANDLE_MODE_FREE,
|
||||
HANDLE_MODE_BALANCED,
|
||||
HANDLE_MODE_MIRROR
|
||||
};
|
||||
|
||||
enum {
|
||||
MENU_KEY_INSERT,
|
||||
MENU_KEY_DUPLICATE,
|
||||
MENU_KEY_DELETE
|
||||
MENU_KEY_DELETE,
|
||||
MENU_KEY_SET_HANDLE_FREE,
|
||||
MENU_KEY_SET_HANDLE_BALANCED,
|
||||
};
|
||||
|
||||
HandleMode handle_mode;
|
||||
OptionButton *handle_mode_option;
|
||||
|
||||
VBoxContainer *right_column;
|
||||
Button *close_button;
|
||||
|
||||
|
@ -69,8 +62,6 @@ class AnimationBezierTrackEdit : public Control {
|
|||
Ref<Texture2D> bezier_handle_icon;
|
||||
Ref<Texture2D> selected_icon;
|
||||
|
||||
Rect2 close_icon_rect;
|
||||
|
||||
Map<int, Rect2> subtracks;
|
||||
|
||||
float v_scroll = 0;
|
||||
|
@ -104,10 +95,12 @@ class AnimationBezierTrackEdit : public Control {
|
|||
int moving_handle_key = 0;
|
||||
Vector2 moving_handle_left;
|
||||
Vector2 moving_handle_right;
|
||||
int moving_handle_mode; // value from Animation::HandleMode
|
||||
|
||||
void _clear_selection();
|
||||
void _clear_selection_for_anim(const Ref<Animation> &p_anim);
|
||||
void _select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos);
|
||||
void _change_selected_keys_handle_mode(Animation::HandleMode p_mode);
|
||||
|
||||
Vector2 menu_insert_key;
|
||||
|
||||
|
|
|
@ -334,6 +334,22 @@ public:
|
|||
setting = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "handle_mode") {
|
||||
const Variant &value = p_value;
|
||||
|
||||
setting = true;
|
||||
undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
|
||||
int prev = animation->bezier_track_get_key_handle_mode(track, key);
|
||||
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, value);
|
||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, prev);
|
||||
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;
|
||||
}
|
||||
} break;
|
||||
case Animation::TYPE_AUDIO: {
|
||||
if (name == "stream") {
|
||||
|
@ -498,6 +514,11 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
if (name == "handle_mode") {
|
||||
r_ret = animation->bezier_track_get_key_handle_mode(track, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
} break;
|
||||
case Animation::TYPE_AUDIO: {
|
||||
if (name == "stream") {
|
||||
|
@ -610,6 +631,7 @@ public:
|
|||
p_list->push_back(PropertyInfo(Variant::FLOAT, "value"));
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR2, "in_handle"));
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR2, "out_handle"));
|
||||
p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Balanced"));
|
||||
|
||||
} break;
|
||||
case Animation::TYPE_AUDIO: {
|
||||
|
@ -949,6 +971,17 @@ public:
|
|||
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, value);
|
||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev);
|
||||
update_obj = true;
|
||||
} else if (name == "handle_mode") {
|
||||
const Variant &value = p_value;
|
||||
|
||||
if (!setting) {
|
||||
setting = true;
|
||||
undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
|
||||
}
|
||||
int prev = animation->bezier_track_get_key_handle_mode(track, key);
|
||||
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, value);
|
||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, prev);
|
||||
update_obj = true;
|
||||
}
|
||||
} break;
|
||||
case Animation::TYPE_AUDIO: {
|
||||
|
@ -1120,6 +1153,11 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
if (name == "handle_mode") {
|
||||
r_ret = animation->bezier_track_get_key_handle_mode(track, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
} break;
|
||||
case Animation::TYPE_AUDIO: {
|
||||
if (name == "stream") {
|
||||
|
@ -1273,6 +1311,7 @@ public:
|
|||
p_list->push_back(PropertyInfo(Variant::FLOAT, "value"));
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR2, "in_handle"));
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR2, "out_handle"));
|
||||
p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Balanced"));
|
||||
} break;
|
||||
case Animation::TYPE_AUDIO: {
|
||||
p_list->push_back(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"));
|
||||
|
@ -2607,6 +2646,17 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
|
|||
text += "In-Handle: " + ih + "\n";
|
||||
Vector2 oh = animation->bezier_track_get_key_out_handle(track, key_idx);
|
||||
text += "Out-Handle: " + oh + "\n";
|
||||
int hm = animation->bezier_track_get_key_handle_mode(track, key_idx);
|
||||
text += "Handle mode: ";
|
||||
switch (hm) {
|
||||
case Animation::HANDLE_MODE_FREE: {
|
||||
text += "Free";
|
||||
} break;
|
||||
case Animation::HANDLE_MODE_BALANCED: {
|
||||
text += "Balanced";
|
||||
} break;
|
||||
}
|
||||
text += "\n";
|
||||
} break;
|
||||
case Animation::TYPE_AUDIO: {
|
||||
String stream_name = "null";
|
||||
|
@ -4796,12 +4846,13 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
|
|||
Variant value;
|
||||
_find_hint_for_track(p_track, bp, &value);
|
||||
Array arr;
|
||||
arr.resize(5);
|
||||
arr.resize(6);
|
||||
arr[0] = value;
|
||||
arr[1] = -0.25;
|
||||
arr[2] = 0;
|
||||
arr[3] = 0.25;
|
||||
arr[4] = 0;
|
||||
arr[5] = 0;
|
||||
|
||||
undo_redo->create_action(TTR("Add Track Key"));
|
||||
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, arr);
|
||||
|
|
|
@ -317,7 +317,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
|
|||
Vector<real_t> times = d["times"];
|
||||
Vector<real_t> values = d["points"];
|
||||
|
||||
ERR_FAIL_COND_V(times.size() * 5 != values.size(), false);
|
||||
ERR_FAIL_COND_V(times.size() * 6 != values.size(), false);
|
||||
|
||||
if (times.size()) {
|
||||
int valcount = times.size();
|
||||
|
@ -330,11 +330,12 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
|
|||
for (int i = 0; i < valcount; i++) {
|
||||
bt->values.write[i].time = rt[i];
|
||||
bt->values.write[i].transition = 0; //unused in bezier
|
||||
bt->values.write[i].value.value = rv[i * 5 + 0];
|
||||
bt->values.write[i].value.in_handle.x = rv[i * 5 + 1];
|
||||
bt->values.write[i].value.in_handle.y = rv[i * 5 + 2];
|
||||
bt->values.write[i].value.out_handle.x = rv[i * 5 + 3];
|
||||
bt->values.write[i].value.out_handle.y = rv[i * 5 + 4];
|
||||
bt->values.write[i].value.value = rv[i * 6 + 0];
|
||||
bt->values.write[i].value.in_handle.x = rv[i * 6 + 1];
|
||||
bt->values.write[i].value.in_handle.y = rv[i * 6 + 2];
|
||||
bt->values.write[i].value.out_handle.x = rv[i * 6 + 3];
|
||||
bt->values.write[i].value.out_handle.y = rv[i * 6 + 4];
|
||||
bt->values.write[i].value.handle_mode = (HandleMode)rv[i * 6 + 5];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -698,7 +699,7 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
|
|||
int kk = bt->values.size();
|
||||
|
||||
key_times.resize(kk);
|
||||
key_points.resize(kk * 5);
|
||||
key_points.resize(kk * 6);
|
||||
|
||||
real_t *wti = key_times.ptrw();
|
||||
real_t *wpo = key_points.ptrw();
|
||||
|
@ -709,11 +710,12 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
|
|||
|
||||
for (int i = 0; i < kk; i++) {
|
||||
wti[idx] = vls[i].time;
|
||||
wpo[idx * 5 + 0] = vls[i].value.value;
|
||||
wpo[idx * 5 + 1] = vls[i].value.in_handle.x;
|
||||
wpo[idx * 5 + 2] = vls[i].value.in_handle.y;
|
||||
wpo[idx * 5 + 3] = vls[i].value.out_handle.x;
|
||||
wpo[idx * 5 + 4] = vls[i].value.out_handle.y;
|
||||
wpo[idx * 6 + 0] = vls[i].value.value;
|
||||
wpo[idx * 6 + 1] = vls[i].value.in_handle.x;
|
||||
wpo[idx * 6 + 2] = vls[i].value.in_handle.y;
|
||||
wpo[idx * 6 + 3] = vls[i].value.out_handle.x;
|
||||
wpo[idx * 6 + 4] = vls[i].value.out_handle.y;
|
||||
wpo[idx * 6 + 5] = (double)vls[i].value.handle_mode;
|
||||
idx++;
|
||||
}
|
||||
|
||||
|
@ -1623,7 +1625,7 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke
|
|||
BezierTrack *bt = static_cast<BezierTrack *>(t);
|
||||
|
||||
Array arr = p_key;
|
||||
ERR_FAIL_COND(arr.size() != 5);
|
||||
ERR_FAIL_COND(arr.size() != 6);
|
||||
|
||||
TKey<BezierKey> k;
|
||||
k.time = p_time;
|
||||
|
@ -1632,6 +1634,7 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke
|
|||
k.value.in_handle.y = arr[2];
|
||||
k.value.out_handle.x = arr[3];
|
||||
k.value.out_handle.y = arr[4];
|
||||
k.value.handle_mode = (HandleMode) int(arr[5]);
|
||||
_insert(p_time, bt->values, k);
|
||||
|
||||
} break;
|
||||
|
@ -1770,12 +1773,13 @@ Variant Animation::track_get_key_value(int p_track, int p_key_idx) const {
|
|||
ERR_FAIL_INDEX_V(p_key_idx, bt->values.size(), Variant());
|
||||
|
||||
Array arr;
|
||||
arr.resize(5);
|
||||
arr.resize(6);
|
||||
arr[0] = bt->values[p_key_idx].value.value;
|
||||
arr[1] = bt->values[p_key_idx].value.in_handle.x;
|
||||
arr[2] = bt->values[p_key_idx].value.in_handle.y;
|
||||
arr[3] = bt->values[p_key_idx].value.out_handle.x;
|
||||
arr[4] = bt->values[p_key_idx].value.out_handle.y;
|
||||
arr[5] = (double)bt->values[p_key_idx].value.handle_mode;
|
||||
return arr;
|
||||
|
||||
} break;
|
||||
|
@ -2144,13 +2148,14 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p
|
|||
ERR_FAIL_INDEX(p_key_idx, bt->values.size());
|
||||
|
||||
Array arr = p_value;
|
||||
ERR_FAIL_COND(arr.size() != 5);
|
||||
ERR_FAIL_COND(arr.size() != 6);
|
||||
|
||||
bt->values.write[p_key_idx].value.value = arr[0];
|
||||
bt->values.write[p_key_idx].value.in_handle.x = arr[1];
|
||||
bt->values.write[p_key_idx].value.in_handle.y = arr[2];
|
||||
bt->values.write[p_key_idx].value.out_handle.x = arr[3];
|
||||
bt->values.write[p_key_idx].value.out_handle.y = arr[4];
|
||||
bt->values.write[p_key_idx].value.handle_mode = (HandleMode) int(arr[5]);
|
||||
|
||||
} break;
|
||||
case TYPE_AUDIO: {
|
||||
|
@ -3203,7 +3208,7 @@ StringName Animation::method_track_get_name(int p_track, int p_key_idx) const {
|
|||
return pm->methods[p_key_idx].method;
|
||||
}
|
||||
|
||||
int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle) {
|
||||
int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const HandleMode p_handle_mode) {
|
||||
ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
|
||||
Track *t = tracks[p_track];
|
||||
ERR_FAIL_COND_V(t->type != TYPE_BEZIER, -1);
|
||||
|
@ -3221,6 +3226,7 @@ int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_valu
|
|||
if (k.value.out_handle.x < 0) {
|
||||
k.value.out_handle.x = 0;
|
||||
}
|
||||
k.value.handle_mode = p_handle_mode;
|
||||
|
||||
int key = _insert(p_time, bt->values, k);
|
||||
|
||||
|
@ -3229,6 +3235,30 @@ int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_valu
|
|||
return key;
|
||||
}
|
||||
|
||||
void Animation::bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, double p_balanced_value_time_ratio) {
|
||||
ERR_FAIL_INDEX(p_track, tracks.size());
|
||||
Track *t = tracks[p_track];
|
||||
ERR_FAIL_COND(t->type != TYPE_BEZIER);
|
||||
|
||||
BezierTrack *bt = static_cast<BezierTrack *>(t);
|
||||
|
||||
ERR_FAIL_INDEX(p_index, bt->values.size());
|
||||
|
||||
bt->values.write[p_index].value.handle_mode = p_mode;
|
||||
|
||||
if (p_mode == HANDLE_MODE_BALANCED) {
|
||||
Transform2D xform;
|
||||
xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio));
|
||||
|
||||
Vector2 vec_in = xform.xform(bt->values[p_index].value.in_handle);
|
||||
Vector2 vec_out = xform.xform(bt->values[p_index].value.out_handle);
|
||||
|
||||
bt->values.write[p_index].value.in_handle = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length());
|
||||
}
|
||||
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void Animation::bezier_track_set_key_value(int p_track, int p_index, real_t p_value) {
|
||||
ERR_FAIL_INDEX(p_track, tracks.size());
|
||||
Track *t = tracks[p_track];
|
||||
|
@ -3242,7 +3272,7 @@ void Animation::bezier_track_set_key_value(int p_track, int p_index, real_t p_va
|
|||
emit_changed();
|
||||
}
|
||||
|
||||
void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle) {
|
||||
void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio) {
|
||||
ERR_FAIL_INDEX(p_track, tracks.size());
|
||||
Track *t = tracks[p_track];
|
||||
ERR_FAIL_COND(t->type != TYPE_BEZIER);
|
||||
|
@ -3251,14 +3281,26 @@ void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const V
|
|||
|
||||
ERR_FAIL_INDEX(p_index, bt->values.size());
|
||||
|
||||
bt->values.write[p_index].value.in_handle = p_handle;
|
||||
if (bt->values[p_index].value.in_handle.x > 0) {
|
||||
bt->values.write[p_index].value.in_handle.x = 0;
|
||||
Vector2 in_handle = p_handle;
|
||||
if (in_handle.x > 0) {
|
||||
in_handle.x = 0;
|
||||
}
|
||||
bt->values.write[p_index].value.in_handle = in_handle;
|
||||
|
||||
if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) {
|
||||
Transform2D xform;
|
||||
xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio));
|
||||
|
||||
Vector2 vec_out = xform.xform(bt->values[p_index].value.out_handle);
|
||||
Vector2 vec_in = xform.xform(in_handle);
|
||||
|
||||
bt->values.write[p_index].value.out_handle = xform.affine_inverse().xform(-vec_in.normalized() * vec_out.length());
|
||||
}
|
||||
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle) {
|
||||
void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio) {
|
||||
ERR_FAIL_INDEX(p_track, tracks.size());
|
||||
Track *t = tracks[p_track];
|
||||
ERR_FAIL_COND(t->type != TYPE_BEZIER);
|
||||
|
@ -3267,10 +3309,22 @@ void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const
|
|||
|
||||
ERR_FAIL_INDEX(p_index, bt->values.size());
|
||||
|
||||
bt->values.write[p_index].value.out_handle = p_handle;
|
||||
if (bt->values[p_index].value.out_handle.x < 0) {
|
||||
bt->values.write[p_index].value.out_handle.x = 0;
|
||||
Vector2 out_handle = p_handle;
|
||||
if (out_handle.x < 0) {
|
||||
out_handle.x = 0;
|
||||
}
|
||||
bt->values.write[p_index].value.out_handle = out_handle;
|
||||
|
||||
if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) {
|
||||
Transform2D xform;
|
||||
xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio));
|
||||
|
||||
Vector2 vec_in = xform.xform(bt->values[p_index].value.in_handle);
|
||||
Vector2 vec_out = xform.xform(out_handle);
|
||||
|
||||
bt->values.write[p_index].value.in_handle = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length());
|
||||
}
|
||||
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
|
@ -3286,6 +3340,18 @@ real_t Animation::bezier_track_get_key_value(int p_track, int p_index) const {
|
|||
return bt->values[p_index].value.value;
|
||||
}
|
||||
|
||||
int Animation::bezier_track_get_key_handle_mode(int p_track, int p_index) const {
|
||||
ERR_FAIL_INDEX_V(p_track, tracks.size(), 0);
|
||||
Track *t = tracks[p_track];
|
||||
ERR_FAIL_COND_V(t->type != TYPE_BEZIER, 0);
|
||||
|
||||
BezierTrack *bt = static_cast<BezierTrack *>(t);
|
||||
|
||||
ERR_FAIL_INDEX_V(p_index, bt->values.size(), 0);
|
||||
|
||||
return bt->values[p_index].value.handle_mode;
|
||||
}
|
||||
|
||||
Vector2 Animation::bezier_track_get_key_in_handle(int p_track, int p_index) const {
|
||||
ERR_FAIL_INDEX_V(p_track, tracks.size(), Vector2());
|
||||
Track *t = tracks[p_track];
|
||||
|
@ -3718,11 +3784,11 @@ void Animation::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("method_track_get_name", "track_idx", "key_idx"), &Animation::method_track_get_name);
|
||||
ClassDB::bind_method(D_METHOD("method_track_get_params", "track_idx", "key_idx"), &Animation::method_track_get_params);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track_idx", "time", "value", "in_handle", "out_handle"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2()));
|
||||
ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track_idx", "time", "value", "in_handle", "out_handle", "handle_mode"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(Animation::HandleMode::HANDLE_MODE_BALANCED));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("bezier_track_set_key_value", "track_idx", "key_idx", "value"), &Animation::bezier_track_set_key_value);
|
||||
ClassDB::bind_method(D_METHOD("bezier_track_set_key_in_handle", "track_idx", "key_idx", "in_handle"), &Animation::bezier_track_set_key_in_handle);
|
||||
ClassDB::bind_method(D_METHOD("bezier_track_set_key_out_handle", "track_idx", "key_idx", "out_handle"), &Animation::bezier_track_set_key_out_handle);
|
||||
ClassDB::bind_method(D_METHOD("bezier_track_set_key_in_handle", "track_idx", "key_idx", "in_handle", "balanced_value_time_ratio"), &Animation::bezier_track_set_key_in_handle, DEFVAL(1.0));
|
||||
ClassDB::bind_method(D_METHOD("bezier_track_set_key_out_handle", "track_idx", "key_idx", "out_handle", "balanced_value_time_ratio"), &Animation::bezier_track_set_key_out_handle, DEFVAL(1.0));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("bezier_track_get_key_value", "track_idx", "key_idx"), &Animation::bezier_track_get_key_value);
|
||||
ClassDB::bind_method(D_METHOD("bezier_track_get_key_in_handle", "track_idx", "key_idx"), &Animation::bezier_track_get_key_in_handle);
|
||||
|
@ -3738,6 +3804,9 @@ void Animation::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("audio_track_get_key_start_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_start_offset);
|
||||
ClassDB::bind_method(D_METHOD("audio_track_get_key_end_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_end_offset);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("bezier_track_set_key_handle_mode", "track_idx", "key_idx", "key_handle_mode", "balanced_value_time_ratio"), &Animation::bezier_track_set_key_handle_mode, DEFVAL(1.0));
|
||||
ClassDB::bind_method(D_METHOD("bezier_track_get_key_handle_mode", "track_idx", "key_idx"), &Animation::bezier_track_get_key_handle_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("animation_track_insert_key", "track_idx", "time", "animation"), &Animation::animation_track_insert_key);
|
||||
ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "track_idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation);
|
||||
ClassDB::bind_method(D_METHOD("animation_track_get_key_animation", "track_idx", "key_idx"), &Animation::animation_track_get_key_animation);
|
||||
|
@ -3784,6 +3853,9 @@ void Animation::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(LOOP_NONE);
|
||||
BIND_ENUM_CONSTANT(LOOP_LINEAR);
|
||||
BIND_ENUM_CONSTANT(LOOP_PINGPONG);
|
||||
|
||||
BIND_ENUM_CONSTANT(HANDLE_MODE_FREE);
|
||||
BIND_ENUM_CONSTANT(HANDLE_MODE_BALANCED);
|
||||
}
|
||||
|
||||
void Animation::clear() {
|
||||
|
|
|
@ -72,6 +72,11 @@ public:
|
|||
LOOP_PINGPONG,
|
||||
};
|
||||
|
||||
enum HandleMode {
|
||||
HANDLE_MODE_FREE,
|
||||
HANDLE_MODE_BALANCED,
|
||||
};
|
||||
|
||||
private:
|
||||
struct Track {
|
||||
TrackType type = TrackType::TYPE_ANIMATION;
|
||||
|
@ -157,10 +162,10 @@ private:
|
|||
};
|
||||
|
||||
/* BEZIER TRACK */
|
||||
|
||||
struct BezierKey {
|
||||
Vector2 in_handle; //relative (x always <0)
|
||||
Vector2 out_handle; //relative (x always >0)
|
||||
HandleMode handle_mode = HANDLE_MODE_BALANCED;
|
||||
real_t value = 0.0;
|
||||
};
|
||||
|
||||
|
@ -419,11 +424,13 @@ public:
|
|||
void track_set_interpolation_type(int p_track, InterpolationType p_interp);
|
||||
InterpolationType track_get_interpolation_type(int p_track) const;
|
||||
|
||||
int bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle);
|
||||
int bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const HandleMode p_handle_mode = HandleMode::HANDLE_MODE_BALANCED);
|
||||
void bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, double p_balanced_value_time_ratio = 1.0);
|
||||
void bezier_track_set_key_value(int p_track, int p_index, real_t p_value);
|
||||
void bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle);
|
||||
void bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle);
|
||||
void bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio = 1.0);
|
||||
void bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio = 1.0);
|
||||
real_t bezier_track_get_key_value(int p_track, int p_index) const;
|
||||
int bezier_track_get_key_handle_mode(int p_track, int p_index) const;
|
||||
Vector2 bezier_track_get_key_in_handle(int p_track, int p_index) const;
|
||||
Vector2 bezier_track_get_key_out_handle(int p_track, int p_index) const;
|
||||
|
||||
|
@ -478,6 +485,7 @@ public:
|
|||
VARIANT_ENUM_CAST(Animation::TrackType);
|
||||
VARIANT_ENUM_CAST(Animation::InterpolationType);
|
||||
VARIANT_ENUM_CAST(Animation::UpdateMode);
|
||||
VARIANT_ENUM_CAST(Animation::HandleMode);
|
||||
VARIANT_ENUM_CAST(Animation::LoopMode);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue