Add support for FPS snap in Animation Editor.
This commit is contained in:
parent
3f76d2c2f3
commit
4203266923
|
@ -109,9 +109,17 @@ public:
|
||||||
ERR_FAIL_COND_V(key == -1, false);
|
ERR_FAIL_COND_V(key == -1, false);
|
||||||
|
|
||||||
String name = p_name;
|
String name = p_name;
|
||||||
if (name == "time") {
|
if (name == "time" || name == "frame") {
|
||||||
|
|
||||||
float new_time = p_value;
|
float new_time = p_value;
|
||||||
|
|
||||||
|
if (name == "frame") {
|
||||||
|
float fps = animation->get_step();
|
||||||
|
if (fps > 0) {
|
||||||
|
fps = 1.0 / fps;
|
||||||
|
}
|
||||||
|
new_time /= fps;
|
||||||
|
}
|
||||||
if (new_time == key_ofs)
|
if (new_time == key_ofs)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -413,6 +421,13 @@ public:
|
||||||
if (name == "time") {
|
if (name == "time") {
|
||||||
r_ret = key_ofs;
|
r_ret = key_ofs;
|
||||||
return true;
|
return true;
|
||||||
|
} else if (name == "frame") {
|
||||||
|
float fps = animation->get_step();
|
||||||
|
if (fps > 0) {
|
||||||
|
fps = 1.0 / fps;
|
||||||
|
}
|
||||||
|
r_ret = key_ofs * fps;
|
||||||
|
return true;
|
||||||
} else if (name == "easing") {
|
} else if (name == "easing") {
|
||||||
r_ret = animation->track_get_key_transition(track, key);
|
r_ret = animation->track_get_key_transition(track, key);
|
||||||
return true;
|
return true;
|
||||||
|
@ -527,7 +542,12 @@ public:
|
||||||
int key = animation->track_find_key(track, key_ofs, true);
|
int key = animation->track_find_key(track, key_ofs, true);
|
||||||
ERR_FAIL_COND(key == -1);
|
ERR_FAIL_COND(key == -1);
|
||||||
|
|
||||||
p_list->push_back(PropertyInfo(Variant::REAL, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
|
if (use_fps && animation->get_step() > 0) {
|
||||||
|
float max_frame = animation->get_length() / animation->get_step();
|
||||||
|
p_list->push_back(PropertyInfo(Variant::REAL, "frame", PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",0.01"));
|
||||||
|
} else {
|
||||||
|
p_list->push_back(PropertyInfo(Variant::REAL, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
|
||||||
|
}
|
||||||
|
|
||||||
switch (animation->track_get_type(track)) {
|
switch (animation->track_get_type(track)) {
|
||||||
|
|
||||||
|
@ -648,6 +668,7 @@ public:
|
||||||
|
|
||||||
PropertyInfo hint;
|
PropertyInfo hint;
|
||||||
NodePath base;
|
NodePath base;
|
||||||
|
bool use_fps;
|
||||||
|
|
||||||
void notify_change() {
|
void notify_change() {
|
||||||
|
|
||||||
|
@ -658,7 +679,13 @@ public:
|
||||||
return root_path;
|
return root_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_use_fps(bool p_enable) {
|
||||||
|
use_fps = p_enable;
|
||||||
|
_change_notify();
|
||||||
|
}
|
||||||
|
|
||||||
AnimationTrackKeyEdit() {
|
AnimationTrackKeyEdit() {
|
||||||
|
use_fps = false;
|
||||||
key_ofs = 0;
|
key_ofs = 0;
|
||||||
track = -1;
|
track = -1;
|
||||||
setting = false;
|
setting = false;
|
||||||
|
@ -887,20 +914,49 @@ void AnimationTimelineEdit::_notification(int p_what) {
|
||||||
decimals = 0;
|
decimals = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < zoomw; i++) {
|
if (use_fps) {
|
||||||
|
|
||||||
float pos = get_value() + double(i) / scale;
|
float step_size = animation->get_step();
|
||||||
float prev = get_value() + (double(i) - 1.0) / scale;
|
if (step_size > 0) {
|
||||||
|
|
||||||
int sc = int(Math::floor(pos * SC_ADJ));
|
int prev_frame_ofs = -10000000;
|
||||||
int prev_sc = int(Math::floor(prev * SC_ADJ));
|
|
||||||
bool sub = (sc % SC_ADJ);
|
|
||||||
|
|
||||||
if ((sc / step) != (prev_sc / step) || (prev_sc < 0 && sc >= 0)) {
|
for (int i = 0; i < zoomw; i++) {
|
||||||
|
|
||||||
int scd = sc < 0 ? prev_sc : sc;
|
float pos = get_value() + double(i) / scale;
|
||||||
draw_line(Point2(get_name_limit() + i, 0), Point2(get_name_limit() + i, h), linecolor);
|
float prev = get_value() + (double(i) - 1.0) / scale;
|
||||||
draw_string(font, Point2(get_name_limit() + i + 3, (h - font->get_height()) / 2 + font->get_ascent()).floor(), String::num((scd - (scd % step)) / double(SC_ADJ), decimals), sub ? color_time_dec : color_time_sec, zoomw - i);
|
|
||||||
|
int frame = pos / step_size;
|
||||||
|
int prev_frame = prev / step_size;
|
||||||
|
|
||||||
|
bool sub = Math::floor(prev) == Math::floor(pos);
|
||||||
|
|
||||||
|
if (frame != prev_frame && i >= prev_frame_ofs) {
|
||||||
|
|
||||||
|
draw_line(Point2(get_name_limit() + i, 0), Point2(get_name_limit() + i, h), linecolor);
|
||||||
|
|
||||||
|
draw_string(font, Point2(get_name_limit() + i + 3 * EDSCALE, (h - font->get_height()) / 2 + font->get_ascent()).floor(), itos(frame), sub ? color_time_dec : color_time_sec, zoomw - i);
|
||||||
|
prev_frame_ofs = i + font->get_string_size(itos(frame)).x + 5 * EDSCALE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < zoomw; i++) {
|
||||||
|
|
||||||
|
float pos = get_value() + double(i) / scale;
|
||||||
|
float prev = get_value() + (double(i) - 1.0) / scale;
|
||||||
|
|
||||||
|
int sc = int(Math::floor(pos * SC_ADJ));
|
||||||
|
int prev_sc = int(Math::floor(prev * SC_ADJ));
|
||||||
|
bool sub = (sc % SC_ADJ);
|
||||||
|
|
||||||
|
if ((sc / step) != (prev_sc / step) || (prev_sc < 0 && sc >= 0)) {
|
||||||
|
|
||||||
|
int scd = sc < 0 ? prev_sc : sc;
|
||||||
|
draw_line(Point2(get_name_limit() + i, 0), Point2(get_name_limit() + i, h), linecolor);
|
||||||
|
draw_string(font, Point2(get_name_limit() + i + 3, (h - font->get_height()) / 2 + font->get_ascent()).floor(), String::num((scd - (scd % step)) / double(SC_ADJ), decimals), sub ? color_time_dec : color_time_sec, zoomw - i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1046,6 +1102,14 @@ void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimationTimelineEdit::set_use_fps(bool p_use_fps) {
|
||||||
|
use_fps = p_use_fps;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
bool AnimationTimelineEdit::is_using_fps() const {
|
||||||
|
return use_fps;
|
||||||
|
}
|
||||||
|
|
||||||
void AnimationTimelineEdit::set_hscroll(HScrollBar *p_hscroll) {
|
void AnimationTimelineEdit::set_hscroll(HScrollBar *p_hscroll) {
|
||||||
|
|
||||||
hscroll = p_hscroll;
|
hscroll = p_hscroll;
|
||||||
|
@ -1072,6 +1136,7 @@ void AnimationTimelineEdit::_bind_methods() {
|
||||||
|
|
||||||
AnimationTimelineEdit::AnimationTimelineEdit() {
|
AnimationTimelineEdit::AnimationTimelineEdit() {
|
||||||
|
|
||||||
|
use_fps = false;
|
||||||
editing = false;
|
editing = false;
|
||||||
name_limit = 150;
|
name_limit = 150;
|
||||||
zoom = NULL;
|
zoom = NULL;
|
||||||
|
@ -2462,7 +2527,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) {
|
||||||
hscroll->show();
|
hscroll->show();
|
||||||
edit->set_disabled(false);
|
edit->set_disabled(false);
|
||||||
step->set_block_signals(true);
|
step->set_block_signals(true);
|
||||||
step->set_value(animation->get_step());
|
|
||||||
|
_update_step_spinbox();
|
||||||
step->set_block_signals(false);
|
step->set_block_signals(false);
|
||||||
step->set_read_only(false);
|
step->set_read_only(false);
|
||||||
snap->set_disabled(false);
|
snap->set_disabled(false);
|
||||||
|
@ -2518,6 +2584,43 @@ void AnimationTrackEditor::update_keying() {
|
||||||
bool AnimationTrackEditor::has_keying() const {
|
bool AnimationTrackEditor::has_keying() const {
|
||||||
return keying;
|
return keying;
|
||||||
}
|
}
|
||||||
|
Dictionary AnimationTrackEditor::get_state() const {
|
||||||
|
Dictionary state;
|
||||||
|
state["fps_mode"] = timeline->is_using_fps();
|
||||||
|
state["zoom"] = zoom->get_value();
|
||||||
|
state["offset"] = timeline->get_value();
|
||||||
|
state["v_scroll"] = scroll->get_v_scrollbar()->get_value();
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
void AnimationTrackEditor::set_state(const Dictionary &p_state) {
|
||||||
|
if (p_state.has("fps_mode")) {
|
||||||
|
bool fps_mode = p_state["fps_mode"];
|
||||||
|
if (fps_mode) {
|
||||||
|
snap_mode->select(1);
|
||||||
|
} else {
|
||||||
|
snap_mode->select(0);
|
||||||
|
}
|
||||||
|
_snap_mode_changed(snap_mode->get_selected());
|
||||||
|
} else {
|
||||||
|
snap_mode->select(0);
|
||||||
|
_snap_mode_changed(snap_mode->get_selected());
|
||||||
|
}
|
||||||
|
if (p_state.has("zoom")) {
|
||||||
|
zoom->set_value(p_state["zoom"]);
|
||||||
|
} else {
|
||||||
|
zoom->set_value(1.0);
|
||||||
|
}
|
||||||
|
if (p_state.has("offset")) {
|
||||||
|
timeline->set_value(p_state["offset"]);
|
||||||
|
} else {
|
||||||
|
timeline->set_value(0);
|
||||||
|
}
|
||||||
|
if (p_state.has("v_scroll")) {
|
||||||
|
scroll->get_v_scrollbar()->set_value(p_state["v_scroll"]);
|
||||||
|
} else {
|
||||||
|
scroll->get_v_scrollbar()->set_value(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AnimationTrackEditor::cleanup() {
|
void AnimationTrackEditor::cleanup() {
|
||||||
set_animation(Ref<Animation>());
|
set_animation(Ref<Animation>());
|
||||||
|
@ -3417,6 +3520,31 @@ void AnimationTrackEditor::_animation_changed() {
|
||||||
call_deferred("_animation_update");
|
call_deferred("_animation_update");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimationTrackEditor::_snap_mode_changed(int p_mode) {
|
||||||
|
|
||||||
|
timeline->set_use_fps(p_mode == 1);
|
||||||
|
if (key_edit) {
|
||||||
|
key_edit->set_use_fps(p_mode == 1);
|
||||||
|
}
|
||||||
|
_update_step_spinbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationTrackEditor::_update_step_spinbox() {
|
||||||
|
step->set_block_signals(true);
|
||||||
|
|
||||||
|
if (timeline->is_using_fps()) {
|
||||||
|
if (animation->get_step() == 0) {
|
||||||
|
step->set_value(0);
|
||||||
|
} else {
|
||||||
|
step->set_value(1.0 / animation->get_step());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
step->set_value(animation->get_step());
|
||||||
|
}
|
||||||
|
|
||||||
|
step->set_block_signals(false);
|
||||||
|
}
|
||||||
void AnimationTrackEditor::_animation_update() {
|
void AnimationTrackEditor::_animation_update() {
|
||||||
|
|
||||||
timeline->update();
|
timeline->update();
|
||||||
|
@ -3454,9 +3582,7 @@ void AnimationTrackEditor::_animation_update() {
|
||||||
|
|
||||||
bezier_edit->update();
|
bezier_edit->update();
|
||||||
|
|
||||||
step->set_block_signals(true);
|
_update_step_spinbox();
|
||||||
step->set_value(animation->get_step());
|
|
||||||
step->set_block_signals(false);
|
|
||||||
|
|
||||||
animation_changing_awaiting_update = false;
|
animation_changing_awaiting_update = false;
|
||||||
}
|
}
|
||||||
|
@ -3497,12 +3623,18 @@ void AnimationTrackEditor::_update_scroll(double) {
|
||||||
void AnimationTrackEditor::_update_step(double p_new_step) {
|
void AnimationTrackEditor::_update_step(double p_new_step) {
|
||||||
|
|
||||||
undo_redo->create_action(TTR("Change Animation Step"));
|
undo_redo->create_action(TTR("Change Animation Step"));
|
||||||
undo_redo->add_do_method(animation.ptr(), "set_step", p_new_step);
|
float step_value = p_new_step;
|
||||||
|
if (timeline->is_using_fps()) {
|
||||||
|
if (step_value != 0.0) {
|
||||||
|
step_value = 1.0 / step_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
undo_redo->add_do_method(animation.ptr(), "set_step", step_value);
|
||||||
undo_redo->add_undo_method(animation.ptr(), "set_step", animation->get_step());
|
undo_redo->add_undo_method(animation.ptr(), "set_step", animation->get_step());
|
||||||
step->set_block_signals(true);
|
step->set_block_signals(true);
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
step->set_block_signals(false);
|
step->set_block_signals(false);
|
||||||
emit_signal("animation_step_changed", p_new_step);
|
emit_signal("animation_step_changed", step_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationTrackEditor::_update_length(double p_new_len) {
|
void AnimationTrackEditor::_update_length(double p_new_len) {
|
||||||
|
@ -4787,6 +4919,7 @@ void AnimationTrackEditor::_bind_methods() {
|
||||||
ClassDB::bind_method("_edit_menu_pressed", &AnimationTrackEditor::_edit_menu_pressed);
|
ClassDB::bind_method("_edit_menu_pressed", &AnimationTrackEditor::_edit_menu_pressed);
|
||||||
ClassDB::bind_method("_view_group_toggle", &AnimationTrackEditor::_view_group_toggle);
|
ClassDB::bind_method("_view_group_toggle", &AnimationTrackEditor::_view_group_toggle);
|
||||||
ClassDB::bind_method("_selection_changed", &AnimationTrackEditor::_selection_changed);
|
ClassDB::bind_method("_selection_changed", &AnimationTrackEditor::_selection_changed);
|
||||||
|
ClassDB::bind_method("_snap_mode_changed", &AnimationTrackEditor::_snap_mode_changed);
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::REAL, "position"), PropertyInfo(Variant::BOOL, "drag")));
|
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::REAL, "position"), PropertyInfo(Variant::BOOL, "drag")));
|
||||||
ADD_SIGNAL(MethodInfo("keying_changed"));
|
ADD_SIGNAL(MethodInfo("keying_changed"));
|
||||||
|
@ -4875,7 +5008,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
||||||
bottom_hb->add_child(memnew(VSeparator));
|
bottom_hb->add_child(memnew(VSeparator));
|
||||||
|
|
||||||
snap = memnew(ToolButton);
|
snap = memnew(ToolButton);
|
||||||
snap->set_text(TTR("Snap (s): "));
|
snap->set_text(TTR("Snap: "));
|
||||||
bottom_hb->add_child(snap);
|
bottom_hb->add_child(snap);
|
||||||
snap->set_disabled(true);
|
snap->set_disabled(true);
|
||||||
snap->set_toggle_mode(true);
|
snap->set_toggle_mode(true);
|
||||||
|
@ -4883,7 +5016,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
||||||
|
|
||||||
step = memnew(EditorSpinSlider);
|
step = memnew(EditorSpinSlider);
|
||||||
step->set_min(0);
|
step->set_min(0);
|
||||||
step->set_max(1000);
|
step->set_max(1000000);
|
||||||
step->set_step(0.01);
|
step->set_step(0.01);
|
||||||
step->set_hide_slider(true);
|
step->set_hide_slider(true);
|
||||||
step->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
|
step->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
|
||||||
|
@ -4892,6 +5025,12 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
||||||
step->connect("value_changed", this, "_update_step");
|
step->connect("value_changed", this, "_update_step");
|
||||||
step->set_read_only(true);
|
step->set_read_only(true);
|
||||||
|
|
||||||
|
snap_mode = memnew(OptionButton);
|
||||||
|
snap_mode->add_item(TTR("Seconds"));
|
||||||
|
snap_mode->add_item(TTR("FPS"));
|
||||||
|
bottom_hb->add_child(snap_mode);
|
||||||
|
snap_mode->connect("item_selected", this, "_snap_mode_changed");
|
||||||
|
|
||||||
bottom_hb->add_child(memnew(VSeparator));
|
bottom_hb->add_child(memnew(VSeparator));
|
||||||
|
|
||||||
zoom_icon = memnew(TextureRect);
|
zoom_icon = memnew(TextureRect);
|
||||||
|
|
|
@ -76,6 +76,7 @@ class AnimationTimelineEdit : public Range {
|
||||||
Rect2 hsize_rect;
|
Rect2 hsize_rect;
|
||||||
|
|
||||||
bool editing;
|
bool editing;
|
||||||
|
bool use_fps;
|
||||||
|
|
||||||
bool panning_timeline;
|
bool panning_timeline;
|
||||||
float panning_timeline_from;
|
float panning_timeline_from;
|
||||||
|
@ -110,6 +111,9 @@ public:
|
||||||
|
|
||||||
void update_values();
|
void update_values();
|
||||||
|
|
||||||
|
void set_use_fps(bool p_use_fps);
|
||||||
|
bool is_using_fps() const;
|
||||||
|
|
||||||
void set_hscroll(HScrollBar *p_hscroll);
|
void set_hscroll(HScrollBar *p_hscroll);
|
||||||
|
|
||||||
AnimationTimelineEdit();
|
AnimationTimelineEdit();
|
||||||
|
@ -303,7 +307,9 @@ class AnimationTrackEditor : public VBoxContainer {
|
||||||
EditorSpinSlider *step;
|
EditorSpinSlider *step;
|
||||||
TextureRect *zoom_icon;
|
TextureRect *zoom_icon;
|
||||||
ToolButton *snap;
|
ToolButton *snap;
|
||||||
|
OptionButton *snap_mode;
|
||||||
|
|
||||||
|
void _snap_mode_changed(int p_mode);
|
||||||
Vector<AnimationTrackEdit *> track_edits;
|
Vector<AnimationTrackEdit *> track_edits;
|
||||||
Vector<AnimationTrackEditGroup *> groups;
|
Vector<AnimationTrackEditGroup *> groups;
|
||||||
|
|
||||||
|
@ -328,6 +334,8 @@ class AnimationTrackEditor : public VBoxContainer {
|
||||||
void _new_track_node_selected(NodePath p_path);
|
void _new_track_node_selected(NodePath p_path);
|
||||||
void _new_track_property_selected(String p_name);
|
void _new_track_property_selected(String p_name);
|
||||||
|
|
||||||
|
void _update_step_spinbox();
|
||||||
|
|
||||||
PropertySelector *prop_selector;
|
PropertySelector *prop_selector;
|
||||||
PropertySelector *method_selector;
|
PropertySelector *method_selector;
|
||||||
SceneTreeDialog *pick_track;
|
SceneTreeDialog *pick_track;
|
||||||
|
@ -484,6 +492,9 @@ public:
|
||||||
void update_keying();
|
void update_keying();
|
||||||
bool has_keying() const;
|
bool has_keying() const;
|
||||||
|
|
||||||
|
Dictionary get_state() const;
|
||||||
|
void set_state(const Dictionary &p_state);
|
||||||
|
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
void set_anim_pos(float p_pos);
|
void set_anim_pos(float p_pos);
|
||||||
|
|
|
@ -670,6 +670,7 @@ Dictionary AnimationPlayerEditor::get_state() const {
|
||||||
if (EditorNode::get_singleton()->get_edited_scene() && is_visible_in_tree() && player) {
|
if (EditorNode::get_singleton()->get_edited_scene() && is_visible_in_tree() && player) {
|
||||||
d["player"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(player);
|
d["player"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(player);
|
||||||
d["animation"] = player->get_assigned_animation();
|
d["animation"] = player->get_assigned_animation();
|
||||||
|
d["track_editor_state"] = track_editor->get_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
|
@ -696,6 +697,10 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) {
|
||||||
_animation_edit();
|
_animation_edit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_state.has("track_editor_state")) {
|
||||||
|
track_editor->set_state(p_state["track_editor_state"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue