diff options
Diffstat (limited to 'core/math')
50 files changed, 993 insertions, 736 deletions
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index b380860522..bdceae4374 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -47,8 +47,8 @@ int AStar::get_available_point_id() const { } void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) { - ERR_FAIL_COND(p_id < 0); - ERR_FAIL_COND(p_weight_scale < 1); + ERR_FAIL_COND_MSG(p_id < 0, vformat("Can't add a point with negative id: %d.", p_id)); + ERR_FAIL_COND_MSG(p_weight_scale < 1, vformat("Can't add a point with weight scale less than one: %f.", p_weight_scale)); Point *found_pt; bool p_exists = points.lookup(p_id, found_pt); @@ -72,7 +72,7 @@ void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) { Vector3 AStar::get_point_position(int p_id) const { Point *p; bool p_exists = points.lookup(p_id, p); - ERR_FAIL_COND_V(!p_exists, Vector3()); + ERR_FAIL_COND_V_MSG(!p_exists, Vector3(), vformat("Can't get point's position. Point with id: %d doesn't exist.", p_id)); return p->pos; } @@ -80,7 +80,7 @@ Vector3 AStar::get_point_position(int p_id) const { void AStar::set_point_position(int p_id, const Vector3 &p_pos) { Point *p; bool p_exists = points.lookup(p_id, p); - ERR_FAIL_COND(!p_exists); + ERR_FAIL_COND_MSG(!p_exists, vformat("Can't set point's position. Point with id: %d doesn't exist.", p_id)); p->pos = p_pos; } @@ -88,7 +88,7 @@ void AStar::set_point_position(int p_id, const Vector3 &p_pos) { real_t AStar::get_point_weight_scale(int p_id) const { Point *p; bool p_exists = points.lookup(p_id, p); - ERR_FAIL_COND_V(!p_exists, 0); + ERR_FAIL_COND_V_MSG(!p_exists, 0, vformat("Can't get point's weight scale. Point with id: %d doesn't exist.", p_id)); return p->weight_scale; } @@ -96,8 +96,8 @@ real_t AStar::get_point_weight_scale(int p_id) const { void AStar::set_point_weight_scale(int p_id, real_t p_weight_scale) { Point *p; bool p_exists = points.lookup(p_id, p); - ERR_FAIL_COND(!p_exists); - ERR_FAIL_COND(p_weight_scale < 1); + ERR_FAIL_COND_MSG(!p_exists, vformat("Can't set point's weight scale. Point with id: %d doesn't exist.", p_id)); + ERR_FAIL_COND_MSG(p_weight_scale < 1, vformat("Can't set point's weight scale less than one: %f.", p_weight_scale)); p->weight_scale = p_weight_scale; } @@ -105,7 +105,7 @@ void AStar::set_point_weight_scale(int p_id, real_t p_weight_scale) { void AStar::remove_point(int p_id) { Point *p; bool p_exists = points.lookup(p_id, p); - ERR_FAIL_COND(!p_exists); + ERR_FAIL_COND_MSG(!p_exists, vformat("Can't remove point. Point with id: %d doesn't exist.", p_id)); for (OAHashMap<int, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { Segment s(p_id, (*it.key)); @@ -129,15 +129,15 @@ void AStar::remove_point(int p_id) { } void AStar::connect_points(int p_id, int p_with_id, bool bidirectional) { - ERR_FAIL_COND(p_id == p_with_id); + ERR_FAIL_COND_MSG(p_id == p_with_id, vformat("Can't connect point with id: %d to itself.", p_id)); Point *a; bool from_exists = points.lookup(p_id, a); - ERR_FAIL_COND(!from_exists); + ERR_FAIL_COND_MSG(!from_exists, vformat("Can't connect points. Point with id: %d doesn't exist.", p_id)); Point *b; bool to_exists = points.lookup(p_with_id, b); - ERR_FAIL_COND(!to_exists); + ERR_FAIL_COND_MSG(!to_exists, vformat("Can't connect points. Point with id: %d doesn't exist.", p_with_id)); a->neighbours.set(b->id, b); @@ -169,11 +169,11 @@ void AStar::connect_points(int p_id, int p_with_id, bool bidirectional) { void AStar::disconnect_points(int p_id, int p_with_id, bool bidirectional) { Point *a; bool a_exists = points.lookup(p_id, a); - ERR_FAIL_COND(!a_exists); + ERR_FAIL_COND_MSG(!a_exists, vformat("Can't disconnect points. Point with id: %d doesn't exist.", p_id)); Point *b; bool b_exists = points.lookup(p_with_id, b); - ERR_FAIL_COND(!b_exists); + ERR_FAIL_COND_MSG(!b_exists, vformat("Can't disconnect points. Point with id: %d doesn't exist.", p_with_id)); Segment s(p_id, p_with_id); int remove_direction = bidirectional ? (int)Segment::BIDIRECTIONAL : s.direction; @@ -210,7 +210,7 @@ bool AStar::has_point(int p_id) const { return points.has(p_id); } -Array AStar::get_points() { +Array AStar::get_point_ids() { Array point_list; for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { @@ -223,7 +223,7 @@ Array AStar::get_points() { Vector<int> AStar::get_point_connections(int p_id) { Point *p; bool p_exists = points.lookup(p_id, p); - ERR_FAIL_COND_V(!p_exists, Vector<int>()); + ERR_FAIL_COND_V_MSG(!p_exists, Vector<int>(), vformat("Can't get point's connections. Point with id: %d doesn't exist.", p_id)); Vector<int> point_list; @@ -239,7 +239,7 @@ bool AStar::are_points_connected(int p_id, int p_with_id, bool bidirectional) co const Set<Segment>::Element *element = segments.find(s); return element != nullptr && - (bidirectional || (element->get().direction & s.direction) == s.direction); + (bidirectional || (element->get().direction & s.direction) == s.direction); } void AStar::clear() { @@ -260,8 +260,8 @@ int AStar::get_point_capacity() const { } void AStar::reserve_space(int p_num_nodes) { - ERR_FAIL_COND_MSG(p_num_nodes <= 0, "New capacity must be greater than 0, was: " + itos(p_num_nodes) + "."); - ERR_FAIL_COND_MSG((uint32_t)p_num_nodes < points.get_capacity(), "New capacity must be greater than current capacity: " + itos(points.get_capacity()) + ", new was: " + itos(p_num_nodes) + "."); + ERR_FAIL_COND_MSG(p_num_nodes <= 0, vformat("New capacity must be greater than 0, new was: %d.", p_num_nodes)); + ERR_FAIL_COND_MSG((uint32_t)p_num_nodes < points.get_capacity(), vformat("New capacity must be greater than current capacity: %d, new was: %d.", points.get_capacity(), p_num_nodes)); points.reserve(p_num_nodes); } @@ -344,7 +344,7 @@ bool AStar::_solve(Point *begin_point, Point *end_point) { } sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list - open_list.remove(open_list.size() - 1); + open_list.remove_at(open_list.size() - 1); p->closed_pass = pass; // Mark the point as closed for (OAHashMap<int, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { @@ -389,11 +389,11 @@ real_t AStar::_estimate_cost(int p_from_id, int p_to_id) { Point *from_point; bool from_exists = points.lookup(p_from_id, from_point); - ERR_FAIL_COND_V(!from_exists, 0); + ERR_FAIL_COND_V_MSG(!from_exists, 0, vformat("Can't estimate cost. Point with id: %d doesn't exist.", p_from_id)); Point *to_point; bool to_exists = points.lookup(p_to_id, to_point); - ERR_FAIL_COND_V(!to_exists, 0); + ERR_FAIL_COND_V_MSG(!to_exists, 0, vformat("Can't estimate cost. Point with id: %d doesn't exist.", p_to_id)); return from_point->pos.distance_to(to_point->pos); } @@ -406,11 +406,11 @@ real_t AStar::_compute_cost(int p_from_id, int p_to_id) { Point *from_point; bool from_exists = points.lookup(p_from_id, from_point); - ERR_FAIL_COND_V(!from_exists, 0); + ERR_FAIL_COND_V_MSG(!from_exists, 0, vformat("Can't compute cost. Point with id: %d doesn't exist.", p_from_id)); Point *to_point; bool to_exists = points.lookup(p_to_id, to_point); - ERR_FAIL_COND_V(!to_exists, 0); + ERR_FAIL_COND_V_MSG(!to_exists, 0, vformat("Can't compute cost. Point with id: %d doesn't exist.", p_to_id)); return from_point->pos.distance_to(to_point->pos); } @@ -418,11 +418,11 @@ real_t AStar::_compute_cost(int p_from_id, int p_to_id) { Vector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) { Point *a; bool from_exists = points.lookup(p_from_id, a); - ERR_FAIL_COND_V(!from_exists, Vector<Vector3>()); + ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector3>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id)); Point *b; bool to_exists = points.lookup(p_to_id, b); - ERR_FAIL_COND_V(!to_exists, Vector<Vector3>()); + ERR_FAIL_COND_V_MSG(!to_exists, Vector<Vector3>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_to_id)); if (a == b) { Vector<Vector3> ret; @@ -467,11 +467,11 @@ Vector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) { Vector<int> AStar::get_id_path(int p_from_id, int p_to_id) { Point *a; bool from_exists = points.lookup(p_from_id, a); - ERR_FAIL_COND_V(!from_exists, Vector<int>()); + ERR_FAIL_COND_V_MSG(!from_exists, Vector<int>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id)); Point *b; bool to_exists = points.lookup(p_to_id, b); - ERR_FAIL_COND_V(!to_exists, Vector<int>()); + ERR_FAIL_COND_V_MSG(!to_exists, Vector<int>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_to_id)); if (a == b) { Vector<int> ret; @@ -516,7 +516,7 @@ Vector<int> AStar::get_id_path(int p_from_id, int p_to_id) { void AStar::set_point_disabled(int p_id, bool p_disabled) { Point *p; bool p_exists = points.lookup(p_id, p); - ERR_FAIL_COND(!p_exists); + ERR_FAIL_COND_MSG(!p_exists, vformat("Can't set if point is disabled. Point with id: %d doesn't exist.", p_id)); p->enabled = !p_disabled; } @@ -524,7 +524,7 @@ void AStar::set_point_disabled(int p_id, bool p_disabled) { bool AStar::is_point_disabled(int p_id) const { Point *p; bool p_exists = points.lookup(p_id, p); - ERR_FAIL_COND_V(!p_exists, false); + ERR_FAIL_COND_V_MSG(!p_exists, false, vformat("Can't get if point is disabled. Point with id: %d doesn't exist.", p_id)); return !p->enabled; } @@ -539,7 +539,7 @@ void AStar::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_point", "id"), &AStar::remove_point); ClassDB::bind_method(D_METHOD("has_point", "id"), &AStar::has_point); ClassDB::bind_method(D_METHOD("get_point_connections", "id"), &AStar::get_point_connections); - ClassDB::bind_method(D_METHOD("get_points"), &AStar::get_points); + ClassDB::bind_method(D_METHOD("get_point_ids"), &AStar::get_point_ids); ClassDB::bind_method(D_METHOD("set_point_disabled", "id", "disabled"), &AStar::set_point_disabled, DEFVAL(true)); ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar::is_point_disabled); @@ -606,8 +606,8 @@ Vector<int> AStar2D::get_point_connections(int p_id) { return astar.get_point_connections(p_id); } -Array AStar2D::get_points() { - return astar.get_points(); +Array AStar2D::get_point_ids() { + return astar.get_point_ids(); } void AStar2D::set_point_disabled(int p_id, bool p_disabled) { @@ -663,11 +663,11 @@ real_t AStar2D::_estimate_cost(int p_from_id, int p_to_id) { AStar::Point *from_point; bool from_exists = astar.points.lookup(p_from_id, from_point); - ERR_FAIL_COND_V(!from_exists, 0); + ERR_FAIL_COND_V_MSG(!from_exists, 0, vformat("Can't estimate cost. Point with id: %d doesn't exist.", p_from_id)); AStar::Point *to_point; bool to_exists = astar.points.lookup(p_to_id, to_point); - ERR_FAIL_COND_V(!to_exists, 0); + ERR_FAIL_COND_V_MSG(!to_exists, 0, vformat("Can't estimate cost. Point with id: %d doesn't exist.", p_to_id)); return from_point->pos.distance_to(to_point->pos); } @@ -680,11 +680,11 @@ real_t AStar2D::_compute_cost(int p_from_id, int p_to_id) { AStar::Point *from_point; bool from_exists = astar.points.lookup(p_from_id, from_point); - ERR_FAIL_COND_V(!from_exists, 0); + ERR_FAIL_COND_V_MSG(!from_exists, 0, vformat("Can't compute cost. Point with id: %d doesn't exist.", p_from_id)); AStar::Point *to_point; bool to_exists = astar.points.lookup(p_to_id, to_point); - ERR_FAIL_COND_V(!to_exists, 0); + ERR_FAIL_COND_V_MSG(!to_exists, 0, vformat("Can't compute cost. Point with id: %d doesn't exist.", p_to_id)); return from_point->pos.distance_to(to_point->pos); } @@ -692,11 +692,11 @@ real_t AStar2D::_compute_cost(int p_from_id, int p_to_id) { Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) { AStar::Point *a; bool from_exists = astar.points.lookup(p_from_id, a); - ERR_FAIL_COND_V(!from_exists, Vector<Vector2>()); + ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector2>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id)); AStar::Point *b; bool to_exists = astar.points.lookup(p_to_id, b); - ERR_FAIL_COND_V(!to_exists, Vector<Vector2>()); + ERR_FAIL_COND_V_MSG(!to_exists, Vector<Vector2>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_to_id)); if (a == b) { Vector<Vector2> ret; @@ -741,11 +741,11 @@ Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) { Vector<int> AStar2D::get_id_path(int p_from_id, int p_to_id) { AStar::Point *a; bool from_exists = astar.points.lookup(p_from_id, a); - ERR_FAIL_COND_V(!from_exists, Vector<int>()); + ERR_FAIL_COND_V_MSG(!from_exists, Vector<int>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id)); AStar::Point *b; bool to_exists = astar.points.lookup(p_to_id, b); - ERR_FAIL_COND_V(!to_exists, Vector<int>()); + ERR_FAIL_COND_V_MSG(!to_exists, Vector<int>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_to_id)); if (a == b) { Vector<int> ret; @@ -812,7 +812,7 @@ bool AStar2D::_solve(AStar::Point *begin_point, AStar::Point *end_point) { } sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list - open_list.remove(open_list.size() - 1); + open_list.remove_at(open_list.size() - 1); p->closed_pass = astar.pass; // Mark the point as closed for (OAHashMap<int, AStar::Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { @@ -859,7 +859,7 @@ void AStar2D::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_point", "id"), &AStar2D::remove_point); ClassDB::bind_method(D_METHOD("has_point", "id"), &AStar2D::has_point); ClassDB::bind_method(D_METHOD("get_point_connections", "id"), &AStar2D::get_point_connections); - ClassDB::bind_method(D_METHOD("get_points"), &AStar2D::get_points); + ClassDB::bind_method(D_METHOD("get_point_ids"), &AStar2D::get_point_ids); ClassDB::bind_method(D_METHOD("set_point_disabled", "id", "disabled"), &AStar2D::set_point_disabled, DEFVAL(true)); ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar2D::is_point_disabled); diff --git a/core/math/a_star.h b/core/math/a_star.h index 64fa32a325..ef6f22d228 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -138,7 +138,7 @@ public: void remove_point(int p_id); bool has_point(int p_id) const; Vector<int> get_point_connections(int p_id); - Array get_points(); + Array get_point_ids(); void set_point_disabled(int p_id, bool p_disabled = true); bool is_point_disabled(int p_id) const; @@ -188,7 +188,7 @@ public: void remove_point(int p_id); bool has_point(int p_id) const; Vector<int> get_point_connections(int p_id); - Array get_points(); + Array get_point_ids(); void set_point_disabled(int p_id, bool p_disabled = true); bool is_point_disabled(int p_id) const; diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp index 33aa65f15d..83726f46b5 100644 --- a/core/math/aabb.cpp +++ b/core/math/aabb.cpp @@ -33,7 +33,7 @@ #include "core/string/print_string.h" #include "core/variant/variant.h" -real_t AABB::get_area() const { +real_t AABB::get_volume() const { return size.x * size.y * size.z; } @@ -46,14 +46,19 @@ bool AABB::operator!=(const AABB &p_rval) const { } 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)) { + ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); + } +#endif Vector3 beg_1, beg_2; Vector3 end_1, end_2; Vector3 min, max; beg_1 = position; beg_2 = p_aabb.position; - end_1 = Vector3(size.x, size.y, size.z) + beg_1; - end_2 = Vector3(p_aabb.size.x, p_aabb.size.y, p_aabb.size.z) + beg_2; + end_1 = size + beg_1; + end_2 = p_aabb.size + beg_2; min.x = (beg_1.x < beg_2.x) ? beg_1.x : beg_2.x; min.y = (beg_1.y < beg_2.y) ? beg_1.y : beg_2.y; @@ -72,6 +77,11 @@ bool AABB::is_equal_approx(const AABB &p_aabb) const { } AABB AABB::intersection(const AABB &p_aabb) const { +#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)) { + ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); + } +#endif Vector3 src_min = position; Vector3 src_max = position + size; Vector3 dst_min = p_aabb.position; @@ -104,6 +114,11 @@ AABB AABB::intersection(const AABB &p_aabb) const { } bool AABB::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip, Vector3 *r_normal) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) { + ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); + } +#endif Vector3 c1, c2; Vector3 end = position + size; real_t near = -1e20; @@ -147,6 +162,11 @@ bool AABB::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 * } bool AABB::intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip, Vector3 *r_normal) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) { + ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); + } +#endif real_t min = 0, max = 1; int axis = 0; real_t sign = 0; diff --git a/core/math/aabb.h b/core/math/aabb.h index e16246902a..81124002e2 100644 --- a/core/math/aabb.h +++ b/core/math/aabb.h @@ -46,8 +46,8 @@ public: Vector3 position; Vector3 size; - real_t get_area() const; /// get area - _FORCE_INLINE_ bool has_no_area() const { + real_t get_volume() const; + _FORCE_INLINE_ bool has_no_volume() const { return (size.x <= 0 || size.y <= 0 || size.z <= 0); } @@ -118,6 +118,10 @@ public: return position + size; } + _FORCE_INLINE_ Vector3 get_center() const { + return position + (size * 0.5); + } + operator String() const; _FORCE_INLINE_ AABB() {} @@ -128,6 +132,11 @@ public: }; inline bool AABB::intersects(const AABB &p_aabb) const { +#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)) { + ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); + } +#endif if (position.x >= (p_aabb.position.x + p_aabb.size.x)) { return false; } @@ -151,6 +160,11 @@ inline bool AABB::intersects(const AABB &p_aabb) const { } inline bool AABB::intersects_inclusive(const AABB &p_aabb) const { +#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)) { + ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); + } +#endif if (position.x > (p_aabb.position.x + p_aabb.size.x)) { return false; } @@ -174,6 +188,11 @@ inline bool AABB::intersects_inclusive(const AABB &p_aabb) const { } inline bool AABB::encloses(const AABB &p_aabb) const { +#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)) { + ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); + } +#endif Vector3 src_min = position; Vector3 src_max = position + size; Vector3 dst_min = p_aabb.position; @@ -196,7 +215,7 @@ Vector3 AABB::get_support(const Vector3 &p_normal) const { (p_normal.x > 0) ? half_extents.x : -half_extents.x, (p_normal.y > 0) ? half_extents.y : -half_extents.y, (p_normal.z > 0) ? half_extents.z : -half_extents.z) + - ofs; + ofs; } Vector3 AABB::get_endpoint(int p_point) const { @@ -284,6 +303,11 @@ bool AABB::inside_convex_shape(const Plane *p_planes, int p_plane_count) const { } bool AABB::has_point(const Vector3 &p_point) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) { + ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); + } +#endif if (p_point.x < position.x) { return false; } @@ -307,6 +331,11 @@ bool AABB::has_point(const Vector3 &p_point) const { } inline void AABB::expand_to(const Vector3 &p_vector) { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) { + ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); + } +#endif Vector3 begin = position; Vector3 end = position + size; @@ -373,6 +402,11 @@ inline real_t AABB::get_shortest_axis_size() const { } bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) { + ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); + } +#endif real_t divx = 1.0 / p_dir.x; real_t divy = 1.0 / p_dir.y; real_t divz = 1.0 / p_dir.z; diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h index a5616b8d79..4a11b99fe8 100644 --- a/core/math/audio_frame.h +++ b/core/math/audio_frame.h @@ -124,10 +124,9 @@ struct AudioFrame { r = p_frame.r; } - _ALWAYS_INLINE_ AudioFrame &operator=(const AudioFrame &p_frame) { + _ALWAYS_INLINE_ void operator=(const AudioFrame &p_frame) { l = p_frame.l; r = p_frame.r; - return *this; } _ALWAYS_INLINE_ operator Vector2() const { diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 5c42213e61..566300c716 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -58,8 +58,8 @@ void Basis::invert() { cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1) }; real_t det = elements[0][0] * co[0] + - elements[0][1] * co[1] + - elements[0][2] * co[2]; + elements[0][1] * co[1] + + elements[0][2] * co[2]; #ifdef MATH_CHECKS ERR_FAIL_COND(det == 0); #endif @@ -207,6 +207,10 @@ Basis Basis::transposed() const { return tr; } +Basis Basis::from_scale(const Vector3 &p_scale) { + return Basis(p_scale.x, 0, 0, 0, p_scale.y, 0, 0, 0, p_scale.z); +} + // 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) { @@ -246,10 +250,7 @@ void Basis::make_scale_uniform() { } Basis Basis::scaled_local(const Vector3 &p_scale) const { - Basis b; - b.set_diagonal(p_scale); - - return (*this) * b; + return (*this) * Basis::from_scale(p_scale); } Vector3 Basis::get_scale_abs() const { @@ -260,7 +261,7 @@ Vector3 Basis::get_scale_abs() const { } Vector3 Basis::get_scale_local() const { - real_t det_sign = SGN(determinant()); + real_t det_sign = SIGN(determinant()); return det_sign * Vector3(elements[0].length(), elements[1].length(), elements[2].length()); } @@ -286,11 +287,8 @@ Vector3 Basis::get_scale() const { // matrix elements. // // The rotation part of this decomposition is returned by get_rotation* functions. - real_t det_sign = SGN(determinant()); - return det_sign * Vector3( - Vector3(elements[0][0], elements[1][0], elements[2][0]).length(), - Vector3(elements[0][1], elements[1][1], elements[2][1]).length(), - Vector3(elements[0][2], elements[1][2], elements[2][2]).length()); + real_t det_sign = SIGN(determinant()); + return det_sign * get_scale_abs(); } // Decomposes a Basis into a rotation-reflection matrix (an element of the group O(3)) and a positive scaling matrix as B = O.S. @@ -353,7 +351,7 @@ void Basis::rotate(const Quaternion &p_quaternion) { *this = rotated(p_quaternion); } -Vector3 Basis::get_rotation_euler() const { +Vector3 Basis::get_euler_normalized(EulerOrder p_order) const { // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). // See the comment in get_scale() for further information. @@ -364,7 +362,7 @@ Vector3 Basis::get_rotation_euler() const { m.scale(Vector3(-1, -1, -1)); } - return m.get_euler(); + return m.get_euler(p_order); } Quaternion Basis::get_rotation_quaternion() const { @@ -423,218 +421,203 @@ void Basis::get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) cons p_angle = -p_angle; } -// get_euler_xyz returns a vector containing the Euler angles in the format -// (a1,a2,a3), where a3 is the angle of the first rotation, and a1 is the last -// (following the convention they are commonly defined in the literature). -// -// The current implementation uses XYZ convention (Z is the first rotation), -// so euler.z is the angle of the (first) rotation around Z axis and so on, -// -// And thus, assuming the matrix is a rotation matrix, this function returns -// the angles in the decomposition R = X(a1).Y(a2).Z(a3) where Z(a) rotates -// around the z-axis by a and so on. -Vector3 Basis::get_euler_xyz() const { - // Euler angles in XYZ convention. - // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix - // - // rot = cy*cz -cy*sz sy - // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx - // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy - - Vector3 euler; - real_t sy = elements[0][2]; - if (sy < (1.0 - CMP_EPSILON)) { - if (sy > -(1.0 - CMP_EPSILON)) { - // is this a pure Y rotation? - if (elements[1][0] == 0.0 && elements[0][1] == 0.0 && elements[1][2] == 0 && elements[2][1] == 0 && elements[1][1] == 1) { - // return the simplest form (human friendlier in editor and scripts) - euler.x = 0; - euler.y = atan2(elements[0][2], elements[0][0]); - euler.z = 0; +Vector3 Basis::get_euler(EulerOrder p_order) const { + switch (p_order) { + case EULER_ORDER_XYZ: { + // Euler angles in XYZ convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cy*cz -cy*sz sy + // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx + // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy + + Vector3 euler; + real_t sy = elements[0][2]; + if (sy < (1.0 - CMP_EPSILON)) { + if (sy > -(1.0 - CMP_EPSILON)) { + // is this a pure Y rotation? + if (elements[1][0] == 0.0 && elements[0][1] == 0.0 && elements[1][2] == 0 && elements[2][1] == 0 && elements[1][1] == 1) { + // return the simplest form (human friendlier in editor and scripts) + euler.x = 0; + euler.y = atan2(elements[0][2], elements[0][0]); + euler.z = 0; + } else { + euler.x = Math::atan2(-elements[1][2], elements[2][2]); + euler.y = Math::asin(sy); + euler.z = Math::atan2(-elements[0][1], elements[0][0]); + } + } else { + euler.x = Math::atan2(elements[2][1], elements[1][1]); + euler.y = -Math_PI / 2.0; + euler.z = 0.0; + } } else { - euler.x = Math::atan2(-elements[1][2], elements[2][2]); - euler.y = Math::asin(sy); - euler.z = Math::atan2(-elements[0][1], elements[0][0]); + euler.x = Math::atan2(elements[2][1], elements[1][1]); + euler.y = Math_PI / 2.0; + euler.z = 0.0; + } + return euler; + } break; + case EULER_ORDER_XZY: { + // Euler angles in XZY convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cz*cy -sz cz*sy + // sx*sy+cx*cy*sz cx*cz cx*sz*sy-cy*sx + // cy*sx*sz cz*sx cx*cy+sx*sz*sy + + Vector3 euler; + real_t sz = elements[0][1]; + if (sz < (1.0 - CMP_EPSILON)) { + if (sz > -(1.0 - CMP_EPSILON)) { + euler.x = Math::atan2(elements[2][1], elements[1][1]); + euler.y = Math::atan2(elements[0][2], elements[0][0]); + euler.z = Math::asin(-sz); + } else { + // It's -1 + euler.x = -Math::atan2(elements[1][2], elements[2][2]); + euler.y = 0.0; + euler.z = Math_PI / 2.0; + } + } else { + // It's 1 + euler.x = -Math::atan2(elements[1][2], elements[2][2]); + euler.y = 0.0; + euler.z = -Math_PI / 2.0; + } + return euler; + } break; + case EULER_ORDER_YXZ: { + // Euler angles in YXZ convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cy*cz+sy*sx*sz cz*sy*sx-cy*sz cx*sy + // cx*sz cx*cz -sx + // cy*sx*sz-cz*sy cy*cz*sx+sy*sz cy*cx + + Vector3 euler; + + real_t m12 = elements[1][2]; + + if (m12 < (1 - CMP_EPSILON)) { + if (m12 > -(1 - CMP_EPSILON)) { + // is this a pure X rotation? + if (elements[1][0] == 0 && elements[0][1] == 0 && elements[0][2] == 0 && elements[2][0] == 0 && elements[0][0] == 1) { + // return the simplest form (human friendlier in editor and scripts) + euler.x = atan2(-m12, elements[1][1]); + euler.y = 0; + euler.z = 0; + } else { + euler.x = asin(-m12); + euler.y = atan2(elements[0][2], elements[2][2]); + euler.z = atan2(elements[1][0], elements[1][1]); + } + } else { // m12 == -1 + euler.x = Math_PI * 0.5; + euler.y = atan2(elements[0][1], elements[0][0]); + euler.z = 0; + } + } else { // m12 == 1 + euler.x = -Math_PI * 0.5; + euler.y = -atan2(elements[0][1], elements[0][0]); + euler.z = 0; } - } else { - euler.x = Math::atan2(elements[2][1], elements[1][1]); - euler.y = -Math_PI / 2.0; - euler.z = 0.0; - } - } else { - euler.x = Math::atan2(elements[2][1], elements[1][1]); - euler.y = Math_PI / 2.0; - euler.z = 0.0; - } - return euler; -} - -// set_euler_xyz expects a vector containing the Euler angles in the format -// (ax,ay,az), where ax is the angle of rotation around x axis, -// and similar for other axes. -// The current implementation uses XYZ convention (Z is the first rotation). -void Basis::set_euler_xyz(const Vector3 &p_euler) { - real_t c, s; - - c = Math::cos(p_euler.x); - s = Math::sin(p_euler.x); - Basis xmat(1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c); - - c = Math::cos(p_euler.y); - s = Math::sin(p_euler.y); - Basis ymat(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); - - c = Math::cos(p_euler.z); - s = Math::sin(p_euler.z); - Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - - //optimizer will optimize away all this anyway - *this = xmat * (ymat * zmat); -} - -Vector3 Basis::get_euler_xzy() const { - // Euler angles in XZY convention. - // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix - // - // rot = cz*cy -sz cz*sy - // sx*sy+cx*cy*sz cx*cz cx*sz*sy-cy*sx - // cy*sx*sz cz*sx cx*cy+sx*sz*sy - - Vector3 euler; - real_t sz = elements[0][1]; - if (sz < (1.0 - CMP_EPSILON)) { - if (sz > -(1.0 - CMP_EPSILON)) { - euler.x = Math::atan2(elements[2][1], elements[1][1]); - euler.y = Math::atan2(elements[0][2], elements[0][0]); - euler.z = Math::asin(-sz); - } else { - // It's -1 - euler.x = -Math::atan2(elements[1][2], elements[2][2]); - euler.y = 0.0; - euler.z = Math_PI / 2.0; - } - } else { - // It's 1 - euler.x = -Math::atan2(elements[1][2], elements[2][2]); - euler.y = 0.0; - euler.z = -Math_PI / 2.0; - } - return euler; -} - -void Basis::set_euler_xzy(const Vector3 &p_euler) { - real_t c, s; - - c = Math::cos(p_euler.x); - s = Math::sin(p_euler.x); - Basis xmat(1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c); - - c = Math::cos(p_euler.y); - s = Math::sin(p_euler.y); - Basis ymat(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); - - c = Math::cos(p_euler.z); - s = Math::sin(p_euler.z); - Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - - *this = xmat * zmat * ymat; -} - -Vector3 Basis::get_euler_yzx() const { - // Euler angles in YZX convention. - // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix - // - // rot = cy*cz sy*sx-cy*cx*sz cx*sy+cy*sz*sx - // sz cz*cx -cz*sx - // -cz*sy cy*sx+cx*sy*sz cy*cx-sy*sz*sx - - Vector3 euler; - real_t sz = elements[1][0]; - if (sz < (1.0 - CMP_EPSILON)) { - if (sz > -(1.0 - CMP_EPSILON)) { - euler.x = Math::atan2(-elements[1][2], elements[1][1]); - euler.y = Math::atan2(-elements[2][0], elements[0][0]); - euler.z = Math::asin(sz); - } else { - // It's -1 - euler.x = Math::atan2(elements[2][1], elements[2][2]); - euler.y = 0.0; - euler.z = -Math_PI / 2.0; - } - } else { - // It's 1 - euler.x = Math::atan2(elements[2][1], elements[2][2]); - euler.y = 0.0; - euler.z = Math_PI / 2.0; - } - return euler; -} - -void Basis::set_euler_yzx(const Vector3 &p_euler) { - real_t c, s; - - c = Math::cos(p_euler.x); - s = Math::sin(p_euler.x); - Basis xmat(1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c); - - c = Math::cos(p_euler.y); - s = Math::sin(p_euler.y); - Basis ymat(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); - - c = Math::cos(p_euler.z); - s = Math::sin(p_euler.z); - Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - - *this = ymat * zmat * xmat; -} - -// get_euler_yxz returns a vector containing the Euler angles in the YXZ convention, -// as in first-Z, then-X, last-Y. The angles for X, Y, and Z rotations are returned -// as the x, y, and z components of a Vector3 respectively. -Vector3 Basis::get_euler_yxz() const { - // Euler angles in YXZ convention. - // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix - // - // rot = cy*cz+sy*sx*sz cz*sy*sx-cy*sz cx*sy - // cx*sz cx*cz -sx - // cy*sx*sz-cz*sy cy*cz*sx+sy*sz cy*cx - - Vector3 euler; - - real_t m12 = elements[1][2]; - if (m12 < (1 - CMP_EPSILON)) { - if (m12 > -(1 - CMP_EPSILON)) { - // is this a pure X rotation? - if (elements[1][0] == 0 && elements[0][1] == 0 && elements[0][2] == 0 && elements[2][0] == 0 && elements[0][0] == 1) { - // return the simplest form (human friendlier in editor and scripts) - euler.x = atan2(-m12, elements[1][1]); - euler.y = 0; + return euler; + } break; + case EULER_ORDER_YZX: { + // Euler angles in YZX convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cy*cz sy*sx-cy*cx*sz cx*sy+cy*sz*sx + // sz cz*cx -cz*sx + // -cz*sy cy*sx+cx*sy*sz cy*cx-sy*sz*sx + + Vector3 euler; + real_t sz = elements[1][0]; + if (sz < (1.0 - CMP_EPSILON)) { + if (sz > -(1.0 - CMP_EPSILON)) { + euler.x = Math::atan2(-elements[1][2], elements[1][1]); + euler.y = Math::atan2(-elements[2][0], elements[0][0]); + euler.z = Math::asin(sz); + } else { + // It's -1 + euler.x = Math::atan2(elements[2][1], elements[2][2]); + euler.y = 0.0; + euler.z = -Math_PI / 2.0; + } + } else { + // It's 1 + euler.x = Math::atan2(elements[2][1], elements[2][2]); + euler.y = 0.0; + euler.z = Math_PI / 2.0; + } + return euler; + } break; + case EULER_ORDER_ZXY: { + // Euler angles in ZXY convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cz*cy-sz*sx*sy -cx*sz cz*sy+cy*sz*sx + // cy*sz+cz*sx*sy cz*cx sz*sy-cz*cy*sx + // -cx*sy sx cx*cy + Vector3 euler; + real_t sx = elements[2][1]; + if (sx < (1.0 - CMP_EPSILON)) { + if (sx > -(1.0 - CMP_EPSILON)) { + euler.x = Math::asin(sx); + euler.y = Math::atan2(-elements[2][0], elements[2][2]); + euler.z = Math::atan2(-elements[0][1], elements[1][1]); + } else { + // It's -1 + euler.x = -Math_PI / 2.0; + euler.y = Math::atan2(elements[0][2], elements[0][0]); + euler.z = 0; + } + } else { + // It's 1 + euler.x = Math_PI / 2.0; + euler.y = Math::atan2(elements[0][2], elements[0][0]); euler.z = 0; + } + return euler; + } break; + case EULER_ORDER_ZYX: { + // Euler angles in ZYX convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cz*cy cz*sy*sx-cx*sz sz*sx+cz*cx*cy + // cy*sz cz*cx+sz*sy*sx cx*sz*sy-cz*sx + // -sy cy*sx cy*cx + Vector3 euler; + real_t sy = elements[2][0]; + if (sy < (1.0 - CMP_EPSILON)) { + if (sy > -(1.0 - CMP_EPSILON)) { + euler.x = Math::atan2(elements[2][1], elements[2][2]); + euler.y = Math::asin(-sy); + euler.z = Math::atan2(elements[1][0], elements[0][0]); + } else { + // It's -1 + euler.x = 0; + euler.y = Math_PI / 2.0; + euler.z = -Math::atan2(elements[0][1], elements[1][1]); + } } else { - euler.x = asin(-m12); - euler.y = atan2(elements[0][2], elements[2][2]); - euler.z = atan2(elements[1][0], elements[1][1]); + // It's 1 + euler.x = 0; + euler.y = -Math_PI / 2.0; + euler.z = -Math::atan2(elements[0][1], elements[1][1]); } - } else { // m12 == -1 - euler.x = Math_PI * 0.5; - euler.y = atan2(elements[0][1], elements[0][0]); - euler.z = 0; + return euler; + } break; + default: { + ERR_FAIL_V_MSG(Vector3(), "Invalid parameter for get_euler(order)"); } - } else { // m12 == 1 - euler.x = -Math_PI * 0.5; - euler.y = -atan2(elements[0][1], elements[0][0]); - euler.z = 0; } - - return euler; + return Vector3(); } -// set_euler_yxz expects a vector containing the Euler angles in the format -// (ax,ay,az), where ax is the angle of rotation around x axis, -// and similar for other axes. -// The current implementation uses YXZ convention (Z is the first rotation). -void Basis::set_euler_yxz(const Vector3 &p_euler) { +void Basis::set_euler(const Vector3 &p_euler, EulerOrder p_order) { real_t c, s; c = Math::cos(p_euler.x); @@ -649,102 +632,29 @@ void Basis::set_euler_yxz(const Vector3 &p_euler) { s = Math::sin(p_euler.z); Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - //optimizer will optimize away all this anyway - *this = ymat * xmat * zmat; -} - -Vector3 Basis::get_euler_zxy() const { - // Euler angles in ZXY convention. - // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix - // - // rot = cz*cy-sz*sx*sy -cx*sz cz*sy+cy*sz*sx - // cy*sz+cz*sx*sy cz*cx sz*sy-cz*cy*sx - // -cx*sy sx cx*cy - Vector3 euler; - real_t sx = elements[2][1]; - if (sx < (1.0 - CMP_EPSILON)) { - if (sx > -(1.0 - CMP_EPSILON)) { - euler.x = Math::asin(sx); - euler.y = Math::atan2(-elements[2][0], elements[2][2]); - euler.z = Math::atan2(-elements[0][1], elements[1][1]); - } else { - // It's -1 - euler.x = -Math_PI / 2.0; - euler.y = Math::atan2(elements[0][2], elements[0][0]); - euler.z = 0; + switch (p_order) { + case EULER_ORDER_XYZ: { + *this = xmat * (ymat * zmat); + } break; + case EULER_ORDER_XZY: { + *this = xmat * zmat * ymat; + } break; + case EULER_ORDER_YXZ: { + *this = ymat * xmat * zmat; + } break; + case EULER_ORDER_YZX: { + *this = ymat * zmat * xmat; + } break; + case EULER_ORDER_ZXY: { + *this = zmat * xmat * ymat; + } break; + case EULER_ORDER_ZYX: { + *this = zmat * ymat * xmat; + } break; + default: { + ERR_FAIL_MSG("Invalid order parameter for set_euler(vec3,order)"); } - } else { - // It's 1 - euler.x = Math_PI / 2.0; - euler.y = Math::atan2(elements[0][2], elements[0][0]); - euler.z = 0; } - return euler; -} - -void Basis::set_euler_zxy(const Vector3 &p_euler) { - real_t c, s; - - c = Math::cos(p_euler.x); - s = Math::sin(p_euler.x); - Basis xmat(1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c); - - c = Math::cos(p_euler.y); - s = Math::sin(p_euler.y); - Basis ymat(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); - - c = Math::cos(p_euler.z); - s = Math::sin(p_euler.z); - Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - - *this = zmat * xmat * ymat; -} - -Vector3 Basis::get_euler_zyx() const { - // Euler angles in ZYX convention. - // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix - // - // rot = cz*cy cz*sy*sx-cx*sz sz*sx+cz*cx*cy - // cy*sz cz*cx+sz*sy*sx cx*sz*sy-cz*sx - // -sy cy*sx cy*cx - Vector3 euler; - real_t sy = elements[2][0]; - if (sy < (1.0 - CMP_EPSILON)) { - if (sy > -(1.0 - CMP_EPSILON)) { - euler.x = Math::atan2(elements[2][1], elements[2][2]); - euler.y = Math::asin(-sy); - euler.z = Math::atan2(elements[1][0], elements[0][0]); - } else { - // It's -1 - euler.x = 0; - euler.y = Math_PI / 2.0; - euler.z = -Math::atan2(elements[0][1], elements[1][1]); - } - } else { - // It's 1 - euler.x = 0; - euler.y = -Math_PI / 2.0; - euler.z = -Math::atan2(elements[0][1], elements[1][1]); - } - return euler; -} - -void Basis::set_euler_zyx(const Vector3 &p_euler) { - real_t c, s; - - c = Math::cos(p_euler.x); - s = Math::sin(p_euler.x); - Basis xmat(1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c); - - c = Math::cos(p_euler.y); - s = Math::sin(p_euler.y); - Basis ymat(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); - - c = Math::cos(p_euler.z); - s = Math::sin(p_euler.z); - Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - - *this = zmat * ymat * xmat; } bool Basis::is_equal_approx(const Basis &p_basis) const { @@ -769,13 +679,13 @@ bool Basis::operator!=(const Basis &p_matrix) const { Basis::operator String() const { return "[X: " + get_axis(0).operator String() + - ", Y: " + get_axis(1).operator String() + - ", Z: " + get_axis(2).operator String() + "]"; + ", Y: " + get_axis(1).operator String() + + ", Z: " + get_axis(2).operator String() + "]"; } Quaternion Basis::get_quaternion() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_rotation(), Quaternion(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quaternion() or call orthonormalized() instead."); + ERR_FAIL_COND_V_MSG(!is_rotation(), Quaternion(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quaternion() or call orthonormalized() if the Basis contains linearly independent vectors."); #endif /* Allow getting a quaternion from an unnormalized transform */ Basis m = *this; @@ -791,9 +701,9 @@ Quaternion Basis::get_quaternion() const { temp[1] = ((m.elements[0][2] - m.elements[2][0]) * s); temp[2] = ((m.elements[1][0] - m.elements[0][1]) * s); } else { - int i = m.elements[0][0] < m.elements[1][1] ? - (m.elements[1][1] < m.elements[2][2] ? 2 : 1) : - (m.elements[0][0] < m.elements[2][2] ? 2 : 0); + int i = m.elements[0][0] < m.elements[1][1] + ? (m.elements[1][1] < m.elements[2][2] ? 2 : 1) + : (m.elements[0][0] < m.elements[2][2] ? 2 : 0); int j = (i + 1) % 3; int k = (i + 2) % 3; @@ -991,21 +901,23 @@ void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_phi) { } void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { - set_diagonal(p_scale); + _set_diagonal(p_scale); rotate(p_axis, p_phi); } void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale) { - set_diagonal(p_scale); + _set_diagonal(p_scale); rotate(p_euler); } void Basis::set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale) { - set_diagonal(p_scale); + _set_diagonal(p_scale); rotate(p_quaternion); } -void Basis::set_diagonal(const Vector3 &p_diag) { +// This also sets the non-diagonal elements to 0, which is misleading from the +// name, so we want this method to be private. Use `from_scale` externally. +void Basis::_set_diagonal(const Vector3 &p_diag) { elements[0][0] = p_diag.x; elements[0][1] = 0; elements[0][2] = 0; diff --git a/core/math/basis.h b/core/math/basis.h index 9d8ed16e29..e2fdb95685 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -35,6 +35,9 @@ #include "core/math/vector3.h" class Basis { +private: + void _set_diagonal(const Vector3 &p_diag); + public: Vector3 elements[3] = { Vector3(1, 0, 0), @@ -82,40 +85,35 @@ public: void rotate(const Quaternion &p_quaternion); Basis rotated(const Quaternion &p_quaternion) const; - Vector3 get_rotation_euler() const; + enum EulerOrder { + EULER_ORDER_XYZ, + EULER_ORDER_XZY, + EULER_ORDER_YXZ, + EULER_ORDER_YZX, + EULER_ORDER_ZXY, + EULER_ORDER_ZYX + }; + + Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) const; void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const; void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const; Quaternion get_rotation_quaternion() const; - Vector3 get_rotation() const { return get_rotation_euler(); }; void rotate_to_align(Vector3 p_start_direction, Vector3 p_end_direction); Vector3 rotref_posscale_decomposition(Basis &rotref) const; - Vector3 get_euler_xyz() const; - void set_euler_xyz(const Vector3 &p_euler); - - Vector3 get_euler_xzy() const; - void set_euler_xzy(const Vector3 &p_euler); - - Vector3 get_euler_yzx() const; - void set_euler_yzx(const Vector3 &p_euler); - - Vector3 get_euler_yxz() const; - void set_euler_yxz(const Vector3 &p_euler); - - Vector3 get_euler_zxy() const; - void set_euler_zxy(const Vector3 &p_euler); - - Vector3 get_euler_zyx() const; - void set_euler_zyx(const Vector3 &p_euler); + Vector3 get_euler(EulerOrder p_order = EULER_ORDER_YXZ) const; + void set_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ); + static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) { + Basis b; + b.set_euler(p_euler, p_order); + return b; + } Quaternion get_quaternion() const; void set_quaternion(const Quaternion &p_quaternion); - Vector3 get_euler() const { return get_euler_yxz(); } - void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); } - void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const; void set_axis_angle(const Vector3 &p_axis, real_t p_phi); @@ -166,8 +164,6 @@ public: int get_orthogonal_index() const; void set_orthogonal_index(int p_index); - void set_diagonal(const Vector3 &p_diag); - bool is_orthogonal() const; bool is_diagonal() const; bool is_rotation() const; @@ -249,11 +245,9 @@ public: 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); } - Basis(const Vector3 &p_euler) { set_euler(p_euler); } - Basis(const Vector3 &p_euler, const Vector3 &p_scale) { set_euler_scale(p_euler, p_scale); } - Basis(const Vector3 &p_axis, real_t p_phi) { set_axis_angle(p_axis, p_phi); } Basis(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_phi, p_scale); } + static Basis from_scale(const Vector3 &p_scale); _FORCE_INLINE_ Basis(const Vector3 &row0, const Vector3 &row1, const Vector3 &row2) { elements[0] = row0; @@ -330,7 +324,7 @@ Vector3 Basis::xform_inv(const Vector3 &p_vector) const { real_t Basis::determinant() const { return elements[0][0] * (elements[1][1] * elements[2][2] - elements[2][1] * elements[1][2]) - - elements[1][0] * (elements[0][1] * elements[2][2] - elements[2][1] * elements[0][2]) + - elements[2][0] * (elements[0][1] * elements[1][2] - elements[1][1] * elements[0][2]); + elements[1][0] * (elements[0][1] * elements[2][2] - elements[2][1] * elements[0][2]) + + elements[2][0] * (elements[0][1] * elements[1][2] - elements[1][1] * elements[0][2]); } #endif // BASIS_H diff --git a/core/math/bvh.h b/core/math/bvh.h index cefbc9b0db..c1eff02178 100644 --- a/core/math/bvh.h +++ b/core/math/bvh.h @@ -200,7 +200,7 @@ public: // use in conjunction with activate if you have deferred the collision check, and // set pairable has never been called. - // (deferred collision checks are a workaround for visual server for historical reasons) + // (deferred collision checks are a workaround for rendering server for historical reasons) void force_collision_check(BVHHandle p_handle) { if (USE_PAIRS) { // the aabb should already be up to date in the BVH @@ -654,7 +654,7 @@ private: // remove from changed items (not very efficient yet) for (int n = 0; n < (int)changed_items.size(); n++) { if (changed_items[n] == p_handle) { - changed_items.remove_unordered(n); + changed_items.remove_at_unordered(n); // because we are using an unordered remove, // the last changed item will now be at spot 'n', diff --git a/core/math/bvh_cull.inc b/core/math/bvh_cull.inc index cba8ea6cb3..d7edc8a884 100644 --- a/core/math/bvh_cull.inc +++ b/core/math/bvh_cull.inc @@ -14,7 +14,7 @@ struct CullParams { uint32_t pairable_type; // optional components for different tests - Vector3 point; + Point point; BVHABB_CLASS abb; typename BVHABB_CLASS::ConvexHull hull; typename BVHABB_CLASS::Segment segment; diff --git a/core/math/bvh_debug.inc b/core/math/bvh_debug.inc index a97304334c..55db794ee3 100644 --- a/core/math/bvh_debug.inc +++ b/core/math/bvh_debug.inc @@ -6,24 +6,21 @@ void _debug_recursive_print_tree(int p_tree_id) const { } String _debug_aabb_to_string(const BVHABB_CLASS &aabb) const { - String sz = "("; - sz += itos(aabb.min.x); - sz += " ~ "; - sz += itos(-aabb.neg_max.x); - sz += ") ("; + Point size = aabb.calculate_size(); - sz += itos(aabb.min.y); - sz += " ~ "; - sz += itos(-aabb.neg_max.y); - sz += ") ("; + String sz; + float vol = 0.0; - sz += itos(aabb.min.z); - sz += " ~ "; - sz += itos(-aabb.neg_max.z); - sz += ") "; + for (int i = 0; i < Point::AXES_COUNT; ++i) { + sz += "("; + sz += itos(aabb.min[i]); + sz += " ~ "; + sz += itos(-aabb.neg_max[i]); + sz += ") "; + + vol += size[i]; + } - Vector3 size = aabb.calculate_size(); - float vol = size.x * size.y * size.z; sz += "vol " + itos(vol); return sz; diff --git a/core/math/bvh_logic.inc b/core/math/bvh_logic.inc index afab08f151..c65002a9fd 100644 --- a/core/math/bvh_logic.inc +++ b/core/math/bvh_logic.inc @@ -42,24 +42,24 @@ BVHABB_CLASS _logic_abb_merge(const BVHABB_CLASS &a, const BVHABB_CLASS &b) { //-------------------------------------------------------------------------------------------------- /** -@file q3DynamicAABBTree.h -@author Randy Gaul -@date 10/10/2014 - Copyright (c) 2014 Randy Gaul http://www.randygaul.net - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ + * @file q3DynamicAABBTree.h + * @author Randy Gaul + * @date 10/10/2014 + * Copyright (c) 2014 Randy Gaul http://www.randygaul.net + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ //-------------------------------------------------------------------------------------------------- // This function is based on the 'Balance' function from Randy Gaul's qu3e @@ -67,7 +67,7 @@ BVHABB_CLASS _logic_abb_merge(const BVHABB_CLASS &a, const BVHABB_CLASS &b) { // It is MODIFIED from qu3e version. // This is the only function used (and _logic_abb_merge helper function). int32_t _logic_balance(int32_t iA, uint32_t p_tree_id) { - // return iA; // uncomment this to bypass balance + //return iA; // uncomment this to bypass balance TNode *A = &_nodes[iA]; @@ -75,12 +75,12 @@ int32_t _logic_balance(int32_t iA, uint32_t p_tree_id) { return iA; } - /* A - / \ - B C - / \ / \ - D E F G - */ + /* A + * / \ + * B C + * / \ / \ + * D E F G + */ CRASH_COND(A->num_children != 2); int32_t iB = A->children[0]; diff --git a/core/math/bvh_pair.inc b/core/math/bvh_pair.inc index 839db59a3a..a12acec2b6 100644 --- a/core/math/bvh_pair.inc +++ b/core/math/bvh_pair.inc @@ -51,7 +51,7 @@ struct ItemPairs { for (int n = 0; n < num_pairs; n++) { if (extended_pairs[n].handle == h) { userdata = extended_pairs[n].userdata; - extended_pairs.remove_unordered(n); + extended_pairs.remove_at_unordered(n); num_pairs--; break; } diff --git a/core/math/bvh_split.inc b/core/math/bvh_split.inc index 3fcc4c7b10..f19ee8a7da 100644 --- a/core/math/bvh_split.inc +++ b/core/math/bvh_split.inc @@ -28,11 +28,15 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u Point centre = full_bound.calculate_centre(); Point size = full_bound.calculate_size(); - int order[3]; + int order[Point::AXIS_COUNT]; - order[0] = size.min_axis(); - order[2] = size.max_axis(); - order[1] = 3 - (order[0] + order[2]); + order[0] = size.min_axis_index(); + order[Point::AXIS_COUNT - 1] = size.max_axis_index(); + + static_assert(Point::AXIS_COUNT <= 3); + if (Point::AXIS_COUNT == 3) { + order[1] = 3 - (order[0] + order[2]); + } // simplest case, split on the longest axis int split_axis = order[0]; @@ -54,7 +58,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u // detect when split on longest axis failed int min_threshold = MAX_ITEMS / 4; - int min_group_size[3]; + int min_group_size[Point::AXIS_COUNT]; min_group_size[0] = MIN(num_a, num_b); if (min_group_size[0] < min_threshold) { // slow but sure .. first move everything back into a @@ -64,7 +68,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u num_b = 0; // now calculate the best split - for (int axis = 1; axis < 3; axis++) { + for (int axis = 1; axis < Point::AXIS_COUNT; axis++) { split_axis = order[axis]; int count = 0; @@ -82,7 +86,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u // best axis int best_axis = 0; int best_min = min_group_size[0]; - for (int axis = 1; axis < 3; axis++) { + for (int axis = 1; axis < Point::AXIS_COUNT; axis++) { if (min_group_size[axis] > best_min) { best_min = min_group_size[axis]; best_axis = axis; diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 8066a59281..48984c4d5b 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -35,17 +35,17 @@ float CameraMatrix::determinant() const { return matrix[0][3] * matrix[1][2] * matrix[2][1] * matrix[3][0] - matrix[0][2] * matrix[1][3] * matrix[2][1] * matrix[3][0] - - matrix[0][3] * matrix[1][1] * matrix[2][2] * matrix[3][0] + matrix[0][1] * matrix[1][3] * matrix[2][2] * matrix[3][0] + - matrix[0][2] * matrix[1][1] * matrix[2][3] * matrix[3][0] - matrix[0][1] * matrix[1][2] * matrix[2][3] * matrix[3][0] - - matrix[0][3] * matrix[1][2] * matrix[2][0] * matrix[3][1] + matrix[0][2] * matrix[1][3] * matrix[2][0] * matrix[3][1] + - matrix[0][3] * matrix[1][0] * matrix[2][2] * matrix[3][1] - matrix[0][0] * matrix[1][3] * matrix[2][2] * matrix[3][1] - - matrix[0][2] * matrix[1][0] * matrix[2][3] * matrix[3][1] + matrix[0][0] * matrix[1][2] * matrix[2][3] * matrix[3][1] + - matrix[0][3] * matrix[1][1] * matrix[2][0] * matrix[3][2] - matrix[0][1] * matrix[1][3] * matrix[2][0] * matrix[3][2] - - matrix[0][3] * matrix[1][0] * matrix[2][1] * matrix[3][2] + matrix[0][0] * matrix[1][3] * matrix[2][1] * matrix[3][2] + - matrix[0][1] * matrix[1][0] * matrix[2][3] * matrix[3][2] - matrix[0][0] * matrix[1][1] * matrix[2][3] * matrix[3][2] - - matrix[0][2] * matrix[1][1] * matrix[2][0] * matrix[3][3] + matrix[0][1] * matrix[1][2] * matrix[2][0] * matrix[3][3] + - matrix[0][2] * matrix[1][0] * matrix[2][1] * matrix[3][3] - matrix[0][0] * matrix[1][2] * matrix[2][1] * matrix[3][3] - - matrix[0][1] * matrix[1][0] * matrix[2][2] * matrix[3][3] + matrix[0][0] * matrix[1][1] * matrix[2][2] * matrix[3][3]; + matrix[0][3] * matrix[1][1] * matrix[2][2] * matrix[3][0] + matrix[0][1] * matrix[1][3] * matrix[2][2] * matrix[3][0] + + matrix[0][2] * matrix[1][1] * matrix[2][3] * matrix[3][0] - matrix[0][1] * matrix[1][2] * matrix[2][3] * matrix[3][0] - + matrix[0][3] * matrix[1][2] * matrix[2][0] * matrix[3][1] + matrix[0][2] * matrix[1][3] * matrix[2][0] * matrix[3][1] + + matrix[0][3] * matrix[1][0] * matrix[2][2] * matrix[3][1] - matrix[0][0] * matrix[1][3] * matrix[2][2] * matrix[3][1] - + matrix[0][2] * matrix[1][0] * matrix[2][3] * matrix[3][1] + matrix[0][0] * matrix[1][2] * matrix[2][3] * matrix[3][1] + + matrix[0][3] * matrix[1][1] * matrix[2][0] * matrix[3][2] - matrix[0][1] * matrix[1][3] * matrix[2][0] * matrix[3][2] - + matrix[0][3] * matrix[1][0] * matrix[2][1] * matrix[3][2] + matrix[0][0] * matrix[1][3] * matrix[2][1] * matrix[3][2] + + matrix[0][1] * matrix[1][0] * matrix[2][3] * matrix[3][2] - matrix[0][0] * matrix[1][1] * matrix[2][3] * matrix[3][2] - + matrix[0][2] * matrix[1][1] * matrix[2][0] * matrix[3][3] + matrix[0][1] * matrix[1][2] * matrix[2][0] * matrix[3][3] + + matrix[0][2] * matrix[1][0] * matrix[2][1] * matrix[3][3] - matrix[0][0] * matrix[1][2] * matrix[2][1] * matrix[3][3] - + matrix[0][1] * matrix[1][0] * matrix[2][2] * matrix[3][3] + matrix[0][0] * matrix[1][1] * matrix[2][2] * matrix[3][3]; } void CameraMatrix::set_identity() { diff --git a/core/math/color.cpp b/core/math/color.cpp index dc86cacf8f..8310c342ed 100644 --- a/core/math/color.cpp +++ b/core/math/color.cpp @@ -107,6 +107,39 @@ uint64_t Color::to_rgba64() const { return c; } +String _to_hex(float p_val) { + int v = Math::round(p_val * 255); + v = CLAMP(v, 0, 255); + String ret; + + for (int i = 0; i < 2; i++) { + char32_t c[2] = { 0, 0 }; + int lv = v & 0xF; + if (lv < 10) { + c[0] = '0' + lv; + } else { + c[0] = 'a' + lv - 10; + } + + v >>= 4; + String cs = (const char32_t *)c; + ret = cs + ret; + } + + return ret; +} + +String Color::to_html(bool p_alpha) const { + String txt; + txt += _to_hex(r); + txt += _to_hex(g); + txt += _to_hex(b); + if (p_alpha) { + txt += _to_hex(a); + } + return txt; +} + float Color::get_h() const { float min = MIN(r, g); min = MIN(min, b); @@ -249,20 +282,6 @@ Color Color::hex64(uint64_t p_hex) { return Color(r, g, b, a); } -Color Color::from_rgbe9995(uint32_t p_rgbe) { - float r = p_rgbe & 0x1ff; - float g = (p_rgbe >> 9) & 0x1ff; - float b = (p_rgbe >> 18) & 0x1ff; - float e = (p_rgbe >> 27); - float m = Math::pow(2, e - 15.0 - 9.0); - - float rd = r * m; - float gd = g * m; - float bd = b * m; - - return Color(rd, gd, bd, 1.0f); -} - static int _parse_col4(const String &p_str, int p_ofs) { char character = p_str[p_ofs]; @@ -428,43 +447,24 @@ Color Color::from_string(const String &p_string, const Color &p_default) { } } -String _to_hex(float p_val) { - int v = Math::round(p_val * 255); - v = CLAMP(v, 0, 255); - String ret; - - for (int i = 0; i < 2; i++) { - char32_t c[2] = { 0, 0 }; - int lv = v & 0xF; - if (lv < 10) { - c[0] = '0' + lv; - } else { - c[0] = 'a' + lv - 10; - } - - v >>= 4; - String cs = (const char32_t *)c; - ret = cs + ret; - } - - return ret; +Color Color::from_hsv(float p_h, float p_s, float p_v, float p_alpha) { + Color c; + c.set_hsv(p_h, p_s, p_v, p_alpha); + return c; } -String Color::to_html(bool p_alpha) const { - String txt; - txt += _to_hex(r); - txt += _to_hex(g); - txt += _to_hex(b); - if (p_alpha) { - txt += _to_hex(a); - } - return txt; -} +Color Color::from_rgbe9995(uint32_t p_rgbe) { + float r = p_rgbe & 0x1ff; + float g = (p_rgbe >> 9) & 0x1ff; + float b = (p_rgbe >> 18) & 0x1ff; + float e = (p_rgbe >> 27); + float m = Math::pow(2, e - 15.0 - 9.0); -Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const { - Color c; - c.set_hsv(p_h, p_s, p_v, p_a); - return c; + float rd = r * m; + float gd = g * m; + float bd = b * m; + + return Color(rd, gd, bd, 1.0f); } Color::operator String() const { diff --git a/core/math/color.h b/core/math/color.h index a95dbf4f60..ffd0fd8f6e 100644 --- a/core/math/color.h +++ b/core/math/color.h @@ -51,6 +51,7 @@ struct Color { uint64_t to_rgba64() const; uint64_t to_argb64() const; uint64_t to_abgr64() const; + String to_html(bool p_alpha = true) const; float get_h() const; float get_s() const; float get_v() const; @@ -189,8 +190,7 @@ struct Color { static String get_named_color_name(int p_idx); static Color get_named_color(int p_idx); static Color from_string(const String &p_string, const Color &p_default); - String to_html(bool p_alpha = true) const; - Color from_hsv(float p_h, float p_s, float p_v, float p_a) const; + static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0); static Color from_rgbe9995(uint32_t p_rgbe); _FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp index 21cb0efe20..6f551319df 100644 --- a/core/math/convex_hull.cpp +++ b/core/math/convex_hull.cpp @@ -265,8 +265,7 @@ public: } int32_t get_sign() const { - return ((int64_t)high < 0) ? -1 : (high || low) ? 1 : - 0; + return ((int64_t)high < 0) ? -1 : ((high || low) ? 1 : 0); } bool operator<(const Int128 &b) const { @@ -594,8 +593,6 @@ private: IntermediateHull() { } - - void print(); }; enum Orientation { NONE, @@ -609,9 +606,9 @@ private: PagedAllocator<Face> face_pool; LocalVector<Vertex *> original_vertices; int32_t merge_stamp = 0; - int32_t min_axis = 0; - int32_t med_axis = 0; - int32_t max_axis = 0; + Vector3::Axis min_axis = Vector3::Axis::AXIS_X; + Vector3::Axis med_axis = Vector3::Axis::AXIS_X; + Vector3::Axis max_axis = Vector3::Axis::AXIS_X; int32_t used_edge_pairs = 0; int32_t max_used_edge_pairs = 0; @@ -737,8 +734,6 @@ int32_t ConvexHullInternal::Rational64::compare(const Rational64 &b) const { return 0; } - // return (numerator * b.denominator > b.numerator * denominator) ? sign : (numerator * b.denominator < b.numerator * denominator) ? -sign : 0; - #ifdef USE_X86_64_ASM int32_t result; @@ -759,10 +754,9 @@ int32_t ConvexHullInternal::Rational64::compare(const Rational64 &b) const { : "=&b"(result), [tmp] "=&r"(tmp), "=a"(dummy) : "a"(denominator), [bn] "g"(b.numerator), [tn] "g"(numerator), [bd] "g"(b.denominator) : "%rdx", "cc"); - return result ? result ^ sign // if sign is +1, only bit 0 of result is inverted, which does not change the sign of result (and cannot result in zero) - // if sign is -1, all bits of result are inverted, which changes the sign of result (and again cannot result in zero) - : - 0; + // if sign is +1, only bit 0 of result is inverted, which does not change the sign of result (and cannot result in zero) + // if sign is -1, all bits of result are inverted, which changes the sign of result (and again cannot result in zero) + return result ? result ^ sign : 0; #else @@ -795,8 +789,7 @@ int32_t ConvexHullInternal::Rational128::compare(const Rational128 &b) const { int32_t ConvexHullInternal::Rational128::compare(int64_t b) const { if (is_int_64) { int64_t a = sign * (int64_t)numerator.low; - return (a > b) ? 1 : (a < b) ? -1 : - 0; + return (a > b) ? 1 : ((a < b) ? -1 : 0); } if (b > 0) { if (sign <= 0) { @@ -1448,8 +1441,7 @@ void ConvexHullInternal::merge(IntermediateHull &p_h0, IntermediateHull &p_h1) { c1->edges = e; return; } else { - int32_t cmp = !min0 ? 1 : !min1 ? -1 : - min_cot0.compare(min_cot1); + int32_t cmp = !min0 ? 1 : (!min1 ? -1 : min_cot0.compare(min_cot1)); #ifdef DEBUG_CONVEX_HULL printf(" -> Result %d\n", cmp); #endif @@ -1593,12 +1585,12 @@ void ConvexHullInternal::compute(const Vector3 *p_coords, int32_t p_count) { } Vector3 s = aabb.size; - max_axis = s.max_axis(); - min_axis = s.min_axis(); + max_axis = s.max_axis_index(); + min_axis = s.min_axis_index(); if (min_axis == max_axis) { - min_axis = (max_axis + 1) % 3; + min_axis = Vector3::Axis((max_axis + 1) % 3); } - med_axis = 3 - max_axis - min_axis; + med_axis = Vector3::Axis(3 - max_axis - min_axis); s /= real_t(10216); if (((med_axis + 1) % 3) != max_axis) { @@ -1696,7 +1688,7 @@ real_t ConvexHullInternal::shrink(real_t p_amount, real_t p_clamp_amount) { while (stack.size() > 0) { Vertex *v = stack[stack.size() - 1]; - stack.remove(stack.size() - 1); + stack.remove_at(stack.size() - 1); Edge *e = v->edges; if (e) { do { @@ -2260,10 +2252,21 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3 r_mesh.vertices = ch.vertices; - r_mesh.edges.resize(ch.edges.size()); + // Copy the edges over. There's two "half-edges" for every edge, so we pick only one of them. + r_mesh.edges.resize(ch.edges.size() / 2); + uint32_t edges_copied = 0; for (uint32_t i = 0; i < ch.edges.size(); i++) { - r_mesh.edges.write[i].a = (&ch.edges[i])->get_source_vertex(); - r_mesh.edges.write[i].b = (&ch.edges[i])->get_target_vertex(); + uint32_t a = (&ch.edges[i])->get_source_vertex(); + uint32_t b = (&ch.edges[i])->get_target_vertex(); + if (a < b) { // Copy only the "canonical" edge. For the reverse edge, this will be false. + ERR_BREAK(edges_copied >= (uint32_t)r_mesh.edges.size()); + r_mesh.edges.write[edges_copied].a = a; + r_mesh.edges.write[edges_copied].b = b; + edges_copied++; + } + } + if (edges_copied != (uint32_t)r_mesh.edges.size()) { + ERR_PRINT("Invalid edge count."); } r_mesh.faces.resize(ch.faces.size()); diff --git a/core/math/convex_hull.h b/core/math/convex_hull.h index a860d60b02..806c6cc3fb 100644 --- a/core/math/convex_hull.h +++ b/core/math/convex_hull.h @@ -49,7 +49,7 @@ subject to the following restrictions: #include "core/templates/vector.h" /// Convex hull implementation based on Preparata and Hong -/// See https://code.google.com/p/bullet/issues/detail?id=275 +/// See https://code.google.com/archive/p/bullet/issues/275 /// Ole Kniemeyer, MAXON Computer GmbH class ConvexHullComputer { public: diff --git a/core/math/delaunay_2d.h b/core/math/delaunay_2d.h index 95064e5700..779ac96b79 100644 --- a/core/math/delaunay_2d.h +++ b/core/math/delaunay_2d.h @@ -101,7 +101,7 @@ public: } float delta_max = MAX(rect.size.width, rect.size.height); - Vector2 center = rect.position + rect.size * 0.5; + Vector2 center = rect.get_center(); points.push_back(Vector2(center.x - 20 * delta_max, center.y - delta_max)); points.push_back(Vector2(center.x, center.y + 20 * delta_max)); @@ -123,7 +123,7 @@ public: for (int j = 0; j < triangles.size(); j++) { if (triangles[j].bad) { - triangles.remove(j); + triangles.remove_at(j); j--; } } @@ -154,7 +154,7 @@ public: } } if (invalid) { - triangles.remove(i); + triangles.remove_at(i); i--; } } diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h index d63132b4da..0b6286cd9d 100644 --- a/core/math/dynamic_bvh.h +++ b/core/math/dynamic_bvh.h @@ -41,7 +41,7 @@ /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2013 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 05f2c8dac9..fe277cff96 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -410,6 +410,14 @@ Error Expression::_get_token(Token &r_token) { } else if (id == "self") { r_token.type = TK_SELF; } else { + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (id == Variant::get_type_name(Variant::Type(i))) { + r_token.type = TK_BASIC_TYPE; + r_token.value = i; + return OK; + } + } + if (Variant::has_utility_function(id)) { r_token.type = TK_BUILTIN_FUNC; r_token.value = id; @@ -1087,7 +1095,7 @@ Expression::ENode *Expression::_parse_expression() { op->nodes[1] = nullptr; expression.write[i].is_op = false; expression.write[i].node = op; - expression.remove(i + 1); + expression.remove_at(i + 1); } } else { @@ -1119,8 +1127,8 @@ Expression::ENode *Expression::_parse_expression() { //replace all 3 nodes by this operator and make it an expression expression.write[next_op - 1].node = op; - expression.remove(next_op); - expression.remove(next_op); + expression.remove_at(next_op); + expression.remove_at(next_op); } } diff --git a/core/math/face3.cpp b/core/math/face3.cpp index 9af3f868d2..31a853e1a9 100644 --- a/core/math/face3.cpp +++ b/core/math/face3.cpp @@ -151,8 +151,8 @@ Face3::Side Face3::get_side_of(const Face3 &p_face, ClockDirection p_clock_dir) } Vector3 Face3::get_random_point_inside() const { - real_t a = Math::random(0, 1); - real_t b = Math::random(0, 1); + real_t a = Math::random(0.0, 1.0); + real_t b = Math::random(0.0, 1.0); if (a > b) { SWAP(a, b); } @@ -229,7 +229,7 @@ bool Face3::intersects_aabb(const AABB &p_aabb) const { axis.normalize(); real_t minA, maxA, minB, maxB; - p_aabb.project_range_in_plane(Plane(axis, 0), minA, maxA); + p_aabb.project_range_in_plane(Plane(axis), minA, maxA); project_range(axis, Transform3D(), minB, maxB); if (maxA < minB || maxB < minA) { diff --git a/core/math/face3.h b/core/math/face3.h index 9e9026e54e..0a8c1c6041 100644 --- a/core/math/face3.h +++ b/core/math/face3.h @@ -48,13 +48,13 @@ public: Vector3 vertex[3]; /** - * - * @param p_plane plane used to split the face - * @param p_res array of at least 3 faces, amount used in function return - * @param p_is_point_over array of at least 3 booleans, determining which face is over the plane, amount used in function return - * @param _epsilon constant used for numerical error rounding, to add "thickness" to the plane (so coplanar points can happen) - * @return amount of faces generated by the split, either 0 (means no split possible), 2 or 3 - */ + * + * @param p_plane plane used to split the face + * @param p_res array of at least 3 faces, amount used in function return + * @param p_is_point_over array of at least 3 booleans, determining which face is over the plane, amount used in function return + * @param _epsilon constant used for numerical error rounding, to add "thickness" to the plane (so coplanar points can happen) + * @return amount of faces generated by the split, either 0 (means no split possible), 2 or 3 + */ int split_by_plane(const Plane &p_plane, Face3 *p_res, bool *p_is_point_over) const; diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h index 8e5830f9b3..028ac0f4eb 100644 --- a/core/math/geometry_2d.h +++ b/core/math/geometry_2d.h @@ -37,8 +37,6 @@ #include "core/templates/vector.h" class Geometry2D { - Geometry2D(); - public: static real_t get_closest_points_between_segments(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2, Vector2 &c1, Vector2 &c2) { Vector2 d1 = q1 - p1; // Direction vector of segment S1. @@ -183,8 +181,7 @@ public: D = Vector2(D.x * Bn.x + D.y * Bn.y, D.y * Bn.x - D.x * Bn.y); // Fail if C x B and D x B have the same sign (segments don't intersect). - // (equivalent to condition (C.y < 0 && D.y < CMP_EPSILON) || (C.y > 0 && D.y > CMP_EPSILON)) - if (C.y * D.y > CMP_EPSILON) { + if ((C.y < -CMP_EPSILON && D.y < -CMP_EPSILON) || (C.y > CMP_EPSILON && D.y > CMP_EPSILON)) { return false; } diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp index 6628b760e0..88d2656025 100644 --- a/core/math/geometry_3d.cpp +++ b/core/math/geometry_3d.cpp @@ -819,11 +819,9 @@ Vector<Plane> Geometry3D::build_sphere_planes(real_t p_radius, int p_lats, int p planes.push_back(Plane(normal, p_radius)); for (int j = 1; j <= p_lats; j++) { - // FIXME: This is stupid. - Vector3 angle = normal.lerp(axis, j / (real_t)p_lats).normalized(); - Vector3 pos = angle * p_radius; - planes.push_back(Plane(pos, angle)); - planes.push_back(Plane(pos * axis_neg, angle * axis_neg)); + Vector3 plane_normal = normal.lerp(axis, j / (real_t)p_lats).normalized(); + planes.push_back(Plane(plane_normal, p_radius)); + planes.push_back(Plane(plane_normal * axis_neg, p_radius)); } } @@ -852,10 +850,10 @@ Vector<Plane> Geometry3D::build_capsule_planes(real_t p_radius, real_t p_height, planes.push_back(Plane(normal, p_radius)); for (int j = 1; j <= p_lats; j++) { - Vector3 angle = normal.lerp(axis, j / (real_t)p_lats).normalized(); - Vector3 pos = axis * p_height * 0.5 + angle * p_radius; - planes.push_back(Plane(pos, angle)); - planes.push_back(Plane(pos * axis_neg, angle * axis_neg)); + Vector3 plane_normal = normal.lerp(axis, j / (real_t)p_lats).normalized(); + Vector3 position = axis * p_height * 0.5 + plane_normal * p_radius; + planes.push_back(Plane(plane_normal, position)); + planes.push_back(Plane(plane_normal * axis_neg, position * axis_neg)); } } diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h index 766689e222..6a59b34585 100644 --- a/core/math/geometry_3d.h +++ b/core/math/geometry_3d.h @@ -36,8 +36,6 @@ #include "core/templates/vector.h" class Geometry3D { - Geometry3D(); - public: static void get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2, Vector3 &c1, Vector3 &c2) { // Do the function 'd' as defined by pb. I think it's a dot product of some sort. diff --git a/core/math/math_defs.h b/core/math/math_defs.h index c3a8f910c0..1c6139688b 100644 --- a/core/math/math_defs.h +++ b/core/math/math_defs.h @@ -68,37 +68,38 @@ enum Orientation { VERTICAL }; -enum HAlign { - HALIGN_LEFT, - HALIGN_CENTER, - HALIGN_RIGHT, - HALIGN_FILL, +enum HorizontalAlignment { + HORIZONTAL_ALIGNMENT_LEFT, + HORIZONTAL_ALIGNMENT_CENTER, + HORIZONTAL_ALIGNMENT_RIGHT, + HORIZONTAL_ALIGNMENT_FILL, }; -enum VAlign { - VALIGN_TOP, - VALIGN_CENTER, - VALIGN_BOTTOM +enum VerticalAlignment { + VERTICAL_ALIGNMENT_TOP, + VERTICAL_ALIGNMENT_CENTER, + VERTICAL_ALIGNMENT_BOTTOM, + VERTICAL_ALIGNMENT_FILL, }; -enum InlineAlign { +enum InlineAlignment { // Image alignment points. - INLINE_ALIGN_TOP_TO = 0b0000, - INLINE_ALIGN_CENTER_TO = 0b0001, - INLINE_ALIGN_BOTTOM_TO = 0b0010, - INLINE_ALIGN_IMAGE_MASK = 0b0011, + INLINE_ALIGNMENT_TOP_TO = 0b0000, + INLINE_ALIGNMENT_CENTER_TO = 0b0001, + INLINE_ALIGNMENT_BOTTOM_TO = 0b0010, + INLINE_ALIGNMENT_IMAGE_MASK = 0b0011, // Text alignment points. - INLINE_ALIGN_TO_TOP = 0b0000, - INLINE_ALIGN_TO_CENTER = 0b0100, - INLINE_ALIGN_TO_BASELINE = 0b1000, - INLINE_ALIGN_TO_BOTTOM = 0b1100, - INLINE_ALIGN_TEXT_MASK = 0b1100, + INLINE_ALIGNMENT_TO_TOP = 0b0000, + INLINE_ALIGNMENT_TO_CENTER = 0b0100, + INLINE_ALIGNMENT_TO_BASELINE = 0b1000, + INLINE_ALIGNMENT_TO_BOTTOM = 0b1100, + INLINE_ALIGNMENT_TEXT_MASK = 0b1100, // Presets. - INLINE_ALIGN_TOP = INLINE_ALIGN_TOP_TO | INLINE_ALIGN_TO_TOP, - INLINE_ALIGN_CENTER = INLINE_ALIGN_CENTER_TO | INLINE_ALIGN_TO_CENTER, - INLINE_ALIGN_BOTTOM = INLINE_ALIGN_BOTTOM_TO | INLINE_ALIGN_TO_BOTTOM + INLINE_ALIGNMENT_TOP = INLINE_ALIGNMENT_TOP_TO | INLINE_ALIGNMENT_TO_TOP, + INLINE_ALIGNMENT_CENTER = INLINE_ALIGNMENT_CENTER_TO | INLINE_ALIGNMENT_TO_CENTER, + INLINE_ALIGNMENT_BOTTOM = INLINE_ALIGNMENT_BOTTOM_TO | INLINE_ALIGNMENT_TO_BOTTOM }; enum Side { @@ -116,10 +117,10 @@ enum Corner { }; /** - * The "Real" type is an abstract type used for real numbers, such as 1.5, - * in contrast to integer numbers. Precision can be controlled with the - * presence or absence of the REAL_T_IS_DOUBLE define. - */ + * The "Real" type is an abstract type used for real numbers, such as 1.5, + * in contrast to integer numbers. Precision can be controlled with the + * presence or absence of the REAL_T_IS_DOUBLE define. + */ #ifdef REAL_T_IS_DOUBLE typedef double real_t; #else diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp index bbed257f60..2b6d92fe0e 100644 --- a/core/math/math_funcs.cpp +++ b/core/math/math_funcs.cpp @@ -53,6 +53,10 @@ uint32_t Math::rand() { return default_rand.rand(); } +double Math::randfn(double mean, double deviation) { + return default_rand.randfn(mean, deviation); +} + int Math::step_decimals(double p_step) { static const int maxn = 10; static const double sd[maxn] = { diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 4e4f566517..8df45255c9 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -159,7 +159,7 @@ public: } ieee754; ieee754.f = p_val; return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && - ((unsigned)ieee754.u == 0); + ((unsigned)ieee754.u == 0); #else return isinf(p_val); #endif @@ -266,8 +266,8 @@ public: float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f); return s * s * (3.0f - 2.0f * s); } - static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta; } - static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta; } + static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; } + static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; } static _ALWAYS_INLINE_ double linear2db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; } static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; } @@ -291,6 +291,19 @@ public: return is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); } + static _ALWAYS_INLINE_ float fract(float value) { + return value - floor(value); + } + static _ALWAYS_INLINE_ double fract(double value) { + return value - floor(value); + } + static _ALWAYS_INLINE_ float pingpong(float value, float length) { + return (length != 0.0f) ? abs(fract((value - length) / (length * 2.0f)) * length * 2.0f - length) : 0.0f; + } + static _ALWAYS_INLINE_ double pingpong(double value, double length) { + return (length != 0.0) ? abs(fract((value - length) / (length * 2.0)) * length * 2.0 - length) : 0.0; + } + // double only, as these functions are mainly used by the editor and not performance-critical, static double ease(double p_x, double p_c); static int step_decimals(double p_step); @@ -305,6 +318,7 @@ public: static uint32_t rand(); static _ALWAYS_INLINE_ double randd() { return (double)rand() / (double)Math::RANDOM_32BIT_MAX; } static _ALWAYS_INLINE_ float randf() { return (float)rand() / (float)Math::RANDOM_32BIT_MAX; } + static double randfn(double mean, double deviation); static double random(double from, double to); static float random(float from, float to); @@ -461,7 +475,7 @@ public: mantissa = 0; } hf = (((uint16_t)sign) << 15) | (uint16_t)((0x1F << 10)) | - (uint16_t)(mantissa >> 13); + (uint16_t)(mantissa >> 13); } // check if exponent is <= -15 else if (exp <= 0x38000000) { @@ -474,8 +488,8 @@ public: hf = 0; //denormals do not work for 3D, convert to zero } else { hf = (((uint16_t)sign) << 15) | - (uint16_t)((exp - 0x38000000) >> 13) | - (uint16_t)(mantissa >> 13); + (uint16_t)((exp - 0x38000000) >> 13) | + (uint16_t)(mantissa >> 13); } return hf; diff --git a/core/math/plane.cpp b/core/math/plane.cpp index 3c78b55b90..59f7918258 100644 --- a/core/math/plane.cpp +++ b/core/math/plane.cpp @@ -88,7 +88,7 @@ bool Plane::intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r *r_result = ((vec3_cross(normal1, normal2) * p_plane0.d) + (vec3_cross(normal2, normal0) * p_plane1.d) + (vec3_cross(normal0, normal1) * p_plane2.d)) / - denom; + denom; } return true; diff --git a/core/math/plane.h b/core/math/plane.h index 2267b28c53..18be5d5d12 100644 --- a/core/math/plane.h +++ b/core/math/plane.h @@ -85,8 +85,8 @@ public: normal(p_a, p_b, p_c), d(p_d) {} - _FORCE_INLINE_ Plane(const Vector3 &p_normal, real_t p_d); - _FORCE_INLINE_ Plane(const Vector3 &p_point, const Vector3 &p_normal); + _FORCE_INLINE_ 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); }; @@ -109,7 +109,7 @@ Plane::Plane(const Vector3 &p_normal, real_t p_d) : d(p_d) { } -Plane::Plane(const Vector3 &p_point, const Vector3 &p_normal) : +Plane::Plane(const Vector3 &p_normal, const Vector3 &p_point) : normal(p_normal), d(p_normal.dot(p_point)) { } diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp index 3f1d2c58e5..944474686a 100644 --- a/core/math/quaternion.cpp +++ b/core/math/quaternion.cpp @@ -44,7 +44,7 @@ real_t Quaternion::angle_to(const Quaternion &p_to) const { // This implementation uses XYZ convention (Z is the first rotation). Vector3 Quaternion::get_euler_xyz() const { Basis m(*this); - return m.get_euler_xyz(); + return m.get_euler(Basis::EULER_ORDER_XYZ); } // get_euler_yxz returns a vector containing the Euler angles in the format @@ -56,7 +56,7 @@ Vector3 Quaternion::get_euler_yxz() const { ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized."); #endif Basis m(*this); - return m.get_euler_yxz(); + return m.get_euler(Basis::EULER_ORDER_YXZ); } void Quaternion::operator*=(const Quaternion &p_q) { @@ -189,6 +189,15 @@ Quaternion::operator String() const { return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")"; } +Vector3 Quaternion::get_axis() const { + real_t r = ((real_t)1) / Math::sqrt(1 - w * w); + return Vector3(x * r, y * r, z * r); +} + +float Quaternion::get_angle() const { + return 2 * Math::acos(w); +} + Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) { #ifdef MATH_CHECKS ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized."); diff --git a/core/math/quaternion.h b/core/math/quaternion.h index 35324323b3..457d167516 100644 --- a/core/math/quaternion.h +++ b/core/math/quaternion.h @@ -72,6 +72,9 @@ public: Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const; Quaternion cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const; + Vector3 get_axis() const; + float get_angle() const; + _FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { r_angle = 2 * Math::acos(w); real_t r = ((real_t)1) / Math::sqrt(1 - w * w); @@ -83,13 +86,6 @@ public: void operator*=(const Quaternion &p_q); Quaternion operator*(const Quaternion &p_q) const; - Quaternion operator*(const Vector3 &v) const { - return Quaternion(w * v.x + y * v.z - z * v.y, - w * v.y + z * v.x - x * v.z, - w * v.z + x * v.y - y * v.x, - -x * v.x - y * v.y - z * v.z); - } - _FORCE_INLINE_ Vector3 xform(const Vector3 &v) const { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(!is_normalized(), v, "The quaternion must be normalized."); @@ -138,12 +134,11 @@ public: w(p_q.w) { } - Quaternion &operator=(const Quaternion &p_q) { + void operator=(const Quaternion &p_q) { x = p_q.x; y = p_q.y; z = p_q.z; w = p_q.w; - return *this; } Quaternion(const Vector3 &v0, const Vector3 &v1) // shortest arc diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index 0960fe19a6..d438a9a377 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -265,8 +265,8 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ //create new faces from horizon edges List<List<Face>::Element *> new_faces; //new faces - for (Map<Edge, FaceConnect>::Element *E = lit_edges.front(); E; E = E->next()) { - FaceConnect &fc = E->get(); + for (KeyValue<Edge, FaceConnect> &E : lit_edges) { + FaceConnect &fc = E.value; if (fc.left && fc.right) { continue; //edge is uninteresting, not on horizon } @@ -275,8 +275,8 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ Face face; face.vertices[0] = f.points_over[next]; - face.vertices[1] = E->key().vertices[0]; - face.vertices[2] = E->key().vertices[1]; + face.vertices[1] = E.key.vertices[0]; + face.vertices[2] = E.key.vertices[1]; Plane p(p_points[face.vertices[0]], p_points[face.vertices[1]], p_points[face.vertices[2]]); @@ -418,13 +418,13 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ } // remove all edge connections to this face - for (Map<Edge, RetFaceConnect>::Element *G = ret_edges.front(); G; G = G->next()) { - if (G->get().left == O) { - G->get().left = nullptr; + for (KeyValue<Edge, RetFaceConnect> &G : ret_edges) { + if (G.value.left == O) { + G.value.left = nullptr; } - if (G->get().right == O) { - G->get().right = nullptr; + if (G.value.right == O) { + G.value.right = nullptr; } } @@ -444,10 +444,10 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ } r_mesh.edges.resize(ret_edges.size()); idx = 0; - for (Map<Edge, RetFaceConnect>::Element *E = ret_edges.front(); E; E = E->next()) { + for (const KeyValue<Edge, RetFaceConnect> &E : ret_edges) { Geometry3D::MeshData::Edge e; - e.a = E->key().vertices[0]; - e.b = E->key().vertices[1]; + e.a = E.key.vertices[0]; + e.b = E.key.vertices[1]; r_mesh.edges.write[idx++] = e; } diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp index f64bf560c8..0e6127b017 100644 --- a/core/math/rect2.cpp +++ b/core/math/rect2.cpp @@ -35,6 +35,11 @@ bool Rect2::is_equal_approx(const Rect2 &p_rect) const { } bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || 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 real_t min = 0, max = 1; int axis = 0; real_t sign = 0; @@ -95,6 +100,11 @@ bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 } bool Rect2::intersects_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 //SAT intersection between local and transformed rect2 Vector2 xf_points[4] = { diff --git a/core/math/rect2.h b/core/math/rect2.h index ab0b489b4a..7029204cf1 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -46,7 +46,14 @@ struct Rect2 { real_t get_area() const { return size.width * size.height; } + _FORCE_INLINE_ Vector2 get_center() const { return position + (size * 0.5); } + inline bool intersects(const Rect2 &p_rect, const bool p_include_borders = false) 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 (p_include_borders) { if (position.x > (p_rect.position.x + p_rect.size.width)) { return false; @@ -79,6 +86,11 @@ struct Rect2 { } inline real_t distance_to(const Vector2 &p_point) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || 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 real_t dist = 0.0; bool inside = true; @@ -115,9 +127,14 @@ struct Rect2 { bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos = nullptr, Point2 *r_normal = nullptr) const; inline bool encloses(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 return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) && - ((p_rect.position.x + p_rect.size.x) <= (position.x + size.x)) && - ((p_rect.position.y + p_rect.size.y) <= (position.y + size.y)); + ((p_rect.position.x + p_rect.size.x) <= (position.x + size.x)) && + ((p_rect.position.y + p_rect.size.y) <= (position.y + size.y)); } _FORCE_INLINE_ bool has_no_area() const { @@ -145,7 +162,11 @@ struct Rect2 { } inline Rect2 merge(const Rect2 &p_rect) const { ///< return a merged rect - +#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 Rect2 new_rect; new_rect.position.x = MIN(p_rect.position.x, position.x); @@ -159,6 +180,11 @@ struct Rect2 { return new_rect; } inline bool has_point(const Point2 &p_point) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || 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 (p_point.x < position.x) { return false; } @@ -181,6 +207,11 @@ struct Rect2 { bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; } inline Rect2 grow(real_t p_amount) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || 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 Rect2 g = *this; g.grow_by(p_amount); return g; @@ -207,6 +238,11 @@ struct Rect2 { } inline Rect2 grow_individual(real_t p_left, real_t p_top, real_t p_right, real_t p_bottom) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || 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 Rect2 g = *this; g.position.x -= p_left; g.position.y -= p_top; @@ -223,7 +259,11 @@ struct Rect2 { } inline void expand_to(const Vector2 &p_vector) { //in place function for speed - +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || 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 Vector2 begin = position; Vector2 end = position + size; @@ -255,11 +295,11 @@ struct Rect2 { return Vector2( (p_normal.x > 0) ? -half_extents.x : half_extents.x, (p_normal.y > 0) ? -half_extents.y : half_extents.y) + - ofs; + ofs; } _FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const { - Vector2 center = position + size * 0.5; + Vector2 center = get_center(); int side_plus = 0; int side_minus = 0; Vector2 end = position + size; @@ -344,7 +384,14 @@ struct Rect2i { int get_area() const { return size.width * size.height; } + _FORCE_INLINE_ Vector2i get_center() const { return position + (size / 2); } + inline bool intersects(const Rect2i &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("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size."); + } +#endif if (position.x > (p_rect.position.x + p_rect.size.width)) { return false; } @@ -362,9 +409,14 @@ struct Rect2i { } inline bool encloses(const Rect2i &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("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size."); + } +#endif return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) && - ((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) && - ((p_rect.position.y + p_rect.size.y) < (position.y + size.y)); + ((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) && + ((p_rect.position.y + p_rect.size.y) < (position.y + size.y)); } _FORCE_INLINE_ bool has_no_area() const { @@ -385,14 +437,18 @@ struct Rect2i { Point2i p_rect_end = p_rect.position + p_rect.size; Point2i end = position + size; - new_rect.size.x = (int)(MIN(p_rect_end.x, end.x) - new_rect.position.x); - new_rect.size.y = (int)(MIN(p_rect_end.y, end.y) - new_rect.position.y); + new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x; + new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y; return new_rect; } inline Rect2i merge(const Rect2i &p_rect) const { ///< return a merged rect - +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) { + ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size."); + } +#endif Rect2i new_rect; new_rect.position.x = MIN(p_rect.position.x, position.x); @@ -406,6 +462,11 @@ struct Rect2i { return new_rect; } bool has_point(const Point2i &p_point) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || size.y < 0)) { + ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size."); + } +#endif if (p_point.x < position.x) { return false; } @@ -427,6 +488,11 @@ struct Rect2i { bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; } Rect2i grow(int p_amount) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || size.y < 0)) { + ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size."); + } +#endif Rect2i g = *this; g.position.x -= p_amount; g.position.y -= p_amount; @@ -449,6 +515,11 @@ struct Rect2i { } inline Rect2i grow_individual(int p_left, int p_top, int p_right, int p_bottom) const { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || size.y < 0)) { + ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size."); + } +#endif Rect2i g = *this; g.position.x -= p_left; g.position.y -= p_top; @@ -465,6 +536,11 @@ struct Rect2i { } inline void expand_to(const Point2i &p_vector) { +#ifdef MATH_CHECKS + if (unlikely(size.x < 0 || size.y < 0)) { + ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size."); + } +#endif Point2i begin = position; Point2i end = position + size; diff --git a/core/math/static_raycaster.cpp b/core/math/static_raycaster.cpp new file mode 100644 index 0000000000..da05d49428 --- /dev/null +++ b/core/math/static_raycaster.cpp @@ -0,0 +1,40 @@ +/*************************************************************************/ +/* static_raycaster.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "static_raycaster.h" + +StaticRaycaster *(*StaticRaycaster::create_function)() = nullptr; + +Ref<StaticRaycaster> StaticRaycaster::create() { + if (create_function) { + return Ref<StaticRaycaster>(create_function()); + } + return Ref<StaticRaycaster>(); +} diff --git a/core/math/static_raycaster.h b/core/math/static_raycaster.h new file mode 100644 index 0000000000..3759c788a7 --- /dev/null +++ b/core/math/static_raycaster.h @@ -0,0 +1,111 @@ +/*************************************************************************/ +/* static_raycaster.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef STATIC_RAYCASTER_H +#define STATIC_RAYCASTER_H + +#include "core/object/ref_counted.h" + +#if !defined(__aligned) + +#if defined(_WIN32) && defined(_MSC_VER) +#define __aligned(...) __declspec(align(__VA_ARGS__)) +#else +#define __aligned(...) __attribute__((aligned(__VA_ARGS__))) +#endif + +#endif + +class StaticRaycaster : public RefCounted { + GDCLASS(StaticRaycaster, RefCounted) +protected: + static StaticRaycaster *(*create_function)(); + +public: + // compatible with embree3 rays + struct __aligned(16) Ray { + const static unsigned int INVALID_GEOMETRY_ID = ((unsigned int)-1); // from rtcore_common.h + + /*! Default construction does nothing. */ + _FORCE_INLINE_ Ray() : + geomID(INVALID_GEOMETRY_ID) {} + + /*! Constructs a ray from origin, direction, and ray segment. Near + * has to be smaller than far. */ + _FORCE_INLINE_ Ray(const Vector3 &org, + const Vector3 &dir, + float tnear = 0.0f, + float tfar = INFINITY) : + org(org), + tnear(tnear), + dir(dir), + time(0.0f), + tfar(tfar), + mask(-1), + u(0.0), + v(0.0), + primID(INVALID_GEOMETRY_ID), + geomID(INVALID_GEOMETRY_ID), + instID(INVALID_GEOMETRY_ID) {} + + /*! Tests if we hit something. */ + _FORCE_INLINE_ explicit operator bool() const { return geomID != INVALID_GEOMETRY_ID; } + + public: + Vector3 org; //!< Ray origin + tnear + float tnear; //!< Start of ray segment + Vector3 dir; //!< Ray direction + tfar + float time; //!< Time of this ray for motion blur. + float tfar; //!< End of ray segment + unsigned int mask; //!< used to mask out objects during traversal + unsigned int id; //!< ray ID + unsigned int flags; //!< ray flags + + Vector3 normal; //!< Not normalized geometry normal + float u; //!< Barycentric u coordinate of hit + float v; //!< Barycentric v coordinate of hit + unsigned int primID; //!< primitive ID + unsigned int geomID; //!< geometry ID + unsigned int instID; //!< instance ID + }; + + virtual bool intersect(Ray &p_ray) = 0; + virtual void intersect(Vector<Ray> &r_rays) = 0; + + virtual void add_mesh(const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices, unsigned int p_id) = 0; + virtual void commit() = 0; + + virtual void set_mesh_filter(const Set<int> &p_mesh_ids) = 0; + virtual void clear_mesh_filter() = 0; + + static Ref<StaticRaycaster> create(); +}; + +#endif // STATIC_RAYCASTER_H diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 16934d67df..4bdeaa2a58 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -63,25 +63,25 @@ Transform2D Transform2D::affine_inverse() const { return inv; } -void Transform2D::rotate(real_t p_phi) { +void Transform2D::rotate(const real_t p_phi) { *this = Transform2D(p_phi, Vector2()) * (*this); } real_t Transform2D::get_skew() const { real_t det = basis_determinant(); - return Math::acos(elements[0].normalized().dot(SGN(det) * elements[1].normalized())) - Math_PI * 0.5; + return Math::acos(elements[0].normalized().dot(SIGN(det) * elements[1].normalized())) - Math_PI * 0.5; } -void Transform2D::set_skew(float p_angle) { +void Transform2D::set_skew(const real_t p_angle) { real_t det = basis_determinant(); - elements[1] = SGN(det) * elements[0].rotated((Math_PI * 0.5 + p_angle)).normalized() * elements[1].length(); + elements[1] = SIGN(det) * elements[0].rotated((Math_PI * 0.5 + p_angle)).normalized() * elements[1].length(); } real_t Transform2D::get_rotation() const { return Math::atan2(elements[0].y, elements[0].x); } -void Transform2D::set_rotation(real_t p_rot) { +void Transform2D::set_rotation(const real_t p_rot) { Size2 scale = get_scale(); real_t cr = Math::cos(p_rot); real_t sr = Math::sin(p_rot); @@ -92,7 +92,7 @@ void Transform2D::set_rotation(real_t p_rot) { set_scale(scale); } -Transform2D::Transform2D(real_t p_rot, const Vector2 &p_pos) { +Transform2D::Transform2D(const real_t p_rot, const Vector2 &p_pos) { real_t cr = Math::cos(p_rot); real_t sr = Math::sin(p_rot); elements[0][0] = cr; @@ -102,8 +102,16 @@ Transform2D::Transform2D(real_t p_rot, const Vector2 &p_pos) { elements[2] = p_pos; } +Transform2D::Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos) { + elements[0][0] = Math::cos(p_rot) * p_scale.x; + elements[1][1] = Math::cos(p_rot + p_skew) * p_scale.y; + elements[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y; + elements[0][1] = Math::sin(p_rot) * p_scale.x; + elements[2] = p_pos; +} + Size2 Transform2D::get_scale() const { - real_t det_sign = SGN(basis_determinant()); + real_t det_sign = SIGN(basis_determinant()); return Size2(elements[0].length(), det_sign * elements[1].length()); } @@ -126,7 +134,7 @@ void Transform2D::scale_basis(const Size2 &p_scale) { elements[1][1] *= p_scale.y; } -void Transform2D::translate(real_t p_tx, real_t p_ty) { +void Transform2D::translate(const real_t p_tx, const real_t p_ty) { translate(Vector2(p_tx, p_ty)); } @@ -231,7 +239,7 @@ Transform2D Transform2D::translated(const Vector2 &p_offset) const { return copy; } -Transform2D Transform2D::rotated(real_t p_phi) const { +Transform2D Transform2D::rotated(const real_t p_phi) const { Transform2D copy = *this; copy.rotate(p_phi); return copy; @@ -241,7 +249,7 @@ real_t Transform2D::basis_determinant() const { return elements[0].x * elements[1].y - elements[0].y * elements[1].x; } -Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t p_c) const { +Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, const real_t p_c) const { //extract parameters Vector2 p1 = get_origin(); Vector2 p2 = p_transform.get_origin(); @@ -271,7 +279,7 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t } //construct matrix - Transform2D res(Math::atan2(v.y, v.x), p1.lerp(p2, p_c)); + Transform2D res(v.angle(), p1.lerp(p2, p_c)); res.scale_basis(s1.lerp(s2, p_c)); return res; } @@ -290,6 +298,6 @@ Transform2D Transform2D::operator*(const real_t p_val) const { Transform2D::operator String() const { return "[X: " + elements[0].operator String() + - ", Y: " + elements[1].operator String() + - ", O: " + elements[2].operator String() + "]"; + ", Y: " + elements[1].operator String() + + ", O: " + elements[2].operator String() + "]"; } diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index 34cfd0c1a9..8a0e876d96 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -68,17 +68,17 @@ struct Transform2D { void affine_invert(); Transform2D affine_inverse() const; - void set_rotation(real_t p_rot); + void set_rotation(const real_t p_rot); real_t get_rotation() const; real_t get_skew() const; - void set_skew(float p_angle); - _FORCE_INLINE_ void set_rotation_and_scale(real_t p_rot, const Size2 &p_scale); - _FORCE_INLINE_ void set_rotation_scale_and_skew(real_t p_rot, const Size2 &p_scale, float p_skew); - void rotate(real_t p_phi); + void set_skew(const real_t p_angle); + _FORCE_INLINE_ void set_rotation_and_scale(const real_t p_rot, const Size2 &p_scale); + _FORCE_INLINE_ void set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew); + void rotate(const real_t p_phi); void scale(const Size2 &p_scale); void scale_basis(const Size2 &p_scale); - void translate(real_t p_tx, real_t p_ty); + void translate(const real_t p_tx, const real_t p_ty); void translate(const Vector2 &p_translation); real_t basis_determinant() const; @@ -92,7 +92,7 @@ struct Transform2D { Transform2D scaled(const Size2 &p_scale) const; Transform2D basis_scaled(const Size2 &p_scale) const; Transform2D translated(const Vector2 &p_offset) const; - Transform2D rotated(real_t p_phi) const; + Transform2D rotated(const real_t p_phi) const; Transform2D untranslated() const; @@ -110,7 +110,7 @@ struct Transform2D { void operator*=(const real_t p_val); Transform2D operator*(const real_t p_val) const; - Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const; + Transform2D interpolate_with(const Transform2D &p_transform, const real_t p_c) const; _FORCE_INLINE_ Vector2 basis_xform(const Vector2 &p_vec) const; _FORCE_INLINE_ Vector2 basis_xform_inv(const Vector2 &p_vec) const; @@ -123,7 +123,7 @@ struct Transform2D { operator String() const; - Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy) { + Transform2D(const real_t xx, const real_t xy, const real_t yx, const real_t yy, const real_t ox, const real_t oy) { elements[0][0] = xx; elements[0][1] = xy; elements[1][0] = yx; @@ -138,7 +138,10 @@ struct Transform2D { elements[2] = p_origin; } - Transform2D(real_t p_rot, const Vector2 &p_pos); + Transform2D(const real_t p_rot, const Vector2 &p_pos); + + Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos); + Transform2D() { elements[0][0] = 1.0; elements[1][1] = 1.0; @@ -161,7 +164,7 @@ Vector2 Transform2D::xform(const Vector2 &p_vec) const { return Vector2( tdotx(p_vec), tdoty(p_vec)) + - elements[2]; + elements[2]; } Vector2 Transform2D::xform_inv(const Vector2 &p_vec) const { @@ -185,14 +188,14 @@ Rect2 Transform2D::xform(const Rect2 &p_rect) const { return new_rect; } -void Transform2D::set_rotation_and_scale(real_t p_rot, const Size2 &p_scale) { +void Transform2D::set_rotation_and_scale(const real_t p_rot, const Size2 &p_scale) { elements[0][0] = Math::cos(p_rot) * p_scale.x; elements[1][1] = Math::cos(p_rot) * p_scale.y; elements[1][0] = -Math::sin(p_rot) * p_scale.y; elements[0][1] = Math::sin(p_rot) * p_scale.x; } -void Transform2D::set_rotation_scale_and_skew(real_t p_rot, const Size2 &p_scale, float p_skew) { +void Transform2D::set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew) { elements[0][0] = Math::cos(p_rot) * p_scale.x; elements[1][1] = Math::cos(p_rot + p_skew) * p_scale.y; elements[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y; diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp index 4f4943c8ef..78ef117443 100644 --- a/core/math/transform_3d.cpp +++ b/core/math/transform_3d.cpp @@ -175,9 +175,9 @@ Transform3D Transform3D::operator*(const real_t p_val) const { Transform3D::operator String() const { return "[X: " + basis.get_axis(0).operator String() + - ", Y: " + basis.get_axis(1).operator String() + - ", Z: " + basis.get_axis(2).operator String() + - ", O: " + origin.operator String() + "]"; + ", Y: " + basis.get_axis(1).operator String() + + ", Z: " + basis.get_axis(2).operator String() + + ", O: " + origin.operator String() + "]"; } Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) : diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index bf06c848c5..2f3da0b6a8 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -76,7 +76,7 @@ int TriangleMesh::_create_bvh(BVH *p_bvh, BVH **p_bb, int p_from, int p_size, in int index = r_max_alloc++; BVH *_new = &p_bvh[index]; _new->aabb = aabb; - _new->center = aabb.position + aabb.size * 0.5; + _new->center = aabb.get_center(); _new->face_index = -1; _new->left = left; _new->right = right; @@ -152,13 +152,13 @@ void TriangleMesh::create(const Vector<Vector3> &p_faces) { bw[i].left = -1; bw[i].right = -1; bw[i].face_index = i; - bw[i].center = bw[i].aabb.position + bw[i].aabb.size * 0.5; + bw[i].center = bw[i].aabb.get_center(); } vertices.resize(db.size()); Vector3 *vw = vertices.ptrw(); - for (Map<Vector3, int>::Element *E = db.front(); E; E = E->next()) { - vw[E->get()] = E->key(); + for (const KeyValue<Vector3, int> &E : db) { + vw[E.value] = E.key; } } diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h index 463b0dd5c8..2d3b4db4bb 100644 --- a/core/math/triangle_mesh.h +++ b/core/math/triangle_mesh.h @@ -37,11 +37,13 @@ class TriangleMesh : public RefCounted { GDCLASS(TriangleMesh, RefCounted); +public: struct Triangle { Vector3 normal; int indices[3]; }; +private: Vector<Triangle> triangles; Vector<Vector3> vertices; @@ -86,8 +88,8 @@ public: Vector3 get_area_normal(const AABB &p_aabb) const; Vector<Face3> get_faces() const; - Vector<Triangle> get_triangles() const { return triangles; } - Vector<Vector3> get_vertices() const { return vertices; } + const Vector<Triangle> &get_triangles() const { return triangles; } + const Vector<Vector3> &get_vertices() const { return vertices; } void get_indices(Vector<int> *r_triangles_indices) const; void create(const Vector<Vector3> &p_faces); diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp index fa1588dbc5..28f1d96b14 100644 --- a/core/math/triangulate.cpp +++ b/core/math/triangulate.cpp @@ -42,18 +42,13 @@ real_t Triangulate::get_area(const Vector<Vector2> &contour) { return A * 0.5; } -/* - is_inside_triangle decides if a point P is Inside of the triangle - defined by A, B, C. - */ - +/* `is_inside_triangle` decides if a point P is inside the triangle + * defined by A, B, C. */ bool Triangulate::is_inside_triangle(real_t Ax, real_t Ay, real_t Bx, real_t By, real_t Cx, real_t Cy, real_t Px, real_t Py, - bool include_edges) - -{ + bool include_edges) { real_t ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; real_t cCROSSap, bCROSScp, aCROSSbp; diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index 54abc1b7f2..718e94eee4 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -34,6 +34,10 @@ real_t Vector2::angle() const { return Math::atan2(y, x); } +Vector2 Vector2::from_angle(const real_t p_angle) { + return Vector2(Math::cos(p_angle), Math::sin(p_angle)); +} + real_t Vector2::length() const { return Math::sqrt(x * x + y * y); } @@ -75,7 +79,7 @@ real_t Vector2::angle_to(const Vector2 &p_vector2) const { } real_t Vector2::angle_to_point(const Vector2 &p_vector2) const { - return Math::atan2(y - p_vector2.y, x - p_vector2.x); + return (p_vector2 - *this).angle(); } real_t Vector2::dot(const Vector2 &p_other) const { @@ -87,7 +91,7 @@ real_t Vector2::cross(const Vector2 &p_other) const { } Vector2 Vector2::sign() const { - return Vector2(SGN(x), SGN(y)); + return Vector2(SIGN(x), SIGN(y)); } Vector2 Vector2::floor() const { @@ -156,10 +160,11 @@ Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, c real_t t3 = t2 * t; Vector2 out; - out = 0.5 * ((p1 * 2.0) + - (-p0 + p2) * t + - (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + - (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); + out = 0.5 * + ((p1 * 2.0) + + (-p0 + p2) * t + + (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); return out; } diff --git a/core/math/vector2.h b/core/math/vector2.h index 330b4741b1..c0a189e040 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -70,12 +70,12 @@ struct Vector2 { x = y = p_value; } - _FORCE_INLINE_ int min_axis() const { - return x < y ? 0 : 1; + _FORCE_INLINE_ Vector2::Axis min_axis_index() const { + return x < y ? Vector2::AXIS_X : Vector2::AXIS_Y; } - _FORCE_INLINE_ int max_axis() const { - return x < y ? 1 : 0; + _FORCE_INLINE_ Vector2::Axis max_axis_index() const { + return x < y ? Vector2::AXIS_Y : Vector2::AXIS_X; } void normalize(); @@ -147,6 +147,7 @@ struct Vector2 { 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(const real_t p_angle); _FORCE_INLINE_ Vector2 abs() const { return Vector2(Math::abs(x), Math::abs(y)); @@ -300,12 +301,12 @@ struct Vector2i { return p_idx ? y : x; } - _FORCE_INLINE_ int min_axis() const { - return x < y ? 0 : 1; + _FORCE_INLINE_ Vector2i::Axis min_axis_index() const { + return x < y ? Vector2i::AXIS_X : Vector2i::AXIS_Y; } - _FORCE_INLINE_ int max_axis() const { - return x < y ? 1 : 0; + _FORCE_INLINE_ Vector2i::Axis max_axis_index() const { + return x < y ? Vector2i::AXIS_Y : Vector2i::AXIS_X; } Vector2i min(const Vector2i &p_vector2i) const { @@ -344,7 +345,7 @@ struct Vector2i { bool operator!=(const Vector2i &p_vec2) const; real_t aspect() const { return width / (real_t)height; } - Vector2i sign() const { return Vector2i(SGN(x), SGN(y)); } + Vector2i sign() const { return Vector2i(SIGN(x), SIGN(y)); } Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); } Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const; diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index 401c3ccd9c..b9bd04b8c1 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -93,10 +93,11 @@ Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, c real_t t3 = t2 * t; Vector3 out; - out = 0.5 * ((p1 * 2.0) + - (-p0 + p2) * t + - (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + - (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); + out = 0.5 * + ((p1 * 2.0) + + (-p0 + p2) * t + + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); return out; } @@ -107,20 +108,14 @@ Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const { return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta; } -Basis Vector3::outer(const Vector3 &p_b) const { - Vector3 row0(x * p_b.x, x * p_b.y, x * p_b.z); - Vector3 row1(y * p_b.x, y * p_b.y, y * p_b.z); - Vector3 row2(z * p_b.x, z * p_b.y, z * p_b.z); +Basis Vector3::outer(const Vector3 &p_with) const { + Vector3 row0(x * p_with.x, x * p_with.y, x * p_with.z); + Vector3 row1(y * p_with.x, y * p_with.y, y * p_with.z); + Vector3 row2(z * p_with.x, z * p_with.y, z * p_with.z); return Basis(row0, row1, row2); } -Basis Vector3::to_diagonal_matrix() const { - return Basis(x, 0, 0, - 0, y, 0, - 0, 0, z); -} - 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); } diff --git a/core/math/vector3.h b/core/math/vector3.h index 6a4c42f41b..c0f80e8f11 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -32,9 +32,9 @@ #define VECTOR3_H #include "core/math/math_funcs.h" +#include "core/math/vector2.h" #include "core/math/vector3i.h" #include "core/string/ustring.h" - class Basis; struct Vector3 { @@ -71,12 +71,12 @@ struct Vector3 { x = y = z = p_value; } - _FORCE_INLINE_ int min_axis() const { - return x < y ? (x < z ? 0 : 2) : (y < z ? 1 : 2); + _FORCE_INLINE_ Vector3::Axis min_axis_index() const { + return x < y ? (x < z ? Vector3::AXIS_X : Vector3::AXIS_Z) : (y < z ? Vector3::AXIS_Y : Vector3::AXIS_Z); } - _FORCE_INLINE_ int max_axis() const { - return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0); + _FORCE_INLINE_ Vector3::Axis max_axis_index() const { + return x < y ? (y < z ? Vector3::AXIS_Z : Vector3::AXIS_Y) : (x < z ? Vector3::AXIS_Z : Vector3::AXIS_X); } _FORCE_INLINE_ real_t length() const; @@ -103,10 +103,34 @@ struct Vector3 { Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const; Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const; - _FORCE_INLINE_ Vector3 cross(const Vector3 &p_b) const; - _FORCE_INLINE_ real_t dot(const Vector3 &p_b) const; - Basis outer(const Vector3 &p_b) const; - Basis to_diagonal_matrix() const; + _FORCE_INLINE_ Vector2 octahedron_encode() const { + Vector3 n = *this; + n /= Math::abs(n.x) + Math::abs(n.y) + Math::abs(n.z); + Vector2 o; + if (n.z >= 0.0) { + o.x = n.x; + o.y = n.y; + } else { + o.x = (1.0 - Math::abs(n.y)) * (n.x >= 0.0 ? 1.0 : -1.0); + o.y = (1.0 - Math::abs(n.x)) * (n.y >= 0.0 ? 1.0 : -1.0); + } + o.x = o.x * 0.5 + 0.5; + o.y = o.y * 0.5 + 0.5; + return o; + } + + static _FORCE_INLINE_ Vector3 octahedron_decode(const Vector2 &p_oct) { + Vector2 f(p_oct.x * 2.0 - 1.0, p_oct.y * 2.0 - 1.0); + Vector3 n(f.x, f.y, 1.0f - Math::abs(f.x) - Math::abs(f.y)); + float t = CLAMP(-n.z, 0.0, 1.0); + n.x += n.x >= 0 ? -t : t; + n.y += n.y >= 0 ? -t : t; + return n.normalized(); + } + + _FORCE_INLINE_ Vector3 cross(const Vector3 &p_with) const; + _FORCE_INLINE_ real_t dot(const Vector3 &p_with) const; + Basis outer(const Vector3 &p_with) const; _FORCE_INLINE_ Vector3 abs() const; _FORCE_INLINE_ Vector3 floor() const; @@ -175,17 +199,17 @@ struct Vector3 { } }; -Vector3 Vector3::cross(const Vector3 &p_b) const { +Vector3 Vector3::cross(const Vector3 &p_with) const { Vector3 ret( - (y * p_b.z) - (z * p_b.y), - (z * p_b.x) - (x * p_b.z), - (x * p_b.y) - (y * p_b.x)); + (y * p_with.z) - (z * p_with.y), + (z * p_with.x) - (x * p_with.z), + (x * p_with.y) - (y * p_with.x)); return ret; } -real_t Vector3::dot(const Vector3 &p_b) const { - return x * p_b.x + y * p_b.y + z * p_b.z; +real_t Vector3::dot(const Vector3 &p_with) const { + return x * p_with.x + y * p_with.y + z * p_with.z; } Vector3 Vector3::abs() const { @@ -193,7 +217,7 @@ Vector3 Vector3::abs() const { } Vector3 Vector3::sign() const { - return Vector3(SGN(x), SGN(y), SGN(z)); + return Vector3(SIGN(x), SIGN(y), SIGN(z)); } Vector3 Vector3::floor() const { diff --git a/core/math/vector3i.cpp b/core/math/vector3i.cpp index d3a57af77c..7812a0b41c 100644 --- a/core/math/vector3i.cpp +++ b/core/math/vector3i.cpp @@ -40,12 +40,12 @@ int32_t Vector3i::get_axis(const int p_axis) const { return operator[](p_axis); } -int Vector3i::min_axis() const { - return x < y ? (x < z ? 0 : 2) : (y < z ? 1 : 2); +Vector3i::Axis Vector3i::min_axis_index() const { + return x < y ? (x < z ? Vector3i::AXIS_X : Vector3i::AXIS_Z) : (y < z ? Vector3i::AXIS_Y : Vector3i::AXIS_Z); } -int Vector3i::max_axis() const { - return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0); +Vector3i::Axis Vector3i::max_axis_index() const { + return x < y ? (y < z ? Vector3i::AXIS_Z : Vector3i::AXIS_Y) : (x < z ? Vector3i::AXIS_Z : Vector3i::AXIS_X); } Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const { diff --git a/core/math/vector3i.h b/core/math/vector3i.h index 9308d09045..fba29a1f8d 100644 --- a/core/math/vector3i.h +++ b/core/math/vector3i.h @@ -62,8 +62,8 @@ struct Vector3i { void set_axis(const int p_axis, const int32_t p_value); int32_t get_axis(const int p_axis) const; - int min_axis() const; - int max_axis() const; + Vector3i::Axis min_axis_index() const; + Vector3i::Axis max_axis_index() const; _FORCE_INLINE_ void zero(); @@ -115,7 +115,7 @@ Vector3i Vector3i::abs() const { } Vector3i Vector3i::sign() const { - return Vector3i(SGN(x), SGN(y), SGN(z)); + return Vector3i(SIGN(x), SIGN(y), SIGN(z)); } /* Operators */ |