summaryrefslogtreecommitdiff
path: root/editor/animation_track_editor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/animation_track_editor.cpp')
-rw-r--r--editor/animation_track_editor.cpp626
1 files changed, 422 insertions, 204 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 14ca35a664..6fce55f8e3 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;
@@ -315,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") {
@@ -412,13 +447,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);
@@ -477,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") {
@@ -523,11 +565,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);
@@ -557,7 +605,8 @@ public:
} break;
case Animation::TYPE_METHOD: {
p_list->push_back(PropertyInfo(Variant::STRING_NAME, "name"));
- p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,5,1"));
+ static_assert(VARIANT_ARG_MAX == 8, "PROPERTY_HINT_RANGE needs to be updated if VARIANT_ARG_MAX != 8");
+ p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,8,1"));
Dictionary d = animation->track_get_key_value(track, key);
ERR_FAIL_COND(!d.has("args"));
@@ -582,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: {
@@ -779,19 +829,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;
@@ -906,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: {
@@ -1009,13 +1085,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);
@@ -1074,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") {
@@ -1159,11 +1243,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);
@@ -1195,7 +1286,8 @@ public:
} break;
case Animation::TYPE_METHOD: {
p_list->push_back(PropertyInfo(Variant::STRING_NAME, "name"));
- p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,5,1"));
+ static_assert(VARIANT_ARG_MAX == 8, "PROPERTY_HINT_RANGE needs to be updated if VARIANT_ARG_MAX != 8");
+ p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,8,1"));
Dictionary d = animation->track_get_key_value(first_track, first_key);
ERR_FAIL_COND(!d.has("args"));
@@ -1219,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"));
@@ -1323,8 +1416,20 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
void AnimationTimelineEdit::_anim_loop_pressed() {
undo_redo->create_action(TTR("Change Animation Loop"));
- undo_redo->add_do_method(animation.ptr(), "set_loop", loop->is_pressed());
- undo_redo->add_undo_method(animation.ptr(), "set_loop", animation->has_loop());
+ switch (animation->get_loop_mode()) {
+ case Animation::LoopMode::LOOP_NONE: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::LOOP_LINEAR);
+ } break;
+ case Animation::LoopMode::LOOP_LINEAR: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::LOOP_PINGPONG);
+ } break;
+ case Animation::LoopMode::LOOP_PINGPONG: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::LOOP_NONE);
+ } break;
+ default:
+ break;
+ }
+ undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode());
undo_redo->commit_action();
}
@@ -1359,7 +1464,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"));
@@ -1607,7 +1715,24 @@ void AnimationTimelineEdit::update_values() {
length->set_tooltip(TTR("Animation length (seconds)"));
time_icon->set_tooltip(TTR("Animation length (seconds)"));
}
- loop->set_pressed(animation->has_loop());
+
+ switch (animation->get_loop_mode()) {
+ case Animation::LoopMode::LOOP_NONE: {
+ loop->set_icon(get_theme_icon("Loop", "EditorIcons"));
+ loop->set_pressed(false);
+ } break;
+ case Animation::LoopMode::LOOP_LINEAR: {
+ loop->set_icon(get_theme_icon("Loop", "EditorIcons"));
+ loop->set_pressed(true);
+ } break;
+ case Animation::LoopMode::LOOP_PINGPONG: {
+ loop->set_icon(get_theme_icon("PingPongLoop", "EditorIcons"));
+ loop->set_pressed(true);
+ } break;
+ default:
+ break;
+ }
+
editing = false;
}
@@ -1636,48 +1761,48 @@ void AnimationTimelineEdit::gui_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP) {
get_zoom()->set_value(get_zoom()->get_value() * 1.05);
accept_event();
}
- if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN) {
get_zoom()->set_value(get_zoom()->get_value() / 1.05);
accept_event();
}
- if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP) {
if (track_edit) {
track_edit->get_editor()->goto_prev_step(true);
}
accept_event();
}
- if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN) {
if (track_edit) {
track_edit->get_editor()->goto_next_step(true);
}
accept_event();
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && hsize_rect.has_point(mb->get_position())) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && hsize_rect.has_point(mb->get_position())) {
dragging_hsize = true;
dragging_hsize_from = mb->get_position().x;
dragging_hsize_at = name_limit;
}
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && dragging_hsize) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && dragging_hsize) {
dragging_hsize = false;
}
if (mb.is_valid() && mb->get_position().x > get_name_limit() && mb->get_position().x < (get_size().width - get_buttons_width())) {
- if (!panning_timeline && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (!panning_timeline && mb->get_button_index() == MouseButton::LEFT) {
int x = mb->get_position().x - get_name_limit();
float ofs = x / get_zoom_scale() + get_value();
- emit_signal(SNAME("timeline_changed"), ofs, false, Input::get_singleton()->is_key_pressed(KEY_ALT));
+ emit_signal(SNAME("timeline_changed"), ofs, false, Input::get_singleton()->is_key_pressed(Key::ALT));
dragging_timeline = true;
}
- if (!dragging_timeline && mb->get_button_index() == MOUSE_BUTTON_MIDDLE) {
+ if (!dragging_timeline && mb->get_button_index() == MouseButton::MIDDLE) {
int x = mb->get_position().x - get_name_limit();
panning_timeline_from = x / get_zoom_scale();
panning_timeline = true;
@@ -1685,11 +1810,11 @@ void AnimationTimelineEdit::gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (dragging_timeline && mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
+ if (dragging_timeline && mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) {
dragging_timeline = false;
}
- if (panning_timeline && mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_MIDDLE && !mb->is_pressed()) {
+ if (panning_timeline && mb.is_valid() && mb->get_button_index() == MouseButton::MIDDLE && !mb->is_pressed()) {
panning_timeline = false;
}
@@ -1713,7 +1838,7 @@ void AnimationTimelineEdit::gui_input(const Ref<InputEvent> &p_event) {
if (dragging_timeline) {
int x = mm->get_position().x - get_name_limit();
float ofs = x / get_zoom_scale() + get_value();
- emit_signal(SNAME("timeline_changed"), ofs, false, Input::get_singleton()->is_key_pressed(KEY_ALT));
+ emit_signal(SNAME("timeline_changed"), ofs, false, Input::get_singleton()->is_key_pressed(Key::ALT));
}
if (panning_timeline) {
int x = mm->get_position().x - get_name_limit();
@@ -1828,9 +1953,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")),
@@ -1979,7 +2107,7 @@ void AnimationTrackEdit::_notification(int p_what) {
update_mode_rect.position.y = int(get_size().height - update_icon->get_height()) / 2;
update_mode_rect.size = update_icon->get_size();
- if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
+ if (!animation->track_is_compressed(track) && animation->track_get_type(track) == Animation::TYPE_VALUE) {
draw_texture(update_icon, update_mode_rect.position);
}
// Make it easier to click.
@@ -2021,7 +2149,7 @@ 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_is_compressed(track) && (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.
@@ -2031,7 +2159,7 @@ void AnimationTrackEdit::_notification(int p_what) {
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_is_compressed(track) && (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 {
@@ -2050,25 +2178,25 @@ void AnimationTrackEdit::_notification(int p_what) {
Ref<Texture2D> icon = wrap_icon[loop_wrap ? 1 : 0];
- loop_mode_rect.position.x = ofs;
- loop_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2;
- loop_mode_rect.size = icon->get_size();
+ loop_wrap_rect.position.x = ofs;
+ loop_wrap_rect.position.y = int(get_size().height - icon->get_height()) / 2;
+ loop_wrap_rect.size = icon->get_size();
- if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) {
- draw_texture(icon, loop_mode_rect.position);
+ if (!animation->track_is_compressed(track) && (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_wrap_rect.position);
}
- loop_mode_rect.position.y = 0;
- loop_mode_rect.size.y = get_size().height;
+ loop_wrap_rect.position.y = 0;
+ loop_wrap_rect.size.y = get_size().height;
ofs += icon->get_width() + hsep;
- loop_mode_rect.size.x += hsep;
+ loop_wrap_rect.size.x += hsep;
- if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) {
+ if (!animation->track_is_compressed(track) && (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();
+ loop_wrap_rect.size.x += down_icon->get_width();
} else {
- loop_mode_rect = Rect2();
+ loop_wrap_rect = Rect2();
}
ofs += down_icon->get_width();
@@ -2079,7 +2207,7 @@ void AnimationTrackEdit::_notification(int p_what) {
{
// Erase.
- Ref<Texture2D> icon = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"));
+ Ref<Texture2D> icon = get_theme_icon(animation->track_is_compressed(track) ? SNAME("Lock") : SNAME("Remove"), SNAME("EditorIcons"));
remove_rect.position.x = ofs + ((get_size().width - ofs) - icon->get_width()) / 2;
remove_rect.position.y = int(get_size().height - icon->get_height()) / 2;
@@ -2168,6 +2296,11 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool
Ref<Texture2D> icon_to_draw = p_selected ? selected_icon : type_icon;
+ if (animation->track_get_type(track) == Animation::TYPE_VALUE && !Math::is_equal_approx(animation->track_get_key_transition(track, p_index), real_t(1.0))) {
+ // Use a different icon for keys with non-linear easing.
+ icon_to_draw = get_theme_icon(p_selected ? SNAME("KeyEasedSelected") : SNAME("KeyValueEased"), SNAME("EditorIcons"));
+ }
+
// Override type icon for invalid value keys, unless selected.
if (!p_selected && animation->track_get_type(track) == Animation::TYPE_VALUE) {
const Variant &v = animation->track_get_key_value(track, p_index);
@@ -2284,9 +2417,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")),
@@ -2415,7 +2551,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
return TTR("Interpolation Mode");
}
- if (loop_mode_rect.has_point(p_pos)) {
+ if (loop_wrap_rect.has_point(p_pos)) {
return TTR("Loop Wrap Mode (Interpolate end with beginning on loop)");
}
@@ -2456,17 +2592,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);
@@ -2506,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";
@@ -2559,7 +2710,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
Point2 pos = mb->get_position();
if (check_rect.has_point(pos)) {
@@ -2614,7 +2765,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
accept_event();
}
- if (loop_mode_rect.has_point(pos)) {
+ if (loop_wrap_rect.has_point(pos)) {
if (!menu) {
menu = memnew(PopupMenu);
add_child(menu);
@@ -2625,7 +2776,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
menu->add_icon_item(get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP);
menu->set_as_minsize();
- Vector2 popup_pos = get_screen_position() + loop_mode_rect.position + Vector2(0, loop_mode_rect.size.height);
+ Vector2 popup_pos = get_screen_position() + loop_wrap_rect.position + Vector2(0, loop_wrap_rect.size.height);
menu->set_position(popup_pos);
menu->popup();
accept_event();
@@ -2644,65 +2795,68 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
// Check keyframes.
- float scale = timeline->get_zoom_scale();
- int limit = timeline->get_name_limit();
- int limit_end = get_size().width - timeline->get_buttons_width();
- // Left Border including space occupied by keyframes on t=0.
- int limit_start_hitbox = limit - type_icon->get_width();
-
- if (pos.x >= limit_start_hitbox && pos.x <= limit_end) {
- int key_idx = -1;
- float key_distance = 1e20;
-
- // Select should happen in the opposite order of drawing for more accurate overlap select.
- for (int i = animation->track_get_key_count(track) - 1; i >= 0; i--) {
- Rect2 rect = get_key_rect(i, scale);
- float offset = animation->track_get_key_time(track, i) - timeline->get_value();
- offset = offset * scale + limit;
- rect.position.x += offset;
+ if (!animation->track_is_compressed(track)) { // Selecting compressed keyframes for editing is not possible.
- if (rect.has_point(pos)) {
- if (is_key_selectable_by_distance()) {
- float distance = ABS(offset - pos.x);
- if (key_idx == -1 || distance < key_distance) {
+ float scale = timeline->get_zoom_scale();
+ int limit = timeline->get_name_limit();
+ int limit_end = get_size().width - timeline->get_buttons_width();
+ // Left Border including space occupied by keyframes on t=0.
+ int limit_start_hitbox = limit - type_icon->get_width();
+
+ if (pos.x >= limit_start_hitbox && pos.x <= limit_end) {
+ int key_idx = -1;
+ float key_distance = 1e20;
+
+ // Select should happen in the opposite order of drawing for more accurate overlap select.
+ for (int i = animation->track_get_key_count(track) - 1; i >= 0; i--) {
+ Rect2 rect = get_key_rect(i, scale);
+ float offset = animation->track_get_key_time(track, i) - timeline->get_value();
+ offset = offset * scale + limit;
+ rect.position.x += offset;
+
+ if (rect.has_point(pos)) {
+ if (is_key_selectable_by_distance()) {
+ float distance = ABS(offset - pos.x);
+ if (key_idx == -1 || distance < key_distance) {
+ key_idx = i;
+ key_distance = distance;
+ }
+ } else {
+ // First one does it.
key_idx = i;
- key_distance = distance;
+ break;
}
- } else {
- // First one does it.
- key_idx = i;
- break;
}
}
- }
- if (key_idx != -1) {
- if (mb->is_command_pressed() || mb->is_shift_pressed()) {
- if (editor->is_key_selected(track, key_idx)) {
- emit_signal(SNAME("deselect_key"), key_idx);
+ if (key_idx != -1) {
+ if (mb->is_command_pressed() || mb->is_shift_pressed()) {
+ if (editor->is_key_selected(track, key_idx)) {
+ emit_signal(SNAME("deselect_key"), key_idx);
+ } else {
+ emit_signal(SNAME("select_key"), key_idx, false);
+ moving_selection_attempt = true;
+ select_single_attempt = -1;
+ moving_selection_from_ofs = (mb->get_position().x - limit) / timeline->get_zoom_scale();
+ }
} else {
- emit_signal(SNAME("select_key"), key_idx, false);
+ if (!editor->is_key_selected(track, key_idx)) {
+ emit_signal(SNAME("select_key"), key_idx, true);
+ select_single_attempt = -1;
+ } else {
+ select_single_attempt = key_idx;
+ }
+
moving_selection_attempt = true;
- select_single_attempt = -1;
moving_selection_from_ofs = (mb->get_position().x - limit) / timeline->get_zoom_scale();
}
- } else {
- if (!editor->is_key_selected(track, key_idx)) {
- emit_signal(SNAME("select_key"), key_idx, true);
- select_single_attempt = -1;
- } else {
- select_single_attempt = key_idx;
- }
-
- moving_selection_attempt = true;
- moving_selection_from_ofs = (mb->get_position().x - limit) / timeline->get_zoom_scale();
+ accept_event();
}
- accept_event();
}
}
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
Point2 pos = mb->get_position();
if (pos.x >= timeline->get_name_limit() && pos.x <= get_size().width - timeline->get_buttons_width()) {
// Can do something with menu too! show insert key.
@@ -2732,7 +2886,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && clicking_on_name) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && clicking_on_name) {
if (!path) {
path_popup = memnew(Popup);
path_popup->set_wrap_controls(true);
@@ -2754,7 +2908,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
if (mb.is_valid() && moving_selection_attempt) {
- if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (!mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
moving_selection_attempt = false;
if (moving_selection) {
emit_signal(SNAME("move_selection_commit"));
@@ -2765,7 +2919,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
select_single_attempt = -1;
}
- if (moving_selection && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (moving_selection && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
moving_selection_attempt = false;
moving_selection = false;
emit_signal(SNAME("move_selection_cancel"));
@@ -2773,7 +2927,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT && moving_selection_attempt) {
+ if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE && moving_selection_attempt) {
if (!moving_selection) {
moving_selection = true;
emit_signal(SNAME("move_selection_begin"));
@@ -2929,6 +3083,9 @@ void AnimationTrackEdit::set_in_group(bool p_enable) {
}
void AnimationTrackEdit::append_to_selection(const Rect2 &p_box, bool p_deselection) {
+ if (animation->track_is_compressed(track)) {
+ return; // Compressed keyframes can't be edited
+ }
// Left Border including space occupied by keyframes on t=0.
int limit_start_hitbox = timeline->get_name_limit() - type_icon->get_width();
Rect2 select_rect(limit_start_hitbox, 0, get_size().width - timeline->get_name_limit() - timeline->get_buttons_width(), get_size().height);
@@ -3272,6 +3429,10 @@ void AnimationTrackEditor::_timeline_changed(float p_new_pos, bool p_drag, bool
}
void AnimationTrackEditor::_track_remove_request(int p_track) {
+ if (animation->track_is_compressed(p_track)) {
+ EditorNode::get_singleton()->show_warning(TTR("Compressed tracks can't be edited or removed. Re-import the animation with compression disabled in order to edit."));
+ return;
+ }
int idx = p_track;
if (idx >= 0 && idx < animation->get_track_count()) {
undo_redo->create_action(TTR("Remove Anim Track"));
@@ -3321,9 +3482,15 @@ 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;
@@ -3416,7 +3583,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
for (const InsertData &E : insert_data) {
// Prevent insertion of multiple tracks.
- if (E.path == p_id.path) {
+ if (E.path == p_id.path && E.type == p_id.type) {
return; // Already inserted a track this frame.
}
}
@@ -3466,7 +3633,11 @@ void AnimationTrackEditor::_insert_track(bool p_create_reset, bool p_create_bezi
}
}
-void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Transform3D &p_xform) {
+void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type, const Variant p_value) {
+ ERR_FAIL_COND(!root);
+ ERR_FAIL_COND_MSG(
+ (p_type != Animation::TYPE_POSITION_3D && p_type != Animation::TYPE_ROTATION_3D && p_type != Animation::TYPE_SCALE_3D),
+ "Track type must be Position/Rotation/Scale 3D.");
if (!keying) {
return;
}
@@ -3474,7 +3645,6 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_
return;
}
- ERR_FAIL_COND(!root);
// Let's build a node path.
String path = root->get_path_to(p_node);
if (p_sub != "") {
@@ -3486,53 +3656,44 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_
int track_idx = -1;
for (int i = 0; i < animation->get_track_count(); i++) {
- if (animation->track_get_type(i) != Animation::TYPE_TRANSFORM3D) {
+ if (animation->track_get_path(i) != np) {
continue;
}
- if (animation->track_get_path(i) != np) {
+ if (animation->track_get_type(i) != p_type) {
continue;
}
-
track_idx = i;
- break;
}
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 = track_idx;
+ id.value = p_value;
+ id.type = p_type;
_query_insert(id);
}
-bool AnimationTrackEditor::has_transform_track(Node3D *p_node, const String &p_sub) {
+bool AnimationTrackEditor::has_track(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type) {
+ ERR_FAIL_COND_V(!root, false);
if (!keying) {
return false;
}
if (!animation.is_valid()) {
return false;
}
- if (!root) {
- return false;
- }
- //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;
}
- int track_id = animation->find_track(path);
+
+ int track_id = animation->find_track(path, p_type);
if (track_id >= 0) {
- if (animation->track_get_type(track_id) == Animation::TYPE_TRANSFORM3D) {
- return true;
- }
+ return true;
}
return false;
}
@@ -3977,18 +4138,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);
@@ -4064,7 +4221,7 @@ bool AnimationTrackEditor::is_selection_active() const {
}
bool AnimationTrackEditor::is_snap_enabled() const {
- return snap->is_pressed() ^ Input::get_singleton()->is_key_pressed(KEY_CTRL);
+ return snap->is_pressed() ^ Input::get_singleton()->is_key_pressed(Key::CTRL);
}
void AnimationTrackEditor::_update_tracks() {
@@ -4404,8 +4561,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;
}
@@ -4415,7 +4577,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);
@@ -4584,7 +4755,27 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
}
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;
@@ -4596,18 +4787,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;
@@ -4638,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);
@@ -4994,27 +5203,27 @@ void AnimationTrackEditor::_box_selection_draw() {
void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
scroll->accept_event();
}
- if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05);
scroll->accept_event();
}
- if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP) {
goto_prev_step(true);
scroll->accept_event();
}
- if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN) {
goto_next_step(true);
scroll->accept_event();
}
- if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
box_selecting = true;
box_selecting_from = scroll->get_global_transform().xform(mb->get_position());
@@ -5042,12 +5251,12 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
+ if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_MIDDLE) != MouseButton::NONE) {
timeline->set_value(timeline->get_value() - mm->get_relative().x / timeline->get_zoom_scale());
}
if (mm.is_valid() && box_selecting) {
- if (!(mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT)) {
+ if ((mm->get_button_mask() & MouseButton::MASK_LEFT) == MouseButton::NONE) {
// No longer.
box_selection->hide();
box_selecting = false;
@@ -5196,7 +5405,7 @@ void AnimationTrackEditor::goto_prev_step(bool p_from_mouse_event) {
if (step == 0) {
step = 1;
}
- if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
// Use more precise snapping when holding Shift.
// This is used when scrobbling the timeline using Alt + Mouse wheel.
step *= 0.25;
@@ -5219,7 +5428,7 @@ void AnimationTrackEditor::goto_next_step(bool p_from_mouse_event) {
if (step == 0) {
step = 1;
}
- if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
// Use more precise snapping when holding Shift.
// This is used when scrobbling the timeline using Alt + Mouse wheel.
// Do not use precise snapping when using the menu action or keyboard shortcut,
@@ -5277,8 +5486,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)";
@@ -5646,7 +5864,7 @@ float AnimationTrackEditor::snap_time(float p_value, bool p_relative) {
snap_increment = step->get_value();
}
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
// Use more precise snapping when holding Shift.
snap_increment *= 0.25;
}
@@ -5760,10 +5978,10 @@ void AnimationTrackEditor::_pick_track_filter_input(const Ref<InputEvent> &p_ie)
if (k.is_valid()) {
switch (k->get_keycode()) {
- case KEY_UP:
- case KEY_DOWN:
- case KEY_PAGEUP:
- case KEY_PAGEDOWN: {
+ case Key::UP:
+ case Key::DOWN:
+ case Key::PAGEUP:
+ case Key::PAGEDOWN: {
pick_track->get_scene_tree()->get_scene_tree()->gui_input(k);
pick_track->get_filter_line_edit()->accept_event();
} break;
@@ -5924,14 +6142,14 @@ AnimationTrackEditor::AnimationTrackEditor() {
edit->get_popup()->add_item(TTR("Scale Selection"), EDIT_SCALE_SELECTION);
edit->get_popup()->add_item(TTR("Scale From Cursor"), EDIT_SCALE_FROM_CURSOR);
edit->get_popup()->add_separator();
- edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection", TTR("Duplicate Selection"), KEY_MASK_CMD | KEY_D), EDIT_DUPLICATE_SELECTION);
- edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection_transposed", TTR("Duplicate Transposed"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_D), EDIT_DUPLICATE_TRANSPOSED);
+ edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection", TTR("Duplicate Selection"), KeyModifierMask::CMD | Key::D), EDIT_DUPLICATE_SELECTION);
+ edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection_transposed", TTR("Duplicate Transposed"), KeyModifierMask::SHIFT | KeyModifierMask::CMD | Key::D), EDIT_DUPLICATE_TRANSPOSED);
edit->get_popup()->add_separator();
- edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/delete_selection", TTR("Delete Selection"), KEY_DELETE), EDIT_DELETE_SELECTION);
+ edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/delete_selection", TTR("Delete Selection"), Key::KEY_DELETE), EDIT_DELETE_SELECTION);
edit->get_popup()->add_separator();
- edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Go to Next Step"), KEY_MASK_CMD | KEY_RIGHT), EDIT_GOTO_NEXT_STEP);
- edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Go to Previous Step"), KEY_MASK_CMD | KEY_LEFT), EDIT_GOTO_PREV_STEP);
+ edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Go to Next Step"), KeyModifierMask::CMD | Key::RIGHT), EDIT_GOTO_NEXT_STEP);
+ edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Go to Previous Step"), KeyModifierMask::CMD | Key::LEFT), EDIT_GOTO_PREV_STEP);
edit->get_popup()->add_separator();
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/apply_reset", TTR("Apply Reset")), EDIT_APPLY_RESET);
edit->get_popup()->add_separator();