diff options
| -rw-r--r-- | editor/icons/icon_editor_handle_add.svg | 6 | ||||
| -rw-r--r-- | editor/icons/icon_editor_handle_selected.svg | 6 | ||||
| -rw-r--r-- | editor/plugins/abstract_polygon_2d_editor.cpp | 425 | ||||
| -rw-r--r-- | editor/plugins/abstract_polygon_2d_editor.h | 35 | 
4 files changed, 315 insertions, 157 deletions
diff --git a/editor/icons/icon_editor_handle_add.svg b/editor/icons/icon_editor_handle_add.svg new file mode 100644 index 0000000000..0e7fe7129a --- /dev/null +++ b/editor/icons/icon_editor_handle_add.svg @@ -0,0 +1,6 @@ +<svg width="8" height="8" version="1.1" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"> +	<g transform="translate(0 -1044.4)"> +		<ellipse cx="4" cy="1048.4" rx="4" ry="4" fill="#fff"/> +		<ellipse cx="4" cy="1048.4" rx="2.8572" ry="2.8571" fill="#84ff84"/> +	</g> +</svg> diff --git a/editor/icons/icon_editor_handle_selected.svg b/editor/icons/icon_editor_handle_selected.svg new file mode 100644 index 0000000000..8d338c1fbd --- /dev/null +++ b/editor/icons/icon_editor_handle_selected.svg @@ -0,0 +1,6 @@ +<svg width="8" height="8" version="1.1" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"> +	<g transform="translate(0 -1044.4)"> +		<ellipse cx="4" cy="1048.4" rx="4" ry="4" fill="#fff"/> +		<ellipse cx="4" cy="1048.4" rx="2.8572" ry="2.8571" fill="#8484ff"/> +	</g> +</svg> diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index ffa4e36b5a..2f839b96cf 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -30,6 +30,49 @@  #include "abstract_polygon_2d_editor.h"  #include "canvas_item_editor_plugin.h" +#include "core/os/keyboard.h" + +AbstractPolygon2DEditor::Vertex::Vertex() +	: polygon(-1), vertex(-1) { +	// invalid vertex +} + +AbstractPolygon2DEditor::Vertex::Vertex(int p_vertex) +	: polygon(-1), vertex(p_vertex) { +	// vertex p_vertex of current wip polygon +} + +AbstractPolygon2DEditor::Vertex::Vertex(int p_polygon, int p_vertex) +	: polygon(p_polygon), vertex(p_vertex) { +	// vertex p_vertex of polygon p_polygon +} + +bool AbstractPolygon2DEditor::Vertex::operator==(const AbstractPolygon2DEditor::Vertex &p_vertex) const { + +	return polygon == p_vertex.polygon && vertex == p_vertex.vertex; +} + +bool AbstractPolygon2DEditor::Vertex::operator!=(const AbstractPolygon2DEditor::Vertex &p_vertex) const { + +	return !(*this == p_vertex); +} + +bool AbstractPolygon2DEditor::Vertex::valid() const { + +	return vertex >= 0; +} + +AbstractPolygon2DEditor::PosVertex::PosVertex() { +	// invalid vertex +} + +AbstractPolygon2DEditor::PosVertex::PosVertex(const Vertex &p_vertex, const Vector2 &p_pos) +	: Vertex(p_vertex.polygon, p_vertex.vertex), pos(p_pos) { +} + +AbstractPolygon2DEditor::PosVertex::PosVertex(int p_polygon, int p_vertex, const Vector2 &p_pos) +	: Vertex(p_polygon, p_vertex), pos(p_pos) { +}  bool AbstractPolygon2DEditor::_is_empty() const { @@ -171,7 +214,10 @@ void AbstractPolygon2DEditor::_wip_close() {  	wip.clear();  	wip_active = false; -	edited_point = -1; + +	edited_point = PosVertex(); +	hover_point = Vertex(); +	selected_point = Vertex();  }  bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { @@ -197,9 +243,6 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)  		Vector2 gpoint = mb->get_position();  		Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position()))); -		//first check if a point is to be added (segment split) -		real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); -  		if (mode == MODE_CREATE) {  			if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { @@ -209,13 +252,16 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)  					wip.clear();  					wip.push_back(cpoint);  					wip_active = true; -					edited_point_pos = cpoint; -					edited_polygon = -1; -					edited_point = 1; +					edited_point = PosVertex(-1, 1, cpoint);  					canvas_item_editor->get_viewport_control()->update(); +					hover_point = Vertex(); +					selected_point = Vertex(0); +					edge_point = PosVertex();  					return true;  				} else { +					const real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); +  					if (wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) {  						//wip closed  						_wip_close(); @@ -224,7 +270,8 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)  					} else {  						wip.push_back(cpoint); -						edited_point = wip.size(); +						edited_point = PosVertex(-1, wip.size(), cpoint); +						selected_point = Vertex(wip.size() - 1);  						canvas_item_editor->get_viewport_control()->update();  						return true; @@ -240,66 +287,31 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)  				if (mb->is_pressed()) { -					if (mb->get_control()) { - -						const int n_polygons = _get_polygon_count(); +					const PosVertex insert = closest_edge_point(gpoint); -						if (n_polygons >= 1) { +					if (insert.valid()) { -							Vector<Vector2> vertices = _get_polygon(n_polygons - 1); +						Vector<Vector2> vertices = _get_polygon(insert.polygon); -							if (vertices.size() < 3) { - -								vertices.push_back(cpoint); -								undo_redo->create_action(TTR("Edit Poly")); -								_action_set_polygon(n_polygons - 1, vertices); -								_commit_action(); -								return true; -							} -						} - -						//search edges -						int closest_poly = -1; -						int closest_idx = -1; -						Vector2 closest_pos; -						real_t closest_dist = 1e10; - -						for (int j = 0; j < n_polygons; j++) { - -							PoolVector<Vector2> points = _get_polygon(j); -							const Vector2 offset = _get_offset(j); -							const int n_points = points.size(); - -							for (int i = 0; i < n_points; i++) { - -								Vector2 p[2] = { xform.xform(points[i] + offset), -									xform.xform(points[(i + 1) % n_points] + offset) }; - -								Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint, p); -								if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2) -									continue; //not valid to reuse point - -								real_t d = cp.distance_to(gpoint); -								if (d < closest_dist && d < grab_threshold) { -									closest_poly = j; -									closest_dist = d; -									closest_pos = cp; -									closest_idx = i; -								} -							} -						} +						if (vertices.size() < 3) { -						if (closest_idx >= 0) { +							vertices.push_back(cpoint); +							undo_redo->create_action(TTR("Edit Poly")); +							selected_point = Vertex(insert.polygon, vertices.size()); +							_action_set_polygon(insert.polygon, vertices); +							_commit_action(); +							return true; +						} else { -							Vector<Vector2> vertices = _get_polygon(closest_poly); +							Vector<Vector2> vertices = _get_polygon(insert.polygon);  							pre_move_edit = vertices; -							vertices.insert(closest_idx + 1, xform.affine_inverse().xform(closest_pos)); -							edited_point = closest_idx + 1; -							edited_polygon = closest_poly; -							edited_point_pos = xform.affine_inverse().xform(closest_pos); +							edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos)); +							vertices.insert(edited_point.vertex, edited_point.pos); +							selected_point = edited_point; +							edge_point = PosVertex();  							undo_redo->create_action(TTR("Insert Point")); -							_action_set_polygon(closest_poly, vertices); +							_action_set_polygon(insert.polygon, vertices);  							_commit_action();  							return true; @@ -307,134 +319,120 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)  					} else {  						//look for points to move -						int closest_poly = -1; -						int closest_idx = -1; -						Vector2 closest_pos; -						real_t closest_dist = 1e10; - -						const int n_polygons = _get_polygon_count(); - -						for (int j = 0; j < n_polygons; j++) { - -							PoolVector<Vector2> points = _get_polygon(j); -							const Vector2 offset = _get_offset(j); -							const int n_points = points.size(); - -							for (int i = 0; i < n_points; i++) { - -								Vector2 cp = xform.xform(points[i] + offset); - -								real_t d = cp.distance_to(gpoint); -								if (d < closest_dist && d < grab_threshold) { -									closest_poly = j; -									closest_dist = d; -									closest_pos = cp; -									closest_idx = i; -								} -							} -						} +						const PosVertex closest = closest_point(gpoint); -						if (closest_idx >= 0) { +						if (closest.valid()) { -							pre_move_edit = _get_polygon(closest_poly); -							edited_polygon = closest_poly; -							edited_point = closest_idx; -							edited_point_pos = xform.affine_inverse().xform(closest_pos); +							pre_move_edit = _get_polygon(closest.polygon); +							edited_point = PosVertex(closest, xform.affine_inverse().xform(closest.pos)); +							selected_point = closest; +							edge_point = PosVertex();  							canvas_item_editor->get_viewport_control()->update();  							return true; +						} else { + +							selected_point = Vertex();  						}  					}  				} else { -					if (edited_point != -1) { +					if (edited_point.valid()) {  						//apply -						Vector<Vector2> vertices = _get_polygon(edited_polygon); -						ERR_FAIL_INDEX_V(edited_point, vertices.size(), false); -						vertices[edited_point] = edited_point_pos - _get_offset(edited_polygon); +						Vector<Vector2> vertices = _get_polygon(edited_point.polygon); +						ERR_FAIL_INDEX_V(edited_point.vertex, vertices.size(), false); +						vertices[edited_point.vertex] = edited_point.pos - _get_offset(edited_point.polygon);  						undo_redo->create_action(TTR("Edit Poly")); -						_action_set_polygon(edited_polygon, pre_move_edit, vertices); +						_action_set_polygon(edited_point.polygon, pre_move_edit, vertices);  						_commit_action(); -						edited_point = -1; +						edited_point = PosVertex();  						return true;  					}  				} -			} else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && edited_point == -1) { +			} else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && !edited_point.valid()) { + +				const PosVertex closest = closest_point(gpoint); + +				if (closest.valid()) { + +					remove_point(closest); +					return true; +				} +			} +		} +	} -				int closest_poly = -1; -				int closest_idx = -1; -				Vector2 closest_pos; -				real_t closest_dist = 1e10; -				const int n_polygons = _get_polygon_count(); +	Ref<InputEventMouseMotion> mm = p_event; -				for (int j = 0; j < n_polygons; j++) { +	if (mm.is_valid()) { -					PoolVector<Vector2> points = _get_polygon(j); -					const int n_points = points.size(); -					const Vector2 offset = _get_offset(j); +		Vector2 gpoint = mm->get_position(); -					for (int i = 0; i < n_points; i++) { +		if (edited_point.valid() && (wip_active || (mm->get_button_mask() & BUTTON_MASK_LEFT))) { -						Vector2 cp = xform.xform(points[i] + offset); +			Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint))); +			edited_point = PosVertex(edited_point, cpoint); -						real_t d = cp.distance_to(gpoint); -						if (d < closest_dist && d < grab_threshold) { -							closest_poly = j; -							closest_dist = d; -							closest_pos = cp; -							closest_idx = i; -						} -					} -				} +			if (!wip_active) { -				if (closest_idx >= 0) { +				Vector<Vector2> vertices = _get_polygon(edited_point.polygon); +				ERR_FAIL_INDEX_V(edited_point.vertex, vertices.size(), false); +				vertices[edited_point.vertex] = cpoint - _get_offset(edited_point.polygon); +				_set_polygon(edited_point.polygon, vertices); +			} -					PoolVector<Vector2> vertices = _get_polygon(closest_poly); +			canvas_item_editor->get_viewport_control()->update(); +		} else if (mode == MODE_EDIT) { -					if (vertices.size() > 3) { +			const PosVertex onEdgeVertex = closest_edge_point(gpoint); -						vertices.remove(closest_idx); +			if (onEdgeVertex.valid()) { -						undo_redo->create_action(TTR("Edit Poly (Remove Point)")); -						_action_set_polygon(closest_poly, vertices); -						_commit_action(); -					} else { +				hover_point = Vertex(); +				edge_point = onEdgeVertex; +				canvas_item_editor->get_viewport_control()->update(); +			} else { -						undo_redo->create_action(TTR("Remove Poly And Point")); -						_action_remove_polygon(closest_poly); -						_commit_action(); -					} +				if (edge_point.valid()) { -					if (_is_empty()) -						_menu_option(MODE_CREATE); -					return true; +					edge_point = PosVertex(); +					canvas_item_editor->get_viewport_control()->update(); +				} + +				const PosVertex new_hover_point = closest_point(gpoint); +				if (hover_point != new_hover_point) { + +					hover_point = new_hover_point; +					canvas_item_editor->get_viewport_control()->update();  				}  			}  		}  	} -	Ref<InputEventMouseMotion> mm = p_event; +	Ref<InputEventKey> k = p_event; -	if (mm.is_valid()) { +	if (k.is_valid() && k->is_pressed() && (k->get_scancode() == KEY_DELETE || k->get_scancode() == KEY_BACKSPACE)) { +		if (wip_active && selected_point.polygon == -1) { -		if (edited_point != -1 && (wip_active || (mm->get_button_mask() & BUTTON_MASK_LEFT))) { +			if (wip.size() > selected_point.vertex) { -			Vector2 gpoint = mm->get_position(); -			Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mm->get_position()))); -			edited_point_pos = cpoint; +				wip.remove(selected_point.vertex); +				selected_point = wip.size() - 1; +				canvas_item_editor->get_viewport_control()->update(); +				return true; +			} +		} else { -			if (!wip_active) { +			const Vertex active_point = get_active_point(); -				Vector<Vector2> vertices = _get_polygon(edited_polygon); -				ERR_FAIL_INDEX_V(edited_point, vertices.size(), false); -				vertices[edited_point] = cpoint - _get_offset(edited_polygon); -				_set_polygon(edited_polygon, vertices); -			} +			if (active_point.valid()) { -			canvas_item_editor->get_viewport_control()->update(); +				remove_point(active_point); +				return true; +			}  		}  	} @@ -448,7 +446,10 @@ void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) {  	Control *vpc = canvas_item_editor->get_viewport_control();  	Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform(); -	Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); +	Ref<Texture> default_handle = get_icon("EditorHandle", "EditorIcons"); +	Ref<Texture> selected_handle = get_icon("EditorHandleSelected", "EditorIcons"); + +	const Vertex active_point = get_active_point();  	const int n_polygons = _get_polygon_count();  	for (int j = -1; j < n_polygons; j++) { @@ -459,7 +460,7 @@ void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) {  		PoolVector<Vector2> points;  		Vector2 offset; -		if (wip_active && j == edited_polygon) { +		if (wip_active && j == edited_point.polygon) {  			points = Variant(wip);  			offset = Vector2(0, 0); @@ -471,7 +472,7 @@ void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) {  			offset = _get_offset(j);  		} -		if (!wip_active && j == edited_polygon && edited_point >= 0 && EDITOR_DEF("editors/poly_editor/show_previous_outline", true)) { +		if (!wip_active && j == edited_point.polygon && EDITOR_DEF("editors/poly_editor/show_previous_outline", true)) {  			const Color col = Color(0.5, 0.5, 0.5); // FIXME polygon->get_outline_color();  			const int n = pre_move_edit.size(); @@ -493,10 +494,12 @@ void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) {  		for (int i = 0; i < n_points; i++) { +			const Vertex vertex(j, i); +  			Vector2 p, p2; -			p = (j == edited_polygon && i == edited_point) ? edited_point_pos : (points[i] + offset); -			if (j == edited_polygon && ((wip_active && i == n_points - 1) || (((i + 1) % n_points) == edited_point))) -				p2 = edited_point_pos; +			p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset); +			if (j == edited_point.polygon && ((wip_active && i == n_points - 1) || (((i + 1) % n_points) == edited_point.vertex))) +				p2 = edited_point.pos;  			else  				p2 = points[(i + 1) % n_points] + offset; @@ -504,9 +507,16 @@ void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) {  			Vector2 next_point = xform.xform(p2);  			vpc->draw_line(point, next_point, col, 2); +			Ref<Texture> handle = vertex == active_point ? selected_handle : default_handle;  			vpc->draw_texture(handle, point - handle->get_size() * 0.5);  		}  	} + +	if (edge_point.valid()) { + +		Ref<Texture> add_handle = get_icon("EditorHandleAdd", "EditorIcons"); +		vpc->draw_texture(add_handle, edge_point.pos - add_handle->get_size() * 0.5); +	}  }  void AbstractPolygon2DEditor::edit(Node *p_polygon) { @@ -525,7 +535,9 @@ void AbstractPolygon2DEditor::edit(Node *p_polygon) {  		wip.clear();  		wip_active = false; -		edited_point = -1; +		edited_point = PosVertex(); +		hover_point = Vertex(); +		selected_point = Vertex();  		canvas_item_editor->get_viewport_control()->update(); @@ -542,6 +554,107 @@ void AbstractPolygon2DEditor::_bind_methods() {  	ClassDB::bind_method(D_METHOD("_create_resource"), &AbstractPolygon2DEditor::_create_resource);  } +void AbstractPolygon2DEditor::remove_point(const Vertex &p_vertex) { + +	PoolVector<Vector2> vertices = _get_polygon(p_vertex.polygon); + +	if (vertices.size() > 3) { + +		vertices.remove(p_vertex.vertex); + +		undo_redo->create_action(TTR("Edit Poly (Remove Point)")); +		_action_set_polygon(p_vertex.polygon, vertices); +		_commit_action(); +	} else { + +		undo_redo->create_action(TTR("Remove Poly And Point")); +		_action_remove_polygon(p_vertex.polygon); +		_commit_action(); +	} + +	if (_is_empty()) +		_menu_option(MODE_CREATE); + +	hover_point = Vertex(); +	if (selected_point == p_vertex) +		selected_point = Vertex(); +} + +AbstractPolygon2DEditor::Vertex AbstractPolygon2DEditor::get_active_point() const { + +	return hover_point.valid() ? hover_point : selected_point; +} + +AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_point(const Vector2 &p_pos) const { + +	const real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); + +	const int n_polygons = _get_polygon_count(); +	const Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform(); + +	PosVertex closest; +	real_t closest_dist = 1e10; + +	for (int j = 0; j < n_polygons; j++) { + +		PoolVector<Vector2> points = _get_polygon(j); +		const Vector2 offset = _get_offset(j); +		const int n_points = points.size(); + +		for (int i = 0; i < n_points; i++) { + +			Vector2 cp = xform.xform(points[i] + offset); + +			real_t d = cp.distance_to(p_pos); +			if (d < closest_dist && d < grab_threshold) { +				closest_dist = d; +				closest = PosVertex(j, i, cp); +			} +		} +	} + +	return closest; +} + +AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_edge_point(const Vector2 &p_pos) const { + +	const real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8); +	const real_t eps = grab_threshold * 2; +	const real_t eps2 = eps * eps; + +	const int n_polygons = _get_polygon_count(); +	const Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform(); + +	PosVertex closest; +	real_t closest_dist = 1e10; + +	for (int j = 0; j < n_polygons; j++) { + +		PoolVector<Vector2> points = _get_polygon(j); +		const Vector2 offset = _get_offset(j); +		const int n_points = points.size(); + +		for (int i = 0; i < n_points; i++) { + +			Vector2 segment[2] = { xform.xform(points[i] + offset), +				xform.xform(points[(i + 1) % n_points] + offset) }; + +			Vector2 cp = Geometry::get_closest_point_to_segment_2d(p_pos, segment); + +			if (cp.distance_squared_to(segment[0]) < eps2 || cp.distance_squared_to(segment[1]) < eps2) +				continue; //not valid to reuse point + +			real_t d = cp.distance_to(p_pos); +			if (d < closest_dist && d < grab_threshold) { +				closest_dist = d; +				closest = PosVertex(j, i, cp); +			} +		} +	} + +	return closest; +} +  AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wip_destructive) {  	canvas_item_editor = NULL; @@ -549,9 +662,13 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wi  	undo_redo = editor->get_undo_redo();  	wip_active = false; -	edited_polygon = -1; +	edited_point = PosVertex();  	wip_destructive = p_wip_destructive; +	hover_point = Vertex(); +	selected_point = Vertex(); +	edge_point = PosVertex(); +  	add_child(memnew(VSeparator));  	button_create = memnew(ToolButton);  	add_child(button_create); diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h index 3e3bff6d0d..8dd22958db 100644 --- a/editor/plugins/abstract_polygon_2d_editor.h +++ b/editor/plugins/abstract_polygon_2d_editor.h @@ -47,9 +47,33 @@ class AbstractPolygon2DEditor : public HBoxContainer {  	ToolButton *button_create;  	ToolButton *button_edit; -	int edited_polygon; -	int edited_point; -	Vector2 edited_point_pos; +	struct Vertex { +		Vertex(); +		Vertex(int p_vertex); +		Vertex(int p_polygon, int p_vertex); + +		bool operator==(const Vertex &p_vertex) const; +		bool operator!=(const Vertex &p_vertex) const; + +		bool valid() const; + +		int polygon; +		int vertex; +	}; + +	struct PosVertex : public Vertex { +		PosVertex(); +		PosVertex(const Vertex &p_vertex, const Vector2 &p_pos); +		PosVertex(int p_polygon, int p_vertex, const Vector2 &p_pos); + +		Vector2 pos; +	}; + +	PosVertex edited_point; +	Vertex hover_point; // point under mouse cursor +	Vertex selected_point; // currently selected +	PosVertex edge_point; // adding an edge point? +  	Vector<Vector2> pre_move_edit;  	Vector<Vector2> wip;  	bool wip_active; @@ -80,6 +104,11 @@ protected:  	void _node_removed(Node *p_node);  	static void _bind_methods(); +	void remove_point(const Vertex &p_vertex); +	Vertex get_active_point() const; +	PosVertex closest_point(const Vector2 &p_pos) const; +	PosVertex closest_edge_point(const Vector2 &p_pos) const; +  	bool _is_empty() const;  	void _commit_action();  |