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