Browse Source

Add support for FPS snap in Animation Editor.

(cherry picked from commit 42032669238bdc807bc7b8f03fff87e6cb5847f1)
Juan Linietsky 6 years ago
parent
commit
6fac922bff

+ 159 - 20
editor/animation_track_editor.cpp

@@ -109,9 +109,17 @@ public:
 		ERR_FAIL_COND_V(key == -1, false);
 
 		String name = p_name;
-		if (name == "time") {
+		if (name == "time" || name == "frame") {
 
 			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)
 				return true;
 
@@ -413,6 +421,13 @@ public:
 		if (name == "time") {
 			r_ret = key_ofs;
 			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") {
 			r_ret = animation->track_get_key_transition(track, key);
 			return true;
@@ -527,7 +542,12 @@ public:
 		int key = animation->track_find_key(track, key_ofs, true);
 		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)) {
 
@@ -648,6 +668,7 @@ public:
 
 	PropertyInfo hint;
 	NodePath base;
+	bool use_fps;
 
 	void notify_change() {
 
@@ -658,7 +679,13 @@ public:
 		return root_path;
 	}
 
+	void set_use_fps(bool p_enable) {
+		use_fps = p_enable;
+		_change_notify();
+	}
+
 	AnimationTrackKeyEdit() {
+		use_fps = false;
 		key_ofs = 0;
 		track = -1;
 		setting = false;
@@ -887,20 +914,49 @@ void AnimationTimelineEdit::_notification(int p_what) {
 				decimals = 0;
 		}
 
-		for (int i = 0; i < zoomw; i++) {
+		if (use_fps) {
+
+			float step_size = animation->get_step();
+			if (step_size > 0) {
+
+				int prev_frame_ofs = -10000000;
+
+				for (int i = 0; i < zoomw; i++) {
+
+					float pos = get_value() + double(i) / scale;
+					float prev = get_value() + (double(i) - 1.0) / scale;
+
+					int frame = pos / step_size;
+					int prev_frame = prev / step_size;
 
-			float pos = get_value() + double(i) / scale;
-			float prev = get_value() + (double(i) - 1.0) / scale;
+					bool sub = Math::floor(prev) == Math::floor(pos);
 
-			int sc = int(Math::floor(pos * SC_ADJ));
-			int prev_sc = int(Math::floor(prev * SC_ADJ));
-			bool sub = (sc % SC_ADJ);
+					if (frame != prev_frame && i >= prev_frame_ofs) {
 
-			if ((sc / step) != (prev_sc / step) || (prev_sc < 0 && sc >= 0)) {
+						draw_line(Point2(get_name_limit() + i, 0), Point2(get_name_limit() + i, h), linecolor);
 
-				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);
+						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) {
 
 	hscroll = p_hscroll;
@@ -1072,6 +1136,7 @@ void AnimationTimelineEdit::_bind_methods() {
 
 AnimationTimelineEdit::AnimationTimelineEdit() {
 
+	use_fps = false;
 	editing = false;
 	name_limit = 150;
 	zoom = NULL;
@@ -2462,7 +2527,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) {
 		hscroll->show();
 		edit->set_disabled(false);
 		step->set_block_signals(true);
-		step->set_value(animation->get_step());
+
+		_update_step_spinbox();
 		step->set_block_signals(false);
 		step->set_read_only(false);
 		snap->set_disabled(false);
@@ -2520,6 +2586,43 @@ void AnimationTrackEditor::update_keying() {
 bool AnimationTrackEditor::has_keying() const {
 	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() {
 	set_animation(Ref<Animation>());
@@ -3419,6 +3522,31 @@ void AnimationTrackEditor::_animation_changed() {
 	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() {
 
 	timeline->update();
@@ -3456,9 +3584,7 @@ void AnimationTrackEditor::_animation_update() {
 
 	bezier_edit->update();
 
-	step->set_block_signals(true);
-	step->set_value(animation->get_step());
-	step->set_block_signals(false);
+	_update_step_spinbox();
 
 	animation_changing_awaiting_update = false;
 }
@@ -3499,12 +3625,18 @@ void AnimationTrackEditor::_update_scroll(double) {
 void AnimationTrackEditor::_update_step(double p_new_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());
 	step->set_block_signals(true);
 	undo_redo->commit_action();
 	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) {
@@ -4789,6 +4921,7 @@ void AnimationTrackEditor::_bind_methods() {
 	ClassDB::bind_method("_edit_menu_pressed", &AnimationTrackEditor::_edit_menu_pressed);
 	ClassDB::bind_method("_view_group_toggle", &AnimationTrackEditor::_view_group_toggle);
 	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("keying_changed"));
@@ -4877,7 +5010,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
 	bottom_hb->add_child(memnew(VSeparator));
 
 	snap = memnew(ToolButton);
-	snap->set_text(TTR("Snap (s): "));
+	snap->set_text(TTR("Snap: "));
 	bottom_hb->add_child(snap);
 	snap->set_disabled(true);
 	snap->set_toggle_mode(true);
@@ -4885,7 +5018,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
 
 	step = memnew(EditorSpinSlider);
 	step->set_min(0);
-	step->set_max(1000);
+	step->set_max(1000000);
 	step->set_step(0.01);
 	step->set_hide_slider(true);
 	step->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
@@ -4894,6 +5027,12 @@ AnimationTrackEditor::AnimationTrackEditor() {
 	step->connect("value_changed", this, "_update_step");
 	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));
 
 	zoom_icon = memnew(TextureRect);

+ 11 - 0
editor/animation_track_editor.h

@@ -76,6 +76,7 @@ class AnimationTimelineEdit : public Range {
 	Rect2 hsize_rect;
 
 	bool editing;
+	bool use_fps;
 
 	bool panning_timeline;
 	float panning_timeline_from;
@@ -110,6 +111,9 @@ public:
 
 	void update_values();
 
+	void set_use_fps(bool p_use_fps);
+	bool is_using_fps() const;
+
 	void set_hscroll(HScrollBar *p_hscroll);
 
 	AnimationTimelineEdit();
@@ -303,7 +307,9 @@ class AnimationTrackEditor : public VBoxContainer {
 	EditorSpinSlider *step;
 	TextureRect *zoom_icon;
 	ToolButton *snap;
+	OptionButton *snap_mode;
 
+	void _snap_mode_changed(int p_mode);
 	Vector<AnimationTrackEdit *> track_edits;
 	Vector<AnimationTrackEditGroup *> groups;
 
@@ -328,6 +334,8 @@ class AnimationTrackEditor : public VBoxContainer {
 	void _new_track_node_selected(NodePath p_path);
 	void _new_track_property_selected(String p_name);
 
+	void _update_step_spinbox();
+
 	PropertySelector *prop_selector;
 	PropertySelector *method_selector;
 	SceneTreeDialog *pick_track;
@@ -484,6 +492,9 @@ public:
 	void update_keying();
 	bool has_keying() const;
 
+	Dictionary get_state() const;
+	void set_state(const Dictionary &p_state);
+
 	void cleanup();
 
 	void set_anim_pos(float p_pos);

+ 5 - 0
editor/plugins/animation_player_editor_plugin.cpp

@@ -670,6 +670,7 @@ Dictionary AnimationPlayerEditor::get_state() const {
 	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["animation"] = player->get_assigned_animation();
+		d["track_editor_state"] = track_editor->get_state();
 	}
 
 	return d;
@@ -696,6 +697,10 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) {
 				_animation_edit();
 			}
 		}
+
+		if (p_state.has("track_editor_state")) {
+			track_editor->set_state(p_state["track_editor_state"]);
+		}
 	}
 }