| 
									
										
										
										
											2017-04-28 20:04:09 +02:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*  curve_editor_plugin.cpp                                              */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							| 
									
										
										
										
											2017-08-27 14:16:55 +02:00
										 |  |  | /*                      https://godotengine.org                          */ | 
					
						
							| 
									
										
										
										
											2017-04-28 20:04:09 +02:00
										 |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2021-01-01 20:13:46 +01:00
										 |  |  | /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							|  |  |  | /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ | 
					
						
							| 
									
										
										
										
											2017-04-28 20:04:09 +02:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the       */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including   */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to */ | 
					
						
							|  |  |  | /* the following conditions:                                             */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be        */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.       */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | #include "curve_editor_plugin.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "canvas_item_editor_plugin.h"
 | 
					
						
							| 
									
										
										
										
											2018-09-11 18:13:45 +02:00
										 |  |  | #include "core/core_string_names.h"
 | 
					
						
							|  |  |  | #include "core/os/input.h"
 | 
					
						
							|  |  |  | #include "core/os/keyboard.h"
 | 
					
						
							| 
									
										
										
										
											2019-12-24 15:17:23 +08:00
										 |  |  | #include "editor/editor_scale.h"
 | 
					
						
							| 
									
										
										
										
											2017-04-28 20:04:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | CurveEditor::CurveEditor() { | 
					
						
							|  |  |  | 	_selected_point = -1; | 
					
						
							|  |  |  | 	_hover_point = -1; | 
					
						
							|  |  |  | 	_selected_tangent = TANGENT_NONE; | 
					
						
							|  |  |  | 	_hover_radius = 6; | 
					
						
							|  |  |  | 	_tangents_length = 40; | 
					
						
							|  |  |  | 	_dragging = false; | 
					
						
							|  |  |  | 	_has_undo_data = false; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	set_focus_mode(FOCUS_ALL); | 
					
						
							|  |  |  | 	set_clip_contents(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_context_menu = memnew(PopupMenu); | 
					
						
							|  |  |  | 	_context_menu->connect("id_pressed", this, "_on_context_menu_item_selected"); | 
					
						
							|  |  |  | 	add_child(_context_menu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_presets_menu = memnew(PopupMenu); | 
					
						
							|  |  |  | 	_presets_menu->set_name("_presets_menu"); | 
					
						
							| 
									
										
										
										
											2019-03-25 01:54:29 +01:00
										 |  |  | 	_presets_menu->add_item(TTR("Flat 0"), PRESET_FLAT0); | 
					
						
							|  |  |  | 	_presets_menu->add_item(TTR("Flat 1"), PRESET_FLAT1); | 
					
						
							| 
									
										
										
										
											2017-10-02 14:39:12 +07:00
										 |  |  | 	_presets_menu->add_item(TTR("Linear"), PRESET_LINEAR); | 
					
						
							| 
									
										
										
										
											2019-03-25 01:54:29 +01:00
										 |  |  | 	_presets_menu->add_item(TTR("Ease In"), PRESET_EASE_IN); | 
					
						
							|  |  |  | 	_presets_menu->add_item(TTR("Ease Out"), PRESET_EASE_OUT); | 
					
						
							| 
									
										
										
										
											2017-10-02 14:39:12 +07:00
										 |  |  | 	_presets_menu->add_item(TTR("Smoothstep"), PRESET_SMOOTHSTEP); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	_presets_menu->connect("id_pressed", this, "_on_preset_item_selected"); | 
					
						
							|  |  |  | 	_context_menu->add_child(_presets_menu); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | void CurveEditor::set_curve(Ref<Curve> curve) { | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (curve == _curve_ref) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (_curve_ref.is_valid()) { | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 		_curve_ref->disconnect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); | 
					
						
							|  |  |  | 		_curve_ref->disconnect(Curve::SIGNAL_RANGE_CHANGED, this, "_curve_changed"); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	_curve_ref = curve; | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	if (_curve_ref.is_valid()) { | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 		_curve_ref->connect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); | 
					
						
							|  |  |  | 		_curve_ref->connect(Curve::SIGNAL_RANGE_CHANGED, this, "_curve_changed"); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	_selected_point = -1; | 
					
						
							|  |  |  | 	_hover_point = -1; | 
					
						
							|  |  |  | 	_selected_tangent = TANGENT_NONE; | 
					
						
							| 
									
										
										
										
											2017-05-20 12:38:03 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	update(); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	// Note: if you edit a curve, then set another, and try to undo,
 | 
					
						
							|  |  |  | 	// it will normally apply on the previous curve, but you won't see it
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Size2 CurveEditor::get_minimum_size() const { | 
					
						
							| 
									
										
										
										
											2018-05-17 18:02:16 -03:00
										 |  |  | 	return Vector2(64, 150) * EDSCALE; | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CurveEditor::_notification(int p_what) { | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (p_what == NOTIFICATION_DRAW) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		_draw(); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { | 
					
						
							|  |  |  | 	Ref<InputEventMouseButton> mb_ref = p_event; | 
					
						
							|  |  |  | 	if (mb_ref.is_valid()) { | 
					
						
							|  |  |  | 		const InputEventMouseButton &mb = **mb_ref; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		if (mb.is_pressed() && !_dragging) { | 
					
						
							|  |  |  | 			Vector2 mpos = mb.get_position(); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 			_selected_tangent = get_tangent_at(mpos); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			if (_selected_tangent == TANGENT_NONE) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 				set_selected_point(get_point_at(mpos)); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 			switch (mb.get_button_index()) { | 
					
						
							|  |  |  | 				case BUTTON_RIGHT: | 
					
						
							|  |  |  | 					_context_click_pos = mpos; | 
					
						
							|  |  |  | 					open_context_menu(get_global_transform().xform(mpos)); | 
					
						
							|  |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 				case BUTTON_MIDDLE: | 
					
						
							|  |  |  | 					remove_point(_hover_point); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				case BUTTON_LEFT: | 
					
						
							|  |  |  | 					_dragging = true; | 
					
						
							|  |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		if (!mb.is_pressed() && _dragging && mb.get_button_index() == BUTTON_LEFT) { | 
					
						
							|  |  |  | 			_dragging = false; | 
					
						
							|  |  |  | 			if (_has_undo_data) { | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 				UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				ur.create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent")); | 
					
						
							|  |  |  | 				ur.add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data()); | 
					
						
							|  |  |  | 				ur.add_undo_method(*_curve_ref, "_set_data", _undo_data); | 
					
						
							|  |  |  | 				// Note: this will trigger one more "changed" signal even if nothing changes,
 | 
					
						
							|  |  |  | 				// but it's ok since it would have fired every frame during the drag anyways
 | 
					
						
							|  |  |  | 				ur.commit_action(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 				_has_undo_data = false; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	Ref<InputEventMouseMotion> mm_ref = p_event; | 
					
						
							|  |  |  | 	if (mm_ref.is_valid()) { | 
					
						
							|  |  |  | 		const InputEventMouseMotion &mm = **mm_ref; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		Vector2 mpos = mm.get_position(); | 
					
						
							| 
									
										
										
										
											2017-05-20 12:38:03 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		if (_dragging && _curve_ref.is_valid()) { | 
					
						
							|  |  |  | 			if (_selected_point != -1) { | 
					
						
							| 
									
										
										
										
											2019-07-01 12:59:42 +02:00
										 |  |  | 				Curve &curve = **_curve_ref; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 				if (!_has_undo_data) { | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 					// Save full curve state before dragging points,
 | 
					
						
							|  |  |  | 					// because this operation can modify their order
 | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 					_undo_data = curve.get_data(); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 					_has_undo_data = true; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-02 13:58:16 +02:00
										 |  |  | 				const float curve_amplitude = curve.get_max_value() - curve.get_min_value(); | 
					
						
							|  |  |  | 				// Snap to "round" coordinates when holding Ctrl.
 | 
					
						
							|  |  |  | 				// Be more precise when holding Shift as well.
 | 
					
						
							|  |  |  | 				float snap_threshold; | 
					
						
							|  |  |  | 				if (mm.get_control()) { | 
					
						
							|  |  |  | 					snap_threshold = mm.get_shift() ? 0.025 : 0.1; | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					snap_threshold = 0.0; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 				if (_selected_tangent == TANGENT_NONE) { | 
					
						
							|  |  |  | 					// Drag point
 | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-02 13:58:16 +02:00
										 |  |  | 					Vector2 point_pos = get_world_pos(mpos).snapped(Vector2(snap_threshold, snap_threshold * curve_amplitude)); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 					int i = curve.set_point_offset(_selected_point, point_pos.x); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 					// The index may change if the point is dragged across another one
 | 
					
						
							|  |  |  | 					set_hover_point_index(i); | 
					
						
							|  |  |  | 					set_selected_point(i); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-18 21:37:17 +01:00
										 |  |  | 					// This is to prevent the user from losing a point out of view.
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 					if (point_pos.y < curve.get_min_value()) { | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 						point_pos.y = curve.get_min_value(); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 					} else if (point_pos.y > curve.get_max_value()) { | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 						point_pos.y = curve.get_max_value(); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 					curve.set_point_value(_selected_point, point_pos.y); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					// Drag tangent
 | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-02 13:58:16 +02:00
										 |  |  | 					const Vector2 point_pos = curve.get_point_position(_selected_point); | 
					
						
							|  |  |  | 					const Vector2 control_pos = get_world_pos(mpos).snapped(Vector2(snap_threshold, snap_threshold * curve_amplitude)); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					Vector2 dir = (control_pos - point_pos).normalized(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					real_t tangent; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 					if (!Math::is_zero_approx(dir.x)) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 						tangent = dir.y / dir.x; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 						tangent = 9999 * (dir.y >= 0 ? 1 : -1); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					bool link = !Input::get_singleton()->is_key_pressed(KEY_SHIFT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if (_selected_tangent == TANGENT_LEFT) { | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 						curve.set_point_left_tangent(_selected_point, tangent); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// Note: if a tangent is set to linear, it shouldn't be linked to the other
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 						if (link && _selected_point != (curve.get_point_count() - 1) && curve.get_point_right_mode(_selected_point) != Curve::TANGENT_LINEAR) { | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 							curve.set_point_right_tangent(_selected_point, tangent); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 						curve.set_point_right_tangent(_selected_point, tangent); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 						if (link && _selected_point != 0 && curve.get_point_left_mode(_selected_point) != Curve::TANGENT_LINEAR) { | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 							curve.set_point_left_tangent(_selected_point, tangent); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			set_hover_point_index(get_point_at(mpos)); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	Ref<InputEventKey> key_ref = p_event; | 
					
						
							|  |  |  | 	if (key_ref.is_valid()) { | 
					
						
							|  |  |  | 		const InputEventKey &key = **key_ref; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		if (key.is_pressed() && _selected_point != -1) { | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			if (key.get_scancode() == KEY_DELETE) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 				remove_point(_selected_point); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | void CurveEditor::on_preset_item_selected(int preset_id) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(preset_id < 0 || preset_id >= PRESET_COUNT); | 
					
						
							|  |  |  | 	ERR_FAIL_COND(_curve_ref.is_null()); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	Curve &curve = **_curve_ref; | 
					
						
							|  |  |  | 	Array previous_data = curve.get_data(); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	curve.clear_points(); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	switch (preset_id) { | 
					
						
							|  |  |  | 		case PRESET_FLAT0: | 
					
						
							|  |  |  | 			curve.add_point(Vector2(0, 0)); | 
					
						
							|  |  |  | 			curve.add_point(Vector2(1, 0)); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 			curve.set_point_right_mode(0, Curve::TANGENT_LINEAR); | 
					
						
							|  |  |  | 			curve.set_point_left_mode(1, Curve::TANGENT_LINEAR); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		case PRESET_FLAT1: | 
					
						
							|  |  |  | 			curve.add_point(Vector2(0, 1)); | 
					
						
							|  |  |  | 			curve.add_point(Vector2(1, 1)); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 			curve.set_point_right_mode(0, Curve::TANGENT_LINEAR); | 
					
						
							|  |  |  | 			curve.set_point_left_mode(1, Curve::TANGENT_LINEAR); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		case PRESET_LINEAR: | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 			curve.add_point(Vector2(0, 0)); | 
					
						
							|  |  |  | 			curve.add_point(Vector2(1, 1)); | 
					
						
							|  |  |  | 			curve.set_point_right_mode(0, Curve::TANGENT_LINEAR); | 
					
						
							|  |  |  | 			curve.set_point_left_mode(1, Curve::TANGENT_LINEAR); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		case PRESET_EASE_IN: | 
					
						
							|  |  |  | 			curve.add_point(Vector2(0, 0)); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 			curve.add_point(Vector2(1, 1), (curve.get_max_value() - curve.get_min_value()) * 1.4, 0); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		case PRESET_EASE_OUT: | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 			curve.add_point(Vector2(0, 0), 0, (curve.get_max_value() - curve.get_min_value()) * 1.4); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 			curve.add_point(Vector2(1, 1)); | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		case PRESET_SMOOTHSTEP: | 
					
						
							|  |  |  | 			curve.add_point(Vector2(0, 0)); | 
					
						
							|  |  |  | 			curve.add_point(Vector2(1, 1)); | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		default: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 	UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); | 
					
						
							|  |  |  | 	ur.create_action(TTR("Load Curve Preset")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ur.add_do_method(&curve, "_set_data", curve.get_data()); | 
					
						
							|  |  |  | 	ur.add_undo_method(&curve, "_set_data", previous_data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ur.commit_action(); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | void CurveEditor::_curve_changed() { | 
					
						
							|  |  |  | 	update(); | 
					
						
							|  |  |  | 	// Point count can change in case of undo
 | 
					
						
							|  |  |  | 	if (_selected_point >= _curve_ref->get_point_count()) { | 
					
						
							|  |  |  | 		set_selected_point(-1); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | void CurveEditor::on_context_menu_item_selected(int action_id) { | 
					
						
							|  |  |  | 	switch (action_id) { | 
					
						
							|  |  |  | 		case CONTEXT_ADD_POINT: | 
					
						
							|  |  |  | 			add_point(_context_click_pos); | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		case CONTEXT_REMOVE_POINT: | 
					
						
							|  |  |  | 			remove_point(_selected_point); | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		case CONTEXT_LINEAR: | 
					
						
							|  |  |  | 			toggle_linear(); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case CONTEXT_LEFT_LINEAR: | 
					
						
							|  |  |  | 			toggle_linear(TANGENT_LEFT); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case CONTEXT_RIGHT_LINEAR: | 
					
						
							|  |  |  | 			toggle_linear(TANGENT_RIGHT); | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CurveEditor::open_context_menu(Vector2 pos) { | 
					
						
							|  |  |  | 	_context_menu->set_position(pos); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_context_menu->clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (_curve_ref.is_valid()) { | 
					
						
							| 
									
										
										
										
											2019-03-25 01:54:29 +01:00
										 |  |  | 		_context_menu->add_item(TTR("Add Point"), CONTEXT_ADD_POINT); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		if (_selected_point >= 0) { | 
					
						
							| 
									
										
										
										
											2019-03-25 01:54:29 +01:00
										 |  |  | 			_context_menu->add_item(TTR("Remove Point"), CONTEXT_REMOVE_POINT); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (_selected_tangent != TANGENT_NONE) { | 
					
						
							|  |  |  | 				_context_menu->add_separator(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				_context_menu->add_check_item(TTR("Linear"), CONTEXT_LINEAR); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-28 14:35:34 +02:00
										 |  |  | 				bool is_linear = _selected_tangent == TANGENT_LEFT | 
					
						
							|  |  |  | 						? _curve_ref->get_point_left_mode(_selected_point) == Curve::TANGENT_LINEAR | 
					
						
							|  |  |  | 						: _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR; | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-02 14:39:12 +07:00
										 |  |  | 				_context_menu->set_item_checked(_context_menu->get_item_index(CONTEXT_LINEAR), is_linear); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 				if (_selected_point > 0 || _selected_point + 1 < _curve_ref->get_point_count()) { | 
					
						
							| 
									
										
										
										
											2018-01-03 16:47:08 -02:00
										 |  |  | 					_context_menu->add_separator(); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if (_selected_point > 0) { | 
					
						
							| 
									
										
										
										
											2019-03-25 01:54:29 +01:00
										 |  |  | 					_context_menu->add_check_item(TTR("Left Linear"), CONTEXT_LEFT_LINEAR); | 
					
						
							| 
									
										
										
										
											2017-10-02 14:39:12 +07:00
										 |  |  | 					_context_menu->set_item_checked(_context_menu->get_item_index(CONTEXT_LEFT_LINEAR), | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 							_curve_ref->get_point_left_mode(_selected_point) == Curve::TANGENT_LINEAR); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (_selected_point + 1 < _curve_ref->get_point_count()) { | 
					
						
							| 
									
										
										
										
											2019-03-25 01:54:29 +01:00
										 |  |  | 					_context_menu->add_check_item(TTR("Right Linear"), CONTEXT_RIGHT_LINEAR); | 
					
						
							| 
									
										
										
										
											2017-10-02 14:39:12 +07:00
										 |  |  | 					_context_menu->set_item_checked(_context_menu->get_item_index(CONTEXT_RIGHT_LINEAR), | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 							_curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		_context_menu->add_separator(); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-25 01:54:29 +01:00
										 |  |  | 	_context_menu->add_submenu_item(TTR("Load Preset"), _presets_menu->get_name()); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-03 16:47:08 -02:00
										 |  |  | 	_context_menu->set_size(Size2(0, 0)); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	_context_menu->popup(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | int CurveEditor::get_point_at(Vector2 pos) const { | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (_curve_ref.is_null()) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	const Curve &curve = **_curve_ref; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-19 20:27:28 -04:00
										 |  |  | 	const float true_hover_radius = Math::round(_hover_radius * EDSCALE); | 
					
						
							|  |  |  | 	const float r = true_hover_radius * true_hover_radius; | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (int i = 0; i < curve.get_point_count(); ++i) { | 
					
						
							| 
									
										
										
										
											2017-09-10 15:37:49 +02:00
										 |  |  | 		Vector2 p = get_view_pos(curve.get_point_position(i)); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		if (p.distance_squared_to(pos) <= r) { | 
					
						
							|  |  |  | 			return i; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | CurveEditor::TangentIndex CurveEditor::get_tangent_at(Vector2 pos) const { | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (_curve_ref.is_null() || _selected_point < 0) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		return TANGENT_NONE; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (_selected_point != 0) { | 
					
						
							|  |  |  | 		Vector2 control_pos = get_tangent_view_pos(_selected_point, TANGENT_LEFT); | 
					
						
							|  |  |  | 		if (control_pos.distance_to(pos) < _hover_radius) { | 
					
						
							|  |  |  | 			return TANGENT_LEFT; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	if (_selected_point != _curve_ref->get_point_count() - 1) { | 
					
						
							|  |  |  | 		Vector2 control_pos = get_tangent_view_pos(_selected_point, TANGENT_RIGHT); | 
					
						
							|  |  |  | 		if (control_pos.distance_to(pos) < _hover_radius) { | 
					
						
							|  |  |  | 			return TANGENT_RIGHT; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	return TANGENT_NONE; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | void CurveEditor::add_point(Vector2 pos) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(_curve_ref.is_null()); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 	UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); | 
					
						
							|  |  |  | 	ur.create_action(TTR("Remove Curve Point")); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	Vector2 point_pos = get_world_pos(pos); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (point_pos.y < 0.0) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		point_pos.y = 0.0; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} else if (point_pos.y > 1.0) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		point_pos.y = 1.0; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 	// Small trick to get the point index to feed the undo method
 | 
					
						
							|  |  |  | 	int i = _curve_ref->add_point(point_pos); | 
					
						
							|  |  |  | 	_curve_ref->remove_point(i); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ur.add_do_method(*_curve_ref, "add_point", point_pos); | 
					
						
							|  |  |  | 	ur.add_undo_method(*_curve_ref, "remove_point", i); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 	ur.commit_action(); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | void CurveEditor::remove_point(int index) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(_curve_ref.is_null()); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 	UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); | 
					
						
							|  |  |  | 	ur.create_action(TTR("Remove Curve Point")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Curve::Point p = _curve_ref->get_point(index); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 	ur.add_do_method(*_curve_ref, "remove_point", index); | 
					
						
							|  |  |  | 	ur.add_undo_method(*_curve_ref, "add_point", p.pos, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (index == _selected_point) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		set_selected_point(-1); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (index == _hover_point) { | 
					
						
							| 
									
										
										
										
											2019-09-25 18:56:59 +02:00
										 |  |  | 		set_hover_point_index(-1); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-09-25 18:56:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 	ur.commit_action(); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | void CurveEditor::toggle_linear(TangentIndex tangent) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(_curve_ref.is_null()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 	UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); | 
					
						
							|  |  |  | 	ur.create_action(TTR("Toggle Curve Linear Tangent")); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (tangent == TANGENT_NONE) { | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 		tangent = _selected_tangent; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (tangent == TANGENT_LEFT) { | 
					
						
							|  |  |  | 		bool is_linear = _curve_ref->get_point_left_mode(_selected_point) == Curve::TANGENT_LINEAR; | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		Curve::TangentMode prev_mode = _curve_ref->get_point_left_mode(_selected_point); | 
					
						
							|  |  |  | 		Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ur.add_do_method(*_curve_ref, "set_point_left_mode", _selected_point, mode); | 
					
						
							|  |  |  | 		ur.add_undo_method(*_curve_ref, "set_point_left_mode", _selected_point, prev_mode); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		bool is_linear = _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR; | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		Curve::TangentMode prev_mode = _curve_ref->get_point_right_mode(_selected_point); | 
					
						
							|  |  |  | 		Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ur.add_do_method(*_curve_ref, "set_point_right_mode", _selected_point, mode); | 
					
						
							|  |  |  | 		ur.add_undo_method(*_curve_ref, "set_point_right_mode", _selected_point, prev_mode); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 02:42:38 +02:00
										 |  |  | 	ur.commit_action(); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | void CurveEditor::set_selected_point(int index) { | 
					
						
							|  |  |  | 	if (index != _selected_point) { | 
					
						
							|  |  |  | 		_selected_point = index; | 
					
						
							|  |  |  | 		update(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | void CurveEditor::set_hover_point_index(int index) { | 
					
						
							|  |  |  | 	if (index != _hover_point) { | 
					
						
							|  |  |  | 		_hover_point = index; | 
					
						
							|  |  |  | 		update(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | void CurveEditor::update_view_transform() { | 
					
						
							| 
									
										
										
										
											2019-12-19 10:39:11 +08:00
										 |  |  | 	Ref<Font> font = get_font("font", "Label"); | 
					
						
							|  |  |  | 	const real_t margin = font->get_height() + 2 * EDSCALE; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 	float min_y = 0; | 
					
						
							|  |  |  | 	float max_y = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (_curve_ref.is_valid()) { | 
					
						
							|  |  |  | 		min_y = _curve_ref->get_min_value(); | 
					
						
							|  |  |  | 		max_y = _curve_ref->get_max_value(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-19 10:39:11 +08:00
										 |  |  | 	const Rect2 world_rect = Rect2(Curve::MIN_X, min_y, Curve::MAX_X, max_y - min_y); | 
					
						
							|  |  |  | 	const Size2 view_margin(margin, margin); | 
					
						
							|  |  |  | 	const Size2 view_size = get_size() - view_margin * 2; | 
					
						
							|  |  |  | 	const Vector2 scale = view_size / world_rect.size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Transform2D world_trans; | 
					
						
							|  |  |  | 	world_trans.translate(-world_rect.position - Vector2(0, world_rect.size.y)); | 
					
						
							|  |  |  | 	world_trans.scale(Vector2(scale.x, -scale.y)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Transform2D view_trans; | 
					
						
							|  |  |  | 	view_trans.translate(view_margin); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-19 10:39:11 +08:00
										 |  |  | 	_world_to_view = view_trans * world_trans; | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | Vector2 CurveEditor::get_tangent_view_pos(int i, TangentIndex tangent) const { | 
					
						
							|  |  |  | 	Vector2 dir; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (tangent == TANGENT_LEFT) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		dir = -Vector2(1, _curve_ref->get_point_left_tangent(i)); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		dir = Vector2(1, _curve_ref->get_point_right_tangent(i)); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 15:37:49 +02:00
										 |  |  | 	Vector2 point_pos = get_view_pos(_curve_ref->get_point_position(i)); | 
					
						
							|  |  |  | 	Vector2 control_pos = get_view_pos(_curve_ref->get_point_position(i) + dir); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-19 20:27:28 -04:00
										 |  |  | 	return point_pos + Math::round(_tangents_length * EDSCALE) * (control_pos - point_pos).normalized(); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | Vector2 CurveEditor::get_view_pos(Vector2 world_pos) const { | 
					
						
							|  |  |  | 	return _world_to_view.xform(world_pos); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Vector2 CurveEditor::get_world_pos(Vector2 view_pos) const { | 
					
						
							|  |  |  | 	return _world_to_view.affine_inverse().xform(view_pos); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | // Uses non-baked points, but takes advantage of ordered iteration to be faster
 | 
					
						
							|  |  |  | template <typename T> | 
					
						
							|  |  |  | static void plot_curve_accurate(const Curve &curve, float step, T plot_func) { | 
					
						
							|  |  |  | 	if (curve.get_point_count() <= 1) { | 
					
						
							|  |  |  | 		// Not enough points to make a curve, so it's just a straight line
 | 
					
						
							|  |  |  | 		float y = curve.interpolate(0); | 
					
						
							|  |  |  | 		plot_func(Vector2(0, y), Vector2(1.f, y), true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-09-10 15:37:49 +02:00
										 |  |  | 		Vector2 first_point = curve.get_point_position(0); | 
					
						
							|  |  |  | 		Vector2 last_point = curve.get_point_position(curve.get_point_count() - 1); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Edge lines
 | 
					
						
							|  |  |  | 		plot_func(Vector2(0, first_point.y), first_point, false); | 
					
						
							|  |  |  | 		plot_func(Vector2(Curve::MAX_X, last_point.y), last_point, false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Draw section by section, so that we get maximum precision near points.
 | 
					
						
							|  |  |  | 		// It's an accurate representation, but slower than using the baked one.
 | 
					
						
							|  |  |  | 		for (int i = 1; i < curve.get_point_count(); ++i) { | 
					
						
							| 
									
										
										
										
											2017-09-10 15:37:49 +02:00
										 |  |  | 			Vector2 a = curve.get_point_position(i - 1); | 
					
						
							|  |  |  | 			Vector2 b = curve.get_point_position(i); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			Vector2 pos = a; | 
					
						
							|  |  |  | 			Vector2 prev_pos = a; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			float len = b.x - a.x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for (float x = step; x < len; x += step) { | 
					
						
							|  |  |  | 				pos.x = a.x + x; | 
					
						
							|  |  |  | 				pos.y = curve.interpolate_local_nocheck(i - 1, x); | 
					
						
							|  |  |  | 				plot_func(prev_pos, pos, true); | 
					
						
							|  |  |  | 				prev_pos = pos; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			plot_func(prev_pos, b, true); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | struct CanvasItemPlotCurve { | 
					
						
							|  |  |  | 	CanvasItem &ci; | 
					
						
							|  |  |  | 	Color color1; | 
					
						
							|  |  |  | 	Color color2; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-06 21:36:34 +01:00
										 |  |  | 	CanvasItemPlotCurve(CanvasItem &p_ci, Color p_color1, Color p_color2) : | 
					
						
							|  |  |  | 			ci(p_ci), | 
					
						
							|  |  |  | 			color1(p_color1), | 
					
						
							|  |  |  | 			color2(p_color2) {} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	void operator()(Vector2 pos0, Vector2 pos1, bool in_definition) { | 
					
						
							| 
									
										
										
										
											2019-06-01 02:00:08 +02:00
										 |  |  | 		// FIXME: Using a line width greater than 1 breaks curve rendering
 | 
					
						
							|  |  |  | 		ci.draw_line(pos0, pos1, in_definition ? color1 : color2, 1, true); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CurveEditor::_draw() { | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (_curve_ref.is_null()) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	Curve &curve = **_curve_ref; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	update_view_transform(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Background
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Vector2 view_size = get_rect().size; | 
					
						
							|  |  |  | 	draw_style_box(get_stylebox("bg", "Tree"), Rect2(Point2(), view_size)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Grid
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	draw_set_transform_matrix(_world_to_view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Vector2 min_edge = get_world_pos(Vector2(0, view_size.y)); | 
					
						
							|  |  |  | 	Vector2 max_edge = get_world_pos(Vector2(view_size.x, 0)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-01 02:00:08 +02:00
										 |  |  | 	const Color grid_color0 = get_color("mono_color", "Editor") * Color(1, 1, 1, 0.15); | 
					
						
							|  |  |  | 	const Color grid_color1 = get_color("mono_color", "Editor") * Color(1, 1, 1, 0.07); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 	draw_line(Vector2(min_edge.x, curve.get_min_value()), Vector2(max_edge.x, curve.get_min_value()), grid_color0); | 
					
						
							|  |  |  | 	draw_line(Vector2(max_edge.x, curve.get_max_value()), Vector2(min_edge.x, curve.get_max_value()), grid_color0); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	draw_line(Vector2(0, min_edge.y), Vector2(0, max_edge.y), grid_color0); | 
					
						
							|  |  |  | 	draw_line(Vector2(1, max_edge.y), Vector2(1, min_edge.y), grid_color0); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 	float curve_height = (curve.get_max_value() - curve.get_min_value()); | 
					
						
							|  |  |  | 	const Vector2 grid_step(0.25, 0.5 * curve_height); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (real_t x = 0; x < 1.0; x += grid_step.x) { | 
					
						
							|  |  |  | 		draw_line(Vector2(x, min_edge.y), Vector2(x, max_edge.y), grid_color1); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 	for (real_t y = curve.get_min_value(); y < curve.get_max_value(); y += grid_step.y) { | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		draw_line(Vector2(min_edge.x, y), Vector2(max_edge.x, y), grid_color1); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	// Markings
 | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	draw_set_transform_matrix(Transform2D()); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	Ref<Font> font = get_font("font", "Label"); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 	float font_height = font->get_height(); | 
					
						
							| 
									
										
										
										
											2018-05-17 18:02:16 -03:00
										 |  |  | 	Color text_color = get_color("font_color", "Editor"); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		// X axis
 | 
					
						
							|  |  |  | 		float y = curve.get_min_value(); | 
					
						
							|  |  |  | 		Vector2 off(0, font_height - 1); | 
					
						
							|  |  |  | 		draw_string(font, get_view_pos(Vector2(0, y)) + off, "0.0", text_color); | 
					
						
							|  |  |  | 		draw_string(font, get_view_pos(Vector2(0.25, y)) + off, "0.25", text_color); | 
					
						
							|  |  |  | 		draw_string(font, get_view_pos(Vector2(0.5, y)) + off, "0.5", text_color); | 
					
						
							|  |  |  | 		draw_string(font, get_view_pos(Vector2(0.75, y)) + off, "0.75", text_color); | 
					
						
							|  |  |  | 		draw_string(font, get_view_pos(Vector2(1, y)) + off, "1.0", text_color); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		// Y axis
 | 
					
						
							|  |  |  | 		float m0 = curve.get_min_value(); | 
					
						
							|  |  |  | 		float m1 = 0.5 * (curve.get_min_value() + curve.get_max_value()); | 
					
						
							|  |  |  | 		float m2 = curve.get_max_value(); | 
					
						
							|  |  |  | 		Vector2 off(1, -1); | 
					
						
							|  |  |  | 		draw_string(font, get_view_pos(Vector2(0, m0)) + off, String::num(m0, 2), text_color); | 
					
						
							|  |  |  | 		draw_string(font, get_view_pos(Vector2(0, m1)) + off, String::num(m1, 2), text_color); | 
					
						
							|  |  |  | 		draw_string(font, get_view_pos(Vector2(0, m2)) + off, String::num(m2, 3), text_color); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	// Draw tangents for current point
 | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	if (_selected_point >= 0) { | 
					
						
							| 
									
										
										
										
											2017-09-25 21:43:20 -05:00
										 |  |  | 		const Color tangent_color = get_color("accent_color", "Editor"); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		int i = _selected_point; | 
					
						
							| 
									
										
										
										
											2017-09-10 15:37:49 +02:00
										 |  |  | 		Vector2 pos = curve.get_point_position(i); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (i != 0) { | 
					
						
							|  |  |  | 			Vector2 control_pos = get_tangent_view_pos(i, TANGENT_LEFT); | 
					
						
							| 
									
										
										
										
											2019-06-01 02:00:08 +02:00
										 |  |  | 			draw_line(get_view_pos(pos), control_pos, tangent_color, Math::round(EDSCALE), true); | 
					
						
							| 
									
										
										
										
											2021-07-19 20:27:28 -04:00
										 |  |  | 			draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(Math::round(2 * EDSCALE)), tangent_color); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		if (i != curve.get_point_count() - 1) { | 
					
						
							|  |  |  | 			Vector2 control_pos = get_tangent_view_pos(i, TANGENT_RIGHT); | 
					
						
							| 
									
										
										
										
											2019-06-01 02:00:08 +02:00
										 |  |  | 			draw_line(get_view_pos(pos), control_pos, tangent_color, Math::round(EDSCALE), true); | 
					
						
							| 
									
										
										
										
											2021-07-19 20:27:28 -04:00
										 |  |  | 			draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(Math::round(2 * EDSCALE)), tangent_color); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	// Draw lines
 | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 	draw_set_transform_matrix(_world_to_view); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-01 02:00:08 +02:00
										 |  |  | 	const Color line_color = get_color("font_color", "Editor"); | 
					
						
							|  |  |  | 	const Color edge_line_color = get_color("highlight_color", "Editor"); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	CanvasItemPlotCurve plot_func(*this, line_color, edge_line_color); | 
					
						
							|  |  |  | 	plot_curve_accurate(curve, 4.f / view_size.x, plot_func); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Draw points
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	draw_set_transform_matrix(Transform2D()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 21:43:20 -05:00
										 |  |  | 	const Color point_color = get_color("font_color", "Editor"); | 
					
						
							|  |  |  | 	const Color selected_point_color = get_color("accent_color", "Editor"); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (int i = 0; i < curve.get_point_count(); ++i) { | 
					
						
							| 
									
										
										
										
											2017-09-10 15:37:49 +02:00
										 |  |  | 		Vector2 pos = curve.get_point_position(i); | 
					
						
							| 
									
										
										
										
											2021-07-19 20:27:28 -04:00
										 |  |  | 		draw_rect(Rect2(get_view_pos(pos), Vector2(1, 1)).grow(Math::round(3 * EDSCALE)), i == _selected_point ? selected_point_color : point_color); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 		// TODO Circles are prettier. Needs a fix! Or a texture
 | 
					
						
							|  |  |  | 		//draw_circle(pos, 2, point_color);
 | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Hover
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (_hover_point != -1) { | 
					
						
							|  |  |  | 		const Color hover_color = line_color; | 
					
						
							| 
									
										
										
										
											2017-09-10 15:37:49 +02:00
										 |  |  | 		Vector2 pos = curve.get_point_position(_hover_point); | 
					
						
							| 
									
										
										
										
											2021-07-19 20:27:28 -04:00
										 |  |  | 		draw_rect(Rect2(get_view_pos(pos), Vector2(1, 1)).grow(Math::round(_hover_radius * EDSCALE)), hover_color, false, Math::round(EDSCALE)); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Help text
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (_selected_point > 0 && _selected_point + 1 < curve.get_point_count()) { | 
					
						
							| 
									
										
										
										
											2018-05-17 18:02:16 -03:00
										 |  |  | 		text_color.a *= 0.4; | 
					
						
							| 
									
										
										
										
											2019-12-19 10:39:11 +08:00
										 |  |  | 		draw_string(font, Vector2(50 * EDSCALE, font_height), TTR("Hold Shift to edit tangents individually"), text_color); | 
					
						
							| 
									
										
										
										
											2019-10-26 12:26:01 +02:00
										 |  |  | 	} else if (curve.get_point_count() == 0) { | 
					
						
							|  |  |  | 		text_color.a *= 0.4; | 
					
						
							| 
									
										
										
										
											2019-12-19 10:39:11 +08:00
										 |  |  | 		draw_string(font, Vector2(50 * EDSCALE, font_height), TTR("Right click to add point"), text_color); | 
					
						
							| 
									
										
										
										
											2017-06-26 23:39:35 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | void CurveEditor::_bind_methods() { | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("_gui_input"), &CurveEditor::on_gui_input); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("_on_preset_item_selected"), &CurveEditor::on_preset_item_selected); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("_curve_changed"), &CurveEditor::_curve_changed); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("_on_context_menu_item_selected"), &CurveEditor::on_context_menu_item_selected); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | //---------------
 | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-17 18:02:16 -03:00
										 |  |  | bool EditorInspectorPluginCurve::can_handle(Object *p_object) { | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 	return Object::cast_to<Curve>(p_object) != nullptr; | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-17 18:02:16 -03:00
										 |  |  | void EditorInspectorPluginCurve::parse_begin(Object *p_object) { | 
					
						
							|  |  |  | 	Curve *curve = Object::cast_to<Curve>(p_object); | 
					
						
							|  |  |  | 	ERR_FAIL_COND(!curve); | 
					
						
							|  |  |  | 	Ref<Curve> c(curve); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-17 18:02:16 -03:00
										 |  |  | 	CurveEditor *editor = memnew(CurveEditor); | 
					
						
							|  |  |  | 	editor->set_curve(curve); | 
					
						
							|  |  |  | 	add_custom_control(editor); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-17 18:02:16 -03:00
										 |  |  | CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) { | 
					
						
							|  |  |  | 	Ref<EditorInspectorPluginCurve> curve_plugin; | 
					
						
							|  |  |  | 	curve_plugin.instance(); | 
					
						
							|  |  |  | 	EditorInspector::add_inspector_plugin(curve_plugin); | 
					
						
							| 
									
										
										
										
											2017-04-30 16:27:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-17 18:02:16 -03:00
										 |  |  | 	get_editor_interface()->get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator)); | 
					
						
							| 
									
										
										
										
											2017-04-06 23:36:37 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-07-02 01:46:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | //-----------------------------------
 | 
					
						
							|  |  |  | // Preview generator
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool CurvePreviewGenerator::handles(const String &p_type) const { | 
					
						
							|  |  |  | 	return p_type == "Curve"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 11:54:12 +02:00
										 |  |  | Ref<Texture> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, const Size2 &p_size) const { | 
					
						
							| 
									
										
										
										
											2017-07-02 01:46:44 +02:00
										 |  |  | 	Ref<Curve> curve_ref = p_from; | 
					
						
							| 
									
										
										
										
											2019-09-25 10:28:50 +02:00
										 |  |  | 	ERR_FAIL_COND_V_MSG(curve_ref.is_null(), Ref<Texture>(), "It's not a reference to a valid Resource object."); | 
					
						
							| 
									
										
										
										
											2017-07-02 01:46:44 +02:00
										 |  |  | 	Curve &curve = **curve_ref; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 12:07:44 +02:00
										 |  |  | 	// FIXME: Should be ported to use p_size as done in b2633a97
 | 
					
						
							| 
									
										
										
										
											2017-07-02 01:46:44 +02:00
										 |  |  | 	int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); | 
					
						
							|  |  |  | 	thumbnail_size *= EDSCALE; | 
					
						
							|  |  |  | 	Ref<Image> img_ref; | 
					
						
							|  |  |  | 	img_ref.instance(); | 
					
						
							|  |  |  | 	Image &im = **img_ref; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 16:28:24 +02:00
										 |  |  | 	im.create(thumbnail_size, thumbnail_size / 2, false, Image::FORMAT_RGBA8); | 
					
						
							| 
									
										
										
										
											2017-07-02 01:46:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	im.lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Color bg_color(0.1, 0.1, 0.1, 1.0); | 
					
						
							|  |  |  | 	for (int i = 0; i < thumbnail_size; i++) { | 
					
						
							| 
									
										
										
										
											2018-05-18 12:37:18 -03:00
										 |  |  | 		for (int j = 0; j < thumbnail_size / 2; j++) { | 
					
						
							| 
									
										
										
										
											2017-07-07 19:05:45 +02:00
										 |  |  | 			im.set_pixel(i, j, bg_color); | 
					
						
							| 
									
										
										
										
											2017-07-02 01:46:44 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Color line_color(0.8, 0.8, 0.8, 1.0); | 
					
						
							|  |  |  | 	float range_y = curve.get_max_value() - curve.get_min_value(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int prev_y = 0; | 
					
						
							|  |  |  | 	for (int x = 0; x < im.get_width(); ++x) { | 
					
						
							|  |  |  | 		float t = static_cast<float>(x) / im.get_width(); | 
					
						
							|  |  |  | 		float v = (curve.interpolate_baked(t) - curve.get_min_value()) / range_y; | 
					
						
							|  |  |  | 		int y = CLAMP(im.get_height() - v * im.get_height(), 0, im.get_height()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Plot point
 | 
					
						
							|  |  |  | 		if (y >= 0 && y < im.get_height()) { | 
					
						
							| 
									
										
										
										
											2017-07-07 19:05:45 +02:00
										 |  |  | 			im.set_pixel(x, y, line_color); | 
					
						
							| 
									
										
										
										
											2017-07-02 01:46:44 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Plot vertical line to fix discontinuity (not 100% correct but enough for a preview)
 | 
					
						
							|  |  |  | 		if (x != 0 && Math::abs(y - prev_y) > 1) { | 
					
						
							|  |  |  | 			int y0, y1; | 
					
						
							|  |  |  | 			if (y < prev_y) { | 
					
						
							|  |  |  | 				y0 = y; | 
					
						
							|  |  |  | 				y1 = prev_y; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				y0 = prev_y; | 
					
						
							|  |  |  | 				y1 = y; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for (int ly = y0; ly < y1; ++ly) { | 
					
						
							| 
									
										
										
										
											2017-07-07 19:05:45 +02:00
										 |  |  | 				im.set_pixel(x, ly, line_color); | 
					
						
							| 
									
										
										
										
											2017-07-02 01:46:44 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		prev_y = y; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	im.unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ptex->create_from_image(img_ref, 0); | 
					
						
							|  |  |  | 	return ptex; | 
					
						
							|  |  |  | } |