diff --git a/include/godot_cpp/core/math.hpp b/include/godot_cpp/core/math.hpp index 2ee7b54cd..b4c5e84e3 100644 --- a/include/godot_cpp/core/math.hpp +++ b/include/godot_cpp/core/math.hpp @@ -295,7 +295,32 @@ constexpr int64_t division_round_up(int64_t p_num, int64_t p_den) { constexpr uint64_t division_round_up(uint64_t p_num, uint64_t p_den) { return (p_num + p_den - 1) / p_den; } - +GODOT_MSVC_WARNING_PUSH_AND_IGNORE(4146) // Unary minus operator applied to unsigned type, result still unsigned +constexpr int32_t division_no_overflow(int32_t p_num, int32_t p_den) { + if (unlikely(p_den == -1)) { + return int32_t(-uint32_t(p_num)); + } + return p_num / p_den; +} +constexpr int64_t division_no_overflow(int64_t p_num, int64_t p_den) { + if (unlikely(p_den == -1)) { + return int64_t(-uint64_t(p_num)); + } + return p_num / p_den; +} +GODOT_MSVC_WARNING_POP +constexpr int32_t modulo_no_overflow(int32_t p_num, int32_t p_den) { + if (unlikely(p_den == -1)) { + return 0; + } + return p_num % p_den; +} +constexpr int64_t modulo_no_overflow(int64_t p_num, int64_t p_den) { + if (unlikely(p_den == -1)) { + return 0; + } + return p_num % p_den; +} constexpr bool is_finite(double p_val) { return !is_nan(p_val) && !is_inf(p_val); } diff --git a/include/godot_cpp/variant/aabb.hpp b/include/godot_cpp/variant/aabb.hpp index cac221964..ee5d8fba3 100644 --- a/include/godot_cpp/variant/aabb.hpp +++ b/include/godot_cpp/variant/aabb.hpp @@ -60,10 +60,15 @@ struct [[nodiscard]] AABB { const Vector3 &get_size() const { return size; } void set_size(const Vector3 &p_size) { size = p_size; } - bool operator==(const AABB &p_rval) const; - bool operator!=(const AABB &p_rval) const; + constexpr bool operator==(const AABB &p_rval) const { + return position == p_rval.position && size == p_rval.size; + } + constexpr bool operator!=(const AABB &p_rval) const { + return position != p_rval.position || size != p_rval.size; + } bool is_equal_approx(const AABB &p_aabb) const; + bool is_same(const AABB &p_aabb) const; bool is_finite() const; _FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap _FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap @@ -128,10 +133,10 @@ struct [[nodiscard]] AABB { return position + (size * 0.5f); } - operator String() const; + explicit operator String() const; - _FORCE_INLINE_ AABB() {} - inline AABB(const Vector3 &p_pos, const Vector3 &p_size) : + AABB() = default; + constexpr AABB(const Vector3 &p_pos, const Vector3 &p_size) : position(p_pos), size(p_size) { } @@ -273,10 +278,10 @@ bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count, con for (int k = 0; k < 3; k++) { for (int i = 0; i < p_point_count; i++) { - if (p_points[i].coord[k] > ofs.coord[k] + half_extents.coord[k]) { + if (p_points[i][k] > ofs[k] + half_extents[k]) { bad_point_counts_positive[k]++; } - if (p_points[i].coord[k] < ofs.coord[k] - half_extents.coord[k]) { + if (p_points[i][k] < ofs[k] - half_extents[k]) { bad_point_counts_negative[k]++; } } @@ -497,4 +502,6 @@ AABB AABB::quantized(real_t p_unit) const { return ret; } +template <> +struct is_zero_constructible : std::true_type {}; } // namespace godot diff --git a/include/godot_cpp/variant/basis.hpp b/include/godot_cpp/variant/basis.hpp index efe21cf6d..978764f57 100644 --- a/include/godot_cpp/variant/basis.hpp +++ b/include/godot_cpp/variant/basis.hpp @@ -37,16 +37,20 @@ namespace godot { struct [[nodiscard]] Basis { + static const Basis FLIP_X; + static const Basis FLIP_Y; + static const Basis FLIP_Z; + Vector3 rows[3] = { Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1) }; - _FORCE_INLINE_ const Vector3 &operator[](int p_row) const { + constexpr const Vector3 &operator[](int p_row) const { return rows[p_row]; } - _FORCE_INLINE_ Vector3 &operator[](int p_row) { + constexpr Vector3 &operator[](int p_row) { return rows[p_row]; } @@ -77,7 +81,7 @@ struct [[nodiscard]] Basis { void rotate_to_align(Vector3 p_start_direction, Vector3 p_end_direction); - Vector3 rotref_posscale_decomposition(Basis &rotref) const; + Vector3 rotref_posscale_decomposition(Basis &r_rotref) const; Vector3 get_euler(EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const; void set_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ); @@ -123,23 +127,24 @@ struct [[nodiscard]] Basis { } bool is_equal_approx(const Basis &p_basis) const; + bool is_same(const Basis &p_basis) const; bool is_finite() const; - bool operator==(const Basis &p_matrix) const; - bool operator!=(const Basis &p_matrix) const; + constexpr bool operator==(const Basis &p_matrix) const; + constexpr bool operator!=(const Basis &p_matrix) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const; _FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const; _FORCE_INLINE_ void operator*=(const Basis &p_matrix); _FORCE_INLINE_ Basis operator*(const Basis &p_matrix) const; - _FORCE_INLINE_ void operator+=(const Basis &p_matrix); - _FORCE_INLINE_ Basis operator+(const Basis &p_matrix) const; - _FORCE_INLINE_ void operator-=(const Basis &p_matrix); - _FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const; - _FORCE_INLINE_ void operator*=(real_t p_val); - _FORCE_INLINE_ Basis operator*(real_t p_val) const; - _FORCE_INLINE_ void operator/=(real_t p_val); - _FORCE_INLINE_ Basis operator/(real_t p_val) const; + constexpr void operator+=(const Basis &p_matrix); + constexpr Basis operator+(const Basis &p_matrix) const; + constexpr void operator-=(const Basis &p_matrix); + constexpr Basis operator-(const Basis &p_matrix) const; + constexpr void operator*=(real_t p_val); + constexpr Basis operator*(real_t p_val) const; + constexpr void operator/=(real_t p_val); + constexpr Basis operator/(real_t p_val) const; bool is_orthogonal() const; bool is_orthonormal() const; @@ -151,7 +156,7 @@ struct [[nodiscard]] Basis { Basis slerp(const Basis &p_to, real_t p_weight) const; void rotate_sh(real_t *p_values); - operator String() const; + explicit operator String() const; /* create / set */ @@ -206,9 +211,12 @@ struct [[nodiscard]] Basis { rows[0].z * p_m[0].y + rows[1].z * p_m[1].y + rows[2].z * p_m[2].y, rows[0].z * p_m[0].z + rows[1].z * p_m[1].z + rows[2].z * p_m[2].z); } - Basis(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) { - set(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz); - } + constexpr Basis(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) : + rows{ + { p_xx, p_xy, p_xz }, + { p_yx, p_yy, p_yz }, + { p_zx, p_zy, p_zz }, + } {} void orthonormalize(); Basis orthonormalized() const; @@ -223,7 +231,7 @@ struct [[nodiscard]] Basis { operator Quaternion() const { return get_quaternion(); } - static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false); + static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3::UP, bool p_use_model_front = false); Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); } Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); } @@ -232,17 +240,40 @@ struct [[nodiscard]] Basis { Basis(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_angle, p_scale); } static Basis from_scale(const Vector3 &p_scale); - _FORCE_INLINE_ Basis(const Vector3 &p_x_axis, const Vector3 &p_y_axis, const Vector3 &p_z_axis) { - set_columns(p_x_axis, p_y_axis, p_z_axis); - } + constexpr Basis(const Vector3 &p_x_axis, const Vector3 &p_y_axis, const Vector3 &p_z_axis) : + rows{ + { p_x_axis.x, p_y_axis.x, p_z_axis.x }, + { p_x_axis.y, p_y_axis.y, p_z_axis.y }, + { p_x_axis.z, p_y_axis.z, p_z_axis.z }, + } {} - _FORCE_INLINE_ Basis() {} + Basis() = default; private: // Helper method. void _set_diagonal(const Vector3 &p_diag); }; +inline constexpr Basis Basis::FLIP_X = { { -1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; +inline constexpr Basis Basis::FLIP_Y = { { 1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } }; +inline constexpr Basis Basis::FLIP_Z = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, -1 } }; + +constexpr bool Basis::operator==(const Basis &p_matrix) const { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (rows[i][j] != p_matrix.rows[i][j]) { + return false; + } + } + } + + return true; +} + +constexpr bool Basis::operator!=(const Basis &p_matrix) const { + return (!(*this == p_matrix)); +} + _FORCE_INLINE_ void Basis::operator*=(const Basis &p_matrix) { set( p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]), @@ -257,49 +288,49 @@ _FORCE_INLINE_ Basis Basis::operator*(const Basis &p_matrix) const { p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2])); } -_FORCE_INLINE_ void Basis::operator+=(const Basis &p_matrix) { +constexpr void Basis::operator+=(const Basis &p_matrix) { rows[0] += p_matrix.rows[0]; rows[1] += p_matrix.rows[1]; rows[2] += p_matrix.rows[2]; } -_FORCE_INLINE_ Basis Basis::operator+(const Basis &p_matrix) const { +constexpr Basis Basis::operator+(const Basis &p_matrix) const { Basis ret(*this); ret += p_matrix; return ret; } -_FORCE_INLINE_ void Basis::operator-=(const Basis &p_matrix) { +constexpr void Basis::operator-=(const Basis &p_matrix) { rows[0] -= p_matrix.rows[0]; rows[1] -= p_matrix.rows[1]; rows[2] -= p_matrix.rows[2]; } -_FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const { +constexpr Basis Basis::operator-(const Basis &p_matrix) const { Basis ret(*this); ret -= p_matrix; return ret; } -_FORCE_INLINE_ void Basis::operator*=(real_t p_val) { +constexpr void Basis::operator*=(real_t p_val) { rows[0] *= p_val; rows[1] *= p_val; rows[2] *= p_val; } -_FORCE_INLINE_ Basis Basis::operator*(real_t p_val) const { +constexpr Basis Basis::operator*(real_t p_val) const { Basis ret(*this); ret *= p_val; return ret; } -_FORCE_INLINE_ void Basis::operator/=(real_t p_val) { +constexpr void Basis::operator/=(real_t p_val) { rows[0] /= p_val; rows[1] /= p_val; rows[2] /= p_val; } -_FORCE_INLINE_ Basis Basis::operator/(real_t p_val) const { +constexpr Basis Basis::operator/(real_t p_val) const { Basis ret(*this); ret /= p_val; return ret; diff --git a/include/godot_cpp/variant/color.hpp b/include/godot_cpp/variant/color.hpp index d3bbc725b..7ef10fe02 100644 --- a/include/godot_cpp/variant/color.hpp +++ b/include/godot_cpp/variant/color.hpp @@ -37,15 +37,10 @@ namespace godot { class String; struct [[nodiscard]] Color { - union { - struct { - float r; - float g; - float b; - float a; - }; - float components[4] = { 0, 0, 0, 1.0 }; - }; + float r = 0.0f; + float g = 0.0f; + float b = 0.0f; + float a = 1.0f; uint32_t to_rgba32() const; uint32_t to_argb32() const; @@ -59,38 +54,51 @@ struct [[nodiscard]] Color { float get_v() const; void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f); - _FORCE_INLINE_ float &operator[](int p_idx) { - return components[p_idx]; + constexpr float &operator[](int p_idx) { + // The pointer math below assumes that the elements are placed back-to-back, like an array. + // This is always true in practice, but technically not guaranteed; we safety-check it here. + static_assert(offsetof(Color, r) == 0 * sizeof(float)); + static_assert(offsetof(Color, g) == 1 * sizeof(float)); + static_assert(offsetof(Color, b) == 2 * sizeof(float)); + static_assert(offsetof(Color, a) == 3 * sizeof(float)); + static_assert(sizeof(Color) == 4 * sizeof(float)); + + DEV_ASSERT((unsigned int)p_idx < 4); + return (&r)[p_idx]; } - _FORCE_INLINE_ const float &operator[](int p_idx) const { - return components[p_idx]; + constexpr const float &operator[](int p_idx) const { + DEV_ASSERT((unsigned int)p_idx < 4); + return (&r)[p_idx]; } - bool operator==(const Color &p_color) const { + constexpr const float *as_float4_buffer() const { return &r; } + + constexpr bool operator==(const Color &p_color) const { return (r == p_color.r && g == p_color.g && b == p_color.b && a == p_color.a); } - bool operator!=(const Color &p_color) const { + constexpr bool operator!=(const Color &p_color) const { return (r != p_color.r || g != p_color.g || b != p_color.b || a != p_color.a); } - Color operator+(const Color &p_color) const; - void operator+=(const Color &p_color); + constexpr Color operator+(const Color &p_color) const; + constexpr void operator+=(const Color &p_color); - Color operator-() const; - Color operator-(const Color &p_color) const; - void operator-=(const Color &p_color); + constexpr Color operator-() const; + constexpr Color operator-(const Color &p_color) const; + constexpr void operator-=(const Color &p_color); - Color operator*(const Color &p_color) const; - Color operator*(float p_scalar) const; - void operator*=(const Color &p_color); - void operator*=(float p_scalar); + constexpr Color operator*(const Color &p_color) const; + constexpr Color operator*(float p_scalar) const; + constexpr void operator*=(const Color &p_color); + constexpr void operator*=(float p_scalar); - Color operator/(const Color &p_color) const; - Color operator/(float p_scalar) const; - void operator/=(const Color &p_color); - void operator/=(float p_scalar); + constexpr Color operator/(const Color &p_color) const; + constexpr Color operator/(float p_scalar) const; + constexpr void operator/=(const Color &p_color); + constexpr void operator/=(float p_scalar); bool is_equal_approx(const Color &p_color) const; + bool is_same(const Color &p_color) const; Color clamp(const Color &p_min = Color(0, 0, 0, 0), const Color &p_max = Color(1, 1, 1, 1)) const; void invert(); @@ -211,55 +219,43 @@ struct [[nodiscard]] Color { static Color from_rgbe9995(uint32_t p_rgbe); static Color from_rgba8(int64_t p_r8, int64_t p_g8, int64_t p_b8, int64_t p_a8 = 255); - _FORCE_INLINE_ bool operator<(const Color &p_color) const; // Used in set keys. - operator String() const; + constexpr bool operator<(const Color &p_color) const; // Used in set keys. + explicit operator String() const; // For the binder. - _FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0f); } + _FORCE_INLINE_ void set_r8(int32_t p_r8) { r = (CLAMP(p_r8, 0, 255) / 255.0f); } _FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(Math::round(r * 255.0f), 0.0f, 255.0f)); } - _FORCE_INLINE_ void set_g8(int32_t g8) { g = (CLAMP(g8, 0, 255) / 255.0f); } + _FORCE_INLINE_ void set_g8(int32_t p_g8) { g = (CLAMP(p_g8, 0, 255) / 255.0f); } _FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(Math::round(g * 255.0f), 0.0f, 255.0f)); } - _FORCE_INLINE_ void set_b8(int32_t b8) { b = (CLAMP(b8, 0, 255) / 255.0f); } + _FORCE_INLINE_ void set_b8(int32_t p_b8) { b = (CLAMP(p_b8, 0, 255) / 255.0f); } _FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(Math::round(b * 255.0f), 0.0f, 255.0f)); } - _FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0f); } + _FORCE_INLINE_ void set_a8(int32_t p_a8) { a = (CLAMP(p_a8, 0, 255) / 255.0f); } _FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(Math::round(a * 255.0f), 0.0f, 255.0f)); } _FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v(), a); } _FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v(), a); } _FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v, a); } - _FORCE_INLINE_ Color() {} + constexpr Color() = default; /** * RGBA construct parameters. * Alpha is not optional as otherwise we can't bind the RGB version for scripting. */ - _FORCE_INLINE_ Color(float p_r, float p_g, float p_b, float p_a) { - r = p_r; - g = p_g; - b = p_b; - a = p_a; - } + constexpr Color(float p_r, float p_g, float p_b, float p_a) : + r(p_r), g(p_g), b(p_b), a(p_a) {} /** * RGB construct parameters. */ - _FORCE_INLINE_ Color(float p_r, float p_g, float p_b) { - r = p_r; - g = p_g; - b = p_b; - a = 1.0f; - } + constexpr Color(float p_r, float p_g, float p_b) : + r(p_r), g(p_g), b(p_b), a(1) {} /** * Construct a Color from another Color, but with the specified alpha value. */ - _FORCE_INLINE_ Color(const Color &p_c, float p_a) { - r = p_c.r; - g = p_c.g; - b = p_c.b; - a = p_a; - } + constexpr Color(const Color &p_c, float p_a) : + r(p_c.r), g(p_c.g), b(p_c.b), a(p_a) {} Color(const String &p_code) { if (html_is_valid(p_code)) { @@ -275,7 +271,105 @@ struct [[nodiscard]] Color { } }; -bool Color::operator<(const Color &p_color) const { +constexpr Color Color::operator+(const Color &p_color) const { + return Color( + r + p_color.r, + g + p_color.g, + b + p_color.b, + a + p_color.a); +} + +constexpr void Color::operator+=(const Color &p_color) { + r = r + p_color.r; + g = g + p_color.g; + b = b + p_color.b; + a = a + p_color.a; +} + +constexpr Color Color::operator-(const Color &p_color) const { + return Color( + r - p_color.r, + g - p_color.g, + b - p_color.b, + a - p_color.a); +} + +constexpr void Color::operator-=(const Color &p_color) { + r = r - p_color.r; + g = g - p_color.g; + b = b - p_color.b; + a = a - p_color.a; +} + +constexpr Color Color::operator*(const Color &p_color) const { + return Color( + r * p_color.r, + g * p_color.g, + b * p_color.b, + a * p_color.a); +} + +constexpr Color Color::operator*(float p_scalar) const { + return Color( + r * p_scalar, + g * p_scalar, + b * p_scalar, + a * p_scalar); +} + +constexpr void Color::operator*=(const Color &p_color) { + r = r * p_color.r; + g = g * p_color.g; + b = b * p_color.b; + a = a * p_color.a; +} + +constexpr void Color::operator*=(float p_scalar) { + r = r * p_scalar; + g = g * p_scalar; + b = b * p_scalar; + a = a * p_scalar; +} + +constexpr Color Color::operator/(const Color &p_color) const { + return Color( + r / p_color.r, + g / p_color.g, + b / p_color.b, + a / p_color.a); +} + +constexpr Color Color::operator/(float p_scalar) const { + return Color( + r / p_scalar, + g / p_scalar, + b / p_scalar, + a / p_scalar); +} + +constexpr void Color::operator/=(const Color &p_color) { + r = r / p_color.r; + g = g / p_color.g; + b = b / p_color.b; + a = a / p_color.a; +} + +constexpr void Color::operator/=(float p_scalar) { + r = r / p_scalar; + g = g / p_scalar; + b = b / p_scalar; + a = a / p_scalar; +} + +constexpr Color Color::operator-() const { + return Color( + 1.0f - r, + 1.0f - g, + 1.0f - b, + 1.0f - a); +} + +constexpr bool Color::operator<(const Color &p_color) const { if (r == p_color.r) { if (g == p_color.g) { if (b == p_color.b) { @@ -291,7 +385,7 @@ bool Color::operator<(const Color &p_color) const { } } -_FORCE_INLINE_ Color operator*(float p_scalar, const Color &p_color) { +constexpr Color operator*(float p_scalar, const Color &p_color) { return p_color * p_scalar; } diff --git a/include/godot_cpp/variant/plane.hpp b/include/godot_cpp/variant/plane.hpp index c7572045b..3284e3e65 100644 --- a/include/godot_cpp/variant/plane.hpp +++ b/include/godot_cpp/variant/plane.hpp @@ -38,12 +38,21 @@ namespace godot { class Variant; struct [[nodiscard]] Plane { + static const Plane PLANE_YZ; + static const Plane PLANE_XZ; + static const Plane PLANE_XY; + Vector3 normal; real_t d = 0; void set_normal(const Vector3 &p_normal); _FORCE_INLINE_ Vector3 get_normal() const { return normal; } + void zero() { + normal.zero(); + d = 0; + } + void normalize(); Plane normalized() const; @@ -73,25 +82,30 @@ struct [[nodiscard]] Plane { /* misc */ - Plane operator-() const { return Plane(-normal, -d); } + constexpr Plane operator-() const { return Plane(-normal, -d); } bool is_equal_approx(const Plane &p_plane) const; + bool is_same(const Plane &p_plane) const; bool is_equal_approx_any_side(const Plane &p_plane) const; bool is_finite() const; - _FORCE_INLINE_ bool operator==(const Plane &p_plane) const; - _FORCE_INLINE_ bool operator!=(const Plane &p_plane) const; - operator String() const; + constexpr bool operator==(const Plane &p_plane) const; + constexpr bool operator!=(const Plane &p_plane) const; + explicit operator String() const; - _FORCE_INLINE_ Plane() {} - _FORCE_INLINE_ Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) : + Plane() = default; + constexpr Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) : normal(p_a, p_b, p_c), d(p_d) {} - _FORCE_INLINE_ Plane(const Vector3 &p_normal, real_t p_d = 0.0); + constexpr Plane(const Vector3 &p_normal, real_t p_d = 0.0); _FORCE_INLINE_ Plane(const Vector3 &p_normal, const Vector3 &p_point); _FORCE_INLINE_ Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir = CLOCKWISE); }; +inline constexpr Plane Plane::PLANE_YZ = { 1, 0, 0, 0 }; +inline constexpr Plane Plane::PLANE_XZ = { 0, 1, 0, 0 }; +inline constexpr Plane Plane::PLANE_XY = { 0, 0, 1, 0 }; + bool Plane::is_point_over(const Vector3 &p_point) const { return (normal.dot(p_point) > d); } @@ -106,7 +120,7 @@ bool Plane::has_point(const Vector3 &p_point, real_t p_tolerance) const { return (dist <= p_tolerance); } -Plane::Plane(const Vector3 &p_normal, real_t p_d) : +constexpr Plane::Plane(const Vector3 &p_normal, real_t p_d) : normal(p_normal), d(p_d) { } @@ -127,12 +141,15 @@ Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_ d = normal.dot(p_point1); } -bool Plane::operator==(const Plane &p_plane) const { +constexpr bool Plane::operator==(const Plane &p_plane) const { return normal == p_plane.normal && d == p_plane.d; } -bool Plane::operator!=(const Plane &p_plane) const { +constexpr bool Plane::operator!=(const Plane &p_plane) const { return normal != p_plane.normal || d != p_plane.d; } +template <> +struct is_zero_constructible : std::true_type {}; + } // namespace godot diff --git a/include/godot_cpp/variant/projection.hpp b/include/godot_cpp/variant/projection.hpp index 42eb41662..7df1e9608 100644 --- a/include/godot_cpp/variant/projection.hpp +++ b/include/godot_cpp/variant/projection.hpp @@ -54,14 +54,19 @@ struct [[nodiscard]] Projection { PLANE_BOTTOM }; - Vector4 columns[4]; + Vector4 columns[4] = { + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 }, + }; - _FORCE_INLINE_ const Vector4 &operator[](int p_axis) const { + constexpr const Vector4 &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 4); return columns[p_axis]; } - _FORCE_INLINE_ Vector4 &operator[](int p_axis) { + constexpr Vector4 &operator[](int p_axis) { DEV_ASSERT((unsigned int)p_axis < 4); return columns[p_axis]; } @@ -116,7 +121,7 @@ struct [[nodiscard]] Projection { void invert(); Projection inverse() const; - Projection operator*(const Projection &p_matrix) const; + constexpr Projection operator*(const Projection &p_matrix) const; Plane xform4(const Plane &p_vec4) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vec3) const; @@ -124,7 +129,7 @@ struct [[nodiscard]] Projection { Vector4 xform(const Vector4 &p_vec4) const; Vector4 xform_inv(const Vector4 &p_vec4) const; - operator String() const; + explicit operator String() const; void scale_translate_to_fit(const AABB &p_aabb); void add_jitter_offset(const Vector2 &p_offset); @@ -134,7 +139,9 @@ struct [[nodiscard]] Projection { void flip_y(); - bool operator==(const Projection &p_cam) const { + bool is_same(const Projection &p_cam) const; + + constexpr bool operator==(const Projection &p_cam) const { for (uint32_t i = 0; i < 4; i++) { for (uint32_t j = 0; j < 4; j++) { if (columns[i][j] != p_cam.columns[i][j]) { @@ -145,19 +152,41 @@ struct [[nodiscard]] Projection { return true; } - bool operator!=(const Projection &p_cam) const { + constexpr bool operator!=(const Projection &p_cam) const { return !(*this == p_cam); } real_t get_lod_multiplier() const; - Projection(); - Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w); - Projection(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_xw, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_yw, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_zw, real_t p_wx, real_t p_wy, real_t p_wz, real_t p_ww); + Projection() = default; + constexpr Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w) : + columns{ p_x, p_y, p_z, p_w } {} + constexpr Projection(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_xw, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_yw, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_zw, real_t p_wx, real_t p_wy, real_t p_wz, real_t p_ww) : + columns{ + { p_xx, p_xy, p_xz, p_xw }, + { p_yx, p_yy, p_yz, p_yw }, + { p_zx, p_zy, p_zz, p_zw }, + { p_wx, p_wy, p_wz, p_ww }, + } {} Projection(const Transform3D &p_transform); - ~Projection(); }; +constexpr Projection Projection::operator*(const Projection &p_matrix) const { + Projection new_matrix; + + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + real_t ab = 0; + for (int k = 0; k < 4; k++) { + ab += columns[k][i] * p_matrix.columns[j][k]; + } + new_matrix.columns[j][i] = ab; + } + } + + return new_matrix; +} + Vector3 Projection::xform(const Vector3 &p_vec3) const { Vector3 ret; ret.x = columns[0][0] * p_vec3.x + columns[1][0] * p_vec3.y + columns[2][0] * p_vec3.z + columns[3][0]; diff --git a/include/godot_cpp/variant/quaternion.hpp b/include/godot_cpp/variant/quaternion.hpp index d0efa0867..3606a095e 100644 --- a/include/godot_cpp/variant/quaternion.hpp +++ b/include/godot_cpp/variant/quaternion.hpp @@ -37,24 +37,31 @@ namespace godot { struct [[nodiscard]] Quaternion { - union { - struct { - real_t x; - real_t y; - real_t z; - real_t w; - }; - real_t components[4] = { 0, 0, 0, 1.0 }; - }; - - _FORCE_INLINE_ real_t &operator[](int p_idx) { - return components[p_idx]; + real_t x = 0.0f; + real_t y = 0.0f; + real_t z = 0.0f; + real_t w = 1.0f; + + constexpr real_t &operator[](int p_idx) { + // The pointer math below assumes that the elements are placed back-to-back, like an array. + // This is always true in practice, but technically not guaranteed; we safety-check it here. + static_assert(offsetof(Quaternion, x) == 0 * sizeof(real_t)); + static_assert(offsetof(Quaternion, y) == 1 * sizeof(real_t)); + static_assert(offsetof(Quaternion, z) == 2 * sizeof(real_t)); + static_assert(offsetof(Quaternion, w) == 3 * sizeof(real_t)); + static_assert(sizeof(Quaternion) == 4 * sizeof(real_t)); + + DEV_ASSERT((unsigned int)p_idx < 4); + return (&x)[p_idx]; } - _FORCE_INLINE_ const real_t &operator[](int p_idx) const { - return components[p_idx]; + constexpr const real_t &operator[](int p_idx) const { + DEV_ASSERT((unsigned int)p_idx < 4); + return (&x)[p_idx]; } + _FORCE_INLINE_ real_t length_squared() const; bool is_equal_approx(const Quaternion &p_quaternion) const; + bool is_same(const Quaternion &p_quaternion) const; bool is_finite() const; real_t length() const; void normalize(); @@ -85,8 +92,8 @@ struct [[nodiscard]] Quaternion { r_axis.z = z * r; } - void operator*=(const Quaternion &p_q); - Quaternion operator*(const Quaternion &p_q) const; + constexpr void operator*=(const Quaternion &p_q); + constexpr Quaternion operator*(const Quaternion &p_q) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_v) const { #ifdef MATH_CHECKS @@ -101,51 +108,37 @@ struct [[nodiscard]] Quaternion { return inverse().xform(p_v); } - _FORCE_INLINE_ void operator+=(const Quaternion &p_q); - _FORCE_INLINE_ void operator-=(const Quaternion &p_q); - _FORCE_INLINE_ void operator*=(real_t p_s); - _FORCE_INLINE_ void operator/=(real_t p_s); - _FORCE_INLINE_ Quaternion operator+(const Quaternion &p_q2) const; - _FORCE_INLINE_ Quaternion operator-(const Quaternion &p_q2) const; - _FORCE_INLINE_ Quaternion operator-() const; - _FORCE_INLINE_ Quaternion operator*(real_t p_s) const; - _FORCE_INLINE_ Quaternion operator/(real_t p_s) const; + constexpr void operator+=(const Quaternion &p_q); + constexpr void operator-=(const Quaternion &p_q); + constexpr void operator*=(real_t p_s); + constexpr void operator/=(real_t p_s); + constexpr Quaternion operator+(const Quaternion &p_q2) const; + constexpr Quaternion operator-(const Quaternion &p_q2) const; + constexpr Quaternion operator-() const; + constexpr Quaternion operator*(real_t p_s) const; + constexpr Quaternion operator/(real_t p_s) const; - _FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const; - _FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const; + constexpr bool operator==(const Quaternion &p_quaternion) const; + constexpr bool operator!=(const Quaternion &p_quaternion) const; - operator String() const; + explicit operator String() const; - _FORCE_INLINE_ Quaternion() {} + constexpr Quaternion() = default; - _FORCE_INLINE_ Quaternion(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : - x(p_x), - y(p_y), - z(p_z), - w(p_w) { - } + constexpr Quaternion(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : + x(p_x), y(p_y), z(p_z), w(p_w) {} Quaternion(const Vector3 &p_axis, real_t p_angle); - Quaternion(const Quaternion &p_q) : - x(p_q.x), - y(p_q.y), - z(p_q.z), - w(p_q.w) { - } - - void operator=(const Quaternion &p_q) { - x = p_q.x; - y = p_q.y; - z = p_q.z; - w = p_q.w; - } - Quaternion(const Vector3 &p_v0, const Vector3 &p_v1) { // Shortest arc. #ifdef MATH_CHECKS ERR_FAIL_COND_MSG(p_v0.is_zero_approx() || p_v1.is_zero_approx(), "The vectors must not be zero."); #endif - constexpr real_t ALMOST_ONE = 1.0f - (real_t)CMP_EPSILON; +#ifdef REAL_T_IS_DOUBLE + constexpr real_t ALMOST_ONE = 0.999999999999999; +#else + constexpr real_t ALMOST_ONE = 0.99999975f; +#endif Vector3 n0 = p_v0.normalized(); Vector3 n1 = p_v1.normalized(); real_t d = n0.dot(n1); @@ -168,6 +161,7 @@ struct [[nodiscard]] Quaternion { z = c.z * rs; w = s * 0.5f; } + normalize(); } }; @@ -179,63 +173,79 @@ real_t Quaternion::length_squared() const { return dot(*this); } -void Quaternion::operator+=(const Quaternion &p_q) { +constexpr void Quaternion::operator+=(const Quaternion &p_q) { x += p_q.x; y += p_q.y; z += p_q.z; w += p_q.w; } -void Quaternion::operator-=(const Quaternion &p_q) { +constexpr void Quaternion::operator-=(const Quaternion &p_q) { x -= p_q.x; y -= p_q.y; z -= p_q.z; w -= p_q.w; } -void Quaternion::operator*=(real_t p_s) { +constexpr void Quaternion::operator*=(real_t p_s) { x *= p_s; y *= p_s; z *= p_s; w *= p_s; } -void Quaternion::operator/=(real_t p_s) { - *this *= 1.0f / p_s; +constexpr void Quaternion::operator/=(real_t p_s) { + *this *= (1 / p_s); } -Quaternion Quaternion::operator+(const Quaternion &p_q2) const { +constexpr Quaternion Quaternion::operator+(const Quaternion &p_q2) const { const Quaternion &q1 = *this; return Quaternion(q1.x + p_q2.x, q1.y + p_q2.y, q1.z + p_q2.z, q1.w + p_q2.w); } -Quaternion Quaternion::operator-(const Quaternion &p_q2) const { +constexpr Quaternion Quaternion::operator-(const Quaternion &p_q2) const { const Quaternion &q1 = *this; return Quaternion(q1.x - p_q2.x, q1.y - p_q2.y, q1.z - p_q2.z, q1.w - p_q2.w); } -Quaternion Quaternion::operator-() const { +constexpr Quaternion Quaternion::operator-() const { const Quaternion &q2 = *this; return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w); } -Quaternion Quaternion::operator*(real_t p_s) const { +constexpr Quaternion Quaternion::operator*(real_t p_s) const { return Quaternion(x * p_s, y * p_s, z * p_s, w * p_s); } -Quaternion Quaternion::operator/(real_t p_s) const { - return *this * (1.0f / p_s); +constexpr Quaternion Quaternion::operator/(real_t p_s) const { + return *this * (1 / p_s); } -bool Quaternion::operator==(const Quaternion &p_quaternion) const { +constexpr bool Quaternion::operator==(const Quaternion &p_quaternion) const { return x == p_quaternion.x && y == p_quaternion.y && z == p_quaternion.z && w == p_quaternion.w; } -bool Quaternion::operator!=(const Quaternion &p_quaternion) const { +constexpr bool Quaternion::operator!=(const Quaternion &p_quaternion) const { return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w; } -_FORCE_INLINE_ Quaternion operator*(real_t p_real, const Quaternion &p_quaternion) { +constexpr void Quaternion::operator*=(const Quaternion &p_q) { + real_t xx = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y; + real_t yy = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z; + real_t zz = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x; + w = w * p_q.w - x * p_q.x - y * p_q.y - z * p_q.z; + x = xx; + y = yy; + z = zz; +} + +constexpr Quaternion Quaternion::operator*(const Quaternion &p_q) const { + Quaternion r = *this; + r *= p_q; + return r; +} + +constexpr Quaternion operator*(real_t p_real, const Quaternion &p_quaternion) { return p_quaternion * p_real; } diff --git a/include/godot_cpp/variant/rect2.hpp b/include/godot_cpp/variant/rect2.hpp index a5e334041..de9c82262 100644 --- a/include/godot_cpp/variant/rect2.hpp +++ b/include/godot_cpp/variant/rect2.hpp @@ -145,6 +145,8 @@ struct [[nodiscard]] Rect2 { return size.x > 0.0f && size.y > 0.0f; } + Rect2 intersection_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const; + // Returns the intersection between two Rect2s or an empty Rect2 if there is no intersection. inline Rect2 intersection(const Rect2 &p_rect) const { Rect2 new_rect = p_rect; @@ -204,10 +206,11 @@ struct [[nodiscard]] Rect2 { } bool is_equal_approx(const Rect2 &p_rect) const; + bool is_same(const Rect2 &p_rect) const; bool is_finite() const; - bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; } - bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; } + constexpr bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; } + constexpr bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; } inline Rect2 grow(real_t p_amount) const { Rect2 g = *this; @@ -359,18 +362,44 @@ struct [[nodiscard]] Rect2 { return position + size; } - operator String() const; + explicit operator String() const; operator Rect2i() const; - Rect2() {} - Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) : + static Rect2 from_points(const Vector2 *p_points, int p_point_count) { + Rect2 result; + ERR_FAIL_NULL_V_MSG(p_points, result, "The pointer of points passed in is invalid."); + ERR_FAIL_COND_V_MSG(p_point_count <= 0, result, "The number of points passed in is invalid."); + result.position = p_points[0]; + Vector2 end = result.position; + for (int i = 1; i < p_point_count; i++) { + const Vector2 &p = p_points[i]; + + if (p.x < result.position.x) { + result.position.x = p.x; + } else if (p.x > end.x) { + end.x = p.x; + } + if (p.y < result.position.y) { + result.position.y = p.y; + } else if (p.y > end.y) { + end.y = p.y; + } + } + result.size = end - result.position; + return result; + } + + Rect2() = default; + constexpr Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) : position(Point2(p_x, p_y)), size(Size2(p_width, p_height)) { } - Rect2(const Point2 &p_pos, const Size2 &p_size) : + constexpr Rect2(const Point2 &p_pos, const Size2 &p_size) : position(p_pos), size(p_size) { } }; +template <> +struct is_zero_constructible : std::true_type {}; } // namespace godot diff --git a/include/godot_cpp/variant/rect2i.hpp b/include/godot_cpp/variant/rect2i.hpp index 0c593edeb..0370f0770 100644 --- a/include/godot_cpp/variant/rect2i.hpp +++ b/include/godot_cpp/variant/rect2i.hpp @@ -145,8 +145,8 @@ struct [[nodiscard]] Rect2i { return true; } - bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; } - bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; } + constexpr bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; } + constexpr bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; } Rect2i grow(int p_amount) const { Rect2i g = *this; @@ -225,18 +225,20 @@ struct [[nodiscard]] Rect2i { return position + size; } - operator String() const; + explicit operator String() const; operator Rect2() const; - Rect2i() {} - Rect2i(int p_x, int p_y, int p_width, int p_height) : + Rect2i() = default; + constexpr Rect2i(int p_x, int p_y, int p_width, int p_height) : position(Point2i(p_x, p_y)), size(Size2i(p_width, p_height)) { } - Rect2i(const Point2i &p_pos, const Size2i &p_size) : + constexpr Rect2i(const Point2i &p_pos, const Size2i &p_size) : position(p_pos), size(p_size) { } }; +template <> +struct is_zero_constructible : std::true_type {}; } // namespace godot diff --git a/include/godot_cpp/variant/transform2d.hpp b/include/godot_cpp/variant/transform2d.hpp index 9170e5688..7fffdb789 100644 --- a/include/godot_cpp/variant/transform2d.hpp +++ b/include/godot_cpp/variant/transform2d.hpp @@ -30,6 +30,7 @@ #pragma once +#include #include #include #include @@ -53,13 +54,20 @@ struct [[nodiscard]] Transform2D { // WARNING: Be aware that unlike 3D code, 2D code uses a left-handed coordinate system: // Y-axis points down, and angle is measure from +X to +Y in a clockwise-fashion. - Vector2 columns[3]; + static const Transform2D FLIP_X; + static const Transform2D FLIP_Y; + + Vector2 columns[3] = { + { 1, 0 }, + { 0, 1 }, + { 0, 0 }, + }; _FORCE_INLINE_ real_t tdotx(const Vector2 &p_v) const { return columns[0][0] * p_v.x + columns[1][0] * p_v.y; } _FORCE_INLINE_ real_t tdoty(const Vector2 &p_v) const { return columns[0][1] * p_v.x + columns[1][1] * p_v.y; } - const Vector2 &operator[](int p_idx) const { return columns[p_idx]; } - Vector2 &operator[](int p_idx) { return columns[p_idx]; } + constexpr const Vector2 &operator[](int p_idx) const { return columns[p_idx]; } + constexpr Vector2 &operator[](int p_idx) { return columns[p_idx]; } void invert(); Transform2D inverse() const; @@ -101,19 +109,20 @@ struct [[nodiscard]] Transform2D { Transform2D orthonormalized() const; bool is_conformal() const; bool is_equal_approx(const Transform2D &p_transform) const; + bool is_same(const Transform2D &p_transform) const; bool is_finite() const; Transform2D looking_at(const Vector2 &p_target) const; - bool operator==(const Transform2D &p_transform) const; - bool operator!=(const Transform2D &p_transform) const; + constexpr bool operator==(const Transform2D &p_transform) const; + constexpr bool operator!=(const Transform2D &p_transform) const; void operator*=(const Transform2D &p_transform); Transform2D operator*(const Transform2D &p_transform) const; - void operator*=(real_t p_val); - Transform2D operator*(real_t p_val) const; - void operator/=(real_t p_val); - Transform2D operator/(real_t p_val) const; + constexpr void operator*=(real_t p_val); + constexpr Transform2D operator*(real_t p_val) const; + constexpr void operator/=(real_t p_val); + constexpr Transform2D operator/(real_t p_val) const; Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const; @@ -126,33 +135,72 @@ struct [[nodiscard]] Transform2D { _FORCE_INLINE_ PackedVector2Array xform(const PackedVector2Array &p_array) const; _FORCE_INLINE_ PackedVector2Array xform_inv(const PackedVector2Array &p_array) const; - operator String() const; + explicit operator String() const; - Transform2D(real_t p_xx, real_t p_xy, real_t p_yx, real_t p_yy, real_t p_ox, real_t p_oy) { - columns[0][0] = p_xx; - columns[0][1] = p_xy; - columns[1][0] = p_yx; - columns[1][1] = p_yy; - columns[2][0] = p_ox; - columns[2][1] = p_oy; - } + constexpr Transform2D(real_t p_xx, real_t p_xy, real_t p_yx, real_t p_yy, real_t p_ox, real_t p_oy) : + columns{ + { p_xx, p_xy }, + { p_yx, p_yy }, + { p_ox, p_oy }, + } {} - Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) { - columns[0] = p_x; - columns[1] = p_y; - columns[2] = p_origin; - } + constexpr Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) : + columns{ p_x, p_y, p_origin } {} Transform2D(real_t p_rot, const Vector2 &p_pos); Transform2D(real_t p_rot, const Size2 &p_scale, real_t p_skew, const Vector2 &p_pos); - Transform2D() { - columns[0][0] = 1.0; - columns[1][1] = 1.0; - } + Transform2D() = default; }; +inline constexpr Transform2D Transform2D::FLIP_X = { { -1, 0 }, { 0, 1 }, { 0, 0 } }; +inline constexpr Transform2D Transform2D::FLIP_Y = { { 1, 0 }, { 0, -1 }, { 0, 0 } }; + +constexpr bool Transform2D::operator==(const Transform2D &p_transform) const { + for (int i = 0; i < 3; i++) { + if (columns[i] != p_transform.columns[i]) { + return false; + } + } + + return true; +} + +constexpr bool Transform2D::operator!=(const Transform2D &p_transform) const { + for (int i = 0; i < 3; i++) { + if (columns[i] != p_transform.columns[i]) { + return true; + } + } + + return false; +} + +constexpr void Transform2D::operator*=(real_t p_val) { + columns[0] *= p_val; + columns[1] *= p_val; + columns[2] *= p_val; +} + +constexpr Transform2D Transform2D::operator*(real_t p_val) const { + Transform2D ret(*this); + ret *= p_val; + return ret; +} + +constexpr void Transform2D::operator/=(real_t p_val) { + columns[0] /= p_val; + columns[1] /= p_val; + columns[2] /= p_val; +} + +constexpr Transform2D Transform2D::operator/(real_t p_val) const { + Transform2D ret(*this); + ret /= p_val; + return ret; +} + Vector2 Transform2D::basis_xform(const Vector2 &p_vec) const { return Vector2( tdotx(p_vec), diff --git a/include/godot_cpp/variant/transform3d.hpp b/include/godot_cpp/variant/transform3d.hpp index 80392e396..a54cbe3cc 100644 --- a/include/godot_cpp/variant/transform3d.hpp +++ b/include/godot_cpp/variant/transform3d.hpp @@ -31,6 +31,7 @@ #pragma once #include +#include #include #include #include @@ -39,6 +40,10 @@ namespace godot { struct [[nodiscard]] Transform3D { + static const Transform3D FLIP_X; + static const Transform3D FLIP_Y; + static const Transform3D FLIP_Z; + Basis basis; Vector3 origin; @@ -54,8 +59,8 @@ struct [[nodiscard]] Transform3D { void rotate(const Vector3 &p_axis, real_t p_angle); void rotate_basis(const Vector3 &p_axis, real_t p_angle); - void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false); - Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false) const; + void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3::UP, bool p_use_model_front = false); + Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3::UP, bool p_use_model_front = false) const; void scale(const Vector3 &p_scale); Transform3D scaled(const Vector3 &p_scale) const; @@ -77,10 +82,11 @@ struct [[nodiscard]] Transform3D { void orthogonalize(); Transform3D orthogonalized() const; bool is_equal_approx(const Transform3D &p_transform) const; + bool is_same(const Transform3D &p_transform) const; bool is_finite() const; - bool operator==(const Transform3D &p_transform) const; - bool operator!=(const Transform3D &p_transform) const; + constexpr bool operator==(const Transform3D &p_transform) const; + constexpr bool operator!=(const Transform3D &p_transform) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const; _FORCE_INLINE_ AABB xform(const AABB &p_aabb) const; @@ -104,16 +110,16 @@ struct [[nodiscard]] Transform3D { void operator*=(const Transform3D &p_transform); Transform3D operator*(const Transform3D &p_transform) const; - void operator*=(real_t p_val); - Transform3D operator*(real_t p_val) const; - void operator/=(real_t p_val); - Transform3D operator/(real_t p_val) const; + constexpr void operator*=(real_t p_val); + constexpr Transform3D operator*(real_t p_val) const; + constexpr void operator/=(real_t p_val); + constexpr Transform3D operator/(real_t p_val) const; Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const; - _FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &t) const { - Vector3 v = t.origin - origin; - return Transform3D(basis.transpose_xform(t.basis), + _FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &p_transform) const { + Vector3 v = p_transform.origin - origin; + return Transform3D(basis.transpose_xform(p_transform.basis), basis.xform(v)); } @@ -124,14 +130,54 @@ struct [[nodiscard]] Transform3D { origin.z = p_tz; } - operator String() const; - - Transform3D() {} - Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3()); - Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin); - Transform3D(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_ox, real_t p_oy, real_t p_oz); + explicit operator String() const; + + Transform3D() = default; + constexpr Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3()) : + basis(p_basis), + origin(p_origin) {} + constexpr Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : + basis(p_x, p_y, p_z), + origin(p_origin) {} + constexpr Transform3D(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_ox, real_t p_oy, real_t p_oz) : + basis(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz), + origin(p_ox, p_oy, p_oz) {} }; +inline constexpr Transform3D Transform3D::FLIP_X = { Basis::FLIP_X }; +inline constexpr Transform3D Transform3D::FLIP_Y = { Basis::FLIP_Y }; +inline constexpr Transform3D Transform3D::FLIP_Z = { Basis::FLIP_Z }; + +constexpr bool Transform3D::operator==(const Transform3D &p_transform) const { + return (basis == p_transform.basis && origin == p_transform.origin); +} + +constexpr bool Transform3D::operator!=(const Transform3D &p_transform) const { + return (basis != p_transform.basis || origin != p_transform.origin); +} + +constexpr void Transform3D::operator*=(real_t p_val) { + origin *= p_val; + basis *= p_val; +} + +constexpr Transform3D Transform3D::operator*(real_t p_val) const { + Transform3D ret(*this); + ret *= p_val; + return ret; +} + +constexpr void Transform3D::operator/=(real_t p_val) { + basis /= p_val; + origin /= p_val; +} + +constexpr Transform3D Transform3D::operator/(real_t p_val) const { + Transform3D ret(*this); + ret /= p_val; + return ret; +} + _FORCE_INLINE_ Vector3 Transform3D::xform(const Vector3 &p_vector) const { return Vector3( basis[0].dot(p_vector) + origin.x, diff --git a/include/godot_cpp/variant/vector2.hpp b/include/godot_cpp/variant/vector2.hpp index 400bdeffe..1db7df611 100644 --- a/include/godot_cpp/variant/vector2.hpp +++ b/include/godot_cpp/variant/vector2.hpp @@ -39,7 +39,12 @@ class String; struct Vector2i; struct [[nodiscard]] Vector2 { - static const int AXIS_COUNT = 2; + static const Vector2 LEFT; + static const Vector2 RIGHT; + static const Vector2 UP; + static const Vector2 DOWN; + + static constexpr int AXIS_COUNT = 2; enum Axis { AXIS_X, @@ -47,27 +52,29 @@ struct [[nodiscard]] Vector2 { }; union { - struct { - union { - real_t x; - real_t width; - }; - union { - real_t y; - real_t height; - }; - }; - - real_t coord[2] = { 0 }; + real_t x = 0.0f; + real_t width; + }; + union { + real_t y = 0.0f; + real_t height; }; - _FORCE_INLINE_ real_t &operator[](int p_axis) { + constexpr real_t &operator[](int p_axis) { + // The pointer math below assumes that the elements are placed back-to-back, like an array. + // This is always true in practice, but technically not guaranteed; we safety-check it here. + static_assert(offsetof(Vector2, x) == 0 * sizeof(real_t)); + static_assert(offsetof(Vector2, width) == 0 * sizeof(real_t)); + static_assert(offsetof(Vector2, y) == 1 * sizeof(real_t)); + static_assert(offsetof(Vector2, height) == 1 * sizeof(real_t)); + static_assert(sizeof(Vector2) == 2 * sizeof(real_t)); + DEV_ASSERT((unsigned int)p_axis < 2); - return coord[p_axis]; + return (&x)[p_axis]; } - _FORCE_INLINE_ const real_t &operator[](int p_axis) const { + constexpr const real_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 2); - return coord[p_axis]; + return (&x)[p_axis]; } _FORCE_INLINE_ Vector2::Axis min_axis_index() const { @@ -86,6 +93,8 @@ struct [[nodiscard]] Vector2 { real_t length_squared() const; Vector2 limit_length(real_t p_len = 1.0) const; + void zero() { x = y = 0; } + Vector2 min(const Vector2 &p_vector2) const { return Vector2(MIN(x, p_vector2.x), MIN(y, p_vector2.y)); } @@ -130,35 +139,36 @@ struct [[nodiscard]] Vector2 { Vector2 reflect(const Vector2 &p_normal) const; bool is_equal_approx(const Vector2 &p_v) const; + bool is_same(const Vector2 &p_v) const; bool is_zero_approx() const; bool is_finite() const; - Vector2 operator+(const Vector2 &p_v) const; - void operator+=(const Vector2 &p_v); - Vector2 operator-(const Vector2 &p_v) const; - void operator-=(const Vector2 &p_v); - Vector2 operator*(const Vector2 &p_v1) const; + constexpr Vector2 operator+(const Vector2 &p_v) const; + constexpr void operator+=(const Vector2 &p_v); + constexpr Vector2 operator-(const Vector2 &p_v) const; + constexpr void operator-=(const Vector2 &p_v); + constexpr Vector2 operator*(const Vector2 &p_v1) const; - Vector2 operator*(real_t p_rvalue) const; - void operator*=(real_t p_rvalue); - void operator*=(const Vector2 &p_rvalue) { *this = *this * p_rvalue; } + constexpr Vector2 operator*(real_t p_rvalue) const; + constexpr void operator*=(real_t p_rvalue); + constexpr void operator*=(const Vector2 &p_rvalue) { *this = *this * p_rvalue; } - Vector2 operator/(const Vector2 &p_v1) const; + constexpr Vector2 operator/(const Vector2 &p_v1) const; - Vector2 operator/(real_t p_rvalue) const; + constexpr Vector2 operator/(real_t p_rvalue) const; - void operator/=(real_t p_rvalue); - void operator/=(const Vector2 &p_rvalue) { *this = *this / p_rvalue; } + constexpr void operator/=(real_t p_rvalue); + constexpr void operator/=(const Vector2 &p_rvalue) { *this = *this / p_rvalue; } - Vector2 operator-() const; + constexpr Vector2 operator-() const; - bool operator==(const Vector2 &p_vec2) const; - bool operator!=(const Vector2 &p_vec2) const; + constexpr bool operator==(const Vector2 &p_vec2) const; + constexpr bool operator!=(const Vector2 &p_vec2) const; - bool operator<(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y < p_vec2.y) : (x < p_vec2.x); } - bool operator>(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y > p_vec2.y) : (x > p_vec2.x); } - bool operator<=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } - bool operator>=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } + constexpr bool operator<(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y < p_vec2.y) : (x < p_vec2.x); } + constexpr bool operator>(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y > p_vec2.y) : (x > p_vec2.x); } + constexpr bool operator<=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } + constexpr bool operator>=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } real_t angle() const; static Vector2 from_angle(real_t p_angle); @@ -182,73 +192,76 @@ struct [[nodiscard]] Vector2 { Vector2 clampf(real_t p_min, real_t p_max) const; real_t aspect() const { return width / height; } - operator String() const; + explicit operator String() const; operator Vector2i() const; - _FORCE_INLINE_ Vector2() {} - _FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) { - x = p_x; - y = p_y; - } + constexpr Vector2() = default; + constexpr Vector2(real_t p_x, real_t p_y) : + x(p_x), y(p_y) {} }; +inline constexpr Vector2 Vector2::LEFT = { -1, 0 }; +inline constexpr Vector2 Vector2::RIGHT = { 1, 0 }; +inline constexpr Vector2 Vector2::UP = { 0, -1 }; +inline constexpr Vector2 Vector2::DOWN = { 0, 1 }; + _FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec) const { return p_vec - *this * (dot(p_vec) - p_d); } -_FORCE_INLINE_ Vector2 Vector2::operator+(const Vector2 &p_v) const { +constexpr Vector2 Vector2::operator+(const Vector2 &p_v) const { return Vector2(x + p_v.x, y + p_v.y); } -_FORCE_INLINE_ void Vector2::operator+=(const Vector2 &p_v) { +constexpr void Vector2::operator+=(const Vector2 &p_v) { x += p_v.x; y += p_v.y; } -_FORCE_INLINE_ Vector2 Vector2::operator-(const Vector2 &p_v) const { +constexpr Vector2 Vector2::operator-(const Vector2 &p_v) const { return Vector2(x - p_v.x, y - p_v.y); } -_FORCE_INLINE_ void Vector2::operator-=(const Vector2 &p_v) { +constexpr void Vector2::operator-=(const Vector2 &p_v) { x -= p_v.x; y -= p_v.y; } -_FORCE_INLINE_ Vector2 Vector2::operator*(const Vector2 &p_v1) const { +constexpr Vector2 Vector2::operator*(const Vector2 &p_v1) const { return Vector2(x * p_v1.x, y * p_v1.y); } -_FORCE_INLINE_ Vector2 Vector2::operator*(real_t p_rvalue) const { +constexpr Vector2 Vector2::operator*(real_t p_rvalue) const { return Vector2(x * p_rvalue, y * p_rvalue); } -_FORCE_INLINE_ void Vector2::operator*=(real_t p_rvalue) { +constexpr void Vector2::operator*=(real_t p_rvalue) { x *= p_rvalue; y *= p_rvalue; } -_FORCE_INLINE_ Vector2 Vector2::operator/(const Vector2 &p_v1) const { +constexpr Vector2 Vector2::operator/(const Vector2 &p_v1) const { return Vector2(x / p_v1.x, y / p_v1.y); } -_FORCE_INLINE_ Vector2 Vector2::operator/(real_t p_rvalue) const { +constexpr Vector2 Vector2::operator/(real_t p_rvalue) const { return Vector2(x / p_rvalue, y / p_rvalue); } -_FORCE_INLINE_ void Vector2::operator/=(real_t p_rvalue) { +constexpr void Vector2::operator/=(real_t p_rvalue) { x /= p_rvalue; y /= p_rvalue; } -_FORCE_INLINE_ Vector2 Vector2::operator-() const { +constexpr Vector2 Vector2::operator-() const { return Vector2(-x, -y); } -_FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const { +constexpr bool Vector2::operator==(const Vector2 &p_vec2) const { return x == p_vec2.x && y == p_vec2.y; } -_FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const { +constexpr bool Vector2::operator!=(const Vector2 &p_vec2) const { return x != p_vec2.x || y != p_vec2.y; } @@ -309,23 +322,25 @@ Vector2 Vector2::direction_to(const Vector2 &p_to) const { // Multiplication operators required to workaround issues with LLVM using implicit conversion // to Vector2i instead for integers where it should not. -_FORCE_INLINE_ Vector2 operator*(float p_scalar, const Vector2 &p_vec) { +constexpr Vector2 operator*(float p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector2 operator*(double p_scalar, const Vector2 &p_vec) { +constexpr Vector2 operator*(double p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector2 operator*(int32_t p_scalar, const Vector2 &p_vec) { +constexpr Vector2 operator*(int32_t p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector2 operator*(int64_t p_scalar, const Vector2 &p_vec) { +constexpr Vector2 operator*(int64_t p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } typedef Vector2 Size2; typedef Vector2 Point2; +template <> +struct is_zero_constructible : std::true_type {}; } // namespace godot diff --git a/include/godot_cpp/variant/vector2i.hpp b/include/godot_cpp/variant/vector2i.hpp index 3278af9f1..1beb35f24 100644 --- a/include/godot_cpp/variant/vector2i.hpp +++ b/include/godot_cpp/variant/vector2i.hpp @@ -39,7 +39,12 @@ class String; struct Vector2; struct [[nodiscard]] Vector2i { - static const int AXIS_COUNT = 2; + static const Vector2i LEFT; + static const Vector2i RIGHT; + static const Vector2i UP; + static const Vector2i DOWN; + + static constexpr int AXIS_COUNT = 2; enum Axis { AXIS_X, @@ -47,27 +52,29 @@ struct [[nodiscard]] Vector2i { }; union { - struct { - union { - int32_t x; - int32_t width; - }; - union { - int32_t y; - int32_t height; - }; - }; - - int32_t coord[2] = { 0 }; + int32_t x = 0; + int32_t width; + }; + union { + int32_t y = 0; + int32_t height; }; - _FORCE_INLINE_ int32_t &operator[](int p_axis) { + constexpr int32_t &operator[](int p_axis) { + // The pointer math below assumes that the elements are placed back-to-back, like an array. + // This is always true in practice, but technically not guaranteed; we safety-check it here. + static_assert(offsetof(Vector2i, x) == 0 * sizeof(int32_t)); + static_assert(offsetof(Vector2i, width) == 0 * sizeof(int32_t)); + static_assert(offsetof(Vector2i, y) == 1 * sizeof(int32_t)); + static_assert(offsetof(Vector2i, height) == 1 * sizeof(int32_t)); + static_assert(sizeof(Vector2i) == 2 * sizeof(int32_t)); + DEV_ASSERT((unsigned int)p_axis < 2); - return coord[p_axis]; + return (&x)[p_axis]; } - _FORCE_INLINE_ const int32_t &operator[](int p_axis) const { + constexpr const int32_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 2); - return coord[p_axis]; + return (&x)[p_axis]; } _FORCE_INLINE_ Vector2i::Axis min_axis_index() const { @@ -102,32 +109,32 @@ struct [[nodiscard]] Vector2i { return (p_to - *this).length_squared(); } - Vector2i operator+(const Vector2i &p_v) const; - void operator+=(const Vector2i &p_v); - Vector2i operator-(const Vector2i &p_v) const; - void operator-=(const Vector2i &p_v); - Vector2i operator*(const Vector2i &p_v1) const; + constexpr Vector2i operator+(const Vector2i &p_v) const; + constexpr void operator+=(const Vector2i &p_v); + constexpr Vector2i operator-(const Vector2i &p_v) const; + constexpr void operator-=(const Vector2i &p_v); + constexpr Vector2i operator*(const Vector2i &p_v1) const; - Vector2i operator*(int32_t p_rvalue) const; - void operator*=(int32_t p_rvalue); + constexpr Vector2i operator*(int32_t p_rvalue) const; + constexpr void operator*=(int32_t p_rvalue); - Vector2i operator/(const Vector2i &p_v1) const; - Vector2i operator/(int32_t p_rvalue) const; - void operator/=(int32_t p_rvalue); + constexpr Vector2i operator/(const Vector2i &p_v1) const; + constexpr Vector2i operator/(int32_t p_rvalue) const; + constexpr void operator/=(int32_t p_rvalue); - Vector2i operator%(const Vector2i &p_v1) const; - Vector2i operator%(int32_t p_rvalue) const; - void operator%=(int32_t p_rvalue); + constexpr Vector2i operator%(const Vector2i &p_v1) const; + constexpr Vector2i operator%(int32_t p_rvalue) const; + constexpr void operator%=(int32_t p_rvalue); - Vector2i operator-() const; - bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } - bool operator>(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); } + constexpr Vector2i operator-() const; + constexpr bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } + constexpr bool operator>(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); } - bool operator<=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } - bool operator>=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } + constexpr bool operator<=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } + constexpr bool operator>=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } - bool operator==(const Vector2i &p_vec2) const; - bool operator!=(const Vector2i &p_vec2) const; + constexpr bool operator==(const Vector2i &p_vec2) const; + constexpr bool operator!=(const Vector2i &p_vec2) const; int64_t length_squared() const; double length() const; @@ -140,35 +147,109 @@ struct [[nodiscard]] Vector2i { Vector2i snapped(const Vector2i &p_step) const; Vector2i snappedi(int32_t p_step) const; - operator String() const; + explicit operator String() const; operator Vector2() const; - inline Vector2i() {} - inline Vector2i(int32_t p_x, int32_t p_y) { - x = p_x; - y = p_y; - } + constexpr Vector2i() = default; + constexpr Vector2i(int32_t p_x, int32_t p_y) : + x(p_x), y(p_y) {} }; +inline constexpr Vector2i Vector2i::LEFT = { -1, 0 }; +inline constexpr Vector2i Vector2i::RIGHT = { 1, 0 }; +inline constexpr Vector2i Vector2i::UP = { 0, -1 }; +inline constexpr Vector2i Vector2i::DOWN = { 0, 1 }; + +constexpr Vector2i Vector2i::operator+(const Vector2i &p_v) const { + return Vector2i(x + p_v.x, y + p_v.y); +} + +constexpr void Vector2i::operator+=(const Vector2i &p_v) { + x += p_v.x; + y += p_v.y; +} + +constexpr Vector2i Vector2i::operator-(const Vector2i &p_v) const { + return Vector2i(x - p_v.x, y - p_v.y); +} + +constexpr void Vector2i::operator-=(const Vector2i &p_v) { + x -= p_v.x; + y -= p_v.y; +} + +constexpr Vector2i Vector2i::operator*(const Vector2i &p_v1) const { + return Vector2i(x * p_v1.x, y * p_v1.y); +} + +constexpr Vector2i Vector2i::operator*(int32_t p_rvalue) const { + return Vector2i(x * p_rvalue, y * p_rvalue); +} + +constexpr void Vector2i::operator*=(int32_t p_rvalue) { + x *= p_rvalue; + y *= p_rvalue; +} + +constexpr Vector2i Vector2i::operator/(const Vector2i &p_v1) const { + return Vector2i(Math::division_no_overflow(x, p_v1.x), Math::division_no_overflow(y, p_v1.y)); +} + +constexpr Vector2i Vector2i::operator/(int32_t p_rvalue) const { + return Vector2i(Math::division_no_overflow(x, p_rvalue), Math::division_no_overflow(y, p_rvalue)); +} + +constexpr void Vector2i::operator/=(int32_t p_rvalue) { + x = Math::division_no_overflow(x, p_rvalue); + y = Math::division_no_overflow(y, p_rvalue); +} + +constexpr Vector2i Vector2i::operator%(const Vector2i &p_v1) const { + return Vector2i(Math::modulo_no_overflow(x, p_v1.x), Math::modulo_no_overflow(y, p_v1.y)); +} + +constexpr Vector2i Vector2i::operator%(int32_t p_rvalue) const { + return Vector2i(Math::modulo_no_overflow(x, p_rvalue), Math::modulo_no_overflow(y, p_rvalue)); +} + +constexpr void Vector2i::operator%=(int32_t p_rvalue) { + x = Math::modulo_no_overflow(x, p_rvalue); + y = Math::modulo_no_overflow(y, p_rvalue); +} + +constexpr Vector2i Vector2i::operator-() const { + return Vector2i(-x, -y); +} + +constexpr bool Vector2i::operator==(const Vector2i &p_vec2) const { + return x == p_vec2.x && y == p_vec2.y; +} + +constexpr bool Vector2i::operator!=(const Vector2i &p_vec2) const { + return x != p_vec2.x || y != p_vec2.y; +} + // Multiplication operators required to workaround issues with LLVM using implicit conversion. -_FORCE_INLINE_ Vector2i operator*(int32_t p_scalar, const Vector2i &p_vector) { +constexpr Vector2i operator*(int32_t p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(int64_t p_scalar, const Vector2i &p_vector) { +constexpr Vector2i operator*(int64_t p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(float p_scalar, const Vector2i &p_vector) { +constexpr Vector2i operator*(float p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(double p_scalar, const Vector2i &p_vector) { +constexpr Vector2i operator*(double p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } typedef Vector2i Size2i; typedef Vector2i Point2i; +template <> +struct is_zero_constructible : std::true_type {}; } // namespace godot diff --git a/include/godot_cpp/variant/vector3.hpp b/include/godot_cpp/variant/vector3.hpp index 034e6ca29..f4e2eaf95 100644 --- a/include/godot_cpp/variant/vector3.hpp +++ b/include/godot_cpp/variant/vector3.hpp @@ -41,7 +41,20 @@ struct Vector2; struct Vector3i; struct [[nodiscard]] Vector3 { - static const int AXIS_COUNT = 3; + static const Vector3 LEFT; + static const Vector3 RIGHT; + static const Vector3 UP; + static const Vector3 DOWN; + static const Vector3 FORWARD; + static const Vector3 BACK; + static const Vector3 MODEL_LEFT; + static const Vector3 MODEL_RIGHT; + static const Vector3 MODEL_TOP; + static const Vector3 MODEL_BOTTOM; + static const Vector3 MODEL_FRONT; + static const Vector3 MODEL_REAR; + + static constexpr int AXIS_COUNT = 3; enum Axis { AXIS_X, @@ -49,24 +62,24 @@ struct [[nodiscard]] Vector3 { AXIS_Z, }; - union { - struct { - real_t x; - real_t y; - real_t z; - }; + real_t x = 0.0f; + real_t y = 0.0f; + real_t z = 0.0f; - real_t coord[3] = { 0 }; - }; + constexpr real_t &operator[](int p_axis) { + // The pointer math below assumes that the elements are placed back-to-back, like an array. + // This is always true in practice, but technically not guaranteed; we safety-check it here. + static_assert(offsetof(Vector3, x) == 0 * sizeof(real_t)); + static_assert(offsetof(Vector3, y) == 1 * sizeof(real_t)); + static_assert(offsetof(Vector3, z) == 2 * sizeof(real_t)); + static_assert(sizeof(Vector3) == 3 * sizeof(real_t)); - _FORCE_INLINE_ const real_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 3); - return coord[p_axis]; + return (&x)[p_axis]; } - - _FORCE_INLINE_ real_t &operator[](int p_axis) { + constexpr const real_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 3); - return coord[p_axis]; + return (&x)[p_axis]; } _FORCE_INLINE_ Vector3::Axis min_axis_index() const { @@ -93,6 +106,20 @@ struct [[nodiscard]] Vector3 { return Vector3(MAX(x, p_scalar), MAX(y, p_scalar), MAX(z, p_scalar)); } + Vector3 clamp(const Vector3 &p_min, const Vector3 &p_max) const { + return Vector3( + CLAMP(x, p_min.x, p_max.x), + CLAMP(y, p_min.y, p_max.y), + CLAMP(z, p_min.z, p_max.z)); + } + + Vector3 clampf(real_t p_min, real_t p_max) const { + return Vector3( + CLAMP(x, p_min, p_max), + CLAMP(y, p_min, p_max), + CLAMP(z, p_min, p_max)); + } + _FORCE_INLINE_ real_t length() const; _FORCE_INLINE_ real_t length_squared() const; @@ -138,8 +165,6 @@ struct [[nodiscard]] Vector3 { _FORCE_INLINE_ Vector3 sign() const; _FORCE_INLINE_ Vector3 ceil() const; _FORCE_INLINE_ Vector3 round() const; - Vector3 clamp(const Vector3 &p_min, const Vector3 &p_max) const; - Vector3 clampf(real_t p_min, real_t p_max) const; _FORCE_INLINE_ real_t distance_to(const Vector3 &p_to) const; _FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_to) const; @@ -157,45 +182,57 @@ struct [[nodiscard]] Vector3 { _FORCE_INLINE_ Vector3 reflect(const Vector3 &p_normal) const; bool is_equal_approx(const Vector3 &p_v) const; + bool is_same(const Vector3 &p_v) const; bool is_zero_approx() const; bool is_finite() const; /* Operators */ - _FORCE_INLINE_ Vector3 &operator+=(const Vector3 &p_v); - _FORCE_INLINE_ Vector3 operator+(const Vector3 &p_v) const; - _FORCE_INLINE_ Vector3 &operator-=(const Vector3 &p_v); - _FORCE_INLINE_ Vector3 operator-(const Vector3 &p_v) const; - _FORCE_INLINE_ Vector3 &operator*=(const Vector3 &p_v); - _FORCE_INLINE_ Vector3 operator*(const Vector3 &p_v) const; - _FORCE_INLINE_ Vector3 &operator/=(const Vector3 &p_v); - _FORCE_INLINE_ Vector3 operator/(const Vector3 &p_v) const; - - _FORCE_INLINE_ Vector3 &operator*=(real_t p_scalar); - _FORCE_INLINE_ Vector3 operator*(real_t p_scalar) const; - _FORCE_INLINE_ Vector3 &operator/=(real_t p_scalar); - _FORCE_INLINE_ Vector3 operator/(real_t p_scalar) const; - - _FORCE_INLINE_ Vector3 operator-() const; - - _FORCE_INLINE_ bool operator==(const Vector3 &p_v) const; - _FORCE_INLINE_ bool operator!=(const Vector3 &p_v) const; - _FORCE_INLINE_ bool operator<(const Vector3 &p_v) const; - _FORCE_INLINE_ bool operator<=(const Vector3 &p_v) const; - _FORCE_INLINE_ bool operator>(const Vector3 &p_v) const; - _FORCE_INLINE_ bool operator>=(const Vector3 &p_v) const; - - operator String() const; + constexpr Vector3 &operator+=(const Vector3 &p_v); + constexpr Vector3 operator+(const Vector3 &p_v) const; + constexpr Vector3 &operator-=(const Vector3 &p_v); + constexpr Vector3 operator-(const Vector3 &p_v) const; + constexpr Vector3 &operator*=(const Vector3 &p_v); + constexpr Vector3 operator*(const Vector3 &p_v) const; + constexpr Vector3 &operator/=(const Vector3 &p_v); + constexpr Vector3 operator/(const Vector3 &p_v) const; + + constexpr Vector3 &operator*=(real_t p_scalar); + constexpr Vector3 operator*(real_t p_scalar) const; + constexpr Vector3 &operator/=(real_t p_scalar); + constexpr Vector3 operator/(real_t p_scalar) const; + + constexpr Vector3 operator-() const; + + constexpr bool operator==(const Vector3 &p_v) const; + constexpr bool operator!=(const Vector3 &p_v) const; + constexpr bool operator<(const Vector3 &p_v) const; + constexpr bool operator<=(const Vector3 &p_v) const; + constexpr bool operator>(const Vector3 &p_v) const; + constexpr bool operator>=(const Vector3 &p_v) const; + + explicit operator String() const; operator Vector3i() const; - _FORCE_INLINE_ Vector3() {} - _FORCE_INLINE_ Vector3(real_t p_x, real_t p_y, real_t p_z) { - x = p_x; - y = p_y; - z = p_z; - } + constexpr Vector3() : + x(0), y(0), z(0) {} + constexpr Vector3(real_t p_x, real_t p_y, real_t p_z) : + x(p_x), y(p_y), z(p_z) {} }; +inline constexpr Vector3 Vector3::LEFT = { -1, 0, 0 }; +inline constexpr Vector3 Vector3::RIGHT = { 1, 0, 0 }; +inline constexpr Vector3 Vector3::UP = { 0, 1, 0 }; +inline constexpr Vector3 Vector3::DOWN = { 0, -1, 0 }; +inline constexpr Vector3 Vector3::FORWARD = { 0, 0, -1 }; +inline constexpr Vector3 Vector3::BACK = { 0, 0, 1 }; +inline constexpr Vector3 Vector3::MODEL_LEFT = { 1, 0, 0 }; +inline constexpr Vector3 Vector3::MODEL_RIGHT = { -1, 0, 0 }; +inline constexpr Vector3 Vector3::MODEL_TOP = { 0, 1, 0 }; +inline constexpr Vector3 Vector3::MODEL_BOTTOM = { 0, -1, 0 }; +inline constexpr Vector3 Vector3::MODEL_FRONT = { 0, 0, 1 }; +inline constexpr Vector3 Vector3::MODEL_REAR = { 0, 0, -1 }; + Vector3 Vector3::cross(const Vector3 &p_with) const { Vector3 ret( (y * p_with.z) - (z * p_with.y), @@ -335,56 +372,56 @@ Vector3 Vector3::get_any_perpendicular() const { // since it could be a different vector depending on the prior branching code Math::abs(x) <= Math::abs(y) && Math::abs(x) <= Math::abs(z). // However, it would be reasonable to use any of the axes of the basis, as it is simpler to calculate. ERR_FAIL_COND_V_MSG(is_zero_approx(), Vector3(0, 0, 0), "The Vector3 must not be zero."); - return cross((Math::abs(x) <= Math::abs(y) && Math::abs(x) <= Math::abs(z)) ? Vector3(1, 0, 0) : Vector3(0, 1, 0)).normalized(); + return cross((Math::abs(x) <= Math::abs(y) && Math::abs(x) <= Math::abs(z)) ? Vector3::RIGHT : Vector3::UP).normalized(); } /* Operators */ -Vector3 &Vector3::operator+=(const Vector3 &p_v) { +constexpr Vector3 &Vector3::operator+=(const Vector3 &p_v) { x += p_v.x; y += p_v.y; z += p_v.z; return *this; } -Vector3 Vector3::operator+(const Vector3 &p_v) const { +constexpr Vector3 Vector3::operator+(const Vector3 &p_v) const { return Vector3(x + p_v.x, y + p_v.y, z + p_v.z); } -Vector3 &Vector3::operator-=(const Vector3 &p_v) { +constexpr Vector3 &Vector3::operator-=(const Vector3 &p_v) { x -= p_v.x; y -= p_v.y; z -= p_v.z; return *this; } -Vector3 Vector3::operator-(const Vector3 &p_v) const { +constexpr Vector3 Vector3::operator-(const Vector3 &p_v) const { return Vector3(x - p_v.x, y - p_v.y, z - p_v.z); } -Vector3 &Vector3::operator*=(const Vector3 &p_v) { +constexpr Vector3 &Vector3::operator*=(const Vector3 &p_v) { x *= p_v.x; y *= p_v.y; z *= p_v.z; return *this; } -Vector3 Vector3::operator*(const Vector3 &p_v) const { +constexpr Vector3 Vector3::operator*(const Vector3 &p_v) const { return Vector3(x * p_v.x, y * p_v.y, z * p_v.z); } -Vector3 &Vector3::operator/=(const Vector3 &p_v) { +constexpr Vector3 &Vector3::operator/=(const Vector3 &p_v) { x /= p_v.x; y /= p_v.y; z /= p_v.z; return *this; } -Vector3 Vector3::operator/(const Vector3 &p_v) const { +constexpr Vector3 Vector3::operator/(const Vector3 &p_v) const { return Vector3(x / p_v.x, y / p_v.y, z / p_v.z); } -Vector3 &Vector3::operator*=(real_t p_scalar) { +constexpr Vector3 &Vector3::operator*=(real_t p_scalar) { x *= p_scalar; y *= p_scalar; z *= p_scalar; @@ -394,50 +431,50 @@ Vector3 &Vector3::operator*=(real_t p_scalar) { // Multiplication operators required to workaround issues with LLVM using implicit conversion // to Vector3i instead for integers where it should not. -_FORCE_INLINE_ Vector3 operator*(float p_scalar, const Vector3 &p_vec) { +constexpr Vector3 operator*(float p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector3 operator*(double p_scalar, const Vector3 &p_vec) { +constexpr Vector3 operator*(double p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector3 operator*(int32_t p_scalar, const Vector3 &p_vec) { +constexpr Vector3 operator*(int32_t p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector3 operator*(int64_t p_scalar, const Vector3 &p_vec) { +constexpr Vector3 operator*(int64_t p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -Vector3 Vector3::operator*(real_t p_scalar) const { +constexpr Vector3 Vector3::operator*(real_t p_scalar) const { return Vector3(x * p_scalar, y * p_scalar, z * p_scalar); } -Vector3 &Vector3::operator/=(real_t p_scalar) { +constexpr Vector3 &Vector3::operator/=(real_t p_scalar) { x /= p_scalar; y /= p_scalar; z /= p_scalar; return *this; } -Vector3 Vector3::operator/(real_t p_scalar) const { +constexpr Vector3 Vector3::operator/(real_t p_scalar) const { return Vector3(x / p_scalar, y / p_scalar, z / p_scalar); } -Vector3 Vector3::operator-() const { +constexpr Vector3 Vector3::operator-() const { return Vector3(-x, -y, -z); } -bool Vector3::operator==(const Vector3 &p_v) const { +constexpr bool Vector3::operator==(const Vector3 &p_v) const { return x == p_v.x && y == p_v.y && z == p_v.z; } -bool Vector3::operator!=(const Vector3 &p_v) const { +constexpr bool Vector3::operator!=(const Vector3 &p_v) const { return x != p_v.x || y != p_v.y || z != p_v.z; } -bool Vector3::operator<(const Vector3 &p_v) const { +constexpr bool Vector3::operator<(const Vector3 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z < p_v.z; @@ -447,7 +484,7 @@ bool Vector3::operator<(const Vector3 &p_v) const { return x < p_v.x; } -bool Vector3::operator>(const Vector3 &p_v) const { +constexpr bool Vector3::operator>(const Vector3 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z > p_v.z; @@ -457,7 +494,7 @@ bool Vector3::operator>(const Vector3 &p_v) const { return x > p_v.x; } -bool Vector3::operator<=(const Vector3 &p_v) const { +constexpr bool Vector3::operator<=(const Vector3 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z <= p_v.z; @@ -467,7 +504,7 @@ bool Vector3::operator<=(const Vector3 &p_v) const { return x < p_v.x; } -bool Vector3::operator>=(const Vector3 &p_v) const { +constexpr bool Vector3::operator>=(const Vector3 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z >= p_v.z; @@ -502,14 +539,22 @@ real_t Vector3::length_squared() const { } void Vector3::normalize() { - real_t lengthsq = length_squared(); - if (lengthsq == 0) { - x = y = z = 0; + if (!is_finite()) { +#ifdef MATH_CHECKS + WARN_PRINT("Vector3 cannot be normalized, the elements must be finite. Making (0, 0, 0) as a fallback."); +#endif // MATH_CHECKS + zero(); + return; + } + + real_t l = length_squared(); + if (l == 0) { + zero(); } else { - real_t length = Math::sqrt(lengthsq); - x /= length; - y /= length; - z /= length; + l = Math::sqrt(l); + x /= l; + y /= l; + z /= l; } } @@ -551,4 +596,7 @@ Vector3 Vector3::reflect(const Vector3 &p_normal) const { return 2.0f * p_normal * dot(p_normal) - *this; } +template <> +struct is_zero_constructible : std::true_type {}; + } // namespace godot diff --git a/include/godot_cpp/variant/vector3i.hpp b/include/godot_cpp/variant/vector3i.hpp index 2901b3665..734d5813c 100644 --- a/include/godot_cpp/variant/vector3i.hpp +++ b/include/godot_cpp/variant/vector3i.hpp @@ -39,7 +39,14 @@ class String; struct Vector3; struct [[nodiscard]] Vector3i { - static const int AXIS_COUNT = 3; + static const Vector3i LEFT; + static const Vector3i RIGHT; + static const Vector3i UP; + static const Vector3i DOWN; + static const Vector3i FORWARD; + static const Vector3i BACK; + + static constexpr int AXIS_COUNT = 3; enum Axis { AXIS_X, @@ -47,24 +54,24 @@ struct [[nodiscard]] Vector3i { AXIS_Z, }; - union { - struct { - int32_t x; - int32_t y; - int32_t z; - }; + int32_t x = 0; + int32_t y = 0; + int32_t z = 0; - int32_t coord[3] = { 0 }; - }; + constexpr int32_t &operator[](int p_axis) { + // The pointer math below assumes that the elements are placed back-to-back, like an array. + // This is always true in practice, but technically not guaranteed; we safety-check it here. + static_assert(offsetof(Vector3i, x) == 0 * sizeof(int32_t)); + static_assert(offsetof(Vector3i, y) == 1 * sizeof(int32_t)); + static_assert(offsetof(Vector3i, z) == 2 * sizeof(int32_t)); + static_assert(sizeof(Vector3i) == 3 * sizeof(int32_t)); - _FORCE_INLINE_ const int32_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 3); - return coord[p_axis]; + return (&x)[p_axis]; } - - _FORCE_INLINE_ int32_t &operator[](int p_axis) { + constexpr const int32_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 3); - return coord[p_axis]; + return (&x)[p_axis]; } Vector3i::Axis min_axis_index() const; @@ -103,44 +110,48 @@ struct [[nodiscard]] Vector3i { /* Operators */ - _FORCE_INLINE_ Vector3i &operator+=(const Vector3i &p_v); - _FORCE_INLINE_ Vector3i operator+(const Vector3i &p_v) const; - _FORCE_INLINE_ Vector3i &operator-=(const Vector3i &p_v); - _FORCE_INLINE_ Vector3i operator-(const Vector3i &p_v) const; - _FORCE_INLINE_ Vector3i &operator*=(const Vector3i &p_v); - _FORCE_INLINE_ Vector3i operator*(const Vector3i &p_v) const; - _FORCE_INLINE_ Vector3i &operator/=(const Vector3i &p_v); - _FORCE_INLINE_ Vector3i operator/(const Vector3i &p_v) const; - _FORCE_INLINE_ Vector3i &operator%=(const Vector3i &p_v); - _FORCE_INLINE_ Vector3i operator%(const Vector3i &p_v) const; - - _FORCE_INLINE_ Vector3i &operator*=(int32_t p_scalar); - _FORCE_INLINE_ Vector3i operator*(int32_t p_scalar) const; - _FORCE_INLINE_ Vector3i &operator/=(int32_t p_scalar); - _FORCE_INLINE_ Vector3i operator/(int32_t p_scalar) const; - _FORCE_INLINE_ Vector3i &operator%=(int32_t p_scalar); - _FORCE_INLINE_ Vector3i operator%(int32_t p_scalar) const; - - _FORCE_INLINE_ Vector3i operator-() const; - - _FORCE_INLINE_ bool operator==(const Vector3i &p_v) const; - _FORCE_INLINE_ bool operator!=(const Vector3i &p_v) const; - _FORCE_INLINE_ bool operator<(const Vector3i &p_v) const; - _FORCE_INLINE_ bool operator<=(const Vector3i &p_v) const; - _FORCE_INLINE_ bool operator>(const Vector3i &p_v) const; - _FORCE_INLINE_ bool operator>=(const Vector3i &p_v) const; - - operator String() const; + constexpr Vector3i &operator+=(const Vector3i &p_v); + constexpr Vector3i operator+(const Vector3i &p_v) const; + constexpr Vector3i &operator-=(const Vector3i &p_v); + constexpr Vector3i operator-(const Vector3i &p_v) const; + constexpr Vector3i &operator*=(const Vector3i &p_v); + constexpr Vector3i operator*(const Vector3i &p_v) const; + constexpr Vector3i &operator/=(const Vector3i &p_v); + constexpr Vector3i operator/(const Vector3i &p_v) const; + constexpr Vector3i &operator%=(const Vector3i &p_v); + constexpr Vector3i operator%(const Vector3i &p_v) const; + + constexpr Vector3i &operator*=(int32_t p_scalar); + constexpr Vector3i operator*(int32_t p_scalar) const; + constexpr Vector3i &operator/=(int32_t p_scalar); + constexpr Vector3i operator/(int32_t p_scalar) const; + constexpr Vector3i &operator%=(int32_t p_scalar); + constexpr Vector3i operator%(int32_t p_scalar) const; + + constexpr Vector3i operator-() const; + + constexpr bool operator==(const Vector3i &p_v) const; + constexpr bool operator!=(const Vector3i &p_v) const; + constexpr bool operator<(const Vector3i &p_v) const; + constexpr bool operator<=(const Vector3i &p_v) const; + constexpr bool operator>(const Vector3i &p_v) const; + constexpr bool operator>=(const Vector3i &p_v) const; + + explicit operator String() const; operator Vector3() const; - _FORCE_INLINE_ Vector3i() {} - _FORCE_INLINE_ Vector3i(int32_t p_x, int32_t p_y, int32_t p_z) { - x = p_x; - y = p_y; - z = p_z; - } + constexpr Vector3i() = default; + constexpr Vector3i(int32_t p_x, int32_t p_y, int32_t p_z) : + x(p_x), y(p_y), z(p_z) {} }; +inline constexpr Vector3i Vector3i::LEFT = { -1, 0, 0 }; +inline constexpr Vector3i Vector3i::RIGHT = { 1, 0, 0 }; +inline constexpr Vector3i Vector3i::UP = { 0, 1, 0 }; +inline constexpr Vector3i Vector3i::DOWN = { 0, -1, 0 }; +inline constexpr Vector3i Vector3i::FORWARD = { 0, 0, -1 }; +inline constexpr Vector3i Vector3i::BACK = { 0, 0, 1 }; + int64_t Vector3i::length_squared() const { return x * (int64_t)x + y * (int64_t)y + z * (int64_t)z; } @@ -167,125 +178,125 @@ int64_t Vector3i::distance_squared_to(const Vector3i &p_to) const { /* Operators */ -Vector3i &Vector3i::operator+=(const Vector3i &p_v) { +constexpr Vector3i &Vector3i::operator+=(const Vector3i &p_v) { x += p_v.x; y += p_v.y; z += p_v.z; return *this; } -Vector3i Vector3i::operator+(const Vector3i &p_v) const { +constexpr Vector3i Vector3i::operator+(const Vector3i &p_v) const { return Vector3i(x + p_v.x, y + p_v.y, z + p_v.z); } -Vector3i &Vector3i::operator-=(const Vector3i &p_v) { +constexpr Vector3i &Vector3i::operator-=(const Vector3i &p_v) { x -= p_v.x; y -= p_v.y; z -= p_v.z; return *this; } -Vector3i Vector3i::operator-(const Vector3i &p_v) const { +constexpr Vector3i Vector3i::operator-(const Vector3i &p_v) const { return Vector3i(x - p_v.x, y - p_v.y, z - p_v.z); } -Vector3i &Vector3i::operator*=(const Vector3i &p_v) { +constexpr Vector3i &Vector3i::operator*=(const Vector3i &p_v) { x *= p_v.x; y *= p_v.y; z *= p_v.z; return *this; } -Vector3i Vector3i::operator*(const Vector3i &p_v) const { +constexpr Vector3i Vector3i::operator*(const Vector3i &p_v) const { return Vector3i(x * p_v.x, y * p_v.y, z * p_v.z); } -Vector3i &Vector3i::operator/=(const Vector3i &p_v) { - x /= p_v.x; - y /= p_v.y; - z /= p_v.z; +constexpr Vector3i &Vector3i::operator/=(const Vector3i &p_v) { + x = Math::division_no_overflow(x, p_v.x); + y = Math::division_no_overflow(y, p_v.y); + z = Math::division_no_overflow(z, p_v.z); return *this; } -Vector3i Vector3i::operator/(const Vector3i &p_v) const { - return Vector3i(x / p_v.x, y / p_v.y, z / p_v.z); +constexpr Vector3i Vector3i::operator/(const Vector3i &p_v) const { + return Vector3i(Math::division_no_overflow(x, p_v.x), Math::division_no_overflow(y, p_v.y), Math::division_no_overflow(z, p_v.z)); } -Vector3i &Vector3i::operator%=(const Vector3i &p_v) { - x %= p_v.x; - y %= p_v.y; - z %= p_v.z; +constexpr Vector3i &Vector3i::operator%=(const Vector3i &p_v) { + x = Math::modulo_no_overflow(x, p_v.x); + y = Math::modulo_no_overflow(y, p_v.y); + z = Math::modulo_no_overflow(z, p_v.z); return *this; } -Vector3i Vector3i::operator%(const Vector3i &p_v) const { - return Vector3i(x % p_v.x, y % p_v.y, z % p_v.z); +constexpr Vector3i Vector3i::operator%(const Vector3i &p_v) const { + return Vector3i(Math::modulo_no_overflow(x, p_v.x), Math::modulo_no_overflow(y, p_v.y), Math::modulo_no_overflow(z, p_v.z)); } -Vector3i &Vector3i::operator*=(int32_t p_scalar) { +constexpr Vector3i &Vector3i::operator*=(int32_t p_scalar) { x *= p_scalar; y *= p_scalar; z *= p_scalar; return *this; } -Vector3i Vector3i::operator*(int32_t p_scalar) const { +constexpr Vector3i Vector3i::operator*(int32_t p_scalar) const { return Vector3i(x * p_scalar, y * p_scalar, z * p_scalar); } // Multiplication operators required to workaround issues with LLVM using implicit conversion. -_FORCE_INLINE_ Vector3i operator*(int32_t p_scalar, const Vector3i &p_vector) { +constexpr Vector3i operator*(int32_t p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector3i operator*(int64_t p_scalar, const Vector3i &p_vector) { +constexpr Vector3i operator*(int64_t p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector3i operator*(float p_scalar, const Vector3i &p_vector) { +constexpr Vector3i operator*(float p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector3i operator*(double p_scalar, const Vector3i &p_vector) { +constexpr Vector3i operator*(double p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -Vector3i &Vector3i::operator/=(int32_t p_scalar) { - x /= p_scalar; - y /= p_scalar; - z /= p_scalar; +constexpr Vector3i &Vector3i::operator/=(int32_t p_scalar) { + x = Math::division_no_overflow(x, p_scalar); + y = Math::division_no_overflow(y, p_scalar); + z = Math::division_no_overflow(z, p_scalar); return *this; } -Vector3i Vector3i::operator/(int32_t p_scalar) const { - return Vector3i(x / p_scalar, y / p_scalar, z / p_scalar); +constexpr Vector3i Vector3i::operator/(int32_t p_scalar) const { + return Vector3i(Math::division_no_overflow(x, p_scalar), Math::division_no_overflow(y, p_scalar), Math::division_no_overflow(z, p_scalar)); } -Vector3i &Vector3i::operator%=(int32_t p_scalar) { - x %= p_scalar; - y %= p_scalar; - z %= p_scalar; +constexpr Vector3i &Vector3i::operator%=(int32_t p_scalar) { + x = Math::modulo_no_overflow(x, p_scalar); + y = Math::modulo_no_overflow(y, p_scalar); + z = Math::modulo_no_overflow(z, p_scalar); return *this; } -Vector3i Vector3i::operator%(int32_t p_scalar) const { - return Vector3i(x % p_scalar, y % p_scalar, z % p_scalar); +constexpr Vector3i Vector3i::operator%(int32_t p_scalar) const { + return Vector3i(Math::modulo_no_overflow(x, p_scalar), Math::modulo_no_overflow(y, p_scalar), Math::modulo_no_overflow(z, p_scalar)); } -Vector3i Vector3i::operator-() const { +constexpr Vector3i Vector3i::operator-() const { return Vector3i(-x, -y, -z); } -bool Vector3i::operator==(const Vector3i &p_v) const { +constexpr bool Vector3i::operator==(const Vector3i &p_v) const { return (x == p_v.x && y == p_v.y && z == p_v.z); } -bool Vector3i::operator!=(const Vector3i &p_v) const { +constexpr bool Vector3i::operator!=(const Vector3i &p_v) const { return (x != p_v.x || y != p_v.y || z != p_v.z); } -bool Vector3i::operator<(const Vector3i &p_v) const { +constexpr bool Vector3i::operator<(const Vector3i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z < p_v.z; @@ -297,7 +308,7 @@ bool Vector3i::operator<(const Vector3i &p_v) const { } } -bool Vector3i::operator>(const Vector3i &p_v) const { +constexpr bool Vector3i::operator>(const Vector3i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z > p_v.z; @@ -309,7 +320,7 @@ bool Vector3i::operator>(const Vector3i &p_v) const { } } -bool Vector3i::operator<=(const Vector3i &p_v) const { +constexpr bool Vector3i::operator<=(const Vector3i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z <= p_v.z; @@ -321,7 +332,7 @@ bool Vector3i::operator<=(const Vector3i &p_v) const { } } -bool Vector3i::operator>=(const Vector3i &p_v) const { +constexpr bool Vector3i::operator>=(const Vector3i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z >= p_v.z; @@ -337,4 +348,6 @@ void Vector3i::zero() { x = y = z = 0; } +template <> +struct is_zero_constructible : std::true_type {}; } // namespace godot diff --git a/include/godot_cpp/variant/vector4.hpp b/include/godot_cpp/variant/vector4.hpp index 3348f6111..058e15361 100644 --- a/include/godot_cpp/variant/vector4.hpp +++ b/include/godot_cpp/variant/vector4.hpp @@ -39,7 +39,7 @@ class String; struct Vector4i; struct [[nodiscard]] Vector4 { - static const int AXIS_COUNT = 4; + static constexpr int AXIS_COUNT = 4; enum Axis { AXIS_X, @@ -48,23 +48,26 @@ struct [[nodiscard]] Vector4 { AXIS_W, }; - union { - struct { - real_t x; - real_t y; - real_t z; - real_t w; - }; - real_t coord[4] = { 0, 0, 0, 0 }; - }; + real_t x = 0.0f; + real_t y = 0.0f; + real_t z = 0.0f; + real_t w = 0.0f; + + constexpr real_t &operator[](int p_axis) { + // The pointer math below assumes that the elements are placed back-to-back, like an array. + // This is always true in practice, but technically not guaranteed; we safety-check it here. + static_assert(offsetof(Vector4, x) == 0 * sizeof(real_t)); + static_assert(offsetof(Vector4, y) == 1 * sizeof(real_t)); + static_assert(offsetof(Vector4, z) == 2 * sizeof(real_t)); + static_assert(offsetof(Vector4, w) == 3 * sizeof(real_t)); + static_assert(sizeof(Vector4) == 4 * sizeof(real_t)); - _FORCE_INLINE_ real_t &operator[](int p_axis) { DEV_ASSERT((unsigned int)p_axis < 4); - return coord[p_axis]; + return (&x)[p_axis]; } - _FORCE_INLINE_ const real_t &operator[](int p_axis) const { + constexpr const real_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 4); - return coord[p_axis]; + return (&x)[p_axis]; } Vector4::Axis min_axis_index() const; @@ -89,12 +92,15 @@ struct [[nodiscard]] Vector4 { _FORCE_INLINE_ real_t length_squared() const; bool is_equal_approx(const Vector4 &p_vec4) const; bool is_zero_approx() const; + bool is_same(const Vector4 &p_vec4) const; bool is_finite() const; real_t length() const; void normalize(); Vector4 normalized() const; bool is_normalized() const; + void zero() { x = y = z = w = 0; } + real_t distance_to(const Vector4 &p_to) const; real_t distance_squared_to(const Vector4 &p_to) const; Vector4 direction_to(const Vector4 &p_to) const; @@ -120,37 +126,33 @@ struct [[nodiscard]] Vector4 { Vector4 inverse() const; _FORCE_INLINE_ real_t dot(const Vector4 &p_vec4) const; - _FORCE_INLINE_ void operator+=(const Vector4 &p_vec4); - _FORCE_INLINE_ void operator-=(const Vector4 &p_vec4); - _FORCE_INLINE_ void operator*=(const Vector4 &p_vec4); - _FORCE_INLINE_ void operator/=(const Vector4 &p_vec4); - _FORCE_INLINE_ void operator*=(real_t p_s); - _FORCE_INLINE_ void operator/=(real_t p_s); - _FORCE_INLINE_ Vector4 operator+(const Vector4 &p_vec4) const; - _FORCE_INLINE_ Vector4 operator-(const Vector4 &p_vec4) const; - _FORCE_INLINE_ Vector4 operator*(const Vector4 &p_vec4) const; - _FORCE_INLINE_ Vector4 operator/(const Vector4 &p_vec4) const; - _FORCE_INLINE_ Vector4 operator-() const; - _FORCE_INLINE_ Vector4 operator*(real_t p_s) const; - _FORCE_INLINE_ Vector4 operator/(real_t p_s) const; - - _FORCE_INLINE_ bool operator==(const Vector4 &p_vec4) const; - _FORCE_INLINE_ bool operator!=(const Vector4 &p_vec4) const; - _FORCE_INLINE_ bool operator>(const Vector4 &p_vec4) const; - _FORCE_INLINE_ bool operator<(const Vector4 &p_vec4) const; - _FORCE_INLINE_ bool operator>=(const Vector4 &p_vec4) const; - _FORCE_INLINE_ bool operator<=(const Vector4 &p_vec4) const; - - operator String() const; + constexpr void operator+=(const Vector4 &p_vec4); + constexpr void operator-=(const Vector4 &p_vec4); + constexpr void operator*=(const Vector4 &p_vec4); + constexpr void operator/=(const Vector4 &p_vec4); + constexpr void operator*=(real_t p_s); + constexpr void operator/=(real_t p_s); + constexpr Vector4 operator+(const Vector4 &p_vec4) const; + constexpr Vector4 operator-(const Vector4 &p_vec4) const; + constexpr Vector4 operator*(const Vector4 &p_vec4) const; + constexpr Vector4 operator/(const Vector4 &p_vec4) const; + constexpr Vector4 operator-() const; + constexpr Vector4 operator*(real_t p_s) const; + constexpr Vector4 operator/(real_t p_s) const; + + constexpr bool operator==(const Vector4 &p_vec4) const; + constexpr bool operator!=(const Vector4 &p_vec4) const; + constexpr bool operator>(const Vector4 &p_vec4) const; + constexpr bool operator<(const Vector4 &p_vec4) const; + constexpr bool operator>=(const Vector4 &p_vec4) const; + constexpr bool operator<=(const Vector4 &p_vec4) const; + + explicit operator String() const; operator Vector4i() const; - _FORCE_INLINE_ Vector4() {} - _FORCE_INLINE_ Vector4(real_t p_x, real_t p_y, real_t p_z, real_t p_w) { - x = p_x; - y = p_y; - z = p_z; - w = p_w; - } + constexpr Vector4() = default; + constexpr Vector4(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : + x(p_x), y(p_y), z(p_z), w(p_w) {} }; real_t Vector4::dot(const Vector4 &p_vec4) const { @@ -161,81 +163,84 @@ real_t Vector4::length_squared() const { return dot(*this); } -void Vector4::operator+=(const Vector4 &p_vec4) { +constexpr void Vector4::operator+=(const Vector4 &p_vec4) { x += p_vec4.x; y += p_vec4.y; z += p_vec4.z; w += p_vec4.w; } -void Vector4::operator-=(const Vector4 &p_vec4) { +constexpr void Vector4::operator-=(const Vector4 &p_vec4) { x -= p_vec4.x; y -= p_vec4.y; z -= p_vec4.z; w -= p_vec4.w; } -void Vector4::operator*=(const Vector4 &p_vec4) { +constexpr void Vector4::operator*=(const Vector4 &p_vec4) { x *= p_vec4.x; y *= p_vec4.y; z *= p_vec4.z; w *= p_vec4.w; } -void Vector4::operator/=(const Vector4 &p_vec4) { +constexpr void Vector4::operator/=(const Vector4 &p_vec4) { x /= p_vec4.x; y /= p_vec4.y; z /= p_vec4.z; w /= p_vec4.w; } -void Vector4::operator*=(real_t p_s) { +constexpr void Vector4::operator*=(real_t p_s) { x *= p_s; y *= p_s; z *= p_s; w *= p_s; } -void Vector4::operator/=(real_t p_s) { - *this *= 1.0f / p_s; +constexpr void Vector4::operator/=(real_t p_s) { + x /= p_s; + y /= p_s; + z /= p_s; + w /= p_s; } -Vector4 Vector4::operator+(const Vector4 &p_vec4) const { +constexpr Vector4 Vector4::operator+(const Vector4 &p_vec4) const { return Vector4(x + p_vec4.x, y + p_vec4.y, z + p_vec4.z, w + p_vec4.w); } -Vector4 Vector4::operator-(const Vector4 &p_vec4) const { +constexpr Vector4 Vector4::operator-(const Vector4 &p_vec4) const { return Vector4(x - p_vec4.x, y - p_vec4.y, z - p_vec4.z, w - p_vec4.w); } -Vector4 Vector4::operator*(const Vector4 &p_vec4) const { +constexpr Vector4 Vector4::operator*(const Vector4 &p_vec4) const { return Vector4(x * p_vec4.x, y * p_vec4.y, z * p_vec4.z, w * p_vec4.w); } -Vector4 Vector4::operator/(const Vector4 &p_vec4) const { +constexpr Vector4 Vector4::operator/(const Vector4 &p_vec4) const { return Vector4(x / p_vec4.x, y / p_vec4.y, z / p_vec4.z, w / p_vec4.w); } -Vector4 Vector4::operator-() const { +constexpr Vector4 Vector4::operator-() const { return Vector4(-x, -y, -z, -w); } -Vector4 Vector4::operator*(real_t p_s) const { +constexpr Vector4 Vector4::operator*(real_t p_s) const { return Vector4(x * p_s, y * p_s, z * p_s, w * p_s); } -Vector4 Vector4::operator/(real_t p_s) const { - return *this * (1.0f / p_s); +constexpr Vector4 Vector4::operator/(real_t p_s) const { + return Vector4(x / p_s, y / p_s, z / p_s, w / p_s); } -bool Vector4::operator==(const Vector4 &p_vec4) const { +constexpr bool Vector4::operator==(const Vector4 &p_vec4) const { return x == p_vec4.x && y == p_vec4.y && z == p_vec4.z && w == p_vec4.w; } -bool Vector4::operator!=(const Vector4 &p_vec4) const { +constexpr bool Vector4::operator!=(const Vector4 &p_vec4) const { return x != p_vec4.x || y != p_vec4.y || z != p_vec4.z || w != p_vec4.w; } -bool Vector4::operator<(const Vector4 &p_v) const { +constexpr bool Vector4::operator<(const Vector4 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -248,7 +253,7 @@ bool Vector4::operator<(const Vector4 &p_v) const { return x < p_v.x; } -bool Vector4::operator>(const Vector4 &p_v) const { +constexpr bool Vector4::operator>(const Vector4 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -261,7 +266,7 @@ bool Vector4::operator>(const Vector4 &p_v) const { return x > p_v.x; } -bool Vector4::operator<=(const Vector4 &p_v) const { +constexpr bool Vector4::operator<=(const Vector4 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -274,7 +279,7 @@ bool Vector4::operator<=(const Vector4 &p_v) const { return x < p_v.x; } -bool Vector4::operator>=(const Vector4 &p_v) const { +constexpr bool Vector4::operator>=(const Vector4 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -287,20 +292,22 @@ bool Vector4::operator>=(const Vector4 &p_v) const { return x > p_v.x; } -_FORCE_INLINE_ Vector4 operator*(float p_scalar, const Vector4 &p_vec) { +constexpr Vector4 operator*(float p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector4 operator*(double p_scalar, const Vector4 &p_vec) { +constexpr Vector4 operator*(double p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector4 operator*(int32_t p_scalar, const Vector4 &p_vec) { +constexpr Vector4 operator*(int32_t p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector4 operator*(int64_t p_scalar, const Vector4 &p_vec) { +constexpr Vector4 operator*(int64_t p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } +template <> +struct is_zero_constructible : std::true_type {}; } // namespace godot diff --git a/include/godot_cpp/variant/vector4i.hpp b/include/godot_cpp/variant/vector4i.hpp index 1a7471af6..14c2a32f4 100644 --- a/include/godot_cpp/variant/vector4i.hpp +++ b/include/godot_cpp/variant/vector4i.hpp @@ -39,7 +39,7 @@ class String; struct Vector4; struct [[nodiscard]] Vector4i { - static const int AXIS_COUNT = 4; + static constexpr int AXIS_COUNT = 4; enum Axis { AXIS_X, @@ -48,25 +48,26 @@ struct [[nodiscard]] Vector4i { AXIS_W, }; - union { - struct { - int32_t x; - int32_t y; - int32_t z; - int32_t w; - }; + int32_t x = 0; + int32_t y = 0; + int32_t z = 0; + int32_t w = 0; - int32_t coord[4] = { 0 }; - }; + constexpr int32_t &operator[](int p_axis) { + // The pointer math below assumes that the elements are placed back-to-back, like an array. + // This is always true in practice, but technically not guaranteed; we safety-check it here. + static_assert(offsetof(Vector4i, x) == 0 * sizeof(int32_t)); + static_assert(offsetof(Vector4i, y) == 1 * sizeof(int32_t)); + static_assert(offsetof(Vector4i, z) == 2 * sizeof(int32_t)); + static_assert(offsetof(Vector4i, w) == 3 * sizeof(int32_t)); + static_assert(sizeof(Vector4i) == 4 * sizeof(int32_t)); - _FORCE_INLINE_ const int32_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 4); - return coord[p_axis]; + return (&x)[p_axis]; } - - _FORCE_INLINE_ int32_t &operator[](int p_axis) { + constexpr const int32_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 4); - return coord[p_axis]; + return (&x)[p_axis]; } Vector4i::Axis min_axis_index() const; @@ -105,44 +106,39 @@ struct [[nodiscard]] Vector4i { /* Operators */ - _FORCE_INLINE_ Vector4i &operator+=(const Vector4i &p_v); - _FORCE_INLINE_ Vector4i operator+(const Vector4i &p_v) const; - _FORCE_INLINE_ Vector4i &operator-=(const Vector4i &p_v); - _FORCE_INLINE_ Vector4i operator-(const Vector4i &p_v) const; - _FORCE_INLINE_ Vector4i &operator*=(const Vector4i &p_v); - _FORCE_INLINE_ Vector4i operator*(const Vector4i &p_v) const; - _FORCE_INLINE_ Vector4i &operator/=(const Vector4i &p_v); - _FORCE_INLINE_ Vector4i operator/(const Vector4i &p_v) const; - _FORCE_INLINE_ Vector4i &operator%=(const Vector4i &p_v); - _FORCE_INLINE_ Vector4i operator%(const Vector4i &p_v) const; - - _FORCE_INLINE_ Vector4i &operator*=(int32_t p_scalar); - _FORCE_INLINE_ Vector4i operator*(int32_t p_scalar) const; - _FORCE_INLINE_ Vector4i &operator/=(int32_t p_scalar); - _FORCE_INLINE_ Vector4i operator/(int32_t p_scalar) const; - _FORCE_INLINE_ Vector4i &operator%=(int32_t p_scalar); - _FORCE_INLINE_ Vector4i operator%(int32_t p_scalar) const; - - _FORCE_INLINE_ Vector4i operator-() const; - - _FORCE_INLINE_ bool operator==(const Vector4i &p_v) const; - _FORCE_INLINE_ bool operator!=(const Vector4i &p_v) const; - _FORCE_INLINE_ bool operator<(const Vector4i &p_v) const; - _FORCE_INLINE_ bool operator<=(const Vector4i &p_v) const; - _FORCE_INLINE_ bool operator>(const Vector4i &p_v) const; - _FORCE_INLINE_ bool operator>=(const Vector4i &p_v) const; - - operator String() const; + constexpr Vector4i &operator+=(const Vector4i &p_v); + constexpr Vector4i operator+(const Vector4i &p_v) const; + constexpr Vector4i &operator-=(const Vector4i &p_v); + constexpr Vector4i operator-(const Vector4i &p_v) const; + constexpr Vector4i &operator*=(const Vector4i &p_v); + constexpr Vector4i operator*(const Vector4i &p_v) const; + constexpr Vector4i &operator/=(const Vector4i &p_v); + constexpr Vector4i operator/(const Vector4i &p_v) const; + constexpr Vector4i &operator%=(const Vector4i &p_v); + constexpr Vector4i operator%(const Vector4i &p_v) const; + + constexpr Vector4i &operator*=(int32_t p_scalar); + constexpr Vector4i operator*(int32_t p_scalar) const; + constexpr Vector4i &operator/=(int32_t p_scalar); + constexpr Vector4i operator/(int32_t p_scalar) const; + constexpr Vector4i &operator%=(int32_t p_scalar); + constexpr Vector4i operator%(int32_t p_scalar) const; + + constexpr Vector4i operator-() const; + + constexpr bool operator==(const Vector4i &p_v) const; + constexpr bool operator!=(const Vector4i &p_v) const; + constexpr bool operator<(const Vector4i &p_v) const; + constexpr bool operator<=(const Vector4i &p_v) const; + constexpr bool operator>(const Vector4i &p_v) const; + constexpr bool operator>=(const Vector4i &p_v) const; + + explicit operator String() const; operator Vector4() const; - _FORCE_INLINE_ Vector4i() {} - Vector4i(const Vector4 &p_vec4); - _FORCE_INLINE_ Vector4i(int32_t p_x, int32_t p_y, int32_t p_z, int32_t p_w) { - x = p_x; - y = p_y; - z = p_z; - w = p_w; - } + constexpr Vector4i() = default; + constexpr Vector4i(int32_t p_x, int32_t p_y, int32_t p_z, int32_t p_w) : + x(p_x), y(p_y), z(p_z), w(p_w) {} }; int64_t Vector4i::length_squared() const { @@ -171,7 +167,7 @@ Vector4i Vector4i::sign() const { /* Operators */ -Vector4i &Vector4i::operator+=(const Vector4i &p_v) { +constexpr Vector4i &Vector4i::operator+=(const Vector4i &p_v) { x += p_v.x; y += p_v.y; z += p_v.z; @@ -179,11 +175,11 @@ Vector4i &Vector4i::operator+=(const Vector4i &p_v) { return *this; } -Vector4i Vector4i::operator+(const Vector4i &p_v) const { +constexpr Vector4i Vector4i::operator+(const Vector4i &p_v) const { return Vector4i(x + p_v.x, y + p_v.y, z + p_v.z, w + p_v.w); } -Vector4i &Vector4i::operator-=(const Vector4i &p_v) { +constexpr Vector4i &Vector4i::operator-=(const Vector4i &p_v) { x -= p_v.x; y -= p_v.y; z -= p_v.z; @@ -191,11 +187,11 @@ Vector4i &Vector4i::operator-=(const Vector4i &p_v) { return *this; } -Vector4i Vector4i::operator-(const Vector4i &p_v) const { +constexpr Vector4i Vector4i::operator-(const Vector4i &p_v) const { return Vector4i(x - p_v.x, y - p_v.y, z - p_v.z, w - p_v.w); } -Vector4i &Vector4i::operator*=(const Vector4i &p_v) { +constexpr Vector4i &Vector4i::operator*=(const Vector4i &p_v) { x *= p_v.x; y *= p_v.y; z *= p_v.z; @@ -203,35 +199,35 @@ Vector4i &Vector4i::operator*=(const Vector4i &p_v) { return *this; } -Vector4i Vector4i::operator*(const Vector4i &p_v) const { +constexpr Vector4i Vector4i::operator*(const Vector4i &p_v) const { return Vector4i(x * p_v.x, y * p_v.y, z * p_v.z, w * p_v.w); } -Vector4i &Vector4i::operator/=(const Vector4i &p_v) { - x /= p_v.x; - y /= p_v.y; - z /= p_v.z; - w /= p_v.w; +constexpr Vector4i &Vector4i::operator/=(const Vector4i &p_v) { + x = Math::division_no_overflow(x, p_v.x); + y = Math::division_no_overflow(y, p_v.y); + z = Math::division_no_overflow(z, p_v.z); + w = Math::division_no_overflow(w, p_v.w); return *this; } -Vector4i Vector4i::operator/(const Vector4i &p_v) const { - return Vector4i(x / p_v.x, y / p_v.y, z / p_v.z, w / p_v.w); +constexpr Vector4i Vector4i::operator/(const Vector4i &p_v) const { + return Vector4i(Math::division_no_overflow(x, p_v.x), Math::division_no_overflow(y, p_v.y), Math::division_no_overflow(z, p_v.z), Math::division_no_overflow(w, p_v.w)); } -Vector4i &Vector4i::operator%=(const Vector4i &p_v) { - x %= p_v.x; - y %= p_v.y; - z %= p_v.z; - w %= p_v.w; +constexpr Vector4i &Vector4i::operator%=(const Vector4i &p_v) { + x = Math::modulo_no_overflow(x, p_v.x); + y = Math::modulo_no_overflow(y, p_v.y); + z = Math::modulo_no_overflow(z, p_v.z); + w = Math::modulo_no_overflow(w, p_v.w); return *this; } -Vector4i Vector4i::operator%(const Vector4i &p_v) const { - return Vector4i(x % p_v.x, y % p_v.y, z % p_v.z, w % p_v.w); +constexpr Vector4i Vector4i::operator%(const Vector4i &p_v) const { + return Vector4i(Math::modulo_no_overflow(x, p_v.x), Math::modulo_no_overflow(y, p_v.y), Math::modulo_no_overflow(z, p_v.z), Math::modulo_no_overflow(w, p_v.w)); } -Vector4i &Vector4i::operator*=(int32_t p_scalar) { +constexpr Vector4i &Vector4i::operator*=(int32_t p_scalar) { x *= p_scalar; y *= p_scalar; z *= p_scalar; @@ -239,65 +235,65 @@ Vector4i &Vector4i::operator*=(int32_t p_scalar) { return *this; } -Vector4i Vector4i::operator*(int32_t p_scalar) const { +constexpr Vector4i Vector4i::operator*(int32_t p_scalar) const { return Vector4i(x * p_scalar, y * p_scalar, z * p_scalar, w * p_scalar); } // Multiplication operators required to workaround issues with LLVM using implicit conversion. -_FORCE_INLINE_ Vector4i operator*(int32_t p_scalar, const Vector4i &p_vector) { +constexpr Vector4i operator*(int32_t p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector4i operator*(int64_t p_scalar, const Vector4i &p_vector) { +constexpr Vector4i operator*(int64_t p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector4i operator*(float p_scalar, const Vector4i &p_vector) { +constexpr Vector4i operator*(float p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector4i operator*(double p_scalar, const Vector4i &p_vector) { +constexpr Vector4i operator*(double p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -Vector4i &Vector4i::operator/=(int32_t p_scalar) { - x /= p_scalar; - y /= p_scalar; - z /= p_scalar; - w /= p_scalar; +constexpr Vector4i &Vector4i::operator/=(int32_t p_scalar) { + x = Math::division_no_overflow(x, p_scalar); + y = Math::division_no_overflow(y, p_scalar); + z = Math::division_no_overflow(z, p_scalar); + w = Math::division_no_overflow(w, p_scalar); return *this; } -Vector4i Vector4i::operator/(int32_t p_scalar) const { - return Vector4i(x / p_scalar, y / p_scalar, z / p_scalar, w / p_scalar); +constexpr Vector4i Vector4i::operator/(int32_t p_scalar) const { + return Vector4i(Math::division_no_overflow(x, p_scalar), Math::division_no_overflow(y, p_scalar), Math::division_no_overflow(z, p_scalar), Math::division_no_overflow(w, p_scalar)); } -Vector4i &Vector4i::operator%=(int32_t p_scalar) { - x %= p_scalar; - y %= p_scalar; - z %= p_scalar; - w %= p_scalar; +constexpr Vector4i &Vector4i::operator%=(int32_t p_scalar) { + x = Math::modulo_no_overflow(x, p_scalar); + y = Math::modulo_no_overflow(y, p_scalar); + z = Math::modulo_no_overflow(z, p_scalar); + w = Math::modulo_no_overflow(w, p_scalar); return *this; } -Vector4i Vector4i::operator%(int32_t p_scalar) const { - return Vector4i(x % p_scalar, y % p_scalar, z % p_scalar, w % p_scalar); +constexpr Vector4i Vector4i::operator%(int32_t p_scalar) const { + return Vector4i(Math::modulo_no_overflow(x, p_scalar), Math::modulo_no_overflow(y, p_scalar), Math::modulo_no_overflow(z, p_scalar), Math::modulo_no_overflow(w, p_scalar)); } -Vector4i Vector4i::operator-() const { +constexpr Vector4i Vector4i::operator-() const { return Vector4i(-x, -y, -z, -w); } -bool Vector4i::operator==(const Vector4i &p_v) const { +constexpr bool Vector4i::operator==(const Vector4i &p_v) const { return (x == p_v.x && y == p_v.y && z == p_v.z && w == p_v.w); } -bool Vector4i::operator!=(const Vector4i &p_v) const { +constexpr bool Vector4i::operator!=(const Vector4i &p_v) const { return (x != p_v.x || y != p_v.y || z != p_v.z || w != p_v.w); } -bool Vector4i::operator<(const Vector4i &p_v) const { +constexpr bool Vector4i::operator<(const Vector4i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -313,7 +309,7 @@ bool Vector4i::operator<(const Vector4i &p_v) const { } } -bool Vector4i::operator>(const Vector4i &p_v) const { +constexpr bool Vector4i::operator>(const Vector4i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -329,7 +325,7 @@ bool Vector4i::operator>(const Vector4i &p_v) const { } } -bool Vector4i::operator<=(const Vector4i &p_v) const { +constexpr bool Vector4i::operator<=(const Vector4i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -345,7 +341,7 @@ bool Vector4i::operator<=(const Vector4i &p_v) const { } } -bool Vector4i::operator>=(const Vector4i &p_v) const { +constexpr bool Vector4i::operator>=(const Vector4i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -365,4 +361,6 @@ void Vector4i::zero() { x = y = z = w = 0; } +template <> +struct is_zero_constructible : std::true_type {}; } // namespace godot diff --git a/src/variant/aabb.cpp b/src/variant/aabb.cpp index c0ac63899..2c8d9bec0 100644 --- a/src/variant/aabb.cpp +++ b/src/variant/aabb.cpp @@ -39,14 +39,6 @@ real_t AABB::get_volume() const { return size.x * size.y * size.z; } -bool AABB::operator==(const AABB &p_rval) const { - return ((position == p_rval.position) && (size == p_rval.size)); -} - -bool AABB::operator!=(const AABB &p_rval) const { - return ((position != p_rval.position) || (size != p_rval.size)); -} - void AABB::merge_with(const AABB &p_aabb) { #ifdef MATH_CHECKS if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) { @@ -78,6 +70,10 @@ bool AABB::is_equal_approx(const AABB &p_aabb) const { return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size); } +bool AABB::is_same(const AABB &p_aabb) const { + return position.is_same(p_aabb.position) && size.is_same(p_aabb.size); +} + bool AABB::is_finite() const { return position.is_finite() && size.is_finite(); } @@ -177,7 +173,7 @@ bool AABB::find_intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, bool // Prevent float error by making sure the point is exactly // on the AABB border on the relevant axis. - r_intersection_point->coord[axis] = (p_dir[axis] >= 0) ? position.coord[axis] : end.coord[axis]; + (*r_intersection_point)[axis] = (p_dir[axis] >= 0) ? position[axis] : end[axis]; } if (r_normal) { *r_normal = Vector3(); @@ -447,7 +443,7 @@ Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) c } AABB::operator String() const { - return "[P: " + position.operator String() + ", S: " + size + "]"; + return "[P: " + String(position) + ", S: " + String(size) + "]"; } } // namespace godot diff --git a/src/variant/basis.cpp b/src/variant/basis.cpp index 751ae63d9..89a8bd6a7 100644 --- a/src/variant/basis.cpp +++ b/src/variant/basis.cpp @@ -59,7 +59,8 @@ void Basis::invert() { } void Basis::orthonormalize() { - // Gram-Schmidt Process + // Orthonormalizable check is done in Vector3 class below. + // Gram-Schmidt Process: Vector3 x = get_column(0); Vector3 y = get_column(1); @@ -237,15 +238,9 @@ Basis Basis::from_scale(const Vector3 &p_scale) { // Multiplies the matrix from left by the scaling matrix: M -> S.M // See the comment for Basis::rotated for further explanation. void Basis::scale(const Vector3 &p_scale) { - rows[0][0] *= p_scale.x; - rows[0][1] *= p_scale.x; - rows[0][2] *= p_scale.x; - rows[1][0] *= p_scale.y; - rows[1][1] *= p_scale.y; - rows[1][2] *= p_scale.y; - rows[2][0] *= p_scale.z; - rows[2][1] *= p_scale.z; - rows[2][2] *= p_scale.z; + rows[0] *= p_scale.x; + rows[1] *= p_scale.y; + rows[2] *= p_scale.z; } Basis Basis::scaled(const Vector3 &p_scale) const { @@ -257,7 +252,9 @@ Basis Basis::scaled(const Vector3 &p_scale) const { void Basis::scale_local(const Vector3 &p_scale) { // performs a scaling in object-local coordinate system: // M -> (M.S.Minv).M = M.S. - *this = scaled_local(p_scale); + rows[0] *= p_scale; + rows[1] *= p_scale; + rows[2] *= p_scale; } void Basis::scale_orthogonal(const Vector3 &p_scale) { @@ -288,7 +285,9 @@ real_t Basis::get_uniform_scale() const { } Basis Basis::scaled_local(const Vector3 &p_scale) const { - return (*this) * Basis::from_scale(p_scale); + Basis m = *this; + m.scale_local(p_scale); + return m; } Vector3 Basis::get_scale_abs() const { @@ -332,7 +331,7 @@ Vector3 Basis::get_scale() const { // Decomposes a Basis into a rotation-reflection matrix (an element of the group O(3)) and a positive scaling matrix as B = O.S. // Returns the rotation-reflection matrix via reference argument, and scaling information is returned as a Vector3. // This (internal) function is too specific and named too ugly to expose to users, and probably there's no need to do so. -Vector3 Basis::rotref_posscale_decomposition(Basis &rotref) const { +Vector3 Basis::rotref_posscale_decomposition(Basis &r_rotref) const { #ifdef MATH_CHECKS ERR_FAIL_COND_V(determinant() == 0, Vector3()); @@ -341,10 +340,10 @@ Vector3 Basis::rotref_posscale_decomposition(Basis &rotref) const { #endif Vector3 scale = get_scale(); Basis inv_scale = Basis().scaled(scale.inverse()); // this will also absorb the sign of scale - rotref = (*this) * inv_scale; + r_rotref = (*this) * inv_scale; #ifdef MATH_CHECKS - ERR_FAIL_COND_V(!rotref.is_orthogonal(), Vector3()); + ERR_FAIL_COND_V(!r_rotref.is_orthogonal(), Vector3()); #endif return scale.abs(); } @@ -482,7 +481,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { if (rows[1][0] == 0 && rows[0][1] == 0 && rows[1][2] == 0 && rows[2][1] == 0 && rows[1][1] == 1) { // return the simplest form (human friendlier in editor and scripts) euler.x = 0; - euler.y = atan2(rows[0][2], rows[0][0]); + euler.y = std::atan2(rows[0][2], rows[0][0]); euler.z = 0; } else { euler.x = Math::atan2(-rows[1][2], rows[2][2]); @@ -547,22 +546,22 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { // is this a pure X rotation? if (rows[1][0] == 0 && rows[0][1] == 0 && rows[0][2] == 0 && rows[2][0] == 0 && rows[0][0] == 1) { // return the simplest form (human friendlier in editor and scripts) - euler.x = atan2(-m12, rows[1][1]); + euler.x = std::atan2(-m12, rows[1][1]); euler.y = 0; euler.z = 0; } else { - euler.x = asin(-m12); - euler.y = atan2(rows[0][2], rows[2][2]); - euler.z = atan2(rows[1][0], rows[1][1]); + euler.x = std::asin(-m12); + euler.y = std::atan2(rows[0][2], rows[2][2]); + euler.z = std::atan2(rows[1][0], rows[1][1]); } } else { // m12 == -1 euler.x = Math::PI * 0.5f; - euler.y = atan2(rows[0][1], rows[0][0]); + euler.y = std::atan2(rows[0][1], rows[0][0]); euler.z = 0; } } else { // m12 == 1 euler.x = -Math::PI * 0.5f; - euler.y = -atan2(rows[0][1], rows[0][0]); + euler.y = -std::atan2(rows[0][1], rows[0][0]); euler.z = 0; } @@ -704,24 +703,12 @@ bool Basis::is_equal_approx(const Basis &p_basis) const { return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]); } -bool Basis::is_finite() const { - return rows[0].is_finite() && rows[1].is_finite() && rows[2].is_finite(); +bool Basis::is_same(const Basis &p_basis) const { + return rows[0].is_same(p_basis.rows[0]) && rows[1].is_same(p_basis.rows[1]) && rows[2].is_same(p_basis.rows[2]); } -bool Basis::operator==(const Basis &p_matrix) const { - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (rows[i][j] != p_matrix.rows[i][j]) { - return false; - } - } - } - - return true; -} - -bool Basis::operator!=(const Basis &p_matrix) const { - return (!(*this == p_matrix)); +bool Basis::is_finite() const { + return rows[0].is_finite() && rows[1].is_finite() && rows[2].is_finite(); } Basis::operator String() const { @@ -773,7 +760,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { #endif */ - // https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + // https://www.euclideanspace.com/math/geometry/rotations/conversions/matrixToAngle/index.htm real_t x, y, z; // Variables for result. if (Math::is_zero_approx(rows[0][1] - rows[1][0]) && Math::is_zero_approx(rows[0][2] - rows[2][0]) && Math::is_zero_approx(rows[1][2] - rows[2][1])) { // Singularity found. diff --git a/src/variant/color.cpp b/src/variant/color.cpp index 1fb5211a5..f5e76e6ea 100644 --- a/src/variant/color.cpp +++ b/src/variant/color.cpp @@ -35,7 +35,6 @@ #include namespace godot { - uint32_t Color::to_argb32() const { uint32_t c = (uint8_t)Math::round(a * 255.0f); c <<= 8; @@ -245,6 +244,10 @@ bool Color::is_equal_approx(const Color &p_color) const { return Math::is_equal_approx(r, p_color.r) && Math::is_equal_approx(g, p_color.g) && Math::is_equal_approx(b, p_color.b) && Math::is_equal_approx(a, p_color.a); } +bool Color::is_same(const Color &p_color) const { + return Math::is_same(r, p_color.r) && Math::is_same(g, p_color.g) && Math::is_same(b, p_color.b) && Math::is_same(a, p_color.a); +} + Color Color::clamp(const Color &p_min, const Color &p_max) const { return Color( CLAMP(r, p_min.r, p_max.r), @@ -307,47 +310,38 @@ Color Color::inverted() const { } Color Color::html(const String &p_rgba) { - String color = p_rgba; - if (color.length() == 0) { + if (p_rgba.is_empty()) { return Color(); } - if (color[0] == '#') { - color = color.substr(1); - } - // If enabled, use 1 hex digit per channel instead of 2. - // Other sizes aren't in the HTML/CSS spec but we could add them if desired. - bool is_shorthand = color.length() < 5; - bool alpha = false; - - if (color.length() == 8) { - alpha = true; - } else if (color.length() == 6) { - alpha = false; - } else if (color.length() == 4) { - alpha = true; - } else if (color.length() == 3) { - alpha = false; - } else { - ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_rgba + "."); - } + const int current_pos = (p_rgba[0] == '#') ? 1 : 0; + const int num_of_digits = p_rgba.length() - current_pos; float r, g, b, a = 1.0f; - if (is_shorthand) { - r = _parse_col4(color, 0) / 15.0f; - g = _parse_col4(color, 1) / 15.0f; - b = _parse_col4(color, 2) / 15.0f; - if (alpha) { - a = _parse_col4(color, 3) / 15.0f; - } + + if (num_of_digits == 3) { + // #rgb + r = _parse_col4(p_rgba, current_pos) / 15.0f; + g = _parse_col4(p_rgba, current_pos + 1) / 15.0f; + b = _parse_col4(p_rgba, current_pos + 2) / 15.0f; + } else if (num_of_digits == 4) { + r = _parse_col4(p_rgba, current_pos) / 15.0f; + g = _parse_col4(p_rgba, current_pos + 1) / 15.0f; + b = _parse_col4(p_rgba, current_pos + 2) / 15.0f; + a = _parse_col4(p_rgba, current_pos + 3) / 15.0f; + } else if (num_of_digits == 6) { + r = _parse_col8(p_rgba, current_pos) / 255.0f; + g = _parse_col8(p_rgba, current_pos + 2) / 255.0f; + b = _parse_col8(p_rgba, current_pos + 4) / 255.0f; + } else if (num_of_digits == 8) { + r = _parse_col8(p_rgba, current_pos) / 255.0f; + g = _parse_col8(p_rgba, current_pos + 2) / 255.0f; + b = _parse_col8(p_rgba, current_pos + 4) / 255.0f; + a = _parse_col8(p_rgba, current_pos + 6) / 255.0f; } else { - r = _parse_col8(color, 0) / 255.0f; - g = _parse_col8(color, 2) / 255.0f; - b = _parse_col8(color, 4) / 255.0f; - if (alpha) { - a = _parse_col8(color, 6) / 255.0f; - } + ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_rgba + "."); } + ERR_FAIL_COND_V_MSG(r < 0.0f, Color(), "Invalid color code: " + p_rgba + "."); ERR_FAIL_COND_V_MSG(g < 0.0f, Color(), "Invalid color code: " + p_rgba + "."); ERR_FAIL_COND_V_MSG(b < 0.0f, Color(), "Invalid color code: " + p_rgba + "."); @@ -359,22 +353,20 @@ Color Color::html(const String &p_rgba) { bool Color::html_is_valid(const String &p_color) { String color = p_color; - if (color.length() == 0) { + if (color.is_empty()) { return false; } - if (color[0] == '#') { - color = color.substr(1); - } - // Check if the amount of hex digits is valid. - int len = color.length(); - if (!(len == 3 || len == 4 || len == 6 || len == 8)) { + const int current_pos = (color[0] == '#') ? 1 : 0; + const int len = color.length(); + const int num_of_digits = len - current_pos; + if (!(num_of_digits == 3 || num_of_digits == 4 || num_of_digits == 6 || num_of_digits == 8)) { return false; } // Check if each hex digit is valid. - for (int i = 0; i < len; i++) { - if (_parse_col4(color, i) == -1) { + for (int i = current_pos; i < len; i++) { + if (!is_hex_digit(p_color[i])) { return false; } } @@ -406,6 +398,7 @@ int Color::find_named_color(const String &p_name) { name = name.replace("_", ""); name = name.replace("'", ""); name = name.replace(".", ""); + name = name.to_upper(); static HashMap named_colors_hashmap; @@ -425,7 +418,7 @@ int Color::find_named_color(const String &p_name) { } int Color::get_named_color_count() { - return sizeof(named_colors) / sizeof(NamedColor); + return std_size(named_colors); } String Color::get_named_color_name(int p_idx) { @@ -476,102 +469,4 @@ Color::operator String() const { return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")"; } -Color Color::operator+(const Color &p_color) const { - return Color( - r + p_color.r, - g + p_color.g, - b + p_color.b, - a + p_color.a); -} - -void Color::operator+=(const Color &p_color) { - r = r + p_color.r; - g = g + p_color.g; - b = b + p_color.b; - a = a + p_color.a; -} - -Color Color::operator-(const Color &p_color) const { - return Color( - r - p_color.r, - g - p_color.g, - b - p_color.b, - a - p_color.a); -} - -void Color::operator-=(const Color &p_color) { - r = r - p_color.r; - g = g - p_color.g; - b = b - p_color.b; - a = a - p_color.a; -} - -Color Color::operator*(const Color &p_color) const { - return Color( - r * p_color.r, - g * p_color.g, - b * p_color.b, - a * p_color.a); -} - -Color Color::operator*(float p_scalar) const { - return Color( - r * p_scalar, - g * p_scalar, - b * p_scalar, - a * p_scalar); -} - -void Color::operator*=(const Color &p_color) { - r = r * p_color.r; - g = g * p_color.g; - b = b * p_color.b; - a = a * p_color.a; -} - -void Color::operator*=(float p_scalar) { - r = r * p_scalar; - g = g * p_scalar; - b = b * p_scalar; - a = a * p_scalar; -} - -Color Color::operator/(const Color &p_color) const { - return Color( - r / p_color.r, - g / p_color.g, - b / p_color.b, - a / p_color.a); -} - -Color Color::operator/(float p_scalar) const { - return Color( - r / p_scalar, - g / p_scalar, - b / p_scalar, - a / p_scalar); -} - -void Color::operator/=(const Color &p_color) { - r = r / p_color.r; - g = g / p_color.g; - b = b / p_color.b; - a = a / p_color.a; -} - -void Color::operator/=(float p_scalar) { - r = r / p_scalar; - g = g / p_scalar; - b = b / p_scalar; - a = a / p_scalar; -} - -Color Color::operator-() const { - return Color( - 1.0f - r, - 1.0f - g, - 1.0f - b, - 1.0f - a); -} - } // namespace godot diff --git a/src/variant/plane.cpp b/src/variant/plane.cpp index 9b72c7af2..ee852467f 100644 --- a/src/variant/plane.cpp +++ b/src/variant/plane.cpp @@ -40,9 +40,15 @@ void Plane::set_normal(const Vector3 &p_normal) { } void Plane::normalize() { +#ifdef MATH_CHECKS + if (!is_finite()) { + WARN_PRINT("Plane cannot be normalized, the distance and the normal should be finite."); + } +#endif // MATH_CHECKS + real_t l = normal.length(); if (l == 0) { - *this = Plane(0, 0, 0, 0); + zero(); return; } normal /= l; @@ -174,6 +180,10 @@ bool Plane::is_equal_approx(const Plane &p_plane) const { return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d); } +bool Plane::is_same(const Plane &p_plane) const { + return normal.is_same(p_plane.normal) && Math::is_same(d, p_plane.d); +} + bool Plane::is_finite() const { return normal.is_finite() && Math::is_finite(d); } diff --git a/src/variant/projection.cpp b/src/variant/projection.cpp index d8e35d441..34a4563b1 100644 --- a/src/variant/projection.cpp +++ b/src/variant/projection.cpp @@ -284,7 +284,7 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t real_t left, right, modeltranslation, ymax, xmax, frustumshift; - ymax = p_z_near * tan(Math::deg_to_rad(p_fovy_degrees / 2.0)); + ymax = p_z_near * std::tan(Math::deg_to_rad(p_fovy_degrees / 2.0)); xmax = ymax * p_aspect; frustumshift = (p_intraocular_dist / 2.0) * p_z_near / p_convergence_dist; @@ -404,82 +404,35 @@ void Projection::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, r } real_t Projection::get_z_far() const { - const real_t *matrix = (const real_t *)columns; - Plane new_plane = Plane(matrix[3] - matrix[2], - matrix[7] - matrix[6], - matrix[11] - matrix[10], - matrix[15] - matrix[14]); - - new_plane.normalize(); - - return new_plane.d; + // NOTE: This assumes z-facing near and far planes, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - near and far planes are z-facing (i.e. columns[0][2] and [1][2] == 0) + return (columns[3][3] - columns[3][2]) / (columns[2][3] - columns[2][2]); } real_t Projection::get_z_near() const { - const real_t *matrix = (const real_t *)columns; - Plane new_plane = Plane(matrix[3] + matrix[2], - matrix[7] + matrix[6], - matrix[11] + matrix[10], - -matrix[15] - matrix[14]); - - new_plane.normalize(); - return new_plane.d; + // NOTE: This assumes z-facing near and far planes, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - near and far planes are z-facing (i.e. columns[0][2] and [1][2] == 0) + return (columns[3][3] + columns[3][2]) / (columns[2][3] + columns[2][2]); } Vector2 Projection::get_viewport_half_extents() const { - const real_t *matrix = (const real_t *)columns; - ///////--- Near Plane ---/////// - Plane near_plane = Plane(matrix[3] + matrix[2], - matrix[7] + matrix[6], - matrix[11] + matrix[10], - -matrix[15] - matrix[14]); - near_plane.normalize(); - - ///////--- Right Plane ---/////// - Plane right_plane = Plane(matrix[3] - matrix[0], - matrix[7] - matrix[4], - matrix[11] - matrix[8], - -matrix[15] + matrix[12]); - right_plane.normalize(); - - Plane top_plane = Plane(matrix[3] - matrix[1], - matrix[7] - matrix[5], - matrix[11] - matrix[9], - -matrix[15] + matrix[13]); - top_plane.normalize(); - - Vector3 res; - near_plane.intersect_3(right_plane, top_plane, &res); - - return Vector2(res.x, res.y); + // NOTE: This assumes a symmetrical frustum, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + // - there is no offset / skew (i.e. columns[2][0] == columns[2][1] == 0) + real_t w = -get_z_near() * columns[2][3] + columns[3][3]; + return Vector2(w / columns[0][0], w / columns[1][1]); } Vector2 Projection::get_far_plane_half_extents() const { - const real_t *matrix = (const real_t *)columns; - ///////--- Far Plane ---/////// - Plane far_plane = Plane(matrix[3] - matrix[2], - matrix[7] - matrix[6], - matrix[11] - matrix[10], - -matrix[15] + matrix[14]); - far_plane.normalize(); - - ///////--- Right Plane ---/////// - Plane right_plane = Plane(matrix[3] - matrix[0], - matrix[7] - matrix[4], - matrix[11] - matrix[8], - -matrix[15] + matrix[12]); - right_plane.normalize(); - - Plane top_plane = Plane(matrix[3] - matrix[1], - matrix[7] - matrix[5], - matrix[11] - matrix[9], - -matrix[15] + matrix[13]); - top_plane.normalize(); - - Vector3 res; - far_plane.intersect_3(right_plane, top_plane, &res); - - return Vector2(res.x, res.y); + // NOTE: This assumes a symmetrical frustum, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + // - there is no offset / skew (i.e. columns[2][0] == columns[2][1] == 0) + real_t w = -get_z_far() * columns[2][3] + columns[3][3]; + return Vector2(w / columns[0][0], w / columns[1][1]); } bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const { @@ -829,24 +782,8 @@ void Projection::flip_y() { } } -Projection::Projection() { - set_identity(); -} - -Projection Projection::operator*(const Projection &p_matrix) const { - Projection new_matrix; - - for (int j = 0; j < 4; j++) { - for (int i = 0; i < 4; i++) { - real_t ab = 0; - for (int k = 0; k < 4; k++) { - ab += columns[k][i] * p_matrix.columns[j][k]; - } - new_matrix.columns[j][i] = ab; - } - } - - return new_matrix; +bool Projection::is_same(const Projection &p_cam) const { + return columns[0].is_same(p_cam.columns[0]) && columns[1].is_same(p_cam.columns[1]) && columns[2].is_same(p_cam.columns[2]) && columns[3].is_same(p_cam.columns[3]); } void Projection::set_depth_correction(bool p_flip_y, bool p_reverse_z, bool p_remap_z) { @@ -921,53 +858,45 @@ Projection::operator String() const { } real_t Projection::get_aspect() const { - Vector2 vp_he = get_viewport_half_extents(); - return vp_he.x / vp_he.y; + // NOTE: This assumes a rectangular projection plane, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + return columns[1][1] / columns[0][0]; } int Projection::get_pixels_per_meter(int p_for_pixel_width) const { - Vector3 result = xform(Vector3(1, 0, -1)); - - return int((result.x * 0.5 + 0.5) * p_for_pixel_width); + // NOTE: This assumes a rectangular projection plane, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + real_t width = 2 * (-get_z_near() * columns[2][3] + columns[3][3]) / columns[0][0]; + return p_for_pixel_width / width; // Note : return type should be real_t (kept as int for compatibility for now). } bool Projection::is_orthogonal() const { - return columns[3][3] == 1.0; + // NOTE: This assumes that the matrix is a projection across z-axis + // i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0 + return columns[2][3] == 0.0; } real_t Projection::get_fov() const { - const real_t *matrix = (const real_t *)columns; - - Plane right_plane = Plane(matrix[3] - matrix[0], - matrix[7] - matrix[4], - matrix[11] - matrix[8], - -matrix[15] + matrix[12]); - right_plane.normalize(); - - if ((matrix[8] == 0) && (matrix[9] == 0)) { - return Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0; + // NOTE: This assumes a rectangular projection plane, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + if (columns[2][0] == 0) { + return Math::rad_to_deg(2 * Math::atan2(1, columns[0][0])); } else { - // our frustum is asymmetrical need to calculate the left planes angle separately.. - Plane left_plane = Plane(matrix[3] + matrix[0], - matrix[7] + matrix[4], - matrix[11] + matrix[8], - matrix[15] + matrix[12]); - left_plane.normalize(); - - return Math::rad_to_deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x))); + // The frustum is asymmetrical so we need to calculate the left and right angles separately. + real_t right = Math::atan2(columns[2][0] + 1, columns[0][0]); + real_t left = Math::atan2(columns[2][0] - 1, columns[0][0]); + return Math::rad_to_deg(right - left); } } real_t Projection::get_lod_multiplier() const { - if (is_orthogonal()) { - return get_viewport_half_extents().x; - } else { - const real_t zn = get_z_near(); - const real_t width = get_viewport_half_extents().x * 2.0f; - return 1.0f / (zn / width); - } - - // Usage is lod_size / (lod_distance * multiplier) < threshold + // NOTE: This assumes a rectangular projection plane, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + return 2 / columns[0][0]; } void Projection::make_scale(const Vector3 &p_scale) { @@ -1030,20 +959,6 @@ Projection::operator Transform3D() const { return tr; } -Projection::Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w) { - columns[0] = p_x; - columns[1] = p_y; - columns[2] = p_z; - columns[3] = p_w; -} - -Projection::Projection(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_xw, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_yw, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_zw, real_t p_wx, real_t p_wy, real_t p_wz, real_t p_ww) { - columns[0] = Vector4(p_xx, p_xy, p_xz, p_xw); - columns[1] = Vector4(p_yx, p_yy, p_yz, p_yw); - columns[2] = Vector4(p_zx, p_zy, p_zz, p_zw); - columns[3] = Vector4(p_wx, p_wy, p_wz, p_ww); -} - Projection::Projection(const Transform3D &p_transform) { const Transform3D &tr = p_transform; real_t *m = &columns[0][0]; @@ -1066,7 +981,4 @@ Projection::Projection(const Transform3D &p_transform) { m[15] = 1.0; } -Projection::~Projection() { -} - } // namespace godot diff --git a/src/variant/quaternion.cpp b/src/variant/quaternion.cpp index 572daa9b9..24ad830d1 100644 --- a/src/variant/quaternion.cpp +++ b/src/variant/quaternion.cpp @@ -48,26 +48,14 @@ Vector3 Quaternion::get_euler(EulerOrder p_order) const { return Basis(*this).get_euler(p_order); } -void Quaternion::operator*=(const Quaternion &p_q) { - real_t xx = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y; - real_t yy = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z; - real_t zz = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x; - w = w * p_q.w - x * p_q.x - y * p_q.y - z * p_q.z; - x = xx; - y = yy; - z = zz; -} - -Quaternion Quaternion::operator*(const Quaternion &p_q) const { - Quaternion r = *this; - r *= p_q; - return r; -} - bool Quaternion::is_equal_approx(const Quaternion &p_quaternion) const { return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.w); } +bool Quaternion::is_same(const Quaternion &p_quaternion) const { + return Math::is_same(x, p_quaternion.x) && Math::is_same(y, p_quaternion.y) && Math::is_same(z, p_quaternion.z) && Math::is_same(w, p_quaternion.w); +} + bool Quaternion::is_finite() const { return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w); } @@ -77,6 +65,11 @@ real_t Quaternion::length() const { } void Quaternion::normalize() { +#ifdef MATH_CHECKS + if (!is_finite()) { + WARN_PRINT("Quaternion cannot be normalized, the elements should be finite."); + } +#endif // MATH_CHECKS *this /= length(); } diff --git a/src/variant/rect2.cpp b/src/variant/rect2.cpp index 7192a7111..d64b4d55b 100644 --- a/src/variant/rect2.cpp +++ b/src/variant/rect2.cpp @@ -40,6 +40,10 @@ 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); } +bool Rect2::is_same(const Rect2 &p_rect) const { + return position.is_same(p_rect.position) && size.is_same(p_rect.size); +} + bool Rect2::is_finite() const { return position.is_finite() && size.is_finite(); } @@ -284,6 +288,122 @@ bool Rect2::intersects_transformed(const Transform2D &p_xform, const Rect2 &p_re return true; } +Rect2 Rect2::intersection_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) { + ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size."); + } +#endif + + if ((Math::is_zero_approx(p_xform.columns[0].y) && Math::is_zero_approx(p_xform.columns[1].x)) || + (Math::is_zero_approx(p_xform.columns[0].x) && Math::is_zero_approx(p_xform.columns[1].y))) { + return intersection(p_xform.xform(p_rect)); + } + + if (!intersects_transformed(p_xform, p_rect)) { + return Rect2(); + } + + const Vector2 xf_points[4] = { + p_xform.xform(p_rect.position), + p_xform.xform(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y)), + p_xform.xform(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y + p_rect.size.y)), + p_xform.xform(Vector2(p_rect.position.x, p_rect.position.y + p_rect.size.y)), + }; + + // Use Sutherland–Hodgman algorithm. + + Vector2 subject[8]; + int subject_count = 4; + subject[0] = xf_points[0]; + subject[1] = xf_points[1]; + subject[2] = xf_points[2]; + subject[3] = xf_points[3]; + + const Vector2 min = position; + const Vector2 max = position + size; + Vector2 intersected; + + for (int edge = 0; edge < 4; edge++) { + const int axis = edge % 2; + const int another_axis = 1 - axis; + const bool is_min = (edge < 2); + intersected[axis] = is_min ? min[axis] : max[axis]; + + Vector2 output[8]; + int output_count = 0; + + Vector2 prev = subject[subject_count - 1]; + bool prev_in_halfplane = is_min ? (prev[axis] >= intersected[axis]) : (prev[axis] <= intersected[axis]); + + for (int i = 0; i < subject_count; i++) { + const Vector2 &curr = subject[i]; + bool curr_in_halfplane = is_min ? (curr[axis] >= intersected[axis]) : (curr[axis] <= intersected[axis]); + if (prev_in_halfplane != curr_in_halfplane) { + // Entering/exiting the half-plane. + real_t t = (intersected[axis] - prev[axis]) / (curr[axis] - prev[axis]); + intersected[another_axis] = prev[another_axis] + (curr[another_axis] - prev[another_axis]) * t; + output[output_count++] = intersected; + } + if (curr_in_halfplane) { + output[output_count++] = curr; + } + prev = curr; + prev_in_halfplane = curr_in_halfplane; + } + + for (int i = 0; i < output_count; i++) { + subject[i] = output[i]; + } + + subject_count = output_count; + if (subject_count == 0) { + break; + } + } + + if (subject_count > 0) { + return Rect2::from_points(subject, subject_count); + } + + // Perform a reverse containment test; the current rect may be inside the transformed rect. + + const Vector2 corners[4] = { + position, + Vector2(max.x, min.y), + max, + Vector2(min.x, max.y) + }; + + Vector2 inside_points[4]; + int inside_count = 0; + + for (int point_idx = 0; point_idx < 4; point_idx++) { + bool has_pos = false; + bool has_neg = false; + for (int idx = 0; idx < 4; idx++) { + const int next_idx = (idx + 1) % 4; + Vector2 v0 = xf_points[next_idx] - xf_points[idx]; + Vector2 v1 = corners[point_idx] - xf_points[idx]; + real_t cross = v0.cross(v1); + if (cross > CMP_EPSILON) { + has_pos = true; + } + if (cross < -CMP_EPSILON) { + has_neg = true; + } + if (has_pos && has_neg) { + break; + } + } + if (!(has_pos && has_neg)) { + inside_points[inside_count++] = corners[point_idx]; + } + } + + return inside_count > 0 ? Rect2::from_points(inside_points, inside_count) : Rect2(); +} + Rect2::operator String() const { return "[P: " + position.operator String() + ", S: " + size.operator String() + "]"; } diff --git a/src/variant/rect2i.cpp b/src/variant/rect2i.cpp index 3ea7147d8..68399ba37 100644 --- a/src/variant/rect2i.cpp +++ b/src/variant/rect2i.cpp @@ -36,7 +36,7 @@ namespace godot { Rect2i::operator String() const { - return "[P: " + position.operator String() + ", S: " + size + "]"; + return "[P: " + String(position) + ", S: " + String(size) + "]"; } Rect2i::operator Rect2() const { diff --git a/src/variant/transform2d.cpp b/src/variant/transform2d.cpp index be2eced6a..7be38c348 100644 --- a/src/variant/transform2d.cpp +++ b/src/variant/transform2d.cpp @@ -147,7 +147,8 @@ void Transform2D::translate_local(const Vector2 &p_translation) { } void Transform2D::orthonormalize() { - // Gram-Schmidt Process + // Orthonormalizable check is done in Vector2 class below. + // Gram-Schmidt Process: Vector2 x = columns[0]; Vector2 y = columns[1]; @@ -182,6 +183,10 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const { return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]); } +bool Transform2D::is_same(const Transform2D &p_transform) const { + return columns[0].is_same(p_transform.columns[0]) && columns[1].is_same(p_transform.columns[1]) && columns[2].is_same(p_transform.columns[2]); +} + bool Transform2D::is_finite() const { return columns[0].is_finite() && columns[1].is_finite() && columns[2].is_finite(); } @@ -193,26 +198,6 @@ Transform2D Transform2D::looking_at(const Vector2 &p_target) const { return return_trans; } -bool Transform2D::operator==(const Transform2D &p_transform) const { - for (int i = 0; i < 3; i++) { - if (columns[i] != p_transform.columns[i]) { - return false; - } - } - - return true; -} - -bool Transform2D::operator!=(const Transform2D &p_transform) const { - for (int i = 0; i < 3; i++) { - if (columns[i] != p_transform.columns[i]) { - return true; - } - } - - return false; -} - void Transform2D::operator*=(const Transform2D &p_transform) { columns[2] = xform(p_transform.columns[2]); @@ -285,30 +270,6 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t get_origin().lerp(p_transform.get_origin(), p_weight)); } -void Transform2D::operator*=(real_t p_val) { - columns[0] *= p_val; - columns[1] *= p_val; - columns[2] *= p_val; -} - -Transform2D Transform2D::operator*(real_t p_val) const { - Transform2D ret(*this); - ret *= p_val; - return ret; -} - -void Transform2D::operator/=(real_t p_val) { - columns[0] /= p_val; - columns[1] /= p_val; - columns[2] /= p_val; -} - -Transform2D Transform2D::operator/(real_t p_val) const { - Transform2D ret(*this); - ret /= p_val; - return ret; -} - Transform2D::operator String() const { return "[X: " + columns[0].operator String() + ", Y: " + columns[1].operator String() + diff --git a/src/variant/transform3d.cpp b/src/variant/transform3d.cpp index 765bc62e7..b3e8499bd 100644 --- a/src/variant/transform3d.cpp +++ b/src/variant/transform3d.cpp @@ -152,6 +152,7 @@ Transform3D Transform3D::translated_local(const Vector3 &p_translation) const { } void Transform3D::orthonormalize() { + // Orthonormalizable check is done in Basis class below. basis.orthonormalize(); } @@ -175,16 +176,12 @@ bool Transform3D::is_equal_approx(const Transform3D &p_transform) const { return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin); } -bool Transform3D::is_finite() const { - return basis.is_finite() && origin.is_finite(); -} - -bool Transform3D::operator==(const Transform3D &p_transform) const { - return (basis == p_transform.basis && origin == p_transform.origin); +bool Transform3D::is_same(const Transform3D &p_transform) const { + return basis.is_same(p_transform.basis) && origin.is_same(p_transform.origin); } -bool Transform3D::operator!=(const Transform3D &p_transform) const { - return (basis != p_transform.basis || origin != p_transform.origin); +bool Transform3D::is_finite() const { + return basis.is_finite() && origin.is_finite(); } void Transform3D::operator*=(const Transform3D &p_transform) { @@ -198,28 +195,6 @@ Transform3D Transform3D::operator*(const Transform3D &p_transform) const { return t; } -void Transform3D::operator*=(real_t p_val) { - origin *= p_val; - basis *= p_val; -} - -Transform3D Transform3D::operator*(real_t p_val) const { - Transform3D ret(*this); - ret *= p_val; - return ret; -} - -void Transform3D::operator/=(real_t p_val) { - basis /= p_val; - origin /= p_val; -} - -Transform3D Transform3D::operator/(real_t p_val) const { - Transform3D ret(*this); - ret /= p_val; - return ret; -} - Transform3D::operator String() const { return "[X: " + basis.get_column(0).operator String() + ", Y: " + basis.get_column(1).operator String() + @@ -227,21 +202,4 @@ Transform3D::operator String() const { ", O: " + origin.operator String() + "]"; } -Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) : - basis(p_basis), - origin(p_origin) { -} - -Transform3D::Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : - origin(p_origin) { - basis.set_column(0, p_x); - basis.set_column(1, p_y); - basis.set_column(2, p_z); -} - -Transform3D::Transform3D(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_ox, real_t p_oy, real_t p_oz) { - basis = Basis(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz); - origin = Vector3(p_ox, p_oy, p_oz); -} - } // namespace godot diff --git a/src/variant/vector2.cpp b/src/variant/vector2.cpp index cb190db12..4e1216381 100644 --- a/src/variant/vector2.cpp +++ b/src/variant/vector2.cpp @@ -52,8 +52,18 @@ real_t Vector2::length_squared() const { } void Vector2::normalize() { - real_t l = x * x + y * y; - if (l != 0) { + if (!is_finite()) { +#ifdef MATH_CHECKS + WARN_PRINT("Vector2 cannot be normalized, the elements must be finite. Making (0, 0) as a fallback."); +#endif // MATH_CHECKS + zero(); + return; + } + + real_t l = length_squared(); + if (l == 0) { + zero(); + } else { l = Math::sqrt(l); x /= l; y /= l; @@ -196,6 +206,10 @@ bool Vector2::is_equal_approx(const Vector2 &p_v) const { return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y); } +bool Vector2::is_same(const Vector2 &p_v) const { + return Math::is_same(x, p_v.x) && Math::is_same(y, p_v.y); +} + bool Vector2::is_zero_approx() const { return Math::is_zero_approx(x) && Math::is_zero_approx(y); } diff --git a/src/variant/vector2i.cpp b/src/variant/vector2i.cpp index d39cb7b4e..dc2119c15 100644 --- a/src/variant/vector2i.cpp +++ b/src/variant/vector2i.cpp @@ -67,75 +67,6 @@ double Vector2i::length() const { return Math::sqrt((double)length_squared()); } -Vector2i Vector2i::operator+(const Vector2i &p_v) const { - return Vector2i(x + p_v.x, y + p_v.y); -} - -void Vector2i::operator+=(const Vector2i &p_v) { - x += p_v.x; - y += p_v.y; -} - -Vector2i Vector2i::operator-(const Vector2i &p_v) const { - return Vector2i(x - p_v.x, y - p_v.y); -} - -void Vector2i::operator-=(const Vector2i &p_v) { - x -= p_v.x; - y -= p_v.y; -} - -Vector2i Vector2i::operator*(const Vector2i &p_v1) const { - return Vector2i(x * p_v1.x, y * p_v1.y); -} - -Vector2i Vector2i::operator*(int32_t p_rvalue) const { - return Vector2i(x * p_rvalue, y * p_rvalue); -} - -void Vector2i::operator*=(int32_t p_rvalue) { - x *= p_rvalue; - y *= p_rvalue; -} - -Vector2i Vector2i::operator/(const Vector2i &p_v1) const { - return Vector2i(x / p_v1.x, y / p_v1.y); -} - -Vector2i Vector2i::operator/(int32_t p_rvalue) const { - return Vector2i(x / p_rvalue, y / p_rvalue); -} - -void Vector2i::operator/=(int32_t p_rvalue) { - x /= p_rvalue; - y /= p_rvalue; -} - -Vector2i Vector2i::operator%(const Vector2i &p_v1) const { - return Vector2i(x % p_v1.x, y % p_v1.y); -} - -Vector2i Vector2i::operator%(int32_t p_rvalue) const { - return Vector2i(x % p_rvalue, y % p_rvalue); -} - -void Vector2i::operator%=(int32_t p_rvalue) { - x %= p_rvalue; - y %= p_rvalue; -} - -Vector2i Vector2i::operator-() const { - return Vector2i(-x, -y); -} - -bool Vector2i::operator==(const Vector2i &p_vec2) const { - return x == p_vec2.x && y == p_vec2.y; -} - -bool Vector2i::operator!=(const Vector2i &p_vec2) const { - return x != p_vec2.x || y != p_vec2.y; -} - Vector2i::operator String() const { return "(" + itos(x) + ", " + itos(y) + ")"; } diff --git a/src/variant/vector3.cpp b/src/variant/vector3.cpp index fe42c189d..908c78c30 100644 --- a/src/variant/vector3.cpp +++ b/src/variant/vector3.cpp @@ -47,20 +47,6 @@ Vector3 Vector3::rotated(const Vector3 &p_axis, real_t p_angle) const { return r; } -Vector3 Vector3::clamp(const Vector3 &p_min, const Vector3 &p_max) const { - return Vector3( - CLAMP(x, p_min.x, p_max.x), - CLAMP(y, p_min.y, p_max.y), - CLAMP(z, p_min.z, p_max.z)); -} - -Vector3 Vector3::clampf(real_t p_min, real_t p_max) const { - return Vector3( - CLAMP(x, p_min, p_max), - CLAMP(y, p_min, p_max), - CLAMP(z, p_min, p_max)); -} - void Vector3::snap(const Vector3 &p_step) { x = Math::snapped(x, p_step.x); y = Math::snapped(y, p_step.y); @@ -158,6 +144,10 @@ bool Vector3::is_equal_approx(const Vector3 &p_v) const { return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z); } +bool Vector3::is_same(const Vector3 &p_v) const { + return Math::is_same(x, p_v.x) && Math::is_same(y, p_v.y) && Math::is_same(z, p_v.z); +} + bool Vector3::is_zero_approx() const { return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z); } diff --git a/src/variant/vector4.cpp b/src/variant/vector4.cpp index 9b58c9400..90470de99 100644 --- a/src/variant/vector4.cpp +++ b/src/variant/vector4.cpp @@ -63,6 +63,10 @@ bool Vector4::is_equal_approx(const Vector4 &p_vec4) const { return Math::is_equal_approx(x, p_vec4.x) && Math::is_equal_approx(y, p_vec4.y) && Math::is_equal_approx(z, p_vec4.z) && Math::is_equal_approx(w, p_vec4.w); } +bool Vector4::is_same(const Vector4 &p_vec4) const { + return Math::is_same(x, p_vec4.x) && Math::is_same(y, p_vec4.y) && Math::is_same(z, p_vec4.z) && Math::is_same(w, p_vec4.w); +} + bool Vector4::is_zero_approx() const { return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w); } @@ -76,15 +80,23 @@ real_t Vector4::length() const { } void Vector4::normalize() { - real_t lengthsq = length_squared(); - if (lengthsq == 0) { - x = y = z = w = 0; + if (!is_finite()) { +#ifdef MATH_CHECKS + WARN_PRINT("Vector4 cannot be normalized, the elements must be finite. Making (0, 0, 0, 0) as a fallback."); +#endif // MATH_CHECKS + zero(); + return; + } + + real_t l = length_squared(); + if (l == 0) { + zero(); } else { - real_t length = Math::sqrt(lengthsq); - x /= length; - y /= length; - z /= length; - w /= length; + l = Math::sqrt(l); + x /= l; + y /= l; + z /= l; + w /= l; } } diff --git a/src/variant/vector4i.cpp b/src/variant/vector4i.cpp index d138610d9..b1ddfbb7c 100644 --- a/src/variant/vector4i.cpp +++ b/src/variant/vector4i.cpp @@ -99,13 +99,5 @@ Vector4i::operator Vector4() const { return Vector4(x, y, z, w); } -Vector4i::Vector4i(const Vector4 &p_vec4) { - x = (int32_t)p_vec4.x; - y = (int32_t)p_vec4.y; - z = (int32_t)p_vec4.z; - w = (int32_t)p_vec4.w; -} - static_assert(sizeof(Vector4i) == 4 * sizeof(int32_t)); - } // namespace godot