diff options
Diffstat (limited to 'core/math')
43 files changed, 2227 insertions, 2145 deletions
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index 4212b43621..41a0848d01 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -33,21 +33,21 @@ #include "core/math/geometry_3d.h" #include "core/object/script_language.h" -int AStar3D::get_available_point_id() const { +int64_t AStar3D::get_available_point_id() const { if (points.has(last_free_id)) { - int cur_new_id = last_free_id + 1; + int64_t cur_new_id = last_free_id + 1; while (points.has(cur_new_id)) { cur_new_id++; } - const_cast<int &>(last_free_id) = cur_new_id; + const_cast<int64_t &>(last_free_id) = cur_new_id; } return last_free_id; } -void AStar3D::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) { +void AStar3D::add_point(int64_t p_id, const Vector3 &p_pos, real_t p_weight_scale) { 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)); + ERR_FAIL_COND_MSG(p_weight_scale < 0.0, vformat("Can't add a point with weight scale less than 0.0: %f.", p_weight_scale)); Point *found_pt; bool p_exists = points.lookup(p_id, found_pt); @@ -68,7 +68,7 @@ void AStar3D::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) { } } -Vector3 AStar3D::get_point_position(int p_id) const { +Vector3 AStar3D::get_point_position(int64_t p_id) const { Point *p; bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_V_MSG(!p_exists, Vector3(), vformat("Can't get point's position. Point with id: %d doesn't exist.", p_id)); @@ -76,7 +76,7 @@ Vector3 AStar3D::get_point_position(int p_id) const { return p->pos; } -void AStar3D::set_point_position(int p_id, const Vector3 &p_pos) { +void AStar3D::set_point_position(int64_t p_id, const Vector3 &p_pos) { Point *p; bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_MSG(!p_exists, vformat("Can't set point's position. Point with id: %d doesn't exist.", p_id)); @@ -84,7 +84,7 @@ void AStar3D::set_point_position(int p_id, const Vector3 &p_pos) { p->pos = p_pos; } -real_t AStar3D::get_point_weight_scale(int p_id) const { +real_t AStar3D::get_point_weight_scale(int64_t p_id) const { Point *p; bool p_exists = points.lookup(p_id, p); 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)); @@ -92,21 +92,21 @@ real_t AStar3D::get_point_weight_scale(int p_id) const { return p->weight_scale; } -void AStar3D::set_point_weight_scale(int p_id, real_t p_weight_scale) { +void AStar3D::set_point_weight_scale(int64_t p_id, real_t p_weight_scale) { Point *p; bool p_exists = points.lookup(p_id, p); 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)); + ERR_FAIL_COND_MSG(p_weight_scale < 0.0, vformat("Can't set point's weight scale less than 0.0: %f.", p_weight_scale)); p->weight_scale = p_weight_scale; } -void AStar3D::remove_point(int p_id) { +void AStar3D::remove_point(int64_t p_id) { Point *p; bool p_exists = points.lookup(p_id, p); 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)) { + for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { Segment s(p_id, (*it.key)); segments.erase(s); @@ -114,7 +114,7 @@ void AStar3D::remove_point(int p_id) { (*it.value)->unlinked_neighbours.remove(p->id); } - for (OAHashMap<int, Point *>::Iterator it = p->unlinked_neighbours.iter(); it.valid; it = p->unlinked_neighbours.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = p->unlinked_neighbours.iter(); it.valid; it = p->unlinked_neighbours.next_iter(it)) { Segment s(p_id, (*it.key)); segments.erase(s); @@ -127,7 +127,7 @@ void AStar3D::remove_point(int p_id) { last_free_id = p_id; } -void AStar3D::connect_points(int p_id, int p_with_id, bool bidirectional) { +void AStar3D::connect_points(int64_t p_id, int64_t p_with_id, bool bidirectional) { ERR_FAIL_COND_MSG(p_id == p_with_id, vformat("Can't connect point with id: %d to itself.", p_id)); Point *a; @@ -151,21 +151,21 @@ void AStar3D::connect_points(int p_id, int p_with_id, bool bidirectional) { s.direction = Segment::BIDIRECTIONAL; } - Set<Segment>::Element *element = segments.find(s); - if (element != nullptr) { - s.direction |= element->get().direction; + HashSet<Segment, Segment>::Iterator element = segments.find(s); + if (element) { + s.direction |= element->direction; if (s.direction == Segment::BIDIRECTIONAL) { // Both are neighbours of each other now a->unlinked_neighbours.remove(b->id); b->unlinked_neighbours.remove(a->id); } - segments.erase(element); + segments.remove(element); } segments.insert(s); } -void AStar3D::disconnect_points(int p_id, int p_with_id, bool bidirectional) { +void AStar3D::disconnect_points(int64_t p_id, int64_t p_with_id, bool bidirectional) { Point *a; bool a_exists = points.lookup(p_id, a); ERR_FAIL_COND_MSG(!a_exists, vformat("Can't disconnect points. Point with id: %d doesn't exist.", p_id)); @@ -175,18 +175,18 @@ void AStar3D::disconnect_points(int p_id, int p_with_id, bool bidirectional) { 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; + int remove_direction = bidirectional ? (int)Segment::BIDIRECTIONAL : (int)s.direction; - Set<Segment>::Element *element = segments.find(s); - if (element != nullptr) { + HashSet<Segment, Segment>::Iterator element = segments.find(s); + if (element) { // s is the new segment // Erase the directions to be removed - s.direction = (element->get().direction & ~remove_direction); + s.direction = (element->direction & ~remove_direction); a->neighbours.remove(b->id); if (bidirectional) { b->neighbours.remove(a->id); - if (element->get().direction != Segment::BIDIRECTIONAL) { + if (element->direction != Segment::BIDIRECTIONAL) { a->unlinked_neighbours.remove(b->id); b->unlinked_neighbours.remove(a->id); } @@ -198,77 +198,77 @@ void AStar3D::disconnect_points(int p_id, int p_with_id, bool bidirectional) { } } - segments.erase(element); + segments.remove(element); if (s.direction != Segment::NONE) { segments.insert(s); } } } -bool AStar3D::has_point(int p_id) const { +bool AStar3D::has_point(int64_t p_id) const { return points.has(p_id); } Array AStar3D::get_point_ids() { Array point_list; - for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { point_list.push_back(*(it.key)); } return point_list; } -Vector<int> AStar3D::get_point_connections(int p_id) { +Vector<int64_t> AStar3D::get_point_connections(int64_t p_id) { Point *p; bool p_exists = points.lookup(p_id, p); - 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)); + ERR_FAIL_COND_V_MSG(!p_exists, Vector<int64_t>(), vformat("Can't get point's connections. Point with id: %d doesn't exist.", p_id)); - Vector<int> point_list; + Vector<int64_t> point_list; - for (OAHashMap<int, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { point_list.push_back((*it.key)); } return point_list; } -bool AStar3D::are_points_connected(int p_id, int p_with_id, bool bidirectional) const { +bool AStar3D::are_points_connected(int64_t p_id, int64_t p_with_id, bool bidirectional) const { Segment s(p_id, p_with_id); - const Set<Segment>::Element *element = segments.find(s); + const HashSet<Segment, Segment>::Iterator element = segments.find(s); - return element != nullptr && - (bidirectional || (element->get().direction & s.direction) == s.direction); + return element && + (bidirectional || (element->direction & s.direction) == s.direction); } void AStar3D::clear() { last_free_id = 0; - for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { memdelete(*(it.value)); } segments.clear(); points.clear(); } -int AStar3D::get_point_count() const { +int64_t AStar3D::get_point_count() const { return points.get_num_elements(); } -int AStar3D::get_point_capacity() const { +int64_t AStar3D::get_point_capacity() const { return points.get_capacity(); } -void AStar3D::reserve_space(int p_num_nodes) { +void AStar3D::reserve_space(int64_t 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); } -int AStar3D::get_closest_point(const Vector3 &p_point, bool p_include_disabled) const { - int closest_id = -1; +int64_t AStar3D::get_closest_point(const Vector3 &p_point, bool p_include_disabled) const { + int64_t closest_id = -1; real_t closest_dist = 1e20; - for (OAHashMap<int, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { + for (OAHashMap<int64_t, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { if (!p_include_disabled && !(*it.value)->enabled) { continue; // Disabled points should not be considered. } @@ -276,7 +276,7 @@ int AStar3D::get_closest_point(const Vector3 &p_point, bool p_include_disabled) // Keep the closest point's ID, and in case of multiple closest IDs, // the smallest one (makes it deterministic). real_t d = p_point.distance_squared_to((*it.value)->pos); - int id = *(it.key); + int64_t id = *(it.key); if (d <= closest_dist) { if (d == closest_dist && id > closest_id) { // Keep lowest ID. continue; @@ -293,10 +293,10 @@ Vector3 AStar3D::get_closest_position_in_segment(const Vector3 &p_point) const { real_t closest_dist = 1e20; Vector3 closest_point; - for (const Set<Segment>::Element *E = segments.front(); E; E = E->next()) { + for (const Segment &E : segments) { Point *from_point = nullptr, *to_point = nullptr; - points.lookup(E->get().u, from_point); - points.lookup(E->get().v, to_point); + points.lookup(E.key.first, from_point); + points.lookup(E.key.second, to_point); if (!(from_point->enabled && to_point->enabled)) { continue; @@ -346,7 +346,7 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) { 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)) { + for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { Point *e = *(it.value); // The neighbour point if (!e->enabled || e->closed_pass == pass) { @@ -380,7 +380,7 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) { return found_route; } -real_t AStar3D::_estimate_cost(int p_from_id, int p_to_id) { +real_t AStar3D::_estimate_cost(int64_t p_from_id, int64_t p_to_id) { real_t scost; if (GDVIRTUAL_CALL(_estimate_cost, p_from_id, p_to_id, scost)) { return scost; @@ -397,7 +397,7 @@ real_t AStar3D::_estimate_cost(int p_from_id, int p_to_id) { return from_point->pos.distance_to(to_point->pos); } -real_t AStar3D::_compute_cost(int p_from_id, int p_to_id) { +real_t AStar3D::_compute_cost(int64_t p_from_id, int64_t p_to_id) { real_t scost; if (GDVIRTUAL_CALL(_compute_cost, p_from_id, p_to_id, scost)) { return scost; @@ -414,7 +414,7 @@ real_t AStar3D::_compute_cost(int p_from_id, int p_to_id) { return from_point->pos.distance_to(to_point->pos); } -Vector<Vector3> AStar3D::get_point_path(int p_from_id, int p_to_id) { +Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) { Point *a; bool from_exists = points.lookup(p_from_id, a); 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)); @@ -438,7 +438,7 @@ Vector<Vector3> AStar3D::get_point_path(int p_from_id, int p_to_id) { } Point *p = end_point; - int pc = 1; // Begin point + int64_t pc = 1; // Begin point while (p != begin_point) { pc++; p = p->prev_point; @@ -451,7 +451,7 @@ Vector<Vector3> AStar3D::get_point_path(int p_from_id, int p_to_id) { Vector3 *w = path.ptrw(); Point *p2 = end_point; - int idx = pc - 1; + int64_t idx = pc - 1; while (p2 != begin_point) { w[idx--] = p2->pos; p2 = p2->prev_point; @@ -463,17 +463,17 @@ Vector<Vector3> AStar3D::get_point_path(int p_from_id, int p_to_id) { return path; } -Vector<int> AStar3D::get_id_path(int p_from_id, int p_to_id) { +Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id) { Point *a; bool from_exists = points.lookup(p_from_id, a); - 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)); + ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), 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_MSG(!to_exists, Vector<int>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_to_id)); + ERR_FAIL_COND_V_MSG(!to_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_to_id)); if (a == b) { - Vector<int> ret; + Vector<int64_t> ret; ret.push_back(a->id); return ret; } @@ -483,24 +483,24 @@ Vector<int> AStar3D::get_id_path(int p_from_id, int p_to_id) { bool found_route = _solve(begin_point, end_point); if (!found_route) { - return Vector<int>(); + return Vector<int64_t>(); } Point *p = end_point; - int pc = 1; // Begin point + int64_t pc = 1; // Begin point while (p != begin_point) { pc++; p = p->prev_point; } - Vector<int> path; + Vector<int64_t> path; path.resize(pc); { - int *w = path.ptrw(); + int64_t *w = path.ptrw(); p = end_point; - int idx = pc - 1; + int64_t idx = pc - 1; while (p != begin_point) { w[idx--] = p->id; p = p->prev_point; @@ -512,7 +512,7 @@ Vector<int> AStar3D::get_id_path(int p_from_id, int p_to_id) { return path; } -void AStar3D::set_point_disabled(int p_id, bool p_disabled) { +void AStar3D::set_point_disabled(int64_t p_id, bool p_disabled) { Point *p; bool p_exists = points.lookup(p_id, p); ERR_FAIL_COND_MSG(!p_exists, vformat("Can't set if point is disabled. Point with id: %d doesn't exist.", p_id)); @@ -520,7 +520,7 @@ void AStar3D::set_point_disabled(int p_id, bool p_disabled) { p->enabled = !p_disabled; } -bool AStar3D::is_point_disabled(int p_id) const { +bool AStar3D::is_point_disabled(int64_t p_id) const { Point *p; bool p_exists = points.lookup(p_id, p); 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)); @@ -568,40 +568,40 @@ AStar3D::~AStar3D() { ///////////////////////////////////////////////////////////// -int AStar2D::get_available_point_id() const { +int64_t AStar2D::get_available_point_id() const { return astar.get_available_point_id(); } -void AStar2D::add_point(int p_id, const Vector2 &p_pos, real_t p_weight_scale) { +void AStar2D::add_point(int64_t p_id, const Vector2 &p_pos, real_t p_weight_scale) { astar.add_point(p_id, Vector3(p_pos.x, p_pos.y, 0), p_weight_scale); } -Vector2 AStar2D::get_point_position(int p_id) const { +Vector2 AStar2D::get_point_position(int64_t p_id) const { Vector3 p = astar.get_point_position(p_id); return Vector2(p.x, p.y); } -void AStar2D::set_point_position(int p_id, const Vector2 &p_pos) { +void AStar2D::set_point_position(int64_t p_id, const Vector2 &p_pos) { astar.set_point_position(p_id, Vector3(p_pos.x, p_pos.y, 0)); } -real_t AStar2D::get_point_weight_scale(int p_id) const { +real_t AStar2D::get_point_weight_scale(int64_t p_id) const { return astar.get_point_weight_scale(p_id); } -void AStar2D::set_point_weight_scale(int p_id, real_t p_weight_scale) { +void AStar2D::set_point_weight_scale(int64_t p_id, real_t p_weight_scale) { astar.set_point_weight_scale(p_id, p_weight_scale); } -void AStar2D::remove_point(int p_id) { +void AStar2D::remove_point(int64_t p_id) { astar.remove_point(p_id); } -bool AStar2D::has_point(int p_id) const { +bool AStar2D::has_point(int64_t p_id) const { return astar.has_point(p_id); } -Vector<int> AStar2D::get_point_connections(int p_id) { +Vector<int64_t> AStar2D::get_point_connections(int64_t p_id) { return astar.get_point_connections(p_id); } @@ -609,31 +609,31 @@ Array AStar2D::get_point_ids() { return astar.get_point_ids(); } -void AStar2D::set_point_disabled(int p_id, bool p_disabled) { +void AStar2D::set_point_disabled(int64_t p_id, bool p_disabled) { astar.set_point_disabled(p_id, p_disabled); } -bool AStar2D::is_point_disabled(int p_id) const { +bool AStar2D::is_point_disabled(int64_t p_id) const { return astar.is_point_disabled(p_id); } -void AStar2D::connect_points(int p_id, int p_with_id, bool p_bidirectional) { +void AStar2D::connect_points(int64_t p_id, int64_t p_with_id, bool p_bidirectional) { astar.connect_points(p_id, p_with_id, p_bidirectional); } -void AStar2D::disconnect_points(int p_id, int p_with_id) { - astar.disconnect_points(p_id, p_with_id); +void AStar2D::disconnect_points(int64_t p_id, int64_t p_with_id, bool p_bidirectional) { + astar.disconnect_points(p_id, p_with_id, p_bidirectional); } -bool AStar2D::are_points_connected(int p_id, int p_with_id) const { - return astar.are_points_connected(p_id, p_with_id); +bool AStar2D::are_points_connected(int64_t p_id, int64_t p_with_id, bool p_bidirectional) const { + return astar.are_points_connected(p_id, p_with_id, p_bidirectional); } -int AStar2D::get_point_count() const { +int64_t AStar2D::get_point_count() const { return astar.get_point_count(); } -int AStar2D::get_point_capacity() const { +int64_t AStar2D::get_point_capacity() const { return astar.get_point_capacity(); } @@ -641,11 +641,11 @@ void AStar2D::clear() { astar.clear(); } -void AStar2D::reserve_space(int p_num_nodes) { +void AStar2D::reserve_space(int64_t p_num_nodes) { astar.reserve_space(p_num_nodes); } -int AStar2D::get_closest_point(const Vector2 &p_point, bool p_include_disabled) const { +int64_t AStar2D::get_closest_point(const Vector2 &p_point, bool p_include_disabled) const { return astar.get_closest_point(Vector3(p_point.x, p_point.y, 0), p_include_disabled); } @@ -654,7 +654,7 @@ Vector2 AStar2D::get_closest_position_in_segment(const Vector2 &p_point) const { return Vector2(p.x, p.y); } -real_t AStar2D::_estimate_cost(int p_from_id, int p_to_id) { +real_t AStar2D::_estimate_cost(int64_t p_from_id, int64_t p_to_id) { real_t scost; if (GDVIRTUAL_CALL(_estimate_cost, p_from_id, p_to_id, scost)) { return scost; @@ -671,7 +671,7 @@ real_t AStar2D::_estimate_cost(int p_from_id, int p_to_id) { return from_point->pos.distance_to(to_point->pos); } -real_t AStar2D::_compute_cost(int p_from_id, int p_to_id) { +real_t AStar2D::_compute_cost(int64_t p_from_id, int64_t p_to_id) { real_t scost; if (GDVIRTUAL_CALL(_compute_cost, p_from_id, p_to_id, scost)) { return scost; @@ -688,7 +688,7 @@ real_t AStar2D::_compute_cost(int p_from_id, int p_to_id) { return from_point->pos.distance_to(to_point->pos); } -Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) { +Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) { AStar3D::Point *a; bool from_exists = astar.points.lookup(p_from_id, a); 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)); @@ -711,7 +711,7 @@ Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) { } AStar3D::Point *p = end_point; - int pc = 1; // Begin point + int64_t pc = 1; // Begin point while (p != begin_point) { pc++; p = p->prev_point; @@ -724,7 +724,7 @@ Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) { Vector2 *w = path.ptrw(); AStar3D::Point *p2 = end_point; - int idx = pc - 1; + int64_t idx = pc - 1; while (p2 != begin_point) { w[idx--] = Vector2(p2->pos.x, p2->pos.y); p2 = p2->prev_point; @@ -736,17 +736,17 @@ Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) { return path; } -Vector<int> AStar2D::get_id_path(int p_from_id, int p_to_id) { +Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) { AStar3D::Point *a; bool from_exists = astar.points.lookup(p_from_id, a); - 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)); + ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id)); AStar3D::Point *b; bool to_exists = astar.points.lookup(p_to_id, b); - 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)); + ERR_FAIL_COND_V_MSG(!to_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_to_id)); if (a == b) { - Vector<int> ret; + Vector<int64_t> ret; ret.push_back(a->id); return ret; } @@ -756,24 +756,24 @@ Vector<int> AStar2D::get_id_path(int p_from_id, int p_to_id) { bool found_route = _solve(begin_point, end_point); if (!found_route) { - return Vector<int>(); + return Vector<int64_t>(); } AStar3D::Point *p = end_point; - int pc = 1; // Begin point + int64_t pc = 1; // Begin point while (p != begin_point) { pc++; p = p->prev_point; } - Vector<int> path; + Vector<int64_t> path; path.resize(pc); { - int *w = path.ptrw(); + int64_t *w = path.ptrw(); p = end_point; - int idx = pc - 1; + int64_t idx = pc - 1; while (p != begin_point) { w[idx--] = p->id; p = p->prev_point; @@ -813,7 +813,7 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) { open_list.remove_at(open_list.size() - 1); p->closed_pass = astar.pass; // Mark the point as closed - for (OAHashMap<int, AStar3D::Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { + for (OAHashMap<int64_t, AStar3D::Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) { AStar3D::Point *e = *(it.value); // The neighbour point if (!e->enabled || e->closed_pass == astar.pass) { @@ -863,8 +863,8 @@ void AStar2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar2D::is_point_disabled); ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar2D::connect_points, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id"), &AStar2D::disconnect_points); - ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id"), &AStar2D::are_points_connected); + ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id", "bidirectional"), &AStar2D::disconnect_points, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id", "bidirectional"), &AStar2D::are_points_connected, DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_point_count"), &AStar2D::get_point_count); ClassDB::bind_method(D_METHOD("get_point_capacity"), &AStar2D::get_point_capacity); diff --git a/core/math/a_star.h b/core/math/a_star.h index bb7112fb09..c1497d133f 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -47,13 +47,13 @@ class AStar3D : public RefCounted { struct Point { Point() {} - int id = 0; + int64_t id = 0; Vector3 pos; real_t weight_scale = 0; bool enabled = false; - OAHashMap<int, Point *> neighbours = 4u; - OAHashMap<int, Point *> unlinked_neighbours = 4u; + OAHashMap<int64_t, Point *> neighbours = 4u; + OAHashMap<int64_t, Point *> unlinked_neighbours = 4u; // Used for pathfinding. Point *prev_point = nullptr; @@ -76,13 +76,7 @@ class AStar3D : public RefCounted { }; struct Segment { - union { - struct { - int32_t u; - int32_t v; - }; - uint64_t key = 0; - }; + Pair<int64_t, int64_t> key; enum { NONE = 0, @@ -92,69 +86,72 @@ class AStar3D : public RefCounted { }; unsigned char direction = NONE; - bool operator<(const Segment &p_s) const { return key < p_s.key; } + static uint32_t hash(const Segment &p_seg) { + return PairHash<int64_t, int64_t>().hash(p_seg.key); + } + bool operator==(const Segment &p_s) const { return key == p_s.key; } Segment() {} - Segment(int p_from, int p_to) { + Segment(int64_t p_from, int64_t p_to) { if (p_from < p_to) { - u = p_from; - v = p_to; + key.first = p_from; + key.second = p_to; direction = FORWARD; } else { - u = p_to; - v = p_from; + key.first = p_to; + key.second = p_from; direction = BACKWARD; } } }; - int last_free_id = 0; + int64_t last_free_id = 0; uint64_t pass = 1; - OAHashMap<int, Point *> points; - Set<Segment> segments; + OAHashMap<int64_t, Point *> points; + HashSet<Segment, Segment> segments; bool _solve(Point *begin_point, Point *end_point); protected: static void _bind_methods(); - virtual real_t _estimate_cost(int p_from_id, int p_to_id); - virtual real_t _compute_cost(int p_from_id, int p_to_id); + virtual real_t _estimate_cost(int64_t p_from_id, int64_t p_to_id); + virtual real_t _compute_cost(int64_t p_from_id, int64_t p_to_id); GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t) GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t) public: - int get_available_point_id() const; - - void add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale = 1); - Vector3 get_point_position(int p_id) const; - void set_point_position(int p_id, const Vector3 &p_pos); - real_t get_point_weight_scale(int p_id) const; - void set_point_weight_scale(int p_id, real_t p_weight_scale); - void remove_point(int p_id); - bool has_point(int p_id) const; - Vector<int> get_point_connections(int p_id); + int64_t get_available_point_id() const; + + void add_point(int64_t p_id, const Vector3 &p_pos, real_t p_weight_scale = 1); + Vector3 get_point_position(int64_t p_id) const; + void set_point_position(int64_t p_id, const Vector3 &p_pos); + real_t get_point_weight_scale(int64_t p_id) const; + void set_point_weight_scale(int64_t p_id, real_t p_weight_scale); + void remove_point(int64_t p_id); + bool has_point(int64_t p_id) const; + Vector<int64_t> get_point_connections(int64_t p_id); Array get_point_ids(); - void set_point_disabled(int p_id, bool p_disabled = true); - bool is_point_disabled(int p_id) const; + void set_point_disabled(int64_t p_id, bool p_disabled = true); + bool is_point_disabled(int64_t p_id) const; - void connect_points(int p_id, int p_with_id, bool bidirectional = true); - void disconnect_points(int p_id, int p_with_id, bool bidirectional = true); - bool are_points_connected(int p_id, int p_with_id, bool bidirectional = true) const; + void connect_points(int64_t p_id, int64_t p_with_id, bool bidirectional = true); + void disconnect_points(int64_t p_id, int64_t p_with_id, bool bidirectional = true); + bool are_points_connected(int64_t p_id, int64_t p_with_id, bool bidirectional = true) const; - int get_point_count() const; - int get_point_capacity() const; - void reserve_space(int p_num_nodes); + int64_t get_point_count() const; + int64_t get_point_capacity() const; + void reserve_space(int64_t p_num_nodes); void clear(); - int get_closest_point(const Vector3 &p_point, bool p_include_disabled = false) const; + int64_t get_closest_point(const Vector3 &p_point, bool p_include_disabled = false) const; Vector3 get_closest_position_in_segment(const Vector3 &p_point) const; - Vector<Vector3> get_point_path(int p_from_id, int p_to_id); - Vector<int> get_id_path(int p_from_id, int p_to_id); + Vector<Vector3> get_point_path(int64_t p_from_id, int64_t p_to_id); + Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id); AStar3D() {} ~AStar3D(); @@ -169,42 +166,42 @@ class AStar2D : public RefCounted { protected: static void _bind_methods(); - virtual real_t _estimate_cost(int p_from_id, int p_to_id); - virtual real_t _compute_cost(int p_from_id, int p_to_id); + virtual real_t _estimate_cost(int64_t p_from_id, int64_t p_to_id); + virtual real_t _compute_cost(int64_t p_from_id, int64_t p_to_id); GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t) GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t) public: - int get_available_point_id() const; - - void add_point(int p_id, const Vector2 &p_pos, real_t p_weight_scale = 1); - Vector2 get_point_position(int p_id) const; - void set_point_position(int p_id, const Vector2 &p_pos); - real_t get_point_weight_scale(int p_id) const; - void set_point_weight_scale(int p_id, real_t p_weight_scale); - void remove_point(int p_id); - bool has_point(int p_id) const; - Vector<int> get_point_connections(int p_id); + int64_t get_available_point_id() const; + + void add_point(int64_t p_id, const Vector2 &p_pos, real_t p_weight_scale = 1); + Vector2 get_point_position(int64_t p_id) const; + void set_point_position(int64_t p_id, const Vector2 &p_pos); + real_t get_point_weight_scale(int64_t p_id) const; + void set_point_weight_scale(int64_t p_id, real_t p_weight_scale); + void remove_point(int64_t p_id); + bool has_point(int64_t p_id) const; + Vector<int64_t> get_point_connections(int64_t p_id); Array get_point_ids(); - void set_point_disabled(int p_id, bool p_disabled = true); - bool is_point_disabled(int p_id) const; + void set_point_disabled(int64_t p_id, bool p_disabled = true); + bool is_point_disabled(int64_t p_id) const; - void connect_points(int p_id, int p_with_id, bool p_bidirectional = true); - void disconnect_points(int p_id, int p_with_id); - bool are_points_connected(int p_id, int p_with_id) const; + void connect_points(int64_t p_id, int64_t p_with_id, bool p_bidirectional = true); + void disconnect_points(int64_t p_id, int64_t p_with_id, bool p_bidirectional = true); + bool are_points_connected(int64_t p_id, int64_t p_with_id, bool p_bidirectional = true) const; - int get_point_count() const; - int get_point_capacity() const; - void reserve_space(int p_num_nodes); + int64_t get_point_count() const; + int64_t get_point_capacity() const; + void reserve_space(int64_t p_num_nodes); void clear(); - int get_closest_point(const Vector2 &p_point, bool p_include_disabled = false) const; + int64_t get_closest_point(const Vector2 &p_point, bool p_include_disabled = false) const; Vector2 get_closest_position_in_segment(const Vector2 &p_point) const; - Vector<Vector2> get_point_path(int p_from_id, int p_to_id); - Vector<int> get_id_path(int p_from_id, int p_to_id); + Vector<Vector2> get_point_path(int64_t p_from_id, int64_t p_to_id); + Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id); AStar2D() {} ~AStar2D() {} diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h index 8b244e9fe4..b3d63c0094 100644 --- a/core/math/audio_frame.h +++ b/core/math/audio_frame.h @@ -52,7 +52,7 @@ static const float AUDIO_MIN_PEAK_DB = -200.0f; // linear2db(AUDIO_PEAK_OFFSET) struct AudioFrame { //left and right samples - float l, r; + float l = 0.f, r = 0.f; _ALWAYS_INLINE_ const float &operator[](int idx) const { return idx == 0 ? l : r; } _ALWAYS_INLINE_ float &operator[](int idx) { return idx == 0 ? l : r; } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index eb6703aff2..f8e7c47107 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -34,32 +34,32 @@ #include "core/string/print_string.h" #define cofac(row1, col1, row2, col2) \ - (elements[row1][col1] * elements[row2][col2] - elements[row1][col2] * elements[row2][col1]) + (rows[row1][col1] * rows[row2][col2] - rows[row1][col2] * rows[row2][col1]) void Basis::from_z(const Vector3 &p_z) { if (Math::abs(p_z.z) > (real_t)Math_SQRT12) { // choose p in y-z plane real_t a = p_z[1] * p_z[1] + p_z[2] * p_z[2]; real_t k = 1.0f / Math::sqrt(a); - elements[0] = Vector3(0, -p_z[2] * k, p_z[1] * k); - elements[1] = Vector3(a * k, -p_z[0] * elements[0][2], p_z[0] * elements[0][1]); + rows[0] = Vector3(0, -p_z[2] * k, p_z[1] * k); + rows[1] = Vector3(a * k, -p_z[0] * rows[0][2], p_z[0] * rows[0][1]); } else { // choose p in x-y plane real_t a = p_z.x * p_z.x + p_z.y * p_z.y; real_t k = 1.0f / Math::sqrt(a); - elements[0] = Vector3(-p_z.y * k, p_z.x * k, 0); - elements[1] = Vector3(-p_z.z * elements[0].y, p_z.z * elements[0].x, a * k); + rows[0] = Vector3(-p_z.y * k, p_z.x * k, 0); + rows[1] = Vector3(-p_z.z * rows[0].y, p_z.z * rows[0].x, a * k); } - elements[2] = p_z; + rows[2] = p_z; } void Basis::invert() { real_t co[3] = { 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]; + real_t det = rows[0][0] * co[0] + + rows[0][1] * co[1] + + rows[0][2] * co[2]; #ifdef MATH_CHECKS ERR_FAIL_COND(det == 0); #endif @@ -73,9 +73,9 @@ void Basis::invert() { void Basis::orthonormalize() { // Gram-Schmidt Process - Vector3 x = get_axis(0); - Vector3 y = get_axis(1); - Vector3 z = get_axis(2); + Vector3 x = get_column(0); + Vector3 y = get_column(1); + Vector3 z = get_column(2); x.normalize(); y = (y - x * (x.dot(y))); @@ -83,9 +83,9 @@ void Basis::orthonormalize() { z = (z - x * (x.dot(z)) - y * (y.dot(z))); z.normalize(); - set_axis(0, x); - set_axis(1, y); - set_axis(2, z); + set_column(0, x); + set_column(1, y); + set_column(2, z); } Basis Basis::orthonormalized() const { @@ -115,9 +115,9 @@ bool Basis::is_orthogonal() const { bool Basis::is_diagonal() const { return ( - Math::is_zero_approx(elements[0][1]) && Math::is_zero_approx(elements[0][2]) && - Math::is_zero_approx(elements[1][0]) && Math::is_zero_approx(elements[1][2]) && - Math::is_zero_approx(elements[2][0]) && Math::is_zero_approx(elements[2][1])); + Math::is_zero_approx(rows[0][1]) && Math::is_zero_approx(rows[0][2]) && + Math::is_zero_approx(rows[1][0]) && Math::is_zero_approx(rows[1][2]) && + Math::is_zero_approx(rows[2][0]) && Math::is_zero_approx(rows[2][1])); } bool Basis::is_rotation() const { @@ -127,13 +127,13 @@ bool Basis::is_rotation() const { #ifdef MATH_CHECKS // This method is only used once, in diagonalize. If it's desired elsewhere, feel free to remove the #ifdef. bool Basis::is_symmetric() const { - if (!Math::is_equal_approx(elements[0][1], elements[1][0])) { + if (!Math::is_equal_approx(rows[0][1], rows[1][0])) { return false; } - if (!Math::is_equal_approx(elements[0][2], elements[2][0])) { + if (!Math::is_equal_approx(rows[0][2], rows[2][0])) { return false; } - if (!Math::is_equal_approx(elements[1][2], elements[2][1])) { + if (!Math::is_equal_approx(rows[1][2], rows[2][1])) { return false; } @@ -149,14 +149,14 @@ Basis Basis::diagonalize() { #endif const int ite_max = 1024; - real_t off_matrix_norm_2 = elements[0][1] * elements[0][1] + elements[0][2] * elements[0][2] + elements[1][2] * elements[1][2]; + real_t off_matrix_norm_2 = rows[0][1] * rows[0][1] + rows[0][2] * rows[0][2] + rows[1][2] * rows[1][2]; int ite = 0; Basis acc_rot; while (off_matrix_norm_2 > (real_t)CMP_EPSILON2 && ite++ < ite_max) { - real_t el01_2 = elements[0][1] * elements[0][1]; - real_t el02_2 = elements[0][2] * elements[0][2]; - real_t el12_2 = elements[1][2] * elements[1][2]; + real_t el01_2 = rows[0][1] * rows[0][1]; + real_t el02_2 = rows[0][2] * rows[0][2]; + real_t el12_2 = rows[1][2] * rows[1][2]; // Find the pivot element int i, j; if (el01_2 > el02_2) { @@ -179,19 +179,19 @@ Basis Basis::diagonalize() { // Compute the rotation angle real_t angle; - if (Math::is_equal_approx(elements[j][j], elements[i][i])) { + if (Math::is_equal_approx(rows[j][j], rows[i][i])) { angle = Math_PI / 4; } else { - angle = 0.5f * Math::atan(2 * elements[i][j] / (elements[j][j] - elements[i][i])); + angle = 0.5f * Math::atan(2 * rows[i][j] / (rows[j][j] - rows[i][i])); } // Compute the rotation matrix Basis rot; - rot.elements[i][i] = rot.elements[j][j] = Math::cos(angle); - rot.elements[i][j] = -(rot.elements[j][i] = Math::sin(angle)); + rot.rows[i][i] = rot.rows[j][j] = Math::cos(angle); + rot.rows[i][j] = -(rot.rows[j][i] = Math::sin(angle)); // Update the off matrix norm - off_matrix_norm_2 -= elements[i][j] * elements[i][j]; + off_matrix_norm_2 -= rows[i][j] * rows[i][j]; // Apply the rotation *this = rot * *this * rot.transposed(); @@ -208,9 +208,9 @@ Basis Basis::inverse() const { } void Basis::transpose() { - SWAP(elements[0][1], elements[1][0]); - SWAP(elements[0][2], elements[2][0]); - SWAP(elements[1][2], elements[2][1]); + SWAP(rows[0][1], rows[1][0]); + SWAP(rows[0][2], rows[2][0]); + SWAP(rows[1][2], rows[2][1]); } Basis Basis::transposed() const { @@ -226,15 +226,15 @@ Basis Basis::from_scale(const Vector3 &p_scale) { // Multiplies the matrix from left by the scaling matrix: M -> S.M // See the comment for Basis::rotated for further explanation. void Basis::scale(const Vector3 &p_scale) { - elements[0][0] *= p_scale.x; - elements[0][1] *= p_scale.x; - elements[0][2] *= p_scale.x; - elements[1][0] *= p_scale.y; - elements[1][1] *= p_scale.y; - elements[1][2] *= p_scale.y; - elements[2][0] *= p_scale.z; - elements[2][1] *= p_scale.z; - elements[2][2] *= p_scale.z; + rows[0][0] *= p_scale.x; + rows[0][1] *= p_scale.x; + rows[0][2] *= p_scale.x; + rows[1][0] *= p_scale.y; + rows[1][1] *= p_scale.y; + rows[1][2] *= p_scale.y; + rows[2][0] *= p_scale.z; + rows[2][1] *= p_scale.z; + rows[2][2] *= p_scale.z; } Basis Basis::scaled(const Vector3 &p_scale) const { @@ -260,7 +260,7 @@ Basis Basis::scaled_orthogonal(const Vector3 &p_scale) const { Basis b; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - dots[j] += s[i] * abs(m.get_axis(i).normalized().dot(b.get_axis(j))); + dots[j] += s[i] * abs(m.get_column(i).normalized().dot(b.get_column(j))); } } m.scale_local(Vector3(1, 1, 1) + dots); @@ -268,14 +268,14 @@ Basis Basis::scaled_orthogonal(const Vector3 &p_scale) const { } float Basis::get_uniform_scale() const { - return (elements[0].length() + elements[1].length() + elements[2].length()) / 3.0f; + return (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f; } void Basis::make_scale_uniform() { - float l = (elements[0].length() + elements[1].length() + elements[2].length()) / 3.0f; + float l = (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f; for (int i = 0; i < 3; i++) { - elements[i].normalize(); - elements[i] *= l; + rows[i].normalize(); + rows[i] *= l; } } @@ -285,14 +285,14 @@ Basis Basis::scaled_local(const Vector3 &p_scale) const { Vector3 Basis::get_scale_abs() const { return 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()); + Vector3(rows[0][0], rows[1][0], rows[2][0]).length(), + Vector3(rows[0][1], rows[1][1], rows[2][1]).length(), + Vector3(rows[0][2], rows[1][2], rows[2][2]).length()); } Vector3 Basis::get_scale_local() const { real_t det_sign = SIGN(determinant()); - return det_sign * Vector3(elements[0].length(), elements[1].length(), elements[2].length()); + return det_sign * Vector3(rows[0].length(), rows[1].length(), rows[2].length()); } // get_scale works with get_rotation, use get_scale_abs if you need to enforce positive signature. @@ -347,30 +347,30 @@ Vector3 Basis::rotref_posscale_decomposition(Basis &rotref) const { // The main use of Basis is as Transform.basis, which is used by the transformation matrix // of 3D object. Rotate here refers to rotation of the object (which is R * (*this)), // not the matrix itself (which is R * (*this) * R.transposed()). -Basis Basis::rotated(const Vector3 &p_axis, real_t p_phi) const { - return Basis(p_axis, p_phi) * (*this); +Basis Basis::rotated(const Vector3 &p_axis, real_t p_angle) const { + return Basis(p_axis, p_angle) * (*this); } -void Basis::rotate(const Vector3 &p_axis, real_t p_phi) { - *this = rotated(p_axis, p_phi); +void Basis::rotate(const Vector3 &p_axis, real_t p_angle) { + *this = rotated(p_axis, p_angle); } -void Basis::rotate_local(const Vector3 &p_axis, real_t p_phi) { +void Basis::rotate_local(const Vector3 &p_axis, real_t p_angle) { // performs a rotation in object-local coordinate system: // M -> (M.R.Minv).M = M.R. - *this = rotated_local(p_axis, p_phi); + *this = rotated_local(p_axis, p_angle); } -Basis Basis::rotated_local(const Vector3 &p_axis, real_t p_phi) const { - return (*this) * Basis(p_axis, p_phi); +Basis Basis::rotated_local(const Vector3 &p_axis, real_t p_angle) const { + return (*this) * Basis(p_axis, p_angle); } -Basis Basis::rotated(const Vector3 &p_euler) const { - return Basis(p_euler) * (*this); +Basis Basis::rotated(const Vector3 &p_euler, EulerOrder p_order) const { + return Basis::from_euler(p_euler, p_order) * (*this); } -void Basis::rotate(const Vector3 &p_euler) { - *this = rotated(p_euler); +void Basis::rotate(const Vector3 &p_euler, EulerOrder p_order) { + *this = rotated(p_euler, p_order); } Basis Basis::rotated(const Quaternion &p_quaternion) const { @@ -462,27 +462,27 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy Vector3 euler; - real_t sy = elements[0][2]; + real_t sy = rows[0][2]; if (sy < (1.0f - (real_t)CMP_EPSILON)) { if (sy > -(1.0f - (real_t)CMP_EPSILON)) { // is this a pure Y rotation? - if (elements[1][0] == 0 && elements[0][1] == 0 && elements[1][2] == 0 && elements[2][1] == 0 && elements[1][1] == 1) { + if (rows[1][0] == 0 && rows[0][1] == 0 && rows[1][2] == 0 && rows[2][1] == 0 && rows[1][1] == 1) { // return the simplest form (human friendlier in editor and scripts) euler.x = 0; - euler.y = atan2(elements[0][2], elements[0][0]); + euler.y = atan2(rows[0][2], rows[0][0]); euler.z = 0; } else { - euler.x = Math::atan2(-elements[1][2], elements[2][2]); + euler.x = Math::atan2(-rows[1][2], rows[2][2]); euler.y = Math::asin(sy); - euler.z = Math::atan2(-elements[0][1], elements[0][0]); + euler.z = Math::atan2(-rows[0][1], rows[0][0]); } } else { - euler.x = Math::atan2(elements[2][1], elements[1][1]); + euler.x = Math::atan2(rows[2][1], rows[1][1]); euler.y = -Math_PI / 2.0f; euler.z = 0.0f; } } else { - euler.x = Math::atan2(elements[2][1], elements[1][1]); + euler.x = Math::atan2(rows[2][1], rows[1][1]); euler.y = Math_PI / 2.0f; euler.z = 0.0f; } @@ -497,21 +497,21 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { // cy*sx*sz cz*sx cx*cy+sx*sz*sy Vector3 euler; - real_t sz = elements[0][1]; + real_t sz = rows[0][1]; if (sz < (1.0f - (real_t)CMP_EPSILON)) { if (sz > -(1.0f - (real_t)CMP_EPSILON)) { - euler.x = Math::atan2(elements[2][1], elements[1][1]); - euler.y = Math::atan2(elements[0][2], elements[0][0]); + euler.x = Math::atan2(rows[2][1], rows[1][1]); + euler.y = Math::atan2(rows[0][2], rows[0][0]); euler.z = Math::asin(-sz); } else { // It's -1 - euler.x = -Math::atan2(elements[1][2], elements[2][2]); + euler.x = -Math::atan2(rows[1][2], rows[2][2]); euler.y = 0.0f; euler.z = Math_PI / 2.0f; } } else { // It's 1 - euler.x = -Math::atan2(elements[1][2], elements[2][2]); + euler.x = -Math::atan2(rows[1][2], rows[2][2]); euler.y = 0.0f; euler.z = -Math_PI / 2.0f; } @@ -527,29 +527,29 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { Vector3 euler; - real_t m12 = elements[1][2]; + real_t m12 = rows[1][2]; if (m12 < (1 - (real_t)CMP_EPSILON)) { if (m12 > -(1 - (real_t)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) { + if (rows[1][0] == 0 && rows[0][1] == 0 && rows[0][2] == 0 && rows[2][0] == 0 && rows[0][0] == 1) { // return the simplest form (human friendlier in editor and scripts) - euler.x = atan2(-m12, elements[1][1]); + euler.x = atan2(-m12, rows[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]); + euler.y = atan2(rows[0][2], rows[2][2]); + euler.z = atan2(rows[1][0], rows[1][1]); } } else { // m12 == -1 euler.x = Math_PI * 0.5f; - euler.y = atan2(elements[0][1], elements[0][0]); + euler.y = atan2(rows[0][1], rows[0][0]); euler.z = 0; } } else { // m12 == 1 euler.x = -Math_PI * 0.5f; - euler.y = -atan2(elements[0][1], elements[0][0]); + euler.y = -atan2(rows[0][1], rows[0][0]); euler.z = 0; } @@ -564,21 +564,21 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { // -cz*sy cy*sx+cx*sy*sz cy*cx-sy*sz*sx Vector3 euler; - real_t sz = elements[1][0]; + real_t sz = rows[1][0]; if (sz < (1.0f - (real_t)CMP_EPSILON)) { if (sz > -(1.0f - (real_t)CMP_EPSILON)) { - euler.x = Math::atan2(-elements[1][2], elements[1][1]); - euler.y = Math::atan2(-elements[2][0], elements[0][0]); + euler.x = Math::atan2(-rows[1][2], rows[1][1]); + euler.y = Math::atan2(-rows[2][0], rows[0][0]); euler.z = Math::asin(sz); } else { // It's -1 - euler.x = Math::atan2(elements[2][1], elements[2][2]); + euler.x = Math::atan2(rows[2][1], rows[2][2]); euler.y = 0.0f; euler.z = -Math_PI / 2.0f; } } else { // It's 1 - euler.x = Math::atan2(elements[2][1], elements[2][2]); + euler.x = Math::atan2(rows[2][1], rows[2][2]); euler.y = 0.0f; euler.z = Math_PI / 2.0f; } @@ -592,22 +592,22 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { // 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]; + real_t sx = rows[2][1]; if (sx < (1.0f - (real_t)CMP_EPSILON)) { if (sx > -(1.0f - (real_t)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]); + euler.y = Math::atan2(-rows[2][0], rows[2][2]); + euler.z = Math::atan2(-rows[0][1], rows[1][1]); } else { // It's -1 euler.x = -Math_PI / 2.0f; - euler.y = Math::atan2(elements[0][2], elements[0][0]); + euler.y = Math::atan2(rows[0][2], rows[0][0]); euler.z = 0; } } else { // It's 1 euler.x = Math_PI / 2.0f; - euler.y = Math::atan2(elements[0][2], elements[0][0]); + euler.y = Math::atan2(rows[0][2], rows[0][0]); euler.z = 0; } return euler; @@ -620,23 +620,23 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { // 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]; + real_t sy = rows[2][0]; if (sy < (1.0f - (real_t)CMP_EPSILON)) { if (sy > -(1.0f - (real_t)CMP_EPSILON)) { - euler.x = Math::atan2(elements[2][1], elements[2][2]); + euler.x = Math::atan2(rows[2][1], rows[2][2]); euler.y = Math::asin(-sy); - euler.z = Math::atan2(elements[1][0], elements[0][0]); + euler.z = Math::atan2(rows[1][0], rows[0][0]); } else { // It's -1 euler.x = 0; euler.y = Math_PI / 2.0f; - euler.z = -Math::atan2(elements[0][1], elements[1][1]); + euler.z = -Math::atan2(rows[0][1], rows[1][1]); } } else { // It's 1 euler.x = 0; euler.y = -Math_PI / 2.0f; - euler.z = -Math::atan2(elements[0][1], elements[1][1]); + euler.z = -Math::atan2(rows[0][1], rows[1][1]); } return euler; } break; @@ -688,13 +688,13 @@ void Basis::set_euler(const Vector3 &p_euler, EulerOrder p_order) { } bool Basis::is_equal_approx(const Basis &p_basis) const { - return elements[0].is_equal_approx(p_basis.elements[0]) && elements[1].is_equal_approx(p_basis.elements[1]) && elements[2].is_equal_approx(p_basis.elements[2]); + return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]); } bool Basis::operator==(const Basis &p_matrix) const { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - if (elements[i][j] != p_matrix.elements[i][j]) { + if (rows[i][j] != p_matrix.rows[i][j]) { return false; } } @@ -708,9 +708,9 @@ 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() + "]"; + return "[X: " + get_column(0).operator String() + + ", Y: " + get_column(1).operator String() + + ", Z: " + get_column(2).operator String() + "]"; } Quaternion Basis::get_quaternion() const { @@ -719,7 +719,7 @@ Quaternion Basis::get_quaternion() const { #endif /* Allow getting a quaternion from an unnormalized transform */ Basis m = *this; - real_t trace = m.elements[0][0] + m.elements[1][1] + m.elements[2][2]; + real_t trace = m.rows[0][0] + m.rows[1][1] + m.rows[2][2]; real_t temp[4]; if (trace > 0.0f) { @@ -727,23 +727,23 @@ Quaternion Basis::get_quaternion() const { temp[3] = (s * 0.5f); s = 0.5f / s; - temp[0] = ((m.elements[2][1] - m.elements[1][2]) * s); - temp[1] = ((m.elements[0][2] - m.elements[2][0]) * s); - temp[2] = ((m.elements[1][0] - m.elements[0][1]) * s); + temp[0] = ((m.rows[2][1] - m.rows[1][2]) * s); + temp[1] = ((m.rows[0][2] - m.rows[2][0]) * s); + temp[2] = ((m.rows[1][0] - m.rows[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.rows[0][0] < m.rows[1][1] + ? (m.rows[1][1] < m.rows[2][2] ? 2 : 1) + : (m.rows[0][0] < m.rows[2][2] ? 2 : 0); int j = (i + 1) % 3; int k = (i + 2) % 3; - real_t s = Math::sqrt(m.elements[i][i] - m.elements[j][j] - m.elements[k][k] + 1.0f); + real_t s = Math::sqrt(m.rows[i][i] - m.rows[j][j] - m.rows[k][k] + 1.0f); temp[i] = s * 0.5f; s = 0.5f / s; - temp[3] = (m.elements[k][j] - m.elements[j][k]) * s; - temp[j] = (m.elements[j][i] + m.elements[i][j]) * s; - temp[k] = (m.elements[k][i] + m.elements[i][k]) * s; + temp[3] = (m.rows[k][j] - m.rows[j][k]) * s; + temp[j] = (m.rows[j][i] + m.rows[i][j]) * s; + temp[k] = (m.rows[k][i] + m.rows[i][k]) * s; } return Quaternion(temp[0], temp[1], temp[2], temp[3]); @@ -817,14 +817,13 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { #endif */ real_t angle, x, y, z; // variables for result - real_t epsilon = 0.01; // margin to allow for rounding errors - real_t epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees + real_t angle_epsilon = 0.1; // margin to distinguish between 0 and 180 degrees - if ((Math::abs(elements[1][0] - elements[0][1]) < epsilon) && (Math::abs(elements[2][0] - elements[0][2]) < epsilon) && (Math::abs(elements[2][1] - elements[1][2]) < epsilon)) { + if ((Math::abs(rows[1][0] - rows[0][1]) < CMP_EPSILON) && (Math::abs(rows[2][0] - rows[0][2]) < CMP_EPSILON) && (Math::abs(rows[2][1] - rows[1][2]) < CMP_EPSILON)) { // singularity found // first check for identity matrix which must have +1 for all terms // in leading diagonal and zero in other terms - if ((Math::abs(elements[1][0] + elements[0][1]) < epsilon2) && (Math::abs(elements[2][0] + elements[0][2]) < epsilon2) && (Math::abs(elements[2][1] + elements[1][2]) < epsilon2) && (Math::abs(elements[0][0] + elements[1][1] + elements[2][2] - 3) < epsilon2)) { + if ((Math::abs(rows[1][0] + rows[0][1]) < angle_epsilon) && (Math::abs(rows[2][0] + rows[0][2]) < angle_epsilon) && (Math::abs(rows[2][1] + rows[1][2]) < angle_epsilon) && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < angle_epsilon)) { // this singularity is identity matrix so angle = 0 r_axis = Vector3(0, 1, 0); r_angle = 0; @@ -832,14 +831,14 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { } // otherwise this singularity is angle = 180 angle = Math_PI; - real_t xx = (elements[0][0] + 1) / 2; - real_t yy = (elements[1][1] + 1) / 2; - real_t zz = (elements[2][2] + 1) / 2; - real_t xy = (elements[1][0] + elements[0][1]) / 4; - real_t xz = (elements[2][0] + elements[0][2]) / 4; - real_t yz = (elements[2][1] + elements[1][2]) / 4; - if ((xx > yy) && (xx > zz)) { // elements[0][0] is the largest diagonal term - if (xx < epsilon) { + real_t xx = (rows[0][0] + 1) / 2; + real_t yy = (rows[1][1] + 1) / 2; + real_t zz = (rows[2][2] + 1) / 2; + real_t xy = (rows[1][0] + rows[0][1]) / 4; + real_t xz = (rows[2][0] + rows[0][2]) / 4; + real_t yz = (rows[2][1] + rows[1][2]) / 4; + if ((xx > yy) && (xx > zz)) { // rows[0][0] is the largest diagonal term + if (xx < CMP_EPSILON) { x = 0; y = Math_SQRT12; z = Math_SQRT12; @@ -848,8 +847,8 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { y = xy / x; z = xz / x; } - } else if (yy > zz) { // elements[1][1] is the largest diagonal term - if (yy < epsilon) { + } else if (yy > zz) { // rows[1][1] is the largest diagonal term + if (yy < CMP_EPSILON) { x = Math_SQRT12; y = 0; z = Math_SQRT12; @@ -858,8 +857,8 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { x = xy / y; z = yz / y; } - } else { // elements[2][2] is the largest diagonal term so base result on this - if (zz < epsilon) { + } else { // rows[2][2] is the largest diagonal term so base result on this + if (zz < CMP_EPSILON) { x = Math_SQRT12; y = Math_SQRT12; z = 0; @@ -874,15 +873,15 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { return; } // as we have reached here there are no singularities so we can handle normally - real_t s = Math::sqrt((elements[1][2] - elements[2][1]) * (elements[1][2] - elements[2][1]) + (elements[2][0] - elements[0][2]) * (elements[2][0] - elements[0][2]) + (elements[0][1] - elements[1][0]) * (elements[0][1] - elements[1][0])); // s=|axis||sin(angle)|, used to normalise + real_t s = Math::sqrt((rows[1][2] - rows[2][1]) * (rows[1][2] - rows[2][1]) + (rows[2][0] - rows[0][2]) * (rows[2][0] - rows[0][2]) + (rows[0][1] - rows[1][0]) * (rows[0][1] - rows[1][0])); // s=|axis||sin(angle)|, used to normalise - angle = Math::acos((elements[0][0] + elements[1][1] + elements[2][2] - 1) / 2); + angle = Math::acos((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2); if (angle < 0) { s = -s; } - x = (elements[2][1] - elements[1][2]) / s; - y = (elements[0][2] - elements[2][0]) / s; - z = (elements[1][0] - elements[0][1]) / s; + x = (rows[2][1] - rows[1][2]) / s; + y = (rows[0][2] - rows[2][0]) / s; + z = (rows[1][0] - rows[0][1]) / s; r_axis = Vector3(x, y, z); r_angle = angle; @@ -900,44 +899,44 @@ void Basis::set_quaternion(const Quaternion &p_quaternion) { xz - wy, yz + wx, 1.0f - (xx + yy)); } -void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_phi) { +void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_angle) { // Rotation matrix from axis and angle, see https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_angle #ifdef MATH_CHECKS ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized."); #endif Vector3 axis_sq(p_axis.x * p_axis.x, p_axis.y * p_axis.y, p_axis.z * p_axis.z); - real_t cosine = Math::cos(p_phi); - elements[0][0] = axis_sq.x + cosine * (1.0f - axis_sq.x); - elements[1][1] = axis_sq.y + cosine * (1.0f - axis_sq.y); - elements[2][2] = axis_sq.z + cosine * (1.0f - axis_sq.z); + real_t cosine = Math::cos(p_angle); + rows[0][0] = axis_sq.x + cosine * (1.0f - axis_sq.x); + rows[1][1] = axis_sq.y + cosine * (1.0f - axis_sq.y); + rows[2][2] = axis_sq.z + cosine * (1.0f - axis_sq.z); - real_t sine = Math::sin(p_phi); + real_t sine = Math::sin(p_angle); real_t t = 1 - cosine; real_t xyzt = p_axis.x * p_axis.y * t; real_t zyxs = p_axis.z * sine; - elements[0][1] = xyzt - zyxs; - elements[1][0] = xyzt + zyxs; + rows[0][1] = xyzt - zyxs; + rows[1][0] = xyzt + zyxs; xyzt = p_axis.x * p_axis.z * t; zyxs = p_axis.y * sine; - elements[0][2] = xyzt + zyxs; - elements[2][0] = xyzt - zyxs; + rows[0][2] = xyzt + zyxs; + rows[2][0] = xyzt - zyxs; xyzt = p_axis.y * p_axis.z * t; zyxs = p_axis.x * sine; - elements[1][2] = xyzt - zyxs; - elements[2][1] = xyzt + zyxs; + rows[1][2] = xyzt - zyxs; + rows[2][1] = xyzt + zyxs; } -void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { +void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) { _set_diagonal(p_scale); - rotate(p_axis, p_phi); + rotate(p_axis, p_angle); } -void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale) { +void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order) { _set_diagonal(p_scale); - rotate(p_euler); + rotate(p_euler, p_order); } void Basis::set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale) { @@ -948,24 +947,24 @@ void Basis::set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 & // 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; + rows[0][0] = p_diag.x; + rows[0][1] = 0; + rows[0][2] = 0; - elements[1][0] = 0; - elements[1][1] = p_diag.y; - elements[1][2] = 0; + rows[1][0] = 0; + rows[1][1] = p_diag.y; + rows[1][2] = 0; - elements[2][0] = 0; - elements[2][1] = 0; - elements[2][2] = p_diag.z; + rows[2][0] = 0; + rows[2][1] = 0; + rows[2][2] = p_diag.z; } Basis Basis::lerp(const Basis &p_to, const real_t &p_weight) const { Basis b; - b.elements[0] = elements[0].lerp(p_to.elements[0], p_weight); - b.elements[1] = elements[1].lerp(p_to.elements[1], p_weight); - b.elements[2] = elements[2].lerp(p_to.elements[2], p_weight); + b.rows[0] = rows[0].lerp(p_to.rows[0], p_weight); + b.rows[1] = rows[1].lerp(p_to.rows[1], p_weight); + b.rows[2] = rows[2].lerp(p_to.rows[2], p_weight); return b; } @@ -976,9 +975,9 @@ Basis Basis::slerp(const Basis &p_to, const real_t &p_weight) const { Quaternion to(p_to); Basis b(from.slerp(to, p_weight)); - b.elements[0] *= Math::lerp(elements[0].length(), p_to.elements[0].length(), p_weight); - b.elements[1] *= Math::lerp(elements[1].length(), p_to.elements[1].length(), p_weight); - b.elements[2] *= Math::lerp(elements[2].length(), p_to.elements[2].length(), p_weight); + b.rows[0] *= Math::lerp(rows[0].length(), p_to.rows[0].length(), p_weight); + b.rows[1] *= Math::lerp(rows[1].length(), p_to.rows[1].length(), p_weight); + b.rows[2] *= Math::lerp(rows[2].length(), p_to.rows[2].length(), p_weight); return b; } @@ -1004,15 +1003,15 @@ void Basis::rotate_sh(real_t *p_values) { const real_t src[9] = { p_values[0], p_values[1], p_values[2], p_values[3], p_values[4], p_values[5], p_values[6], p_values[7], p_values[8] }; - real_t m00 = elements[0][0]; - real_t m01 = elements[0][1]; - real_t m02 = elements[0][2]; - real_t m10 = elements[1][0]; - real_t m11 = elements[1][1]; - real_t m12 = elements[1][2]; - real_t m20 = elements[2][0]; - real_t m21 = elements[2][1]; - real_t m22 = elements[2][2]; + real_t m00 = rows[0][0]; + real_t m01 = rows[0][1]; + real_t m02 = rows[0][2]; + real_t m10 = rows[1][0]; + real_t m11 = rows[1][1]; + real_t m12 = rows[1][2]; + real_t m20 = rows[2][0]; + real_t m21 = rows[2][1]; + real_t m22 = rows[2][2]; p_values[0] = src[0]; p_values[1] = m11 * src[1] - m12 * src[2] + m10 * src[3]; @@ -1107,6 +1106,6 @@ Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up) { Vector3 v_y = v_z.cross(v_x); Basis basis; - basis.set(v_x, v_y, v_z); + basis.set_columns(v_x, v_y, v_z); return basis; } diff --git a/core/math/basis.h b/core/math/basis.h index 683f05150c..4be325cdd2 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -35,17 +35,17 @@ #include "core/math/vector3.h" struct _NO_DISCARD_ Basis { - Vector3 elements[3] = { + Vector3 rows[3] = { Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1) }; _FORCE_INLINE_ const Vector3 &operator[](int axis) const { - return elements[axis]; + return rows[axis]; } _FORCE_INLINE_ Vector3 &operator[](int axis) { - return elements[axis]; + return rows[axis]; } void invert(); @@ -56,31 +56,6 @@ struct _NO_DISCARD_ Basis { _FORCE_INLINE_ real_t determinant() const; - void from_z(const Vector3 &p_z); - - _FORCE_INLINE_ Vector3 get_axis(int p_axis) const { - // get actual basis axis (elements is transposed for performance) - return Vector3(elements[0][p_axis], elements[1][p_axis], elements[2][p_axis]); - } - _FORCE_INLINE_ void set_axis(int p_axis, const Vector3 &p_value) { - // get actual basis axis (elements is transposed for performance) - elements[0][p_axis] = p_value.x; - elements[1][p_axis] = p_value.y; - elements[2][p_axis] = p_value.z; - } - - void rotate(const Vector3 &p_axis, real_t p_phi); - Basis rotated(const Vector3 &p_axis, real_t p_phi) const; - - void rotate_local(const Vector3 &p_axis, real_t p_phi); - Basis rotated_local(const Vector3 &p_axis, real_t p_phi) const; - - void rotate(const Vector3 &p_euler); - Basis rotated(const Vector3 &p_euler) const; - - void rotate(const Quaternion &p_quaternion); - Basis rotated(const Quaternion &p_quaternion) const; - enum EulerOrder { EULER_ORDER_XYZ, EULER_ORDER_XZY, @@ -90,6 +65,20 @@ struct _NO_DISCARD_ Basis { EULER_ORDER_ZYX }; + void from_z(const Vector3 &p_z); + + void rotate(const Vector3 &p_axis, real_t p_angle); + Basis rotated(const Vector3 &p_axis, real_t p_angle) const; + + void rotate_local(const Vector3 &p_axis, real_t p_angle); + Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const; + + void rotate(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ); + Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) const; + + void rotate(const Quaternion &p_quaternion); + Basis rotated(const Quaternion &p_quaternion) const; + 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; @@ -111,7 +100,7 @@ struct _NO_DISCARD_ Basis { void set_quaternion(const Quaternion &p_quaternion); void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const; - void set_axis_angle(const Vector3 &p_axis, real_t p_phi); + void set_axis_angle(const Vector3 &p_axis, real_t p_angle); void scale(const Vector3 &p_scale); Basis scaled(const Vector3 &p_scale) const; @@ -129,19 +118,19 @@ struct _NO_DISCARD_ Basis { Vector3 get_scale_abs() const; Vector3 get_scale_local() const; - void set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale); - void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale); + void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale); + void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EULER_ORDER_YXZ); void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale); // transposed dot products _FORCE_INLINE_ real_t tdotx(const Vector3 &v) const { - return elements[0][0] * v[0] + elements[1][0] * v[1] + elements[2][0] * v[2]; + return rows[0][0] * v[0] + rows[1][0] * v[1] + rows[2][0] * v[2]; } _FORCE_INLINE_ real_t tdoty(const Vector3 &v) const { - return elements[0][1] * v[0] + elements[1][1] * v[1] + elements[2][1] * v[2]; + return rows[0][1] * v[0] + rows[1][1] * v[1] + rows[2][1] * v[2]; } _FORCE_INLINE_ real_t tdotz(const Vector3 &v) const { - return elements[0][2] * v[0] + elements[1][2] * v[1] + elements[2][2] * v[2]; + return rows[0][2] * v[0] + rows[1][2] * v[1] + rows[2][2] * v[2]; } bool is_equal_approx(const Basis &p_basis) const; @@ -176,55 +165,55 @@ struct _NO_DISCARD_ Basis { /* create / set */ _FORCE_INLINE_ void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) { - elements[0][0] = xx; - elements[0][1] = xy; - elements[0][2] = xz; - elements[1][0] = yx; - elements[1][1] = yy; - elements[1][2] = yz; - elements[2][0] = zx; - elements[2][1] = zy; - elements[2][2] = zz; - } - _FORCE_INLINE_ void set(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) { - set_axis(0, p_x); - set_axis(1, p_y); - set_axis(2, p_z); + rows[0][0] = xx; + rows[0][1] = xy; + rows[0][2] = xz; + rows[1][0] = yx; + rows[1][1] = yy; + rows[1][2] = yz; + rows[2][0] = zx; + rows[2][1] = zy; + rows[2][2] = zz; } - _FORCE_INLINE_ Vector3 get_column(int i) const { - return Vector3(elements[0][i], elements[1][i], elements[2][i]); + _FORCE_INLINE_ void set_columns(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) { + set_column(0, p_x); + set_column(1, p_y); + set_column(2, p_z); } - _FORCE_INLINE_ Vector3 get_row(int i) const { - return Vector3(elements[i][0], elements[i][1], elements[i][2]); + _FORCE_INLINE_ Vector3 get_column(int p_index) const { + // Get actual basis axis column (we store transposed as rows for performance). + return Vector3(rows[0][p_index], rows[1][p_index], rows[2][p_index]); } - _FORCE_INLINE_ Vector3 get_main_diagonal() const { - return Vector3(elements[0][0], elements[1][1], elements[2][2]); + + _FORCE_INLINE_ void set_column(int p_index, const Vector3 &p_value) { + // Set actual basis axis column (we store transposed as rows for performance). + rows[0][p_index] = p_value.x; + rows[1][p_index] = p_value.y; + rows[2][p_index] = p_value.z; } - _FORCE_INLINE_ void set_row(int i, const Vector3 &p_row) { - elements[i][0] = p_row.x; - elements[i][1] = p_row.y; - elements[i][2] = p_row.z; + _FORCE_INLINE_ Vector3 get_main_diagonal() const { + return Vector3(rows[0][0], rows[1][1], rows[2][2]); } _FORCE_INLINE_ void set_zero() { - elements[0].zero(); - elements[1].zero(); - elements[2].zero(); + rows[0].zero(); + rows[1].zero(); + rows[2].zero(); } _FORCE_INLINE_ Basis transpose_xform(const Basis &m) const { return Basis( - elements[0].x * m[0].x + elements[1].x * m[1].x + elements[2].x * m[2].x, - elements[0].x * m[0].y + elements[1].x * m[1].y + elements[2].x * m[2].y, - elements[0].x * m[0].z + elements[1].x * m[1].z + elements[2].x * m[2].z, - elements[0].y * m[0].x + elements[1].y * m[1].x + elements[2].y * m[2].x, - elements[0].y * m[0].y + elements[1].y * m[1].y + elements[2].y * m[2].y, - elements[0].y * m[0].z + elements[1].y * m[1].z + elements[2].y * m[2].z, - elements[0].z * m[0].x + elements[1].z * m[1].x + elements[2].z * m[2].x, - elements[0].z * m[0].y + elements[1].z * m[1].y + elements[2].z * m[2].y, - elements[0].z * m[0].z + elements[1].z * m[1].z + elements[2].z * m[2].z); + rows[0].x * m[0].x + rows[1].x * m[1].x + rows[2].x * m[2].x, + rows[0].x * m[0].y + rows[1].x * m[1].y + rows[2].x * m[2].y, + rows[0].x * m[0].z + rows[1].x * m[1].z + rows[2].x * m[2].z, + rows[0].y * m[0].x + rows[1].y * m[1].x + rows[2].y * m[2].x, + rows[0].y * m[0].y + rows[1].y * m[1].y + rows[2].y * m[2].y, + rows[0].y * m[0].z + rows[1].y * m[1].z + rows[2].y * m[2].z, + rows[0].z * m[0].x + rows[1].z * m[1].x + rows[2].z * m[2].x, + rows[0].z * m[0].y + rows[1].z * m[1].y + rows[2].z * m[2].y, + rows[0].z * m[0].z + rows[1].z * m[1].z + rows[2].z * m[2].z); } Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) { set(xx, xy, xz, yx, yy, yz, zx, zy, zz); @@ -248,14 +237,14 @@ struct _NO_DISCARD_ Basis { 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_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); } + Basis(const Vector3 &p_axis, real_t p_angle) { set_axis_angle(p_axis, p_angle); } + Basis(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_angle, p_scale); } static Basis from_scale(const Vector3 &p_scale); _FORCE_INLINE_ Basis(const Vector3 &row0, const Vector3 &row1, const Vector3 &row2) { - elements[0] = row0; - elements[1] = row1; - elements[2] = row2; + rows[0] = row0; + rows[1] = row1; + rows[2] = row2; } _FORCE_INLINE_ Basis() {} @@ -267,22 +256,22 @@ private: _FORCE_INLINE_ void Basis::operator*=(const Basis &p_matrix) { set( - p_matrix.tdotx(elements[0]), p_matrix.tdoty(elements[0]), p_matrix.tdotz(elements[0]), - p_matrix.tdotx(elements[1]), p_matrix.tdoty(elements[1]), p_matrix.tdotz(elements[1]), - p_matrix.tdotx(elements[2]), p_matrix.tdoty(elements[2]), p_matrix.tdotz(elements[2])); + p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]), + p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]), + p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2])); } _FORCE_INLINE_ Basis Basis::operator*(const Basis &p_matrix) const { return Basis( - p_matrix.tdotx(elements[0]), p_matrix.tdoty(elements[0]), p_matrix.tdotz(elements[0]), - p_matrix.tdotx(elements[1]), p_matrix.tdoty(elements[1]), p_matrix.tdotz(elements[1]), - p_matrix.tdotx(elements[2]), p_matrix.tdoty(elements[2]), p_matrix.tdotz(elements[2])); + p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]), + p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]), + p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2])); } _FORCE_INLINE_ void Basis::operator+=(const Basis &p_matrix) { - elements[0] += p_matrix.elements[0]; - elements[1] += p_matrix.elements[1]; - elements[2] += p_matrix.elements[2]; + rows[0] += p_matrix.rows[0]; + rows[1] += p_matrix.rows[1]; + rows[2] += p_matrix.rows[2]; } _FORCE_INLINE_ Basis Basis::operator+(const Basis &p_matrix) const { @@ -292,9 +281,9 @@ _FORCE_INLINE_ Basis Basis::operator+(const Basis &p_matrix) const { } _FORCE_INLINE_ void Basis::operator-=(const Basis &p_matrix) { - elements[0] -= p_matrix.elements[0]; - elements[1] -= p_matrix.elements[1]; - elements[2] -= p_matrix.elements[2]; + rows[0] -= p_matrix.rows[0]; + rows[1] -= p_matrix.rows[1]; + rows[2] -= p_matrix.rows[2]; } _FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const { @@ -304,9 +293,9 @@ _FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const { } _FORCE_INLINE_ void Basis::operator*=(const real_t p_val) { - elements[0] *= p_val; - elements[1] *= p_val; - elements[2] *= p_val; + rows[0] *= p_val; + rows[1] *= p_val; + rows[2] *= p_val; } _FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const { @@ -317,22 +306,22 @@ _FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const { Vector3 Basis::xform(const Vector3 &p_vector) const { return Vector3( - elements[0].dot(p_vector), - elements[1].dot(p_vector), - elements[2].dot(p_vector)); + rows[0].dot(p_vector), + rows[1].dot(p_vector), + rows[2].dot(p_vector)); } Vector3 Basis::xform_inv(const Vector3 &p_vector) const { return Vector3( - (elements[0][0] * p_vector.x) + (elements[1][0] * p_vector.y) + (elements[2][0] * p_vector.z), - (elements[0][1] * p_vector.x) + (elements[1][1] * p_vector.y) + (elements[2][1] * p_vector.z), - (elements[0][2] * p_vector.x) + (elements[1][2] * p_vector.y) + (elements[2][2] * p_vector.z)); + (rows[0][0] * p_vector.x) + (rows[1][0] * p_vector.y) + (rows[2][0] * p_vector.z), + (rows[0][1] * p_vector.x) + (rows[1][1] * p_vector.y) + (rows[2][1] * p_vector.z), + (rows[0][2] * p_vector.x) + (rows[1][2] * p_vector.y) + (rows[2][2] * p_vector.z)); } 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]); + return rows[0][0] * (rows[1][1] * rows[2][2] - rows[2][1] * rows[1][2]) - + rows[1][0] * (rows[0][1] * rows[2][2] - rows[2][1] * rows[0][2]) + + rows[2][0] * (rows[0][1] * rows[1][2] - rows[1][1] * rows[0][2]); } #endif // BASIS_H diff --git a/core/math/bvh.h b/core/math/bvh.h index 9f6ab9f736..b5f5eda3e6 100644 --- a/core/math/bvh.h +++ b/core/math/bvh.h @@ -302,7 +302,7 @@ public: tree.update(); _check_for_collisions(); #ifdef BVH_INTEGRITY_CHECKS - tree.integrity_check_all(); + tree._integrity_check_all(); #endif } diff --git a/core/math/bvh_public.inc b/core/math/bvh_public.inc index 36b0bfeb13..fc1c67a21b 100644 --- a/core/math/bvh_public.inc +++ b/core/math/bvh_public.inc @@ -2,7 +2,7 @@ public: BVHHandle item_add(T *p_userdata, bool p_active, const BOUNDS &p_aabb, int32_t p_subindex, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_invisible = false) { #ifdef BVH_VERBOSE_TREE VERBOSE_PRINT("\nitem_add BEFORE"); - _debug_recursive_print_tree(0); + _debug_recursive_print_tree(p_tree_id); VERBOSE_PRINT("\n"); #endif @@ -78,8 +78,8 @@ BVHHandle item_add(T *p_userdata, bool p_active, const BOUNDS &p_aabb, int32_t p mem += _nodes.estimate_memory_use(); String sz = _debug_aabb_to_string(abb); - VERBOSE_PRINT("\titem_add [" + itos(ref_id) + "] " + itos(_refs.size()) + " refs,\t" + itos(_nodes.size()) + " nodes " + sz); - VERBOSE_PRINT("mem use : " + itos(mem) + ", num nodes : " + itos(_nodes.size())); + VERBOSE_PRINT("\titem_add [" + itos(ref_id) + "] " + itos(_refs.used_size()) + " refs,\t" + itos(_nodes.used_size()) + " nodes " + sz); + VERBOSE_PRINT("mem use : " + itos(mem) + ", num nodes reserved : " + itos(_nodes.reserved_size())); #endif diff --git a/core/math/color.cpp b/core/math/color.cpp index e32f9147d9..4bdeafd2f2 100644 --- a/core/math/color.cpp +++ b/core/math/color.cpp @@ -33,7 +33,9 @@ #include "color_names.inc" #include "core/math/math_funcs.h" #include "core/string/print_string.h" -#include "core/templates/map.h" +#include "core/templates/rb_map.h" + +#include "thirdparty/misc/ok_color.h" uint32_t Color::to_argb32() const { uint32_t c = (uint8_t)Math::round(a * 255); @@ -240,6 +242,20 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) { } } +void Color::set_ok_hsl(float p_h, float p_s, float p_l, float p_alpha) { + ok_color::HSL hsl; + hsl.h = p_h; + hsl.s = p_s; + hsl.l = p_l; + ok_color new_ok_color; + ok_color::RGB rgb = new_ok_color.okhsl_to_srgb(hsl); + Color c = Color(rgb.r, rgb.g, rgb.b, p_alpha).clamp(); + r = c.r; + g = c.g; + b = c.b; + a = c.a; +} + bool Color::is_equal_approx(const Color &p_color) const { return Math::is_equal_approx(r, p_color.r) && Math::is_equal_approx(g, p_color.g) && Math::is_equal_approx(b, p_color.b) && Math::is_equal_approx(a, p_color.a); } @@ -568,3 +584,48 @@ Color Color::operator-() const { 1.0f - b, 1.0f - a); } + +Color Color::from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha) { + Color c; + c.set_ok_hsl(p_h, p_s, p_l, p_alpha); + return c; +} + +float Color::get_ok_hsl_h() const { + ok_color::RGB rgb; + rgb.r = r; + rgb.g = g; + rgb.b = b; + ok_color new_ok_color; + ok_color::HSL ok_hsl = new_ok_color.srgb_to_okhsl(rgb); + if (Math::is_nan(ok_hsl.h)) { + return 0.0f; + } + return CLAMP(ok_hsl.h, 0.0f, 1.0f); +} + +float Color::get_ok_hsl_s() const { + ok_color::RGB rgb; + rgb.r = r; + rgb.g = g; + rgb.b = b; + ok_color new_ok_color; + ok_color::HSL ok_hsl = new_ok_color.srgb_to_okhsl(rgb); + if (Math::is_nan(ok_hsl.s)) { + return 0.0f; + } + return CLAMP(ok_hsl.s, 0.0f, 1.0f); +} + +float Color::get_ok_hsl_l() const { + ok_color::RGB rgb; + rgb.r = r; + rgb.g = g; + rgb.b = b; + ok_color new_ok_color; + ok_color::HSL ok_hsl = new_ok_color.srgb_to_okhsl(rgb); + if (Math::is_nan(ok_hsl.l)) { + return 0.0f; + } + return CLAMP(ok_hsl.l, 0.0f, 1.0f); +} diff --git a/core/math/color.h b/core/math/color.h index 91e0bf5532..65036f74cc 100644 --- a/core/math/color.h +++ b/core/math/color.h @@ -56,6 +56,10 @@ struct _NO_DISCARD_ Color { float get_s() const; float get_v() const; void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0); + float get_ok_hsl_h() const; + float get_ok_hsl_s() const; + float get_ok_hsl_l() const; + void set_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0); _FORCE_INLINE_ float &operator[](int p_idx) { return components[p_idx]; @@ -195,6 +199,7 @@ struct _NO_DISCARD_ Color { static Color get_named_color(int p_idx); static Color from_string(const String &p_string, const Color &p_default); static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0); + static Color from_ok_hsl(float p_h, float p_s, float p_l, 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 @@ -210,9 +215,12 @@ struct _NO_DISCARD_ Color { _FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0f); } _FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(Math::round(a * 255.0f), 0.0f, 255.0f)); } - _FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v()); } - _FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v()); } - _FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v); } + _FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v(), a); } + _FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v(), a); } + _FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v, a); } + _FORCE_INLINE_ void set_ok_hsl_h(float p_h) { set_ok_hsl(p_h, get_ok_hsl_s(), get_ok_hsl_l(), a); } + _FORCE_INLINE_ void set_ok_hsl_s(float p_s) { set_ok_hsl(get_ok_hsl_h(), p_s, get_ok_hsl_l(), a); } + _FORCE_INLINE_ void set_ok_hsl_l(float p_l) { set_ok_hsl(get_ok_hsl_h(), get_ok_hsl_s(), p_l, a); } _FORCE_INLINE_ Color() {} diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp index 23a0b5dd54..996f4f4d67 100644 --- a/core/math/convex_hull.cpp +++ b/core/math/convex_hull.cpp @@ -666,7 +666,7 @@ public: face_pool.reset(true); } - Vertex *vertex_list; + Vertex *vertex_list = nullptr; void compute(const Vector3 *p_coords, int32_t p_count); diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h index 7ad5f76645..898c3c2d91 100644 --- a/core/math/delaunay_3d.h +++ b/core/math/delaunay_3d.h @@ -33,7 +33,7 @@ #include "core/io/file_access.h" #include "core/math/aabb.h" -#include "core/math/camera_matrix.h" +#include "core/math/projection.h" #include "core/math/vector3.h" #include "core/string/print_string.h" #include "core/templates/local_vector.h" @@ -101,7 +101,7 @@ class Delaunay3D { _FORCE_INLINE_ static uint32_t hash(const Triangle &p_triangle) { uint32_t h = hash_djb2_one_32(p_triangle.triangle[0]); h = hash_djb2_one_32(p_triangle.triangle[1], h); - return hash_djb2_one_32(p_triangle.triangle[2], h); + return hash_fmix32(hash_djb2_one_32(p_triangle.triangle[2], h)); } }; @@ -184,7 +184,7 @@ class Delaunay3D { return true; } - CameraMatrix cm; + Projection cm; cm.matrix[0][0] = p_points[p_simplex.points[0]].x; cm.matrix[0][1] = p_points[p_simplex.points[1]].x; @@ -323,7 +323,6 @@ public: E = N; } - uint32_t good_triangles = 0; for (uint32_t j = 0; j < triangles.size(); j++) { if (triangles[j].bad) { continue; @@ -360,11 +359,8 @@ public: } } } - - good_triangles++; } - //print_line("at point " + itos(i) + "/" + itos(point_count) + " simplices added " + itos(good_triangles) + "/" + itos(simplex_list.size()) + " - triangles: " + itos(triangles.size())); triangles.clear(); triangles_inserted.clear(); } diff --git a/core/math/disjoint_set.h b/core/math/disjoint_set.h index 8657dc068e..d07c08e45e 100644 --- a/core/math/disjoint_set.h +++ b/core/math/disjoint_set.h @@ -31,11 +31,11 @@ #ifndef DISJOINT_SET_H #define DISJOINT_SET_H -#include "core/templates/map.h" +#include "core/templates/rb_map.h" #include "core/templates/vector.h" /* This DisjointSet class uses Find with path compression and Union by rank */ -template <typename T, class C = Comparator<T>, class AL = DefaultAllocator> +template <typename T, class H = HashMapHasherDefault, class C = HashMapComparatorDefault<T>, class AL = DefaultAllocator> class DisjointSet { struct Element { T object; @@ -43,7 +43,7 @@ class DisjointSet { int rank = 0; }; - typedef Map<T, Element *, C, AL> MapT; + typedef HashMap<T, Element *, H, C> MapT; MapT elements; @@ -65,15 +65,15 @@ public: /* FUNCTIONS */ -template <typename T, class C, class AL> -DisjointSet<T, C, AL>::~DisjointSet() { - for (typename MapT::Element *itr = elements.front(); itr != nullptr; itr = itr->next()) { - memdelete_allocator<Element, AL>(itr->value()); +template <typename T, class H, class C, class AL> +DisjointSet<T, H, C, AL>::~DisjointSet() { + for (KeyValue<T, Element *> &E : elements) { + memdelete_allocator<Element, AL>(E.value); } } -template <typename T, class C, class AL> -typename DisjointSet<T, C, AL>::Element *DisjointSet<T, C, AL>::get_parent(Element *element) { +template <typename T, class H, class C, class AL> +typename DisjointSet<T, H, C, AL>::Element *DisjointSet<T, H, C, AL>::get_parent(Element *element) { if (element->parent != element) { element->parent = get_parent(element->parent); } @@ -81,11 +81,11 @@ typename DisjointSet<T, C, AL>::Element *DisjointSet<T, C, AL>::get_parent(Eleme return element->parent; } -template <typename T, class C, class AL> -typename DisjointSet<T, C, AL>::Element *DisjointSet<T, C, AL>::insert_or_get(T object) { - typename MapT::Element *itr = elements.find(object); +template <typename T, class H, class C, class AL> +typename DisjointSet<T, H, C, AL>::Element *DisjointSet<T, H, C, AL>::insert_or_get(T object) { + typename MapT::Iterator itr = elements.find(object); if (itr != nullptr) { - return itr->value(); + return itr->value; } Element *new_element = memnew_allocator(Element, AL); @@ -96,8 +96,8 @@ typename DisjointSet<T, C, AL>::Element *DisjointSet<T, C, AL>::insert_or_get(T return new_element; } -template <typename T, class C, class AL> -void DisjointSet<T, C, AL>::create_union(T a, T b) { +template <typename T, class H, class C, class AL> +void DisjointSet<T, H, C, AL>::create_union(T a, T b) { Element *x = insert_or_get(a); Element *y = insert_or_get(b); @@ -121,28 +121,28 @@ void DisjointSet<T, C, AL>::create_union(T a, T b) { } } -template <typename T, class C, class AL> -void DisjointSet<T, C, AL>::get_representatives(Vector<T> &out_representatives) { - for (typename MapT::Element *itr = elements.front(); itr != nullptr; itr = itr->next()) { - Element *element = itr->value(); +template <typename T, class H, class C, class AL> +void DisjointSet<T, H, C, AL>::get_representatives(Vector<T> &out_representatives) { + for (KeyValue<T, Element *> &E : elements) { + Element *element = E.value; if (element->parent == element) { out_representatives.push_back(element->object); } } } -template <typename T, class C, class AL> -void DisjointSet<T, C, AL>::get_members(Vector<T> &out_members, T representative) { - typename MapT::Element *rep_itr = elements.find(representative); +template <typename T, class H, class C, class AL> +void DisjointSet<T, H, C, AL>::get_members(Vector<T> &out_members, T representative) { + typename MapT::Iterator rep_itr = elements.find(representative); ERR_FAIL_COND(rep_itr == nullptr); - Element *rep_element = rep_itr->value(); + Element *rep_element = rep_itr->value; ERR_FAIL_COND(rep_element->parent != rep_element); - for (typename MapT::Element *itr = elements.front(); itr != nullptr; itr = itr->next()) { - Element *parent = get_parent(itr->value()); + for (KeyValue<T, Element *> &E : elements) { + Element *parent = get_parent(E.value); if (parent == rep_element) { - out_members.push_back(itr->key()); + out_members.push_back(E.key); } } } diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 9dd1257474..e230b69dc9 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -155,7 +155,12 @@ Error Expression::_get_token(Token &r_token) { return OK; } case '*': { - r_token.type = TK_OP_MUL; + if (expression[str_ofs] == '*') { + r_token.type = TK_OP_POW; + str_ofs++; + } else { + r_token.type = TK_OP_MUL; + } return OK; } case '%': { @@ -542,6 +547,7 @@ const char *Expression::token_name[TK_MAX] = { "OP MUL", "OP DIV", "OP MOD", + "OP POW", "OP SHIFT LEFT", "OP SHIFT RIGHT", "OP BIT AND", @@ -885,7 +891,7 @@ Expression::ENode *Expression::_parse_expression() { case TK_PERIOD: { //named indexing or function call _get_token(tk); - if (tk.type != TK_IDENTIFIER) { + if (tk.type != TK_IDENTIFIER && tk.type != TK_BUILTIN_FUNC) { _set_error("Expected identifier after '.'"); return nullptr; } @@ -1013,6 +1019,9 @@ Expression::ENode *Expression::_parse_expression() { case TK_OP_MOD: op = Variant::OP_MODULE; break; + case TK_OP_POW: + op = Variant::OP_POWER; + break; case TK_OP_SHIFT_LEFT: op = Variant::OP_SHIFT_LEFT; break; @@ -1066,35 +1075,38 @@ Expression::ENode *Expression::_parse_expression() { bool unary = false; switch (expression[i].op) { - case Variant::OP_BIT_NEGATE: + case Variant::OP_POWER: priority = 0; + break; + case Variant::OP_BIT_NEGATE: + priority = 1; unary = true; break; case Variant::OP_NEGATE: - priority = 1; + priority = 2; unary = true; break; case Variant::OP_MULTIPLY: case Variant::OP_DIVIDE: case Variant::OP_MODULE: - priority = 2; + priority = 3; break; case Variant::OP_ADD: case Variant::OP_SUBTRACT: - priority = 3; + priority = 4; break; case Variant::OP_SHIFT_LEFT: case Variant::OP_SHIFT_RIGHT: - priority = 4; + priority = 5; break; case Variant::OP_BIT_AND: - priority = 5; + priority = 6; break; case Variant::OP_BIT_XOR: - priority = 6; + priority = 7; break; case Variant::OP_BIT_OR: - priority = 7; + priority = 8; break; case Variant::OP_LESS: case Variant::OP_LESS_EQUAL: @@ -1102,20 +1114,20 @@ Expression::ENode *Expression::_parse_expression() { case Variant::OP_GREATER_EQUAL: case Variant::OP_EQUAL: case Variant::OP_NOT_EQUAL: - priority = 8; + priority = 9; break; case Variant::OP_IN: - priority = 10; + priority = 11; break; case Variant::OP_NOT: - priority = 11; + priority = 12; unary = true; break; case Variant::OP_AND: - priority = 12; + priority = 13; break; case Variant::OP_OR: - priority = 13; + priority = 14; break; default: { _set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op)); @@ -1228,12 +1240,12 @@ bool Expression::_compile_expression() { return false; } -bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str) { +bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, bool p_const_calls_only, String &r_error_str) { switch (p_node->type) { case Expression::ENode::TYPE_INPUT: { const Expression::InputNode *in = static_cast<const Expression::InputNode *>(p_node); if (in->index < 0 || in->index >= p_inputs.size()) { - r_error_str = vformat(RTR("Invalid input %i (not passed) in expression"), in->index); + r_error_str = vformat(RTR("Invalid input %d (not passed) in expression"), in->index); return true; } r_ret = p_inputs[in->index]; @@ -1254,7 +1266,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: const Expression::OperatorNode *op = static_cast<const Expression::OperatorNode *>(p_node); Variant a; - bool ret = _execute(p_inputs, p_instance, op->nodes[0], a, r_error_str); + bool ret = _execute(p_inputs, p_instance, op->nodes[0], a, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1262,7 +1274,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: Variant b; if (op->nodes[1]) { - ret = _execute(p_inputs, p_instance, op->nodes[1], b, r_error_str); + ret = _execute(p_inputs, p_instance, op->nodes[1], b, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1280,14 +1292,14 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: const Expression::IndexNode *index = static_cast<const Expression::IndexNode *>(p_node); Variant base; - bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str); + bool ret = _execute(p_inputs, p_instance, index->base, base, p_const_calls_only, r_error_str); if (ret) { return true; } Variant idx; - ret = _execute(p_inputs, p_instance, index->index, idx, r_error_str); + ret = _execute(p_inputs, p_instance, index->index, idx, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1304,7 +1316,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: const Expression::NamedIndexNode *index = static_cast<const Expression::NamedIndexNode *>(p_node); Variant base; - bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str); + bool ret = _execute(p_inputs, p_instance, index->base, base, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1324,7 +1336,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: arr.resize(array->array.size()); for (int i = 0; i < array->array.size(); i++) { Variant value; - bool ret = _execute(p_inputs, p_instance, array->array[i], value, r_error_str); + bool ret = _execute(p_inputs, p_instance, array->array[i], value, p_const_calls_only, r_error_str); if (ret) { return true; @@ -1341,14 +1353,14 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: Dictionary d; for (int i = 0; i < dictionary->dict.size(); i += 2) { Variant key; - bool ret = _execute(p_inputs, p_instance, dictionary->dict[i + 0], key, r_error_str); + bool ret = _execute(p_inputs, p_instance, dictionary->dict[i + 0], key, p_const_calls_only, r_error_str); if (ret) { return true; } Variant value; - ret = _execute(p_inputs, p_instance, dictionary->dict[i + 1], value, r_error_str); + ret = _execute(p_inputs, p_instance, dictionary->dict[i + 1], value, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1368,7 +1380,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: for (int i = 0; i < constructor->arguments.size(); i++) { Variant value; - bool ret = _execute(p_inputs, p_instance, constructor->arguments[i], value, r_error_str); + bool ret = _execute(p_inputs, p_instance, constructor->arguments[i], value, p_const_calls_only, r_error_str); if (ret) { return true; @@ -1396,7 +1408,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: for (int i = 0; i < bifunc->arguments.size(); i++) { Variant value; - bool ret = _execute(p_inputs, p_instance, bifunc->arguments[i], value, r_error_str); + bool ret = _execute(p_inputs, p_instance, bifunc->arguments[i], value, p_const_calls_only, r_error_str); if (ret) { return true; } @@ -1417,7 +1429,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: const Expression::CallNode *call = static_cast<const Expression::CallNode *>(p_node); Variant base; - bool ret = _execute(p_inputs, p_instance, call->base, base, r_error_str); + bool ret = _execute(p_inputs, p_instance, call->base, base, p_const_calls_only, r_error_str); if (ret) { return true; @@ -1430,7 +1442,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: for (int i = 0; i < call->arguments.size(); i++) { Variant value; - ret = _execute(p_inputs, p_instance, call->arguments[i], value, r_error_str); + ret = _execute(p_inputs, p_instance, call->arguments[i], value, p_const_calls_only, r_error_str); if (ret) { return true; @@ -1440,7 +1452,11 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression: } Callable::CallError ce; - base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce); + if (p_const_calls_only) { + base.call_const(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce); + } else { + base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce); + } if (ce.error != Callable::CallError::CALL_OK) { r_error_str = vformat(RTR("On call to '%s':"), String(call->method)); @@ -1479,13 +1495,13 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu return OK; } -Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) { +Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error, bool p_const_calls_only) { ERR_FAIL_COND_V_MSG(error_set, Variant(), "There was previously a parse error: " + error_str + "."); execution_error = false; Variant output; String error_txt; - bool err = _execute(p_inputs, p_base, root, output, error_txt); + bool err = _execute(p_inputs, p_base, root, output, p_const_calls_only, error_txt); if (err) { execution_error = true; error_str = error_txt; @@ -1505,7 +1521,7 @@ String Expression::get_error_text() const { void Expression::_bind_methods() { ClassDB::bind_method(D_METHOD("parse", "expression", "input_names"), &Expression::parse, DEFVAL(Vector<String>())); - ClassDB::bind_method(D_METHOD("execute", "inputs", "base_instance", "show_error"), &Expression::execute, DEFVAL(Array()), DEFVAL(Variant()), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("execute", "inputs", "base_instance", "show_error", "const_calls_only"), &Expression::execute, DEFVAL(Array()), DEFVAL(Variant()), DEFVAL(true), DEFVAL(false)); ClassDB::bind_method(D_METHOD("has_execute_failed"), &Expression::has_execute_failed); ClassDB::bind_method(D_METHOD("get_error_text"), &Expression::get_error_text); } diff --git a/core/math/expression.h b/core/math/expression.h index d43cc4091a..2d58915996 100644 --- a/core/math/expression.h +++ b/core/math/expression.h @@ -85,6 +85,7 @@ private: TK_OP_MUL, TK_OP_DIV, TK_OP_MOD, + TK_OP_POW, TK_OP_SHIFT_LEFT, TK_OP_SHIFT_RIGHT, TK_OP_BIT_AND, @@ -256,14 +257,14 @@ private: Vector<String> input_names; bool execution_error = false; - bool _execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str); + bool _execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, bool p_const_calls_only, String &r_error_str); protected: static void _bind_methods(); public: Error parse(const String &p_expression, const Vector<String> &p_input_names = Vector<String>()); - Variant execute(Array p_inputs = Array(), Object *p_base = nullptr, bool p_show_error = true); + Variant execute(Array p_inputs = Array(), Object *p_base = nullptr, bool p_show_error = true, bool p_const_calls_only = false); bool has_execute_failed() const; String get_error_text() const; diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp index 46b7d99b43..31fade5a99 100644 --- a/core/math/geometry_2d.cpp +++ b/core/math/geometry_2d.cpp @@ -74,14 +74,14 @@ Vector<Vector<Vector2>> Geometry2D::decompose_polygon_in_convex(Vector<Point2> p struct _AtlasWorkRect { Size2i s; Point2i p; - int idx; + int idx = 0; _FORCE_INLINE_ bool operator<(const _AtlasWorkRect &p_r) const { return s.width > p_r.s.width; }; }; struct _AtlasWorkRectResult { Vector<_AtlasWorkRect> result; - int max_w; - int max_h; + int max_w = 0; + int max_h = 0; }; void Geometry2D::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size) { diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp index f76de079e4..ec96753c79 100644 --- a/core/math/geometry_3d.cpp +++ b/core/math/geometry_3d.cpp @@ -36,7 +36,7 @@ #include "thirdparty/misc/polypartition.h" void Geometry3D::MeshData::optimize_vertices() { - Map<int, int> vtx_remap; + HashMap<int, int> vtx_remap; for (int i = 0; i < faces.size(); i++) { for (int j = 0; j < faces[i].indices.size(); j++) { diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp index 1717ecd74b..208f89f449 100644 --- a/core/math/math_fieldwise.cpp +++ b/core/math/math_fieldwise.cpp @@ -76,6 +76,36 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const return target; } + case Variant::VECTOR3I: { + SETUP_TYPE(Vector3i) + + /**/ TRY_TRANSFER_FIELD("x", x) + else TRY_TRANSFER_FIELD("y", y) + else TRY_TRANSFER_FIELD("z", z) + + return target; + } + case Variant::VECTOR4: { + SETUP_TYPE(Vector4) + + /**/ TRY_TRANSFER_FIELD("x", x) + else TRY_TRANSFER_FIELD("y", y) + else TRY_TRANSFER_FIELD("z", z) + else TRY_TRANSFER_FIELD("w", w) + + return target; + } + case Variant::VECTOR4I: { + SETUP_TYPE(Vector4i) + + /**/ TRY_TRANSFER_FIELD("x", x) + else TRY_TRANSFER_FIELD("y", y) + else TRY_TRANSFER_FIELD("z", z) + else TRY_TRANSFER_FIELD("w", w) + + return target; + } + case Variant::PLANE: { SETUP_TYPE(Plane) @@ -115,12 +145,12 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const case Variant::TRANSFORM2D: { SETUP_TYPE(Transform2D) - /**/ TRY_TRANSFER_FIELD("xx", elements[0][0]) - else TRY_TRANSFER_FIELD("xy", elements[0][1]) - else TRY_TRANSFER_FIELD("yx", elements[1][0]) - else TRY_TRANSFER_FIELD("yy", elements[1][1]) - else TRY_TRANSFER_FIELD("ox", elements[2][0]) - else TRY_TRANSFER_FIELD("oy", elements[2][1]) + /**/ TRY_TRANSFER_FIELD("xx", columns[0][0]) + else TRY_TRANSFER_FIELD("xy", columns[0][1]) + else TRY_TRANSFER_FIELD("yx", columns[1][0]) + else TRY_TRANSFER_FIELD("yy", columns[1][1]) + else TRY_TRANSFER_FIELD("ox", columns[2][0]) + else TRY_TRANSFER_FIELD("oy", columns[2][1]) return target; } @@ -128,15 +158,15 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const case Variant::BASIS: { SETUP_TYPE(Basis) - /**/ TRY_TRANSFER_FIELD("xx", elements[0][0]) - else TRY_TRANSFER_FIELD("xy", elements[0][1]) - else TRY_TRANSFER_FIELD("xz", elements[0][2]) - else TRY_TRANSFER_FIELD("yx", elements[1][0]) - else TRY_TRANSFER_FIELD("yy", elements[1][1]) - else TRY_TRANSFER_FIELD("yz", elements[1][2]) - else TRY_TRANSFER_FIELD("zx", elements[2][0]) - else TRY_TRANSFER_FIELD("zy", elements[2][1]) - else TRY_TRANSFER_FIELD("zz", elements[2][2]) + /**/ TRY_TRANSFER_FIELD("xx", rows[0][0]) + else TRY_TRANSFER_FIELD("xy", rows[0][1]) + else TRY_TRANSFER_FIELD("xz", rows[0][2]) + else TRY_TRANSFER_FIELD("yx", rows[1][0]) + else TRY_TRANSFER_FIELD("yy", rows[1][1]) + else TRY_TRANSFER_FIELD("yz", rows[1][2]) + else TRY_TRANSFER_FIELD("zx", rows[2][0]) + else TRY_TRANSFER_FIELD("zy", rows[2][1]) + else TRY_TRANSFER_FIELD("zz", rows[2][2]) return target; } @@ -144,15 +174,15 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const case Variant::TRANSFORM3D: { SETUP_TYPE(Transform3D) - /**/ TRY_TRANSFER_FIELD("xx", basis.elements[0][0]) - else TRY_TRANSFER_FIELD("xy", basis.elements[0][1]) - else TRY_TRANSFER_FIELD("xz", basis.elements[0][2]) - else TRY_TRANSFER_FIELD("yx", basis.elements[1][0]) - else TRY_TRANSFER_FIELD("yy", basis.elements[1][1]) - else TRY_TRANSFER_FIELD("yz", basis.elements[1][2]) - else TRY_TRANSFER_FIELD("zx", basis.elements[2][0]) - else TRY_TRANSFER_FIELD("zy", basis.elements[2][1]) - else TRY_TRANSFER_FIELD("zz", basis.elements[2][2]) + /**/ TRY_TRANSFER_FIELD("xx", basis.rows[0][0]) + else TRY_TRANSFER_FIELD("xy", basis.rows[0][1]) + else TRY_TRANSFER_FIELD("xz", basis.rows[0][2]) + else TRY_TRANSFER_FIELD("yx", basis.rows[1][0]) + else TRY_TRANSFER_FIELD("yy", basis.rows[1][1]) + else TRY_TRANSFER_FIELD("yz", basis.rows[1][2]) + else TRY_TRANSFER_FIELD("zx", basis.rows[2][0]) + else TRY_TRANSFER_FIELD("zy", basis.rows[2][1]) + else TRY_TRANSFER_FIELD("zz", basis.rows[2][2]) else TRY_TRANSFER_FIELD("xo", origin.x) else TRY_TRANSFER_FIELD("yo", origin.y) else TRY_TRANSFER_FIELD("zo", origin.z) diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 068bc0397e..53deb9bd42 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -253,6 +253,27 @@ public: (-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight)); } + static _ALWAYS_INLINE_ double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + double omt = (1.0 - p_t); + double omt2 = omt * omt; + double omt3 = omt2 * omt; + double t2 = p_t * p_t; + double t3 = t2 * p_t; + + return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; + } + static _ALWAYS_INLINE_ float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + float omt = (1.0f - p_t); + float omt2 = omt * omt; + float omt3 = omt2 * omt; + float t2 = p_t * p_t; + float t3 = t2 * p_t; + + return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3; + } + static _ALWAYS_INLINE_ double lerp_angle(double p_from, double p_to, double p_weight) { double difference = fmod(p_to - p_from, Math_TAU); double distance = fmod(2.0 * difference, Math_TAU) - difference; @@ -302,11 +323,19 @@ public: } static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) { double range = max - min; - return is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); + double result = is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); + if (is_equal_approx(result, max)) { + return min; + } + return result; } static _ALWAYS_INLINE_ float wrapf(float value, float min, float max) { float range = max - min; - return is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); + float result = is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); + if (is_equal_approx(result, max)) { + return min; + } + return result; } static _ALWAYS_INLINE_ float fract(float value) { diff --git a/core/math/octree.h b/core/math/octree.h deleted file mode 100644 index 65ab9e2292..0000000000 --- a/core/math/octree.h +++ /dev/null @@ -1,1271 +0,0 @@ -/*************************************************************************/ -/* octree.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 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 OCTREE_H -#define OCTREE_H - -#include "core/math/aabb.h" -#include "core/math/geometry_3d.h" -#include "core/math/vector3.h" -#include "core/string/print_string.h" -#include "core/templates/list.h" -#include "core/templates/map.h" -#include "core/variant/variant.h" - -typedef uint32_t OctreeElementID; - -#define OCTREE_ELEMENT_INVALID_ID 0 -#define OCTREE_SIZE_LIMIT 1e15 - -template <class T, bool use_pairs = false, class AL = DefaultAllocator> -class Octree { -public: - typedef void *(*PairCallback)(void *, OctreeElementID, T *, int, OctreeElementID, T *, int); - typedef void (*UnpairCallback)(void *, OctreeElementID, T *, int, OctreeElementID, T *, int, void *); - -private: - enum { - NEG = 0, - POS = 1, - }; - - enum { - OCTANT_NX_NY_NZ, - OCTANT_PX_NY_NZ, - OCTANT_NX_PY_NZ, - OCTANT_PX_PY_NZ, - OCTANT_NX_NY_PZ, - OCTANT_PX_NY_PZ, - OCTANT_NX_PY_PZ, - OCTANT_PX_PY_PZ - }; - - struct PairKey { - union { - struct { - OctreeElementID A; - OctreeElementID B; - }; - uint64_t key; - }; - - _FORCE_INLINE_ bool operator<(const PairKey &p_pair) const { - return key < p_pair.key; - } - - _FORCE_INLINE_ PairKey(OctreeElementID p_A, OctreeElementID p_B) { - if (p_A < p_B) { - A = p_A; - B = p_B; - } else { - B = p_A; - A = p_B; - } - } - - _FORCE_INLINE_ PairKey() {} - }; - - struct Element; - - struct Octant { - // cached for FAST plane check - AABB aabb; - - uint64_t last_pass = 0; - Octant *parent = nullptr; - Octant *children[8] = { nullptr }; - - int children_count = 0; // cache for amount of children (fast check for removal) - int parent_index = -1; // cache for parent index (fast check for removal) - - List<Element *, AL> pairable_elements; - List<Element *, AL> elements; - - Octant() {} - ~Octant() {} - }; - - struct PairData; - - struct Element { - Octree *octree = nullptr; - - T *userdata = nullptr; - int subindex = 0; - bool pairable = false; - uint32_t pairable_mask = 0; - uint32_t pairable_type = 0; - - uint64_t last_pass = 0; - OctreeElementID _id = 0; - Octant *common_parent = nullptr; - - AABB aabb; - AABB container_aabb; - - List<PairData *, AL> pair_list; - - struct OctantOwner { - Octant *octant = nullptr; - typename List<Element *, AL>::Element *E; - }; // an element can be in max 8 octants - - List<OctantOwner, AL> octant_owners; - - Element() {} - }; - - struct PairData { - int refcount; - bool intersect; - Element *A, *B; - void *ud = nullptr; - typename List<PairData *, AL>::Element *eA, *eB; - }; - - typedef Map<OctreeElementID, Element, Comparator<OctreeElementID>, AL> ElementMap; - typedef Map<PairKey, PairData, Comparator<PairKey>, AL> PairMap; - ElementMap element_map; - PairMap pair_map; - - PairCallback pair_callback = nullptr; - UnpairCallback unpair_callback = nullptr; - void *pair_callback_userdata = nullptr; - void *unpair_callback_userdata = nullptr; - - OctreeElementID last_element_id = 1; - uint64_t pass = 1; - - real_t unit_size = 1.0; - Octant *root = nullptr; - int octant_count = 0; - int pair_count = 0; - - _FORCE_INLINE_ void _pair_check(PairData *p_pair) { - bool intersect = p_pair->A->aabb.intersects_inclusive(p_pair->B->aabb); - - if (intersect != p_pair->intersect) { - if (intersect) { - if (pair_callback) { - p_pair->ud = pair_callback(pair_callback_userdata, p_pair->A->_id, p_pair->A->userdata, p_pair->A->subindex, p_pair->B->_id, p_pair->B->userdata, p_pair->B->subindex); - } - pair_count++; - } else { - if (unpair_callback) { - unpair_callback(pair_callback_userdata, p_pair->A->_id, p_pair->A->userdata, p_pair->A->subindex, p_pair->B->_id, p_pair->B->userdata, p_pair->B->subindex, p_pair->ud); - } - pair_count--; - } - - p_pair->intersect = intersect; - } - } - - _FORCE_INLINE_ void _pair_reference(Element *p_A, Element *p_B) { - if (p_A == p_B || (p_A->userdata == p_B->userdata && p_A->userdata)) { - return; - } - - if (!(p_A->pairable_type & p_B->pairable_mask) && - !(p_B->pairable_type & p_A->pairable_mask)) { - return; // none can pair with none - } - - PairKey key(p_A->_id, p_B->_id); - typename PairMap::Element *E = pair_map.find(key); - - if (!E) { - PairData pdata; - pdata.refcount = 1; - pdata.A = p_A; - pdata.B = p_B; - pdata.intersect = false; - E = pair_map.insert(key, pdata); - E->get().eA = p_A->pair_list.push_back(&E->get()); - E->get().eB = p_B->pair_list.push_back(&E->get()); - } else { - E->get().refcount++; - } - } - - _FORCE_INLINE_ void _pair_unreference(Element *p_A, Element *p_B) { - if (p_A == p_B) { - return; - } - - PairKey key(p_A->_id, p_B->_id); - typename PairMap::Element *E = pair_map.find(key); - if (!E) { - return; // no pair - } - - E->get().refcount--; - - if (E->get().refcount == 0) { - // bye pair - - if (E->get().intersect) { - if (unpair_callback) { - unpair_callback(pair_callback_userdata, p_A->_id, p_A->userdata, p_A->subindex, p_B->_id, p_B->userdata, p_B->subindex, E->get().ud); - } - - pair_count--; - } - - if (p_A == E->get().B) { - //may be reaching inverted - SWAP(p_A, p_B); - } - - p_A->pair_list.erase(E->get().eA); - p_B->pair_list.erase(E->get().eB); - pair_map.erase(E); - } - } - - _FORCE_INLINE_ void _element_check_pairs(Element *p_element) { - typename List<PairData *, AL>::Element *E = p_element->pair_list.front(); - while (E) { - _pair_check(E->get()); - E = E->next(); - } - } - - _FORCE_INLINE_ void _optimize() { - while (root && root->children_count < 2 && !root->elements.size() && !(use_pairs && root->pairable_elements.size())) { - Octant *new_root = nullptr; - if (root->children_count == 1) { - for (int i = 0; i < 8; i++) { - if (root->children[i]) { - new_root = root->children[i]; - root->children[i] = nullptr; - break; - } - } - ERR_FAIL_COND(!new_root); - new_root->parent = nullptr; - new_root->parent_index = -1; - } - - memdelete_allocator<Octant, AL>(root); - octant_count--; - root = new_root; - } - } - - void _insert_element(Element *p_element, Octant *p_octant); - void _ensure_valid_root(const AABB &p_aabb); - bool _remove_element_from_octant(Element *p_element, Octant *p_octant, Octant *p_limit = nullptr); - void _remove_element(Element *p_element); - void _pair_element(Element *p_element, Octant *p_octant); - void _unpair_element(Element *p_element, Octant *p_octant); - - struct _CullConvexData { - const Plane *planes; - int plane_count; - const Vector3 *points; - int point_count; - T **result_array; - int *result_idx = nullptr; - int result_max; - uint32_t mask; - }; - - void _cull_convex(Octant *p_octant, _CullConvexData *p_cull); - void _cull_aabb(Octant *p_octant, const AABB &p_aabb, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask); - void _cull_segment(Octant *p_octant, const Vector3 &p_from, const Vector3 &p_to, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask); - void _cull_point(Octant *p_octant, const Vector3 &p_point, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask); - - void _remove_tree(Octant *p_octant) { - if (!p_octant) { - return; - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i]) { - _remove_tree(p_octant->children[i]); - } - } - - memdelete_allocator<Octant, AL>(p_octant); - } - -public: - OctreeElementID create(T *p_userdata, const AABB &p_aabb = AABB(), int p_subindex = 0, bool p_pairable = false, uint32_t p_pairable_type = 0, uint32_t pairable_mask = 1); - void move(OctreeElementID p_id, const AABB &p_aabb); - void set_pairable(OctreeElementID p_id, bool p_pairable = false, uint32_t p_pairable_type = 0, uint32_t pairable_mask = 1); - void erase(OctreeElementID p_id); - - bool is_pairable(OctreeElementID p_id) const; - T *get(OctreeElementID p_id) const; - int get_subindex(OctreeElementID p_id) const; - - int cull_convex(const Vector<Plane> &p_convex, T **p_result_array, int p_result_max, uint32_t p_mask = 0xFFFFFFFF); - int cull_aabb(const AABB &p_aabb, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF); - int cull_segment(const Vector3 &p_from, const Vector3 &p_to, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF); - - int cull_point(const Vector3 &p_point, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF); - - void set_pair_callback(PairCallback p_callback, void *p_userdata); - void set_unpair_callback(UnpairCallback p_callback, void *p_userdata); - - int get_octant_count() const { return octant_count; } - int get_pair_count() const { return pair_count; } - Octree(real_t p_unit_size = 1.0); - ~Octree() { _remove_tree(root); } -}; - -/* PRIVATE FUNCTIONS */ - -template <class T, bool use_pairs, class AL> -T *Octree<T, use_pairs, AL>::get(OctreeElementID p_id) const { - const typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, nullptr); - return E->get().userdata; -} - -template <class T, bool use_pairs, class AL> -bool Octree<T, use_pairs, AL>::is_pairable(OctreeElementID p_id) const { - const typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, false); - return E->get().pairable; -} - -template <class T, bool use_pairs, class AL> -int Octree<T, use_pairs, AL>::get_subindex(OctreeElementID p_id) const { - const typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND_V(!E, -1); - return E->get().subindex; -} - -#define OCTREE_DIVISOR 4 - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_insert_element(Element *p_element, Octant *p_octant) { - real_t element_size = p_element->aabb.get_longest_axis_size() * 1.01; // avoid precision issues - - if (p_octant->aabb.size.x / OCTREE_DIVISOR < element_size) { - //if (p_octant->aabb.size.x*0.5 < element_size) { - /* at smallest possible size for the element */ - typename Element::OctantOwner owner; - owner.octant = p_octant; - - if (use_pairs && p_element->pairable) { - p_octant->pairable_elements.push_back(p_element); - owner.E = p_octant->pairable_elements.back(); - } else { - p_octant->elements.push_back(p_element); - owner.E = p_octant->elements.back(); - } - - p_element->octant_owners.push_back(owner); - - if (p_element->common_parent == nullptr) { - p_element->common_parent = p_octant; - p_element->container_aabb = p_octant->aabb; - } else { - p_element->container_aabb.merge_with(p_octant->aabb); - } - - if (use_pairs && p_octant->children_count > 0) { - pass++; //elements below this only get ONE reference added - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i]) { - _pair_element(p_element, p_octant->children[i]); - } - } - } - } else { - /* not big enough, send it to subitems */ - int splits = 0; - bool candidate = p_element->common_parent == nullptr; - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i]) { - /* element exists, go straight to it */ - if (p_octant->children[i]->aabb.intersects_inclusive(p_element->aabb)) { - _insert_element(p_element, p_octant->children[i]); - splits++; - } - } else { - /* check against AABB where child should be */ - - AABB aabb = p_octant->aabb; - aabb.size *= 0.5; - - if (i & 1) { - aabb.position.x += aabb.size.x; - } - if (i & 2) { - aabb.position.y += aabb.size.y; - } - if (i & 4) { - aabb.position.z += aabb.size.z; - } - - if (aabb.intersects_inclusive(p_element->aabb)) { - /* if actually intersects, create the child */ - - Octant *child = memnew_allocator(Octant, AL); - p_octant->children[i] = child; - child->parent = p_octant; - child->parent_index = i; - - child->aabb = aabb; - - p_octant->children_count++; - - _insert_element(p_element, child); - octant_count++; - splits++; - } - } - } - - if (candidate && splits > 1) { - p_element->common_parent = p_octant; - } - } - - if (use_pairs) { - typename List<Element *, AL>::Element *E = p_octant->pairable_elements.front(); - - while (E) { - _pair_reference(p_element, E->get()); - E = E->next(); - } - - if (p_element->pairable) { - // and always test non-pairable if element is pairable - E = p_octant->elements.front(); - while (E) { - _pair_reference(p_element, E->get()); - E = E->next(); - } - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_ensure_valid_root(const AABB &p_aabb) { - if (!root) { - // octre is empty - - AABB base(Vector3(), Vector3(1.0, 1.0, 1.0) * unit_size); - - while (!base.encloses(p_aabb)) { - if (ABS(base.position.x + base.size.x) <= ABS(base.position.x)) { - /* grow towards positive */ - base.size *= 2.0; - } else { - base.position -= base.size; - base.size *= 2.0; - } - } - - root = memnew_allocator(Octant, AL); - - root->parent = nullptr; - root->parent_index = -1; - root->aabb = base; - - octant_count++; - - } else { - AABB base = root->aabb; - - while (!base.encloses(p_aabb)) { - ERR_FAIL_COND_MSG(base.size.x > OCTREE_SIZE_LIMIT, "Octree upper size limit reached, does the AABB supplied contain NAN?"); - - Octant *gp = memnew_allocator(Octant, AL); - octant_count++; - root->parent = gp; - - if (ABS(base.position.x + base.size.x) <= ABS(base.position.x)) { - /* grow towards positive */ - base.size *= 2.0; - gp->aabb = base; - gp->children[0] = root; - root->parent_index = 0; - } else { - base.position -= base.size; - base.size *= 2.0; - gp->aabb = base; - gp->children[(1 << 0) | (1 << 1) | (1 << 2)] = root; // add at all-positive - root->parent_index = (1 << 0) | (1 << 1) | (1 << 2); - } - - gp->children_count = 1; - root = gp; - } - } -} - -template <class T, bool use_pairs, class AL> -bool Octree<T, use_pairs, AL>::_remove_element_from_octant(Element *p_element, Octant *p_octant, Octant *p_limit) { - bool octant_removed = false; - - while (true) { - // check all exit conditions - - if (p_octant == p_limit) { // reached limit, nothing to erase, exit - return octant_removed; - } - - bool unpaired = false; - - if (use_pairs && p_octant->last_pass != pass) { - // check whether we should unpair stuff - // always test pairable - typename List<Element *, AL>::Element *E = p_octant->pairable_elements.front(); - while (E) { - _pair_unreference(p_element, E->get()); - E = E->next(); - } - if (p_element->pairable) { - // and always test non-pairable if element is pairable - E = p_octant->elements.front(); - while (E) { - _pair_unreference(p_element, E->get()); - E = E->next(); - } - } - p_octant->last_pass = pass; - unpaired = true; - } - - bool removed = false; - - Octant *parent = p_octant->parent; - - if (p_octant->children_count == 0 && p_octant->elements.is_empty() && p_octant->pairable_elements.is_empty()) { - // erase octant - - if (p_octant == root) { // won't have a parent, just erase - - root = nullptr; - } else { - ERR_FAIL_INDEX_V(p_octant->parent_index, 8, octant_removed); - - parent->children[p_octant->parent_index] = nullptr; - parent->children_count--; - } - - memdelete_allocator<Octant, AL>(p_octant); - octant_count--; - removed = true; - octant_removed = true; - } - - if (!removed && !unpaired) { - return octant_removed; // no reason to keep going up anymore! was already visited and was not removed - } - - p_octant = parent; - } - - return octant_removed; -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_unpair_element(Element *p_element, Octant *p_octant) { - // always test pairable - typename List<Element *, AL>::Element *E = p_octant->pairable_elements.front(); - while (E) { - if (E->get()->last_pass != pass) { // only remove ONE reference - _pair_unreference(p_element, E->get()); - E->get()->last_pass = pass; - } - E = E->next(); - } - - if (p_element->pairable) { - // and always test non-pairable if element is pairable - E = p_octant->elements.front(); - while (E) { - if (E->get()->last_pass != pass) { // only remove ONE reference - _pair_unreference(p_element, E->get()); - E->get()->last_pass = pass; - } - E = E->next(); - } - } - - p_octant->last_pass = pass; - - if (p_octant->children_count == 0) { - return; // small optimization for leafs - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i]) { - _unpair_element(p_element, p_octant->children[i]); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_pair_element(Element *p_element, Octant *p_octant) { - // always test pairable - - typename List<Element *, AL>::Element *E = p_octant->pairable_elements.front(); - - while (E) { - if (E->get()->last_pass != pass) { // only get ONE reference - _pair_reference(p_element, E->get()); - E->get()->last_pass = pass; - } - E = E->next(); - } - - if (p_element->pairable) { - // and always test non-pairable if element is pairable - E = p_octant->elements.front(); - while (E) { - if (E->get()->last_pass != pass) { // only get ONE reference - _pair_reference(p_element, E->get()); - E->get()->last_pass = pass; - } - E = E->next(); - } - } - p_octant->last_pass = pass; - - if (p_octant->children_count == 0) { - return; // small optimization for leafs - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i]) { - _pair_element(p_element, p_octant->children[i]); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_remove_element(Element *p_element) { - pass++; // will do a new pass for this - - typename List<typename Element::OctantOwner, AL>::Element *I = p_element->octant_owners.front(); - - /* FIRST remove going up normally */ - for (; I; I = I->next()) { - Octant *o = I->get().octant; - - if (!use_pairs) { // small speedup - o->elements.erase(I->get().E); - } - - _remove_element_from_octant(p_element, o); - } - - /* THEN remove going down */ - - I = p_element->octant_owners.front(); - - if (use_pairs) { - for (; I; I = I->next()) { - Octant *o = I->get().octant; - - // erase children pairs, they are erased ONCE even if repeated - pass++; - for (int i = 0; i < 8; i++) { - if (o->children[i]) { - _unpair_element(p_element, o->children[i]); - } - } - - if (p_element->pairable) { - o->pairable_elements.erase(I->get().E); - } else { - o->elements.erase(I->get().E); - } - } - } - - p_element->octant_owners.clear(); - - if (use_pairs) { - int remaining = p_element->pair_list.size(); - //p_element->pair_list.clear(); - ERR_FAIL_COND(remaining); - } -} - -template <class T, bool use_pairs, class AL> -OctreeElementID Octree<T, use_pairs, AL>::create(T *p_userdata, const AABB &p_aabb, int p_subindex, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask) { -// check for AABB validity -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_V(p_aabb.position.x > 1e15 || p_aabb.position.x < -1e15, 0); - ERR_FAIL_COND_V(p_aabb.position.y > 1e15 || p_aabb.position.y < -1e15, 0); - ERR_FAIL_COND_V(p_aabb.position.z > 1e15 || p_aabb.position.z < -1e15, 0); - ERR_FAIL_COND_V(p_aabb.size.x > 1e15 || p_aabb.size.x < 0.0, 0); - ERR_FAIL_COND_V(p_aabb.size.y > 1e15 || p_aabb.size.y < 0.0, 0); - ERR_FAIL_COND_V(p_aabb.size.z > 1e15 || p_aabb.size.z < 0.0, 0); - ERR_FAIL_COND_V(Math::is_nan(p_aabb.size.x), 0); - ERR_FAIL_COND_V(Math::is_nan(p_aabb.size.y), 0); - ERR_FAIL_COND_V(Math::is_nan(p_aabb.size.z), 0); - -#endif - typename ElementMap::Element *E = element_map.insert(last_element_id++, - Element()); - Element &e = E->get(); - - e.aabb = p_aabb; - e.userdata = p_userdata; - e.subindex = p_subindex; - e.last_pass = 0; - e.octree = this; - e.pairable = p_pairable; - e.pairable_type = p_pairable_type; - e.pairable_mask = p_pairable_mask; - e._id = last_element_id - 1; - - if (!e.aabb.has_no_surface()) { - _ensure_valid_root(p_aabb); - _insert_element(&e, root); - if (use_pairs) { - _element_check_pairs(&e); - } - } - - return last_element_id - 1; -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::move(OctreeElementID p_id, const AABB &p_aabb) { -#ifdef DEBUG_ENABLED - // check for AABB validity - ERR_FAIL_COND(p_aabb.position.x > 1e15 || p_aabb.position.x < -1e15); - ERR_FAIL_COND(p_aabb.position.y > 1e15 || p_aabb.position.y < -1e15); - ERR_FAIL_COND(p_aabb.position.z > 1e15 || p_aabb.position.z < -1e15); - ERR_FAIL_COND(p_aabb.size.x > 1e15 || p_aabb.size.x < 0.0); - ERR_FAIL_COND(p_aabb.size.y > 1e15 || p_aabb.size.y < 0.0); - ERR_FAIL_COND(p_aabb.size.z > 1e15 || p_aabb.size.z < 0.0); - ERR_FAIL_COND(Math::is_nan(p_aabb.size.x)); - ERR_FAIL_COND(Math::is_nan(p_aabb.size.y)); - ERR_FAIL_COND(Math::is_nan(p_aabb.size.z)); -#endif - typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - Element &e = E->get(); - - bool old_has_surf = !e.aabb.has_no_surface(); - bool new_has_surf = !p_aabb.has_no_surface(); - - if (old_has_surf != new_has_surf) { - if (old_has_surf) { - _remove_element(&e); // removing - e.common_parent = nullptr; - e.aabb = AABB(); - _optimize(); - } else { - _ensure_valid_root(p_aabb); // inserting - e.common_parent = nullptr; - e.aabb = p_aabb; - _insert_element(&e, root); - if (use_pairs) { - _element_check_pairs(&e); - } - } - - return; - } - - if (!old_has_surf) { // doing nothing - return; - } - - // it still is enclosed in the same AABB it was assigned to - if (e.container_aabb.encloses(p_aabb)) { - e.aabb = p_aabb; - if (use_pairs) { - _element_check_pairs(&e); // must check pairs anyway - } - - return; - } - - AABB combined = e.aabb; - combined.merge_with(p_aabb); - _ensure_valid_root(combined); - - ERR_FAIL_COND(e.octant_owners.front() == nullptr); - - /* FIND COMMON PARENT */ - - List<typename Element::OctantOwner, AL> owners = e.octant_owners; // save the octant owners - Octant *common_parent = e.common_parent; - ERR_FAIL_COND(!common_parent); - - //src is now the place towards where insertion is going to happen - pass++; - - while (common_parent && !common_parent->aabb.encloses(p_aabb)) { - common_parent = common_parent->parent; - } - - ERR_FAIL_COND(!common_parent); - - //prepare for reinsert - e.octant_owners.clear(); - e.common_parent = nullptr; - e.aabb = p_aabb; - - _insert_element(&e, common_parent); // reinsert from this point - - pass++; - - for (typename List<typename Element::OctantOwner, AL>::Element *F = owners.front(); F;) { - Octant *o = F->get().octant; - typename List<typename Element::OctantOwner, AL>::Element *N = F->next(); - - if (use_pairs && e.pairable) { - o->pairable_elements.erase(F->get().E); - } else { - o->elements.erase(F->get().E); - } - - if (_remove_element_from_octant(&e, o, common_parent->parent)) { - owners.erase(F); - } - - F = N; - } - - if (use_pairs) { - //unpair child elements in anything that survived - for (typename List<typename Element::OctantOwner, AL>::Element *F = owners.front(); F; F = F->next()) { - Octant *o = F->get().octant; - - // erase children pairs, unref ONCE - pass++; - for (int i = 0; i < 8; i++) { - if (o->children[i]) { - _unpair_element(&e, o->children[i]); - } - } - } - - _element_check_pairs(&e); - } - - _optimize(); -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::set_pairable(OctreeElementID p_id, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask) { - typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - - Element &e = E->get(); - - if (p_pairable == e.pairable && e.pairable_type == p_pairable_type && e.pairable_mask == p_pairable_mask) { - return; // no changes, return - } - - if (!e.aabb.has_no_surface()) { - _remove_element(&e); - } - - e.pairable = p_pairable; - e.pairable_type = p_pairable_type; - e.pairable_mask = p_pairable_mask; - e.common_parent = nullptr; - - if (!e.aabb.has_no_surface()) { - _ensure_valid_root(e.aabb); - _insert_element(&e, root); - if (use_pairs) { - _element_check_pairs(&e); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::erase(OctreeElementID p_id) { - typename ElementMap::Element *E = element_map.find(p_id); - ERR_FAIL_COND(!E); - - Element &e = E->get(); - - if (!e.aabb.has_no_surface()) { - _remove_element(&e); - } - - element_map.erase(p_id); - _optimize(); -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_cull_convex(Octant *p_octant, _CullConvexData *p_cull) { - if (*p_cull->result_idx == p_cull->result_max) { - return; //pointless - } - - if (!p_octant->elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->elements.front(); - - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_cull->mask))) { - continue; - } - e->last_pass = pass; - - if (e->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count, p_cull->points, p_cull->point_count)) { - if (*p_cull->result_idx < p_cull->result_max) { - p_cull->result_array[*p_cull->result_idx] = e->userdata; - (*p_cull->result_idx)++; - } else { - return; // pointless to continue - } - } - } - } - - if (use_pairs && !p_octant->pairable_elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->pairable_elements.front(); - - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_cull->mask))) { - continue; - } - e->last_pass = pass; - - if (e->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count, p_cull->points, p_cull->point_count)) { - if (*p_cull->result_idx < p_cull->result_max) { - p_cull->result_array[*p_cull->result_idx] = e->userdata; - (*p_cull->result_idx)++; - } else { - return; // pointless to continue - } - } - } - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i] && p_octant->children[i]->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count, p_cull->points, p_cull->point_count)) { - _cull_convex(p_octant->children[i], p_cull); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_cull_aabb(Octant *p_octant, const AABB &p_aabb, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (*p_result_idx == p_result_max) { - return; //pointless - } - - if (!p_octant->elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - e->last_pass = pass; - - if (p_aabb.intersects_inclusive(e->aabb)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - - (*p_result_idx)++; - } else { - return; // pointless to continue - } - } - } - } - - if (use_pairs && !p_octant->pairable_elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->pairable_elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - e->last_pass = pass; - - if (p_aabb.intersects_inclusive(e->aabb)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - (*p_result_idx)++; - } else { - return; // pointless to continue - } - } - } - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i] && p_octant->children[i]->aabb.intersects_inclusive(p_aabb)) { - _cull_aabb(p_octant->children[i], p_aabb, p_result_array, p_result_idx, p_result_max, p_subindex_array, p_mask); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_cull_segment(Octant *p_octant, const Vector3 &p_from, const Vector3 &p_to, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (*p_result_idx == p_result_max) { - return; //pointless - } - - if (!p_octant->elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - e->last_pass = pass; - - if (e->aabb.intersects_segment(p_from, p_to)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - (*p_result_idx)++; - - } else { - return; // pointless to continue - } - } - } - } - - if (use_pairs && !p_octant->pairable_elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->pairable_elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - - e->last_pass = pass; - - if (e->aabb.intersects_segment(p_from, p_to)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - - (*p_result_idx)++; - - } else { - return; // pointless to continue - } - } - } - } - - for (int i = 0; i < 8; i++) { - if (p_octant->children[i] && p_octant->children[i]->aabb.intersects_segment(p_from, p_to)) { - _cull_segment(p_octant->children[i], p_from, p_to, p_result_array, p_result_idx, p_result_max, p_subindex_array, p_mask); - } - } -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::_cull_point(Octant *p_octant, const Vector3 &p_point, T **p_result_array, int *p_result_idx, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (*p_result_idx == p_result_max) { - return; //pointless - } - - if (!p_octant->elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - e->last_pass = pass; - - if (e->aabb.has_point(p_point)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - (*p_result_idx)++; - - } else { - return; // pointless to continue - } - } - } - } - - if (use_pairs && !p_octant->pairable_elements.is_empty()) { - typename List<Element *, AL>::Element *I; - I = p_octant->pairable_elements.front(); - for (; I; I = I->next()) { - Element *e = I->get(); - - if (e->last_pass == pass || (use_pairs && !(e->pairable_type & p_mask))) { - continue; - } - - e->last_pass = pass; - - if (e->aabb.has_point(p_point)) { - if (*p_result_idx < p_result_max) { - p_result_array[*p_result_idx] = e->userdata; - if (p_subindex_array) { - p_subindex_array[*p_result_idx] = e->subindex; - } - - (*p_result_idx)++; - - } else { - return; // pointless to continue - } - } - } - } - - for (int i = 0; i < 8; i++) { - //could be optimized.. - if (p_octant->children[i] && p_octant->children[i]->aabb.has_point(p_point)) { - _cull_point(p_octant->children[i], p_point, p_result_array, p_result_idx, p_result_max, p_subindex_array, p_mask); - } - } -} - -template <class T, bool use_pairs, class AL> -int Octree<T, use_pairs, AL>::cull_convex(const Vector<Plane> &p_convex, T **p_result_array, int p_result_max, uint32_t p_mask) { - if (!root || p_convex.size() == 0) { - return 0; - } - - Vector<Vector3> convex_points = Geometry3D::compute_convex_mesh_points(&p_convex[0], p_convex.size()); - if (convex_points.size() == 0) { - return 0; - } - - int result_count = 0; - pass++; - _CullConvexData cdata; - cdata.planes = &p_convex[0]; - cdata.plane_count = p_convex.size(); - cdata.points = &convex_points[0]; - cdata.point_count = convex_points.size(); - cdata.result_array = p_result_array; - cdata.result_max = p_result_max; - cdata.result_idx = &result_count; - cdata.mask = p_mask; - - _cull_convex(root, &cdata); - - return result_count; -} - -template <class T, bool use_pairs, class AL> -int Octree<T, use_pairs, AL>::cull_aabb(const AABB &p_aabb, T **p_result_array, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (!root) { - return 0; - } - - int result_count = 0; - pass++; - _cull_aabb(root, p_aabb, p_result_array, &result_count, p_result_max, p_subindex_array, p_mask); - - return result_count; -} - -template <class T, bool use_pairs, class AL> -int Octree<T, use_pairs, AL>::cull_segment(const Vector3 &p_from, const Vector3 &p_to, T **p_result_array, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (!root) { - return 0; - } - - int result_count = 0; - pass++; - _cull_segment(root, p_from, p_to, p_result_array, &result_count, p_result_max, p_subindex_array, p_mask); - - return result_count; -} - -template <class T, bool use_pairs, class AL> -int Octree<T, use_pairs, AL>::cull_point(const Vector3 &p_point, T **p_result_array, int p_result_max, int *p_subindex_array, uint32_t p_mask) { - if (!root) { - return 0; - } - - int result_count = 0; - pass++; - _cull_point(root, p_point, p_result_array, &result_count, p_result_max, p_subindex_array, p_mask); - - return result_count; -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::set_pair_callback(PairCallback p_callback, void *p_userdata) { - pair_callback = p_callback; - pair_callback_userdata = p_userdata; -} - -template <class T, bool use_pairs, class AL> -void Octree<T, use_pairs, AL>::set_unpair_callback(UnpairCallback p_callback, void *p_userdata) { - unpair_callback = p_callback; - unpair_callback_userdata = p_userdata; -} - -template <class T, bool use_pairs, class AL> -Octree<T, use_pairs, AL>::Octree(real_t p_unit_size) { - unit_size = p_unit_size; -} - -#endif // OCTREE_H diff --git a/core/math/plane.h b/core/math/plane.h index 66c1741662..73babfa496 100644 --- a/core/math/plane.h +++ b/core/math/plane.h @@ -52,7 +52,7 @@ struct _NO_DISCARD_ Plane { _FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane _FORCE_INLINE_ real_t distance_to(const Vector3 &p_point) const; - _FORCE_INLINE_ bool has_point(const Vector3 &p_point, real_t _epsilon = CMP_EPSILON) const; + _FORCE_INLINE_ bool has_point(const Vector3 &p_point, real_t p_tolerance = CMP_EPSILON) const; /* intersections */ @@ -97,10 +97,10 @@ real_t Plane::distance_to(const Vector3 &p_point) const { return (normal.dot(p_point) - d); } -bool Plane::has_point(const Vector3 &p_point, real_t _epsilon) const { +bool Plane::has_point(const Vector3 &p_point, real_t p_tolerance) const { real_t dist = normal.dot(p_point) - d; dist = ABS(dist); - return (dist <= _epsilon); + return (dist <= p_tolerance); } Plane::Plane(const Vector3 &p_normal, real_t p_d) : diff --git a/core/math/camera_matrix.cpp b/core/math/projection.cpp index f4392c74b7..edf8bf36cd 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/projection.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* camera_matrix.cpp */ +/* projection.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "camera_matrix.h" +#include "projection.h" #include "core/math/aabb.h" #include "core/math/math_funcs.h" @@ -37,7 +37,7 @@ #include "core/math/transform_3d.h" #include "core/string/print_string.h" -float CameraMatrix::determinant() const { +float Projection::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] - @@ -52,7 +52,7 @@ float CameraMatrix::determinant() const { 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() { +void Projection::set_identity() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[i][j] = (i == j) ? 1 : 0; @@ -60,7 +60,7 @@ void CameraMatrix::set_identity() { } } -void CameraMatrix::set_zero() { +void Projection::set_zero() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[i][j] = 0; @@ -68,7 +68,7 @@ void CameraMatrix::set_zero() { } } -Plane CameraMatrix::xform4(const Plane &p_vec4) const { +Plane Projection::xform4(const Plane &p_vec4) const { Plane ret; ret.normal.x = matrix[0][0] * p_vec4.normal.x + matrix[1][0] * p_vec4.normal.y + matrix[2][0] * p_vec4.normal.z + matrix[3][0] * p_vec4.d; @@ -78,7 +78,22 @@ Plane CameraMatrix::xform4(const Plane &p_vec4) const { return ret; } -void CameraMatrix::adjust_perspective_znear(real_t p_new_znear) { +Vector4 Projection::xform(const Vector4 &p_vec4) const { + return Vector4( + matrix[0][0] * p_vec4.x + matrix[1][0] * p_vec4.y + matrix[2][0] * p_vec4.z + matrix[3][0] * p_vec4.w, + matrix[0][1] * p_vec4.x + matrix[1][1] * p_vec4.y + matrix[2][1] * p_vec4.z + matrix[3][1] * p_vec4.w, + matrix[0][2] * p_vec4.x + matrix[1][2] * p_vec4.y + matrix[2][2] * p_vec4.z + matrix[3][2] * p_vec4.w, + matrix[0][3] * p_vec4.x + matrix[1][3] * p_vec4.y + matrix[2][3] * p_vec4.z + matrix[3][3] * p_vec4.w); +} +Vector4 Projection::xform_inv(const Vector4 &p_vec4) const { + return Vector4( + matrix[0][0] * p_vec4.x + matrix[0][1] * p_vec4.y + matrix[0][2] * p_vec4.z + matrix[0][3] * p_vec4.w, + matrix[1][0] * p_vec4.x + matrix[1][1] * p_vec4.y + matrix[1][2] * p_vec4.z + matrix[1][3] * p_vec4.w, + matrix[2][0] * p_vec4.x + matrix[2][1] * p_vec4.y + matrix[2][2] * p_vec4.z + matrix[2][3] * p_vec4.w, + matrix[3][0] * p_vec4.x + matrix[3][1] * p_vec4.y + matrix[3][2] * p_vec4.z + matrix[3][3] * p_vec4.w); +} + +void Projection::adjust_perspective_znear(real_t p_new_znear) { real_t zfar = get_z_far(); real_t znear = p_new_znear; @@ -87,7 +102,154 @@ void CameraMatrix::adjust_perspective_znear(real_t p_new_znear) { matrix[3][2] = -2 * znear * zfar / deltaZ; } -void CameraMatrix::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov) { +Projection Projection::create_depth_correction(bool p_flip_y) { + Projection proj; + proj.set_depth_correction(p_flip_y); + return proj; +} + +Projection Projection::create_light_atlas_rect(const Rect2 &p_rect) { + Projection proj; + proj.set_light_atlas_rect(p_rect); + return proj; +} + +Projection Projection::create_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov) { + Projection proj; + proj.set_perspective(p_fovy_degrees, p_aspect, p_z_near, p_z_far, p_flip_fov); + return proj; +} + +Projection Projection::create_perspective_hmd(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) { + Projection proj; + proj.set_perspective(p_fovy_degrees, p_aspect, p_z_near, p_z_far, p_flip_fov, p_eye, p_intraocular_dist, p_convergence_dist); + return proj; +} + +Projection Projection::create_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far) { + Projection proj; + proj.set_for_hmd(p_eye, p_aspect, p_intraocular_dist, p_display_width, p_display_to_lens, p_oversample, p_z_near, p_z_far); + return proj; +} + +Projection Projection::create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) { + Projection proj; + proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_zfar, p_zfar); + return proj; +} + +Projection Projection::create_orthogonal_aspect(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) { + Projection proj; + proj.set_orthogonal(p_size, p_aspect, p_znear, p_zfar, p_flip_fov); + return proj; +} + +Projection Projection::create_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) { + Projection proj; + proj.set_frustum(p_left, p_right, p_bottom, p_top, p_near, p_far); + return proj; +} + +Projection Projection::create_frustum_aspect(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) { + Projection proj; + proj.set_frustum(p_size, p_aspect, p_offset, p_near, p_far, p_flip_fov); + return proj; +} + +Projection Projection::create_fit_aabb(const AABB &p_aabb) { + Projection proj; + proj.scale_translate_to_fit(p_aabb); + return proj; +} + +Projection Projection::perspective_znear_adjusted(real_t p_new_znear) const { + Projection proj = *this; + proj.adjust_perspective_znear(p_new_znear); + return proj; +} + +Plane Projection::get_projection_plane(Planes p_plane) const { + const real_t *matrix = (const real_t *)this->matrix; + + switch (p_plane) { + case PLANE_NEAR: { + Plane new_plane = Plane(matrix[3] + matrix[2], + matrix[7] + matrix[6], + matrix[11] + matrix[10], + matrix[15] + matrix[14]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + case PLANE_FAR: { + Plane new_plane = Plane(matrix[3] - matrix[2], + matrix[7] - matrix[6], + matrix[11] - matrix[10], + matrix[15] - matrix[14]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + case PLANE_LEFT: { + Plane new_plane = Plane(matrix[3] + matrix[0], + matrix[7] + matrix[4], + matrix[11] + matrix[8], + matrix[15] + matrix[12]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + case PLANE_TOP: { + Plane new_plane = Plane(matrix[3] - matrix[1], + matrix[7] - matrix[5], + matrix[11] - matrix[9], + matrix[15] - matrix[13]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + case PLANE_RIGHT: { + Plane new_plane = Plane(matrix[3] - matrix[0], + matrix[7] - matrix[4], + matrix[11] - matrix[8], + matrix[15] - matrix[12]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + case PLANE_BOTTOM: { + Plane new_plane = Plane(matrix[3] + matrix[1], + matrix[7] + matrix[5], + matrix[11] + matrix[9], + matrix[15] + matrix[13]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + } + + return Plane(); +} + +Projection Projection::flipped_y() const { + Projection proj = *this; + proj.flip_y(); + return proj; +} + +Projection Projection ::jitter_offseted(const Vector2 &p_offset) const { + Projection proj = *this; + proj.add_jitter_offset(p_offset); + return proj; +} + +void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov) { if (p_flip_fov) { p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect); } @@ -113,7 +275,7 @@ void CameraMatrix::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_ matrix[3][3] = 0; } -void CameraMatrix::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) { +void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) { if (p_flip_fov) { p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect); } @@ -145,13 +307,13 @@ void CameraMatrix::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_ set_frustum(left, right, -ymax, ymax, p_z_near, p_z_far); // translate matrix by (modeltranslation, 0.0, 0.0) - CameraMatrix cm; + Projection cm; cm.set_identity(); cm.matrix[3][0] = modeltranslation; *this = *this * cm; } -void CameraMatrix::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far) { +void Projection::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far) { // we first calculate our base frustum on our values without taking our lens magnification into account. real_t f1 = (p_intraocular_dist * 0.5) / p_display_to_lens; real_t f2 = ((p_display_width - p_intraocular_dist) * 0.5) / p_display_to_lens; @@ -179,7 +341,7 @@ void CameraMatrix::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_ } } -void CameraMatrix::set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) { +void Projection::set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) { set_identity(); matrix[0][0] = 2.0 / (p_right - p_left); @@ -191,7 +353,7 @@ void CameraMatrix::set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom matrix[3][3] = 1.0; } -void CameraMatrix::set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) { +void Projection::set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) { if (!p_flip_fov) { p_size *= p_aspect; } @@ -199,7 +361,7 @@ void CameraMatrix::set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear set_orthogonal(-p_size / 2, +p_size / 2, -p_size / p_aspect / 2, +p_size / p_aspect / 2, p_znear, p_zfar); } -void CameraMatrix::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) { +void Projection::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) { ERR_FAIL_COND(p_right <= p_left); ERR_FAIL_COND(p_top <= p_bottom); ERR_FAIL_COND(p_far <= p_near); @@ -231,7 +393,7 @@ void CameraMatrix::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, r te[15] = 0; } -void CameraMatrix::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) { +void Projection::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) { if (!p_flip_fov) { p_size *= p_aspect; } @@ -239,7 +401,7 @@ void CameraMatrix::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, set_frustum(-p_size / 2 + p_offset.x, +p_size / 2 + p_offset.x, -p_size / p_aspect / 2 + p_offset.y, +p_size / p_aspect / 2 + p_offset.y, p_near, p_far); } -real_t CameraMatrix::get_z_far() const { +real_t Projection::get_z_far() const { const real_t *matrix = (const real_t *)this->matrix; Plane new_plane = Plane(matrix[3] - matrix[2], matrix[7] - matrix[6], @@ -252,7 +414,7 @@ real_t CameraMatrix::get_z_far() const { return new_plane.d; } -real_t CameraMatrix::get_z_near() const { +real_t Projection::get_z_near() const { const real_t *matrix = (const real_t *)this->matrix; Plane new_plane = Plane(matrix[3] + matrix[2], matrix[7] + matrix[6], @@ -263,7 +425,7 @@ real_t CameraMatrix::get_z_near() const { return new_plane.d; } -Vector2 CameraMatrix::get_viewport_half_extents() const { +Vector2 Projection::get_viewport_half_extents() const { const real_t *matrix = (const real_t *)this->matrix; ///////--- Near Plane ---/////// Plane near_plane = Plane(matrix[3] + matrix[2], @@ -291,7 +453,7 @@ Vector2 CameraMatrix::get_viewport_half_extents() const { return Vector2(res.x, res.y); } -Vector2 CameraMatrix::get_far_plane_half_extents() const { +Vector2 Projection::get_far_plane_half_extents() const { const real_t *matrix = (const real_t *)this->matrix; ///////--- Far Plane ---/////// Plane far_plane = Plane(matrix[3] - matrix[2], @@ -319,7 +481,7 @@ Vector2 CameraMatrix::get_far_plane_half_extents() const { return Vector2(res.x, res.y); } -bool CameraMatrix::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const { +bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const { Vector<Plane> planes = get_projection_planes(Transform3D()); const Planes intersections[8][3] = { { PLANE_FAR, PLANE_LEFT, PLANE_TOP }, @@ -342,7 +504,7 @@ bool CameraMatrix::get_endpoints(const Transform3D &p_transform, Vector3 *p_8poi return true; } -Vector<Plane> CameraMatrix::get_projection_planes(const Transform3D &p_transform) const { +Vector<Plane> Projection::get_projection_planes(const Transform3D &p_transform) const { /** Fast Plane Extraction from combined modelview/projection matrices. * References: * https://web.archive.org/web/20011221205252/https://www.markmorley.com/opengl/frustumculling.html @@ -425,13 +587,13 @@ Vector<Plane> CameraMatrix::get_projection_planes(const Transform3D &p_transform return planes; } -CameraMatrix CameraMatrix::inverse() const { - CameraMatrix cm = *this; +Projection Projection::inverse() const { + Projection cm = *this; cm.invert(); return cm; } -void CameraMatrix::invert() { +void Projection::invert() { int i, j, k; int pvt_i[4], pvt_j[4]; /* Locations of pivot matrix */ real_t pvt_val; /* Value of current pivot element */ @@ -529,18 +691,18 @@ void CameraMatrix::invert() { } } -void CameraMatrix::flip_y() { +void Projection::flip_y() { for (int i = 0; i < 4; i++) { matrix[1][i] = -matrix[1][i]; } } -CameraMatrix::CameraMatrix() { +Projection::Projection() { set_identity(); } -CameraMatrix CameraMatrix::operator*(const CameraMatrix &p_matrix) const { - CameraMatrix new_matrix; +Projection Projection::operator*(const Projection &p_matrix) const { + Projection new_matrix; for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { @@ -555,7 +717,7 @@ CameraMatrix CameraMatrix::operator*(const CameraMatrix &p_matrix) const { return new_matrix; } -void CameraMatrix::set_depth_correction(bool p_flip_y) { +void Projection::set_depth_correction(bool p_flip_y) { real_t *m = &matrix[0][0]; m[0] = 1; @@ -576,7 +738,7 @@ void CameraMatrix::set_depth_correction(bool p_flip_y) { m[15] = 1.0; } -void CameraMatrix::set_light_bias() { +void Projection::set_light_bias() { real_t *m = &matrix[0][0]; m[0] = 0.5; @@ -597,7 +759,7 @@ void CameraMatrix::set_light_bias() { m[15] = 1.0; } -void CameraMatrix::set_light_atlas_rect(const Rect2 &p_rect) { +void Projection::set_light_atlas_rect(const Rect2 &p_rect) { real_t *m = &matrix[0][0]; m[0] = p_rect.size.width; @@ -618,7 +780,7 @@ void CameraMatrix::set_light_atlas_rect(const Rect2 &p_rect) { m[15] = 1.0; } -CameraMatrix::operator String() const { +Projection::operator String() const { String str; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -629,22 +791,22 @@ CameraMatrix::operator String() const { return str; } -real_t CameraMatrix::get_aspect() const { +real_t Projection::get_aspect() const { Vector2 vp_he = get_viewport_half_extents(); return vp_he.x / vp_he.y; } -int CameraMatrix::get_pixels_per_meter(int p_for_pixel_width) const { +int Projection::get_pixels_per_meter(int p_for_pixel_width) const { Vector3 result = xform(Vector3(1, 0, -1)); return int((result.x * 0.5 + 0.5) * p_for_pixel_width); } -bool CameraMatrix::is_orthogonal() const { +bool Projection::is_orthogonal() const { return matrix[3][3] == 1.0; } -real_t CameraMatrix::get_fov() const { +real_t Projection::get_fov() const { const real_t *matrix = (const real_t *)this->matrix; Plane right_plane = Plane(matrix[3] - matrix[0], @@ -667,7 +829,7 @@ real_t CameraMatrix::get_fov() const { } } -float CameraMatrix::get_lod_multiplier() const { +float Projection::get_lod_multiplier() const { if (is_orthogonal()) { return get_viewport_half_extents().x; } else { @@ -678,14 +840,14 @@ float CameraMatrix::get_lod_multiplier() const { //usage is lod_size / (lod_distance * multiplier) < threshold } -void CameraMatrix::make_scale(const Vector3 &p_scale) { +void Projection::make_scale(const Vector3 &p_scale) { set_identity(); matrix[0][0] = p_scale.x; matrix[1][1] = p_scale.y; matrix[2][2] = p_scale.z; } -void CameraMatrix::scale_translate_to_fit(const AABB &p_aabb) { +void Projection::scale_translate_to_fit(const AABB &p_aabb) { Vector3 min = p_aabb.position; Vector3 max = p_aabb.position + p_aabb.size; @@ -710,21 +872,26 @@ void CameraMatrix::scale_translate_to_fit(const AABB &p_aabb) { matrix[3][3] = 1; } -CameraMatrix::operator Transform3D() const { +void Projection::add_jitter_offset(const Vector2 &p_offset) { + matrix[3][0] += p_offset.x; + matrix[3][1] += p_offset.y; +} + +Projection::operator Transform3D() const { Transform3D tr; const real_t *m = &matrix[0][0]; - tr.basis.elements[0][0] = m[0]; - tr.basis.elements[1][0] = m[1]; - tr.basis.elements[2][0] = m[2]; + tr.basis.rows[0][0] = m[0]; + tr.basis.rows[1][0] = m[1]; + tr.basis.rows[2][0] = m[2]; - tr.basis.elements[0][1] = m[4]; - tr.basis.elements[1][1] = m[5]; - tr.basis.elements[2][1] = m[6]; + tr.basis.rows[0][1] = m[4]; + tr.basis.rows[1][1] = m[5]; + tr.basis.rows[2][1] = m[6]; - tr.basis.elements[0][2] = m[8]; - tr.basis.elements[1][2] = m[9]; - tr.basis.elements[2][2] = m[10]; + tr.basis.rows[0][2] = m[8]; + tr.basis.rows[1][2] = m[9]; + tr.basis.rows[2][2] = m[10]; tr.origin.x = m[12]; tr.origin.y = m[13]; @@ -732,22 +899,27 @@ CameraMatrix::operator Transform3D() const { return tr; } - -CameraMatrix::CameraMatrix(const Transform3D &p_transform) { +Projection::Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w) { + matrix[0] = p_x; + matrix[1] = p_y; + matrix[2] = p_z; + matrix[3] = p_w; +} +Projection::Projection(const Transform3D &p_transform) { const Transform3D &tr = p_transform; real_t *m = &matrix[0][0]; - m[0] = tr.basis.elements[0][0]; - m[1] = tr.basis.elements[1][0]; - m[2] = tr.basis.elements[2][0]; + m[0] = tr.basis.rows[0][0]; + m[1] = tr.basis.rows[1][0]; + m[2] = tr.basis.rows[2][0]; m[3] = 0.0; - m[4] = tr.basis.elements[0][1]; - m[5] = tr.basis.elements[1][1]; - m[6] = tr.basis.elements[2][1]; + m[4] = tr.basis.rows[0][1]; + m[5] = tr.basis.rows[1][1]; + m[6] = tr.basis.rows[2][1]; m[7] = 0.0; - m[8] = tr.basis.elements[0][2]; - m[9] = tr.basis.elements[1][2]; - m[10] = tr.basis.elements[2][2]; + m[8] = tr.basis.rows[0][2]; + m[9] = tr.basis.rows[1][2]; + m[10] = tr.basis.rows[2][2]; m[11] = 0.0; m[12] = tr.origin.x; m[13] = tr.origin.y; @@ -755,5 +927,5 @@ CameraMatrix::CameraMatrix(const Transform3D &p_transform) { m[15] = 1.0; } -CameraMatrix::~CameraMatrix() { +Projection::~Projection() { } diff --git a/core/math/camera_matrix.h b/core/math/projection.h index f1aea5e4e8..a3d2d7720b 100644 --- a/core/math/camera_matrix.h +++ b/core/math/projection.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* camera_matrix.h */ +/* projection.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CAMERA_MATRIX_H -#define CAMERA_MATRIX_H +#ifndef PROJECTION_H +#define PROJECTION_H #include "core/math/math_defs.h" #include "core/math/vector3.h" +#include "core/math/vector4.h" #include "core/templates/vector.h" struct AABB; @@ -41,7 +42,7 @@ struct Rect2; struct Transform3D; struct Vector2; -struct CameraMatrix { +struct Projection { enum Planes { PLANE_NEAR, PLANE_FAR, @@ -51,13 +52,24 @@ struct CameraMatrix { PLANE_BOTTOM }; - real_t matrix[4][4]; + Vector4 matrix[4]; + + _FORCE_INLINE_ const Vector4 &operator[](const int p_axis) const { + DEV_ASSERT((unsigned int)p_axis < 4); + return matrix[p_axis]; + } + + _FORCE_INLINE_ Vector4 &operator[](const int p_axis) { + DEV_ASSERT((unsigned int)p_axis < 4); + return matrix[p_axis]; + } float determinant() const; void set_identity(); void set_zero(); void set_light_bias(); void set_depth_correction(bool p_flip_y = true); + void set_light_atlas_rect(const Rect2 &p_rect); void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false); void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist); @@ -68,6 +80,21 @@ struct CameraMatrix { void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false); void adjust_perspective_znear(real_t p_new_znear); + static Projection create_depth_correction(bool p_flip_y); + static Projection create_light_atlas_rect(const Rect2 &p_rect); + static Projection create_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false); + static Projection create_perspective_hmd(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist); + static Projection create_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far); + static Projection create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar); + static Projection create_orthogonal_aspect(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false); + static Projection create_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far); + static Projection create_frustum_aspect(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false); + static Projection create_fit_aabb(const AABB &p_aabb); + Projection perspective_znear_adjusted(real_t p_new_znear) const; + Plane get_projection_plane(Planes p_plane) const; + Projection flipped_y() const; + Projection jitter_offseted(const Vector2 &p_offset) const; + static real_t get_fovy(real_t p_fovx, real_t p_aspect) { return Math::rad2deg(Math::atan(p_aspect * Math::tan(Math::deg2rad(p_fovx) * 0.5)) * 2.0); } @@ -85,23 +112,27 @@ struct CameraMatrix { Vector2 get_far_plane_half_extents() const; void invert(); - CameraMatrix inverse() const; + Projection inverse() const; - CameraMatrix operator*(const CameraMatrix &p_matrix) const; + Projection operator*(const Projection &p_matrix) const; Plane xform4(const Plane &p_vec4) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vec3) const; + Vector4 xform(const Vector4 &p_vec4) const; + Vector4 xform_inv(const Vector4 &p_vec4) const; + operator String() const; void scale_translate_to_fit(const AABB &p_aabb); + void add_jitter_offset(const Vector2 &p_offset); void make_scale(const Vector3 &p_scale); int get_pixels_per_meter(int p_for_pixel_width) const; operator Transform3D() const; void flip_y(); - bool operator==(const CameraMatrix &p_cam) const { + bool operator==(const Projection &p_cam) const { for (uint32_t i = 0; i < 4; i++) { for (uint32_t j = 0; j < 4; j++) { if (matrix[i][j] != p_cam.matrix[i][j]) { @@ -112,18 +143,19 @@ struct CameraMatrix { return true; } - bool operator!=(const CameraMatrix &p_cam) const { + bool operator!=(const Projection &p_cam) const { return !(*this == p_cam); } float get_lod_multiplier() const; - CameraMatrix(); - CameraMatrix(const Transform3D &p_transform); - ~CameraMatrix(); + Projection(); + Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w); + Projection(const Transform3D &p_transform); + ~Projection(); }; -Vector3 CameraMatrix::xform(const Vector3 &p_vec3) const { +Vector3 Projection::xform(const Vector3 &p_vec3) const { Vector3 ret; ret.x = matrix[0][0] * p_vec3.x + matrix[1][0] * p_vec3.y + matrix[2][0] * p_vec3.z + matrix[3][0]; ret.y = matrix[0][1] * p_vec3.x + matrix[1][1] * p_vec3.y + matrix[2][1] * p_vec3.z + matrix[3][1]; @@ -132,4 +164,4 @@ Vector3 CameraMatrix::xform(const Vector3 &p_vec3) const { return ret / w; } -#endif // CAMERA_MATRIX_H +#endif // PROJECTION_H diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp index 11bfcc1a6f..c681c60694 100644 --- a/core/math/quaternion.cpp +++ b/core/math/quaternion.cpp @@ -111,7 +111,7 @@ Quaternion Quaternion::log() const { Quaternion Quaternion::exp() const { Quaternion src = *this; Vector3 src_v = Vector3(src.x, src.y, src.z); - float theta = src_v.length(); + real_t theta = src_v.length(); if (theta < CMP_EPSILON) { return Quaternion(0, 0, 0, 1); } @@ -132,15 +132,9 @@ Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) con // adjust signs (if necessary) if (cosom < 0.0f) { cosom = -cosom; - to1.x = -p_to.x; - to1.y = -p_to.y; - to1.z = -p_to.z; - to1.w = -p_to.w; + to1 = -p_to; } else { - to1.x = p_to.x; - to1.y = p_to.y; - to1.z = p_to.z; - to1.w = p_to.w; + to1 = p_to; } // calculate coefficients @@ -189,16 +183,54 @@ Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) c invFactor * from.w + newFactor * p_to.w); } -Quaternion Quaternion::cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const { +Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized."); #endif - //the only way to do slerp :| - real_t t2 = (1.0f - p_weight) * p_weight * 2; - Quaternion sp = this->slerp(p_b, p_weight); - Quaternion sq = p_pre_a.slerpni(p_post_b, p_weight); - return sp.slerpni(sq, t2); + Quaternion from_q = *this; + Quaternion pre_q = p_pre_a; + Quaternion to_q = p_b; + Quaternion post_q = p_post_b; + + // Align flip phases. + from_q = Basis(from_q).get_rotation_quaternion(); + pre_q = Basis(pre_q).get_rotation_quaternion(); + to_q = Basis(to_q).get_rotation_quaternion(); + post_q = Basis(post_q).get_rotation_quaternion(); + + // Flip quaternions to shortest path if necessary. + bool flip1 = signbit(from_q.dot(pre_q)); + pre_q = flip1 ? -pre_q : pre_q; + bool flip2 = signbit(from_q.dot(to_q)); + to_q = flip2 ? -to_q : to_q; + bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : signbit(to_q.dot(post_q)); + post_q = flip3 ? -post_q : post_q; + + // Calc by Expmap in from_q space. + Quaternion ln_from = Quaternion(0, 0, 0, 0); + Quaternion ln_to = (from_q.inverse() * to_q).log(); + Quaternion ln_pre = (from_q.inverse() * pre_q).log(); + Quaternion ln_post = (from_q.inverse() * post_q).log(); + Quaternion ln = Quaternion(0, 0, 0, 0); + ln.x = Math::cubic_interpolate(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight); + ln.y = Math::cubic_interpolate(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight); + ln.z = Math::cubic_interpolate(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight); + Quaternion q1 = from_q * ln.exp(); + + // Calc by Expmap in to_q space. + ln_from = (to_q.inverse() * from_q).log(); + ln_to = Quaternion(0, 0, 0, 0); + ln_pre = (to_q.inverse() * pre_q).log(); + ln_post = (to_q.inverse() * post_q).log(); + ln = Quaternion(0, 0, 0, 0); + ln.x = Math::cubic_interpolate(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight); + ln.y = Math::cubic_interpolate(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight); + ln.z = Math::cubic_interpolate(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight); + Quaternion q2 = to_q * ln.exp(); + + // To cancel error made by Expmap ambiguity, do blends. + return q1.slerp(q2, p_weight); } Quaternion::operator String() const { @@ -213,7 +245,7 @@ Vector3 Quaternion::get_axis() const { return Vector3(x * r, y * r, z * r); } -float Quaternion::get_angle() const { +real_t Quaternion::get_angle() const { return 2 * Math::acos(w); } diff --git a/core/math/quaternion.h b/core/math/quaternion.h index 9801746659..cb54a6f540 100644 --- a/core/math/quaternion.h +++ b/core/math/quaternion.h @@ -71,10 +71,10 @@ struct _NO_DISCARD_ Quaternion { Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const; 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; + Quaternion spherical_cubic_interpolate(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; + real_t get_angle() const; _FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { r_angle = 2 * Math::acos(w); diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index 8e87d44b7f..c7727a44a1 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -30,7 +30,7 @@ #include "quick_hull.h" -#include "core/templates/map.h" +#include "core/templates/rb_map.h" uint32_t QuickHull::debug_stop_after = 0xFFFFFFFF; @@ -52,7 +52,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ Vector<bool> valid_points; valid_points.resize(p_points.size()); - Set<Vector3> valid_cache; + HashSet<Vector3> valid_cache; for (int i = 0; i < p_points.size(); i++) { Vector3 sp = p_points[i].snapped(Vector3(0.0001, 0.0001, 0.0001)); @@ -237,7 +237,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ //find lit faces and lit edges List<List<Face>::Element *> lit_faces; //lit face is a death sentence - Map<Edge, FaceConnect> lit_edges; //create this on the flight, should not be that bad for performance and simplifies code a lot + HashMap<Edge, FaceConnect, Edge> lit_edges; //create this on the flight, should not be that bad for performance and simplifies code a lot for (List<Face>::Element *E = faces.front(); E; E = E->next()) { if (E->get().plane.distance_to(v) > 0) { @@ -248,15 +248,15 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ uint32_t b = E->get().vertices[(i + 1) % 3]; Edge e(a, b); - Map<Edge, FaceConnect>::Element *F = lit_edges.find(e); + HashMap<Edge, FaceConnect, Edge>::Iterator F = lit_edges.find(e); if (!F) { F = lit_edges.insert(e, FaceConnect()); } if (e.vertices[0] == a) { //left - F->get().left = E; + F->value.left = E; } else { - F->get().right = E; + F->value.right = E; } } } @@ -333,7 +333,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ /* CREATE MESHDATA */ //make a map of edges again - Map<Edge, RetFaceConnect> ret_edges; + HashMap<Edge, RetFaceConnect, Edge> ret_edges; List<Geometry3D::MeshData::Face> ret_faces; for (const Face &E : faces) { @@ -351,15 +351,15 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ uint32_t b = E.vertices[(i + 1) % 3]; Edge e(a, b); - Map<Edge, RetFaceConnect>::Element *G = ret_edges.find(e); + HashMap<Edge, RetFaceConnect, Edge>::Iterator G = ret_edges.find(e); if (!G) { G = ret_edges.insert(e, RetFaceConnect()); } if (e.vertices[0] == a) { //left - G->get().left = F; + G->value.left = F; } else { - G->get().right = F; + G->value.right = F; } } } @@ -374,17 +374,16 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ int b = E->get().indices[(i + 1) % f.indices.size()]; Edge e(a, b); - Map<Edge, RetFaceConnect>::Element *F = ret_edges.find(e); + HashMap<Edge, RetFaceConnect, Edge>::Iterator F = ret_edges.find(e); ERR_CONTINUE(!F); - List<Geometry3D::MeshData::Face>::Element *O = F->get().left == E ? F->get().right : F->get().left; + List<Geometry3D::MeshData::Face>::Element *O = F->value.left == E ? F->value.right : F->value.left; ERR_CONTINUE(O == E); ERR_CONTINUE(O == nullptr); if (O->get().plane.is_equal_approx(f.plane)) { //merge and delete edge and contiguous face, while repointing edges (uuugh!) int ois = O->get().indices.size(); - int merged = 0; for (int j = 0; j < ois; j++) { //search a @@ -399,17 +398,16 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ if (idx != a) { f.indices.insert(i + 1, idx); i++; - merged++; } Edge e2(idx, idxn); - Map<Edge, RetFaceConnect>::Element *F2 = ret_edges.find(e2); + HashMap<Edge, RetFaceConnect, Edge>::Iterator F2 = ret_edges.find(e2); ERR_CONTINUE(!F2); //change faceconnect, point to this face instead - if (F2->get().left == O) { - F2->get().left = E; - } else if (F2->get().right == O) { - F2->get().right = E; + if (F2->value.left == O) { + F2->value.left = E; + } else if (F2->value.right == O) { + F2->value.right = E; } } @@ -428,7 +426,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ } } - ret_edges.erase(F); //remove the edge + ret_edges.remove(F); //remove the edge ret_faces.erase(O); //remove the face } } diff --git a/core/math/quick_hull.h b/core/math/quick_hull.h index b8d813c979..6783743fc2 100644 --- a/core/math/quick_hull.h +++ b/core/math/quick_hull.h @@ -33,8 +33,8 @@ #include "core/math/aabb.h" #include "core/math/geometry_3d.h" +#include "core/templates/hash_set.h" #include "core/templates/list.h" -#include "core/templates/set.h" class QuickHull { public: @@ -44,9 +44,16 @@ public: uint64_t id = 0; }; + static uint32_t hash(const Edge &p_edge) { + return hash_one_uint64(p_edge.id); + } + bool operator<(const Edge &p_edge) const { return id < p_edge.id; } + bool operator==(const Edge &p_edge) const { + return id == p_edge.id; + } Edge(int p_vtx_a = 0, int p_vtx_b = 0) { if (p_vtx_a > p_vtx_b) { diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h index 65fcf67664..a088b30d17 100644 --- a/core/math/random_pcg.h +++ b/core/math/random_pcg.h @@ -61,8 +61,8 @@ static int __bsr_clz32(uint32_t x) { class RandomPCG { pcg32_random_t pcg; - uint64_t current_seed; // The seed the current generator state started from. - uint64_t current_inc; + uint64_t current_seed = 0; // The seed the current generator state started from. + uint64_t current_inc = 0; public: static const uint64_t DEFAULT_SEED = 12047754176567800795U; diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp index d6e20bdc3c..9e78ead816 100644 --- a/core/math/rect2.cpp +++ b/core/math/rect2.cpp @@ -201,33 +201,33 @@ next4: Vector2(position.x + size.x, position.y + size.y), }; - real_t maxa = p_xform.elements[0].dot(xf_points2[0]); + real_t maxa = p_xform.columns[0].dot(xf_points2[0]); real_t mina = maxa; - real_t dp = p_xform.elements[0].dot(xf_points2[1]); + real_t dp = p_xform.columns[0].dot(xf_points2[1]); maxa = MAX(dp, maxa); mina = MIN(dp, mina); - dp = p_xform.elements[0].dot(xf_points2[2]); + dp = p_xform.columns[0].dot(xf_points2[2]); maxa = MAX(dp, maxa); mina = MIN(dp, mina); - dp = p_xform.elements[0].dot(xf_points2[3]); + dp = p_xform.columns[0].dot(xf_points2[3]); maxa = MAX(dp, maxa); mina = MIN(dp, mina); - real_t maxb = p_xform.elements[0].dot(xf_points[0]); + real_t maxb = p_xform.columns[0].dot(xf_points[0]); real_t minb = maxb; - dp = p_xform.elements[0].dot(xf_points[1]); + dp = p_xform.columns[0].dot(xf_points[1]); maxb = MAX(dp, maxb); minb = MIN(dp, minb); - dp = p_xform.elements[0].dot(xf_points[2]); + dp = p_xform.columns[0].dot(xf_points[2]); maxb = MAX(dp, maxb); minb = MIN(dp, minb); - dp = p_xform.elements[0].dot(xf_points[3]); + dp = p_xform.columns[0].dot(xf_points[3]); maxb = MAX(dp, maxb); minb = MIN(dp, minb); @@ -238,33 +238,33 @@ next4: return false; } - maxa = p_xform.elements[1].dot(xf_points2[0]); + maxa = p_xform.columns[1].dot(xf_points2[0]); mina = maxa; - dp = p_xform.elements[1].dot(xf_points2[1]); + dp = p_xform.columns[1].dot(xf_points2[1]); maxa = MAX(dp, maxa); mina = MIN(dp, mina); - dp = p_xform.elements[1].dot(xf_points2[2]); + dp = p_xform.columns[1].dot(xf_points2[2]); maxa = MAX(dp, maxa); mina = MIN(dp, mina); - dp = p_xform.elements[1].dot(xf_points2[3]); + dp = p_xform.columns[1].dot(xf_points2[3]); maxa = MAX(dp, maxa); mina = MIN(dp, mina); - maxb = p_xform.elements[1].dot(xf_points[0]); + maxb = p_xform.columns[1].dot(xf_points[0]); minb = maxb; - dp = p_xform.elements[1].dot(xf_points[1]); + dp = p_xform.columns[1].dot(xf_points[1]); maxb = MAX(dp, maxb); minb = MIN(dp, minb); - dp = p_xform.elements[1].dot(xf_points[2]); + dp = p_xform.columns[1].dot(xf_points[2]); maxb = MAX(dp, maxb); minb = MIN(dp, minb); - dp = p_xform.elements[1].dot(xf_points[3]); + dp = p_xform.columns[1].dot(xf_points[3]); maxb = MAX(dp, maxb); minb = MIN(dp, minb); diff --git a/core/math/static_raycaster.h b/core/math/static_raycaster.h index 33254399c7..bc6511c073 100644 --- a/core/math/static_raycaster.h +++ b/core/math/static_raycaster.h @@ -102,7 +102,7 @@ public: 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 set_mesh_filter(const HashSet<int> &p_mesh_ids) = 0; virtual void clear_mesh_filter() = 0; static Ref<StaticRaycaster> create(); diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 71953e4130..226076029b 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -35,8 +35,8 @@ void Transform2D::invert() { // FIXME: this function assumes the basis is a rotation matrix, with no scaling. // Transform2D::affine_inverse can handle matrices with scaling, so GDScript should eventually use that. - SWAP(elements[0][1], elements[1][0]); - elements[2] = basis_xform(-elements[2]); + SWAP(columns[0][1], columns[1][0]); + columns[2] = basis_xform(-columns[2]); } Transform2D Transform2D::inverse() const { @@ -52,11 +52,11 @@ void Transform2D::affine_invert() { #endif real_t idet = 1.0f / det; - SWAP(elements[0][0], elements[1][1]); - elements[0] *= Vector2(idet, -idet); - elements[1] *= Vector2(-idet, idet); + SWAP(columns[0][0], columns[1][1]); + columns[0] *= Vector2(idet, -idet); + columns[1] *= Vector2(-idet, idet); - elements[2] = basis_xform(-elements[2]); + columns[2] = basis_xform(-columns[2]); } Transform2D Transform2D::affine_inverse() const { @@ -65,97 +65,97 @@ Transform2D Transform2D::affine_inverse() const { return inv; } -void Transform2D::rotate(const real_t p_phi) { - *this = Transform2D(p_phi, Vector2()) * (*this); +void Transform2D::rotate(const real_t p_angle) { + *this = Transform2D(p_angle, Vector2()) * (*this); } real_t Transform2D::get_skew() const { real_t det = basis_determinant(); - return Math::acos(elements[0].normalized().dot(SIGN(det) * elements[1].normalized())) - (real_t)Math_PI * 0.5f; + return Math::acos(columns[0].normalized().dot(SIGN(det) * columns[1].normalized())) - (real_t)Math_PI * 0.5f; } void Transform2D::set_skew(const real_t p_angle) { real_t det = basis_determinant(); - elements[1] = SIGN(det) * elements[0].rotated(((real_t)Math_PI * 0.5f + p_angle)).normalized() * elements[1].length(); + columns[1] = SIGN(det) * columns[0].rotated(((real_t)Math_PI * 0.5f + p_angle)).normalized() * columns[1].length(); } real_t Transform2D::get_rotation() const { - return Math::atan2(elements[0].y, elements[0].x); + return Math::atan2(columns[0].y, columns[0].x); } 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); - elements[0][0] = cr; - elements[0][1] = sr; - elements[1][0] = -sr; - elements[1][1] = cr; + columns[0][0] = cr; + columns[0][1] = sr; + columns[1][0] = -sr; + columns[1][1] = cr; set_scale(scale); } 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; - elements[0][1] = sr; - elements[1][0] = -sr; - elements[1][1] = cr; - elements[2] = p_pos; + columns[0][0] = cr; + columns[0][1] = sr; + columns[1][0] = -sr; + columns[1][1] = cr; + columns[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; + columns[0][0] = Math::cos(p_rot) * p_scale.x; + columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y; + columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y; + columns[0][1] = Math::sin(p_rot) * p_scale.x; + columns[2] = p_pos; } Size2 Transform2D::get_scale() const { real_t det_sign = SIGN(basis_determinant()); - return Size2(elements[0].length(), det_sign * elements[1].length()); + return Size2(columns[0].length(), det_sign * columns[1].length()); } void Transform2D::set_scale(const Size2 &p_scale) { - elements[0].normalize(); - elements[1].normalize(); - elements[0] *= p_scale.x; - elements[1] *= p_scale.y; + columns[0].normalize(); + columns[1].normalize(); + columns[0] *= p_scale.x; + columns[1] *= p_scale.y; } void Transform2D::scale(const Size2 &p_scale) { scale_basis(p_scale); - elements[2] *= p_scale; + columns[2] *= p_scale; } void Transform2D::scale_basis(const Size2 &p_scale) { - elements[0][0] *= p_scale.x; - elements[0][1] *= p_scale.y; - elements[1][0] *= p_scale.x; - elements[1][1] *= p_scale.y; + columns[0][0] *= p_scale.x; + columns[0][1] *= p_scale.y; + columns[1][0] *= p_scale.x; + columns[1][1] *= p_scale.y; } -void Transform2D::translate(const real_t p_tx, const real_t p_ty) { - translate(Vector2(p_tx, p_ty)); +void Transform2D::translate_local(const real_t p_tx, const real_t p_ty) { + translate_local(Vector2(p_tx, p_ty)); } -void Transform2D::translate(const Vector2 &p_translation) { - elements[2] += basis_xform(p_translation); +void Transform2D::translate_local(const Vector2 &p_translation) { + columns[2] += basis_xform(p_translation); } void Transform2D::orthonormalize() { // Gram-Schmidt Process - Vector2 x = elements[0]; - Vector2 y = elements[1]; + Vector2 x = columns[0]; + Vector2 y = columns[1]; x.normalize(); y = (y - x * (x.dot(y))); y.normalize(); - elements[0] = x; - elements[1] = y; + columns[0] = x; + columns[1] = y; } Transform2D Transform2D::orthonormalized() const { @@ -165,7 +165,7 @@ Transform2D Transform2D::orthonormalized() const { } bool Transform2D::is_equal_approx(const Transform2D &p_transform) const { - return elements[0].is_equal_approx(p_transform.elements[0]) && elements[1].is_equal_approx(p_transform.elements[1]) && elements[2].is_equal_approx(p_transform.elements[2]); + return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]); } Transform2D Transform2D::looking_at(const Vector2 &p_target) const { @@ -177,7 +177,7 @@ Transform2D Transform2D::looking_at(const Vector2 &p_target) const { bool Transform2D::operator==(const Transform2D &p_transform) const { for (int i = 0; i < 3; i++) { - if (elements[i] != p_transform.elements[i]) { + if (columns[i] != p_transform.columns[i]) { return false; } } @@ -187,7 +187,7 @@ bool Transform2D::operator==(const Transform2D &p_transform) const { bool Transform2D::operator!=(const Transform2D &p_transform) const { for (int i = 0; i < 3; i++) { - if (elements[i] != p_transform.elements[i]) { + if (columns[i] != p_transform.columns[i]) { return true; } } @@ -196,19 +196,19 @@ bool Transform2D::operator!=(const Transform2D &p_transform) const { } void Transform2D::operator*=(const Transform2D &p_transform) { - elements[2] = xform(p_transform.elements[2]); + columns[2] = xform(p_transform.columns[2]); real_t x0, x1, y0, y1; - x0 = tdotx(p_transform.elements[0]); - x1 = tdoty(p_transform.elements[0]); - y0 = tdotx(p_transform.elements[1]); - y1 = tdoty(p_transform.elements[1]); + x0 = tdotx(p_transform.columns[0]); + x1 = tdoty(p_transform.columns[0]); + y0 = tdotx(p_transform.columns[1]); + y1 = tdoty(p_transform.columns[1]); - elements[0][0] = x0; - elements[0][1] = x1; - elements[1][0] = y0; - elements[1][1] = y1; + columns[0][0] = x0; + columns[0][1] = x1; + columns[1][0] = y0; + columns[1][1] = y1; } Transform2D Transform2D::operator*(const Transform2D &p_transform) const { @@ -217,38 +217,52 @@ Transform2D Transform2D::operator*(const Transform2D &p_transform) const { return t; } -Transform2D Transform2D::scaled(const Size2 &p_scale) const { +Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const { Transform2D copy = *this; - copy.scale(p_scale); + copy.scale_basis(p_scale); return copy; } -Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const { +Transform2D Transform2D::scaled(const Size2 &p_scale) const { + // Equivalent to left multiplication Transform2D copy = *this; - copy.scale_basis(p_scale); + copy.scale(p_scale); return copy; } +Transform2D Transform2D::scaled_local(const Size2 &p_scale) const { + // Equivalent to right multiplication + return Transform2D(columns[0] * p_scale.x, columns[1] * p_scale.y, columns[2]); +} + Transform2D Transform2D::untranslated() const { Transform2D copy = *this; - copy.elements[2] = Vector2(); + copy.columns[2] = Vector2(); return copy; } Transform2D Transform2D::translated(const Vector2 &p_offset) const { - Transform2D copy = *this; - copy.translate(p_offset); - return copy; + // Equivalent to left multiplication + return Transform2D(columns[0], columns[1], columns[2] + p_offset); } -Transform2D Transform2D::rotated(const real_t p_phi) const { - Transform2D copy = *this; - copy.rotate(p_phi); - return copy; +Transform2D Transform2D::translated_local(const Vector2 &p_offset) const { + // Equivalent to right multiplication + return Transform2D(columns[0], columns[1], columns[2] + basis_xform(p_offset)); +} + +Transform2D Transform2D::rotated(const real_t p_angle) const { + // Equivalent to left multiplication + return Transform2D(p_angle, Vector2()) * (*this); +} + +Transform2D Transform2D::rotated_local(const real_t p_angle) const { + // Equivalent to right multiplication + return (*this) * Transform2D(p_angle, Vector2()); // Could be optimized, because origin transform can be skipped. } real_t Transform2D::basis_determinant() const { - return elements[0].x * elements[1].y - elements[0].y * elements[1].x; + return columns[0].x * columns[1].y - columns[0].y * columns[1].x; } Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, const real_t p_c) const { @@ -287,9 +301,9 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, const } void Transform2D::operator*=(const real_t p_val) { - elements[0] *= p_val; - elements[1] *= p_val; - elements[2] *= p_val; + columns[0] *= p_val; + columns[1] *= p_val; + columns[2] *= p_val; } Transform2D Transform2D::operator*(const real_t p_val) const { @@ -299,7 +313,7 @@ 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() + "]"; + return "[X: " + columns[0].operator String() + + ", Y: " + columns[1].operator String() + + ", O: " + columns[2].operator String() + "]"; } diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index f4546c13c8..f23f32867a 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -39,33 +39,24 @@ class String; struct _NO_DISCARD_ Transform2D { - // Warning #1: basis of Transform2D is stored differently from Basis. In terms of elements array, the basis matrix looks like "on paper": - // M = (elements[0][0] elements[1][0]) - // (elements[0][1] elements[1][1]) - // This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as elements[i]. - // Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to elements[1][0] here. + // Warning #1: basis of Transform2D is stored differently from Basis. In terms of columns array, the basis matrix looks like "on paper": + // M = (columns[0][0] columns[1][0]) + // (columns[0][1] columns[1][1]) + // This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as columns[i]. + // Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to columns[1][0] here. // This requires additional care when working with explicit indices. // See https://en.wikipedia.org/wiki/Row-_and_column-major_order for further reading. // Warning #2: 2D be aware that unlike 3D code, 2D code uses a left-handed coordinate system: Y-axis points down, // and angle is measure from +X to +Y in a clockwise-fashion. - Vector2 elements[3]; + Vector2 columns[3]; - _FORCE_INLINE_ real_t tdotx(const Vector2 &v) const { return elements[0][0] * v.x + elements[1][0] * v.y; } - _FORCE_INLINE_ real_t tdoty(const Vector2 &v) const { return elements[0][1] * v.x + elements[1][1] * v.y; } + _FORCE_INLINE_ real_t tdotx(const Vector2 &v) const { return columns[0][0] * v.x + columns[1][0] * v.y; } + _FORCE_INLINE_ real_t tdoty(const Vector2 &v) const { return columns[0][1] * v.x + columns[1][1] * v.y; } - const Vector2 &operator[](int p_idx) const { return elements[p_idx]; } - Vector2 &operator[](int p_idx) { return elements[p_idx]; } - - _FORCE_INLINE_ Vector2 get_axis(int p_axis) const { - ERR_FAIL_INDEX_V(p_axis, 3, Vector2()); - return elements[p_axis]; - } - _FORCE_INLINE_ void set_axis(int p_axis, const Vector2 &p_vec) { - ERR_FAIL_INDEX(p_axis, 3); - elements[p_axis] = p_vec; - } + const Vector2 &operator[](int p_idx) const { return columns[p_idx]; } + Vector2 &operator[](int p_idx) { return columns[p_idx]; } void invert(); Transform2D inverse() const; @@ -79,25 +70,28 @@ struct _NO_DISCARD_ Transform2D { 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 rotate(const real_t p_angle); void scale(const Size2 &p_scale); void scale_basis(const Size2 &p_scale); - void translate(const real_t p_tx, const real_t p_ty); - void translate(const Vector2 &p_translation); + void translate_local(const real_t p_tx, const real_t p_ty); + void translate_local(const Vector2 &p_translation); real_t basis_determinant() const; Size2 get_scale() const; void set_scale(const Size2 &p_scale); - _FORCE_INLINE_ const Vector2 &get_origin() const { return elements[2]; } - _FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { elements[2] = p_origin; } + _FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; } + _FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; } - Transform2D scaled(const Size2 &p_scale) const; Transform2D basis_scaled(const Size2 &p_scale) const; + Transform2D scaled(const Size2 &p_scale) const; + Transform2D scaled_local(const Size2 &p_scale) const; Transform2D translated(const Vector2 &p_offset) const; - Transform2D rotated(const real_t p_phi) const; + Transform2D translated_local(const Vector2 &p_offset) const; + Transform2D rotated(const real_t p_angle) const; + Transform2D rotated_local(const real_t p_angle) const; Transform2D untranslated() const; @@ -129,18 +123,18 @@ struct _NO_DISCARD_ Transform2D { operator String() const; 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; - elements[1][1] = yy; - elements[2][0] = ox; - elements[2][1] = oy; + columns[0][0] = xx; + columns[0][1] = xy; + columns[1][0] = yx; + columns[1][1] = yy; + columns[2][0] = ox; + columns[2][1] = oy; } Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) { - elements[0] = p_x; - elements[1] = p_y; - elements[2] = p_origin; + columns[0] = p_x; + columns[1] = p_y; + columns[2] = p_origin; } Transform2D(const real_t p_rot, const Vector2 &p_pos); @@ -148,8 +142,8 @@ struct _NO_DISCARD_ Transform2D { 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; + columns[0][0] = 1.0; + columns[1][1] = 1.0; } }; @@ -161,28 +155,28 @@ Vector2 Transform2D::basis_xform(const Vector2 &p_vec) const { Vector2 Transform2D::basis_xform_inv(const Vector2 &p_vec) const { return Vector2( - elements[0].dot(p_vec), - elements[1].dot(p_vec)); + columns[0].dot(p_vec), + columns[1].dot(p_vec)); } Vector2 Transform2D::xform(const Vector2 &p_vec) const { return Vector2( tdotx(p_vec), tdoty(p_vec)) + - elements[2]; + columns[2]; } Vector2 Transform2D::xform_inv(const Vector2 &p_vec) const { - Vector2 v = p_vec - elements[2]; + Vector2 v = p_vec - columns[2]; return Vector2( - elements[0].dot(v), - elements[1].dot(v)); + columns[0].dot(v), + columns[1].dot(v)); } Rect2 Transform2D::xform(const Rect2 &p_rect) const { - Vector2 x = elements[0] * p_rect.size.x; - Vector2 y = elements[1] * p_rect.size.y; + Vector2 x = columns[0] * p_rect.size.x; + Vector2 y = columns[1] * p_rect.size.y; Vector2 pos = xform(p_rect.position); Rect2 new_rect; @@ -194,17 +188,17 @@ Rect2 Transform2D::xform(const Rect2 &p_rect) const { } 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; + columns[0][0] = Math::cos(p_rot) * p_scale.x; + columns[1][1] = Math::cos(p_rot) * p_scale.y; + columns[1][0] = -Math::sin(p_rot) * p_scale.y; + columns[0][1] = Math::sin(p_rot) * p_scale.x; } 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; - elements[0][1] = Math::sin(p_rot) * p_scale.x; + columns[0][0] = Math::cos(p_rot) * p_scale.x; + columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y; + columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y; + columns[0][1] = Math::sin(p_rot) * p_scale.x; } Rect2 Transform2D::xform_inv(const Rect2 &p_rect) const { diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp index e5374315e2..a634faca9a 100644 --- a/core/math/transform_3d.cpp +++ b/core/math/transform_3d.cpp @@ -57,30 +57,44 @@ Transform3D Transform3D::inverse() const { return ret; } -void Transform3D::rotate(const Vector3 &p_axis, real_t p_phi) { - *this = rotated(p_axis, p_phi); +void Transform3D::rotate(const Vector3 &p_axis, real_t p_angle) { + *this = rotated(p_axis, p_angle); } -Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_phi) const { - return Transform3D(Basis(p_axis, p_phi), Vector3()) * (*this); +Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_angle) const { + // Equivalent to left multiplication + Basis p_basis(p_axis, p_angle); + return Transform3D(p_basis * basis, p_basis.xform(origin)); } -void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_phi) { - basis.rotate(p_axis, p_phi); +Transform3D Transform3D::rotated_local(const Vector3 &p_axis, real_t p_angle) const { + // Equivalent to right multiplication + Basis p_basis(p_axis, p_angle); + return Transform3D(basis * p_basis, origin); +} + +void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_angle) { + basis.rotate(p_axis, p_angle); } Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(origin.is_equal_approx(p_target), Transform3D(), "The transform's origin and target can't be equal."); +#endif Transform3D t = *this; t.basis = Basis::looking_at(p_target - origin, p_up); return t; } void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { +#ifdef MATH_CHECKS + ERR_FAIL_COND_MSG(p_eye.is_equal_approx(p_target), "The eye and target vectors can't be equal."); +#endif basis = Basis::looking_at(p_target - p_eye, p_up); origin = p_eye; } -Transform3D Transform3D::sphere_interpolate_with(const Transform3D &p_transform, real_t p_c) const { +Transform3D Transform3D::spherical_interpolate_with(const Transform3D &p_transform, real_t p_c) const { /* not sure if very "efficient" but good enough? */ Transform3D interp; @@ -114,29 +128,37 @@ void Transform3D::scale(const Vector3 &p_scale) { } Transform3D Transform3D::scaled(const Vector3 &p_scale) const { - Transform3D t = *this; - t.scale(p_scale); - return t; + // Equivalent to left multiplication + return Transform3D(basis.scaled(p_scale), origin * p_scale); +} + +Transform3D Transform3D::scaled_local(const Vector3 &p_scale) const { + // Equivalent to right multiplication + return Transform3D(basis.scaled_local(p_scale), origin); } void Transform3D::scale_basis(const Vector3 &p_scale) { basis.scale(p_scale); } -void Transform3D::translate(real_t p_tx, real_t p_ty, real_t p_tz) { - translate(Vector3(p_tx, p_ty, p_tz)); +void Transform3D::translate_local(real_t p_tx, real_t p_ty, real_t p_tz) { + translate_local(Vector3(p_tx, p_ty, p_tz)); } -void Transform3D::translate(const Vector3 &p_translation) { +void Transform3D::translate_local(const Vector3 &p_translation) { for (int i = 0; i < 3; i++) { origin[i] += basis[i].dot(p_translation); } } Transform3D Transform3D::translated(const Vector3 &p_translation) const { - Transform3D t = *this; - t.translate(p_translation); - return t; + // Equivalent to left multiplication + return Transform3D(basis, origin + p_translation); +} + +Transform3D Transform3D::translated_local(const Vector3 &p_translation) const { + // Equivalent to right multiplication + return Transform3D(basis, origin + basis.xform(p_translation)); } void Transform3D::orthonormalize() { @@ -194,9 +216,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() + + return "[X: " + basis.get_column(0).operator String() + + ", Y: " + basis.get_column(1).operator String() + + ", Z: " + basis.get_column(2).operator String() + ", O: " + origin.operator String() + "]"; } @@ -207,9 +229,9 @@ Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) : Transform3D::Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : origin(p_origin) { - basis.set_axis(0, p_x); - basis.set_axis(1, p_y); - basis.set_axis(2, p_z); + basis.set_column(0, p_x); + basis.set_column(1, p_y); + basis.set_column(2, p_z); } Transform3D::Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) { diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h index 3b4762e221..b572e90859 100644 --- a/core/math/transform_3d.h +++ b/core/math/transform_3d.h @@ -45,20 +45,23 @@ struct _NO_DISCARD_ Transform3D { void affine_invert(); Transform3D affine_inverse() const; - Transform3D rotated(const Vector3 &p_axis, real_t p_phi) const; + Transform3D rotated(const Vector3 &p_axis, real_t p_angle) const; + Transform3D rotated_local(const Vector3 &p_axis, real_t p_angle) const; - void rotate(const Vector3 &p_axis, real_t p_phi); - void rotate_basis(const Vector3 &p_axis, real_t p_phi); + void rotate(const Vector3 &p_axis, real_t p_angle); + void rotate_basis(const Vector3 &p_axis, real_t p_angle); void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const; void scale(const Vector3 &p_scale); Transform3D scaled(const Vector3 &p_scale) const; + Transform3D scaled_local(const Vector3 &p_scale) const; void scale_basis(const Vector3 &p_scale); - void translate(real_t p_tx, real_t p_ty, real_t p_tz); - void translate(const Vector3 &p_translation); + void translate_local(real_t p_tx, real_t p_ty, real_t p_tz); + void translate_local(const Vector3 &p_translation); Transform3D translated(const Vector3 &p_translation) const; + Transform3D translated_local(const Vector3 &p_translation) const; const Basis &get_basis() const { return basis; } void set_basis(const Basis &p_basis) { basis = p_basis; } @@ -100,7 +103,7 @@ struct _NO_DISCARD_ Transform3D { void operator*=(const real_t p_val); Transform3D operator*(const real_t p_val) const; - Transform3D sphere_interpolate_with(const Transform3D &p_transform, real_t p_c) const; + Transform3D spherical_interpolate_with(const Transform3D &p_transform, real_t p_c) const; Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const; _FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &t) const { @@ -135,9 +138,9 @@ _FORCE_INLINE_ Vector3 Transform3D::xform_inv(const Vector3 &p_vector) const { Vector3 v = p_vector - origin; return Vector3( - (basis.elements[0][0] * v.x) + (basis.elements[1][0] * v.y) + (basis.elements[2][0] * v.z), - (basis.elements[0][1] * v.x) + (basis.elements[1][1] * v.y) + (basis.elements[2][1] * v.z), - (basis.elements[0][2] * v.x) + (basis.elements[1][2] * v.y) + (basis.elements[2][2] * v.z)); + (basis.rows[0][0] * v.x) + (basis.rows[1][0] * v.y) + (basis.rows[2][0] * v.z), + (basis.rows[0][1] * v.x) + (basis.rows[1][1] * v.y) + (basis.rows[2][1] * v.z), + (basis.rows[0][2] * v.x) + (basis.rows[1][2] * v.y) + (basis.rows[2][2] * v.z)); } // Neither the plane regular xform or xform_inv are particularly efficient, diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index e146c4a4e3..4433559e6d 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -104,9 +104,11 @@ void TriangleMesh::get_indices(Vector<int> *r_triangles_indices) const { } } -void TriangleMesh::create(const Vector<Vector3> &p_faces) { +void TriangleMesh::create(const Vector<Vector3> &p_faces, const Vector<int32_t> &p_surface_indices) { valid = false; + ERR_FAIL_COND(p_surface_indices.size() && p_surface_indices.size() != p_faces.size()); + int fc = p_faces.size(); ERR_FAIL_COND(!fc || ((fc % 3) != 0)); fc /= 3; @@ -121,8 +123,9 @@ void TriangleMesh::create(const Vector<Vector3> &p_faces) { //goes in-place. const Vector3 *r = p_faces.ptr(); + const int32_t *si = p_surface_indices.ptr(); Triangle *w = triangles.ptrw(); - Map<Vector3, int> db; + HashMap<Vector3, int> db; for (int i = 0; i < fc; i++) { Triangle &f = w[i]; @@ -131,9 +134,9 @@ void TriangleMesh::create(const Vector<Vector3> &p_faces) { for (int j = 0; j < 3; j++) { int vidx = -1; Vector3 vs = v[j].snapped(Vector3(0.0001, 0.0001, 0.0001)); - Map<Vector3, int>::Element *E = db.find(vs); + HashMap<Vector3, int>::Iterator E = db.find(vs); if (E) { - vidx = E->get(); + vidx = E->value; } else { vidx = db.size(); db[vs] = vidx; @@ -148,6 +151,7 @@ void TriangleMesh::create(const Vector<Vector3> &p_faces) { } f.normal = Face3(r[i * 3 + 0], r[i * 3 + 1], r[i * 3 + 2]).get_plane().get_normal(); + f.surface_index = si ? si[i] : 0; bw[i].left = -1; bw[i].right = -1; @@ -264,7 +268,7 @@ Vector3 TriangleMesh::get_area_normal(const AABB &p_aabb) const { return n; } -bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const { +bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index) const { uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); enum { @@ -317,6 +321,9 @@ bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_en d = nd; r_point = res; r_normal = f3.get_plane().get_normal(); + if (r_surf_index) { + *r_surf_index = s.surface_index; + } inters = true; } } @@ -366,7 +373,7 @@ bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_en return inters; } -bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal) const { +bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index) const { uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); enum { @@ -417,6 +424,9 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V d = nd; r_point = res; r_normal = f3.get_plane().get_normal(); + if (r_surf_index) { + *r_surf_index = s.surface_index; + } inters = true; } } diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h index 1b99945698..166b4adb7a 100644 --- a/core/math/triangle_mesh.h +++ b/core/math/triangle_mesh.h @@ -41,6 +41,7 @@ public: struct Triangle { Vector3 normal; int indices[3]; + int32_t surface_index; }; private: @@ -81,8 +82,8 @@ private: public: bool is_valid() const; - bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const; - bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal) const; + bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const; + bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const; bool intersect_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const; bool inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale = Vector3(1, 1, 1)) const; Vector3 get_area_normal(const AABB &p_aabb) const; @@ -92,7 +93,7 @@ public: const Vector<Vector3> &get_vertices() const { return vertices; } void get_indices(Vector<int> *r_triangles_indices) const; - void create(const Vector<Vector3> &p_faces); + void create(const Vector<Vector3> &p_faces, const Vector<int32_t> &p_surface_indices = Vector<int32_t>()); TriangleMesh(); }; diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index a27227905c..d9b5d55454 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -152,13 +152,6 @@ Vector2 Vector2::limit_length(const real_t p_len) const { return v; } -Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const { - Vector2 res = *this; - res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); - res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); - return res; -} - Vector2 Vector2::move_toward(const Vector2 &p_to, const real_t p_delta) const { Vector2 v = *this; Vector2 vd = p_to - v; diff --git a/core/math/vector2.h b/core/math/vector2.h index bd67299f33..91d3d3a56b 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -113,7 +113,9 @@ struct _NO_DISCARD_ Vector2 { _FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, const real_t p_weight) const; _FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, const real_t p_weight) const; - Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const; + _FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const; + _FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const; + Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const; Vector2 slide(const Vector2 &p_normal) const; @@ -261,6 +263,26 @@ Vector2 Vector2::slerp(const Vector2 &p_to, const real_t p_weight) const { return rotated(angle * p_weight) * (result_length / start_length); } +Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const { + Vector2 res = *this; + res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); + res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); + return res; +} + +Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const { + Vector2 res = *this; + + /* Formula from Wikipedia article on Bezier curves. */ + real_t omt = (1.0 - p_t); + real_t omt2 = omt * omt; + real_t omt3 = omt2 * omt; + real_t t2 = p_t * p_t; + real_t t3 = t2 * p_t; + + return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; +} + Vector2 Vector2::direction_to(const Vector2 &p_to) const { Vector2 ret(p_to.x - x, p_to.y - y); ret.normalize(); diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index 87b2ac7104..d71d365053 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -35,13 +35,13 @@ #include "core/math/vector3i.h" #include "core/string/ustring.h" -void Vector3::rotate(const Vector3 &p_axis, const real_t p_phi) { - *this = Basis(p_axis, p_phi).xform(*this); +void Vector3::rotate(const Vector3 &p_axis, const real_t p_angle) { + *this = Basis(p_axis, p_angle).xform(*this); } -Vector3 Vector3::rotated(const Vector3 &p_axis, const real_t p_phi) const { +Vector3 Vector3::rotated(const Vector3 &p_axis, const real_t p_angle) const { Vector3 r = *this; - r.rotate(p_axis, p_phi); + r.rotate(p_axis, p_angle); return r; } @@ -85,14 +85,6 @@ Vector3 Vector3::limit_length(const real_t p_len) const { return v; } -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 res = *this; - res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); - res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); - res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight); - return res; -} - Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const { Vector3 v = *this; Vector3 vd = p_to - v; diff --git a/core/math/vector3.h b/core/math/vector3.h index b22ebeaf0a..4ce01da60e 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -97,14 +97,16 @@ struct _NO_DISCARD_ Vector3 { void snap(const Vector3 p_val); Vector3 snapped(const Vector3 p_val) const; - void rotate(const Vector3 &p_axis, const real_t p_phi); - Vector3 rotated(const Vector3 &p_axis, const real_t p_phi) const; + void rotate(const Vector3 &p_axis, const real_t p_angle); + Vector3 rotated(const Vector3 &p_axis, const real_t p_angle) const; /* Static Methods between 2 vector3s */ _FORCE_INLINE_ Vector3 lerp(const Vector3 &p_to, const real_t p_weight) const; _FORCE_INLINE_ Vector3 slerp(const Vector3 &p_to, const real_t p_weight) const; - Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const; + _FORCE_INLINE_ Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const; + _FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const; + Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const; Vector2 octahedron_encode() const; @@ -215,16 +217,46 @@ Vector3 Vector3::lerp(const Vector3 &p_to, const real_t p_weight) const { } Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const { + // This method seems more complicated than it really is, since we write out + // the internals of some methods for efficiency (mainly, checking length). real_t start_length_sq = length_squared(); real_t end_length_sq = p_to.length_squared(); if (unlikely(start_length_sq == 0.0f || end_length_sq == 0.0f)) { // Zero length vectors have no angle, so the best we can do is either lerp or throw an error. return lerp(p_to, p_weight); } + Vector3 axis = cross(p_to); + real_t axis_length_sq = axis.length_squared(); + if (unlikely(axis_length_sq == 0.0f)) { + // Colinear vectors have no rotation axis or angle between them, so the best we can do is lerp. + return lerp(p_to, p_weight); + } + axis /= Math::sqrt(axis_length_sq); real_t start_length = Math::sqrt(start_length_sq); real_t result_length = Math::lerp(start_length, Math::sqrt(end_length_sq), p_weight); real_t angle = angle_to(p_to); - return rotated(cross(p_to).normalized(), angle * p_weight) * (result_length / start_length); + return rotated(axis, angle * p_weight) * (result_length / start_length); +} + +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 res = *this; + res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); + res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); + res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight); + return res; +} + +Vector3 Vector3::bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const { + Vector3 res = *this; + + /* Formula from Wikipedia article on Bezier curves. */ + real_t omt = (1.0 - p_t); + real_t omt2 = omt * omt; + real_t omt3 = omt2 * omt; + real_t t2 = p_t * p_t; + real_t t3 = t2 * p_t; + + return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; } real_t Vector3::distance_to(const Vector3 &p_to) const { diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp new file mode 100644 index 0000000000..4697c311b4 --- /dev/null +++ b/core/math/vector4.cpp @@ -0,0 +1,172 @@ +/*************************************************************************/ +/* vector4.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "vector4.h" + +#include "core/math/basis.h" +#include "core/string/print_string.h" + +void Vector4::set_axis(const int p_axis, const real_t p_value) { + ERR_FAIL_INDEX(p_axis, 4); + components[p_axis] = p_value; +} + +real_t Vector4::get_axis(const int p_axis) const { + ERR_FAIL_INDEX_V(p_axis, 4, 0); + return operator[](p_axis); +} + +Vector4::Axis Vector4::min_axis_index() const { + uint32_t min_index = 0; + real_t min_value = x; + for (uint32_t i = 1; i < 4; i++) { + if (operator[](i) <= min_value) { + min_index = i; + min_value = operator[](i); + } + } + return Vector4::Axis(min_index); +} + +Vector4::Axis Vector4::max_axis_index() const { + uint32_t max_index = 0; + real_t max_value = x; + for (uint32_t i = 1; i < 4; i++) { + if (operator[](i) > max_value) { + max_index = i; + max_value = operator[](i); + } + } + return Vector4::Axis(max_index); +} + +bool Vector4::is_equal_approx(const Vector4 &p_vec4) const { + return Math::is_equal_approx(x, p_vec4.x) && Math::is_equal_approx(y, p_vec4.y) && Math::is_equal_approx(z, p_vec4.z) && Math::is_equal_approx(w, p_vec4.w); +} + +real_t Vector4::length() const { + return Math::sqrt(length_squared()); +} + +void Vector4::normalize() { + *this /= length(); +} + +Vector4 Vector4::normalized() const { + return *this / length(); +} + +bool Vector4::is_normalized() const { + return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); // Use less epsilon. +} + +real_t Vector4::distance_to(const Vector4 &p_to) const { + return (p_to - *this).length(); +} + +Vector4 Vector4::direction_to(const Vector4 &p_to) const { + Vector4 ret(p_to.x - x, p_to.y - y, p_to.z - z, p_to.w - w); + ret.normalize(); + return ret; +} + +Vector4 Vector4::abs() const { + return Vector4(Math::abs(x), Math::abs(y), Math::abs(z), Math::abs(w)); +} + +Vector4 Vector4::sign() const { + return Vector4(SIGN(x), SIGN(y), SIGN(z), SIGN(w)); +} + +Vector4 Vector4::floor() const { + return Vector4(Math::floor(x), Math::floor(y), Math::floor(z), Math::floor(w)); +} + +Vector4 Vector4::ceil() const { + return Vector4(Math::ceil(x), Math::ceil(y), Math::ceil(z), Math::ceil(w)); +} + +Vector4 Vector4::round() const { + return Vector4(Math::round(x), Math::round(y), Math::round(z), Math::round(w)); +} + +Vector4 Vector4::lerp(const Vector4 &p_to, const real_t p_weight) const { + return Vector4( + x + (p_weight * (p_to.x - x)), + y + (p_weight * (p_to.y - y)), + z + (p_weight * (p_to.z - z)), + w + (p_weight * (p_to.w - w))); +} + +Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const { + Vector4 res = *this; + res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); + res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); + res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight); + res.w = Math::cubic_interpolate(res.w, p_b.w, p_pre_a.w, p_post_b.w, p_weight); + return res; +} + +Vector4 Vector4::posmod(const real_t p_mod) const { + return Vector4(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod), Math::fposmod(w, p_mod)); +} + +Vector4 Vector4::posmodv(const Vector4 &p_modv) const { + return Vector4(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y), Math::fposmod(z, p_modv.z), Math::fposmod(w, p_modv.w)); +} + +void Vector4::snap(const Vector4 &p_step) { + x = Math::snapped(x, p_step.x); + y = Math::snapped(y, p_step.y); + z = Math::snapped(z, p_step.z); + w = Math::snapped(w, p_step.w); +} + +Vector4 Vector4::snapped(const Vector4 &p_step) const { + Vector4 v = *this; + v.snap(p_step); + return v; +} + +Vector4 Vector4::inverse() const { + return Vector4(1.0f / x, 1.0f / y, 1.0f / z, 1.0f / w); +} + +Vector4 Vector4::clamp(const Vector4 &p_min, const Vector4 &p_max) const { + return Vector4( + CLAMP(x, p_min.x, p_max.x), + CLAMP(y, p_min.y, p_max.y), + CLAMP(z, p_min.z, p_max.z), + CLAMP(w, p_min.w, p_max.w)); +} + +Vector4::operator String() const { + return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")"; +} diff --git a/core/math/vector4.h b/core/math/vector4.h new file mode 100644 index 0000000000..373a6a1218 --- /dev/null +++ b/core/math/vector4.h @@ -0,0 +1,302 @@ +/*************************************************************************/ +/* vector4.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 VECTOR4_H +#define VECTOR4_H + +#include "core/math/math_defs.h" +#include "core/math/math_funcs.h" +#include "core/math/vector3.h" +#include "core/string/ustring.h" + +struct _NO_DISCARD_ Vector4 { + enum Axis { + AXIS_X, + AXIS_Y, + AXIS_Z, + AXIS_W, + }; + + union { + struct { + real_t x; + real_t y; + real_t z; + real_t w; + }; + real_t components[4] = { 0, 0, 0, 0 }; + }; + + _FORCE_INLINE_ real_t &operator[](const int p_axis) { + DEV_ASSERT((unsigned int)p_axis < 4); + return components[p_axis]; + } + _FORCE_INLINE_ const real_t &operator[](const int p_axis) const { + DEV_ASSERT((unsigned int)p_axis < 4); + return components[p_axis]; + } + + _FORCE_INLINE_ void set_all(const real_t p_value); + + void set_axis(const int p_axis, const real_t p_value); + real_t get_axis(const int p_axis) const; + + Vector4::Axis min_axis_index() const; + Vector4::Axis max_axis_index() const; + + _FORCE_INLINE_ real_t length_squared() const; + bool is_equal_approx(const Vector4 &p_vec4) const; + real_t length() const; + void normalize(); + Vector4 normalized() const; + bool is_normalized() const; + + real_t distance_to(const Vector4 &p_to) const; + Vector4 direction_to(const Vector4 &p_to) const; + + Vector4 abs() const; + Vector4 sign() const; + Vector4 floor() const; + Vector4 ceil() const; + Vector4 round() const; + Vector4 lerp(const Vector4 &p_to, const real_t p_weight) const; + Vector4 cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const; + + Vector4 posmod(const real_t p_mod) const; + Vector4 posmodv(const Vector4 &p_modv) const; + void snap(const Vector4 &p_step); + Vector4 snapped(const Vector4 &p_step) const; + Vector4 clamp(const Vector4 &p_min, const Vector4 &p_max) const; + + Vector4 inverse() const; + _FORCE_INLINE_ real_t dot(const Vector4 &p_vec4) const; + + _FORCE_INLINE_ void operator+=(const Vector4 &p_vec4); + _FORCE_INLINE_ void operator-=(const Vector4 &p_vec4); + _FORCE_INLINE_ void operator*=(const Vector4 &p_vec4); + _FORCE_INLINE_ void operator/=(const Vector4 &p_vec4); + _FORCE_INLINE_ void operator*=(const real_t &s); + _FORCE_INLINE_ void operator/=(const real_t &s); + _FORCE_INLINE_ Vector4 operator+(const Vector4 &p_vec4) const; + _FORCE_INLINE_ Vector4 operator-(const Vector4 &p_vec4) const; + _FORCE_INLINE_ Vector4 operator*(const Vector4 &p_vec4) const; + _FORCE_INLINE_ Vector4 operator/(const Vector4 &p_vec4) const; + _FORCE_INLINE_ Vector4 operator-() const; + _FORCE_INLINE_ Vector4 operator*(const real_t &s) const; + _FORCE_INLINE_ Vector4 operator/(const real_t &s) const; + + _FORCE_INLINE_ bool operator==(const Vector4 &p_vec4) const; + _FORCE_INLINE_ bool operator!=(const Vector4 &p_vec4) const; + _FORCE_INLINE_ bool operator>(const Vector4 &p_vec4) const; + _FORCE_INLINE_ bool operator<(const Vector4 &p_vec4) const; + _FORCE_INLINE_ bool operator>=(const Vector4 &p_vec4) const; + _FORCE_INLINE_ bool operator<=(const Vector4 &p_vec4) const; + + operator String() const; + + _FORCE_INLINE_ Vector4() {} + + _FORCE_INLINE_ Vector4(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : + x(p_x), + y(p_y), + z(p_z), + w(p_w) { + } + + Vector4(const Vector4 &p_vec4) : + x(p_vec4.x), + y(p_vec4.y), + z(p_vec4.z), + w(p_vec4.w) { + } + + void operator=(const Vector4 &p_vec4) { + x = p_vec4.x; + y = p_vec4.y; + z = p_vec4.z; + w = p_vec4.w; + } +}; + +void Vector4::set_all(const real_t p_value) { + x = y = z = p_value; +} + +real_t Vector4::dot(const Vector4 &p_vec4) const { + return x * p_vec4.x + y * p_vec4.y + z * p_vec4.z + w * p_vec4.w; +} + +real_t Vector4::length_squared() const { + return dot(*this); +} + +void Vector4::operator+=(const Vector4 &p_vec4) { + x += p_vec4.x; + y += p_vec4.y; + z += p_vec4.z; + w += p_vec4.w; +} + +void Vector4::operator-=(const Vector4 &p_vec4) { + x -= p_vec4.x; + y -= p_vec4.y; + z -= p_vec4.z; + w -= p_vec4.w; +} + +void Vector4::operator*=(const Vector4 &p_vec4) { + x *= p_vec4.x; + y *= p_vec4.y; + z *= p_vec4.z; + w *= p_vec4.w; +} + +void Vector4::operator/=(const Vector4 &p_vec4) { + x /= p_vec4.x; + y /= p_vec4.y; + z /= p_vec4.z; + w /= p_vec4.w; +} +void Vector4::operator*=(const real_t &s) { + x *= s; + y *= s; + z *= s; + w *= s; +} + +void Vector4::operator/=(const real_t &s) { + *this *= 1.0f / s; +} + +Vector4 Vector4::operator+(const Vector4 &p_vec4) const { + return Vector4(x + p_vec4.x, y + p_vec4.y, z + p_vec4.z, w + p_vec4.w); +} + +Vector4 Vector4::operator-(const Vector4 &p_vec4) const { + return Vector4(x - p_vec4.x, y - p_vec4.y, z - p_vec4.z, w - p_vec4.w); +} + +Vector4 Vector4::operator*(const Vector4 &p_vec4) const { + return Vector4(x * p_vec4.x, y * p_vec4.y, z * p_vec4.z, w * p_vec4.w); +} + +Vector4 Vector4::operator/(const Vector4 &p_vec4) const { + return Vector4(x / p_vec4.x, y / p_vec4.y, z / p_vec4.z, w / p_vec4.w); +} + +Vector4 Vector4::operator-() const { + return Vector4(-x, -y, -z, -w); +} + +Vector4 Vector4::operator*(const real_t &s) const { + return Vector4(x * s, y * s, z * s, w * s); +} + +Vector4 Vector4::operator/(const real_t &s) const { + return *this * (1.0f / s); +} + +bool Vector4::operator==(const Vector4 &p_vec4) const { + return x == p_vec4.x && y == p_vec4.y && z == p_vec4.z && w == p_vec4.w; +} + +bool Vector4::operator!=(const Vector4 &p_vec4) const { + return x != p_vec4.x || y != p_vec4.y || z != p_vec4.z || w != p_vec4.w; +} + +bool Vector4::operator<(const Vector4 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w < p_v.w; + } + return z < p_v.z; + } + return y < p_v.y; + } + return x < p_v.x; +} + +bool Vector4::operator>(const Vector4 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w > p_v.w; + } + return z > p_v.z; + } + return y > p_v.y; + } + return x > p_v.x; +} + +bool Vector4::operator<=(const Vector4 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w <= p_v.w; + } + return z < p_v.z; + } + return y < p_v.y; + } + return x < p_v.x; +} + +bool Vector4::operator>=(const Vector4 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w >= p_v.w; + } + return z > p_v.z; + } + return y > p_v.y; + } + return x > p_v.x; +} + +_FORCE_INLINE_ Vector4 operator*(const float p_scalar, const Vector4 &p_vec) { + return p_vec * p_scalar; +} + +_FORCE_INLINE_ Vector4 operator*(const double p_scalar, const Vector4 &p_vec) { + return p_vec * p_scalar; +} + +_FORCE_INLINE_ Vector4 operator*(const int32_t p_scalar, const Vector4 &p_vec) { + return p_vec * p_scalar; +} + +_FORCE_INLINE_ Vector4 operator*(const int64_t p_scalar, const Vector4 &p_vec) { + return p_vec * p_scalar; +} + +#endif // VECTOR4_H diff --git a/core/math/vector4i.cpp b/core/math/vector4i.cpp new file mode 100644 index 0000000000..2dc5b74202 --- /dev/null +++ b/core/math/vector4i.cpp @@ -0,0 +1,91 @@ +/*************************************************************************/ +/* vector4i.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "vector4i.h" + +#include "core/math/vector4.h" +#include "core/string/ustring.h" + +void Vector4i::set_axis(const int p_axis, const int32_t p_value) { + ERR_FAIL_INDEX(p_axis, 4); + coord[p_axis] = p_value; +} + +int32_t Vector4i::get_axis(const int p_axis) const { + ERR_FAIL_INDEX_V(p_axis, 4, 0); + return operator[](p_axis); +} + +Vector4i::Axis Vector4i::min_axis_index() const { + uint32_t min_index = 0; + int32_t min_value = x; + for (uint32_t i = 1; i < 4; i++) { + if (operator[](i) <= min_value) { + min_index = i; + min_value = operator[](i); + } + } + return Vector4i::Axis(min_index); +} + +Vector4i::Axis Vector4i::max_axis_index() const { + uint32_t max_index = 0; + int32_t max_value = x; + for (uint32_t i = 1; i < 4; i++) { + if (operator[](i) > max_value) { + max_index = i; + max_value = operator[](i); + } + } + return Vector4i::Axis(max_index); +} + +Vector4i Vector4i::clamp(const Vector4i &p_min, const Vector4i &p_max) const { + return Vector4i( + CLAMP(x, p_min.x, p_max.x), + CLAMP(y, p_min.y, p_max.y), + CLAMP(z, p_min.z, p_max.z), + CLAMP(w, p_min.w, p_max.w)); +} + +Vector4i::operator String() const { + return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ", " + itos(w) + ")"; +} + +Vector4i::operator Vector4() const { + return Vector4(x, y, z, w); +} + +Vector4i::Vector4i(const Vector4 &p_vec4) { + x = p_vec4.x; + y = p_vec4.y; + z = p_vec4.z; + w = p_vec4.w; +} diff --git a/core/math/vector4i.h b/core/math/vector4i.h new file mode 100644 index 0000000000..37d905878f --- /dev/null +++ b/core/math/vector4i.h @@ -0,0 +1,338 @@ +/*************************************************************************/ +/* vector4i.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 VECTOR4I_H +#define VECTOR4I_H + +#include "core/error/error_macros.h" +#include "core/math/math_funcs.h" + +class String; +struct Vector4; + +struct _NO_DISCARD_ Vector4i { + enum Axis { + AXIS_X, + AXIS_Y, + AXIS_Z, + AXIS_W, + }; + + union { + struct { + int32_t x; + int32_t y; + int32_t z; + int32_t w; + }; + + int32_t coord[4] = { 0 }; + }; + + _FORCE_INLINE_ const int32_t &operator[](const int p_axis) const { + DEV_ASSERT((unsigned int)p_axis < 4); + return coord[p_axis]; + } + + _FORCE_INLINE_ int32_t &operator[](const int p_axis) { + DEV_ASSERT((unsigned int)p_axis < 4); + return coord[p_axis]; + } + + void set_axis(const int p_axis, const int32_t p_value); + int32_t get_axis(const int p_axis) const; + + Vector4i::Axis min_axis_index() const; + Vector4i::Axis max_axis_index() const; + + _FORCE_INLINE_ int64_t length_squared() const; + _FORCE_INLINE_ double length() const; + + _FORCE_INLINE_ void zero(); + + _FORCE_INLINE_ Vector4i abs() const; + _FORCE_INLINE_ Vector4i sign() const; + Vector4i clamp(const Vector4i &p_min, const Vector4i &p_max) const; + + /* Operators */ + + _FORCE_INLINE_ Vector4i &operator+=(const Vector4i &p_v); + _FORCE_INLINE_ Vector4i operator+(const Vector4i &p_v) const; + _FORCE_INLINE_ Vector4i &operator-=(const Vector4i &p_v); + _FORCE_INLINE_ Vector4i operator-(const Vector4i &p_v) const; + _FORCE_INLINE_ Vector4i &operator*=(const Vector4i &p_v); + _FORCE_INLINE_ Vector4i operator*(const Vector4i &p_v) const; + _FORCE_INLINE_ Vector4i &operator/=(const Vector4i &p_v); + _FORCE_INLINE_ Vector4i operator/(const Vector4i &p_v) const; + _FORCE_INLINE_ Vector4i &operator%=(const Vector4i &p_v); + _FORCE_INLINE_ Vector4i operator%(const Vector4i &p_v) const; + + _FORCE_INLINE_ Vector4i &operator*=(const int32_t p_scalar); + _FORCE_INLINE_ Vector4i operator*(const int32_t p_scalar) const; + _FORCE_INLINE_ Vector4i &operator/=(const int32_t p_scalar); + _FORCE_INLINE_ Vector4i operator/(const int32_t p_scalar) const; + _FORCE_INLINE_ Vector4i &operator%=(const int32_t p_scalar); + _FORCE_INLINE_ Vector4i operator%(const int32_t p_scalar) const; + + _FORCE_INLINE_ Vector4i operator-() const; + + _FORCE_INLINE_ bool operator==(const Vector4i &p_v) const; + _FORCE_INLINE_ bool operator!=(const Vector4i &p_v) const; + _FORCE_INLINE_ bool operator<(const Vector4i &p_v) const; + _FORCE_INLINE_ bool operator<=(const Vector4i &p_v) const; + _FORCE_INLINE_ bool operator>(const Vector4i &p_v) const; + _FORCE_INLINE_ bool operator>=(const Vector4i &p_v) const; + + operator String() const; + operator Vector4() const; + + _FORCE_INLINE_ Vector4i() {} + Vector4i(const Vector4 &p_vec4); + _FORCE_INLINE_ Vector4i(const int32_t p_x, const int32_t p_y, const int32_t p_z, const int32_t p_w) { + x = p_x; + y = p_y; + z = p_z; + w = p_w; + } +}; + +int64_t Vector4i::length_squared() const { + return x * (int64_t)x + y * (int64_t)y + z * (int64_t)z + w * (int64_t)w; +} + +double Vector4i::length() const { + return Math::sqrt((double)length_squared()); +} + +Vector4i Vector4i::abs() const { + return Vector4i(ABS(x), ABS(y), ABS(z), ABS(w)); +} + +Vector4i Vector4i::sign() const { + return Vector4i(SIGN(x), SIGN(y), SIGN(z), SIGN(w)); +} + +/* Operators */ + +Vector4i &Vector4i::operator+=(const Vector4i &p_v) { + x += p_v.x; + y += p_v.y; + z += p_v.z; + w += p_v.w; + return *this; +} + +Vector4i Vector4i::operator+(const Vector4i &p_v) const { + return Vector4i(x + p_v.x, y + p_v.y, z + p_v.z, w + p_v.w); +} + +Vector4i &Vector4i::operator-=(const Vector4i &p_v) { + x -= p_v.x; + y -= p_v.y; + z -= p_v.z; + w -= p_v.w; + return *this; +} + +Vector4i Vector4i::operator-(const Vector4i &p_v) const { + return Vector4i(x - p_v.x, y - p_v.y, z - p_v.z, w - p_v.w); +} + +Vector4i &Vector4i::operator*=(const Vector4i &p_v) { + x *= p_v.x; + y *= p_v.y; + z *= p_v.z; + w *= p_v.w; + return *this; +} + +Vector4i Vector4i::operator*(const Vector4i &p_v) const { + return Vector4i(x * p_v.x, y * p_v.y, z * p_v.z, w * p_v.w); +} + +Vector4i &Vector4i::operator/=(const Vector4i &p_v) { + x /= p_v.x; + y /= p_v.y; + z /= p_v.z; + w /= p_v.w; + return *this; +} + +Vector4i Vector4i::operator/(const Vector4i &p_v) const { + return Vector4i(x / p_v.x, y / p_v.y, z / p_v.z, w / p_v.w); +} + +Vector4i &Vector4i::operator%=(const Vector4i &p_v) { + x %= p_v.x; + y %= p_v.y; + z %= p_v.z; + w %= p_v.w; + return *this; +} + +Vector4i Vector4i::operator%(const Vector4i &p_v) const { + return Vector4i(x % p_v.x, y % p_v.y, z % p_v.z, w % p_v.w); +} + +Vector4i &Vector4i::operator*=(const int32_t p_scalar) { + x *= p_scalar; + y *= p_scalar; + z *= p_scalar; + w *= p_scalar; + return *this; +} + +Vector4i Vector4i::operator*(const int32_t p_scalar) const { + return Vector4i(x * p_scalar, y * p_scalar, z * p_scalar, w * p_scalar); +} + +// Multiplication operators required to workaround issues with LLVM using implicit conversion. + +_FORCE_INLINE_ Vector4i operator*(const int32_t p_scalar, const Vector4i &p_vector) { + return p_vector * p_scalar; +} + +_FORCE_INLINE_ Vector4i operator*(const int64_t p_scalar, const Vector4i &p_vector) { + return p_vector * p_scalar; +} + +_FORCE_INLINE_ Vector4i operator*(const float p_scalar, const Vector4i &p_vector) { + return p_vector * p_scalar; +} + +_FORCE_INLINE_ Vector4i operator*(const double p_scalar, const Vector4i &p_vector) { + return p_vector * p_scalar; +} + +Vector4i &Vector4i::operator/=(const int32_t p_scalar) { + x /= p_scalar; + y /= p_scalar; + z /= p_scalar; + w /= p_scalar; + return *this; +} + +Vector4i Vector4i::operator/(const int32_t p_scalar) const { + return Vector4i(x / p_scalar, y / p_scalar, z / p_scalar, w / p_scalar); +} + +Vector4i &Vector4i::operator%=(const int32_t p_scalar) { + x %= p_scalar; + y %= p_scalar; + z %= p_scalar; + w %= p_scalar; + return *this; +} + +Vector4i Vector4i::operator%(const int32_t p_scalar) const { + return Vector4i(x % p_scalar, y % p_scalar, z % p_scalar, w % p_scalar); +} + +Vector4i Vector4i::operator-() const { + return Vector4i(-x, -y, -z, -w); +} + +bool Vector4i::operator==(const Vector4i &p_v) const { + return (x == p_v.x && y == p_v.y && z == p_v.z && w == p_v.w); +} + +bool Vector4i::operator!=(const Vector4i &p_v) const { + return (x != p_v.x || y != p_v.y || z != p_v.z || w != p_v.w); +} + +bool Vector4i::operator<(const Vector4i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w < p_v.w; + } else { + return z < p_v.z; + } + } else { + return y < p_v.y; + } + } else { + return x < p_v.x; + } +} + +bool Vector4i::operator>(const Vector4i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w > p_v.w; + } else { + return z > p_v.z; + } + } else { + return y > p_v.y; + } + } else { + return x > p_v.x; + } +} + +bool Vector4i::operator<=(const Vector4i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w <= p_v.w; + } else { + return z < p_v.z; + } + } else { + return y < p_v.y; + } + } else { + return x < p_v.x; + } +} + +bool Vector4i::operator>=(const Vector4i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w >= p_v.w; + } else { + return z > p_v.z; + } + } else { + return y > p_v.y; + } + } else { + return x > p_v.x; + } +} + +void Vector4i::zero() { + x = y = z = w = 0; +} + +#endif // VECTOR4I_H |