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