diff --git a/core/global_constants.cpp b/core/global_constants.cpp index 05384082e..7de8a2f5f 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -118,6 +118,11 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT(MARGIN_RIGHT); BIND_GLOBAL_ENUM_CONSTANT(MARGIN_BOTTOM); + BIND_GLOBAL_ENUM_CONSTANT(SIDE_LEFT); + BIND_GLOBAL_ENUM_CONSTANT(SIDE_TOP); + BIND_GLOBAL_ENUM_CONSTANT(SIDE_RIGHT); + BIND_GLOBAL_ENUM_CONSTANT(SIDE_BOTTOM); + BIND_GLOBAL_ENUM_CONSTANT(CORNER_TOP_LEFT); BIND_GLOBAL_ENUM_CONSTANT(CORNER_TOP_RIGHT); BIND_GLOBAL_ENUM_CONSTANT(CORNER_BOTTOM_RIGHT); diff --git a/core/math/math_defs.h b/core/math/math_defs.h index 9c63d0543..f674d2f1d 100644 --- a/core/math/math_defs.h +++ b/core/math/math_defs.h @@ -92,6 +92,13 @@ enum Margin { MARGIN_BOTTOM }; +enum Side { + SIDE_LEFT, + SIDE_TOP, + SIDE_RIGHT, + SIDE_BOTTOM +}; + enum Corner { CORNER_TOP_LEFT, diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp index 7abbf6c3c..187e4e8ee 100644 --- a/core/math/rect2.cpp +++ b/core/math/rect2.cpp @@ -30,6 +30,8 @@ #include "core/math/transform_2d.h" // Includes rect2.h but Rect2 needs Transform2D +#include "core/math/rect2i.h" + bool Rect2::is_equal_approx(const Rect2 &p_rect) const { return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size); } @@ -263,3 +265,7 @@ next4: return true; } + +Rect2::operator String() const { + return "[P: " + position.operator String() + ", S: " + size + "]"; +} diff --git a/core/math/rect2.h b/core/math/rect2.h index dfc925427..95af2f4de 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -35,6 +35,7 @@ #include "core/math/vector2i.h" struct Transform2D; +struct Rect2i; struct _NO_DISCARD_CLASS_ Rect2 { Point2 position; @@ -146,6 +147,25 @@ struct _NO_DISCARD_CLASS_ Rect2 { return new_rect; } + inline Rect2 intersection(const Rect2 &p_rect) const { + Rect2 new_rect = p_rect; + + if (!intersects(new_rect)) { + return Rect2(); + } + + new_rect.position.x = MAX(p_rect.position.x, position.x); + new_rect.position.y = MAX(p_rect.position.y, position.y); + + Point2 p_rect_end = p_rect.position + p_rect.size; + Point2 end = position + size; + + new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x; + new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y; + + return new_rect; + } + inline Rect2 merge(const Rect2 &p_rect) const { ///< return a merged rect Rect2 new_rect; @@ -204,6 +224,15 @@ struct _NO_DISCARD_CLASS_ Rect2 { return g; } + inline Rect2 grow_side(Side p_side, real_t p_amount) const { + Rect2 g = *this; + g = g.grow_individual((SIDE_LEFT == p_side) ? p_amount : 0, + (SIDE_TOP == p_side) ? p_amount : 0, + (SIDE_RIGHT == p_side) ? p_amount : 0, + (SIDE_BOTTOM == p_side) ? p_amount : 0); + return g; + } + inline Rect2 grow_individual(real_t p_left, real_t p_top, real_t p_right, real_t p_bottom) const { Rect2 g = *this; g.position.x -= p_left; @@ -247,7 +276,78 @@ struct _NO_DISCARD_CLASS_ Rect2 { return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs()); } - operator String() const { return String(position) + ", " + String(size); } + Vector2 get_support(const Vector2 &p_normal) const { + Vector2 half_extents = size * 0.5f; + Vector2 ofs = position + half_extents; + return Vector2( + (p_normal.x > 0) ? -half_extents.x : half_extents.x, + (p_normal.y > 0) ? -half_extents.y : half_extents.y) + + ofs; + } + + _FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const { + Vector2 center = get_center(); + int side_plus = 0; + int side_minus = 0; + Vector2 end = position + size; + + int i_f = p_point_count - 1; + for (int i = 0; i < p_point_count; i++) { + const Vector2 &a = p_points[i_f]; + const Vector2 &b = p_points[i]; + i_f = i; + + Vector2 r = (b - a); + float l = r.length(); + if (l == 0.0f) { + continue; + } + + //check inside + Vector2 tg = r.orthogonal(); + float s = tg.dot(center) - tg.dot(a); + if (s < 0.0f) { + side_plus++; + } else { + side_minus++; + } + + //check ray box + r /= l; + Vector2 ir(1.0f / r.x, 1.0f / r.y); + + // lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner + // r.org is origin of ray + Vector2 t13 = (position - a) * ir; + Vector2 t24 = (end - a) * ir; + + float tmin = MAX(MIN(t13.x, t24.x), MIN(t13.y, t24.y)); + float tmax = MIN(MAX(t13.x, t24.x), MAX(t13.y, t24.y)); + + // if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us + if (tmax < 0 || tmin > tmax || tmin >= l) { + continue; + } + + return true; + } + + if (side_plus * side_minus == 0) { + return true; //all inside + } else { + return false; + } + } + + _FORCE_INLINE_ void set_end(const Vector2 &p_end) { + size = p_end - position; + } + + _FORCE_INLINE_ Vector2 get_end() const { + return position + size; + } + + operator String() const; Rect2() {} Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) : @@ -260,5 +360,4 @@ struct _NO_DISCARD_CLASS_ Rect2 { } }; - #endif // RECT2_H diff --git a/core/math/vector2.h b/core/math/vector2.h index 60fd1522e..5ada6412a 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -164,6 +164,9 @@ struct _NO_DISCARD_CLASS_ Vector2 { Vector2 snapped(const Vector2 &p_by) const; real_t aspect() const { return width / height; } + //TODO + Vector2 orthogonal() { return Vector2(); } + operator String() const { return String::num(x) + ", " + String::num(y); } _FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) { diff --git a/core/method_bind.h b/core/method_bind.h index b32adb51f..65c8b444f 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -171,6 +171,7 @@ VARIANT_ENUM_CAST(Vector2i::Axis); VARIANT_ENUM_CAST(Error); VARIANT_ENUM_CAST(Margin); +VARIANT_ENUM_CAST(Side); VARIANT_ENUM_CAST(Corner); VARIANT_ENUM_CAST(Orientation); VARIANT_ENUM_CAST(HAlign); diff --git a/core/variant.cpp b/core/variant.cpp index cdc0b17ad..9a50ecf61 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -2362,6 +2362,9 @@ Variant::operator Vector() const { Variant::operator Margin() const { return (Margin) operator int(); } +Variant::operator Side() const { + return (Side) operator int(); +} Variant::operator Orientation() const { return (Orientation) operator int(); } diff --git a/core/variant.h b/core/variant.h index 0e7c94d59..131503bda 100644 --- a/core/variant.h +++ b/core/variant.h @@ -264,6 +264,7 @@ public: // some core type enums to convert to operator Margin() const; + operator Side() const; operator Orientation() const; operator IP_Address() const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 16d811618..f2353281e 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -457,18 +457,39 @@ struct _VariantCall { VCALL_LOCALMEM0R(Rect2, get_area); VCALL_LOCALMEM0R(Rect2, get_center); + VCALL_LOCALMEM2R(Rect2, intersects); + VCALL_LOCALMEM1R(Rect2, distance_to); + VCALL_LOCALMEM2R(Rect2, intersects_transformed); + static void _call_Rect2_intersects_segment(Variant &r_ret, Variant &p_self, const Variant **p_args) { + Point2 pos; + Point2 normal; + if (reinterpret_cast(p_self._data._mem)->intersects_segment(*p_args[0], *p_args[1], &pos, &normal)) { + Array arr; + arr.push_back(pos); + arr.push_back(normal); + r_ret = arr; + } else { + r_ret = Variant(); + } + } + VCALL_LOCALMEM1R(Rect2, encloses); VCALL_LOCALMEM0R(Rect2, has_no_area); + VCALL_LOCALMEM1R(Rect2, clip); + VCALL_LOCALMEM1R(Rect2, intersection); + VCALL_LOCALMEM1R(Rect2, merge); VCALL_LOCALMEM1R(Rect2, has_point); VCALL_LOCALMEM1R(Rect2, is_equal_approx); - VCALL_LOCALMEM2R(Rect2, intersects); - VCALL_LOCALMEM1R(Rect2, encloses); - VCALL_LOCALMEM1R(Rect2, clip); - VCALL_LOCALMEM1R(Rect2, merge); - VCALL_LOCALMEM1R(Rect2, expand); VCALL_LOCALMEM1R(Rect2, grow); + VCALL_LOCALMEM1(Rect2, grow_by); VCALL_LOCALMEM2R(Rect2, grow_margin); + VCALL_LOCALMEM2R(Rect2, grow_side); VCALL_LOCALMEM4R(Rect2, grow_individual); + VCALL_LOCALMEM1R(Rect2, expand); + VCALL_LOCALMEM1(Rect2, expand_to); VCALL_LOCALMEM0R(Rect2, abs); + VCALL_LOCALMEM1R(Rect2, get_support); + VCALL_LOCALMEM1(Rect2, set_end); + VCALL_LOCALMEM0R(Rect2, get_end); VCALL_LOCALMEM0R(Rect2i, get_area); VCALL_LOCALMEM0R(Rect2i, get_center); @@ -2172,18 +2193,28 @@ void register_variant_methods() { ADDFUNC0R(RECT2, REAL, Rect2, get_area, varray()); ADDFUNC0R(RECT2, VECTOR2, Rect2, get_center, varray()); + ADDFUNC2R(RECT2, BOOL, Rect2, intersects, RECT2, "b", BOOL, "include_borders", varray(false)); + ADDFUNC1R(RECT2, REAL, Rect2, distance_to, VECTOR2, "point", varray()); + ADDFUNC2R(RECT2, BOOL, Rect2, intersects_transformed, TRANSFORM2D, "xform", RECT2, "rect", varray()); + ADDFUNC2R(RECT2, NIL, Rect2, intersects_segment, VECTOR2, "from", VECTOR2, "to", varray()); + ADDFUNC1R(RECT2, BOOL, Rect2, encloses, RECT2, "b", varray()); ADDFUNC0R(RECT2, BOOL, Rect2, has_no_area, varray()); + ADDFUNC1R(RECT2, RECT2, Rect2, clip, RECT2, "b", varray()); + ADDFUNC1R(RECT2, RECT2, Rect2, intersection, RECT2, "rect", varray()); + ADDFUNC1R(RECT2, RECT2, Rect2, merge, RECT2, "b", varray()); ADDFUNC1R(RECT2, BOOL, Rect2, has_point, VECTOR2, "point", varray()); ADDFUNC1R(RECT2, BOOL, Rect2, is_equal_approx, RECT2, "rect", varray()); - ADDFUNC2R(RECT2, BOOL, Rect2, intersects, RECT2, "b", BOOL, "include_borders", varray(false)); - ADDFUNC1R(RECT2, BOOL, Rect2, encloses, RECT2, "b", varray()); - ADDFUNC1R(RECT2, RECT2, Rect2, clip, RECT2, "b", varray()); - ADDFUNC1R(RECT2, RECT2, Rect2, merge, RECT2, "b", varray()); - ADDFUNC1R(RECT2, RECT2, Rect2, expand, VECTOR2, "to", varray()); ADDFUNC1R(RECT2, RECT2, Rect2, grow, REAL, "by", varray()); + ADDFUNC1(RECT2, NIL, Rect2, grow_by, REAL, "by", varray()); ADDFUNC2R(RECT2, RECT2, Rect2, grow_margin, INT, "margin", REAL, "by", varray()); + ADDFUNC2R(RECT2, RECT2, Rect2, grow_side, INT, "side", REAL, "by", varray()); ADDFUNC4R(RECT2, RECT2, Rect2, grow_individual, REAL, "left", REAL, "top", REAL, "right", REAL, " bottom", varray()); + ADDFUNC1R(RECT2, RECT2, Rect2, expand, VECTOR2, "to", varray()); + ADDFUNC1R(RECT2, RECT2, Rect2, expand_to, VECTOR2, "to", varray()); ADDFUNC0R(RECT2, RECT2, Rect2, abs, varray()); + ADDFUNC1R(RECT2, VECTOR2, Rect2, get_support, VECTOR2, "normal", varray()); + ADDFUNC1(RECT2, NIL, Rect2, set_end, VECTOR2, "end", varray()); + ADDFUNC0R(RECT2, VECTOR2, Rect2, get_end, varray()); ADDFUNC0R(RECT2I, INT, Rect2i, get_area, varray()); ADDFUNC0R(RECT2I, VECTOR2I, Rect2i, get_center, varray()); @@ -2280,7 +2311,6 @@ void register_variant_methods() { ADDFUNC0R(COLOR, INT, Color, to_argb64, varray()); ADDFUNC0R(COLOR, INT, Color, to_abgr64, varray()); ADDFUNC0R(COLOR, REAL, Color, gray, varray()); - ADDFUNC0R(COLOR, REAL, Color, get_h, varray()); ADDFUNC0R(COLOR, REAL, Color, get_s, varray()); ADDFUNC0R(COLOR, REAL, Color, get_v, varray());