瀏覽代碼

Update core data structures to match the engine

Aaron Franke 2 年之前
父節點
當前提交
65eeb94f75

+ 4 - 4
include/godot_cpp/core/math.hpp

@@ -441,17 +441,17 @@ inline T abs(T x) {
 	return std::abs(x);
 }
 
-inline double deg2rad(double p_y) {
+inline double deg_to_rad(double p_y) {
 	return p_y * Math_PI / 180.0;
 }
-inline float deg2rad(float p_y) {
+inline float deg_to_rad(float p_y) {
 	return p_y * static_cast<float>(Math_PI) / 180.f;
 }
 
-inline double rad2deg(double p_y) {
+inline double rad_to_deg(double p_y) {
 	return p_y * 180.0 / Math_PI;
 }
-inline float rad2deg(float p_y) {
+inline float rad_to_deg(float p_y) {
 	return p_y * 180.f / static_cast<float>(Math_PI);
 }
 

+ 80 - 43
include/godot_cpp/variant/aabb.hpp

@@ -31,29 +31,29 @@
 #ifndef GODOT_AABB_HPP
 #define GODOT_AABB_HPP
 
-#include <godot_cpp/core/error_macros.hpp>
-#include <godot_cpp/core/math.hpp>
 #include <godot_cpp/variant/plane.hpp>
 #include <godot_cpp/variant/vector3.hpp>
 
 /**
- * AABB / AABB (Axis Aligned Bounding Box)
- * This is implemented by a point (position) and the box size
+ * AABB (Axis Aligned Bounding Box)
+ * This is implemented by a point (position) and the box size.
  */
 
 namespace godot {
 
+class Variant;
+
 struct _NO_DISCARD_ AABB {
 	Vector3 position;
 	Vector3 size;
 
-	real_t get_area() const; /// get area
-	inline bool has_no_area() const {
-		return (size.x <= 0 || size.y <= 0 || size.z <= 0);
+	real_t get_volume() const;
+	_FORCE_INLINE_ bool has_volume() const {
+		return size.x > 0.0f && size.y > 0.0f && size.z > 0.0f;
 	}
 
-	inline bool has_no_surface() const {
-		return (size.x <= 0 && size.y <= 0 && size.z <= 0);
+	_FORCE_INLINE_ bool has_surface() const {
+		return size.x > 0.0f || size.y > 0.0f || size.z > 0.0f;
 	}
 
 	const Vector3 &get_position() const { return position; }
@@ -65,60 +65,67 @@ struct _NO_DISCARD_ AABB {
 	bool operator!=(const AABB &p_rval) const;
 
 	bool is_equal_approx(const AABB &p_aabb) const;
-	inline bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
-	inline bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
-	inline bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
+	_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
+	_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
+	_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
 
 	AABB merge(const AABB &p_with) const;
-	void merge_with(const AABB &p_aabb); /// merge with another AABB
-	AABB intersection(const AABB &p_aabb) const; /// get box where two intersect, empty if no intersection occurs
+	void merge_with(const AABB &p_aabb); ///merge with another AABB
+	AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs
 	bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
 	bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
-	inline bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const;
+	_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const;
 
-	inline bool intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const;
-	inline bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const;
+	_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const;
+	_FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const;
 	bool intersects_plane(const Plane &p_plane) const;
 
-	inline bool has_point(const Vector3 &p_point) const;
-	inline Vector3 get_support(const Vector3 &p_normal) const;
+	_FORCE_INLINE_ bool has_point(const Vector3 &p_point) const;
+	_FORCE_INLINE_ Vector3 get_support(const Vector3 &p_normal) const;
 
 	Vector3 get_longest_axis() const;
 	int get_longest_axis_index() const;
-	inline real_t get_longest_axis_size() const;
+	_FORCE_INLINE_ real_t get_longest_axis_size() const;
 
 	Vector3 get_shortest_axis() const;
 	int get_shortest_axis_index() const;
-	inline real_t get_shortest_axis_size() const;
+	_FORCE_INLINE_ real_t get_shortest_axis_size() const;
 
 	AABB grow(real_t p_by) const;
-	inline void grow_by(real_t p_amount);
+	_FORCE_INLINE_ void grow_by(real_t p_amount);
 
 	void get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const;
-	inline Vector3 get_endpoint(int p_point) const;
+	_FORCE_INLINE_ Vector3 get_endpoint(int p_point) const;
 
 	AABB expand(const Vector3 &p_vector) const;
-	inline void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const;
-	inline void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
+	_FORCE_INLINE_ void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const;
+	_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
 
-	inline AABB abs() const {
-		return AABB(Vector3(position.x + Math::min(size.x, (real_t)0), position.y + Math::min(size.y, (real_t)0), position.z + Math::min(size.z, (real_t)0)), size.abs());
+	_FORCE_INLINE_ AABB abs() const {
+		return AABB(Vector3(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0), position.z + MIN(size.z, (real_t)0)), size.abs());
 	}
 
-	inline void quantize(real_t p_unit);
-	inline AABB quantized(real_t p_unit) const;
+	Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
+	Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
+
+	_FORCE_INLINE_ void quantize(real_t p_unit);
+	_FORCE_INLINE_ AABB quantized(real_t p_unit) const;
 
-	inline void set_end(const Vector3 &p_end) {
+	_FORCE_INLINE_ void set_end(const Vector3 &p_end) {
 		size = p_end - position;
 	}
 
-	inline Vector3 get_end() const {
+	_FORCE_INLINE_ Vector3 get_end() const {
 		return position + size;
 	}
 
+	_FORCE_INLINE_ Vector3 get_center() const {
+		return position + (size * 0.5f);
+	}
+
 	operator String() const;
 
-	inline AABB() {}
+	_FORCE_INLINE_ AABB() {}
 	inline AABB(const Vector3 &p_pos, const Vector3 &p_size) :
 			position(p_pos),
 			size(p_size) {
@@ -126,6 +133,11 @@ struct _NO_DISCARD_ AABB {
 };
 
 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;
 	}
@@ -149,6 +161,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;
 	}
@@ -172,6 +189,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;
@@ -187,14 +209,14 @@ inline bool AABB::encloses(const AABB &p_aabb) const {
 }
 
 Vector3 AABB::get_support(const Vector3 &p_normal) const {
-	Vector3 half_extents = size * 0.5;
+	Vector3 half_extents = size * 0.5f;
 	Vector3 ofs = position + half_extents;
 
 	return Vector3(
 				   (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 {
@@ -221,7 +243,7 @@ Vector3 AABB::get_endpoint(int p_point) const {
 }
 
 bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const {
-	Vector3 half_extents = size * 0.5;
+	Vector3 half_extents = size * 0.5f;
 	Vector3 ofs = position + half_extents;
 
 	for (int i = 0; i < p_plane_count; i++) {
@@ -263,7 +285,7 @@ bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count, con
 }
 
 bool AABB::inside_convex_shape(const Plane *p_planes, int p_plane_count) const {
-	Vector3 half_extents = size * 0.5;
+	Vector3 half_extents = size * 0.5f;
 	Vector3 ofs = position + half_extents;
 
 	for (int i = 0; i < p_plane_count; i++) {
@@ -282,6 +304,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;
 	}
@@ -305,6 +332,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;
 
@@ -333,7 +365,7 @@ inline void AABB::expand_to(const Vector3 &p_vector) {
 }
 
 void AABB::project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const {
-	Vector3 half_extents(size.x * (real_t)0.5, size.y * (real_t)0.5, size.z * (real_t)0.5);
+	Vector3 half_extents(size.x * 0.5f, size.y * 0.5f, size.z * 0.5f);
 	Vector3 center(position.x + half_extents.x, position.y + half_extents.y, position.z + half_extents.z);
 
 	real_t length = p_plane.normal.abs().dot(half_extents);
@@ -371,9 +403,14 @@ 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 {
-	real_t divx = (real_t)1.0 / p_dir.x;
-	real_t divy = (real_t)1.0 / p_dir.y;
-	real_t divz = (real_t)1.0 / p_dir.z;
+#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.0f / p_dir.x;
+	real_t divy = 1.0f / p_dir.y;
+	real_t divz = 1.0f / p_dir.z;
 
 	Vector3 upbound = position + size;
 	real_t tmin, tmax, tymin, tymax, tzmin, tzmax;
@@ -423,9 +460,9 @@ void AABB::grow_by(real_t p_amount) {
 	position.x -= p_amount;
 	position.y -= p_amount;
 	position.z -= p_amount;
-	size.x += (real_t)2.0 * p_amount;
-	size.y += (real_t)2.0 * p_amount;
-	size.z += (real_t)2.0 * p_amount;
+	size.x += 2.0f * p_amount;
+	size.y += 2.0f * p_amount;
+	size.z += 2.0f * p_amount;
 }
 
 void AABB::quantize(real_t p_unit) {

+ 0 - 1
include/godot_cpp/variant/basis.hpp

@@ -31,7 +31,6 @@
 #ifndef GODOT_BASIS_HPP
 #define GODOT_BASIS_HPP
 
-#include <godot_cpp/core/math.hpp>
 #include <godot_cpp/variant/quaternion.hpp>
 #include <godot_cpp/variant/vector3.hpp>
 

+ 45 - 40
include/godot_cpp/variant/color.hpp

@@ -54,15 +54,16 @@ struct _NO_DISCARD_ 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;
-	void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0);
+	void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
 
-	inline float &operator[](int p_idx) {
+	_FORCE_INLINE_ float &operator[](int p_idx) {
 		return components[p_idx];
 	}
-	inline const float &operator[](int p_idx) const {
+	_FORCE_INLINE_ const float &operator[](int p_idx) const {
 		return components[p_idx];
 	}
 
@@ -92,10 +93,15 @@ struct _NO_DISCARD_ Color {
 
 	bool is_equal_approx(const Color &p_color) const;
 
+	Color clamp(const Color &p_min = Color(0, 0, 0, 0), const Color &p_max = Color(1, 1, 1, 1)) const;
 	void invert();
 	Color inverted() const;
 
-	inline Color lerp(const Color &p_to, float p_weight) const {
+	_FORCE_INLINE_ float get_luminance() const {
+		return 0.2126f * r + 0.7152f * g + 0.0722f * b;
+	}
+
+	_FORCE_INLINE_ Color lerp(const Color &p_to, float p_weight) const {
 		Color res = *this;
 
 		res.r += (p_weight * (p_to.r - r));
@@ -106,7 +112,7 @@ struct _NO_DISCARD_ Color {
 		return res;
 	}
 
-	inline Color darkened(float p_amount) const {
+	_FORCE_INLINE_ Color darkened(float p_amount) const {
 		Color res = *this;
 		res.r = res.r * (1.0f - p_amount);
 		res.g = res.g * (1.0f - p_amount);
@@ -114,7 +120,7 @@ struct _NO_DISCARD_ Color {
 		return res;
 	}
 
-	inline Color lightened(float p_amount) const {
+	_FORCE_INLINE_ Color lightened(float p_amount) const {
 		Color res = *this;
 		res.r = res.r + (1.0f - res.r) * p_amount;
 		res.g = res.g + (1.0f - res.g) * p_amount;
@@ -122,26 +128,26 @@ struct _NO_DISCARD_ Color {
 		return res;
 	}
 
-	inline uint32_t to_rgbe9995() const {
+	_FORCE_INLINE_ uint32_t to_rgbe9995() const {
 		const float pow2to9 = 512.0f;
 		const float B = 15.0f;
 		const float N = 9.0f;
 
 		float sharedexp = 65408.000f; // Result of: ((pow2to9 - 1.0f) / pow2to9) * powf(2.0f, 31.0f - 15.0f)
 
-		float cRed = Math::max(0.0f, Math::min(sharedexp, r));
-		float cGreen = Math::max(0.0f, Math::min(sharedexp, g));
-		float cBlue = Math::max(0.0f, Math::min(sharedexp, b));
+		float cRed = MAX(0.0f, MIN(sharedexp, r));
+		float cGreen = MAX(0.0f, MIN(sharedexp, g));
+		float cBlue = MAX(0.0f, MIN(sharedexp, b));
 
-		float cMax = Math::max(cRed, Math::max(cGreen, cBlue));
+		float cMax = MAX(cRed, MAX(cGreen, cBlue));
 
-		float expp = Math::max(-B - 1.0f, Math::floor(Math::log(cMax) / (float)Math_LN2)) + 1.0f + B;
+		float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / (real_t)Math_LN2)) + 1.0f + B;
 
 		float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f);
 
 		float exps = expp + 1.0f;
 
-		if (0.0 <= sMax && sMax < pow2to9) {
+		if (0.0f <= sMax && sMax < pow2to9) {
 			exps = expp;
 		}
 
@@ -152,9 +158,9 @@ struct _NO_DISCARD_ Color {
 		return (uint32_t(Math::fast_ftoi(sRed)) & 0x1FF) | ((uint32_t(Math::fast_ftoi(sGreen)) & 0x1FF) << 9) | ((uint32_t(Math::fast_ftoi(sBlue)) & 0x1FF) << 18) | ((uint32_t(Math::fast_ftoi(exps)) & 0x1F) << 27);
 	}
 
-	inline Color blend(const Color &p_over) const {
+	_FORCE_INLINE_ Color blend(const Color &p_over) const {
 		Color res;
-		float sa = 1.0 - p_over.a;
+		float sa = 1.0f - p_over.a;
 		res.a = a * sa + p_over.a;
 		if (res.a == 0) {
 			return Color(0, 0, 0, 0);
@@ -166,14 +172,14 @@ struct _NO_DISCARD_ Color {
 		return res;
 	}
 
-	inline Color srgb_to_linear() const {
+	_FORCE_INLINE_ Color srgb_to_linear() const {
 		return Color(
-				r < 0.04045 ? r * (1.0 / 12.92) : Math::pow((r + 0.055f) * (1.0 / (1.0 + 0.055)), 2.4),
-				g < 0.04045 ? g * (1.0 / 12.92) : Math::pow((g + 0.055f) * (1.0 / (1.0 + 0.055)), 2.4),
-				b < 0.04045 ? b * (1.0 / 12.92) : Math::pow((b + 0.055f) * (1.0 / (1.0 + 0.055)), 2.4),
+				r < 0.04045f ? r * (1.0f / 12.92f) : Math::pow((r + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+				g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow((g + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+				b < 0.04045f ? b * (1.0f / 12.92f) : Math::pow((b + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
 				a);
 	}
-	inline Color linear_to_srgb() const {
+	_FORCE_INLINE_ Color linear_to_srgb() const {
 		return Color(
 				r < 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * Math::pow(r, 1.0f / 2.4f) - 0.055f,
 				g < 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * Math::pow(g, 1.0f / 2.4f) - 0.055f,
@@ -191,34 +197,33 @@ struct _NO_DISCARD_ 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;
-	static Color from_hsv(float p_h, float p_s, float p_v, float p_a);
+	static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
 	static Color from_rgbe9995(uint32_t p_rgbe);
 
-	inline bool operator<(const Color &p_color) const; // used in set keys
+	_FORCE_INLINE_ bool operator<(const Color &p_color) const; // Used in set keys.
 	operator String() const;
 
 	// For the binder.
-	inline void set_r8(int32_t r8) { r = (Math::clamp(r8, 0, 255) / 255.0); }
-	inline int32_t get_r8() const { return int32_t(Math::clamp(r * 255.0, 0.0, 255.0)); }
-	inline void set_g8(int32_t g8) { g = (Math::clamp(g8, 0, 255) / 255.0); }
-	inline int32_t get_g8() const { return int32_t(Math::clamp(g * 255.0, 0.0, 255.0)); }
-	inline void set_b8(int32_t b8) { b = (Math::clamp(b8, 0, 255) / 255.0); }
-	inline int32_t get_b8() const { return int32_t(Math::clamp(b * 255.0, 0.0, 255.0)); }
-	inline void set_a8(int32_t a8) { a = (Math::clamp(a8, 0, 255) / 255.0); }
-	inline int32_t get_a8() const { return int32_t(Math::clamp(a * 255.0, 0.0, 255.0)); }
+	_FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0f); }
+	_FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(Math::round(r * 255.0f), 0.0f, 255.0f)); }
+	_FORCE_INLINE_ void set_g8(int32_t g8) { g = (CLAMP(g8, 0, 255) / 255.0f); }
+	_FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(Math::round(g * 255.0f), 0.0f, 255.0f)); }
+	_FORCE_INLINE_ void set_b8(int32_t b8) { b = (CLAMP(b8, 0, 255) / 255.0f); }
+	_FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(Math::round(b * 255.0f), 0.0f, 255.0f)); }
+	_FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0f); }
+	_FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(Math::round(a * 255.0f), 0.0f, 255.0f)); }
 
-	inline void set_h(float p_h) { set_hsv(p_h, get_s(), get_v()); }
-	inline void set_s(float p_s) { set_hsv(get_h(), p_s, get_v()); }
-	inline void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v); }
+	_FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v(), a); }
+	_FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v(), a); }
+	_FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v, a); }
 
-	inline Color() {}
+	_FORCE_INLINE_ Color() {}
 
 	/**
 	 * RGBA construct parameters.
 	 * Alpha is not optional as otherwise we can't bind the RGB version for scripting.
 	 */
-	inline Color(float p_r, float p_g, float p_b, float p_a) {
+	_FORCE_INLINE_ Color(float p_r, float p_g, float p_b, float p_a) {
 		r = p_r;
 		g = p_g;
 		b = p_b;
@@ -228,17 +233,17 @@ struct _NO_DISCARD_ Color {
 	/**
 	 * RGB construct parameters.
 	 */
-	inline Color(float p_r, float p_g, float p_b) {
+	_FORCE_INLINE_ Color(float p_r, float p_g, float p_b) {
 		r = p_r;
 		g = p_g;
 		b = p_b;
-		a = 1.0;
+		a = 1.0f;
 	}
 
 	/**
 	 * Construct a Color from another Color, but with the specified alpha value.
 	 */
-	inline Color(const Color &p_c, float p_a) {
+	_FORCE_INLINE_ Color(const Color &p_c, float p_a) {
 		r = p_c.r;
 		g = p_c.g;
 		b = p_c.b;
@@ -275,7 +280,7 @@ bool Color::operator<(const Color &p_color) const {
 	}
 }
 
-inline Color operator*(float p_scalar, const Color &p_color) {
+_FORCE_INLINE_ Color operator*(float p_scalar, const Color &p_color) {
 	return p_color * p_scalar;
 }
 

+ 24 - 17
include/godot_cpp/variant/plane.hpp

@@ -32,29 +32,30 @@
 #define GODOT_PLANE_HPP
 
 #include <godot_cpp/classes/global_constants.hpp>
-#include <godot_cpp/core/math.hpp>
 #include <godot_cpp/variant/vector3.hpp>
 
 namespace godot {
 
+class Variant;
+
 struct _NO_DISCARD_ Plane {
 	Vector3 normal;
 	real_t d = 0;
 
 	void set_normal(const Vector3 &p_normal);
-	inline Vector3 get_normal() const { return normal; }; /// Point is coplanar, CMP_EPSILON for precision
+	_FORCE_INLINE_ Vector3 get_normal() const { return normal; };
 
 	void normalize();
 	Plane normalized() const;
 
 	/* Plane-Point operations */
 
-	inline Vector3 center() const { return normal * d; }
+	_FORCE_INLINE_ Vector3 center() const { return normal * d; }
 	Vector3 get_any_perpendicular_normal() const;
 
-	inline bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane
-	inline real_t distance_to(const Vector3 &p_point) const;
-	inline bool has_point(const Vector3 &p_point, real_t _epsilon = CMP_EPSILON) const;
+	_FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane
+	_FORCE_INLINE_ real_t distance_to(const Vector3 &p_point) const;
+	_FORCE_INLINE_ bool has_point(const Vector3 &p_point, real_t p_tolerance = CMP_EPSILON) const;
 
 	/* intersections */
 
@@ -62,7 +63,12 @@ struct _NO_DISCARD_ Plane {
 	bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection) const;
 	bool intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 *p_intersection) const;
 
-	inline Vector3 project(const Vector3 &p_point) const {
+	// For Variant bindings.
+	Variant intersect_3_bind(const Plane &p_plane1, const Plane &p_plane2) const;
+	Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
+	Variant intersects_segment_bind(const Vector3 &p_begin, const Vector3 &p_end) const;
+
+	_FORCE_INLINE_ Vector3 project(const Vector3 &p_point) const {
 		return p_point - normal * distance_to(p_point);
 	}
 
@@ -72,18 +78,18 @@ struct _NO_DISCARD_ Plane {
 	bool is_equal_approx(const Plane &p_plane) const;
 	bool is_equal_approx_any_side(const Plane &p_plane) const;
 
-	inline bool operator==(const Plane &p_plane) const;
-	inline bool operator!=(const Plane &p_plane) const;
+	_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
+	_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
 	operator String() const;
 
-	inline Plane() {}
-	inline Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) :
+	_FORCE_INLINE_ Plane() {}
+	_FORCE_INLINE_ Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) :
 			normal(p_a, p_b, p_c),
 			d(p_d) {}
 
-	inline Plane(const Vector3 &p_normal, real_t p_d);
-	inline Plane(const Vector3 &p_point, const Vector3 &p_normal);
-	inline Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir = CLOCKWISE);
+	_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);
 };
 
 bool Plane::is_point_over(const Vector3 &p_point) const {
@@ -94,10 +100,10 @@ real_t Plane::distance_to(const Vector3 &p_point) const {
 	return (normal.dot(p_point) - d);
 }
 
-bool Plane::has_point(const Vector3 &p_point, real_t _epsilon) const {
+bool Plane::has_point(const Vector3 &p_point, real_t p_tolerance) const {
 	real_t dist = normal.dot(p_point) - d;
 	dist = Math::abs(dist);
-	return (dist <= _epsilon);
+	return (dist <= p_tolerance);
 }
 
 Plane::Plane(const Vector3 &p_normal, real_t p_d) :
@@ -105,7 +111,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)) {
 }
@@ -128,6 +134,7 @@ bool Plane::operator==(const Plane &p_plane) const {
 bool Plane::operator!=(const Plane &p_plane) const {
 	return normal != p_plane.normal || d != p_plane.d;
 }
+
 } // namespace godot
 
 #endif // GODOT_PLANE_HPP

+ 13 - 12
include/godot_cpp/variant/projection.hpp

@@ -32,13 +32,12 @@
 #define GODOT_PROJECTION_HPP
 
 #include <godot_cpp/core/math.hpp>
-
-#include <godot_cpp/variant/array.hpp>
 #include <godot_cpp/variant/vector3.hpp>
 #include <godot_cpp/variant/vector4.hpp>
 
 namespace godot {
 
+class Array;
 struct AABB;
 struct Plane;
 struct Rect2;
@@ -55,14 +54,16 @@ struct _NO_DISCARD_ Projection {
 		PLANE_BOTTOM
 	};
 
-	Vector4 matrix[4];
+	Vector4 columns[4];
 
 	_FORCE_INLINE_ const Vector4 &operator[](const int p_axis) const {
-		return matrix[p_axis];
+		DEV_ASSERT((unsigned int)p_axis < 4);
+		return columns[p_axis];
 	}
 
 	_FORCE_INLINE_ Vector4 &operator[](const int p_axis) {
-		return matrix[p_axis];
+		DEV_ASSERT((unsigned int)p_axis < 4);
+		return columns[p_axis];
 	}
 
 	float determinant() const;
@@ -97,7 +98,7 @@ struct _NO_DISCARD_ Projection {
 	Projection jitter_offseted(const Vector2 &p_offset) const;
 
 	static real_t get_fovy(real_t p_fovx, real_t p_aspect) {
-		return Math::rad2deg(Math::atan(p_aspect * Math::tan(Math::deg2rad(p_fovx) * 0.5)) * 2.0);
+		return Math::rad_to_deg(Math::atan(p_aspect * Math::tan(Math::deg_to_rad(p_fovx) * 0.5)) * 2.0);
 	}
 
 	real_t get_z_far() const;
@@ -107,8 +108,8 @@ struct _NO_DISCARD_ Projection {
 	bool is_orthogonal() const;
 
 	Array get_projection_planes(const Transform3D &p_transform) const;
-	bool get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const;
 
+	bool get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const;
 	Vector2 get_viewport_half_extents() const;
 	Vector2 get_far_plane_half_extents() const;
 
@@ -136,7 +137,7 @@ struct _NO_DISCARD_ Projection {
 	bool operator==(const Projection &p_cam) const {
 		for (uint32_t i = 0; i < 4; i++) {
 			for (uint32_t j = 0; j < 4; j++) {
-				if (matrix[i][j] != p_cam.matrix[i][j]) {
+				if (columns[i][j] != p_cam.columns[i][j]) {
 					return false;
 				}
 			}
@@ -158,10 +159,10 @@ struct _NO_DISCARD_ Projection {
 
 Vector3 Projection::xform(const Vector3 &p_vec3) const {
 	Vector3 ret;
-	ret.x = matrix[0][0] * p_vec3.x + matrix[1][0] * p_vec3.y + matrix[2][0] * p_vec3.z + matrix[3][0];
-	ret.y = matrix[0][1] * p_vec3.x + matrix[1][1] * p_vec3.y + matrix[2][1] * p_vec3.z + matrix[3][1];
-	ret.z = matrix[0][2] * p_vec3.x + matrix[1][2] * p_vec3.y + matrix[2][2] * p_vec3.z + matrix[3][2];
-	real_t w = matrix[0][3] * p_vec3.x + matrix[1][3] * p_vec3.y + matrix[2][3] * p_vec3.z + matrix[3][3];
+	ret.x = columns[0][0] * p_vec3.x + columns[1][0] * p_vec3.y + columns[2][0] * p_vec3.z + columns[3][0];
+	ret.y = columns[0][1] * p_vec3.x + columns[1][1] * p_vec3.y + columns[2][1] * p_vec3.z + columns[3][1];
+	ret.z = columns[0][2] * p_vec3.x + columns[1][2] * p_vec3.y + columns[2][2] * p_vec3.z + columns[3][2];
+	real_t w = columns[0][3] * p_vec3.x + columns[1][3] * p_vec3.y + columns[2][3] * p_vec3.z + columns[3][3];
 	return ret / w;
 }
 

+ 1 - 2
include/godot_cpp/variant/quaternion.hpp

@@ -143,8 +143,7 @@ struct _NO_DISCARD_ Quaternion {
 		w = p_q.w;
 	}
 
-	Quaternion(const Vector3 &v0, const Vector3 &v1) // shortest arc
-	{
+	Quaternion(const Vector3 &v0, const Vector3 &v1) { // Shortest arc.
 		Vector3 c = v0.cross(v1);
 		real_t d = v0.dot(v1);
 

+ 62 - 27
include/godot_cpp/variant/rect2.hpp

@@ -32,7 +32,6 @@
 #define GODOT_RECT2_HPP
 
 #include <godot_cpp/classes/global_constants.hpp>
-#include <godot_cpp/core/math.hpp>
 #include <godot_cpp/variant/vector2.hpp>
 
 namespace godot {
@@ -52,7 +51,14 @@ struct _NO_DISCARD_ Rect2 {
 
 	real_t get_area() const { return size.width * size.height; }
 
+	_FORCE_INLINE_ Vector2 get_center() const { return position + (size * 0.5f); }
+
 	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;
@@ -85,6 +91,11 @@ struct _NO_DISCARD_ 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;
 
@@ -121,13 +132,18 @@ struct _NO_DISCARD_ 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));
 	}
 
-	inline bool has_no_area() const {
-		return (size.x <= 0 || size.y <= 0);
+	_FORCE_INLINE_ bool has_area() const {
+		return size.x > 0.0f && size.y > 0.0f;
 	}
 
 	// Returns the instersection between two Rect2s or an empty Rect2 if there is no intersection
@@ -151,7 +167,11 @@ struct _NO_DISCARD_ 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 = Math::min(p_rect.position.x, position.x);
@@ -160,11 +180,17 @@ struct _NO_DISCARD_ Rect2 {
 		new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x);
 		new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y);
 
-		new_rect.size = new_rect.size - new_rect.position; // make relative again
+		new_rect.size = new_rect.size - new_rect.position; // Make relative again.
 
 		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,7 @@ struct _NO_DISCARD_ Rect2 {
 
 		return true;
 	}
+
 	bool is_equal_approx(const Rect2 &p_rect) const;
 
 	bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
@@ -188,13 +215,17 @@ struct _NO_DISCARD_ Rect2 {
 
 	inline Rect2 grow(real_t p_amount) const {
 		Rect2 g = *this;
-		g.position.x -= p_amount;
-		g.position.y -= p_amount;
-		g.size.width += p_amount * 2;
-		g.size.height += p_amount * 2;
+		g.grow_by(p_amount);
 		return g;
 	}
 
+	inline void grow_by(real_t p_amount) {
+		position.x -= p_amount;
+		position.y -= p_amount;
+		size.width += p_amount * 2;
+		size.height += p_amount * 2;
+	}
+
 	inline Rect2 grow_side(Side p_side, real_t p_amount) const {
 		Rect2 g = *this;
 		g = g.grow_individual((SIDE_LEFT == p_side) ? p_amount : 0,
@@ -218,14 +249,18 @@ struct _NO_DISCARD_ Rect2 {
 		return g;
 	}
 
-	inline Rect2 expand(const Vector2 &p_vector) const {
+	_FORCE_INLINE_ Rect2 expand(const Vector2 &p_vector) const {
 		Rect2 r = *this;
 		r.expand_to(p_vector);
 		return r;
 	}
 
-	inline void expand_to(const Vector2 &p_vector) { // in place function for speed
-
+	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;
 
@@ -247,21 +282,21 @@ struct _NO_DISCARD_ Rect2 {
 		size = end - begin;
 	}
 
-	inline Rect2 abs() const {
+	_FORCE_INLINE_ Rect2 abs() const {
 		return Rect2(Point2(position.x + Math::min(size.x, (real_t)0), position.y + Math::min(size.y, (real_t)0)), size.abs());
 	}
 
 	Vector2 get_support(const Vector2 &p_normal) const {
-		Vector2 half_extents = size * 0.5;
+		Vector2 half_extents = size * 0.5f;
 		Vector2 ofs = position + half_extents;
 		return Vector2(
 					   (p_normal.x > 0) ? -half_extents.x : half_extents.x,
 					   (p_normal.y > 0) ? -half_extents.y : half_extents.y) +
-			   ofs;
+				ofs;
 	}
 
-	inline bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const {
-		Vector2 center = position + size * 0.5;
+	_FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const {
+		Vector2 center = get_center();
 		int side_plus = 0;
 		int side_minus = 0;
 		Vector2 end = position + size;
@@ -274,22 +309,22 @@ struct _NO_DISCARD_ Rect2 {
 
 			Vector2 r = (b - a);
 			float l = r.length();
-			if (l == 0.0) {
+			if (l == 0.0f) {
 				continue;
 			}
 
-			// check inside
+			// Check inside.
 			Vector2 tg = r.orthogonal();
 			float s = tg.dot(center) - tg.dot(a);
-			if (s < 0.0) {
+			if (s < 0.0f) {
 				side_plus++;
 			} else {
 				side_minus++;
 			}
 
-			// check ray box
+			// Check ray box.
 			r /= l;
-			Vector2 ir((real_t)1.0 / r.x, (real_t)1.0 / r.y);
+			Vector2 ir(1.0f / r.x, 1.0f / r.y);
 
 			// lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
 			// r.org is origin of ray
@@ -308,17 +343,17 @@ struct _NO_DISCARD_ Rect2 {
 		}
 
 		if (side_plus * side_minus == 0) {
-			return true; // all inside
+			return true; // All inside.
 		} else {
 			return false;
 		}
 	}
 
-	inline void set_end(const Vector2 &p_end) {
+	_FORCE_INLINE_ void set_end(const Vector2 &p_end) {
 		size = p_end - position;
 	}
 
-	inline Vector2 get_end() const {
+	_FORCE_INLINE_ Vector2 get_end() const {
 		return position + size;
 	}
 

+ 42 - 17
include/godot_cpp/variant/rect2i.hpp

@@ -32,7 +32,6 @@
 #define GODOT_RECT2I_HPP
 
 #include <godot_cpp/classes/global_constants.hpp>
-#include <godot_cpp/core/math.hpp>
 #include <godot_cpp/variant/vector2i.hpp>
 
 namespace godot {
@@ -51,17 +50,24 @@ struct _NO_DISCARD_ 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 {
-		if (position.x > (p_rect.position.x + p_rect.size.width)) {
+#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;
 		}
-		if ((position.x + size.width) < p_rect.position.x) {
+		if ((position.x + size.width) <= p_rect.position.x) {
 			return false;
 		}
-		if (position.y > (p_rect.position.y + p_rect.size.height)) {
+		if (position.y >= (p_rect.position.y + p_rect.size.height)) {
 			return false;
 		}
-		if ((position.y + size.height) < p_rect.position.y) {
+		if ((position.y + size.height) <= p_rect.position.y) {
 			return false;
 		}
 
@@ -69,13 +75,18 @@ struct _NO_DISCARD_ 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));
 	}
 
-	inline bool has_no_area() const {
-		return (size.x <= 0 || size.y <= 0);
+	_FORCE_INLINE_ bool has_area() const {
+		return size.x > 0 && size.y > 0;
 	}
 
 	// Returns the instersection between two Rect2is or an empty Rect2i if there is no intersection
@@ -92,14 +103,18 @@ struct _NO_DISCARD_ Rect2i {
 		Point2i p_rect_end = p_rect.position + p_rect.size;
 		Point2i end = position + size;
 
-		new_rect.size.x = (int)(Math::min(p_rect_end.x, end.x) - new_rect.position.x);
-		new_rect.size.y = (int)(Math::min(p_rect_end.y, end.y) - new_rect.position.y);
+		new_rect.size.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x;
+		new_rect.size.y = Math::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 = Math::min(p_rect.position.x, position.x);
@@ -108,11 +123,16 @@ struct _NO_DISCARD_ Rect2i {
 		new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x);
 		new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y);
 
-		new_rect.size = new_rect.size - new_rect.position; // make relative again
+		new_rect.size = new_rect.size - new_rect.position; // Make relative again.
 
 		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;
 		}
@@ -165,13 +185,18 @@ struct _NO_DISCARD_ Rect2i {
 		return g;
 	}
 
-	inline Rect2i expand(const Vector2i &p_vector) const {
+	_FORCE_INLINE_ Rect2i expand(const Vector2i &p_vector) const {
 		Rect2i r = *this;
 		r.expand_to(p_vector);
 		return r;
 	}
 
 	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;
 
@@ -193,15 +218,15 @@ struct _NO_DISCARD_ Rect2i {
 		size = end - begin;
 	}
 
-	inline Rect2i abs() const {
+	_FORCE_INLINE_ Rect2i abs() const {
 		return Rect2i(Point2i(position.x + Math::min(size.x, 0), position.y + Math::min(size.y, 0)), size.abs());
 	}
 
-	inline void set_end(const Vector2i &p_end) {
+	_FORCE_INLINE_ void set_end(const Vector2i &p_end) {
 		size = p_end - position;
 	}
 
-	inline Vector2i get_end() const {
+	_FORCE_INLINE_ Vector2i get_end() const {
 		return position + size;
 	}
 

+ 47 - 40
include/godot_cpp/variant/transform2d.hpp

@@ -31,14 +31,14 @@
 #ifndef GODOT_TRANSFORM2D_HPP
 #define GODOT_TRANSFORM2D_HPP
 
-#include <godot_cpp/core/error_macros.hpp>
-#include <godot_cpp/core/math.hpp>
 #include <godot_cpp/variant/packed_vector2_array.hpp>
 #include <godot_cpp/variant/rect2.hpp>
 #include <godot_cpp/variant/vector2.hpp>
 
 namespace godot {
 
+class String;
+
 struct _NO_DISCARD_ Transform2D {
 	// Warning #1: basis of Transform2D is stored differently from Basis. In terms of columns array, the basis matrix looks like "on paper":
 	// M = (columns[0][0] columns[1][0])
@@ -53,52 +53,46 @@ struct _NO_DISCARD_ Transform2D {
 
 	Vector2 columns[3];
 
-	inline real_t tdotx(const Vector2 &v) const { return columns[0][0] * v.x + columns[1][0] * v.y; }
-	inline real_t tdoty(const Vector2 &v) const { return columns[0][1] * v.x + columns[1][1] * v.y; }
+	_FORCE_INLINE_ real_t tdotx(const Vector2 &v) const { return columns[0][0] * v.x + columns[1][0] * v.y; }
+	_FORCE_INLINE_ real_t tdoty(const Vector2 &v) const { return columns[0][1] * v.x + columns[1][1] * v.y; }
 
 	const Vector2 &operator[](int p_idx) const { return columns[p_idx]; }
 	Vector2 &operator[](int p_idx) { return columns[p_idx]; }
 
-	inline Vector2 get_axis(int p_axis) const {
-		ERR_FAIL_INDEX_V(p_axis, 3, Vector2());
-		return columns[p_axis];
-	}
-	inline void set_axis(int p_axis, const Vector2 &p_vec) {
-		ERR_FAIL_INDEX(p_axis, 3);
-		columns[p_axis] = p_vec;
-	}
-
 	void invert();
 	Transform2D inverse() const;
 
 	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);
-	inline void set_rotation_and_scale(real_t p_rot, const Size2 &p_scale);
-	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_angle);
 
 	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 Vector2 &p_translation);
+	void translate_local(const real_t p_tx, const real_t p_ty);
+	void translate_local(const Vector2 &p_translation);
 
 	real_t basis_determinant() const;
 
 	Size2 get_scale() const;
 	void set_scale(const Size2 &p_scale);
 
-	inline const Vector2 &get_origin() const { return columns[2]; }
-	inline void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; }
+	_FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; }
+	_FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; }
 
-	Transform2D scaled(const Size2 &p_scale) const;
 	Transform2D basis_scaled(const Size2 &p_scale) const;
+	Transform2D scaled(const Size2 &p_scale) const;
+	Transform2D scaled_local(const Size2 &p_scale) const;
 	Transform2D translated(const Vector2 &p_offset) const;
-	Transform2D rotated(real_t p_phi) const;
+	Transform2D translated_local(const Vector2 &p_offset) const;
+	Transform2D rotated(const real_t p_angle) const;
+	Transform2D rotated_local(const real_t p_angle) const;
 
 	Transform2D untranslated() const;
 
@@ -106,26 +100,30 @@ struct _NO_DISCARD_ Transform2D {
 	Transform2D orthonormalized() const;
 	bool is_equal_approx(const Transform2D &p_transform) const;
 
+	Transform2D looking_at(const Vector2 &p_target) const;
+
 	bool operator==(const Transform2D &p_transform) const;
 	bool operator!=(const Transform2D &p_transform) const;
 
 	void operator*=(const Transform2D &p_transform);
 	Transform2D operator*(const Transform2D &p_transform) const;
+	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;
 
-	inline Vector2 basis_xform(const Vector2 &p_vec) const;
-	inline Vector2 basis_xform_inv(const Vector2 &p_vec) const;
-	inline Vector2 xform(const Vector2 &p_vec) const;
-	inline Vector2 xform_inv(const Vector2 &p_vec) const;
-	inline Rect2 xform(const Rect2 &p_rect) const;
-	inline Rect2 xform_inv(const Rect2 &p_rect) const;
-	inline PackedVector2Array xform(const PackedVector2Array &p_array) const;
-	inline PackedVector2Array xform_inv(const PackedVector2Array &p_array) const;
+	_FORCE_INLINE_ Vector2 basis_xform(const Vector2 &p_vec) const;
+	_FORCE_INLINE_ Vector2 basis_xform_inv(const Vector2 &p_vec) const;
+	_FORCE_INLINE_ Vector2 xform(const Vector2 &p_vec) const;
+	_FORCE_INLINE_ Vector2 xform_inv(const Vector2 &p_vec) const;
+	_FORCE_INLINE_ Rect2 xform(const Rect2 &p_rect) const;
+	_FORCE_INLINE_ Rect2 xform_inv(const Rect2 &p_rect) const;
+	_FORCE_INLINE_ PackedVector2Array xform(const PackedVector2Array &p_array) const;
+	_FORCE_INLINE_ PackedVector2Array xform_inv(const PackedVector2Array &p_array) const;
 
 	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) {
 		columns[0][0] = xx;
 		columns[0][1] = xy;
 		columns[1][0] = yx;
@@ -140,7 +138,10 @@ struct _NO_DISCARD_ Transform2D {
 		columns[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() {
 		columns[0][0] = 1.0;
 		columns[1][1] = 1.0;
@@ -163,7 +164,7 @@ Vector2 Transform2D::xform(const Vector2 &p_vec) const {
 	return Vector2(
 				   tdotx(p_vec),
 				   tdoty(p_vec)) +
-		   columns[2];
+			columns[2];
 }
 
 Vector2 Transform2D::xform_inv(const Vector2 &p_vec) const {
@@ -187,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) {
 	columns[0][0] = Math::cos(p_rot) * p_scale.x;
 	columns[1][1] = Math::cos(p_rot) * p_scale.y;
 	columns[1][0] = -Math::sin(p_rot) * p_scale.y;
 	columns[0][1] = Math::sin(p_rot) * p_scale.x;
 }
 
-void Transform2D::set_rotation_scale_and_skew(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) {
 	columns[0][0] = Math::cos(p_rot) * p_scale.x;
 	columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
 	columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
@@ -222,8 +223,11 @@ PackedVector2Array Transform2D::xform(const PackedVector2Array &p_array) const {
 	PackedVector2Array array;
 	array.resize(p_array.size());
 
+	const Vector2 *r = p_array.ptr();
+	Vector2 *w = array.ptrw();
+
 	for (int i = 0; i < p_array.size(); ++i) {
-		array[i] = xform(p_array[i]);
+		w[i] = xform(r[i]);
 	}
 	return array;
 }
@@ -232,8 +236,11 @@ PackedVector2Array Transform2D::xform_inv(const PackedVector2Array &p_array) con
 	PackedVector2Array array;
 	array.resize(p_array.size());
 
+	const Vector2 *r = p_array.ptr();
+	Vector2 *w = array.ptrw();
+
 	for (int i = 0; i < p_array.size(); ++i) {
-		array[i] = xform_inv(p_array[i]);
+		w[i] = xform_inv(r[i]);
 	}
 	return array;
 }

+ 0 - 3
include/godot_cpp/variant/vector4i.hpp

@@ -70,9 +70,6 @@ struct _NO_DISCARD_ Vector4i {
 		return coord[p_axis];
 	}
 
-	void set_axis(const int p_axis, const int32_t p_value);
-	int32_t get_axis(const int p_axis) const;
-
 	Vector4i::Axis min_axis_index() const;
 	Vector4i::Axis max_axis_index() const;
 

+ 49 - 13
src/variant/aabb.cpp

@@ -30,12 +30,12 @@
 
 #include <godot_cpp/variant/aabb.hpp>
 
-#include <godot_cpp/core/defs.hpp>
 #include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/variant.hpp>
 
 namespace godot {
 
-real_t AABB::get_area() const {
+real_t AABB::get_volume() const {
 	return size.x * size.y * size.z;
 }
 
@@ -48,14 +48,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;
@@ -74,6 +79,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;
@@ -106,6 +116,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;
@@ -149,6 +164,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;
@@ -268,14 +288,14 @@ int AABB::get_longest_axis_index() const {
 
 Vector3 AABB::get_shortest_axis() const {
 	Vector3 axis(1, 0, 0);
-	real_t max_size = size.x;
+	real_t min_size = size.x;
 
-	if (size.y < max_size) {
+	if (size.y < min_size) {
 		axis = Vector3(0, 1, 0);
-		max_size = size.y;
+		min_size = size.y;
 	}
 
-	if (size.z < max_size) {
+	if (size.z < min_size) {
 		axis = Vector3(0, 0, 1);
 	}
 
@@ -284,14 +304,14 @@ Vector3 AABB::get_shortest_axis() const {
 
 int AABB::get_shortest_axis_index() const {
 	int axis = 0;
-	real_t max_size = size.x;
+	real_t min_size = size.x;
 
-	if (size.y < max_size) {
+	if (size.y < min_size) {
 		axis = 1;
-		max_size = size.y;
+		min_size = size.y;
 	}
 
-	if (size.z < max_size) {
+	if (size.z < min_size) {
 		axis = 2;
 	}
 
@@ -378,8 +398,24 @@ void AABB::get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const {
 	}
 }
 
+Variant AABB::intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const {
+	Vector3 inters;
+	if (intersects_segment(p_from, p_to, &inters)) {
+		return inters;
+	}
+	return Variant();
+}
+
+Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const {
+	Vector3 inters;
+	if (intersects_ray(p_from, p_dir, &inters)) {
+		return inters;
+	}
+	return Variant();
+}
+
 AABB::operator String() const {
-	return position.operator String() + " - " + size.operator String();
+	return "[P: " + position.operator String() + ", S: " + size + "]";
 }
 
 } // namespace godot

+ 2 - 2
src/variant/basis.cpp

@@ -122,7 +122,7 @@ bool Basis::is_diagonal() const {
 }
 
 bool Basis::is_rotation() const {
-	return Math::is_equal_approx(determinant(), (real_t)1, (real_t)UNIT_EPSILON) && is_orthogonal();
+	return Math::is_equal_approx(determinant(), 1, (real_t)UNIT_EPSILON) && is_orthogonal();
 }
 
 #ifdef MATH_CHECKS
@@ -315,7 +315,7 @@ Vector3 Basis::get_scale() const {
 	//
 	// A proper way to get rid of this issue would be to store the scaling values (or at least their signs)
 	// as a part of Basis. However, if we go that path, we need to disable direct (write) access to the
-	// matrix rows.
+	// matrix elements.
 	//
 	// The rotation part of this decomposition is returned by get_rotation* functions.
 	real_t det_sign = SIGN(determinant());

+ 128 - 118
src/variant/color.cpp

@@ -36,77 +36,110 @@
 namespace godot {
 
 uint32_t Color::to_argb32() const {
-	uint32_t c = (uint8_t)Math::round(a * 255);
+	uint32_t c = (uint8_t)Math::round(a * 255.0f);
 	c <<= 8;
-	c |= (uint8_t)Math::round(r * 255);
+	c |= (uint8_t)Math::round(r * 255.0f);
 	c <<= 8;
-	c |= (uint8_t)Math::round(g * 255);
+	c |= (uint8_t)Math::round(g * 255.0f);
 	c <<= 8;
-	c |= (uint8_t)Math::round(b * 255);
+	c |= (uint8_t)Math::round(b * 255.0f);
 
 	return c;
 }
 
 uint32_t Color::to_abgr32() const {
-	uint32_t c = (uint8_t)Math::round(a * 255);
+	uint32_t c = (uint8_t)Math::round(a * 255.0f);
 	c <<= 8;
-	c |= (uint8_t)Math::round(b * 255);
+	c |= (uint8_t)Math::round(b * 255.0f);
 	c <<= 8;
-	c |= (uint8_t)Math::round(g * 255);
+	c |= (uint8_t)Math::round(g * 255.0f);
 	c <<= 8;
-	c |= (uint8_t)Math::round(r * 255);
+	c |= (uint8_t)Math::round(r * 255.0f);
 
 	return c;
 }
 
 uint32_t Color::to_rgba32() const {
-	uint32_t c = (uint8_t)Math::round(r * 255);
+	uint32_t c = (uint8_t)Math::round(r * 255.0f);
 	c <<= 8;
-	c |= (uint8_t)Math::round(g * 255);
+	c |= (uint8_t)Math::round(g * 255.0f);
 	c <<= 8;
-	c |= (uint8_t)Math::round(b * 255);
+	c |= (uint8_t)Math::round(b * 255.0f);
 	c <<= 8;
-	c |= (uint8_t)Math::round(a * 255);
+	c |= (uint8_t)Math::round(a * 255.0f);
 
 	return c;
 }
 
 uint64_t Color::to_abgr64() const {
-	uint64_t c = (uint16_t)Math::round(a * 65535);
+	uint64_t c = (uint16_t)Math::round(a * 65535.0f);
 	c <<= 16;
-	c |= (uint16_t)Math::round(b * 65535);
+	c |= (uint16_t)Math::round(b * 65535.0f);
 	c <<= 16;
-	c |= (uint16_t)Math::round(g * 65535);
+	c |= (uint16_t)Math::round(g * 65535.0f);
 	c <<= 16;
-	c |= (uint16_t)Math::round(r * 65535);
+	c |= (uint16_t)Math::round(r * 65535.0f);
 
 	return c;
 }
 
 uint64_t Color::to_argb64() const {
-	uint64_t c = (uint16_t)Math::round(a * 65535);
+	uint64_t c = (uint16_t)Math::round(a * 65535.0f);
 	c <<= 16;
-	c |= (uint16_t)Math::round(r * 65535);
+	c |= (uint16_t)Math::round(r * 65535.0f);
 	c <<= 16;
-	c |= (uint16_t)Math::round(g * 65535);
+	c |= (uint16_t)Math::round(g * 65535.0f);
 	c <<= 16;
-	c |= (uint16_t)Math::round(b * 65535);
+	c |= (uint16_t)Math::round(b * 65535.0f);
 
 	return c;
 }
 
 uint64_t Color::to_rgba64() const {
-	uint64_t c = (uint16_t)Math::round(r * 65535);
+	uint64_t c = (uint16_t)Math::round(r * 65535.0f);
 	c <<= 16;
-	c |= (uint16_t)Math::round(g * 65535);
+	c |= (uint16_t)Math::round(g * 65535.0f);
 	c <<= 16;
-	c |= (uint16_t)Math::round(b * 65535);
+	c |= (uint16_t)Math::round(b * 65535.0f);
 	c <<= 16;
-	c |= (uint16_t)Math::round(a * 65535);
+	c |= (uint16_t)Math::round(a * 65535.0f);
 
 	return c;
 }
 
+String _to_hex(float p_val) {
+	int v = Math::round(p_val * 255.0f);
+	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 = txt + _to_hex(r);
+	txt = txt + _to_hex(g);
+	txt = txt + _to_hex(b);
+	if (p_alpha) {
+		txt = txt + _to_hex(a);
+	}
+	return txt;
+}
+
 float Color::get_h() const {
 	float min = Math::min(r, g);
 	min = Math::min(min, b);
@@ -115,8 +148,8 @@ float Color::get_h() const {
 
 	float delta = max - min;
 
-	if (delta == 0) {
-		return 0;
+	if (delta == 0.0f) {
+		return 0.0f;
 	}
 
 	float h;
@@ -128,9 +161,9 @@ float Color::get_h() const {
 		h = 4 + (r - g) / delta; // between magenta & cyan
 	}
 
-	h /= 6.0;
-	if (h < 0) {
-		h += 1.0;
+	h /= 6.0f;
+	if (h < 0.0f) {
+		h += 1.0f;
 	}
 
 	return h;
@@ -144,7 +177,7 @@ float Color::get_s() const {
 
 	float delta = max - min;
 
-	return (max != 0) ? (delta / max) : 0;
+	return (max != 0.0f) ? (delta / max) : 0.0f;
 }
 
 float Color::get_v() const {
@@ -158,20 +191,20 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
 	float f, p, q, t;
 	a = p_alpha;
 
-	if (p_s == 0) {
+	if (p_s == 0.0f) {
 		// Achromatic (grey)
 		r = g = b = p_v;
 		return;
 	}
 
-	p_h *= 6.0;
+	p_h *= 6.0f;
 	p_h = Math::fmod(p_h, 6);
 	i = Math::floor(p_h);
 
 	f = p_h - i;
-	p = p_v * (1 - p_s);
-	q = p_v * (1 - p_s * f);
-	t = p_v * (1 - p_s * (1 - f));
+	p = p_v * (1.0f - p_s);
+	q = p_v * (1.0f - p_s * f);
+	t = p_v * (1.0f - p_s * (1.0f - f));
 
 	switch (i) {
 		case 0: // Red is the dominant color
@@ -211,50 +244,44 @@ bool Color::is_equal_approx(const Color &p_color) const {
 	return Math::is_equal_approx(r, p_color.r) && Math::is_equal_approx(g, p_color.g) && Math::is_equal_approx(b, p_color.b) && Math::is_equal_approx(a, p_color.a);
 }
 
+Color Color::clamp(const Color &p_min, const Color &p_max) const {
+	return Color(
+			CLAMP(r, p_min.r, p_max.r),
+			CLAMP(g, p_min.g, p_max.g),
+			CLAMP(b, p_min.b, p_max.b),
+			CLAMP(a, p_min.a, p_max.a));
+}
+
 void Color::invert() {
-	r = 1.0 - r;
-	g = 1.0 - g;
-	b = 1.0 - b;
+	r = 1.0f - r;
+	g = 1.0f - g;
+	b = 1.0f - b;
 }
 
 Color Color::hex(uint32_t p_hex) {
-	float a = (p_hex & 0xFF) / 255.0;
+	float a = (p_hex & 0xFF) / 255.0f;
 	p_hex >>= 8;
-	float b = (p_hex & 0xFF) / 255.0;
+	float b = (p_hex & 0xFF) / 255.0f;
 	p_hex >>= 8;
-	float g = (p_hex & 0xFF) / 255.0;
+	float g = (p_hex & 0xFF) / 255.0f;
 	p_hex >>= 8;
-	float r = (p_hex & 0xFF) / 255.0;
+	float r = (p_hex & 0xFF) / 255.0f;
 
 	return Color(r, g, b, a);
 }
 
 Color Color::hex64(uint64_t p_hex) {
-	float a = (p_hex & 0xFFFF) / 65535.0;
+	float a = (p_hex & 0xFFFF) / 65535.0f;
 	p_hex >>= 16;
-	float b = (p_hex & 0xFFFF) / 65535.0;
+	float b = (p_hex & 0xFFFF) / 65535.0f;
 	p_hex >>= 16;
-	float g = (p_hex & 0xFFFF) / 65535.0;
+	float g = (p_hex & 0xFFFF) / 65535.0f;
 	p_hex >>= 16;
-	float r = (p_hex & 0xFFFF) / 65535.0;
+	float r = (p_hex & 0xFFFF) / 65535.0f;
 
 	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];
 
@@ -301,29 +328,29 @@ Color Color::html(const String &p_rgba) {
 	} else if (color.length() == 3) {
 		alpha = false;
 	} else {
-		ERR_FAIL_V(Color());
+		ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_rgba + ".");
 	}
 
-	float r, g, b, a = 1.0;
+	float r, g, b, a = 1.0f;
 	if (is_shorthand) {
-		r = _parse_col4(color, 0) / 15.0;
-		g = _parse_col4(color, 1) / 15.0;
-		b = _parse_col4(color, 2) / 15.0;
+		r = _parse_col4(color, 0) / 15.0f;
+		g = _parse_col4(color, 1) / 15.0f;
+		b = _parse_col4(color, 2) / 15.0f;
 		if (alpha) {
-			a = _parse_col4(color, 3) / 15.0;
+			a = _parse_col4(color, 3) / 15.0f;
 		}
 	} else {
-		r = _parse_col8(color, 0) / 255.0;
-		g = _parse_col8(color, 2) / 255.0;
-		b = _parse_col8(color, 4) / 255.0;
+		r = _parse_col8(color, 0) / 255.0f;
+		g = _parse_col8(color, 2) / 255.0f;
+		b = _parse_col8(color, 4) / 255.0f;
 		if (alpha) {
-			a = _parse_col8(color, 6) / 255.0;
+			a = _parse_col8(color, 6) / 255.0f;
 		}
 	}
-	ERR_FAIL_COND_V(r < 0, Color());
-	ERR_FAIL_COND_V(g < 0, Color());
-	ERR_FAIL_COND_V(b < 0, Color());
-	ERR_FAIL_COND_V(a < 0, Color());
+	ERR_FAIL_COND_V_MSG(r < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+	ERR_FAIL_COND_V_MSG(g < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+	ERR_FAIL_COND_V_MSG(b < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+	ERR_FAIL_COND_V_MSG(a < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
 
 	return Color(r, g, b, a);
 }
@@ -357,10 +384,10 @@ bool Color::html_is_valid(const String &p_color) {
 Color Color::named(const String &p_name) {
 	int idx = find_named_color(p_name);
 	if (idx == -1) {
-		ERR_FAIL_V(Color());
+		ERR_FAIL_V_MSG(Color(), "Invalid color name: " + p_name + ".");
 		return Color();
 	}
-	return get_named_color(idx);
+	return named_colors[idx].color;
 }
 
 Color Color::named(const String &p_name, const Color &p_default) {
@@ -368,7 +395,7 @@ Color Color::named(const String &p_name, const Color &p_default) {
 	if (idx == -1) {
 		return p_default;
 	}
-	return get_named_color(idx);
+	return named_colors[idx].color;
 }
 
 int Color::find_named_color(const String &p_name) {
@@ -379,11 +406,11 @@ int Color::find_named_color(const String &p_name) {
 	name = name.replace("_", "");
 	name = name.replace("'", "");
 	name = name.replace(".", "");
-	name = name.to_lower();
+	name = name.to_upper();
 
 	int idx = 0;
 	while (named_colors[idx].name != nullptr) {
-		if (name == String(named_colors[idx].name)) {
+		if (name == String(named_colors[idx].name).replace("_", "")) {
 			return idx;
 		}
 		idx++;
@@ -401,10 +428,12 @@ int Color::get_named_color_count() {
 }
 
 String Color::get_named_color_name(int p_idx) {
+	ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), "");
 	return named_colors[p_idx].name;
 }
 
 Color Color::get_named_color(int p_idx) {
+	ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), Color());
 	return named_colors[p_idx].color;
 }
 
@@ -418,47 +447,28 @@ 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 = Math::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 = txt + _to_hex(g);
-	txt = txt + _to_hex(b);
-	txt = txt + _to_hex(r);
-	if (p_alpha) {
-		txt = 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.0f, e - 15.0f - 9.0f);
 
-Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) {
-	Color result;
-	result.set_hsv(p_h, p_s, p_v, p_a);
-	return result;
+	float rd = r * m;
+	float gd = g * m;
+	float bd = b * m;
+
+	return Color(rd, gd, bd, 1.0f);
 }
 
 Color::operator String() const {
-	return String::num(r, 3) + ", " + String::num(g, 3) + ", " + String::num(b, 3) + ", " + String::num(a, 3);
+	return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")";
 }
 
 Color Color::operator+(const Color &p_color) const {
@@ -553,10 +563,10 @@ void Color::operator/=(float p_scalar) {
 
 Color Color::operator-() const {
 	return Color(
-			1.0 - r,
-			1.0 - g,
-			1.0 - b,
-			1.0 - a);
+			1.0f - r,
+			1.0f - g,
+			1.0f - b,
+			1.0f - a);
 }
 
 } // namespace godot

+ 33 - 5
src/variant/plane.cpp

@@ -31,6 +31,7 @@
 #include <godot_cpp/variant/plane.hpp>
 
 #include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/variant.hpp>
 
 namespace godot {
 
@@ -59,7 +60,7 @@ Vector3 Plane::get_any_perpendicular_normal() const {
 	static const Vector3 p2 = Vector3(0, 1, 0);
 	Vector3 p;
 
-	if (Math::abs(normal.dot(p1)) > 0.99) { // if too similar to p1
+	if (Math::abs(normal.dot(p1)) > 0.99f) { // if too similar to p1
 		p = p2; // use p2
 	} else {
 		p = p1; // use p1
@@ -89,7 +90,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;
@@ -107,7 +108,7 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3
 	real_t dist = (normal.dot(p_from) - d) / den;
 	//printf("dist is %i\n",dist);
 
-	if (dist > CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist
+	if (dist > (real_t)CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist
 
 		return false;
 	}
@@ -130,7 +131,7 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
 	real_t dist = (normal.dot(p_begin) - d) / den;
 	//printf("dist is %i\n",dist);
 
-	if (dist < -CMP_EPSILON || dist > (1.0 + CMP_EPSILON)) {
+	if (dist < (real_t)-CMP_EPSILON || dist > (1.0f + (real_t)CMP_EPSILON)) {
 		return false;
 	}
 
@@ -140,6 +141,33 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
 	return true;
 }
 
+Variant Plane::intersect_3_bind(const Plane &p_plane1, const Plane &p_plane2) const {
+	Vector3 inters;
+	if (intersect_3(p_plane1, p_plane2, &inters)) {
+		return inters;
+	} else {
+		return Variant();
+	}
+}
+
+Variant Plane::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const {
+	Vector3 inters;
+	if (intersects_ray(p_from, p_dir, &inters)) {
+		return inters;
+	} else {
+		return Variant();
+	}
+}
+
+Variant Plane::intersects_segment_bind(const Vector3 &p_begin, const Vector3 &p_end) const {
+	Vector3 inters;
+	if (intersects_segment(p_begin, p_end, &inters)) {
+		return inters;
+	} else {
+		return Variant();
+	}
+}
+
 /* misc */
 
 bool Plane::is_equal_approx_any_side(const Plane &p_plane) const {
@@ -151,7 +179,7 @@ bool Plane::is_equal_approx(const Plane &p_plane) const {
 }
 
 Plane::operator String() const {
-	return normal.operator String() + ", " + String::num(d, 3);
+	return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]";
 }
 
 } // namespace godot

+ 127 - 120
src/variant/projection.cpp

@@ -40,24 +40,24 @@
 namespace godot {
 
 float Projection::determinant() const {
-	return matrix[0][3] * matrix[1][2] * matrix[2][1] * matrix[3][0] - matrix[0][2] * matrix[1][3] * matrix[2][1] * matrix[3][0] -
-		   matrix[0][3] * matrix[1][1] * matrix[2][2] * matrix[3][0] + matrix[0][1] * matrix[1][3] * matrix[2][2] * matrix[3][0] +
-		   matrix[0][2] * matrix[1][1] * matrix[2][3] * matrix[3][0] - matrix[0][1] * matrix[1][2] * matrix[2][3] * matrix[3][0] -
-		   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];
+	return columns[0][3] * columns[1][2] * columns[2][1] * columns[3][0] - columns[0][2] * columns[1][3] * columns[2][1] * columns[3][0] -
+			columns[0][3] * columns[1][1] * columns[2][2] * columns[3][0] + columns[0][1] * columns[1][3] * columns[2][2] * columns[3][0] +
+			columns[0][2] * columns[1][1] * columns[2][3] * columns[3][0] - columns[0][1] * columns[1][2] * columns[2][3] * columns[3][0] -
+			columns[0][3] * columns[1][2] * columns[2][0] * columns[3][1] + columns[0][2] * columns[1][3] * columns[2][0] * columns[3][1] +
+			columns[0][3] * columns[1][0] * columns[2][2] * columns[3][1] - columns[0][0] * columns[1][3] * columns[2][2] * columns[3][1] -
+			columns[0][2] * columns[1][0] * columns[2][3] * columns[3][1] + columns[0][0] * columns[1][2] * columns[2][3] * columns[3][1] +
+			columns[0][3] * columns[1][1] * columns[2][0] * columns[3][2] - columns[0][1] * columns[1][3] * columns[2][0] * columns[3][2] -
+			columns[0][3] * columns[1][0] * columns[2][1] * columns[3][2] + columns[0][0] * columns[1][3] * columns[2][1] * columns[3][2] +
+			columns[0][1] * columns[1][0] * columns[2][3] * columns[3][2] - columns[0][0] * columns[1][1] * columns[2][3] * columns[3][2] -
+			columns[0][2] * columns[1][1] * columns[2][0] * columns[3][3] + columns[0][1] * columns[1][2] * columns[2][0] * columns[3][3] +
+			columns[0][2] * columns[1][0] * columns[2][1] * columns[3][3] - columns[0][0] * columns[1][2] * columns[2][1] * columns[3][3] -
+			columns[0][1] * columns[1][0] * columns[2][2] * columns[3][3] + columns[0][0] * columns[1][1] * columns[2][2] * columns[3][3];
 }
 
 void Projection::set_identity() {
 	for (int i = 0; i < 4; i++) {
 		for (int j = 0; j < 4; j++) {
-			matrix[i][j] = (i == j) ? 1 : 0;
+			columns[i][j] = (i == j) ? 1 : 0;
 		}
 	}
 }
@@ -65,7 +65,7 @@ void Projection::set_identity() {
 void Projection::set_zero() {
 	for (int i = 0; i < 4; i++) {
 		for (int j = 0; j < 4; j++) {
-			matrix[i][j] = 0;
+			columns[i][j] = 0;
 		}
 	}
 }
@@ -73,26 +73,26 @@ void Projection::set_zero() {
 Plane Projection::xform4(const Plane &p_vec4) const {
 	Plane ret;
 
-	ret.normal.x = matrix[0][0] * p_vec4.normal.x + matrix[1][0] * p_vec4.normal.y + matrix[2][0] * p_vec4.normal.z + matrix[3][0] * p_vec4.d;
-	ret.normal.y = matrix[0][1] * p_vec4.normal.x + matrix[1][1] * p_vec4.normal.y + matrix[2][1] * p_vec4.normal.z + matrix[3][1] * p_vec4.d;
-	ret.normal.z = matrix[0][2] * p_vec4.normal.x + matrix[1][2] * p_vec4.normal.y + matrix[2][2] * p_vec4.normal.z + matrix[3][2] * p_vec4.d;
-	ret.d = matrix[0][3] * p_vec4.normal.x + matrix[1][3] * p_vec4.normal.y + matrix[2][3] * p_vec4.normal.z + matrix[3][3] * p_vec4.d;
+	ret.normal.x = columns[0][0] * p_vec4.normal.x + columns[1][0] * p_vec4.normal.y + columns[2][0] * p_vec4.normal.z + columns[3][0] * p_vec4.d;
+	ret.normal.y = columns[0][1] * p_vec4.normal.x + columns[1][1] * p_vec4.normal.y + columns[2][1] * p_vec4.normal.z + columns[3][1] * p_vec4.d;
+	ret.normal.z = columns[0][2] * p_vec4.normal.x + columns[1][2] * p_vec4.normal.y + columns[2][2] * p_vec4.normal.z + columns[3][2] * p_vec4.d;
+	ret.d = columns[0][3] * p_vec4.normal.x + columns[1][3] * p_vec4.normal.y + columns[2][3] * p_vec4.normal.z + columns[3][3] * p_vec4.d;
 	return ret;
 }
 
 Vector4 Projection::xform(const Vector4 &p_vec4) const {
 	return Vector4(
-			matrix[0][0] * p_vec4.x + matrix[1][0] * p_vec4.y + matrix[2][0] * p_vec4.z + matrix[3][0] * p_vec4.w,
-			matrix[0][1] * p_vec4.x + matrix[1][1] * p_vec4.y + matrix[2][1] * p_vec4.z + matrix[3][1] * p_vec4.w,
-			matrix[0][2] * p_vec4.x + matrix[1][2] * p_vec4.y + matrix[2][2] * p_vec4.z + matrix[3][2] * p_vec4.w,
-			matrix[0][3] * p_vec4.x + matrix[1][3] * p_vec4.y + matrix[2][3] * p_vec4.z + matrix[3][3] * p_vec4.w);
+			columns[0][0] * p_vec4.x + columns[1][0] * p_vec4.y + columns[2][0] * p_vec4.z + columns[3][0] * p_vec4.w,
+			columns[0][1] * p_vec4.x + columns[1][1] * p_vec4.y + columns[2][1] * p_vec4.z + columns[3][1] * p_vec4.w,
+			columns[0][2] * p_vec4.x + columns[1][2] * p_vec4.y + columns[2][2] * p_vec4.z + columns[3][2] * p_vec4.w,
+			columns[0][3] * p_vec4.x + columns[1][3] * p_vec4.y + columns[2][3] * p_vec4.z + columns[3][3] * p_vec4.w);
 }
 Vector4 Projection::xform_inv(const Vector4 &p_vec4) const {
 	return Vector4(
-			matrix[0][0] * p_vec4.x + matrix[0][1] * p_vec4.y + matrix[0][2] * p_vec4.z + matrix[0][3] * p_vec4.w,
-			matrix[1][0] * p_vec4.x + matrix[1][1] * p_vec4.y + matrix[1][2] * p_vec4.z + matrix[1][3] * p_vec4.w,
-			matrix[2][0] * p_vec4.x + matrix[2][1] * p_vec4.y + matrix[2][2] * p_vec4.z + matrix[2][3] * p_vec4.w,
-			matrix[3][0] * p_vec4.x + matrix[3][1] * p_vec4.y + matrix[3][2] * p_vec4.z + matrix[3][3] * p_vec4.w);
+			columns[0][0] * p_vec4.x + columns[0][1] * p_vec4.y + columns[0][2] * p_vec4.z + columns[0][3] * p_vec4.w,
+			columns[1][0] * p_vec4.x + columns[1][1] * p_vec4.y + columns[1][2] * p_vec4.z + columns[1][3] * p_vec4.w,
+			columns[2][0] * p_vec4.x + columns[2][1] * p_vec4.y + columns[2][2] * p_vec4.z + columns[2][3] * p_vec4.w,
+			columns[3][0] * p_vec4.x + columns[3][1] * p_vec4.y + columns[3][2] * p_vec4.z + columns[3][3] * p_vec4.w);
 }
 
 void Projection::adjust_perspective_znear(real_t p_new_znear) {
@@ -100,8 +100,8 @@ void Projection::adjust_perspective_znear(real_t p_new_znear) {
 	real_t znear = p_new_znear;
 
 	real_t deltaZ = zfar - znear;
-	matrix[2][2] = -(zfar + znear) / deltaZ;
-	matrix[3][2] = -2 * znear * zfar / deltaZ;
+	columns[2][2] = -(zfar + znear) / deltaZ;
+	columns[3][2] = -2 * znear * zfar / deltaZ;
 }
 
 Projection Projection::create_depth_correction(bool p_flip_y) {
@@ -171,7 +171,7 @@ Projection Projection::perspective_znear_adjusted(real_t p_new_znear) const {
 }
 
 Plane Projection::get_projection_plane(Planes p_plane) const {
-	const real_t *matrix = (const real_t *)this->matrix;
+	const real_t *matrix = (const real_t *)this->columns;
 
 	switch (p_plane) {
 		case PLANE_NEAR: {
@@ -257,7 +257,7 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
 	}
 
 	real_t sine, cotangent, deltaZ;
-	real_t radians = Math::deg2rad(p_fovy_degrees / 2.0);
+	real_t radians = Math::deg_to_rad(p_fovy_degrees / 2.0);
 
 	deltaZ = p_z_far - p_z_near;
 	sine = Math::sin(radians);
@@ -269,12 +269,12 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
 
 	set_identity();
 
-	matrix[0][0] = cotangent / p_aspect;
-	matrix[1][1] = cotangent;
-	matrix[2][2] = -(p_z_far + p_z_near) / deltaZ;
-	matrix[2][3] = -1;
-	matrix[3][2] = -2 * p_z_near * p_z_far / deltaZ;
-	matrix[3][3] = 0;
+	columns[0][0] = cotangent / p_aspect;
+	columns[1][1] = cotangent;
+	columns[2][2] = -(p_z_far + p_z_near) / deltaZ;
+	columns[2][3] = -1;
+	columns[3][2] = -2 * p_z_near * p_z_far / deltaZ;
+	columns[3][3] = 0;
 }
 
 void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) {
@@ -284,7 +284,7 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
 
 	real_t left, right, modeltranslation, ymax, xmax, frustumshift;
 
-	ymax = p_z_near * tan(Math::deg2rad(p_fovy_degrees / 2.0));
+	ymax = p_z_near * tan(Math::deg_to_rad(p_fovy_degrees / 2.0));
 	xmax = ymax * p_aspect;
 	frustumshift = (p_intraocular_dist / 2.0) * p_z_near / p_convergence_dist;
 
@@ -311,7 +311,7 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
 	// translate matrix by (modeltranslation, 0.0, 0.0)
 	Projection cm;
 	cm.set_identity();
-	cm.matrix[3][0] = modeltranslation;
+	cm.columns[3][0] = modeltranslation;
 	*this = *this * cm;
 }
 
@@ -346,13 +346,13 @@ void Projection::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_di
 void Projection::set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) {
 	set_identity();
 
-	matrix[0][0] = 2.0 / (p_right - p_left);
-	matrix[3][0] = -((p_right + p_left) / (p_right - p_left));
-	matrix[1][1] = 2.0 / (p_top - p_bottom);
-	matrix[3][1] = -((p_top + p_bottom) / (p_top - p_bottom));
-	matrix[2][2] = -2.0 / (p_zfar - p_znear);
-	matrix[3][2] = -((p_zfar + p_znear) / (p_zfar - p_znear));
-	matrix[3][3] = 1.0;
+	columns[0][0] = 2.0 / (p_right - p_left);
+	columns[3][0] = -((p_right + p_left) / (p_right - p_left));
+	columns[1][1] = 2.0 / (p_top - p_bottom);
+	columns[3][1] = -((p_top + p_bottom) / (p_top - p_bottom));
+	columns[2][2] = -2.0 / (p_zfar - p_znear);
+	columns[3][2] = -((p_zfar + p_znear) / (p_zfar - p_znear));
+	columns[3][3] = 1.0;
 }
 
 void Projection::set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) {
@@ -368,7 +368,7 @@ void Projection::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, rea
 	ERR_FAIL_COND(p_top <= p_bottom);
 	ERR_FAIL_COND(p_far <= p_near);
 
-	real_t *te = &matrix[0][0];
+	real_t *te = &columns[0][0];
 	real_t x = 2 * p_near / (p_right - p_left);
 	real_t y = 2 * p_near / (p_top - p_bottom);
 
@@ -404,7 +404,7 @@ void Projection::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, r
 }
 
 real_t Projection::get_z_far() const {
-	const real_t *matrix = (const real_t *)this->matrix;
+	const real_t *matrix = (const real_t *)this->columns;
 	Plane new_plane = Plane(matrix[3] - matrix[2],
 			matrix[7] - matrix[6],
 			matrix[11] - matrix[10],
@@ -417,7 +417,7 @@ real_t Projection::get_z_far() const {
 }
 
 real_t Projection::get_z_near() const {
-	const real_t *matrix = (const real_t *)this->matrix;
+	const real_t *matrix = (const real_t *)this->columns;
 	Plane new_plane = Plane(matrix[3] + matrix[2],
 			matrix[7] + matrix[6],
 			matrix[11] + matrix[10],
@@ -428,7 +428,7 @@ real_t Projection::get_z_near() const {
 }
 
 Vector2 Projection::get_viewport_half_extents() const {
-	const real_t *matrix = (const real_t *)this->matrix;
+	const real_t *matrix = (const real_t *)this->columns;
 	///////--- Near Plane ---///////
 	Plane near_plane = Plane(matrix[3] + matrix[2],
 			matrix[7] + matrix[6],
@@ -456,7 +456,7 @@ Vector2 Projection::get_viewport_half_extents() const {
 }
 
 Vector2 Projection::get_far_plane_half_extents() const {
-	const real_t *matrix = (const real_t *)this->matrix;
+	const real_t *matrix = (const real_t *)this->columns;
 	///////--- Far Plane ---///////
 	Plane far_plane = Plane(matrix[3] - matrix[2],
 			matrix[7] - matrix[6],
@@ -498,7 +498,10 @@ bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8point
 
 	for (int i = 0; i < 8; i++) {
 		Vector3 point;
-		bool res = planes[intersections[i][0]].operator Plane().intersect_3(planes[intersections[i][1]].operator Plane(), planes[intersections[i][2]].operator Plane(), &point);
+		Plane a = planes[intersections[i][0]];
+		Plane b = planes[intersections[i][1]];
+		Plane c = planes[intersections[i][2]];
+		bool res = a.intersect_3(b, c, &point);
 		ERR_FAIL_COND_V(!res, false);
 		p_8points[i] = p_transform.xform(point);
 	}
@@ -514,8 +517,9 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const {
 	 */
 
 	Array planes;
+	planes.resize(6);
 
-	const real_t *matrix = (const real_t *)this->matrix;
+	const real_t *matrix = (const real_t *)this->columns;
 
 	Plane new_plane;
 
@@ -528,7 +532,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const {
 	new_plane.normal = -new_plane.normal;
 	new_plane.normalize();
 
-	planes.push_back(p_transform.xform(new_plane));
+	planes[0] = p_transform.xform(new_plane);
 
 	///////--- Far Plane ---///////
 	new_plane = Plane(matrix[3] - matrix[2],
@@ -539,7 +543,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const {
 	new_plane.normal = -new_plane.normal;
 	new_plane.normalize();
 
-	planes.push_back(p_transform.xform(new_plane));
+	planes[1] = p_transform.xform(new_plane);
 
 	///////--- Left Plane ---///////
 	new_plane = Plane(matrix[3] + matrix[0],
@@ -550,7 +554,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const {
 	new_plane.normal = -new_plane.normal;
 	new_plane.normalize();
 
-	planes.push_back(p_transform.xform(new_plane));
+	planes[2] = p_transform.xform(new_plane);
 
 	///////--- Top Plane ---///////
 	new_plane = Plane(matrix[3] - matrix[1],
@@ -561,7 +565,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const {
 	new_plane.normal = -new_plane.normal;
 	new_plane.normalize();
 
-	planes.push_back(p_transform.xform(new_plane));
+	planes[3] = p_transform.xform(new_plane);
 
 	///////--- Right Plane ---///////
 	new_plane = Plane(matrix[3] - matrix[0],
@@ -572,7 +576,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const {
 	new_plane.normal = -new_plane.normal;
 	new_plane.normalize();
 
-	planes.push_back(p_transform.xform(new_plane));
+	planes[4] = p_transform.xform(new_plane);
 
 	///////--- Bottom Plane ---///////
 	new_plane = Plane(matrix[3] + matrix[1],
@@ -583,7 +587,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const {
 	new_plane.normal = -new_plane.normal;
 	new_plane.normalize();
 
-	planes.push_back(p_transform.xform(new_plane));
+	planes[5] = p_transform.xform(new_plane);
 
 	return planes;
 }
@@ -602,15 +606,15 @@ void Projection::invert() {
 	real_t determinant = 1.0f;
 	for (k = 0; k < 4; k++) {
 		/** Locate k'th pivot element **/
-		pvt_val = matrix[k][k]; /** Initialize for search **/
+		pvt_val = columns[k][k]; /** Initialize for search **/
 		pvt_i[k] = k;
 		pvt_j[k] = k;
 		for (i = k; i < 4; i++) {
 			for (j = k; j < 4; j++) {
-				if (Math::abs(matrix[i][j]) > Math::abs(pvt_val)) {
+				if (Math::abs(columns[i][j]) > Math::abs(pvt_val)) {
 					pvt_i[k] = i;
 					pvt_j[k] = j;
-					pvt_val = matrix[i][j];
+					pvt_val = columns[i][j];
 				}
 			}
 		}
@@ -621,13 +625,13 @@ void Projection::invert() {
 			return; /** Matrix is singular (zero determinant). **/
 		}
 
-		/** "Interchange" elements (with sign change stuff) **/
+		/** "Interchange" rows (with sign change stuff) **/
 		i = pvt_i[k];
-		if (i != k) { /** If elements are different **/
+		if (i != k) { /** If rows are different **/
 			for (j = 0; j < 4; j++) {
-				hold = -matrix[k][j];
-				matrix[k][j] = matrix[i][j];
-				matrix[i][j] = hold;
+				hold = -columns[k][j];
+				columns[k][j] = columns[i][j];
+				columns[i][j] = hold;
 			}
 		}
 
@@ -635,25 +639,25 @@ void Projection::invert() {
 		j = pvt_j[k];
 		if (j != k) { /** If columns are different **/
 			for (i = 0; i < 4; i++) {
-				hold = -matrix[i][k];
-				matrix[i][k] = matrix[i][j];
-				matrix[i][j] = hold;
+				hold = -columns[i][k];
+				columns[i][k] = columns[i][j];
+				columns[i][j] = hold;
 			}
 		}
 
 		/** Divide column by minus pivot value **/
 		for (i = 0; i < 4; i++) {
 			if (i != k) {
-				matrix[i][k] /= (-pvt_val);
+				columns[i][k] /= (-pvt_val);
 			}
 		}
 
 		/** Reduce the matrix **/
 		for (i = 0; i < 4; i++) {
-			hold = matrix[i][k];
+			hold = columns[i][k];
 			for (j = 0; j < 4; j++) {
 				if (i != k && j != k) {
-					matrix[i][j] += hold * matrix[k][j];
+					columns[i][j] += hold * columns[k][j];
 				}
 			}
 		}
@@ -661,32 +665,32 @@ void Projection::invert() {
 		/** Divide row by pivot **/
 		for (j = 0; j < 4; j++) {
 			if (j != k) {
-				matrix[k][j] /= pvt_val;
+				columns[k][j] /= pvt_val;
 			}
 		}
 
 		/** Replace pivot by reciprocal (at last we can touch it). **/
-		matrix[k][k] = 1.0 / pvt_val;
+		columns[k][k] = 1.0 / pvt_val;
 	}
 
 	/* That was most of the work, one final pass of row/column interchange */
 	/* to finish */
 	for (k = 4 - 2; k >= 0; k--) { /* Don't need to work with 1 by 1 corner*/
 		i = pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */
-		if (i != k) { /* If elements are different */
+		if (i != k) { /* If rows are different */
 			for (j = 0; j < 4; j++) {
-				hold = matrix[k][j];
-				matrix[k][j] = -matrix[i][j];
-				matrix[i][j] = hold;
+				hold = columns[k][j];
+				columns[k][j] = -columns[i][j];
+				columns[i][j] = hold;
 			}
 		}
 
 		j = pvt_i[k]; /* Columns to swap correspond to pivot ROW */
 		if (j != k) { /* If columns are different */
 			for (i = 0; i < 4; i++) {
-				hold = matrix[i][k];
-				matrix[i][k] = -matrix[i][j];
-				matrix[i][j] = hold;
+				hold = columns[i][k];
+				columns[i][k] = -columns[i][j];
+				columns[i][j] = hold;
 			}
 		}
 	}
@@ -694,7 +698,7 @@ void Projection::invert() {
 
 void Projection::flip_y() {
 	for (int i = 0; i < 4; i++) {
-		matrix[1][i] = -matrix[1][i];
+		columns[1][i] = -columns[1][i];
 	}
 }
 
@@ -709,9 +713,9 @@ Projection Projection::operator*(const Projection &p_matrix) const {
 		for (int i = 0; i < 4; i++) {
 			real_t ab = 0;
 			for (int k = 0; k < 4; k++) {
-				ab += matrix[k][i] * p_matrix.matrix[j][k];
+				ab += columns[k][i] * p_matrix.columns[j][k];
 			}
-			new_matrix.matrix[j][i] = ab;
+			new_matrix.columns[j][i] = ab;
 		}
 	}
 
@@ -719,7 +723,7 @@ Projection Projection::operator*(const Projection &p_matrix) const {
 }
 
 void Projection::set_depth_correction(bool p_flip_y) {
-	real_t *m = &matrix[0][0];
+	real_t *m = &columns[0][0];
 
 	m[0] = 1;
 	m[1] = 0.0;
@@ -740,7 +744,7 @@ void Projection::set_depth_correction(bool p_flip_y) {
 }
 
 void Projection::set_light_bias() {
-	real_t *m = &matrix[0][0];
+	real_t *m = &columns[0][0];
 
 	m[0] = 0.5;
 	m[1] = 0.0;
@@ -761,7 +765,7 @@ void Projection::set_light_bias() {
 }
 
 void Projection::set_light_atlas_rect(const Rect2 &p_rect) {
-	real_t *m = &matrix[0][0];
+	real_t *m = &columns[0][0];
 
 	m[0] = p_rect.size.width;
 	m[1] = 0.0;
@@ -785,7 +789,7 @@ Projection::operator String() const {
 	String str;
 	for (int i = 0; i < 4; i++) {
 		for (int j = 0; j < 4; j++) {
-			str = str + String((j > 0) ? ", " : "\n") + rtos(matrix[i][j]);
+			str = str + String((j > 0) ? ", " : "\n") + rtos(columns[i][j]);
 		}
 	}
 
@@ -804,11 +808,11 @@ int Projection::get_pixels_per_meter(int p_for_pixel_width) const {
 }
 
 bool Projection::is_orthogonal() const {
-	return matrix[3][3] == 1.0;
+	return columns[3][3] == 1.0;
 }
 
 real_t Projection::get_fov() const {
-	const real_t *matrix = (const real_t *)this->matrix;
+	const real_t *matrix = (const real_t *)this->columns;
 
 	Plane right_plane = Plane(matrix[3] - matrix[0],
 			matrix[7] - matrix[4],
@@ -817,7 +821,7 @@ real_t Projection::get_fov() const {
 	right_plane.normalize();
 
 	if ((matrix[8] == 0) && (matrix[9] == 0)) {
-		return Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0;
+		return Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0;
 	} else {
 		// our frustum is asymmetrical need to calculate the left planes angle separately..
 		Plane left_plane = Plane(matrix[3] + matrix[0],
@@ -826,7 +830,7 @@ real_t Projection::get_fov() const {
 				matrix[15] + matrix[12]);
 		left_plane.normalize();
 
-		return Math::rad2deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x)));
+		return Math::rad_to_deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x)));
 	}
 }
 
@@ -839,48 +843,49 @@ float Projection::get_lod_multiplier() const {
 		return 1.0 / (zn / width);
 	}
 
-	// usage is lod_size / (lod_distance * multiplier) < threshold
+	// Usage is lod_size / (lod_distance * multiplier) < threshold
 }
+
 void Projection::make_scale(const Vector3 &p_scale) {
 	set_identity();
-	matrix[0][0] = p_scale.x;
-	matrix[1][1] = p_scale.y;
-	matrix[2][2] = p_scale.z;
+	columns[0][0] = p_scale.x;
+	columns[1][1] = p_scale.y;
+	columns[2][2] = p_scale.z;
 }
 
 void Projection::scale_translate_to_fit(const AABB &p_aabb) {
 	Vector3 min = p_aabb.position;
 	Vector3 max = p_aabb.position + p_aabb.size;
 
-	matrix[0][0] = 2 / (max.x - min.x);
-	matrix[1][0] = 0;
-	matrix[2][0] = 0;
-	matrix[3][0] = -(max.x + min.x) / (max.x - min.x);
+	columns[0][0] = 2 / (max.x - min.x);
+	columns[1][0] = 0;
+	columns[2][0] = 0;
+	columns[3][0] = -(max.x + min.x) / (max.x - min.x);
 
-	matrix[0][1] = 0;
-	matrix[1][1] = 2 / (max.y - min.y);
-	matrix[2][1] = 0;
-	matrix[3][1] = -(max.y + min.y) / (max.y - min.y);
+	columns[0][1] = 0;
+	columns[1][1] = 2 / (max.y - min.y);
+	columns[2][1] = 0;
+	columns[3][1] = -(max.y + min.y) / (max.y - min.y);
 
-	matrix[0][2] = 0;
-	matrix[1][2] = 0;
-	matrix[2][2] = 2 / (max.z - min.z);
-	matrix[3][2] = -(max.z + min.z) / (max.z - min.z);
+	columns[0][2] = 0;
+	columns[1][2] = 0;
+	columns[2][2] = 2 / (max.z - min.z);
+	columns[3][2] = -(max.z + min.z) / (max.z - min.z);
 
-	matrix[0][3] = 0;
-	matrix[1][3] = 0;
-	matrix[2][3] = 0;
-	matrix[3][3] = 1;
+	columns[0][3] = 0;
+	columns[1][3] = 0;
+	columns[2][3] = 0;
+	columns[3][3] = 1;
 }
 
 void Projection::add_jitter_offset(const Vector2 &p_offset) {
-	matrix[3][0] += p_offset.x;
-	matrix[3][1] += p_offset.y;
+	columns[3][0] += p_offset.x;
+	columns[3][1] += p_offset.y;
 }
 
 Projection::operator Transform3D() const {
 	Transform3D tr;
-	const real_t *m = &matrix[0][0];
+	const real_t *m = &columns[0][0];
 
 	tr.basis.rows[0][0] = m[0];
 	tr.basis.rows[1][0] = m[1];
@@ -900,15 +905,17 @@ Projection::operator Transform3D() const {
 
 	return tr;
 }
+
 Projection::Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w) {
-	matrix[0] = p_x;
-	matrix[1] = p_y;
-	matrix[2] = p_z;
-	matrix[3] = p_w;
+	columns[0] = p_x;
+	columns[1] = p_y;
+	columns[2] = p_z;
+	columns[3] = p_w;
 }
+
 Projection::Projection(const Transform3D &p_transform) {
 	const Transform3D &tr = p_transform;
-	real_t *m = &matrix[0][0];
+	real_t *m = &columns[0][0];
 
 	m[0] = tr.basis.rows[0][0];
 	m[1] = tr.basis.rows[1][0];

+ 1 - 1
src/variant/quaternion.cpp

@@ -94,7 +94,7 @@ Quaternion Quaternion::normalized() const {
 }
 
 bool Quaternion::is_normalized() const {
-	return Math::is_equal_approx(length_squared(), (real_t)1.0, (real_t)UNIT_EPSILON); //use less epsilon
+	return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); //use less epsilon
 }
 
 Quaternion Quaternion::inverse() const {

+ 11 - 1
src/variant/rect2.cpp

@@ -41,6 +41,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;
@@ -101,6 +106,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] = {
@@ -271,7 +281,7 @@ next4:
 }
 
 Rect2::operator String() const {
-	return String(position) + ", " + String(size);
+	return "[P: " + position.operator String() + ", S: " + size + "]";
 }
 
 Rect2::operator Rect2i() const {

+ 1 - 1
src/variant/rect2i.cpp

@@ -36,7 +36,7 @@
 namespace godot {
 
 Rect2i::operator String() const {
-	return String(position) + ", " + String(size);
+	return "[P: " + position.operator String() + ", S: " + size + "]";
 }
 
 Rect2i::operator Rect2() const {

+ 69 - 26
src/variant/transform2d.cpp

@@ -50,7 +50,7 @@ void Transform2D::affine_invert() {
 #ifdef MATH_CHECKS
 	ERR_FAIL_COND(det == 0);
 #endif
-	real_t idet = 1.0 / det;
+	real_t idet = 1.0f / det;
 
 	SWAP(columns[0][0], columns[1][1]);
 	columns[0] *= Vector2(idet, -idet);
@@ -65,25 +65,25 @@ Transform2D Transform2D::affine_inverse() const {
 	return inv;
 }
 
-void Transform2D::rotate(real_t p_phi) {
-	*this = Transform2D(p_phi, Vector2()) * (*this);
+void Transform2D::rotate(const real_t p_angle) {
+	*this = Transform2D(p_angle, Vector2()) * (*this);
 }
 
 real_t Transform2D::get_skew() const {
 	real_t det = basis_determinant();
-	return Math::acos(columns[0].normalized().dot(Math::sign(det) * columns[1].normalized())) - Math_PI * 0.5;
+	return Math::acos(columns[0].normalized().dot(SIGN(det) * columns[1].normalized())) - (real_t)Math_PI * 0.5f;
 }
 
-void Transform2D::set_skew(float p_angle) {
+void Transform2D::set_skew(const real_t p_angle) {
 	real_t det = basis_determinant();
-	columns[1] = Math::sign(det) * columns[0].rotated((Math_PI * 0.5 + p_angle)).normalized() * columns[1].length();
+	columns[1] = SIGN(det) * columns[0].rotated(((real_t)Math_PI * 0.5f + p_angle)).normalized() * columns[1].length();
 }
 
 real_t Transform2D::get_rotation() const {
 	return Math::atan2(columns[0].y, columns[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);
@@ -94,7 +94,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);
 	columns[0][0] = cr;
@@ -104,6 +104,14 @@ Transform2D::Transform2D(real_t p_rot, const Vector2 &p_pos) {
 	columns[2] = p_pos;
 }
 
+Transform2D::Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos) {
+	columns[0][0] = Math::cos(p_rot) * p_scale.x;
+	columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
+	columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
+	columns[0][1] = Math::sin(p_rot) * p_scale.x;
+	columns[2] = p_pos;
+}
+
 Size2 Transform2D::get_scale() const {
 	real_t det_sign = Math::sign(basis_determinant());
 	return Size2(columns[0].length(), det_sign * columns[1].length());
@@ -128,11 +136,11 @@ void Transform2D::scale_basis(const Size2 &p_scale) {
 	columns[1][1] *= p_scale.y;
 }
 
-void Transform2D::translate(real_t p_tx, real_t p_ty) {
-	translate(Vector2(p_tx, p_ty));
+void Transform2D::translate_local(const real_t p_tx, const real_t p_ty) {
+	translate_local(Vector2(p_tx, p_ty));
 }
 
-void Transform2D::translate(const Vector2 &p_translation) {
+void Transform2D::translate_local(const Vector2 &p_translation) {
 	columns[2] += basis_xform(p_translation);
 }
 
@@ -160,6 +168,13 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
 	return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]);
 }
 
+Transform2D Transform2D::looking_at(const Vector2 &p_target) const {
+	Transform2D return_trans = Transform2D(get_rotation(), get_origin());
+	Vector2 target_position = affine_inverse().xform(p_target);
+	return_trans.set_rotation(return_trans.get_rotation() + (target_position * get_scale()).angle());
+	return return_trans;
+}
+
 bool Transform2D::operator==(const Transform2D &p_transform) const {
 	for (int i = 0; i < 3; i++) {
 		if (columns[i] != p_transform.columns[i]) {
@@ -202,18 +217,24 @@ Transform2D Transform2D::operator*(const Transform2D &p_transform) const {
 	return t;
 }
 
-Transform2D Transform2D::scaled(const Size2 &p_scale) const {
+Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
 	Transform2D copy = *this;
-	copy.scale(p_scale);
+	copy.scale_basis(p_scale);
 	return copy;
 }
 
-Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
+Transform2D Transform2D::scaled(const Size2 &p_scale) const {
+	// Equivalent to left multiplication
 	Transform2D copy = *this;
-	copy.scale_basis(p_scale);
+	copy.scale(p_scale);
 	return copy;
 }
 
+Transform2D Transform2D::scaled_local(const Size2 &p_scale) const {
+	// Equivalent to right multiplication
+	return Transform2D(columns[0] * p_scale.x, columns[1] * p_scale.y, columns[2]);
+}
+
 Transform2D Transform2D::untranslated() const {
 	Transform2D copy = *this;
 	copy.columns[2] = Vector2();
@@ -221,22 +242,30 @@ Transform2D Transform2D::untranslated() const {
 }
 
 Transform2D Transform2D::translated(const Vector2 &p_offset) const {
-	Transform2D copy = *this;
-	copy.translate(p_offset);
-	return copy;
+	// Equivalent to left multiplication
+	return Transform2D(columns[0], columns[1], columns[2] + p_offset);
 }
 
-Transform2D Transform2D::rotated(real_t p_phi) const {
-	Transform2D copy = *this;
-	copy.rotate(p_phi);
-	return copy;
+Transform2D Transform2D::translated_local(const Vector2 &p_offset) const {
+	// Equivalent to right multiplication
+	return Transform2D(columns[0], columns[1], columns[2] + basis_xform(p_offset));
+}
+
+Transform2D Transform2D::rotated(const real_t p_angle) const {
+	// Equivalent to left multiplication
+	return Transform2D(p_angle, Vector2()) * (*this);
+}
+
+Transform2D Transform2D::rotated_local(const real_t p_angle) const {
+	// Equivalent to right multiplication
+	return (*this) * Transform2D(p_angle, Vector2()); // Could be optimized, because origin transform can be skipped.
 }
 
 real_t Transform2D::basis_determinant() const {
 	return columns[0].x * columns[1].y - columns[0].y * columns[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();
@@ -257,7 +286,7 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t
 
 	Vector2 v;
 
-	if (dot > 0.9995) {
+	if (dot > 0.9995f) {
 		v = v1.lerp(v2, p_c).normalized(); //linearly interpolate to avoid numerical precision issues
 	} else {
 		real_t angle = p_c * Math::acos(dot);
@@ -266,13 +295,27 @@ 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;
 }
 
+void Transform2D::operator*=(const real_t p_val) {
+	columns[0] *= p_val;
+	columns[1] *= p_val;
+	columns[2] *= p_val;
+}
+
+Transform2D Transform2D::operator*(const real_t p_val) const {
+	Transform2D ret(*this);
+	ret *= p_val;
+	return ret;
+}
+
 Transform2D::operator String() const {
-	return columns[0].operator String() + ", " + columns[1].operator String() + ", " + columns[2].operator String();
+	return "[X: " + columns[0].operator String() +
+			", Y: " + columns[1].operator String() +
+			", O: " + columns[2].operator String() + "]";
 }
 
 } // namespace godot

+ 0 - 10
src/variant/vector4i.cpp

@@ -35,16 +35,6 @@
 
 namespace godot {
 
-void Vector4i::set_axis(const int p_axis, const int32_t p_value) {
-	ERR_FAIL_INDEX(p_axis, 4);
-	coord[p_axis] = p_value;
-}
-
-int32_t Vector4i::get_axis(const int p_axis) const {
-	ERR_FAIL_INDEX_V(p_axis, 4, 0);
-	return operator[](p_axis);
-}
-
 Vector4i::Axis Vector4i::min_axis_index() const {
 	uint32_t min_index = 0;
 	int32_t min_value = x;