diff options
Diffstat (limited to 'core/math')
-rw-r--r-- | core/math/a_star.cpp | 170 | ||||
-rw-r--r-- | core/math/a_star.h | 122 | ||||
-rw-r--r-- | core/math/audio_frame.h | 2 | ||||
-rw-r--r-- | core/math/basis.cpp | 25 | ||||
-rw-r--r-- | core/math/basis.h | 24 | ||||
-rw-r--r-- | core/math/camera_matrix.cpp | 5 | ||||
-rw-r--r-- | core/math/camera_matrix.h | 1 | ||||
-rw-r--r-- | core/math/color.cpp | 61 | ||||
-rw-r--r-- | core/math/color.h | 8 | ||||
-rw-r--r-- | core/math/delaunay_3d.h | 2 | ||||
-rw-r--r-- | core/math/expression.cpp | 42 | ||||
-rw-r--r-- | core/math/expression.h | 4 | ||||
-rw-r--r-- | core/math/math_funcs.h | 33 | ||||
-rw-r--r-- | core/math/octree.h | 1271 | ||||
-rw-r--r-- | core/math/triangle_mesh.cpp | 16 | ||||
-rw-r--r-- | core/math/triangle_mesh.h | 7 | ||||
-rw-r--r-- | core/math/vector2.cpp | 7 | ||||
-rw-r--r-- | core/math/vector2.h | 24 | ||||
-rw-r--r-- | core/math/vector3.cpp | 8 | ||||
-rw-r--r-- | core/math/vector3.h | 25 |
20 files changed, 364 insertions, 1493 deletions
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index efa970c681..41a0848d01 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -33,19 +33,19 @@ #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 < 0.0, vformat("Can't add a point with weight scale less than 0.0: %f.", p_weight_scale)); @@ -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,7 +92,7 @@ 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)); @@ -101,12 +101,12 @@ void AStar3D::set_point_weight_scale(int p_id, real_t 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; @@ -165,7 +165,7 @@ void AStar3D::connect_points(int p_id, int p_with_id, bool bidirectional) { 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,7 +175,7 @@ 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; HashSet<Segment, Segment>::Iterator element = segments.find(s); if (element) { @@ -205,35 +205,35 @@ void AStar3D::disconnect_points(int p_id, int p_with_id, bool bidirectional) { } } -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 HashSet<Segment, Segment>::Iterator element = segments.find(s); @@ -243,32 +243,32 @@ bool AStar3D::are_points_connected(int p_id, int p_with_id, bool bidirectional) 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; @@ -295,8 +295,8 @@ Vector3 AStar3D::get_closest_position_in_segment(const Vector3 &p_point) const { for (const Segment &E : segments) { Point *from_point = nullptr, *to_point = nullptr; - points.lookup(E.u, from_point); - points.lookup(E.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 e2f75ad18c..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, @@ -93,28 +87,28 @@ class AStar3D : public RefCounted { unsigned char direction = NONE; static uint32_t hash(const Segment &p_seg) { - return hash_one_uint64(p_seg.key); + 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; + OAHashMap<int64_t, Point *> points; HashSet<Segment, Segment> segments; bool _solve(Point *begin_point, Point *end_point); @@ -122,42 +116,42 @@ class AStar3D : 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 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(); @@ -172,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 65353d8118..f8e7c47107 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -365,12 +365,12 @@ 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 { @@ -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(rows[1][0] - rows[0][1]) < epsilon) && (Math::abs(rows[2][0] - rows[0][2]) < epsilon) && (Math::abs(rows[2][1] - rows[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(rows[1][0] + rows[0][1]) < epsilon2) && (Math::abs(rows[2][0] + rows[0][2]) < epsilon2) && (Math::abs(rows[2][1] + rows[1][2]) < epsilon2) && (Math::abs(rows[0][0] + rows[1][1] + rows[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; @@ -839,7 +838,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { 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 < epsilon) { + if (xx < CMP_EPSILON) { x = 0; y = Math_SQRT12; z = Math_SQRT12; @@ -849,7 +848,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { z = xz / x; } } else if (yy > zz) { // rows[1][1] is the largest diagonal term - if (yy < epsilon) { + if (yy < CMP_EPSILON) { x = Math_SQRT12; y = 0; z = Math_SQRT12; @@ -859,7 +858,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { z = yz / y; } } else { // rows[2][2] is the largest diagonal term so base result on this - if (zz < epsilon) { + if (zz < CMP_EPSILON) { x = Math_SQRT12; y = Math_SQRT12; z = 0; @@ -935,9 +934,9 @@ void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Ve 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) { diff --git a/core/math/basis.h b/core/math/basis.h index 9cce22510b..4be325cdd2 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -56,6 +56,15 @@ struct _NO_DISCARD_ Basis { _FORCE_INLINE_ real_t determinant() const; + enum EulerOrder { + EULER_ORDER_XYZ, + EULER_ORDER_XZY, + EULER_ORDER_YXZ, + EULER_ORDER_YZX, + EULER_ORDER_ZXY, + EULER_ORDER_ZYX + }; + void from_z(const Vector3 &p_z); void rotate(const Vector3 &p_axis, real_t p_angle); @@ -64,21 +73,12 @@ struct _NO_DISCARD_ Basis { 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); - Basis rotated(const Vector3 &p_euler) 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; - enum EulerOrder { - EULER_ORDER_XYZ, - EULER_ORDER_XZY, - EULER_ORDER_YXZ, - EULER_ORDER_YZX, - EULER_ORDER_ZXY, - EULER_ORDER_ZYX - }; - Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) const; void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const; void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const; @@ -119,7 +119,7 @@ struct _NO_DISCARD_ Basis { Vector3 get_scale_local() const; 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); + 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 diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 9443addd22..57c53b0adb 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -710,6 +710,11 @@ void CameraMatrix::scale_translate_to_fit(const AABB &p_aabb) { matrix[3][3] = 1; } +void CameraMatrix::add_jitter_offset(const Vector2 &p_offset) { + matrix[3][0] += p_offset.x; + matrix[3][1] += p_offset.y; +} + CameraMatrix::operator Transform3D() const { Transform3D tr; const real_t *m = &matrix[0][0]; diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index f1aea5e4e8..a4051cee3b 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -95,6 +95,7 @@ struct CameraMatrix { 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; diff --git a/core/math/color.cpp b/core/math/color.cpp index 74552a2894..4bdeafd2f2 100644 --- a/core/math/color.cpp +++ b/core/math/color.cpp @@ -35,6 +35,8 @@ #include "core/string/print_string.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); c <<= 8; @@ -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..0afa6006a8 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 @@ -213,6 +218,9 @@ struct _NO_DISCARD_ Color { _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_ok_hsl_h(float p_h) { set_ok_hsl(p_h, get_ok_hsl_s(), get_ok_hsl_l()); } + _FORCE_INLINE_ void set_ok_hsl_s(float p_s) { set_ok_hsl(get_ok_hsl_h(), p_s, get_ok_hsl_l()); } + _FORCE_INLINE_ void set_ok_hsl_l(float p_l) { set_ok_hsl(get_ok_hsl_h(), get_ok_hsl_s(), p_l); } _FORCE_INLINE_ Color() {} diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h index f8a10ec87e..4ab00e1f34 100644 --- a/core/math/delaunay_3d.h +++ b/core/math/delaunay_3d.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)); } }; diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 97dc175d94..e230b69dc9 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -891,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; } @@ -1240,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]; @@ -1266,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; } @@ -1274,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; } @@ -1292,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; } @@ -1316,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; } @@ -1336,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; @@ -1353,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; } @@ -1380,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; @@ -1408,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; } @@ -1429,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; @@ -1442,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; @@ -1452,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)); @@ -1491,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; @@ -1517,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 6ea3c1611f..2d58915996 100644 --- a/core/math/expression.h +++ b/core/math/expression.h @@ -257,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/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 8dd103f109..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/rb_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 HashMap<OctreeElementID, Element, Comparator<OctreeElementID>, AL> ElementMap; - typedef HashMap<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/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index 54461bf70f..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,6 +123,7 @@ 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(); HashMap<Vector3, int> db; @@ -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 f94f39b7f2..d71d365053 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -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 8891532f42..970416234d 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -104,7 +104,9 @@ struct _NO_DISCARD_ Vector3 { _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; @@ -227,6 +229,27 @@ Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const { return rotated(cross(p_to).normalized(), 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 { return (p_to - *this).length(); } |