summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/math/geometry.cpp11
-rw-r--r--core/math/geometry.h3
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp8
-rw-r--r--scene/2d/canvas_item.h1
-rw-r--r--scene/2d/collision_polygon_2d.cpp5
-rw-r--r--scene/2d/collision_polygon_2d.h1
-rw-r--r--scene/2d/collision_shape_2d.cpp8
-rw-r--r--scene/2d/collision_shape_2d.h1
-rw-r--r--scene/2d/line_2d.cpp26
-rw-r--r--scene/2d/line_2d.h3
-rw-r--r--scene/2d/navigation_polygon.cpp60
-rw-r--r--scene/2d/navigation_polygon.h9
-rw-r--r--scene/2d/path_2d.cpp54
-rw-r--r--scene/2d/path_2d.h3
-rw-r--r--scene/2d/polygon_2d.cpp7
-rw-r--r--scene/2d/polygon_2d.h1
-rw-r--r--scene/2d/sprite.cpp93
-rw-r--r--scene/2d/sprite.h3
-rw-r--r--scene/resources/capsule_shape_2d.cpp29
-rw-r--r--scene/resources/capsule_shape_2d.h3
-rw-r--r--scene/resources/circle_shape_2d.cpp6
-rw-r--r--scene/resources/circle_shape_2d.h2
-rw-r--r--scene/resources/concave_polygon_shape_2d.cpp17
-rw-r--r--scene/resources/concave_polygon_shape_2d.h2
-rw-r--r--scene/resources/convex_polygon_shape_2d.cpp5
-rw-r--r--scene/resources/convex_polygon_shape_2d.h2
-rw-r--r--scene/resources/segment_shape_2d.cpp7
-rw-r--r--scene/resources/segment_shape_2d.h2
-rw-r--r--scene/resources/shape_2d.h2
-rw-r--r--scene/resources/shape_line_2d.cpp15
-rw-r--r--scene/resources/shape_line_2d.h2
31 files changed, 345 insertions, 46 deletions
diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp
index b2145eca85..a3b48320b1 100644
--- a/core/math/geometry.cpp
+++ b/core/math/geometry.cpp
@@ -30,6 +30,17 @@
#include "geometry.h"
#include "print_string.h"
+bool Geometry::is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) {
+
+ Vector<int> indices = Geometry::triangulate_polygon(p_polygon);
+ for (int j = 0; j + 3 <= indices.size(); j += 3) {
+ int i1 = indices[j], i2 = indices[j + 1], i3 = indices[j + 2];
+ if (Geometry::is_point_in_triangle(p_point, p_polygon[i1], p_polygon[i2], p_polygon[i3]))
+ return true;
+ }
+ return false;
+}
+
void Geometry::MeshData::optimize_vertices() {
Map<int, int> vtx_remap;
diff --git a/core/math/geometry.h b/core/math/geometry.h
index ac1a22289c..fefdd88794 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -512,6 +512,9 @@ public:
return true;
}
+
+ static bool is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon);
+
static Vector2 get_closest_point_to_segment_uncapped_2d(const Vector2 &p_point, const Vector2 *p_segment) {
Vector2 p = p_point - p_segment[0];
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 53b52c5f1b..2ef6b60df5 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -612,6 +612,7 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
if (Object::cast_to<Viewport>(p_node))
return;
+ const real_t grab_distance = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
CanvasItem *c = Object::cast_to<CanvasItem>(p_node);
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
@@ -630,9 +631,12 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
if (c && c->is_visible_in_tree() && !c->has_meta("_edit_lock_") && !Object::cast_to<CanvasLayer>(c)) {
Rect2 rect = c->_edit_get_rect();
- Point2 local_pos = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse().xform(p_pos);
+ Transform2D to_local = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse();
+ Point2 local_pos = to_local.xform(p_pos);
+ const real_t local_grab_distance = (to_local.xform(p_pos + Vector2(grab_distance, 0)) - local_pos).length();
+ Rect2 local_pos_rect = Rect2(local_pos, Vector2(0, 0)).grow(local_grab_distance);
- if (rect.has_point(local_pos)) {
+ if (rect.intersects(local_pos_rect) && c->_edit_is_selected_on_click(local_pos, local_grab_distance)) {
Node2D *node = Object::cast_to<Node2D>(c);
_SelectResult res;
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index e994ebb5aa..1db9e4902a 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -229,6 +229,7 @@ public:
// Used to resize/move/select the node
virtual void _edit_set_rect(const Rect2 &p_rect){};
virtual Rect2 _edit_get_rect() const { return Rect2(-32, -32, 64, 64); };
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { return true; }
Rect2 _edit_get_item_and_children_rect() const;
virtual bool _edit_use_rect() const { return false; };
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index eaa650b140..e46bf3c77d 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -248,6 +248,11 @@ Rect2 CollisionPolygon2D::_edit_get_rect() const {
return aabb;
}
+bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return Geometry::is_point_in_polygon(p_point, Variant(polygon));
+}
+
String CollisionPolygon2D::get_configuration_warning() const {
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h
index 4c8b55a9ee..fa7e5e1046 100644
--- a/scene/2d/collision_polygon_2d.h
+++ b/scene/2d/collision_polygon_2d.h
@@ -70,6 +70,7 @@ public:
Vector<Point2> get_polygon() const;
virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
virtual String get_configuration_warning() const;
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 1cadbe83d0..135ede829d 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -163,6 +163,14 @@ Rect2 CollisionShape2D::_edit_get_rect() const {
return rect;
}
+bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ if (!shape.is_valid())
+ return false;
+
+ return shape->_edit_is_selected_on_click(p_point, p_tolerance);
+}
+
String CollisionShape2D::get_configuration_warning() const {
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h
index 833d9ae5cb..921066c5c8 100644
--- a/scene/2d/collision_shape_2d.h
+++ b/scene/2d/collision_shape_2d.h
@@ -52,6 +52,7 @@ protected:
public:
virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
void set_shape(const Ref<Shape2D> &p_shape);
Ref<Shape2D> get_shape() const;
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index f108df140f..abc80216d4 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -48,6 +48,32 @@ Line2D::Line2D() :
_round_precision = 8;
}
+Rect2 Line2D::_edit_get_rect() const {
+
+ if (_points.size() == 0)
+ return Rect2(0, 0, 0, 0);
+ Vector2 d = Vector2(_width, _width);
+ Rect2 aabb = Rect2(_points[0] - d, 2 * d);
+ for (int i = 1; i < _points.size(); i++) {
+ aabb.expand_to(_points[i] - d);
+ aabb.expand_to(_points[i] + d);
+ }
+ return aabb;
+}
+
+bool Line2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ const real_t d = _width / 2 + p_tolerance;
+ PoolVector<Vector2>::Read points = _points.read();
+ for (int i = 0; i < _points.size() - 1; i++) {
+ Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, &points[i]);
+ if (p.distance_to(p_point) <= d)
+ return true;
+ }
+
+ return false;
+}
+
void Line2D::set_points(const PoolVector<Vector2> &p_points) {
_points = p_points;
update();
diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h
index 123728ab39..54a4683dc7 100644
--- a/scene/2d/line_2d.h
+++ b/scene/2d/line_2d.h
@@ -57,6 +57,9 @@ public:
Line2D();
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_points(const PoolVector<Vector2> &p_points);
PoolVector<Vector2> get_points() const;
diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp
index 9c297db52b..dde41dbf3f 100644
--- a/scene/2d/navigation_polygon.cpp
+++ b/scene/2d/navigation_polygon.cpp
@@ -35,9 +35,50 @@
#include "thirdparty/misc/triangulator.h"
+Rect2 NavigationPolygon::_edit_get_rect() const {
+
+ if (rect_cache_dirty) {
+ item_rect = Rect2();
+ bool first = true;
+
+ for (int i = 0; i < outlines.size(); i++) {
+ const PoolVector<Vector2> &outline = outlines[i];
+ const int outline_size = outline.size();
+ if (outline_size < 3)
+ continue;
+ PoolVector<Vector2>::Read p = outline.read();
+ for (int j = 0; j < outline_size; j++) {
+ if (first) {
+ item_rect = Rect2(p[j], Vector2(0, 0));
+ first = false;
+ } else {
+ item_rect.expand_to(p[j]);
+ }
+ }
+ }
+
+ rect_cache_dirty = false;
+ }
+ return item_rect;
+}
+
+bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ for (int i = 0; i < outlines.size(); i++) {
+ const PoolVector<Vector2> &outline = outlines[i];
+ const int outline_size = outline.size();
+ if (outline_size < 3)
+ continue;
+ if (Geometry::is_point_in_polygon(p_point, Variant(outline)))
+ return true;
+ }
+ return false;
+}
+
void NavigationPolygon::set_vertices(const PoolVector<Vector2> &p_vertices) {
vertices = p_vertices;
+ rect_cache_dirty = true;
}
PoolVector<Vector2> NavigationPolygon::get_vertices() const {
@@ -70,6 +111,7 @@ void NavigationPolygon::_set_outlines(const Array &p_array) {
for (int i = 0; i < p_array.size(); i++) {
outlines[i] = p_array[i];
}
+ rect_cache_dirty = true;
}
Array NavigationPolygon::_get_outlines() const {
@@ -93,6 +135,7 @@ void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) {
void NavigationPolygon::add_outline_at_index(const PoolVector<Vector2> &p_outline, int p_index) {
outlines.insert(p_index, p_outline);
+ rect_cache_dirty = true;
}
int NavigationPolygon::get_polygon_count() const {
@@ -112,6 +155,7 @@ void NavigationPolygon::clear_polygons() {
void NavigationPolygon::add_outline(const PoolVector<Vector2> &p_outline) {
outlines.push_back(p_outline);
+ rect_cache_dirty = true;
}
int NavigationPolygon::get_outline_count() const {
@@ -122,12 +166,14 @@ int NavigationPolygon::get_outline_count() const {
void NavigationPolygon::set_outline(int p_idx, const PoolVector<Vector2> &p_outline) {
ERR_FAIL_INDEX(p_idx, outlines.size());
outlines[p_idx] = p_outline;
+ rect_cache_dirty = true;
}
void NavigationPolygon::remove_outline(int p_idx) {
ERR_FAIL_INDEX(p_idx, outlines.size());
outlines.remove(p_idx);
+ rect_cache_dirty = true;
}
PoolVector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
@@ -138,6 +184,7 @@ PoolVector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
void NavigationPolygon::clear_outlines() {
outlines.clear();
+ rect_cache_dirty = true;
}
void NavigationPolygon::make_polygons_from_outlines() {
@@ -269,7 +316,8 @@ void NavigationPolygon::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_outlines", "_get_outlines");
}
-NavigationPolygon::NavigationPolygon() {
+NavigationPolygon::NavigationPolygon() :
+ rect_cache_dirty(true) {
}
void NavigationPolygonInstance::set_enabled(bool p_enabled) {
@@ -311,6 +359,16 @@ bool NavigationPolygonInstance::is_enabled() const {
/////////////////////////////
+Rect2 NavigationPolygonInstance::_edit_get_rect() const {
+
+ return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2();
+}
+
+bool NavigationPolygonInstance::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false;
+}
+
void NavigationPolygonInstance::_notification(int p_what) {
switch (p_what) {
diff --git a/scene/2d/navigation_polygon.h b/scene/2d/navigation_polygon.h
index febdcf2ca6..7b5220f92d 100644
--- a/scene/2d/navigation_polygon.h
+++ b/scene/2d/navigation_polygon.h
@@ -43,6 +43,9 @@ class NavigationPolygon : public Resource {
Vector<Polygon> polygons;
Vector<PoolVector<Vector2> > outlines;
+ mutable Rect2 item_rect;
+ mutable bool rect_cache_dirty;
+
protected:
static void _bind_methods();
@@ -53,6 +56,9 @@ protected:
Array _get_outlines() const;
public:
+ Rect2 _edit_get_rect() const;
+ bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_vertices(const PoolVector<Vector2> &p_vertices);
PoolVector<Vector2> get_vertices() const;
@@ -93,6 +99,9 @@ protected:
static void _bind_methods();
public:
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 06bd55858c..d2a307a9ed 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -32,6 +32,51 @@
#include "engine.h"
#include "scene/scene_string_names.h"
+#ifdef TOOLS_ENABLED
+#include "editor/editor_scale.h"
+#endif
+
+Rect2 Path2D::_edit_get_rect() const {
+
+ if (curve->get_point_count() == 0)
+ return Rect2(0, 0, 0, 0);
+
+ Rect2 aabb = Rect2(curve->get_point_position(0), Vector2(0, 0));
+
+ for (int i = 0; i < curve->get_point_count(); i++) {
+
+ for (int j = 0; j <= 8; j++) {
+
+ real_t frac = j / 8.0;
+ Vector2 p = curve->interpolate(i, frac);
+ aabb.expand_to(p);
+ }
+ }
+
+ return aabb;
+}
+
+bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ for (int i = 0; i < curve->get_point_count(); i++) {
+ Vector2 s[2];
+ s[0] = curve->get_point_position(i);
+
+ for (int j = 1; j <= 8; j++) {
+ real_t frac = j / 8.0;
+ s[1] = curve->interpolate(i, frac);
+
+ Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, s);
+ if (p.distance_to(p_point) <= p_tolerance)
+ return true;
+
+ s[0] = s[1];
+ }
+ }
+
+ return false;
+}
+
void Path2D::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW && curve.is_valid()) {
@@ -41,6 +86,13 @@ void Path2D::_notification(int p_what) {
return;
}
+#if TOOLS_ENABLED
+ const float line_width = 2 * EDSCALE;
+#else
+ const float line_width = 2;
+#endif
+ const Color color = Color(0.5, 0.6, 1.0, 0.7);
+
for (int i = 0; i < curve->get_point_count(); i++) {
Vector2 prev_p = curve->get_point_position(i);
@@ -49,7 +101,7 @@ void Path2D::_notification(int p_what) {
real_t frac = j / 8.0;
Vector2 p = curve->interpolate(i, frac);
- draw_line(prev_p, p, Color(0.5, 0.6, 1.0, 0.7), 2);
+ draw_line(prev_p, p, color, line_width);
prev_p = p;
}
}
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index ebfa77d605..7f53821c7e 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -46,6 +46,9 @@ protected:
static void _bind_methods();
public:
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_curve(const Ref<Curve2D> &p_curve);
Ref<Curve2D> get_curve() const;
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index a2f49d938b..f9951cdd08 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "polygon_2d.h"
+#include "core/math/geometry.h"
Rect2 Polygon2D::_edit_get_rect() const {
@@ -42,13 +43,17 @@ Rect2 Polygon2D::_edit_get_rect() const {
else
item_rect.expand_to(pos);
}
- item_rect = item_rect.grow(20);
rect_cache_dirty = false;
}
return item_rect;
}
+bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return Geometry::is_point_in_polygon(p_point, Variant(polygon));
+}
+
void Polygon2D::_edit_set_pivot(const Point2 &p_pivot) {
set_offset(p_pivot);
diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h
index a23e223e6e..5014cbc6e9 100644
--- a/scene/2d/polygon_2d.h
+++ b/scene/2d/polygon_2d.h
@@ -104,6 +104,7 @@ public:
virtual bool _edit_use_pivot() const;
virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
Polygon2D();
};
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index c4a7e5aebd..68df95c042 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -47,6 +47,40 @@ bool Sprite::_edit_use_pivot() const {
return true;
}
+void Sprite::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const {
+
+ Size2 s;
+ r_filter_clip = false;
+
+ if (region) {
+
+ s = region_rect.size;
+ r_src_rect = region_rect;
+ r_filter_clip = region_filter_clip;
+ } else {
+ s = Size2(texture->get_size());
+ s = s / Size2(hframes, vframes);
+
+ r_src_rect.size = s;
+ r_src_rect.position.x += float(frame % hframes) * s.x;
+ r_src_rect.position.y += float(frame / hframes) * s.y;
+ }
+
+ Point2 ofs = offset;
+ if (centered)
+ ofs -= s / 2;
+ if (Engine::get_singleton()->get_use_pixel_snap()) {
+ ofs = ofs.floor();
+ }
+
+ r_dst_rect = Rect2(ofs, s);
+
+ if (hflip)
+ r_dst_rect.size.x = -r_dst_rect.size.x;
+ if (vflip)
+ r_dst_rect.size.y = -r_dst_rect.size.y;
+}
+
void Sprite::_notification(int p_what) {
switch (p_what) {
@@ -63,38 +97,9 @@ void Sprite::_notification(int p_what) {
break;
*/
- Size2 s;
- Rect2 src_rect;
- bool filter_clip = false;
-
- if (region) {
-
- s = region_rect.size;
- src_rect = region_rect;
- filter_clip = region_filter_clip;
- } else {
- s = Size2(texture->get_size());
- s = s / Size2(hframes, vframes);
-
- src_rect.size = s;
- src_rect.position.x += float(frame % hframes) * s.x;
- src_rect.position.y += float(frame / hframes) * s.y;
- }
-
- Point2 ofs = offset;
- if (centered)
- ofs -= s / 2;
- if (Engine::get_singleton()->get_use_pixel_snap()) {
- ofs = ofs.floor();
- }
-
- Rect2 dst_rect(ofs, s);
-
- if (hflip)
- dst_rect.size.x = -dst_rect.size.x;
- if (vflip)
- dst_rect.size.y = -dst_rect.size.y;
-
+ Rect2 src_rect, dst_rect;
+ bool filter_clip;
+ _get_rects(src_rect, dst_rect, filter_clip);
texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, filter_clip);
} break;
@@ -257,6 +262,30 @@ int Sprite::get_hframes() const {
return hframes;
}
+bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ if (texture.is_null())
+ return false;
+
+ Rect2 src_rect, dst_rect;
+ bool filter_clip;
+ _get_rects(src_rect, dst_rect, filter_clip);
+
+ if (!dst_rect.has_point(p_point))
+ return false;
+
+ Vector2 q = ((p_point - dst_rect.position) / dst_rect.size) * src_rect.size + src_rect.position;
+
+ Ref<Image> image = texture->get_data();
+ ERR_FAIL_COND_V(image.is_null(), false);
+
+ image->lock();
+ const Color c = image->get_pixel((int)q.x, (int)q.y);
+ image->unlock();
+
+ return c.a > 0.01;
+}
+
Rect2 Sprite::_edit_get_rect() const {
if (texture.is_null())
diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h
index c437f6d404..7d9b2cf457 100644
--- a/scene/2d/sprite.h
+++ b/scene/2d/sprite.h
@@ -54,6 +54,8 @@ class Sprite : public Node2D {
int vframes;
int hframes;
+ void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const;
+
protected:
void _notification(int p_what);
@@ -65,6 +67,7 @@ public:
virtual void _edit_set_pivot(const Point2 &p_pivot);
virtual Point2 _edit_get_pivot() const;
virtual bool _edit_use_pivot() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
virtual Rect2 _edit_get_rect() const;
void set_texture(const Ref<Texture> &p_texture);
diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp
index 7b2dbf8e8c..2722ff7207 100644
--- a/scene/resources/capsule_shape_2d.cpp
+++ b/scene/resources/capsule_shape_2d.cpp
@@ -32,6 +32,25 @@
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+Vector<Vector2> CapsuleShape2D::_get_points() const {
+
+ Vector<Vector2> points;
+ for (int i = 0; i < 24; i++) {
+ Vector2 ofs = Vector2(0, (i > 6 && i <= 18) ? -get_height() * 0.5 : get_height() * 0.5);
+
+ points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() + ofs);
+ if (i == 6 || i == 18)
+ points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() - ofs);
+ }
+
+ return points;
+}
+
+bool CapsuleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return Geometry::is_point_in_polygon(p_point, _get_points());
+}
+
void CapsuleShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), Vector2(radius, height));
@@ -62,15 +81,7 @@ real_t CapsuleShape2D::get_height() const {
void CapsuleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
- Vector<Vector2> points;
- for (int i = 0; i < 24; i++) {
- Vector2 ofs = Vector2(0, (i > 6 && i <= 18) ? -get_height() * 0.5 : get_height() * 0.5);
-
- points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() + ofs);
- if (i == 6 || i == 18)
- points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() - ofs);
- }
-
+ Vector<Vector2> points = _get_points();
Vector<Color> col;
col.push_back(p_color);
VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
diff --git a/scene/resources/capsule_shape_2d.h b/scene/resources/capsule_shape_2d.h
index 7ce6a4ed63..784f2c02c8 100644
--- a/scene/resources/capsule_shape_2d.h
+++ b/scene/resources/capsule_shape_2d.h
@@ -39,11 +39,14 @@ class CapsuleShape2D : public Shape2D {
real_t radius;
void _update_shape();
+ Vector<Vector2> _get_points() const;
protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_height(real_t p_height);
real_t get_height() const;
diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp
index d9d0ddbe8f..669b1d8e7d 100644
--- a/scene/resources/circle_shape_2d.cpp
+++ b/scene/resources/circle_shape_2d.cpp
@@ -31,6 +31,12 @@
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+
+bool CircleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return p_point.length() < get_radius() + p_tolerance;
+}
+
void CircleShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), radius);
diff --git a/scene/resources/circle_shape_2d.h b/scene/resources/circle_shape_2d.h
index f14f8f6776..3668521a55 100644
--- a/scene/resources/circle_shape_2d.h
+++ b/scene/resources/circle_shape_2d.h
@@ -42,6 +42,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_radius(real_t p_radius);
real_t get_radius() const;
diff --git a/scene/resources/concave_polygon_shape_2d.cpp b/scene/resources/concave_polygon_shape_2d.cpp
index 19985d4acf..69765796f6 100644
--- a/scene/resources/concave_polygon_shape_2d.cpp
+++ b/scene/resources/concave_polygon_shape_2d.cpp
@@ -32,6 +32,23 @@
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+bool ConcavePolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ PoolVector<Vector2> s = get_segments();
+ int len = s.size();
+ if (len == 0 || (len % 2) == 1)
+ return false;
+
+ PoolVector<Vector2>::Read r = s.read();
+ for (int i = 0; i < len; i += 2) {
+ Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, &r[i]);
+ if (p_point.distance_to(closest) < p_tolerance)
+ return true;
+ }
+
+ return false;
+}
+
void ConcavePolygonShape2D::set_segments(const PoolVector<Vector2> &p_segments) {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), p_segments);
diff --git a/scene/resources/concave_polygon_shape_2d.h b/scene/resources/concave_polygon_shape_2d.h
index 4a5defe72c..7ca14d4d66 100644
--- a/scene/resources/concave_polygon_shape_2d.h
+++ b/scene/resources/concave_polygon_shape_2d.h
@@ -39,6 +39,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_segments(const PoolVector<Vector2> &p_segments);
PoolVector<Vector2> get_segments() const;
diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index 98ef2ca7c6..0402a70898 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -33,6 +33,11 @@
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+bool ConvexPolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return Geometry::is_point_in_polygon(p_point, points);
+}
+
void ConvexPolygonShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), points);
diff --git a/scene/resources/convex_polygon_shape_2d.h b/scene/resources/convex_polygon_shape_2d.h
index f492b7651b..320cf94a5e 100644
--- a/scene/resources/convex_polygon_shape_2d.h
+++ b/scene/resources/convex_polygon_shape_2d.h
@@ -42,6 +42,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_point_cloud(const Vector<Vector2> &p_points);
void set_points(const Vector<Vector2> &p_points);
Vector<Vector2> get_points() const;
diff --git a/scene/resources/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp
index 4682ef5cb3..346599b25a 100644
--- a/scene/resources/segment_shape_2d.cpp
+++ b/scene/resources/segment_shape_2d.cpp
@@ -32,6 +32,13 @@
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+bool SegmentShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ Vector2 l[2] = { a, b };
+ Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l);
+ return p_point.distance_to(closest) < p_tolerance;
+}
+
void SegmentShape2D::_update_shape() {
Rect2 r;
diff --git a/scene/resources/segment_shape_2d.h b/scene/resources/segment_shape_2d.h
index 1285ae4f82..39a71f61d5 100644
--- a/scene/resources/segment_shape_2d.h
+++ b/scene/resources/segment_shape_2d.h
@@ -44,6 +44,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_a(const Vector2 &p_a);
void set_b(const Vector2 &p_b);
diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h
index 5c2c24ed74..877a159aee 100644
--- a/scene/resources/shape_2d.h
+++ b/scene/resources/shape_2d.h
@@ -44,6 +44,8 @@ protected:
Shape2D(const RID &p_rid);
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { return true; }
+
void set_custom_solver_bias(real_t p_bias);
real_t get_custom_solver_bias() const;
diff --git a/scene/resources/shape_line_2d.cpp b/scene/resources/shape_line_2d.cpp
index c6cc3659f6..9548d35370 100644
--- a/scene/resources/shape_line_2d.cpp
+++ b/scene/resources/shape_line_2d.cpp
@@ -30,6 +30,21 @@
#include "shape_line_2d.h"
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+
+bool LineShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ Vector2 point = get_d() * get_normal();
+ Vector2 l[2][2] = { { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }, { point, point + get_normal() * 30 } };
+
+ for (int i = 0; i < 2; i++) {
+ Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l[i]);
+ if (p_point.distance_to(closest) < p_tolerance)
+ return true;
+ }
+
+ return false;
+}
+
void LineShape2D::_update_shape() {
Array arr;
diff --git a/scene/resources/shape_line_2d.h b/scene/resources/shape_line_2d.h
index 747500b0ac..fe6f2d675e 100644
--- a/scene/resources/shape_line_2d.h
+++ b/scene/resources/shape_line_2d.h
@@ -44,6 +44,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_normal(const Vector2 &p_normal);
void set_d(real_t p_d);